Client/Server Feature Split (#63)
This commit is contained in:
7
.github/workflows/archive_steamos.yml
vendored
7
.github/workflows/archive_steamos.yml
vendored
@@ -23,12 +23,13 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cargo build --release --locked --target=x86_64-unknown-linux-gnu
|
cargo build --release --locked --target=x86_64-unknown-linux-gnu --bin hedz_reloaded --no-default-features --features shared/client
|
||||||
|
cargo build --release --locked --target=x86_64-unknown-linux-gnu --bin server --no-default-features --features shared/server
|
||||||
|
|
||||||
- name: Archive
|
- name: Archive
|
||||||
run: |
|
run: |
|
||||||
cp target/x86_64-unknown-linux-gnu/release/hedz_reloaded hedz_reloaded
|
cp target/x86_64-unknown-linux-gnu/release/hedz_reloaded target/x86_64-unknown-linux-gnu/release/server ./
|
||||||
tar -czf steamos.tar.gz hedz_reloaded
|
tar -czf steamos.tar.gz hedz_reloaded server
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
7
.github/workflows/archive_win.yml
vendored
7
.github/workflows/archive_win.yml
vendored
@@ -28,13 +28,14 @@ jobs:
|
|||||||
|
|
||||||
- name: Build binaries (Windows)
|
- name: Build binaries (Windows)
|
||||||
run: |
|
run: |
|
||||||
cargo xwin build --locked --release --target=x86_64-pc-windows-msvc
|
cargo xwin build --locked --release --target=x86_64-pc-windows-msvc --bin hedz_reloaded --no-default-features --features shared/client
|
||||||
|
cargo xwin build --locked --release --target=x86_64-pc-windows-msvc --bin server --no-default-features --features shared/server
|
||||||
|
|
||||||
- name: Archive
|
- name: Archive
|
||||||
run: |
|
run: |
|
||||||
ls -lisa target/x86_64-pc-windows-msvc/release/
|
ls -lisa target/x86_64-pc-windows-msvc/release/
|
||||||
cp target/x86_64-pc-windows-msvc/release/hedz_reloaded.exe hedz_reloaded.exe
|
cp target/x86_64-pc-windows-msvc/release/hedz_reloaded.exe target/x86_64-pc-windows-msvc/release/server.exe ./
|
||||||
tar -czf win.tar.gz hedz_reloaded.exe
|
tar -czf win.tar.gz hedz_reloaded.exe server.exe
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@@ -39,7 +39,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cargo build
|
cargo build --bin hedz_reloaded --no-default-features --features shared/client
|
||||||
|
cargo build --bin server --no-default-features --features shared/server
|
||||||
|
|
||||||
- name: Tests
|
- name: Tests
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
10
.github/workflows/ci_debug.yml
vendored
10
.github/workflows/ci_debug.yml
vendored
@@ -23,7 +23,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Build client
|
- name: Build client
|
||||||
run: |
|
run: |
|
||||||
cargo build --locked --target=x86_64-unknown-linux-gnu
|
cargo build --locked --target=x86_64-unknown-linux-gnu --bin hedz_reloaded --no-default-features --features shared/client
|
||||||
|
|
||||||
|
- name: Build server
|
||||||
|
run: |
|
||||||
|
cargo build --locked --target=x86_64-unknown-linux-gnu --bin server --no-default-features --features shared/server
|
||||||
|
|
||||||
- name: Lints
|
- name: Lints
|
||||||
run: |
|
run: |
|
||||||
@@ -31,8 +35,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Archive
|
- name: Archive
|
||||||
run: |
|
run: |
|
||||||
cp target/x86_64-unknown-linux-gnu/debug/hedz_reloaded hedz_reloaded
|
cp target/x86_64-unknown-linux-gnu/debug/hedz_reloaded target/x86_64-unknown-linux-gnu/debug/server ./
|
||||||
tar -czf steamos-debug.tar.gz hedz_reloaded
|
tar -czf steamos-debug.tar.gz hedz_reloaded server
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
27
.github/workflows/steam_alpha.yml
vendored
27
.github/workflows/steam_alpha.yml
vendored
@@ -22,14 +22,17 @@ jobs:
|
|||||||
|
|
||||||
- name: Build (lipo)
|
- name: Build (lipo)
|
||||||
run: |
|
run: |
|
||||||
cargo build --release --target=x86_64-apple-darwin
|
cargo build --release --target=x86_64-apple-darwin --bin hedz_reloaded --no-default-features --features shared/client
|
||||||
cargo build --release --target=aarch64-apple-darwin
|
cargo build --release --target=x86_64-apple-darwin --bin server --no-default-features --features shared/server
|
||||||
|
cargo build --release --target=aarch64-apple-darwin --bin hedz_reloaded --no-default-features --features shared/client
|
||||||
|
cargo build --release --target=aarch64-apple-darwin --bin server --no-default-features --features shared/server
|
||||||
lipo -create -output target/release/hedz_reloaded target/aarch64-apple-darwin/release/hedz_reloaded target/x86_64-apple-darwin/release/hedz_reloaded
|
lipo -create -output target/release/hedz_reloaded target/aarch64-apple-darwin/release/hedz_reloaded target/x86_64-apple-darwin/release/hedz_reloaded
|
||||||
|
lipo -create -output target/release/server target/aarch64-apple-darwin/release/server target/x86_64-apple-darwin/release/server
|
||||||
|
|
||||||
- name: Archive
|
- name: Archive
|
||||||
run: |
|
run: |
|
||||||
cp target/release/hedz_reloaded ./hedz_reloaded
|
cp target/release/hedz_reloaded target/release/server ./
|
||||||
tar -czf hedz-macos.tar.gz hedz_reloaded
|
tar -czf hedz-macos.tar.gz hedz_reloaded server
|
||||||
ls -lisah hedz-macos.tar.gz
|
ls -lisah hedz-macos.tar.gz
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
@@ -60,7 +63,7 @@ jobs:
|
|||||||
rm -rf $APP_ROOT/* | true
|
rm -rf $APP_ROOT/* | true
|
||||||
mkdir -p $APP_ROOT/assets
|
mkdir -p $APP_ROOT/assets
|
||||||
cp -r assets/* $APP_ROOT/assets
|
cp -r assets/* $APP_ROOT/assets
|
||||||
cp hedz_reloaded $APP_ROOT/
|
cp hedz_reloaded server $APP_ROOT/
|
||||||
cp build/macos/libsteam_api.dylib $APP_ROOT/
|
cp build/macos/libsteam_api.dylib $APP_ROOT/
|
||||||
|
|
||||||
- uses: ./.github/actions/steamcmd
|
- uses: ./.github/actions/steamcmd
|
||||||
@@ -111,12 +114,13 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cargo build --locked --release --target=x86_64-unknown-linux-gnu
|
cargo build --locked --release --target=x86_64-unknown-linux-gnu --bin hedz_reloaded --no-default-features --features shared/client
|
||||||
|
cargo build --locked --release --target=x86_64-unknown-linux-gnu --bin server --no-default-features --features shared/server
|
||||||
|
|
||||||
- name: Archive
|
- name: Archive
|
||||||
run: |
|
run: |
|
||||||
cp target/x86_64-unknown-linux-gnu/release/hedz_reloaded hedz_reloaded
|
cp target/x86_64-unknown-linux-gnu/release/hedz_reloaded target/x86_64-unknown-linux-gnu/release/server ./
|
||||||
tar -czf steamos.tar.gz hedz_reloaded
|
tar -czf steamos.tar.gz hedz_reloaded server
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
@@ -126,7 +130,7 @@ jobs:
|
|||||||
- name: Copy Binary for SteamOS
|
- name: Copy Binary for SteamOS
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build/steamos/content
|
mkdir -p build/steamos/content
|
||||||
cp target/x86_64-unknown-linux-gnu/release/hedz_reloaded build/steamos/content/hedz_reloaded
|
cp target/x86_64-unknown-linux-gnu/release/hedz_reloaded target/x86_64-unknown-linux-gnu/release/server build/steamos/content/
|
||||||
|
|
||||||
- name: Install SteamCMD
|
- name: Install SteamCMD
|
||||||
run: |
|
run: |
|
||||||
@@ -193,12 +197,13 @@ jobs:
|
|||||||
|
|
||||||
- name: Build binaries (Windows)
|
- name: Build binaries (Windows)
|
||||||
run: |
|
run: |
|
||||||
cargo xwin build --locked --release --target=x86_64-pc-windows-msvc
|
cargo xwin build --locked --release --target=x86_64-pc-windows-msvc --bin hedz_reloaded --no-default-features --features shared/client
|
||||||
|
cargo xwin build --locked --release --target=x86_64-pc-windows-msvc --bin server --no-default-features --features shared/server
|
||||||
|
|
||||||
- name: Move binary
|
- name: Move binary
|
||||||
run: |
|
run: |
|
||||||
ls -lisa target/x86_64-pc-windows-msvc/release/
|
ls -lisa target/x86_64-pc-windows-msvc/release/
|
||||||
cp target/x86_64-pc-windows-msvc/release/hedz_reloaded.exe build/win/hedz_reloaded.exe
|
cp target/x86_64-pc-windows-msvc/release/hedz_reloaded.exe target/x86_64-pc-windows-msvc/release/server.exe build/win/
|
||||||
|
|
||||||
- uses: ./.github/actions/steamcmd
|
- uses: ./.github/actions/steamcmd
|
||||||
with:
|
with:
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ build/steamos/hedz_reloaded
|
|||||||
build/steamos/.env
|
build/steamos/.env
|
||||||
build/macos/src/HEDZReloaded.app/Contents/MacOS
|
build/macos/src/HEDZReloaded.app/Contents/MacOS
|
||||||
build/macos/src/Applications
|
build/macos/src/Applications
|
||||||
|
server.log
|
||||||
132
Cargo.lock
generated
132
Cargo.lock
generated
@@ -280,6 +280,56 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"once_cell_polyfill",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.98"
|
version = "1.0.98"
|
||||||
@@ -2257,6 +2307,46 @@ dependencies = [
|
|||||||
"libloading",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.5.47"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.5.47"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.5.47"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clipboard-win"
|
name = "clipboard-win"
|
||||||
version = "5.4.0"
|
version = "5.4.0"
|
||||||
@@ -2282,6 +2372,12 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
version = "4.6.7"
|
version = "4.6.7"
|
||||||
@@ -4038,6 +4134,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@@ -5900,6 +6002,12 @@ version = "1.21.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oneshot"
|
name = "oneshot"
|
||||||
version = "0.1.11"
|
version = "0.1.11"
|
||||||
@@ -6793,9 +6901,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.25"
|
version = "0.1.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
|
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
@@ -6846,9 +6954,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.28"
|
version = "0.23.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643"
|
checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ring",
|
"ring",
|
||||||
@@ -6891,9 +6999,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
version = "0.103.3"
|
version = "0.103.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435"
|
checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ring",
|
"ring",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
@@ -7091,17 +7199,13 @@ dependencies = [
|
|||||||
"bevy-inspector-egui",
|
"bevy-inspector-egui",
|
||||||
"bevy-steamworks",
|
"bevy-steamworks",
|
||||||
"bevy-ui-gradients",
|
"bevy-ui-gradients",
|
||||||
"bevy_asset_loader",
|
|
||||||
"bevy_ballistic",
|
|
||||||
"bevy_common_assets",
|
"bevy_common_assets",
|
||||||
"bevy_debug_log",
|
|
||||||
"bevy_sprite3d",
|
"bevy_sprite3d",
|
||||||
"bevy_trenchbroom",
|
"bevy_trenchbroom",
|
||||||
|
"clap",
|
||||||
"happy_feet",
|
"happy_feet",
|
||||||
"lightyear",
|
"lightyear",
|
||||||
"lightyear_avian3d 0.21.1",
|
"lightyear_avian3d 0.21.1",
|
||||||
"nil 0.14.0",
|
|
||||||
"rand 0.8.5",
|
|
||||||
"ron",
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
"shared",
|
"shared",
|
||||||
@@ -7988,6 +8092,12 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.17.0"
|
version = "1.17.0"
|
||||||
|
|||||||
43
Cargo.toml
43
Cargo.toml
@@ -13,7 +13,43 @@ avian3d = { version = "0.3", default-features = false, features = [
|
|||||||
"parallel",
|
"parallel",
|
||||||
"serialize",
|
"serialize",
|
||||||
] }
|
] }
|
||||||
bevy = { version = "0.16.0", features = ["track_location"] }
|
bevy = { version = "0.16.0", default-features = false, features = [
|
||||||
|
"animation",
|
||||||
|
"async_executor",
|
||||||
|
"bevy_asset",
|
||||||
|
"bevy_audio",
|
||||||
|
"bevy_color",
|
||||||
|
"bevy_core_pipeline",
|
||||||
|
"bevy_gilrs",
|
||||||
|
"bevy_gizmos",
|
||||||
|
"bevy_gltf",
|
||||||
|
"bevy_input_focus",
|
||||||
|
"bevy_log",
|
||||||
|
"bevy_mesh_picking_backend",
|
||||||
|
"bevy_pbr",
|
||||||
|
"bevy_picking",
|
||||||
|
"bevy_render",
|
||||||
|
"bevy_scene",
|
||||||
|
"bevy_sprite",
|
||||||
|
"bevy_sprite_picking_backend",
|
||||||
|
"bevy_state",
|
||||||
|
"bevy_text",
|
||||||
|
"bevy_ui",
|
||||||
|
"bevy_ui_picking_backend",
|
||||||
|
"custom_cursor",
|
||||||
|
"default_font",
|
||||||
|
"hdr",
|
||||||
|
"multi_threaded",
|
||||||
|
"png",
|
||||||
|
"smaa_luts",
|
||||||
|
"std",
|
||||||
|
"sysinfo_plugin",
|
||||||
|
"tonemapping_luts",
|
||||||
|
"vorbis",
|
||||||
|
"webgl2",
|
||||||
|
"x11",
|
||||||
|
"track_location",
|
||||||
|
] }
|
||||||
bevy-inspector-egui = { version = "0.31" }
|
bevy-inspector-egui = { version = "0.31" }
|
||||||
bevy-steamworks = "0.13.0"
|
bevy-steamworks = "0.13.0"
|
||||||
bevy-ui-gradients = "0.4.0"
|
bevy-ui-gradients = "0.4.0"
|
||||||
@@ -22,7 +58,9 @@ bevy_ballistic = "0.4.0"
|
|||||||
bevy_common_assets = { version = "0.13.0", features = ["ron"] }
|
bevy_common_assets = { version = "0.13.0", features = ["ron"] }
|
||||||
bevy_debug_log = "0.6.0"
|
bevy_debug_log = "0.6.0"
|
||||||
bevy_sprite3d = "5.0.0"
|
bevy_sprite3d = "5.0.0"
|
||||||
bevy_trenchbroom = { version = "0.8.1", features = ["avian"] }
|
bevy_trenchbroom = { version = "0.8.1", default-features = false, features = [
|
||||||
|
"avian",
|
||||||
|
] }
|
||||||
happy_feet = { git = "https://github.com/atornity/happy_feet.git", rev = "1b24ed95f166e63af35e7b6f9f0053d6d28e1f1a", features = [
|
happy_feet = { git = "https://github.com/atornity/happy_feet.git", rev = "1b24ed95f166e63af35e7b6f9f0053d6d28e1f1a", features = [
|
||||||
"serde",
|
"serde",
|
||||||
] }
|
] }
|
||||||
@@ -33,7 +71,6 @@ lightyear = { version = "0.22.4", default-features = false, features = [
|
|||||||
"prediction",
|
"prediction",
|
||||||
"replication",
|
"replication",
|
||||||
"std",
|
"std",
|
||||||
"steam",
|
|
||||||
"udp",
|
"udp",
|
||||||
] }
|
] }
|
||||||
lightyear_avian3d = { git = "https://github.com/cBournhonesque/lightyear.git", rev = "03cbf419a2c0595261b64420bc0332fc3fe1cc3f" }
|
lightyear_avian3d = { git = "https://github.com/cBournhonesque/lightyear.git", rev = "03cbf419a2c0595261b64420bc0332fc3fe1cc3f" }
|
||||||
|
|||||||
@@ -5,12 +5,15 @@ edition = "2024"
|
|||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["lightyear/client"]
|
default = ["shared/client"]
|
||||||
dbg = ["avian3d/debug-plugin", "dep:bevy-inspector-egui", "shared/dbg"]
|
dbg = ["avian3d/debug-plugin", "dep:bevy-inspector-egui", "shared/dbg"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
avian3d = { workspace = true }
|
avian3d = { workspace = true }
|
||||||
bevy = { workspace = true }
|
bevy = { workspace = true, default-features = false, features = [
|
||||||
|
"bevy_window",
|
||||||
|
"bevy_winit",
|
||||||
|
] }
|
||||||
bevy-inspector-egui = { workspace = true, optional = true }
|
bevy-inspector-egui = { workspace = true, optional = true }
|
||||||
bevy-steamworks = { workspace = true }
|
bevy-steamworks = { workspace = true }
|
||||||
bevy-ui-gradients = { workspace = true }
|
bevy-ui-gradients = { workspace = true }
|
||||||
@@ -19,7 +22,7 @@ bevy_ballistic = { workspace = true }
|
|||||||
bevy_common_assets = { workspace = true }
|
bevy_common_assets = { workspace = true }
|
||||||
bevy_debug_log = { workspace = true }
|
bevy_debug_log = { workspace = true }
|
||||||
bevy_sprite3d = { workspace = true }
|
bevy_sprite3d = { workspace = true }
|
||||||
bevy_trenchbroom = { workspace = true }
|
bevy_trenchbroom = { workspace = true, features = ["client"] }
|
||||||
happy_feet = { workspace = true }
|
happy_feet = { workspace = true }
|
||||||
lightyear = { workspace = true }
|
lightyear = { workspace = true }
|
||||||
nil = { workspace = true }
|
nil = { workspace = true }
|
||||||
|
|||||||
@@ -1,26 +1,48 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::{prelude::*, utils::synccell::SyncCell};
|
||||||
use lightyear::{
|
use lightyear::{
|
||||||
connection::client::ClientState,
|
|
||||||
netcode::Key,
|
netcode::Key,
|
||||||
prelude::{client::NetcodeConfig, input::native::InputMarker, *},
|
prelude::{client::NetcodeConfig, input::native::InputMarker, *},
|
||||||
};
|
};
|
||||||
use shared::{
|
use nil::prelude::Mutex;
|
||||||
GameState, control::ControlState, global_observer, heads_database::HeadsDatabase,
|
use shared::{GameState, control::ControlState, global_observer, player::Player};
|
||||||
player::Player, tb_entities::SpawnPoint,
|
use std::{
|
||||||
|
env::current_exe,
|
||||||
|
io::{BufRead, BufReader},
|
||||||
|
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||||
|
process::Stdio,
|
||||||
|
sync::{LazyLock, mpsc},
|
||||||
};
|
};
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
|
||||||
|
/// Cache of server processes to be cleared at process exit
|
||||||
|
static SERVER_PROCESSES: LazyLock<Mutex<Vec<std::process::Child>>> = LazyLock::new(Mutex::default);
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.add_systems(Startup, temp_connect_on_startup);
|
app.add_systems(OnEnter(GameState::Connecting), attempt_connection);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
FixedUpdate,
|
Update,
|
||||||
spawn_disconnected_player.run_if(in_state(GameState::Playing)),
|
parse_local_server_stdout.run_if(resource_exists::<LocalServerStdout>),
|
||||||
);
|
);
|
||||||
|
app.add_systems(Last, close_server_processes);
|
||||||
|
|
||||||
|
global_observer!(app, on_connecting);
|
||||||
|
global_observer!(app, on_connection_failed);
|
||||||
|
global_observer!(app, on_connection_succeeded);
|
||||||
global_observer!(app, temp_give_player_marker);
|
global_observer!(app, temp_give_player_marker);
|
||||||
|
global_observer!(app, connect_on_local_server_started);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn temp_connect_on_startup(mut commands: Commands) -> Result {
|
fn close_server_processes(mut app_exit: EventReader<AppExit>) {
|
||||||
|
if app_exit.read().next().is_some() {
|
||||||
|
let mut lock = SERVER_PROCESSES.lock();
|
||||||
|
for mut process in lock.drain(..) {
|
||||||
|
if let Err(err) = process.wait() {
|
||||||
|
error!("{err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attempt_connection(mut commands: Commands) -> Result {
|
||||||
let mut args = std::env::args();
|
let mut args = std::env::args();
|
||||||
let client_port = loop {
|
let client_port = loop {
|
||||||
match args.next().as_deref() {
|
match args.next().as_deref() {
|
||||||
@@ -44,9 +66,9 @@ fn temp_connect_on_startup(mut commands: Commands) -> Result {
|
|||||||
.spawn((
|
.spawn((
|
||||||
Name::from("Client"),
|
Name::from("Client"),
|
||||||
Client::default(),
|
Client::default(),
|
||||||
|
Link::new(None),
|
||||||
LocalAddr(client_addr),
|
LocalAddr(client_addr),
|
||||||
PeerAddr(server_addr),
|
PeerAddr(server_addr),
|
||||||
Link::new(None),
|
|
||||||
ReplicationReceiver::default(),
|
ReplicationReceiver::default(),
|
||||||
client::NetcodeClient::new(
|
client::NetcodeClient::new(
|
||||||
auth,
|
auth,
|
||||||
@@ -62,15 +84,104 @@ fn temp_connect_on_startup(mut commands: Commands) -> Result {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_disconnected_player(
|
fn on_connection_succeeded(
|
||||||
disconnected: Single<&Client, Changed<Client>>,
|
_trigger: Trigger<OnAdd, Connected>,
|
||||||
commands: Commands,
|
state: Res<State<GameState>>,
|
||||||
asset_server: Res<AssetServer>,
|
mut change_state: ResMut<NextState<GameState>>,
|
||||||
query: Query<&Transform, With<SpawnPoint>>,
|
|
||||||
heads_db: Res<HeadsDatabase>,
|
|
||||||
) {
|
) {
|
||||||
if disconnected.state == ClientState::Disconnected {
|
if *state == GameState::Connecting {
|
||||||
shared::player::spawn(commands, Entity::PLACEHOLDER, query, asset_server, heads_db)
|
change_state.set(GameState::Playing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A client starts `Disconnected`, so in order to tell if it *actually* failed to connect/disconnected
|
||||||
|
/// vs. simply having been created, we need some extra state.
|
||||||
|
#[derive(Component)]
|
||||||
|
struct ClientActive;
|
||||||
|
|
||||||
|
fn on_connecting(trigger: Trigger<OnAdd, Connecting>, mut commands: Commands) {
|
||||||
|
commands.entity(trigger.target()).insert(ClientActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
struct LocalServerStdout(SyncCell<mpsc::Receiver<String>>);
|
||||||
|
|
||||||
|
fn on_connection_failed(
|
||||||
|
trigger: Trigger<OnAdd, Disconnected>,
|
||||||
|
disconnected: Query<&Disconnected>,
|
||||||
|
mut commands: Commands,
|
||||||
|
client_active: Query<&ClientActive>,
|
||||||
|
mut opened_server: Local<bool>,
|
||||||
|
) {
|
||||||
|
let disconnected = disconnected.get(trigger.target()).unwrap();
|
||||||
|
if *opened_server {
|
||||||
|
panic!(
|
||||||
|
"failed to connect to local server: {:?}",
|
||||||
|
disconnected.reason
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let client = trigger.target();
|
||||||
|
if client_active.contains(client) {
|
||||||
|
commands.entity(client).remove::<ClientActive>();
|
||||||
|
|
||||||
|
// the server executable is assumed to be adjacent to the client executable
|
||||||
|
let mut exe_path = current_exe().expect("failed to get path of client executable");
|
||||||
|
exe_path.set_file_name("server");
|
||||||
|
let mut server_process = std::process::Command::new(exe_path)
|
||||||
|
.args(["--timeout", "60", "--close-on-client-disconnect"])
|
||||||
|
.stdin(Stdio::null())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::null())
|
||||||
|
.spawn()
|
||||||
|
.expect("failed to start server");
|
||||||
|
let server_stdout = server_process.stdout.take().unwrap();
|
||||||
|
SERVER_PROCESSES.lock().push(server_process);
|
||||||
|
|
||||||
|
let (tx, rx) = std::sync::mpsc::channel();
|
||||||
|
|
||||||
|
let stdout = BufReader::new(server_stdout).lines();
|
||||||
|
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
for line in stdout {
|
||||||
|
match line {
|
||||||
|
Ok(line) => {
|
||||||
|
tx.send(line).unwrap();
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
error!("error reading local server stdout: `{error}`");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
commands.insert_resource(LocalServerStdout(SyncCell::new(rx)));
|
||||||
|
|
||||||
|
*opened_server = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Event)]
|
||||||
|
struct LocalServerStarted;
|
||||||
|
|
||||||
|
fn parse_local_server_stdout(mut commands: Commands, mut stdout: ResMut<LocalServerStdout>) {
|
||||||
|
let stdout: &mut LocalServerStdout = &mut stdout;
|
||||||
|
|
||||||
|
while let Ok(line) = stdout.0.get().try_recv() {
|
||||||
|
if let "hedz.server_started" = &line[..] {
|
||||||
|
commands.trigger(LocalServerStarted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connect_on_local_server_started(
|
||||||
|
_trigger: Trigger<LocalServerStarted>,
|
||||||
|
state: Res<State<GameState>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
client: Single<Entity, With<Client>>,
|
||||||
|
) {
|
||||||
|
if *state == GameState::Connecting {
|
||||||
|
commands.entity(*client).trigger(Connect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
crates/client/src/enemy.rs
Normal file
14
crates/client/src/enemy.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use shared::{GameState, tb_entities::EnemySpawn};
|
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) {
|
||||||
|
app.add_systems(OnExit(GameState::MapLoading), despawn_enemy_spawns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Despawn enemy spawners because only the server will ever spawn enemies with them, and they have a
|
||||||
|
/// collider.
|
||||||
|
fn despawn_enemy_spawns(mut commands: Commands, enemy_spawns: Query<Entity, With<EnemySpawn>>) {
|
||||||
|
for spawner in enemy_spawns.iter() {
|
||||||
|
commands.entity(spawner).despawn();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
mod client;
|
mod client;
|
||||||
mod debug;
|
mod debug;
|
||||||
|
mod enemy;
|
||||||
mod steam;
|
mod steam;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ fn main() {
|
|||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
.set(bevy::log::LogPlugin {
|
.set(bevy::log::LogPlugin {
|
||||||
filter: "info,lightyear_replication=off".into(),
|
filter: "info,lightyear_replication=off,bevy_ecs::hierarchy=off".into(),
|
||||||
level: bevy::log::Level::INFO,
|
level: bevy::log::Level::INFO,
|
||||||
// provide custom log layer to receive logging events
|
// provide custom log layer to receive logging events
|
||||||
custom_layer: bevy_debug_log::log_capture_layer,
|
custom_layer: bevy_debug_log::log_capture_layer,
|
||||||
@@ -90,6 +91,7 @@ fn main() {
|
|||||||
app.add_plugins(animation::plugin);
|
app.add_plugins(animation::plugin);
|
||||||
app.add_plugins(character::plugin);
|
app.add_plugins(character::plugin);
|
||||||
app.add_plugins(cash::plugin);
|
app.add_plugins(cash::plugin);
|
||||||
|
app.add_plugins(enemy::plugin);
|
||||||
app.add_plugins(player::plugin);
|
app.add_plugins(player::plugin);
|
||||||
app.add_plugins(gates::plugin);
|
app.add_plugins(gates::plugin);
|
||||||
app.add_plugins(platforms::plugin);
|
app.add_plugins(platforms::plugin);
|
||||||
|
|||||||
@@ -4,26 +4,22 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["lightyear/server"]
|
default = ["shared/server"]
|
||||||
dbg = ["avian3d/debug-plugin", "dep:bevy-inspector-egui", "shared/dbg"]
|
dbg = ["avian3d/debug-plugin", "dep:bevy-inspector-egui", "shared/dbg"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
avian3d = { workspace = true }
|
avian3d = { workspace = true }
|
||||||
bevy = { workspace = true }
|
bevy = { workspace = true, default-features = false }
|
||||||
bevy-inspector-egui = { workspace = true, optional = true }
|
bevy-inspector-egui = { workspace = true, optional = true }
|
||||||
bevy-steamworks = { workspace = true }
|
bevy-steamworks = { workspace = true }
|
||||||
bevy-ui-gradients = { workspace = true }
|
bevy-ui-gradients = { workspace = true }
|
||||||
bevy_asset_loader = { workspace = true }
|
|
||||||
bevy_ballistic = { workspace = true }
|
|
||||||
bevy_common_assets = { workspace = true }
|
bevy_common_assets = { workspace = true }
|
||||||
bevy_debug_log = { workspace = true }
|
|
||||||
bevy_sprite3d = { workspace = true }
|
bevy_sprite3d = { workspace = true }
|
||||||
bevy_trenchbroom = { workspace = true }
|
bevy_trenchbroom = { workspace = true }
|
||||||
|
clap = { version = "=4.5.47", features = ["derive"] }
|
||||||
happy_feet = { workspace = true }
|
happy_feet = { workspace = true }
|
||||||
lightyear = { workspace = true }
|
lightyear = { workspace = true }
|
||||||
lightyear_avian3d = { workspace = true }
|
lightyear_avian3d = { workspace = true }
|
||||||
nil = { workspace = true }
|
|
||||||
rand = { workspace = true }
|
|
||||||
ron = { workspace = true }
|
ron = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
shared = { workspace = true }
|
shared = { workspace = true }
|
||||||
|
|||||||
20
crates/server/src/config.rs
Normal file
20
crates/server/src/config.rs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) {
|
||||||
|
let config = ServerConfig::parse();
|
||||||
|
|
||||||
|
app.insert_resource(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The server for HEDZ Reloaded
|
||||||
|
#[derive(Resource, Parser, Debug)]
|
||||||
|
#[command(version, about, long_about = None)]
|
||||||
|
pub struct ServerConfig {
|
||||||
|
#[arg(long, default_value_t = f32::INFINITY)]
|
||||||
|
/// How long to wait for a client to connect before closing, in seconds
|
||||||
|
pub timeout: f32,
|
||||||
|
#[arg(long, default_value_t = false)]
|
||||||
|
/// Whether to close when a client disconnects
|
||||||
|
pub close_on_client_disconnect: bool,
|
||||||
|
}
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
use crate::utils::{auto_rotate, explosions};
|
use crate::utils::{auto_rotate, explosions};
|
||||||
use avian3d::prelude::*;
|
use avian3d::prelude::*;
|
||||||
use bevy::{audio::Volume, core_pipeline::tonemapping::Tonemapping, prelude::*};
|
use bevy::{
|
||||||
|
app::plugin_group,
|
||||||
|
audio::Volume,
|
||||||
|
core_pipeline::tonemapping::Tonemapping,
|
||||||
|
log::{BoxedLayer, tracing_subscriber::Layer},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
use bevy_common_assets::ron::RonAssetPlugin;
|
use bevy_common_assets::ron::RonAssetPlugin;
|
||||||
use bevy_sprite3d::Sprite3dPlugin;
|
use bevy_sprite3d::Sprite3dPlugin;
|
||||||
use bevy_trenchbroom::prelude::*;
|
use bevy_trenchbroom::prelude::*;
|
||||||
@@ -11,8 +17,61 @@ use shared::*;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use utils::{billboards, sprite_3d_animation, squish_animation, trail};
|
use utils::{billboards, sprite_3d_animation, squish_animation, trail};
|
||||||
|
|
||||||
|
mod config;
|
||||||
mod server;
|
mod server;
|
||||||
|
|
||||||
|
plugin_group! {
|
||||||
|
pub struct DefaultPlugins {
|
||||||
|
bevy::app:::PanicHandlerPlugin,
|
||||||
|
bevy::log:::LogPlugin,
|
||||||
|
bevy::app:::TaskPoolPlugin,
|
||||||
|
bevy::diagnostic:::FrameCountPlugin,
|
||||||
|
bevy::time:::TimePlugin,
|
||||||
|
bevy::transform:::TransformPlugin,
|
||||||
|
bevy::diagnostic:::DiagnosticsPlugin,
|
||||||
|
bevy::input:::InputPlugin,
|
||||||
|
bevy::app:::ScheduleRunnerPlugin,
|
||||||
|
bevy::window:::WindowPlugin,
|
||||||
|
bevy::a11y:::AccessibilityPlugin,
|
||||||
|
bevy::app:::TerminalCtrlCHandlerPlugin,
|
||||||
|
bevy::asset:::AssetPlugin,
|
||||||
|
bevy::scene:::ScenePlugin,
|
||||||
|
bevy::render:::RenderPlugin,
|
||||||
|
bevy::render::texture:::ImagePlugin,
|
||||||
|
bevy::render::pipelined_rendering:::PipelinedRenderingPlugin,
|
||||||
|
bevy::core_pipeline:::CorePipelinePlugin,
|
||||||
|
bevy::sprite:::SpritePlugin,
|
||||||
|
bevy::text:::TextPlugin,
|
||||||
|
bevy::ui:::UiPlugin,
|
||||||
|
bevy::pbr:::PbrPlugin,
|
||||||
|
bevy::gltf:::GltfPlugin,
|
||||||
|
bevy::audio:::AudioPlugin,
|
||||||
|
bevy::gilrs:::GilrsPlugin,
|
||||||
|
bevy::animation:::AnimationPlugin,
|
||||||
|
bevy::gizmos:::GizmoPlugin,
|
||||||
|
bevy::state::app:::StatesPlugin,
|
||||||
|
#[plugin_group]
|
||||||
|
bevy::picking:::DefaultPickingPlugins,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log_to_file_layer(_app: &mut App) -> Option<BoxedLayer> {
|
||||||
|
let file = std::fs::OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open("server.log")
|
||||||
|
.ok()?;
|
||||||
|
Some(
|
||||||
|
bevy::log::tracing_subscriber::fmt::layer()
|
||||||
|
.with_writer(std::sync::Mutex::new(file))
|
||||||
|
.with_ansi(false)
|
||||||
|
.with_file(true)
|
||||||
|
.with_line_number(true)
|
||||||
|
.boxed(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
|
|
||||||
@@ -26,28 +85,13 @@ fn main() {
|
|||||||
cam_follow: true,
|
cam_follow: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
app.add_plugins(
|
app.add_plugins(DefaultPlugins.set(bevy::log::LogPlugin {
|
||||||
DefaultPlugins
|
filter: "info,lightyear_replication=off".into(),
|
||||||
.set(WindowPlugin {
|
|
||||||
primary_window: Some(Window {
|
|
||||||
title: "HEDZ Reloaded".into(),
|
|
||||||
// resolution: (1024., 768.).into(),
|
|
||||||
..default()
|
|
||||||
}),
|
|
||||||
..default()
|
|
||||||
})
|
|
||||||
.set(bevy::log::LogPlugin {
|
|
||||||
filter: "info".into(),
|
|
||||||
level: bevy::log::Level::INFO,
|
level: bevy::log::Level::INFO,
|
||||||
// provide custom log layer to receive logging events
|
// provide custom log layer to receive logging events
|
||||||
custom_layer: bevy_debug_log::log_capture_layer,
|
custom_layer: log_to_file_layer,
|
||||||
}),
|
}));
|
||||||
);
|
|
||||||
|
|
||||||
app.add_plugins(
|
|
||||||
bevy_debug_log::LogViewerPlugin::default()
|
|
||||||
.auto_open_threshold(bevy::log::tracing::level_filters::LevelFilter::OFF),
|
|
||||||
);
|
|
||||||
app.add_plugins(ServerPlugins {
|
app.add_plugins(ServerPlugins {
|
||||||
tick_duration: Duration::from_secs_f32(1.0 / 60.0),
|
tick_duration: Duration::from_secs_f32(1.0 / 60.0),
|
||||||
});
|
});
|
||||||
@@ -78,6 +122,7 @@ fn main() {
|
|||||||
app.add_plugins(animation::plugin);
|
app.add_plugins(animation::plugin);
|
||||||
app.add_plugins(character::plugin);
|
app.add_plugins(character::plugin);
|
||||||
app.add_plugins(cash::plugin);
|
app.add_plugins(cash::plugin);
|
||||||
|
app.add_plugins(config::plugin);
|
||||||
app.add_plugins(player::plugin);
|
app.add_plugins(player::plugin);
|
||||||
app.add_plugins(gates::plugin);
|
app.add_plugins(gates::plugin);
|
||||||
app.add_plugins(platforms::plugin);
|
app.add_plugins(platforms::plugin);
|
||||||
|
|||||||
@@ -1,16 +1,25 @@
|
|||||||
|
use crate::config::ServerConfig;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use lightyear::prelude::{
|
use lightyear::prelude::{
|
||||||
server::{NetcodeConfig, NetcodeServer, ServerUdpIo},
|
server::{NetcodeConfig, NetcodeServer, ServerUdpIo, Started},
|
||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
use shared::{heads_database::HeadsDatabase, tb_entities::SpawnPoint, utils::commands::IsServer};
|
use shared::{GameState, global_observer, heads_database::HeadsDatabase, tb_entities::SpawnPoint};
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.init_resource::<IsServer>();
|
app.add_systems(Startup, (start_server, setup_timeout_timer));
|
||||||
|
app.add_systems(
|
||||||
|
Update,
|
||||||
|
(
|
||||||
|
notify_started.run_if(in_state(GameState::Playing)),
|
||||||
|
run_timeout,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
app.add_systems(Startup, start_server);
|
global_observer!(app, handle_new_client);
|
||||||
app.add_observer(handle_new_client);
|
global_observer!(app, close_on_disconnect);
|
||||||
|
global_observer!(app, cancel_timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_new_client(
|
fn handle_new_client(
|
||||||
@@ -34,17 +43,52 @@ fn handle_new_client(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn close_on_disconnect(
|
||||||
|
_trigger: Trigger<OnRemove, Connected>,
|
||||||
|
config: Res<ServerConfig>,
|
||||||
|
mut writer: EventWriter<AppExit>,
|
||||||
|
) {
|
||||||
|
if config.close_on_client_disconnect {
|
||||||
|
writer.write(AppExit::Success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn start_server(mut commands: Commands) -> Result {
|
fn start_server(mut commands: Commands) -> Result {
|
||||||
let server_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 25565);
|
let server_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 25565);
|
||||||
|
|
||||||
commands
|
let mut commands = commands.spawn((
|
||||||
.spawn((
|
|
||||||
Name::from("Server"),
|
Name::from("Server"),
|
||||||
LocalAddr(server_addr),
|
LocalAddr(server_addr),
|
||||||
ServerUdpIo::default(),
|
ServerUdpIo::default(),
|
||||||
NetcodeServer::new(NetcodeConfig::default()),
|
NetcodeServer::new(NetcodeConfig::default()),
|
||||||
))
|
));
|
||||||
.trigger(server::Start);
|
commands.trigger(server::Start);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn notify_started(started: Query<&Started>, mut notified: Local<bool>) {
|
||||||
|
if !*notified && !started.is_empty() {
|
||||||
|
println!("hedz.server_started");
|
||||||
|
*notified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
struct TimeoutTimer(f32);
|
||||||
|
|
||||||
|
fn setup_timeout_timer(mut commands: Commands, config: Res<ServerConfig>) {
|
||||||
|
commands.insert_resource(TimeoutTimer(config.timeout));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_timeout(mut timer: ResMut<TimeoutTimer>, mut writer: EventWriter<AppExit>, time: Res<Time>) {
|
||||||
|
timer.0 -= time.delta_secs();
|
||||||
|
|
||||||
|
if timer.0 <= 0.0 {
|
||||||
|
writer.write(AppExit::Success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cancel_timeout(_trigger: Trigger<OnAdd, Connected>, mut timer: ResMut<TimeoutTimer>) {
|
||||||
|
timer.0 = f32::INFINITY;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
client = ["lightyear/client"]
|
||||||
|
server = ["lightyear/server"]
|
||||||
dbg = []
|
dbg = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
avian3d = { workspace = true }
|
avian3d = { workspace = true }
|
||||||
bevy = { workspace = true }
|
bevy = { workspace = true, default-features = false }
|
||||||
bevy-inspector-egui = { workspace = true, optional = true }
|
bevy-inspector-egui = { workspace = true, optional = true }
|
||||||
bevy-steamworks = { workspace = true }
|
bevy-steamworks = { workspace = true }
|
||||||
bevy-ui-gradients = { workspace = true }
|
bevy-ui-gradients = { workspace = true }
|
||||||
|
|||||||
@@ -6,14 +6,11 @@ use crate::{
|
|||||||
physics_layers::GameLayer,
|
physics_layers::GameLayer,
|
||||||
protocol::GltfSceneRoot,
|
protocol::GltfSceneRoot,
|
||||||
tb_entities::EnemySpawn,
|
tb_entities::EnemySpawn,
|
||||||
utils::{
|
utils::{auto_rotate::AutoRotation, commands::CommandExt, global_observer},
|
||||||
auto_rotate::AutoRotation,
|
|
||||||
commands::{CommandExt, EntityCommandExt},
|
|
||||||
global_observer,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use avian3d::prelude::*;
|
use avian3d::prelude::*;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
#[cfg(feature = "server")]
|
||||||
use lightyear::prelude::{NetworkTarget, Replicate};
|
use lightyear::prelude::{NetworkTarget, Replicate};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
@@ -63,8 +60,7 @@ fn on_trigger_missile(
|
|||||||
let mut transform = Transform::from_translation(state.pos).with_rotation(rotation);
|
let mut transform = Transform::from_translation(state.pos).with_rotation(rotation);
|
||||||
transform.translation += transform.forward().as_vec3() * 2.0;
|
transform.translation += transform.forward().as_vec3() * 2.0;
|
||||||
|
|
||||||
commands
|
let mut _projectile = commands.spawn((
|
||||||
.spawn((
|
|
||||||
Name::new("projectile-missile"),
|
Name::new("projectile-missile"),
|
||||||
CurverProjectile {
|
CurverProjectile {
|
||||||
time: time.elapsed_secs(),
|
time: time.elapsed_secs(),
|
||||||
@@ -84,8 +80,10 @@ fn on_trigger_missile(
|
|||||||
AutoRotation(Quat::from_rotation_x(0.4) * Quat::from_rotation_z(0.3)),
|
AutoRotation(Quat::from_rotation_x(0.4) * Quat::from_rotation_z(0.3)),
|
||||||
GltfSceneRoot::Projectile(head.projectile.clone()),
|
GltfSceneRoot::Projectile(head.projectile.clone()),
|
||||||
),],
|
),],
|
||||||
))
|
));
|
||||||
.insert_server(Replicate::to_clients(NetworkTarget::All));
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
_projectile.insert(Replicate::to_clients(NetworkTarget::All));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enemy_hit(
|
fn enemy_hit(
|
||||||
|
|||||||
@@ -6,15 +6,11 @@ use crate::{
|
|||||||
physics_layers::GameLayer,
|
physics_layers::GameLayer,
|
||||||
protocol::GltfSceneRoot,
|
protocol::GltfSceneRoot,
|
||||||
sounds::PlaySound,
|
sounds::PlaySound,
|
||||||
utils::{
|
utils::{commands::CommandExt, explosions::Explosion, global_observer, trail::Trail},
|
||||||
commands::{CommandExt, EntityCommandExt},
|
|
||||||
explosions::Explosion,
|
|
||||||
global_observer,
|
|
||||||
trail::Trail,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use avian3d::prelude::*;
|
use avian3d::prelude::*;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
#[cfg(feature = "server")]
|
||||||
use lightyear::prelude::{NetworkTarget, Replicate};
|
use lightyear::prelude::{NetworkTarget, Replicate};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
@@ -63,8 +59,7 @@ fn on_trigger_missile(
|
|||||||
let mut transform = Transform::from_translation(state.pos).with_rotation(rotation);
|
let mut transform = Transform::from_translation(state.pos).with_rotation(rotation);
|
||||||
transform.translation += transform.forward().as_vec3() * 2.0;
|
transform.translation += transform.forward().as_vec3() * 2.0;
|
||||||
|
|
||||||
commands
|
let mut _projectile = commands.spawn((
|
||||||
.spawn((
|
|
||||||
Name::new("projectile-missile"),
|
Name::new("projectile-missile"),
|
||||||
MissileProjectile {
|
MissileProjectile {
|
||||||
time: time.elapsed_secs(),
|
time: time.elapsed_secs(),
|
||||||
@@ -101,8 +96,9 @@ fn on_trigger_missile(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
))
|
));
|
||||||
.insert_server(Replicate::to_clients(NetworkTarget::All));
|
#[cfg(feature = "server")]
|
||||||
|
_projectile.insert(Replicate::to_clients(NetworkTarget::All));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(mut query: Query<&mut Transform, With<MissileProjectile>>) {
|
fn update(mut query: Query<&mut Transform, With<MissileProjectile>>) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use crate::{
|
|||||||
physics_layers::GameLayer,
|
physics_layers::GameLayer,
|
||||||
player::{Player, PlayerBodyMesh},
|
player::{Player, PlayerBodyMesh},
|
||||||
sounds::PlaySound,
|
sounds::PlaySound,
|
||||||
utils::{billboards::Billboard, commands::IsServer, sprite_3d_animation::AnimationTimer},
|
utils::{billboards::Billboard, sprite_3d_animation::AnimationTimer},
|
||||||
};
|
};
|
||||||
use bevy::{pbr::NotShadowCaster, prelude::*};
|
use bevy::{pbr::NotShadowCaster, prelude::*};
|
||||||
use bevy_sprite3d::{Sprite3dBuilder, Sprite3dParams};
|
use bevy_sprite3d::{Sprite3dBuilder, Sprite3dParams};
|
||||||
@@ -126,11 +126,10 @@ fn on_trigger_state(
|
|||||||
player: Query<(&ActiveHead, &ActionState<ControlState>), With<Player>>,
|
player: Query<(&ActiveHead, &ActionState<ControlState>), With<Player>>,
|
||||||
headdb: Res<HeadsDatabase>,
|
headdb: Res<HeadsDatabase>,
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
is_server: Option<Res<IsServer>>,
|
|
||||||
client: Query<&Client>,
|
client: Query<&Client>,
|
||||||
) {
|
) {
|
||||||
if let Ok(client) = client.single()
|
if let Ok(client) = client.single()
|
||||||
&& (client.state == ClientState::Connected && is_server.is_none())
|
&& (client.state == ClientState::Connected && cfg!(not(feature = "server")))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,15 +7,13 @@ use crate::{
|
|||||||
protocol::GltfSceneRoot,
|
protocol::GltfSceneRoot,
|
||||||
sounds::PlaySound,
|
sounds::PlaySound,
|
||||||
utils::{
|
utils::{
|
||||||
auto_rotate::AutoRotation,
|
auto_rotate::AutoRotation, commands::CommandExt, explosions::Explosion, global_observer,
|
||||||
commands::{CommandExt, EntityCommandExt},
|
|
||||||
explosions::Explosion,
|
|
||||||
global_observer,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use avian3d::prelude::*;
|
use avian3d::prelude::*;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_ballistic::launch_velocity;
|
use bevy_ballistic::launch_velocity;
|
||||||
|
#[cfg(feature = "server")]
|
||||||
use lightyear::prelude::{NetworkTarget, Replicate};
|
use lightyear::prelude::{NetworkTarget, Replicate};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
@@ -62,8 +60,7 @@ fn on_trigger_thrown(
|
|||||||
//TODO: projectile db?
|
//TODO: projectile db?
|
||||||
let explosion_animation = !matches!(state.head, 8 | 16);
|
let explosion_animation = !matches!(state.head, 8 | 16);
|
||||||
|
|
||||||
commands
|
let mut projectile = commands.spawn((
|
||||||
.spawn((
|
|
||||||
Transform::from_translation(pos),
|
Transform::from_translation(pos),
|
||||||
Name::new("projectile-thrown"),
|
Name::new("projectile-thrown"),
|
||||||
ThrownProjectile {
|
ThrownProjectile {
|
||||||
@@ -81,12 +78,14 @@ fn on_trigger_thrown(
|
|||||||
LinearVelocity(vel),
|
LinearVelocity(vel),
|
||||||
Visibility::default(),
|
Visibility::default(),
|
||||||
Sensor,
|
Sensor,
|
||||||
))
|
));
|
||||||
.insert_server(Replicate::to_clients(NetworkTarget::All))
|
projectile.with_child((
|
||||||
.with_child((
|
|
||||||
AutoRotation(Quat::from_rotation_x(0.4) * Quat::from_rotation_z(0.3)),
|
AutoRotation(Quat::from_rotation_x(0.4) * Quat::from_rotation_z(0.3)),
|
||||||
GltfSceneRoot::Projectile(head.projectile.clone()),
|
GltfSceneRoot::Projectile(head.projectile.clone()),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
projectile.insert(Replicate::to_clients(NetworkTarget::All));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shot_collision(
|
fn shot_collision(
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use crate::{
|
|||||||
animation::AnimationFlags,
|
animation::AnimationFlags,
|
||||||
control::{controller_common::MovementSpeedFactor, controls::ControllerSettings},
|
control::{controller_common::MovementSpeedFactor, controls::ControllerSettings},
|
||||||
player::PlayerBodyMesh,
|
player::PlayerBodyMesh,
|
||||||
utils::commands::IsServer,
|
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use happy_feet::prelude::{Grounding, KinematicVelocity, MoveInput};
|
use happy_feet::prelude::{Grounding, KinematicVelocity, MoveInput};
|
||||||
@@ -50,7 +49,6 @@ fn apply_controls(
|
|||||||
&ActionState<ControlState>,
|
&ActionState<ControlState>,
|
||||||
)>,
|
)>,
|
||||||
rig_transform_q: Option<Single<&GlobalTransform, With<PlayerBodyMesh>>>,
|
rig_transform_q: Option<Single<&GlobalTransform, With<PlayerBodyMesh>>>,
|
||||||
is_server: Option<Res<IsServer>>,
|
|
||||||
) {
|
) {
|
||||||
let Ok((
|
let Ok((
|
||||||
mut move_input,
|
mut move_input,
|
||||||
@@ -80,7 +78,7 @@ fn apply_controls(
|
|||||||
move_input.set(direction * move_factor.0);
|
move_input.set(direction * move_factor.0);
|
||||||
|
|
||||||
if controls.jump && grounding.is_grounded() {
|
if controls.jump && grounding.is_grounded() {
|
||||||
if is_server.is_some() {
|
if cfg!(feature = "server") {
|
||||||
flags.jumping = true;
|
flags.jumping = true;
|
||||||
flags.jump_count += 1;
|
flags.jump_count += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use super::{ControlState, Controls};
|
use super::{ControlState, Controls};
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
use crate::player::Player;
|
||||||
use crate::{
|
use crate::{
|
||||||
GameState,
|
GameState,
|
||||||
control::{CharacterInputEnabled, ControllerSet},
|
control::{CharacterInputEnabled, ControllerSet},
|
||||||
player::Player,
|
|
||||||
};
|
};
|
||||||
use bevy::{
|
use bevy::{
|
||||||
input::{
|
input::{
|
||||||
@@ -12,7 +13,8 @@ use bevy::{
|
|||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use lightyear::prelude::{client::input::InputSet::WriteClientInputs, input::native::ActionState};
|
#[cfg(feature = "client")]
|
||||||
|
use lightyear::prelude::input::native::ActionState;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
@@ -38,7 +40,14 @@ pub fn plugin(app: &mut App) {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
app.add_systems(FixedPreUpdate, buffer_inputs.in_set(WriteClientInputs));
|
#[cfg(feature = "client")]
|
||||||
|
{
|
||||||
|
use lightyear::prelude::client::input::InputSet;
|
||||||
|
app.add_systems(
|
||||||
|
FixedPreUpdate,
|
||||||
|
buffer_inputs.in_set(InputSet::WriteClientInputs),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
Update,
|
Update,
|
||||||
@@ -53,6 +62,7 @@ pub struct ControllerSettings {
|
|||||||
pub jump_force: f32,
|
pub jump_force: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "client")]
|
||||||
/// Write inputs from combined keyboard/gamepad state into the networked input buffer
|
/// Write inputs from combined keyboard/gamepad state into the networked input buffer
|
||||||
/// for the local player.
|
/// for the local player.
|
||||||
fn buffer_inputs(
|
fn buffer_inputs(
|
||||||
|
|||||||
@@ -52,5 +52,6 @@ pub enum GameState {
|
|||||||
#[default]
|
#[default]
|
||||||
AssetLoading,
|
AssetLoading,
|
||||||
MapLoading,
|
MapLoading,
|
||||||
|
Connecting,
|
||||||
Playing,
|
Playing,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,17 @@ fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||||||
))
|
))
|
||||||
.observe(
|
.observe(
|
||||||
|_t: Trigger<SceneCollidersReady>,
|
|_t: Trigger<SceneCollidersReady>,
|
||||||
mut next_game_state: ResMut<NextState<GameState>>| {
|
#[cfg(any(feature = "client", feature = "server"))] mut next_game_state: ResMut<
|
||||||
|
NextState<GameState>,
|
||||||
|
>| {
|
||||||
info!("map loaded");
|
info!("map loaded");
|
||||||
|
|
||||||
|
assert!(cfg!(feature = "client") ^ cfg!(feature = "server"));
|
||||||
|
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
next_game_state.set(GameState::Connecting);
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
next_game_state.set(GameState::Playing);
|
next_game_state.set(GameState::Playing);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,13 +12,14 @@ use crate::{
|
|||||||
loading_assets::GameAssets,
|
loading_assets::GameAssets,
|
||||||
sounds::PlaySound,
|
sounds::PlaySound,
|
||||||
tb_entities::EnemySpawn,
|
tb_entities::EnemySpawn,
|
||||||
utils::{
|
utils::billboards::Billboard,
|
||||||
billboards::Billboard,
|
|
||||||
commands::{EntityCommandExt, IsServer},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use bevy::{pbr::NotShadowCaster, prelude::*};
|
use bevy::{pbr::NotShadowCaster, prelude::*};
|
||||||
use lightyear::prelude::{Client, Connected, Disconnected, NetworkTarget, Replicate};
|
use lightyear::prelude::Disconnected;
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
use lightyear::prelude::{Client, Connected};
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
use lightyear::prelude::{NetworkTarget, Replicate};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@@ -56,20 +57,26 @@ pub fn plugin(app: &mut App) {
|
|||||||
|
|
||||||
fn setup(
|
fn setup(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
is_server: Option<Res<IsServer>>,
|
#[cfg(feature = "client")] client: Query<
|
||||||
client: Query<(Option<&Connected>, Option<&Disconnected>), With<Client>>,
|
(Option<&Connected>, Option<&Disconnected>),
|
||||||
|
With<Client>,
|
||||||
|
>,
|
||||||
mut spawned: Local<bool>,
|
mut spawned: Local<bool>,
|
||||||
) {
|
) {
|
||||||
if *spawned {
|
if *spawned {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_server.is_some() {
|
#[cfg(feature = "server")]
|
||||||
|
{
|
||||||
commands.init_resource::<NpcSpawning>();
|
commands.init_resource::<NpcSpawning>();
|
||||||
commands.trigger(OnCheckSpawns { on_client: false });
|
commands.trigger(OnCheckSpawns { on_client: false });
|
||||||
|
|
||||||
*spawned = true;
|
*spawned = true;
|
||||||
} else if let Ok((connected, disconnected)) = client.single()
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
if let Ok((connected, disconnected)) = client.single()
|
||||||
&& (connected.is_some() || disconnected.is_some())
|
&& (connected.is_some() || disconnected.is_some())
|
||||||
{
|
{
|
||||||
commands.init_resource::<NpcSpawning>();
|
commands.init_resource::<NpcSpawning>();
|
||||||
@@ -87,9 +94,8 @@ fn on_spawn_check(
|
|||||||
query: Query<(Entity, &EnemySpawn, &Transform), Without<Npc>>,
|
query: Query<(Entity, &EnemySpawn, &Transform), Without<Npc>>,
|
||||||
heads_db: Res<HeadsDatabase>,
|
heads_db: Res<HeadsDatabase>,
|
||||||
spawning: Res<NpcSpawning>,
|
spawning: Res<NpcSpawning>,
|
||||||
is_server: Option<Res<IsServer>>,
|
|
||||||
) {
|
) {
|
||||||
if is_server.is_none() && !trigger.event().on_client {
|
if cfg!(not(feature = "server")) && !trigger.event().on_client {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,8 +113,8 @@ fn on_spawn_check(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let id = names[&spawn.head];
|
let id = names[&spawn.head];
|
||||||
commands
|
let mut ecommands = commands.entity(e);
|
||||||
.entity(e)
|
ecommands
|
||||||
.insert((
|
.insert((
|
||||||
Hitpoints::new(100),
|
Hitpoints::new(100),
|
||||||
Npc,
|
Npc,
|
||||||
@@ -122,9 +128,10 @@ fn on_spawn_check(
|
|||||||
]),
|
]),
|
||||||
))
|
))
|
||||||
.insert_if(Ai, || !spawn.disable_ai)
|
.insert_if(Ai, || !spawn.disable_ai)
|
||||||
.insert_server(Replicate::to_clients(NetworkTarget::All))
|
|
||||||
.with_child((Name::from("body-rig"), AnimatedCharacter::new(id)))
|
.with_child((Name::from("body-rig"), AnimatedCharacter::new(id)))
|
||||||
.observe(on_kill);
|
.observe(on_kill);
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
ecommands.insert(Replicate::to_clients(NetworkTarget::All));
|
||||||
|
|
||||||
commands.trigger(SpawnCharacter(transform.translation));
|
commands.trigger(SpawnCharacter(transform.translation));
|
||||||
commands.trigger(PlaySound::Beaming);
|
commands.trigger(PlaySound::Beaming);
|
||||||
@@ -133,7 +140,6 @@ fn on_spawn_check(
|
|||||||
|
|
||||||
fn on_kill(
|
fn on_kill(
|
||||||
trigger: Trigger<Kill>,
|
trigger: Trigger<Kill>,
|
||||||
is_server: Option<Res<IsServer>>,
|
|
||||||
disconnected: Option<Single<&Disconnected>>,
|
disconnected: Option<Single<&Disconnected>>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
query: Query<(&Transform, &EnemySpawn, &ActiveHead)>,
|
query: Query<(&Transform, &EnemySpawn, &ActiveHead)>,
|
||||||
@@ -150,7 +156,7 @@ fn on_kill(
|
|||||||
|
|
||||||
commands.trigger(HeadDrops::new(transform.translation, head.0));
|
commands.trigger(HeadDrops::new(transform.translation, head.0));
|
||||||
commands.trigger(OnCheckSpawns {
|
commands.trigger(OnCheckSpawns {
|
||||||
on_client: is_server.is_some() || disconnected.is_some(),
|
on_client: cfg!(feature = "server") || disconnected.is_some(),
|
||||||
});
|
});
|
||||||
|
|
||||||
commands.entity(trigger.target()).despawn();
|
commands.entity(trigger.target()).despawn();
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ use crate::{
|
|||||||
npc::SpawnCharacter,
|
npc::SpawnCharacter,
|
||||||
sounds::PlaySound,
|
sounds::PlaySound,
|
||||||
tb_entities::SpawnPoint,
|
tb_entities::SpawnPoint,
|
||||||
utils::commands::EntityCommandExt,
|
|
||||||
};
|
};
|
||||||
use avian3d::prelude::*;
|
use avian3d::prelude::*;
|
||||||
use bevy::{
|
use bevy::{
|
||||||
@@ -23,9 +22,9 @@ use bevy::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
window::{CursorGrabMode, PrimaryWindow},
|
window::{CursorGrabMode, PrimaryWindow},
|
||||||
};
|
};
|
||||||
use lightyear::prelude::{
|
use lightyear::prelude::input::native::ActionState;
|
||||||
ControlledBy, Lifetime, NetworkTarget, PredictionTarget, Replicate, input::native::ActionState,
|
#[cfg(feature = "server")]
|
||||||
};
|
use lightyear::prelude::{ControlledBy, Lifetime, NetworkTarget, PredictionTarget, Replicate};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Component, Default, Serialize, Deserialize, PartialEq)]
|
#[derive(Component, Default, Serialize, Deserialize, PartialEq)]
|
||||||
@@ -53,7 +52,7 @@ pub fn plugin(app: &mut App) {
|
|||||||
|
|
||||||
pub fn spawn(
|
pub fn spawn(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
owner: Entity,
|
#[cfg(feature = "server")] owner: Entity,
|
||||||
query: Query<&Transform, With<SpawnPoint>>,
|
query: Query<&Transform, With<SpawnPoint>>,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
heads_db: Res<HeadsDatabase>,
|
heads_db: Res<HeadsDatabase>,
|
||||||
@@ -64,17 +63,18 @@ pub fn spawn(
|
|||||||
|
|
||||||
let transform = Transform::from_translation(spawn.translation + Vec3::new(0., 3., 0.));
|
let transform = Transform::from_translation(spawn.translation + Vec3::new(0., 3., 0.));
|
||||||
|
|
||||||
commands
|
let mut player = commands.spawn(player_bundle(transform, &heads_db));
|
||||||
.spawn(player_bundle(transform, &heads_db))
|
player.observe(on_kill);
|
||||||
.insert_server((
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
player.insert((
|
||||||
Replicate::to_clients(NetworkTarget::All),
|
Replicate::to_clients(NetworkTarget::All),
|
||||||
PredictionTarget::to_clients(NetworkTarget::All),
|
PredictionTarget::to_clients(NetworkTarget::All),
|
||||||
ControlledBy {
|
ControlledBy {
|
||||||
owner,
|
owner,
|
||||||
lifetime: Lifetime::SessionBased,
|
lifetime: Lifetime::SessionBased,
|
||||||
},
|
},
|
||||||
))
|
));
|
||||||
.observe(on_kill);
|
|
||||||
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
AudioPlayer::new(asset_server.load("sfx/heads/angry demonstrator.ogg")),
|
AudioPlayer::new(asset_server.load("sfx/heads/angry demonstrator.ogg")),
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
use bevy::ecs::{
|
use bevy::ecs::{
|
||||||
bundle::Bundle,
|
|
||||||
event::Event,
|
event::Event,
|
||||||
resource::Resource,
|
|
||||||
system::{Commands, EntityCommands},
|
system::{Commands, EntityCommands},
|
||||||
world::{EntityWorldMut, World},
|
world::{EntityWorldMut, World},
|
||||||
};
|
};
|
||||||
use lightyear::prelude::Disconnected;
|
use lightyear::prelude::Disconnected;
|
||||||
|
|
||||||
#[derive(Default, Resource)]
|
|
||||||
pub struct IsServer;
|
|
||||||
|
|
||||||
pub trait CommandExt {
|
pub trait CommandExt {
|
||||||
fn trigger_server(&mut self, event: impl Event) -> &mut Self;
|
fn trigger_server(&mut self, event: impl Event) -> &mut Self;
|
||||||
}
|
}
|
||||||
@@ -18,7 +13,7 @@ impl<'w, 's> CommandExt for Commands<'w, 's> {
|
|||||||
fn trigger_server(&mut self, event: impl Event) -> &mut Self {
|
fn trigger_server(&mut self, event: impl Event) -> &mut Self {
|
||||||
self.queue(|world: &mut World| {
|
self.queue(|world: &mut World| {
|
||||||
let mut query_state = world.query::<&Disconnected>();
|
let mut query_state = world.query::<&Disconnected>();
|
||||||
if world.contains_resource::<IsServer>() || !query_state.query(world).is_empty() {
|
if cfg!(feature = "server") || !query_state.query(world).is_empty() {
|
||||||
world.trigger(event);
|
world.trigger(event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -27,23 +22,14 @@ impl<'w, 's> CommandExt for Commands<'w, 's> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait EntityCommandExt {
|
pub trait EntityCommandExt {
|
||||||
fn insert_server(&mut self, bundle: impl Bundle) -> &mut Self;
|
|
||||||
|
|
||||||
fn trigger_server(&mut self, event: impl Event) -> &mut Self;
|
fn trigger_server(&mut self, event: impl Event) -> &mut Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w> EntityCommandExt for EntityCommands<'w> {
|
impl<'w> EntityCommandExt for EntityCommands<'w> {
|
||||||
fn insert_server(&mut self, bundle: impl Bundle) -> &mut Self {
|
|
||||||
self.queue(|mut entity: EntityWorldMut| {
|
|
||||||
if entity.world().contains_resource::<IsServer>() {
|
|
||||||
entity.insert(bundle);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trigger_server(&mut self, event: impl Event) -> &mut Self {
|
fn trigger_server(&mut self, event: impl Event) -> &mut Self {
|
||||||
self.queue(|mut entity: EntityWorldMut| {
|
self.queue(|mut entity: EntityWorldMut| {
|
||||||
if entity.world().contains_resource::<IsServer>() {
|
let mut query_state = entity.world_scope(|world| world.query::<&Disconnected>());
|
||||||
|
if cfg!(feature = "server") || !query_state.query(entity.world()).is_empty() {
|
||||||
entity.trigger(event);
|
entity.trigger(event);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use crate::utils::commands::IsServer;
|
|
||||||
use bevy::{ecs::system::SystemParam, prelude::*};
|
use bevy::{ecs::system::SystemParam, prelude::*};
|
||||||
use lightyear::prelude::{AppTriggerExt, Channel, NetworkDirection, RemoteTrigger, TriggerSender};
|
use lightyear::prelude::{AppTriggerExt, Channel, NetworkDirection, RemoteTrigger, TriggerSender};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -6,12 +5,11 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[derive(SystemParam)]
|
#[derive(SystemParam)]
|
||||||
pub struct ServerMultiTriggerSender<'w, 's, M: Event + Clone> {
|
pub struct ServerMultiTriggerSender<'w, 's, M: Event + Clone> {
|
||||||
senders: Query<'w, 's, &'static mut TriggerSender<M>>,
|
senders: Query<'w, 's, &'static mut TriggerSender<M>>,
|
||||||
is_server: Option<Res<'w, IsServer>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, M: Event + Clone> ServerMultiTriggerSender<'w, 's, M> {
|
impl<'w, 's, M: Event + Clone> ServerMultiTriggerSender<'w, 's, M> {
|
||||||
pub fn server_trigger_targets<C: Channel>(&mut self, trigger: M, target: &[Entity]) {
|
pub fn server_trigger_targets<C: Channel>(&mut self, trigger: M, target: &[Entity]) {
|
||||||
if self.is_server.is_none() {
|
if cfg!(not(feature = "server")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
justfile
23
justfile
@@ -5,24 +5,31 @@ tb_setup_mac:
|
|||||||
ln -s $(pwd)/trenchbroom/hedz/hedz.fgd "$HOME/Library/Application Support/TrenchBroom/games/hedz/hedz.fgd" | true
|
ln -s $(pwd)/trenchbroom/hedz/hedz.fgd "$HOME/Library/Application Support/TrenchBroom/games/hedz/hedz.fgd" | true
|
||||||
ln -s $(pwd)/trenchbroom/hedz/GameConfig.cfg "$HOME/Library/Application Support/TrenchBroom/games/hedz/GameConfig.cfg" | true
|
ln -s $(pwd)/trenchbroom/hedz/GameConfig.cfg "$HOME/Library/Application Support/TrenchBroom/games/hedz/GameConfig.cfg" | true
|
||||||
|
|
||||||
|
client_args := "--bin hedz_reloaded --no-default-features --features shared/client"
|
||||||
|
server_args := "--bin server --no-default-features --features shared/server"
|
||||||
|
|
||||||
run *args:
|
run *args:
|
||||||
RUST_BACKTRACE=1 cargo r --bin hedz_reloaded -- {{args}}
|
cargo b {{server_args}}
|
||||||
|
RUST_BACKTRACE=1 cargo r {{client_args}} -- {{args}}
|
||||||
|
|
||||||
server:
|
server:
|
||||||
RUST_BACKTRACE=1 cargo r --bin server
|
RUST_BACKTRACE=1 cargo r {{server_args}}
|
||||||
|
|
||||||
dbg:
|
dbg:
|
||||||
RUST_BACKTRACE=1 cargo r --bin hedz_reloaded --features dbg
|
RUST_BACKTRACE=1 cargo r {{client_args}},dbg
|
||||||
|
|
||||||
dbg-server:
|
dbg-server:
|
||||||
RUST_BACKTRACE=1 cargo r --bin server --features dbg
|
RUST_BACKTRACE=1 cargo r {{server_args}},dbg
|
||||||
|
|
||||||
sort:
|
sort:
|
||||||
cargo sort --workspace
|
cargo sort --check --workspace
|
||||||
|
|
||||||
check:
|
check:
|
||||||
cargo sort --check --workspace
|
cargo sort --check --workspace
|
||||||
cargo fmt --check
|
cargo fmt --check
|
||||||
cargo b
|
cargo b {{client_args}}
|
||||||
cargo clippy
|
cargo b {{server_args}}
|
||||||
cargo test
|
cargo clippy {{client_args}}
|
||||||
|
cargo clippy {{server_args}}
|
||||||
|
cargo test {{client_args}}
|
||||||
|
cargo test {{server_args}}
|
||||||
|
|||||||
Reference in New Issue
Block a user