Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d7f656cd6a | |||
| 8558334391 | |||
| b6de872d78 | |||
| 712dc10c65 | |||
| cd2b5b4e92 | |||
| 98b5d6506e | |||
| f2e8bc6356 | |||
| 328e1730a0 | |||
| 8010a6211c | |||
| 41b1fd05be | |||
| c5da2a795f | |||
| 7361a9bd5c | |||
| d4e8933352 | |||
| fff376db5e | |||
| d7f1c8415a | |||
| ac09be4202 | |||
| 022190384a | |||
| e4dd5c2dee | |||
| 3e95059ec7 | |||
| abc39e74ef | |||
| 7109d28223 | |||
| 1d1e3829e4 | |||
| a46e4f505b | |||
| 03fbe658f2 | |||
| b96c9e4cdc | |||
| cea405ea30 | |||
| c13d354201 | |||
| ff43f59f74 | |||
| eb97b96daf | |||
| 9bf43a16b4 | |||
| b67247f935 | |||
| f10c591047 | |||
| 82f1965f26 | |||
| a5ddea353a | |||
| 6c977dbe5e | |||
| 5dcfd72b18 |
@@ -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,7 +4,7 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "cargo"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
# - package-ecosystem: "cargo"
|
||||
# directory: "/"
|
||||
# schedule:
|
||||
# interval: "daily"
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
Before Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 97 KiB |
@@ -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
|
||||
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 243 KiB |
|
After Width: | Height: | Size: 64 KiB |
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
|
||||
@@ -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 {}",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,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() {
|
||||
|
||||