Compare commits

...

36 Commits

Author SHA1 Message Date
Logan McNaughton d7f656cd6a update cargo packages 2025-07-25 21:26:54 +02:00
Logan McNaughton 8558334391 Add code signing policy 2025-07-25 16:23:46 +02:00
Logan McNaughton b6de872d78 Sign code using SignPath (#525)
* Sign code using SignPath

* more

* more

* more

* more

* more

* use release-signing
2025-07-25 11:45:11 +02:00
Logan McNaughton 712dc10c65 cleanup netplay error checking 2025-07-25 07:20:50 +02:00
Logan McNaughton cd2b5b4e92 error checking for netplay ui channels (#527)
* error checking for netplay ui channels

* more
2025-07-25 07:00:45 +02:00
Logan McNaughton 98b5d6506e add spacing in settings 2025-07-20 23:12:01 +02:00
Logan McNaughton f2e8bc6356 data access fixes 2025-07-20 21:33:07 +02:00
Logan McNaughton 328e1730a0 Update parallel-rdp (#523) 2025-07-20 09:55:36 +02:00
Logan McNaughton 8010a6211c Use default AR on windows (#522)
* Use default AR on windows

* use llvm-ar

* more
2025-07-20 08:16:04 +02:00
Logan McNaughton 41b1fd05be build without clang-cl on Windows (#521) 2025-07-20 07:51:00 +02:00
Logan McNaughton c5da2a795f use specific llvm version (#520)
* use specific llvm version

* more

* more

* more

* more
2025-07-19 18:30:17 +02:00
Logan McNaughton 7361a9bd5c remove unneeded flag (#519) 2025-07-19 16:45:27 +02:00
Logan McNaughton d4e8933352 Use rust-lld on Windows (#518) 2025-07-19 16:31:58 +02:00
Logan McNaughton fff376db5e cargo update 2025-07-19 15:51:57 +02:00
Logan McNaughton d7f1c8415a disable cargo dependabot 2025-07-19 15:51:23 +02:00
Logan McNaughton ac09be4202 Increase axis movement requirement when configuring controller (#514) 2025-07-17 15:22:21 +02:00
Logan McNaughton 022190384a Add support for custom netplay server url (#511)
* Add support for custom netplay server url

* more

* more

* more

* more

* more

* more

* more

* more

* more

* more
2025-07-16 15:42:54 +02:00
Logan McNaughton e4dd5c2dee Fix crash in wrestlemania (#510) 2025-07-16 12:13:12 +02:00
Logan McNaughton 3e95059ec7 add pause hotkey (#509) 2025-07-15 20:43:31 +02:00
Logan McNaughton abc39e74ef Remember ROM dir (#508)
* Remember ROM dir

* more

* more

* more

* more

* more
2025-07-15 20:05:46 +02:00
Logan McNaughton 7109d28223 update c standard (#507)
* update c standard

* more

* more
2025-07-15 15:28:34 +02:00
Logan McNaughton 1d1e3829e4 Update icon 2025-07-14 15:47:11 +02:00
Logan McNaughton a46e4f505b re-enable mac build 2025-07-13 17:51:37 +02:00
Logan McNaughton 03fbe658f2 Update netplay server url (#491) 2025-07-12 15:01:59 +02:00
Logan McNaughton b96c9e4cdc bump to 1.1.1 (#490) 2025-07-11 21:28:53 +02:00
Logan McNaughton cea405ea30 bump to 1.1.0 (#489) 2025-07-11 21:14:18 +02:00
Logan McNaughton c13d354201 savestate speed improvements (#486)
* savestate speed improvements

* more
2025-07-10 18:13:16 +02:00
Logan McNaughton ff43f59f74 fix compile warning (#485)
* fix compile warning

* more
2025-07-10 14:38:28 +02:00
dependabot[bot] eb97b96daf Bump zip from 4.2.0 to 4.3.0 (#483)
Bumps [zip](https://github.com/zip-rs/zip2) from 4.2.0 to 4.3.0.
- [Release notes](https://github.com/zip-rs/zip2/releases)
- [Changelog](https://github.com/zip-rs/zip2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zip-rs/zip2/compare/v4.2.0...v4.3.0)

---
updated-dependencies:
- dependency-name: zip
  dependency-version: 4.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-10 12:48:44 +02:00
Logan McNaughton 9bf43a16b4 Move SDL_PumpEvents (#482)
* Move SDL_PumpEvents

* more
2025-07-09 22:07:38 +02:00
Logan McNaughton b67247f935 Sync sdl window to prevent fullscreen issues (#481) 2025-07-09 19:55:24 +02:00
Logan McNaughton f10c591047 init rdp device 2025-07-09 10:45:12 +02:00
Logan McNaughton 82f1965f26 avoid syncing RDP too much (#479) 2025-07-09 10:31:20 +02:00
Logan McNaughton a5ddea353a print sdl errors (#478) 2025-07-09 10:19:44 +02:00
Logan McNaughton 6c977dbe5e Update README.md 2025-07-07 14:38:36 +02:00
Logan McNaughton 5dcfd72b18 bump to 1.0.21 (#477) 2025-07-06 20:07:31 +02:00
43 changed files with 842 additions and 564 deletions
+4 -3
View File
@@ -1,8 +1,8 @@
[target.'cfg(not(target_os = "windows"))']
rustflags = ["-C", "linker=clang", "-C", "link-arg=-fuse-ld=lld"]
[target.'cfg(target_os = "linux")']
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
[target.'cfg(target_os = "windows")']
rustflags = ["-C", "linker=lld-link", "-C", "link-arg=-fuse-ld=lld-link"]
linker = "rust-lld"
[target.'cfg(target_arch = "x86_64")']
rustflags = ["-C", "target-cpu=x86-64-v3"]
@@ -13,3 +13,4 @@ rustflags = ["-C", "target-cpu=cortex-a76"]
[env]
CC = "clang"
CXX = "clang++"
AR = "llvm-ar"
+4 -4
View File
@@ -4,7 +4,7 @@ updates:
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "daily"
# - package-ecosystem: "cargo"
# directory: "/"
# schedule:
# interval: "daily"
+31 -9
View File
@@ -5,12 +5,13 @@ permissions:
on:
push:
branches: ["main"]
tags:
- "v*"
pull_request:
branches: ["main"]
env:
CARGO_TERM_COLOR: always
LLVM_VERSION: "20.1"
jobs:
build-linux:
@@ -22,9 +23,11 @@ jobs:
- os: ubuntu-24.04
target: x86_64-unknown-linux-gnu
arch: linux-x86_64
llvm: X64
- os: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
arch: linux-aarch64
llvm: ARM64
steps:
- uses: actions/checkout@v4
with:
@@ -33,6 +36,8 @@ jobs:
with:
target: ${{ matrix.target }}
rustflags: ""
- name: Set LLVM_VERSION
run: echo "LLVM_VERSION=$(rustc --version --verbose | grep "LLVM version" | cut -d':' -f2 | xargs)" >> $GITHUB_ENV
- name: Install SDL Dependencies
# https://wiki.libsdl.org/SDL3/README-linux#build-dependencies
uses: awalsh128/cache-apt-pkgs-action@v1
@@ -48,7 +53,8 @@ jobs:
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
version: "${{ env.LLVM_VERSION }}"
version: ${{ env.LLVM_VERSION }}
force-url: https://github.com/llvm/llvm-project/releases/download/llvmorg-${{ env.LLVM_VERSION }}/LLVM-${{ env.LLVM_VERSION }}-Linux-${{ matrix.llvm }}.tar.xz
- name: Build
run: |
cargo build --release -v --target=${{ matrix.target }}
@@ -69,9 +75,11 @@ jobs:
- os: windows-2025
target: x86_64-pc-windows-msvc
arch: windows-x86_64
llvm: win64
#- os: windows-11-arm
# target: aarch64-pc-windows-msvc
# arch: windows-aarch64
# llvm: woa64
steps:
- uses: actions/checkout@v4
with:
@@ -80,27 +88,39 @@ jobs:
with:
target: ${{ matrix.target }}
rustflags: ""
- name: Set LLVM_VERSION
run: |
$llvm_version = rustc --version --verbose | Select-String "LLVM version" | ForEach-Object { $_.Line.Split(":")[1].Trim() }
echo "LLVM_VERSION=$llvm_version" >> $env:GITHUB_ENV
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
version: "${{ env.LLVM_VERSION }}"
version: ${{ env.LLVM_VERSION }}
force-url: https://github.com/llvm/llvm-project/releases/download/llvmorg-${{ env.LLVM_VERSION }}/LLVM-${{ env.LLVM_VERSION }}-${{ matrix.llvm }}.exe
- name: Build
run: |
cargo build --release -v --target=${{ matrix.target }}
mkdir output
cp target/${{ matrix.target }}/release/gopher64.exe output/gopher64-${{ matrix.arch }}.exe
env:
CC: clang-cl
CXX: clang-cl
AR: llvm-lib
- name: Upload file
- name: Upload unsigned artifact
id: upload-unsigned-artifact
uses: actions/upload-artifact@v4
with:
name: gopher64-${{ matrix.arch }}
path: output/gopher64-${{ matrix.arch }}.exe
- name: SignPath
if: ${{ github.ref_type == 'tag' }}
uses: signpath/github-action-submit-signing-request@v1.1
with:
api-token: "${{ secrets.SIGNPATH_API_TOKEN }}"
organization-id: "${{ secrets.SIGNPATH_ORG_ID }}"
project-slug: "gopher64"
artifact-configuration-slug: "gopher64-${{ matrix.arch }}"
signing-policy-slug: "release-signing"
github-artifact-id: "${{ steps.upload-unsigned-artifact.outputs.artifact-id }}"
wait-for-completion: true
build-macos:
if: false
runs-on: macos-15
strategy:
fail-fast: false
@@ -123,6 +143,8 @@ jobs:
cargo build --release -v --target=${{ matrix.target }}
mkdir output
cp target/${{ matrix.target }}/release/gopher64 output/gopher64-${{ matrix.arch }}
env:
AR: ar
- name: Upload file
uses: actions/upload-artifact@v4
with:
+4 -2
View File
@@ -11,7 +11,6 @@ permissions:
env:
CARGO_TERM_COLOR: always
LLVM_VERSION: "20.1"
jobs:
lint-linux:
@@ -23,6 +22,8 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: clippy, rustfmt
- name: Set LLVM_VERSION
run: echo "LLVM_VERSION=$(rustc --version --verbose | grep "LLVM version" | cut -d':' -f2 | xargs)" >> $GITHUB_ENV
- name: Install SDL Dependencies
# https://wiki.libsdl.org/SDL3/README-linux#build-dependencies
uses: awalsh128/cache-apt-pkgs-action@v1
@@ -38,7 +39,8 @@ jobs:
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
version: "${{ env.LLVM_VERSION }}"
version: ${{ env.LLVM_VERSION }}
force-url: https://github.com/llvm/llvm-project/releases/download/llvmorg-${{ env.LLVM_VERSION }}/LLVM-${{ env.LLVM_VERSION }}-Linux-X64.tar.xz
- name: Rustfmt Check
uses: actions-rust-lang/rustfmt@v1
- name: Lint
+2 -1
View File
@@ -1,3 +1,4 @@
[submodule "parallel-rdp/parallel-rdp-standalone"]
path = parallel-rdp/parallel-rdp-standalone
url = https://github.com/Themaister/parallel-rdp-standalone.git
url = https://github.com/gopher64/parallel-rdp-standalone.git
branch = gopher64
Generated
+131 -141
View File
@@ -4,9 +4,9 @@ version = 4
[[package]]
name = "ab_glyph"
version = "0.2.30"
version = "0.2.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0f4f6fbdc5ee39f2ede9f5f3ec79477271a6d6a2baff22310d51736bda6cea"
checksum = "e074464580a518d16a7126262fffaaa47af89d4099d4cb403f8ed938ba12ee7d"
dependencies = [
"ab_glyph_rasterizer",
"owned_ttf_parser",
@@ -226,12 +226,15 @@ dependencies = [
"enumflags2",
"futures-channel",
"futures-util",
"rand 0.9.1",
"rand 0.9.2",
"raw-window-handle",
"serde",
"serde_repr",
"tokio",
"url",
"wayland-backend",
"wayland-client",
"wayland-protocols",
"zbus",
]
@@ -275,9 +278,9 @@ dependencies = [
[[package]]
name = "async-io"
version = "2.4.1"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1237c0ae75a0f3765f58910ff9cdd0a12eeb39ab2f4c7de23262f337f0aacbb3"
checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca"
dependencies = [
"async-lock",
"cfg-if",
@@ -286,10 +289,9 @@ dependencies = [
"futures-lite",
"parking",
"polling",
"rustix 1.0.7",
"rustix 1.0.8",
"slab",
"tracing",
"windows-sys 0.59.0",
"windows-sys 0.60.2",
]
[[package]]
@@ -305,9 +307,9 @@ dependencies = [
[[package]]
name = "async-process"
version = "2.3.1"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cde3f4e40e6021d7acffc90095cbd6dc54cb593903d1de5832f435eb274b85dc"
checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00"
dependencies = [
"async-channel",
"async-io",
@@ -318,8 +320,7 @@ dependencies = [
"cfg-if",
"event-listener",
"futures-lite",
"rustix 1.0.7",
"tracing",
"rustix 1.0.8",
]
[[package]]
@@ -335,9 +336,9 @@ dependencies = [
[[package]]
name = "async-signal"
version = "0.2.11"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7605a4e50d4b06df3898d5a70bf5fde51ed9059b0434b73105193bc27acce0d"
checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1"
dependencies = [
"async-io",
"async-lock",
@@ -345,10 +346,10 @@ dependencies = [
"cfg-if",
"futures-core",
"futures-io",
"rustix 1.0.7",
"rustix 1.0.8",
"signal-hook-registry",
"slab",
"windows-sys 0.59.0",
"windows-sys 0.60.2",
]
[[package]]
@@ -600,9 +601,9 @@ dependencies = [
[[package]]
name = "bytemuck_derive"
version = "1.9.3"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1"
checksum = "441473f2b4b0459a68628c744bc61d23e730fb00128b841d30fa4bb3972257e4"
dependencies = [
"proc-macro2",
"quote",
@@ -629,21 +630,11 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "bzip2"
version = "0.5.2"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
checksum = "bea8dcd42434048e4f7a304411d9273a411f647446c1234a65ce0554923f4cff"
dependencies = [
"bzip2-sys",
]
[[package]]
name = "bzip2-sys"
version = "0.1.13+1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
dependencies = [
"cc",
"pkg-config",
"libbz2-rs-sys",
]
[[package]]
@@ -687,9 +678,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.29"
version = "1.2.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
dependencies = [
"jobserver",
"libc",
@@ -779,9 +770,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.40"
version = "4.5.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
dependencies = [
"clap_builder",
"clap_derive",
@@ -789,9 +780,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.40"
version = "4.5.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
dependencies = [
"anstream",
"anstyle",
@@ -801,9 +792,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.40"
version = "4.5.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
dependencies = [
"heck",
"proc-macro2",
@@ -819,9 +810,9 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "clipboard-win"
version = "5.4.0"
version = "5.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892"
checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4"
dependencies = [
"error-code",
]
@@ -1050,9 +1041,9 @@ dependencies = [
[[package]]
name = "crc32fast"
version = "1.4.2"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
@@ -1247,18 +1238,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "dispatch2"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a0d569e003ff27784e0e14e4a594048698e0c0f0b66cabcb51511be55a7caa0"
dependencies = [
"bitflags 2.9.1",
"block2 0.6.1",
"libc",
"objc2 0.6.1",
]
[[package]]
name = "dispatch2"
version = "0.3.0"
@@ -1266,6 +1245,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
dependencies = [
"bitflags 2.9.1",
"block2 0.6.1",
"libc",
"objc2 0.6.1",
]
@@ -1898,7 +1879,7 @@ dependencies = [
"bitflags 2.9.1",
"cfg_aliases",
"cgl",
"dispatch2 0.3.0",
"dispatch2",
"glutin_egl_sys",
"glutin_glx_sys",
"glutin_wgl_sys",
@@ -1957,7 +1938,7 @@ dependencies = [
[[package]]
name = "gopher64"
version = "1.0.20"
version = "1.1.1"
dependencies = [
"ab_glyph",
"bindgen 0.72.0",
@@ -2010,7 +1991,7 @@ dependencies = [
"parking_lot",
"portable-atomic",
"quanta",
"rand 0.9.1",
"rand 0.9.2",
"smallvec",
"spinning_top",
"web-time",
@@ -2198,9 +2179,9 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.14"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
dependencies = [
"base64",
"bytes",
@@ -2214,7 +2195,7 @@ dependencies = [
"libc",
"percent-encoding",
"pin-project-lite",
"socket2 0.5.10",
"socket2 0.6.0",
"tokio",
"tower-service",
"tracing",
@@ -2695,9 +2676,9 @@ dependencies = [
[[package]]
name = "io-uring"
version = "0.7.8"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4"
dependencies = [
"bitflags 2.9.1",
"cfg-if",
@@ -2845,11 +2826,12 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "kurbo"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1077d333efea6170d9ccb96d3c3026f300ca0773da4938cc4c811daa6df68b0c"
checksum = "c62026ae44756f8a599ba21140f350303d4f08dcdcc71b5ad9c9bb8128c13c62"
dependencies = [
"arrayvec",
"euclid",
"smallvec",
]
@@ -2865,6 +2847,12 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
[[package]]
name = "libbz2-rs-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "775bf80d5878ab7c2b1080b5351a48b2f737d9f6f8b383574eebcc22be0dfccb"
[[package]]
name = "libc"
version = "0.2.174"
@@ -2929,13 +2917,13 @@ dependencies = [
[[package]]
name = "libredox"
version = "0.1.4"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638"
checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0"
dependencies = [
"bitflags 2.9.1",
"libc",
"redox_syscall 0.5.13",
"redox_syscall 0.5.15",
]
[[package]]
@@ -3085,12 +3073,9 @@ dependencies = [
[[package]]
name = "lzma-rust2"
version = "0.2.2"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e004a649120b31c06728257815826e075f638502ba49a9677c3c112e324e044d"
dependencies = [
"byteorder",
]
checksum = "900106b40381855c6acce992ac062513da7fa4acdb0a9324201da616d4812953"
[[package]]
name = "maybe-rayon"
@@ -3110,9 +3095,9 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "memmap2"
version = "0.9.5"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28"
dependencies = [
"libc",
]
@@ -3462,7 +3447,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
dependencies = [
"bitflags 2.9.1",
"dispatch2 0.3.0",
"dispatch2",
"objc2 0.6.1",
]
@@ -3473,7 +3458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4"
dependencies = [
"bitflags 2.9.1",
"dispatch2 0.3.0",
"dispatch2",
"objc2 0.6.1",
"objc2-core-foundation",
"objc2-io-surface",
@@ -3733,9 +3718,9 @@ dependencies = [
[[package]]
name = "owned_ttf_parser"
version = "0.25.0"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4"
checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b"
dependencies = [
"ttf-parser 0.25.1",
]
@@ -3764,7 +3749,7 @@ checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.5.13",
"redox_syscall 0.5.15",
"smallvec",
"windows-targets 0.52.6",
]
@@ -3882,17 +3867,16 @@ dependencies = [
[[package]]
name = "polling"
version = "3.8.0"
version = "3.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b53a684391ad002dd6a596ceb6c74fd004fdce75f4be2e3f615068abbea5fd50"
checksum = "8ee9b2fa7a4517d2c91ff5bc6c297a427a96749d15f98fcdbb22c05571a4d4b7"
dependencies = [
"cfg-if",
"concurrent-queue",
"hermit-abi 0.5.2",
"pin-project-lite",
"rustix 1.0.7",
"tracing",
"windows-sys 0.59.0",
"rustix 1.0.8",
"windows-sys 0.60.2",
]
[[package]]
@@ -3912,9 +3896,9 @@ dependencies = [
[[package]]
name = "postcard"
version = "1.1.2"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c1de96e20f51df24ca73cafcc4690e044854d803259db27a00a461cb3b9d17a"
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
dependencies = [
"cobs",
"embedded-io 0.4.0",
@@ -3938,6 +3922,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppmd-rust"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c834641d8ad1b348c9ee86dec3b9840d805acd5f24daa5f90c788951a52ff59b"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
@@ -3949,9 +3939,9 @@ dependencies = [
[[package]]
name = "prettyplease"
version = "0.2.35"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a"
checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2"
dependencies = [
"proc-macro2",
"syn",
@@ -4062,7 +4052,7 @@ dependencies = [
"bytes",
"getrandom 0.3.3",
"lru-slab",
"rand 0.9.1",
"rand 0.9.2",
"ring",
"rustc-hash 2.1.1",
"rustls",
@@ -4116,9 +4106,9 @@ dependencies = [
[[package]]
name = "rand"
version = "0.9.1"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
@@ -4270,9 +4260,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.5.13"
version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
checksum = "7e8af0dde094006011e6a740d4879319439489813bd0bcdc7d821beaeeff48ec"
dependencies = [
"bitflags 2.9.1",
]
@@ -4377,13 +4367,13 @@ dependencies = [
[[package]]
name = "rfd"
version = "0.15.3"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80c844748fdc82aae252ee4594a89b6e7ebef1063de7951545564cbc4e57075d"
checksum = "ef2bee61e6cffa4635c72d7d81a84294e28f0930db0ddcb0f66d10244674ebed"
dependencies = [
"ashpd",
"block2 0.6.1",
"dispatch2 0.2.0",
"dispatch2",
"js-sys",
"log",
"objc2 0.6.1",
@@ -4401,9 +4391,9 @@ dependencies = [
[[package]]
name = "rgb"
version = "0.8.51"
version = "0.8.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a457e416a0f90d246a4c3288bd7a25b2304ca727f253f95be383dd17af56be8f"
checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce"
dependencies = [
"bytemuck",
]
@@ -4488,22 +4478,22 @@ dependencies = [
[[package]]
name = "rustix"
version = "1.0.7"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
dependencies = [
"bitflags 2.9.1",
"errno",
"libc",
"linux-raw-sys 0.9.4",
"windows-sys 0.59.0",
"windows-sys 0.60.2",
]
[[package]]
name = "rustls"
version = "0.23.28"
version = "0.23.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643"
checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1"
dependencies = [
"once_cell",
"ring",
@@ -4525,9 +4515,9 @@ dependencies = [
[[package]]
name = "rustls-webpki"
version = "0.103.3"
version = "0.103.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435"
checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc"
dependencies = [
"ring",
"rustls-pki-types",
@@ -4606,15 +4596,15 @@ dependencies = [
[[package]]
name = "sdl3-src"
version = "3.2.16"
version = "3.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5b5d192485408fa251477ea1dfb4778d864efaec72f730ce3a753deaffb27bb"
checksum = "c9b802554a6d768330a2c9cd30849811676da53bda1b5bb78dfd3a402ca6b55f"
[[package]]
name = "sdl3-sys"
version = "0.5.2+SDL3-3.2.16"
version = "0.5.3+SDL3-3.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0a31799d7cbd36f2b187c32a56975fbdd371c200a91b01d4ed0faf0012bcf9c"
checksum = "573534f614334b7bb6f7bceae86448764fcdcafe92d75482092810cc664ece8c"
dependencies = [
"cmake",
"rpkg-config",
@@ -4658,9 +4648,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.140"
version = "1.0.141"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
dependencies = [
"itoa",
"memchr",
@@ -4702,9 +4692,9 @@ dependencies = [
[[package]]
name = "sevenz-rust2"
version = "0.16.0"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5375315e26d60d20f13d74c5bb0b6b627d334b68aa63f0d6d33d828af499d8d2"
checksum = "b4f9cf03fd1a56301a078ffb13856eeca76514626d78d059ecc598998194679e"
dependencies = [
"byteorder",
"crc32fast",
@@ -4967,7 +4957,7 @@ dependencies = [
"objc2-foundation 0.2.2",
"objc2-quartz-core 0.2.2",
"raw-window-handle",
"redox_syscall 0.5.13",
"redox_syscall 0.5.15",
"rustix 0.38.44",
"tiny-xlib",
"wasm-bindgen",
@@ -5044,23 +5034,22 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "strum"
version = "0.27.1"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.27.1"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
@@ -5159,7 +5148,7 @@ dependencies = [
"fastrand",
"getrandom 0.3.3",
"once_cell",
"rustix 1.0.7",
"rustix 1.0.8",
"windows-sys 0.59.0",
]
@@ -5528,7 +5517,7 @@ dependencies = [
"http",
"httparse",
"log",
"rand 0.9.1",
"rand 0.9.2",
"sha1",
"thiserror 2.0.12",
"utf-8",
@@ -5990,9 +5979,9 @@ dependencies = [
[[package]]
name = "webpki-roots"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502"
checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2"
dependencies = [
"rustls-pki-types",
]
@@ -6486,18 +6475,18 @@ dependencies = [
[[package]]
name = "winnow"
version = "0.7.11"
version = "0.7.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
dependencies = [
"memchr",
]
[[package]]
name = "winresource"
version = "0.1.22"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a179ac8923651ff1d15efbee760b4dd3679fd85fa5a8b2bb1109b7248f80e30f"
checksum = "edcacf11b6f48dd21b9ba002f991bdd5de29b2da8cc2800412f4b80f677e4957"
dependencies = [
"toml",
"version_check",
@@ -6576,7 +6565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909"
dependencies = [
"libc",
"rustix 1.0.7",
"rustix 1.0.8",
]
[[package]]
@@ -6617,9 +6606,9 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
[[package]]
name = "xml-rs"
version = "0.8.26"
version = "0.8.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda"
checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7"
[[package]]
name = "xmlwriter"
@@ -6653,9 +6642,9 @@ dependencies = [
[[package]]
name = "zbus"
version = "5.7.1"
version = "5.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3a7c7cee313d044fca3f48fa782cb750c79e4ca76ba7bc7718cd4024cdf6f68"
checksum = "4bb4f9a464286d42851d18a605f7193b8febaf5b0919d71c6399b7b26e5b0aad"
dependencies = [
"async-broadcast",
"async-executor",
@@ -6687,9 +6676,9 @@ dependencies = [
[[package]]
name = "zbus_macros"
version = "5.7.1"
version = "5.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a17e7e5eec1550f747e71a058df81a9a83813ba0f6a95f39c4e218bdc7ba366a"
checksum = "ef9859f68ee0c4ee2e8cde84737c78e3f4c54f946f2a38645d0d4c7a95327659"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -6808,9 +6797,9 @@ dependencies = [
[[package]]
name = "zip"
version = "4.2.0"
version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95ab361742de920c5535880f89bbd611ee62002bf11341d16a5f057bb8ba6899"
checksum = "9aed4ac33e8eb078c89e6cbb1d5c4c7703ec6d299fc3e7c3695af8f8b423468b"
dependencies = [
"aes",
"arbitrary",
@@ -6825,6 +6814,7 @@ dependencies = [
"liblzma",
"memchr",
"pbkdf2",
"ppmd-rust",
"sha1",
"time",
"zeroize",
@@ -6904,9 +6894,9 @@ dependencies = [
[[package]]
name = "zvariant"
version = "5.5.3"
version = "5.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d30786f75e393ee63a21de4f9074d4c038d52c5b1bb4471f955db249f9dffb1"
checksum = "d91b3680bb339216abd84714172b5138a4edac677e641ef17e1d8cb1b3ca6e6f"
dependencies = [
"endi",
"enumflags2",
@@ -6919,9 +6909,9 @@ dependencies = [
[[package]]
name = "zvariant_derive"
version = "5.5.3"
version = "5.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75fda702cd42d735ccd48117b1630432219c0e9616bf6cb0f8350844ee4d9580"
checksum = "3a8c68501be459a8dbfffbe5d792acdd23b4959940fc87785fb013b32edbc208"
dependencies = [
"proc-macro-crate",
"proc-macro2",
+3 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "gopher64"
version = "1.0.20"
version = "1.1.1"
edition = "2024"
rust-version = "1.88"
@@ -8,9 +8,9 @@ rust-version = "1.88"
[dependencies]
dirs = "6.0"
zip = "4.2"
zip = "4.3"
governor = "0.10"
sevenz-rust2 = { version = "0.16", default-features = false }
sevenz-rust2 = { version = "0.17", default-features = false }
chrono = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
+7 -11
View File
@@ -3,7 +3,7 @@
Windows: https://github.com/gopher64/gopher64/releases/latest/download/gopher64-windows-x86_64.exe
Linux: https://github.com/gopher64/gopher64/releases/latest/download/gopher64-linux-x86_64
Linux: https://flathub.org/apps/io.github.gopher64.gopher64
## wiki
@@ -17,10 +17,6 @@ https://discord.gg/9RGXq8W8JQ
Keys are mapped according to [these defaults](https://github.com/gopher64/gopher64/wiki/Default-Keyboard-Setup). Xbox-style controllers also have a [default mapping applied](https://github.com/gopher64/gopher64/wiki/Default-Gamepad-Setup).
You can create your mappings by running `./gopher64 --configure-input-profile my_profile`. You then bind that profile to a port: `./gopher64 --bind-input-profile my_profile --port 1`
To use a controller (for example, an Xbox controller), run `./gopher64 --list-controllers` to get a list of attached controllers, and then assign it by doing `./gopher64 --assign-controller <controller_number> --port 1`
## netplay
Gopher64 supports netplay (online play with others). It has a few public netplay servers. If you are interested in running a public netplay server, please let me know (open an issue or discussion or contact me on Discord). You can also run the server (https://github.com/gopher64/gopher64-netplay-server) yourself on a LAN.
@@ -37,12 +33,6 @@ If you want to run the flatpak from the command line, you need to add the `--fil
flatpak run --filesystem=host:ro io.github.gopher64.gopher64 /path/to/rom.z64
```
## goals
1. Performance. I want to be able to use this emulator on my laptop.
2. Easy to use.
3. Easy to work on. Dynamic recompilers perform well, but they are very hard to read and understand. This emulator will only have interpreters for the CPU and RSP. Additionally, it is completely written in Rust (besides Parallel-RDP), a modern programming language with a growing user base. I've tried to avoid the use of macros, which can reduce some repetitiveness in the code but also reduce readability.
## building and usage
1. Linux only: install the SDL3 dependencies: https://wiki.libsdl.org/SDL3/README-linux#build-dependencies
@@ -59,3 +49,9 @@ I am very open to contributions! Please contact me via a GitHub issue or Discord
## license
Gopher64 is licensed under the GPLv3 license. Many portions of gopher64 have been adapted from mupen64plus and/or ares. The license for mupen64plus can be found here: https://github.com/mupen64plus/mupen64plus-core/blob/master/LICENSES. The license for ares can be found here: https://github.com/ares-emulator/ares/blob/master/LICENSE.
## privacy and code signing policy
Free code signing for the Windows release is provided by [SignPath.io](https://about.signpath.io), certificate by [SignPath Foundation](https://signpath.org).
During online netplay sessions, the server logs your IP address and basic session information (game title and session name) for operational purposes. No additional personal data is collected or stored.
+31 -16
View File
@@ -6,10 +6,17 @@ fn main() {
slint_build::compile_with_config("src/ui/gui/appwindow.slint", slint_config).unwrap();
let mut simd_build = cc::Build::new();
let mut volk_build = cc::Build::new();
volk_build
.std("c17")
.include("parallel-rdp/parallel-rdp-standalone/vulkan-headers/include")
.file("parallel-rdp/parallel-rdp-standalone/volk/volk.c");
let mut rdp_build = cc::Build::new();
rdp_build
.cpp(true)
.warnings(false)
.std("c++23")
.flag("-Wno-unused-parameter")
.flag("-Wno-missing-field-initializers")
.file("parallel-rdp/parallel-rdp-standalone/parallel-rdp/command_ring.cpp")
.file("parallel-rdp/parallel-rdp-standalone/parallel-rdp/rdp_device.cpp")
.file("parallel-rdp/parallel-rdp-standalone/parallel-rdp/rdp_dump_write.cpp")
@@ -29,6 +36,7 @@ fn main() {
.file("parallel-rdp/parallel-rdp-standalone/vulkan/image.cpp")
.file("parallel-rdp/parallel-rdp-standalone/vulkan/indirect_layout.cpp")
.file("parallel-rdp/parallel-rdp-standalone/vulkan/memory_allocator.cpp")
.file("parallel-rdp/parallel-rdp-standalone/vulkan/pipeline_cache.cpp")
.file("parallel-rdp/parallel-rdp-standalone/vulkan/pipeline_event.cpp")
.file("parallel-rdp/parallel-rdp-standalone/vulkan/query_pool.cpp")
.file("parallel-rdp/parallel-rdp-standalone/vulkan/render_pass.cpp")
@@ -46,7 +54,6 @@ fn main() {
.file("parallel-rdp/parallel-rdp-standalone/util/timeline_trace_file.cpp")
.file("parallel-rdp/parallel-rdp-standalone/util/environment.cpp")
.file("parallel-rdp/parallel-rdp-standalone/util/thread_name.cpp")
.file("parallel-rdp/parallel-rdp-standalone/volk/volk.c")
.file("parallel-rdp/interface.cpp")
.file("parallel-rdp/wsi_platform.cpp")
.include("parallel-rdp/parallel-rdp-standalone/parallel-rdp")
@@ -62,26 +69,34 @@ fn main() {
let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let profile = std::env::var("PROFILE").unwrap();
if arch == "x86_64" {
rdp_build.flag("-march=x86-64-v3");
let opt_flag = if arch == "x86_64" {
"-march=x86-64-v3"
} else if arch == "aarch64" {
rdp_build.flag("-march=armv8.2-a");
simd_build.flag("-march=armv8.2-a");
"-march=armv8.2-a"
} else {
panic!("unknown arch")
}
};
volk_build.flag(opt_flag);
rdp_build.flag(opt_flag);
simd_build.flag(opt_flag);
if os == "windows" {
volk_build.flag("-DVK_USE_PLATFORM_WIN32_KHR");
rdp_build.flag("-DVK_USE_PLATFORM_WIN32_KHR");
winresource::WindowsResource::new()
.set_icon("data/icon.ico")
.set_icon("data/icon/icon.ico")
.compile()
.unwrap();
}
if profile == "release" {
volk_build.flag("-flto=thin");
rdp_build.flag("-flto=thin");
simd_build.flag("-flto=thin");
}
volk_build.compile("volk");
rdp_build.compile("parallel-rdp");
let out_path = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
@@ -153,14 +168,14 @@ fn main() {
.write_to_file(out_path.join("simd_bindings.rs"))
.expect("Couldn't write bindings!");
simd_build.flag("-DSSE2NEON_SUPPRESS_WARNINGS");
simd_build.file("src/compat/aarch64.c");
simd_build.file(std::env::temp_dir().join("bindgen").join("extern.c"));
simd_build.include(".");
if profile == "release" {
simd_build.flag("-flto=thin");
}
simd_build.compile("simd");
simd_build
.std("c17")
.flag("-D_POSIX_C_SOURCE=200112L")
.flag("-DSSE2NEON_SUPPRESS_WARNINGS")
.file("src/compat/aarch64.c")
.file(std::env::temp_dir().join("bindgen").join("extern.c"))
.include(".")
.compile("simd");
}
let git_output = std::process::Command::new("git")
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 79 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
magick gopher64.png -resize 512x512 gopher64_512x512.png
magick gopher64.png -resize 256x256 gopher64_256x256.png
magick gopher64.png -resize 128x128 gopher64_128x128.png
magick gopher64.png -resize 256x256 icon.ico
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

+19 -1
View File
@@ -58,6 +58,8 @@ typedef struct
int cmd_cur;
int cmd_ptr;
uint32_t region;
uint64_t vi_counter;
uint64_t last_sync;
} RDP_DEVICE;
static SDL_Window *window;
@@ -149,6 +151,7 @@ bool sdl_event_filter(void *userdata, SDL_Event *event)
{
if (event->type == SDL_EVENT_WINDOW_CLOSE_REQUESTED)
{
callback.paused = false;
callback.emu_running = false;
}
else if (event->type == SDL_EVENT_WINDOW_RESIZED && callback.emu_running)
@@ -172,6 +175,12 @@ bool sdl_event_filter(void *userdata, SDL_Event *event)
callback.enable_speedlimiter = !callback.enable_speedlimiter;
}
break;
case SDL_SCANCODE_P:
if (event->key.mod & SDL_KMOD_ALT)
{
callback.paused = !callback.paused;
}
break;
case SDL_SCANCODE_ESCAPE:
if (gfx_info.fullscreen)
callback.emu_running = false;
@@ -225,7 +234,10 @@ void rdp_new_processor(GFX_INFO _gfx_info)
void rdp_init(void *_window, GFX_INFO _gfx_info)
{
memset(&rdp_device, 0, sizeof(RDP_DEVICE));
window = (SDL_Window *)_window;
SDL_SyncWindow(window);
bool result = SDL_AddEventWatch(sdl_event_filter, nullptr);
if (!result)
{
@@ -276,6 +288,7 @@ void rdp_init(void *_window, GFX_INFO _gfx_info)
callback.emu_running = true;
callback.enable_speedlimiter = true;
callback.paused = false;
crop_letterbox = false;
}
@@ -435,6 +448,7 @@ void rdp_update_screen()
render_frame(device);
wsi->end_frame();
wsi->begin_frame();
rdp_device.vi_counter += 1;
}
CALL_BACK rdp_check_callback()
@@ -542,7 +556,11 @@ uint64_t rdp_process_commands()
break;
}
case RDP::Op::SyncFull:
processor->wait_for_timeline(processor->signal_timeline());
if (rdp_device.last_sync != rdp_device.vi_counter)
{
processor->wait_for_timeline(processor->signal_timeline());
rdp_device.last_sync = rdp_device.vi_counter;
}
interrupt_timer = rdp_device.region;
if (interrupt_timer == 0)
interrupt_timer = 5000;
+1
View File
@@ -33,6 +33,7 @@ extern "C"
bool enable_speedlimiter;
bool lower_volume;
bool raise_volume;
bool paused;
} CALL_BACK;
void rdp_init(void *_window, GFX_INFO _gfx_info);
-1
View File
@@ -56,7 +56,6 @@ bool SDL_WSIPlatform::alive(Vulkan::WSI &wsi)
void SDL_WSIPlatform::poll_input()
{
SDL_PumpEvents();
}
void SDL_WSIPlatform::poll_input_async(Granite::InputTrackerHandler *handler)
+2 -7
View File
@@ -50,9 +50,7 @@ pub fn read_mem(
}
pub fn write_mem(device: &mut device::Device, address: u64, value: u32, mask: u32) {
if device.cart.sc64.cfg[device::cart::sc64::SC64_ROM_WRITE_ENABLE as usize] != 0
&& device.cart.sc64.cfg[device::cart::sc64::SC64_BOOTLOADER_SWITCH as usize] == 0
{
if device.cart.sc64.cfg[device::cart::sc64::SC64_ROM_WRITE_ENABLE as usize] != 0 {
let masked_address = address as usize & CART_MASK;
let mut data = read_cart_word(device, masked_address);
device::memory::masked_write_32(&mut data, value, mask);
@@ -82,9 +80,7 @@ pub fn dma_read(
mut dram_addr: u32,
length: u32,
) -> u64 {
if device.cart.sc64.cfg[device::cart::sc64::SC64_ROM_WRITE_ENABLE as usize] != 0
&& device.cart.sc64.cfg[device::cart::sc64::SC64_BOOTLOADER_SWITCH as usize] == 0
{
if device.cart.sc64.cfg[device::cart::sc64::SC64_ROM_WRITE_ENABLE as usize] != 0 {
dram_addr &= device::rdram::RDRAM_MASK as u32;
cart_addr &= CART_MASK as u32;
@@ -193,7 +189,6 @@ fn set_cic(device: &mut device::Device) {
"53C0088FB777870D0AF32F0251E964030E2E8B72E830C26042FD191169508C05" => {
device.cart.cic_seed = 0xdd; // CicNus5167
device.cart.sc64.cfg[device::cart::sc64::SC64_ROM_WRITE_ENABLE as usize] = 1;
device.cart.sc64.cfg[device::cart::sc64::SC64_BOOTLOADER_SWITCH as usize] = 0;
}
_ => {
device.cart.cic_seed = 0x3F; // CicNus6102
+37 -32
View File
@@ -155,24 +155,26 @@ pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u
let mut i = 0;
while i < length {
if offset + i < device.ui.storage.saves.sdcard.data.len() {
let data = u32::from_be_bytes(
device.ui.storage.saves.sdcard.data
[(offset + i)..(offset + i + 4)]
.try_into()
.unwrap(),
);
let data = u32::from_be_bytes(
device
.ui
.storage
.saves
.sdcard
.data
.get((offset + i)..(offset + i + 4))
.unwrap_or(&[0; 4])
.try_into()
.unwrap_or_default(),
);
device::memory::data_write(
device,
address + i as u64,
data,
0xFFFFFFFF,
false,
);
} else {
panic!("sd card read out of bounds")
}
device::memory::data_write(
device,
address + i as u64,
data,
0xFFFFFFFF,
false,
);
i += 4;
}
}
@@ -187,19 +189,22 @@ pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u
let mut i = 0;
while i < length {
if offset + i < device.ui.storage.saves.sdcard.data.len() {
let data = device::memory::data_read(
device,
address + i as u64,
device::memory::AccessSize::Word,
false,
)
.to_be_bytes();
device.ui.storage.saves.sdcard.data[(offset + i)..(offset + i + 4)]
.copy_from_slice(&data);
} else {
panic!("sd card write out of bounds")
}
let data = device::memory::data_read(
device,
address + i as u64,
device::memory::AccessSize::Word,
false,
)
.to_be_bytes();
device
.ui
.storage
.saves
.sdcard
.data
.get_mut((offset + i)..(offset + i + 4))
.unwrap_or(&mut [0; 4])
.copy_from_slice(&data);
i += 4;
}
device.ui.storage.saves.sdcard.written = true;
@@ -309,7 +314,7 @@ pub fn dma_read(
let mut j = cart_addr;
while i < dram_addr + length {
buffer[j as usize] = *device
*buffer.get_mut(j as usize).unwrap_or(&mut 0) = *device
.rdram
.mem
.get(i as usize ^ device.byte_swap)
@@ -344,7 +349,7 @@ pub fn dma_write(
.rdram
.mem
.get_mut(i as usize ^ device.byte_swap)
.unwrap_or(&mut 0) = buffer[j as usize];
.unwrap_or(&mut 0) = *buffer.get(j as usize).unwrap_or(&0);
i += 1;
j += 1;
}
+16 -2
View File
@@ -151,7 +151,14 @@ fn dma_read_sram(device: &mut device::Device, mut cart_addr: u32, mut dram_addr:
format_sram(device);
while i < dram_addr + length {
device.ui.storage.saves.sram.data[j as usize] = *device
*device
.ui
.storage
.saves
.sram
.data
.get_mut(j as usize)
.unwrap_or(&mut 0) = *device
.rdram
.mem
.get(i as usize ^ device.byte_swap)
@@ -217,7 +224,14 @@ fn dma_write_sram(
.rdram
.mem
.get_mut(i as usize ^ device.byte_swap)
.unwrap_or(&mut 0) = device.ui.storage.saves.sram.data[j as usize];
.unwrap_or(&mut 0) = *device
.ui
.storage
.saves
.sram
.data
.get(j as usize)
.unwrap_or(&0);
i += 1;
j += 1;
}
+3 -3
View File
@@ -33,7 +33,7 @@ pub fn read_mem_fast(
.rdram
.mem
.get(masked_address..masked_address + 4)
.unwrap_or_default()
.unwrap_or(&[0; 4])
.try_into()
.unwrap_or_default(),
)
@@ -55,7 +55,7 @@ pub fn read_mem(
.rdram
.mem
.get(masked_address..masked_address + 4)
.unwrap_or_default()
.unwrap_or(&[0; 4])
.try_into()
.unwrap_or_default(),
)
@@ -67,7 +67,7 @@ pub fn write_mem(device: &mut device::Device, address: u64, value: u32, mask: u3
.rdram
.mem
.get(address as usize..(address + 4) as usize)
.unwrap_or_default()
.unwrap_or(&[0; 4])
.try_into()
.unwrap_or_default(),
);
+1 -1
View File
@@ -180,7 +180,7 @@ fn do_dma(device: &mut device::Device, dma: RspDma) {
.rdram
.mem
.get(dram_addr as usize..dram_addr as usize + 4)
.unwrap_or_default()
.unwrap_or(&[0; 4])
.try_into()
.unwrap_or_default(),
);
+1 -1
View File
@@ -90,7 +90,7 @@ fn copy_pif_rdram(device: &mut device::Device) {
.rdram
.mem
.get(dram_addr + i..dram_addr + i + 4)
.unwrap_or_default()
.unwrap_or(&[0; 4])
.try_into()
.unwrap_or_default(),
);
+2 -2
View File
@@ -192,8 +192,8 @@ pub fn load_savestate(device: &mut device::Device) {
}
}
ui::audio::close(&mut device.ui);
ui::audio::init(&mut device.ui, device.ai.freq);
ui::audio::close_game_audio(&mut device.ui);
ui::audio::init_game_audio(&mut device.ui, device.ai.freq);
ui::video::load_state(device, rdp_state.as_ptr());
println!(
"Savestate loaded from {}",
+12 -4
View File
@@ -15,10 +15,18 @@ pub type Cheats = std::collections::BTreeMap<String, std::collections::BTreeMap<
pub fn cheats_window(app: &AppWindow) {
let weak = app.as_weak();
app.on_cheats_select_rom_clicked(move || {
let select_rom = rfd::AsyncFileDialog::new()
.set_title("Select ROM")
.pick_file();
app.on_cheats_select_rom_clicked(move |rom_dir| {
let select_rom = if !rom_dir.is_empty()
&& let Ok(exists) = std::fs::exists(&rom_dir)
&& exists
{
rfd::AsyncFileDialog::new().set_directory(rom_dir)
} else {
rfd::AsyncFileDialog::new()
}
.set_title("Select ROM")
.add_filter("ROM files", &ui::gui::N64_EXTENSIONS)
.pick_file();
let weak = weak.clone();
tokio::spawn(async move {
if let Some(file) = select_rom.await
+2
View File
@@ -67,6 +67,7 @@ pub struct Config {
pub input: Input,
pub video: Video,
pub emulation: Emulation,
pub rom_dir: std::path::PathBuf,
}
impl Drop for Cheats {
@@ -150,6 +151,7 @@ impl Config {
overclock: false,
disable_expansion_pak: false,
},
rom_dir: std::path::PathBuf::new(),
}
}
}
+29 -5
View File
@@ -5,6 +5,8 @@ use slint::Model;
slint::include_modules!();
pub const N64_EXTENSIONS: [&str; 5] = ["n64", "v64", "z64", "7z", "zip"];
#[derive(serde::Deserialize)]
struct GithubData {
tag_name: String,
@@ -101,6 +103,10 @@ fn settings_window(app: &AppWindow, config: &ui::config::Config) {
_ => 0,
};
app.set_resolution(combobox_value);
if let Some(rom_dir_str) = config.rom_dir.to_str() {
app.set_rom_dir(rom_dir_str.into());
}
}
fn update_input_profiles(weak: &slint::Weak<AppWindow>, config: &ui::config::Config) {
@@ -351,6 +357,7 @@ pub fn run_rom(
.unwrap();
let mut device = device::Device::new();
device.ui.config.rom_dir = file_path.parent().unwrap().to_path_buf();
for i in 0..4 {
if gb_paths.rom[i].is_some() && gb_paths.ram[i].is_some() {
@@ -390,16 +397,31 @@ pub fn run_rom(
vru_window_notifier.try_send(None).unwrap();
}
weak.upgrade_in_event_loop(move |handle| handle.set_game_running(false))
.unwrap();
let rom_dir = device.ui.config.rom_dir.clone();
weak.upgrade_in_event_loop(move |handle| {
if let Some(rom_dir_str) = rom_dir.to_str() {
handle.set_rom_dir(rom_dir_str.into());
}
handle.set_game_running(false);
})
.unwrap();
})
.unwrap();
}
fn open_rom(app: &AppWindow) {
let select_rom = rfd::AsyncFileDialog::new()
.set_title("Select ROM")
.pick_file();
let rom_dir = app.get_rom_dir();
let select_rom = if !rom_dir.is_empty()
&& let Ok(exists) = std::fs::exists(&rom_dir)
&& exists
{
rfd::AsyncFileDialog::new().set_directory(rom_dir)
} else {
rfd::AsyncFileDialog::new()
}
.set_title("Select ROM")
.add_filter("ROM files", &N64_EXTENSIONS)
.pick_file();
let mut select_gb_rom = [None, None, None, None];
let mut select_gb_ram = [None, None, None, None];
@@ -408,11 +430,13 @@ fn open_rom(app: &AppWindow) {
select_gb_rom[i] = Some(
rfd::AsyncFileDialog::new()
.set_title(format!("GB ROM P{}", i + 1))
.add_filter("GB ROM files", &["gb", "gbc"])
.pick_file(),
);
select_gb_ram[i] = Some(
rfd::AsyncFileDialog::new()
.set_title(format!("GB RAM P{}", i + 1))
.add_filter("GB RAM files", &["sav", "ram"])
.pick_file(),
);
}
+6 -4
View File
@@ -14,6 +14,7 @@ export { VruDialog } from "vru_dialog.slint";
export { NetplayCreate } from "netplay_create.slint";
export { NetplayJoin } from "netplay_join.slint";
export { NetplayWait } from "netplay_wait.slint";
export { CustomNetplayServer } from "netplay_page.slint";
export component AppWindow inherits Window {
callback wiki_button_clicked;
@@ -29,7 +30,7 @@ export component AppWindow inherits Window {
callback join_session_button_clicked;
callback netplay_discord_button_clicked;
callback netplay_feedback_button_clicked;
callback cheats_select_rom_clicked;
callback cheats_select_rom_clicked(string);
callback cheats_clear_clicked;
callback cheat_toggled(string, string, string, bool);
in property version <=> AboutData.version;
@@ -41,6 +42,7 @@ export component AppWindow inherits Window {
in-out property overclock_n64_cpu <=> SettingsData.overclock_n64_cpu;
in-out property disable_expansion_pak <=> SettingsData.disable_expansion_pak;
in-out property resolution <=> SettingsData.resolution;
in-out property rom_dir <=> SettingsData.rom_dir;
in-out property emulate_vru <=> ControllerData.emulate_vru;
in-out property controller_enabled <=> ControllerData.controller_enabled;
in-out property transferpak <=> ControllerData.transferpak;
@@ -56,7 +58,7 @@ export component AppWindow inherits Window {
preferred-width: 700px;
preferred-height: 500px;
title: @tr("Gopher64");
icon: @image-url("../../../data/gopher64.png");
icon: @image-url("../../../data/icon/gopher64.png");
HorizontalLayout {
side-bar := SideBar {
@@ -102,8 +104,8 @@ export component AppWindow inherits Window {
}
}
if(side-bar.current-item == 3): Cheats {
cheats_select_rom_clicked => {
cheats_select_rom_clicked();
cheats_select_rom_clicked(rom_dir) => {
cheats_select_rom_clicked(rom_dir);
}
cheats_clear_clicked => {
cheats_clear_clicked();
+4 -3
View File
@@ -3,6 +3,7 @@
import { ListView, HorizontalBox, VerticalBox, Button, GroupBox, CheckBox } from "std-widgets.slint";
import { Page } from "page.slint";
import { SettingsData } from "settings_page.slint";
export global CheatsData {
in-out property <string> cheat_game_name;
@@ -12,7 +13,7 @@ export global CheatsData {
export component Cheats inherits Page {
title: @tr("Cheats");
callback cheats_select_rom_clicked;
callback cheats_select_rom_clicked(string);
callback cheats_clear_clicked;
callback cheat_toggled(string, string, string, bool);
@@ -23,13 +24,13 @@ export component Cheats inherits Page {
if CheatsData.cheat_game_name == "": Button {
text: @tr("Select ROM");
clicked => {
cheats_select_rom_clicked();
cheats_select_rom_clicked(SettingsData.rom_dir);
}
}
if CheatsData.cheat_game_name != "": Button {
text: CheatsData.cheat_game_name;
clicked => {
cheats_select_rom_clicked();
cheats_select_rom_clicked(SettingsData.rom_dir);
}
}
Rectangle {
+18 -5
View File
@@ -5,6 +5,7 @@ export component NetplayCreate inherits Window {
title: @tr("Netplay: Create Session");
in-out property server_names <=> NetplayData.server_names;
in-out property server_urls <=> NetplayData.server_urls;
in-out property custom_server_url <=> NetplayData.custom_server_url;
in-out property ping <=> NetplayData.ping;
in-out property game_name <=> NetplayData.game_name;
in-out property game_hash <=> NetplayData.game_hash;
@@ -12,8 +13,10 @@ export component NetplayCreate inherits Window {
in-out property pending_session <=> NetplayData.pending_session;
in-out property rom_path <=> NetplayData.rom_path;
in-out property peer_addr <=> NetplayData.peer_addr;
in-out property rom_dir <=> NetplayData.rom_dir;
callback get_ping(string);
callback select_rom;
callback get_custom_url();
callback select_rom(string);
callback create_session(string, string, string, string, string, string, string);
VerticalBox {
@@ -68,7 +71,11 @@ export component NetplayCreate inherits Window {
model: NetplayData.server_names;
selected => {
if (self.current-index >= 0) {
get_ping(NetplayData.server_urls[self.current-index]);
if (self.current-value == "Custom") {
get_custom_url();
} else {
get_ping(NetplayData.server_urls[self.current-index]);
}
}
}
}
@@ -83,13 +90,13 @@ export component NetplayCreate inherits Window {
if NetplayData.game_name == "": Button {
text: @tr("Select ROM");
clicked => {
select_rom();
select_rom(NetplayData.rom_dir);
}
}
if NetplayData.game_name != "": Button {
text: NetplayData.game_name;
clicked => {
select_rom();
select_rom(NetplayData.rom_dir);
}
}
@@ -101,12 +108,18 @@ export component NetplayCreate inherits Window {
Rectangle { }
Button {
property <string> server_url;
text: @tr("Create Session");
enabled: NetplayData.session_name != "" && NetplayData.player_name != "" && NetplayData.game_name != "" && !NetplayData.pending_session;
clicked => {
NetplayData.pending_session = true;
if (server.current-value == "Custom") {
server_url = "ws://" + NetplayData.custom_server_url;
} else {
server_url = NetplayData.server_urls[server.current-index];
}
create_session(
NetplayData.server_urls[server.current-index],
server_url,
NetplayData.session_name,
NetplayData.player_name,
NetplayData.game_name,
+16 -5
View File
@@ -5,6 +5,7 @@ export component NetplayJoin inherits Window {
title: @tr("Netplay: Join Session");
in-out property server_names <=> NetplayData.server_names;
in-out property server_urls <=> NetplayData.server_urls;
in-out property custom_server_url <=> NetplayData.custom_server_url;
in-out property ping <=> NetplayData.ping;
in-out property sessions <=> NetplayData.sessions;
in-out property current_session <=> NetplayData.current_session;
@@ -15,9 +16,11 @@ export component NetplayJoin inherits Window {
in-out property peer_addr <=> NetplayData.peer_addr;
in-out property pending_session <=> NetplayData.pending_session;
in-out property rom_path <=> NetplayData.rom_path;
in-out property rom_dir <=> NetplayData.rom_dir;
callback get_ping(string);
callback get_custom_url();
callback refresh_session(string);
callback select_rom;
callback select_rom(string);
callback join_session(string, string, string, int);
VerticalBox {
@@ -45,7 +48,11 @@ export component NetplayJoin inherits Window {
model: NetplayData.server_names;
selected => {
if (self.current-index >= 0) {
get_ping(NetplayData.server_urls[self.current-index]);
if (self.current-value == "Custom") {
get_custom_url();
} else {
get_ping(NetplayData.server_urls[self.current-index]);
}
}
}
}
@@ -88,7 +95,11 @@ export component NetplayJoin inherits Window {
Button {
text: @tr("Refresh Session List");
clicked => {
refresh_session(NetplayData.server_urls[server.current-index]);
if (server.current-value == "Custom") {
refresh_session("ws://" + NetplayData.custom_server_url);
} else {
refresh_session(NetplayData.server_urls[server.current-index]);
}
}
}
}
@@ -104,13 +115,13 @@ export component NetplayJoin inherits Window {
if NetplayData.game_name == "": Button {
text: @tr("Select ROM");
clicked => {
select_rom();
select_rom(NetplayData.rom_dir);
}
}
if NetplayData.game_name != "": Button {
text: NetplayData.game_name;
clicked => {
select_rom();
select_rom(NetplayData.rom_dir);
}
}
+22 -1
View File
@@ -1,7 +1,7 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { VerticalBox, HorizontalBox, Button } from "std-widgets.slint";
import { StandardButton, VerticalBox, HorizontalBox, Button, LineEdit } from "std-widgets.slint";
import { Page } from "page.slint";
export global NetplayData {
@@ -20,6 +20,8 @@ export global NetplayData {
in-out property <[[StandardListViewItem]]> sessions;
in-out property <[int]> ports;
in-out property <int> current_session: -1;
in-out property <string> rom_dir;
in-out property <string> custom_server_url;
}
export component Netplay inherits Page {
@@ -73,3 +75,22 @@ export component Netplay inherits Page {
}
}
}
export component CustomNetplayServer inherits Dialog {
in-out property custom_server_url <=> NetplayData.custom_server_url;
title: @tr("Custom Netplay Server");
preferred-width: 400px;
callback ok_clicked(string);
server_url := LineEdit {
text: NetplayData.custom_server_url;
placeholder-text: "example.com:45000";
}
StandardButton {
kind: ok;
clicked => {
NetplayData.custom_server_url = server_url.text;
ok_clicked(NetplayData.custom_server_url);
}
}
}
+4 -1
View File
@@ -12,6 +12,7 @@ export global SettingsData {
in-out property <bool> overclock_n64_cpu;
in-out property <bool> disable_expansion_pak;
in-out property <int> resolution;
in-out property <string> rom_dir;
}
export component Settings inherits Page {
@@ -79,7 +80,9 @@ export component Settings inherits Page {
}
}
Rectangle { }
Rectangle {
height: 20px;
}
HorizontalBox {
alignment: start;
+8 -2
View File
@@ -363,6 +363,8 @@ pub fn get_controller_paths(game_ui: &ui::Ui) -> Vec<Option<String>> {
}
pub fn get(ui: &ui::Ui, channel: usize) -> InputData {
unsafe { sdl3_sys::events::SDL_PumpEvents() };
let profile_name = ui.config.input.input_profile_binding[channel].clone();
let profile = ui.config.input.input_profiles.get(&profile_name).unwrap();
let mut keys = 0;
@@ -609,7 +611,9 @@ pub fn configure_input_profile(ui: &mut ui::Ui, profile: String, dinput: bool) {
} else if event_type == u32::from(sdl3_sys::events::SDL_EVENT_GAMEPAD_AXIS_MOTION) {
let axis_value = unsafe { event.gaxis.value };
let axis = unsafe { event.gaxis.axis };
if !open_controllers.is_empty() && axis_value.saturating_abs() > i16::MAX / 2 {
if !open_controllers.is_empty()
&& axis_value.saturating_abs() > (i16::MAX as i32 * 3 / 4) as i16
{
let result = ui::config::InputControllerAxis {
enabled: true,
id: axis as i32,
@@ -645,7 +649,9 @@ pub fn configure_input_profile(ui: &mut ui::Ui, profile: String, dinput: bool) {
{
let axis_value = unsafe { event.jaxis.value };
let axis = unsafe { event.jaxis.axis };
if !open_joysticks.is_empty() && axis_value.saturating_abs() > i16::MAX / 2 {
if !open_joysticks.is_empty()
&& axis_value.saturating_abs() > (i16::MAX as i32 * 3 / 4) as i16
{
let result = ui::config::InputControllerAxis {
enabled: true,
id: axis as i32,
+396 -285
View File
@@ -1,8 +1,8 @@
use crate::device;
use crate::ui;
use crate::ui::gui::{
AppWindow, ErrorDialog, GameSettings, GbPaths, NetplayCreate, NetplayDevice, NetplayJoin,
NetplayWait, VruChannel, run_rom, save_settings,
AppWindow, CustomNetplayServer, ErrorDialog, GameSettings, GbPaths, NetplayCreate,
NetplayDevice, NetplayJoin, NetplayWait, VruChannel, run_rom, save_settings,
};
use futures::{SinkExt, StreamExt};
use sha2::{Digest, Sha256};
@@ -56,6 +56,8 @@ trait NetplayPages {
fn refresh_sessions(&self, _server: slint::SharedString) {
// Default implementation does nothing
}
fn invoke_get_ping(&self, server_url: slint::SharedString);
fn set_custom_server_url(&self, server_url: slint::SharedString);
}
impl NetplayPages for NetplayCreate {
@@ -83,6 +85,12 @@ impl NetplayPages for NetplayCreate {
fn set_peer_addr(&self, peer_addr: slint::SharedString) {
self.set_peer_addr(peer_addr);
}
fn invoke_get_ping(&self, server_url: slint::SharedString) {
self.invoke_get_ping(server_url);
}
fn set_custom_server_url(&self, server_url: slint::SharedString) {
self.set_custom_server_url(server_url);
}
}
impl NetplayPages for NetplayJoin {
@@ -113,10 +121,16 @@ impl NetplayPages for NetplayJoin {
fn set_peer_addr(&self, peer_addr: slint::SharedString) {
self.set_peer_addr(peer_addr);
}
fn invoke_get_ping(&self, server_url: slint::SharedString) {
self.invoke_get_ping(server_url);
}
fn set_custom_server_url(&self, server_url: slint::SharedString) {
self.set_custom_server_url(server_url);
}
}
fn populate_server_names<T: ComponentHandle + NetplayPages + 'static>(weak: slint::Weak<T>) {
let task = reqwest::get("https://m64p.s3.amazonaws.com/servers.json");
let task = reqwest::get("https://cdn.gopher64.com/servers-gopher64.json");
tokio::spawn(async move {
let mut local_servers: Vec<(String, String)> = vec![];
@@ -159,6 +173,7 @@ fn populate_server_names<T: ComponentHandle + NetplayPages + 'static>(weak: slin
server_names.push(server.0.into());
server_urls.push(server.1.into());
}
server_names.push("Custom".into());
update_ping(weak2, server_urls.row_data(0).unwrap().into());
handle.refresh_sessions(server_urls.row_data(0).unwrap());
let server_names_model: std::rc::Rc<slint::VecModel<slint::SharedString>> =
@@ -173,10 +188,21 @@ fn populate_server_names<T: ComponentHandle + NetplayPages + 'static>(weak: slin
});
}
fn select_rom<T: ComponentHandle + NetplayPages + 'static>(weak: slint::Weak<T>) {
let select_rom = rfd::AsyncFileDialog::new()
.set_title("Select ROM")
.pick_file();
fn select_rom<T: ComponentHandle + NetplayPages + 'static>(
weak: slint::Weak<T>,
rom_dir: slint::SharedString,
) {
let select_rom = if !rom_dir.is_empty()
&& let Ok(exists) = std::fs::exists(&rom_dir)
&& exists
{
rfd::AsyncFileDialog::new().set_directory(rom_dir)
} else {
rfd::AsyncFileDialog::new()
}
.set_title("Select ROM")
.add_filter("ROM files", &ui::gui::N64_EXTENSIONS)
.pick_file();
tokio::spawn(async move {
if let Some(file) = select_rom.await {
if let Some(rom_contents) = device::get_rom_contents(file.path()) {
@@ -249,9 +275,29 @@ fn update_ping<T: ComponentHandle + NetplayPages + 'static>(
});
}
fn show_custom_url_dialog<T: ComponentHandle + NetplayPages + 'static>(
weak: slint::Weak<T>,
server_url: slint::SharedString,
) {
let url_dialog = CustomNetplayServer::new().unwrap();
url_dialog.set_custom_server_url(server_url);
let weak_dialog = url_dialog.as_weak();
url_dialog.on_ok_clicked(move |server_url| {
weak.upgrade_in_event_loop(move |handle| {
handle.set_custom_server_url(server_url.clone());
let prefix: slint::SharedString = "ws://".into();
handle.invoke_get_ping(prefix + &server_url);
})
.unwrap();
weak_dialog.unwrap().window().hide().unwrap();
});
url_dialog.show().unwrap();
}
pub fn setup_create_window(
create_window: &NetplayCreate,
game_settings: GameSettings,
rom_dir: slint::SharedString,
weak_app: slint::Weak<AppWindow>,
) {
let (netplay_read_sender, netplay_read_receiver): (
@@ -264,14 +310,24 @@ pub fn setup_create_window(
tokio::sync::broadcast::Receiver<Option<NetplayMessage>>,
) = tokio::sync::broadcast::channel(5);
create_window.set_rom_dir(rom_dir);
populate_server_names(create_window.as_weak());
let weak = create_window.as_weak();
create_window.on_get_ping(move |server_url| {
update_ping(weak.clone(), server_url.to_string());
});
let weak = create_window.as_weak();
create_window.on_select_rom(move || {
select_rom(weak.clone());
create_window.on_get_custom_url(move || {
let weak2 = weak.clone();
weak.upgrade_in_event_loop(move |handle| {
handle.set_ping("Ping: Unknown".into());
show_custom_url_dialog(weak2, handle.get_custom_server_url());
})
.unwrap();
});
let weak = create_window.as_weak();
create_window.on_select_rom(move |rom_dir| {
select_rom(weak.clone(), rom_dir);
});
let weak = create_window.as_weak();
@@ -343,13 +399,23 @@ fn manage_websocket<T: ComponentHandle + NetplayPages + 'static>(
}
});
tokio::spawn(async move {
while let Ok(Some(response)) = netplay_write_receiver.recv().await {
write
.send(Message::Binary(Bytes::from(
serde_json::to_vec(&response).unwrap(),
)))
.await
.unwrap();
loop {
match netplay_write_receiver.recv().await {
Ok(Some(response)) => {
write
.send(Message::Binary(Bytes::from(
serde_json::to_vec(&response).unwrap(),
)))
.await
.unwrap();
}
Ok(None) => {
break;
}
Err(err) => {
panic!("netplay_write_receiver error: {err}");
}
}
}
write.close().await.unwrap();
});
@@ -401,74 +467,81 @@ fn update_sessions(
netplay_write_sender.send(Some(request_rooms)).unwrap();
if let Ok(Ok(message)) = tokio::time::timeout(
match tokio::time::timeout(
std::time::Duration::from_secs(2),
netplay_read_receiver.recv(),
)
.await
{
if message.accept.unwrap() == 0 {
if let Some(rooms) = message.rooms {
weak.upgrade_in_event_loop(move |handle| {
let sessions_vec = slint::VecModel::default();
let ports_vec = slint::VecModel::default();
for room in rooms {
let session_vec = slint::VecModel::default();
session_vec.push(slint::StandardListViewItem::from(
slint::SharedString::from(room.room_name.unwrap()),
));
session_vec.push(slint::StandardListViewItem::from(
slint::SharedString::from(room.game_name.unwrap()),
));
session_vec.push(slint::StandardListViewItem::from(
slint::SharedString::from(if room.protected.unwrap() {
"True"
} else {
"False"
}),
));
session_vec.push(slint::StandardListViewItem::from(
slint::SharedString::from(
if room.features.unwrap_or_default().contains_key("cheats") {
Ok(Ok(message)) => {
if message.accept.unwrap() == 0 {
if let Some(rooms) = message.rooms {
weak.upgrade_in_event_loop(move |handle| {
let sessions_vec = slint::VecModel::default();
let ports_vec = slint::VecModel::default();
for room in rooms {
let session_vec = slint::VecModel::default();
session_vec.push(slint::StandardListViewItem::from(
slint::SharedString::from(room.room_name.unwrap()),
));
session_vec.push(slint::StandardListViewItem::from(
slint::SharedString::from(room.game_name.unwrap()),
));
session_vec.push(slint::StandardListViewItem::from(
slint::SharedString::from(if room.protected.unwrap() {
"True"
} else {
"False"
},
),
));
let session_model: std::rc::Rc<
slint::VecModel<slint::StandardListViewItem>,
> = std::rc::Rc::new(session_vec);
sessions_vec.push(slint::ModelRc::from(session_model));
ports_vec.push(room.port.unwrap());
}
let rooms_model: std::rc::Rc<
slint::VecModel<slint::ModelRc<slint::StandardListViewItem>>,
> = std::rc::Rc::new(sessions_vec);
let ports_model: std::rc::Rc<slint::VecModel<i32>> =
std::rc::Rc::new(ports_vec);
handle.set_sessions(slint::ModelRc::from(rooms_model));
handle.set_ports(slint::ModelRc::from(ports_model));
handle.set_current_session(-1);
})
.unwrap();
}),
));
session_vec.push(slint::StandardListViewItem::from(
slint::SharedString::from(
if room.features.unwrap_or_default().contains_key("cheats")
{
"True"
} else {
"False"
},
),
));
let session_model: std::rc::Rc<
slint::VecModel<slint::StandardListViewItem>,
> = std::rc::Rc::new(session_vec);
sessions_vec.push(slint::ModelRc::from(session_model));
ports_vec.push(room.port.unwrap());
}
let rooms_model: std::rc::Rc<
slint::VecModel<slint::ModelRc<slint::StandardListViewItem>>,
> = std::rc::Rc::new(sessions_vec);
let ports_model: std::rc::Rc<slint::VecModel<i32>> =
std::rc::Rc::new(ports_vec);
handle.set_sessions(slint::ModelRc::from(rooms_model));
handle.set_ports(slint::ModelRc::from(ports_model));
handle.set_current_session(-1);
})
.unwrap();
} else {
weak.upgrade_in_event_loop(move |handle| {
clear_sessions(&handle, None);
})
.unwrap();
}
} else {
weak.upgrade_in_event_loop(move |handle| {
clear_sessions(&handle, None);
clear_sessions(&handle, message.message);
})
.unwrap();
}
} else {
}
Ok(Err(err)) => {
panic!("netplay_read_receiver error: {err}");
}
Err(_) => {
weak.upgrade_in_event_loop(move |handle| {
clear_sessions(&handle, message.message);
clear_sessions(&handle, Some("Server did not respond".to_string()));
})
.unwrap();
}
} else {
weak.upgrade_in_event_loop(move |handle| {
clear_sessions(&handle, Some("Server did not respond".to_string()));
})
.unwrap();
}
});
}
@@ -528,71 +601,77 @@ fn create_session(
netplay_write_sender.send(Some(create_room)).unwrap();
if let Ok(Ok(message)) = tokio::time::timeout(
match tokio::time::timeout(
std::time::Duration::from_secs(2),
netplay_read_receiver.recv(),
)
.await
{
if message.accept.unwrap() == 0 {
weak.upgrade_in_event_loop(move |handle| {
let session = message.room.as_ref().unwrap();
let features_default = "false".to_string();
let cheats_default = "{}".to_string();
let overclock = session
.features
.as_ref()
.unwrap()
.get("overclock")
.unwrap_or(&features_default);
let disable_expansion_pak = session
.features
.as_ref()
.unwrap()
.get("disable_expansion_pak")
.unwrap_or(&features_default);
let cheats = session
.features
.as_ref()
.unwrap()
.get("cheats")
.unwrap_or(&cheats_default);
setup_wait_window(
netplay_write_sender,
netplay_read_receiver,
session.room_name.as_ref().unwrap().into(),
session.game_name.as_ref().unwrap().into(),
handle.get_rom_path(),
message.player_name.as_ref().unwrap().into(),
session.port.unwrap(),
true,
GameSettings {
fullscreen: game_settings.fullscreen,
overclock: overclock.parse().unwrap(),
disable_expansion_pak: disable_expansion_pak.parse().unwrap(),
cheats: serde_json::from_str(cheats).unwrap(),
},
handle.get_peer_addr(),
weak_app,
);
handle.window().hide().unwrap();
})
.unwrap();
} else {
Ok(Ok(message)) => {
if message.accept.unwrap() == 0 {
weak.upgrade_in_event_loop(move |handle| {
let session = message.room.as_ref().unwrap();
let features_default = "false".to_string();
let cheats_default = "{}".to_string();
let overclock = session
.features
.as_ref()
.unwrap()
.get("overclock")
.unwrap_or(&features_default);
let disable_expansion_pak = session
.features
.as_ref()
.unwrap()
.get("disable_expansion_pak")
.unwrap_or(&features_default);
let cheats = session
.features
.as_ref()
.unwrap()
.get("cheats")
.unwrap_or(&cheats_default);
setup_wait_window(
netplay_write_sender,
netplay_read_receiver,
session.room_name.as_ref().unwrap().into(),
session.game_name.as_ref().unwrap().into(),
handle.get_rom_path(),
message.player_name.as_ref().unwrap().into(),
session.port.unwrap(),
true,
GameSettings {
fullscreen: game_settings.fullscreen,
overclock: overclock.parse().unwrap(),
disable_expansion_pak: disable_expansion_pak.parse().unwrap(),
cheats: serde_json::from_str(cheats).unwrap(),
},
handle.get_peer_addr(),
weak_app,
);
handle.window().hide().unwrap();
})
.unwrap();
} else {
weak.upgrade_in_event_loop(move |handle| {
handle.set_pending_session(false);
if let Some(message) = message.message {
show_netplay_error(message);
}
})
.unwrap();
}
}
Ok(Err(err)) => {
panic!("netplay_read_receiver error: {err}");
}
Err(_) => {
weak.upgrade_in_event_loop(move |handle| {
handle.set_pending_session(false);
if let Some(message) = message.message {
show_netplay_error(message);
}
show_netplay_error("Server did not respond".to_string());
})
.unwrap();
}
} else {
weak.upgrade_in_event_loop(move |handle| {
handle.set_pending_session(false);
show_netplay_error("Server did not respond".to_string());
})
.unwrap();
}
});
}
@@ -636,71 +715,77 @@ fn join_session(
netplay_write_sender.send(Some(join_room)).unwrap();
if let Ok(Ok(message)) = tokio::time::timeout(
match tokio::time::timeout(
std::time::Duration::from_secs(2),
netplay_read_receiver.recv(),
)
.await
{
if message.accept.unwrap() == 0 {
weak.upgrade_in_event_loop(move |handle| {
let session = message.room.as_ref().unwrap();
let features_default = "false".to_string();
let cheats_default = "{}".to_string();
let overclock = session
.features
.as_ref()
.unwrap()
.get("overclock")
.unwrap_or(&features_default);
let disable_expansion_pak = session
.features
.as_ref()
.unwrap()
.get("disable_expansion_pak")
.unwrap_or(&features_default);
let cheats = session
.features
.as_ref()
.unwrap()
.get("cheats")
.unwrap_or(&cheats_default);
setup_wait_window(
netplay_write_sender,
netplay_read_receiver,
session.room_name.as_ref().unwrap().into(),
session.game_name.as_ref().unwrap().into(),
handle.get_rom_path(),
message.player_name.as_ref().unwrap().into(),
session.port.unwrap(),
false,
GameSettings {
fullscreen,
overclock: overclock.parse().unwrap(),
disable_expansion_pak: disable_expansion_pak.parse().unwrap(),
cheats: serde_json::from_str(cheats).unwrap(),
},
handle.get_peer_addr(),
weak_app,
);
handle.window().hide().unwrap();
})
.unwrap();
} else {
Ok(Ok(message)) => {
if message.accept.unwrap() == 0 {
weak.upgrade_in_event_loop(move |handle| {
let session = message.room.as_ref().unwrap();
let features_default = "false".to_string();
let cheats_default = "{}".to_string();
let overclock = session
.features
.as_ref()
.unwrap()
.get("overclock")
.unwrap_or(&features_default);
let disable_expansion_pak = session
.features
.as_ref()
.unwrap()
.get("disable_expansion_pak")
.unwrap_or(&features_default);
let cheats = session
.features
.as_ref()
.unwrap()
.get("cheats")
.unwrap_or(&cheats_default);
setup_wait_window(
netplay_write_sender,
netplay_read_receiver,
session.room_name.as_ref().unwrap().into(),
session.game_name.as_ref().unwrap().into(),
handle.get_rom_path(),
message.player_name.as_ref().unwrap().into(),
session.port.unwrap(),
false,
GameSettings {
fullscreen,
overclock: overclock.parse().unwrap(),
disable_expansion_pak: disable_expansion_pak.parse().unwrap(),
cheats: serde_json::from_str(cheats).unwrap(),
},
handle.get_peer_addr(),
weak_app,
);
handle.window().hide().unwrap();
})
.unwrap();
} else {
weak.upgrade_in_event_loop(move |handle| {
handle.set_pending_session(false);
if let Some(message) = message.message {
show_netplay_error(message);
}
})
.unwrap();
}
}
Ok(Err(err)) => {
panic!("netplay_read_receiver error: {err}");
}
Err(_) => {
weak.upgrade_in_event_loop(move |handle| {
handle.set_pending_session(false);
if let Some(message) = message.message {
show_netplay_error(message);
}
show_netplay_error("Server did not respond".to_string());
})
.unwrap();
}
} else {
weak.upgrade_in_event_loop(move |handle| {
handle.set_pending_session(false);
show_netplay_error("Server did not respond".to_string());
})
.unwrap();
}
});
}
@@ -811,121 +896,130 @@ fn setup_wait_window(
let weak = wait.as_weak();
tokio::spawn(async move {
while let Ok(response) = netplay_read_receiver.recv().await {
match response.message_type.as_str() {
"reply_motd" => {
let request_players = NetplayMessage {
message_type: "request_players".to_string(),
player_name: None,
client_sha: None,
netplay_version: None,
player_names: None,
emulator: None,
rooms: None,
accept: None,
message: None,
auth_time: None,
auth: None,
room: Some(NetplayRoom {
room_name: None,
password: None,
game_name: None,
md5: None,
protected: None,
port: Some(port),
features: None,
buffer_target: None,
}),
};
netplay_write_sender.send(Some(request_players)).unwrap();
loop {
match netplay_read_receiver.recv().await {
Ok(response) => match response.message_type.as_str() {
"reply_motd" => {
let request_players = NetplayMessage {
message_type: "request_players".to_string(),
player_name: None,
client_sha: None,
netplay_version: None,
player_names: None,
emulator: None,
rooms: None,
accept: None,
message: None,
auth_time: None,
auth: None,
room: Some(NetplayRoom {
room_name: None,
password: None,
game_name: None,
md5: None,
protected: None,
port: Some(port),
features: None,
buffer_target: None,
}),
};
netplay_write_sender.send(Some(request_players)).unwrap();
weak.upgrade_in_event_loop(move |handle| {
#[allow(clippy::regex_creation_in_loops)]
let re = regex::Regex::new(r"<[^>]*>").unwrap();
let motd = re
.replace_all(response.message.unwrap().as_str(), "")
.into_owned();
handle.set_motd(motd.into());
})
.unwrap();
}
"reply_players" => {
weak.upgrade_in_event_loop(move |handle| {
if let Some(player_names) = response.player_names {
let players_vec: slint::VecModel<slint::SharedString> =
slint::VecModel::default();
for player in player_names {
players_vec.push(player.into());
}
let players_model: std::rc::Rc<slint::VecModel<slint::SharedString>> =
std::rc::Rc::new(players_vec);
handle.set_players(slint::ModelRc::from(players_model));
}
})
.unwrap();
}
"reply_chat_message" => {
weak.upgrade_in_event_loop(move |handle| {
let mut chat_text = handle.get_chat_text();
chat_text.push_str(&format!("{}\n", response.message.unwrap()));
handle.set_chat_text(chat_text);
})
.unwrap();
}
"reply_begin_game" => {
if response.accept.unwrap() == 0 {
weak.upgrade_in_event_loop(move |handle| {
handle.window().hide().unwrap();
let _ = netplay_write_sender.send(None);
let mut player_number = 4;
let players = handle.get_players();
for (i, player) in players.iter().enumerate() {
if player == local_player {
player_number = i;
}
}
if player_number > 3 {
panic!("Could not determine player number");
}
run_rom(
GbPaths {
rom: [None, None, None, None],
ram: [None, None, None, None],
},
handle.get_rom_path().as_str().into(),
GameSettings {
fullscreen: game_settings.fullscreen,
overclock: game_settings.overclock,
disable_expansion_pak: game_settings.disable_expansion_pak,
cheats: game_settings.cheats,
},
VruChannel {
vru_window_notifier: None,
vru_word_receiver: None,
},
Some(NetplayDevice {
peer_addr: socket_addr,
player_number: player_number as u8,
}),
weak_app,
);
#[allow(clippy::regex_creation_in_loops)]
let re = regex::Regex::new(r"<[^>]*>").unwrap();
let motd = re
.replace_all(response.message.unwrap().as_str(), "")
.into_owned();
handle.set_motd(motd.into());
})
.unwrap();
return;
} else {
}
"reply_players" => {
weak.upgrade_in_event_loop(move |handle| {
handle.set_can_start(can_start);
if let Some(message) = response.message {
show_netplay_error(message);
if let Some(player_names) = response.player_names {
let players_vec: slint::VecModel<slint::SharedString> =
slint::VecModel::default();
for player in player_names {
players_vec.push(player.into());
}
let players_model: std::rc::Rc<
slint::VecModel<slint::SharedString>,
> = std::rc::Rc::new(players_vec);
handle.set_players(slint::ModelRc::from(players_model));
}
})
.unwrap();
}
"reply_chat_message" => {
weak.upgrade_in_event_loop(move |handle| {
let mut chat_text = handle.get_chat_text();
chat_text.push_str(&format!("{}\n", response.message.unwrap()));
handle.set_chat_text(chat_text);
})
.unwrap();
}
"reply_begin_game" => {
if response.accept.unwrap() == 0 {
weak.upgrade_in_event_loop(move |handle| {
handle.window().hide().unwrap();
let _ = netplay_write_sender.send(None);
let mut player_number = 4;
let players = handle.get_players();
for (i, player) in players.iter().enumerate() {
if player == local_player {
player_number = i;
}
}
if player_number > 3 {
panic!("Could not determine player number");
}
run_rom(
GbPaths {
rom: [None, None, None, None],
ram: [None, None, None, None],
},
handle.get_rom_path().as_str().into(),
GameSettings {
fullscreen: game_settings.fullscreen,
overclock: game_settings.overclock,
disable_expansion_pak: game_settings.disable_expansion_pak,
cheats: game_settings.cheats,
},
VruChannel {
vru_window_notifier: None,
vru_word_receiver: None,
},
Some(NetplayDevice {
peer_addr: socket_addr,
player_number: player_number as u8,
}),
weak_app,
);
})
.unwrap();
return;
} else {
weak.upgrade_in_event_loop(move |handle| {
handle.set_can_start(can_start);
if let Some(message) = response.message {
show_netplay_error(message);
}
})
.unwrap();
}
}
_ => {
println!("Unknown netplay message type: {}", response.message_type);
}
},
Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => {
panic!("netplay_read_receiver lagged");
}
_ => {
println!("Unknown netplay message type: {}", response.message_type);
Err(tokio::sync::broadcast::error::RecvError::Closed) => {
break; // exit the loop if the receiver is closed
}
}
}
@@ -937,6 +1031,7 @@ fn setup_wait_window(
pub fn setup_join_window(
join_window: &NetplayJoin,
fullscreen: bool,
rom_dir: slint::SharedString,
weak_app: slint::Weak<AppWindow>,
) {
let (netplay_read_sender, netplay_read_receiver): (
@@ -949,6 +1044,7 @@ pub fn setup_join_window(
tokio::sync::broadcast::Receiver<Option<NetplayMessage>>,
) = tokio::sync::broadcast::channel(5);
join_window.set_rom_dir(rom_dir);
populate_server_names(join_window.as_weak());
let weak = join_window.as_weak();
join_window.on_get_ping(move |server_url| {
@@ -959,8 +1055,17 @@ pub fn setup_join_window(
.unwrap();
});
let weak = join_window.as_weak();
join_window.on_select_rom(move || {
select_rom(weak.clone());
join_window.on_get_custom_url(move || {
let weak2 = weak.clone();
weak.upgrade_in_event_loop(move |handle| {
handle.set_ping("Ping: Unknown".into());
show_custom_url_dialog(weak2, handle.get_custom_server_url());
})
.unwrap();
});
let weak = join_window.as_weak();
join_window.on_select_rom(move |rom_dir| {
select_rom(weak.clone(), rom_dir);
});
let sender = netplay_write_sender.clone();
@@ -1019,6 +1124,7 @@ pub fn netplay_window(app: &AppWindow, controller_paths: &[Option<String>]) {
disable_expansion_pak: handle.get_disable_expansion_pak(),
cheats: std::collections::HashMap::new(), // not used here
},
handle.get_rom_dir(),
weak_app,
);
})
@@ -1035,7 +1141,12 @@ pub fn netplay_window(app: &AppWindow, controller_paths: &[Option<String>]) {
.upgrade_in_event_loop(move |handle| {
let join_window = NetplayJoin::new().unwrap();
save_settings(&handle, &controller_paths);
setup_join_window(&join_window, handle.get_fullscreen(), weak_app);
setup_join_window(
&join_window,
handle.get_fullscreen(),
handle.get_rom_dir(),
weak_app,
);
})
.unwrap();
});
+2 -1
View File
@@ -341,7 +341,8 @@ pub fn compress_file(data: &[(&[u8], &str)]) -> Vec<u8> {
.start_file(
item.1,
zip::write::SimpleFileOptions::default()
.compression_method(zip::CompressionMethod::Zstd),
.compression_method(zip::CompressionMethod::Zstd)
.compression_level(Some(1)),
)
.unwrap();
writer.write_all(item.0).unwrap();
+16 -3
View File
@@ -37,10 +37,18 @@ pub fn init(device: &mut device::Device) {
sdl3_sys::video::SDL_CreateWindow(title.as_ptr(), window_width, window_height, flags)
};
if device.ui.video.window.is_null() {
panic!("Could not create window");
panic!("Could not create window: {}", unsafe {
std::ffi::CStr::from_ptr(sdl3_sys::error::SDL_GetError())
.to_str()
.unwrap()
});
}
if !unsafe { sdl3_sys::video::SDL_ShowWindow(device.ui.video.window) } {
panic!("Could not show window");
panic!("Could not show window: {}", unsafe {
std::ffi::CStr::from_ptr(sdl3_sys::error::SDL_GetError())
.to_str()
.unwrap()
});
}
unsafe {
sdl3_sys::everything::SDL_HideCursor();
@@ -116,7 +124,7 @@ pub fn load_state(device: &mut device::Device, rdp_state: *const u8) {
pub fn check_callback(device: &mut device::Device) -> bool {
let mut speed_limiter_toggled = false;
let callback = unsafe { rdp_check_callback() };
let mut callback = unsafe { rdp_check_callback() };
device.cpu.running = callback.emu_running;
if device.netplay.is_none() {
if callback.save_state {
@@ -128,6 +136,11 @@ pub fn check_callback(device: &mut device::Device) -> bool {
speed_limiter_toggled = true;
device.vi.enable_speed_limiter = callback.enable_speedlimiter;
}
while callback.paused {
std::thread::sleep(std::time::Duration::from_secs_f64(1.0 / 60.0));
unsafe { sdl3_sys::events::SDL_PumpEvents() };
callback = unsafe { rdp_check_callback() };
}
}
if callback.lower_volume {
+1 -3
View File
@@ -1,5 +1,3 @@
use crate::ui;
pub fn prompt_for_match(
words: &[String],
window_notifier: &tokio::sync::mpsc::Sender<Option<Vec<String>>>,
@@ -13,7 +11,7 @@ pub fn prompt_for_match(
while result.is_err() {
result = word_index_receiver.try_recv();
std::thread::sleep(std::time::Duration::from_secs_f64(1.0 / 60.0));
ui::video::update_screen(); // so the OS doesn't complain about the game window being frozen
unsafe { sdl3_sys::events::SDL_PumpEvents() }; // so the OS doesn't complain about the game window being frozen
}
for (i, v) in words.iter().enumerate() {
if *v == *result.as_ref().unwrap() {