Crate unification (#88)
* move client/server/config into shared * move platforms into shared * move head drops into shared * move tb_entities to shared * reduce server to just a call into shared * get solo play working * fix server opening window * fix fmt * extracted a few more modules from client * near completely migrated client * fixed duplicate CharacterInputEnabled definition * simplify a few things related to builds * more simplifications * fix warnings/check * ci update * address comments * try fixing macos steam build * address comments * address comments * CI tweaks with default client feature --------- Co-authored-by: PROMETHIA-27 <electriccobras@gmail.com>
This commit is contained in:
7
.github/workflows/archive_steamos.yml
vendored
7
.github/workflows/archive_steamos.yml
vendored
@@ -23,13 +23,12 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
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 hedz_reloaded
|
||||||
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 target/x86_64-unknown-linux-gnu/release/server ./
|
cp target/x86_64-unknown-linux-gnu/release/hedz_reloaded ./
|
||||||
tar -czf steamos.tar.gz hedz_reloaded server
|
tar -czf steamos.tar.gz hedz_reloaded
|
||||||
|
|
||||||
- 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
@@ -27,14 +27,13 @@ jobs:
|
|||||||
|
|
||||||
- name: Build binaries (Windows)
|
- name: Build binaries (Windows)
|
||||||
run: |
|
run: |
|
||||||
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 hedz_reloaded
|
||||||
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 target/x86_64-pc-windows-msvc/release/server.exe ./
|
cp target/x86_64-pc-windows-msvc/release/hedz_reloaded.exe ./
|
||||||
tar -czf win.tar.gz hedz_reloaded.exe server.exe
|
tar -czf win.tar.gz hedz_reloaded.exe
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -38,12 +38,10 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cargo build --bin hedz_reloaded --no-default-features --features shared/client
|
cargo build --bin hedz_reloaded
|
||||||
cargo build --bin server --no-default-features --features shared/server
|
cargo build --bin hedz_reloaded_server --no-default-features
|
||||||
|
|
||||||
- name: Tests
|
- name: Tests
|
||||||
run: |
|
run: |
|
||||||
cargo test --lib shared --no-default-features --features client
|
cargo test --lib hedz_reloaded
|
||||||
cargo test --lib shared --no-default-features --features server
|
cargo test --lib hedz_reloaded --no-default-features
|
||||||
cargo test --bin hedz_reloaded --no-default-features --features shared/client
|
|
||||||
cargo test --bin server --no-default-features --features shared/server
|
|
||||||
|
|||||||
8
.github/workflows/ci_debug.yml
vendored
8
.github/workflows/ci_debug.yml
vendored
@@ -23,11 +23,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Build client
|
- name: Build client
|
||||||
run: |
|
run: |
|
||||||
cargo build --locked --target=x86_64-unknown-linux-gnu --bin hedz_reloaded --no-default-features --features shared/client
|
cargo build --locked --target=x86_64-unknown-linux-gnu --bin hedz_reloaded
|
||||||
|
|
||||||
- name: Build server
|
- name: Build server
|
||||||
run: |
|
run: |
|
||||||
cargo build --locked --target=x86_64-unknown-linux-gnu --bin server --no-default-features --features shared/server
|
cargo build --locked --target=x86_64-unknown-linux-gnu --bin hedz_reloaded_server --no-default-features
|
||||||
|
|
||||||
- name: Lints
|
- name: Lints
|
||||||
run: |
|
run: |
|
||||||
@@ -35,8 +35,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Archive
|
- name: Archive
|
||||||
run: |
|
run: |
|
||||||
cp target/x86_64-unknown-linux-gnu/debug/hedz_reloaded target/x86_64-unknown-linux-gnu/debug/server ./
|
cp target/x86_64-unknown-linux-gnu/debug/hedz_reloaded target/x86_64-unknown-linux-gnu/debug/hedz_reloaded_server ./
|
||||||
tar -czf steamos-debug.tar.gz hedz_reloaded server
|
tar -czf steamos-debug.tar.gz hedz_reloaded 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,17 +22,14 @@ jobs:
|
|||||||
|
|
||||||
- name: Build (lipo)
|
- name: Build (lipo)
|
||||||
run: |
|
run: |
|
||||||
cargo build --release --target=x86_64-apple-darwin --bin hedz_reloaded --no-default-features --features shared/client
|
cargo build --release --target=x86_64-apple-darwin --bin hedz_reloaded
|
||||||
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
|
||||||
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 target/release/server ./
|
cp target/release/hedz_reloaded ./
|
||||||
tar -czf hedz-macos.tar.gz hedz_reloaded server
|
tar -czf hedz-macos.tar.gz hedz_reloaded
|
||||||
ls -lisah hedz-macos.tar.gz
|
ls -lisah hedz-macos.tar.gz
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
@@ -63,7 +60,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 server $APP_ROOT/
|
cp hedz_reloaded $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
|
||||||
@@ -114,13 +111,12 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
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 hedz_reloaded
|
||||||
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 target/x86_64-unknown-linux-gnu/release/server ./
|
cp target/x86_64-unknown-linux-gnu/release/hedz_reloaded ./
|
||||||
tar -czf steamos.tar.gz hedz_reloaded server
|
tar -czf steamos.tar.gz hedz_reloaded
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
@@ -130,7 +126,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 target/x86_64-unknown-linux-gnu/release/server build/steamos/content/
|
cp target/x86_64-unknown-linux-gnu/release/hedz_reloaded build/steamos/content/
|
||||||
|
|
||||||
- name: Install SteamCMD
|
- name: Install SteamCMD
|
||||||
run: |
|
run: |
|
||||||
@@ -196,13 +192,12 @@ jobs:
|
|||||||
|
|
||||||
- name: Build binaries (Windows)
|
- name: Build binaries (Windows)
|
||||||
run: |
|
run: |
|
||||||
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 hedz_reloaded
|
||||||
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 target/x86_64-pc-windows-msvc/release/server.exe build/win/
|
cp target/x86_64-pc-windows-msvc/release/hedz_reloaded.exe build/win/
|
||||||
|
|
||||||
- uses: ./.github/actions/steamcmd
|
- uses: ./.github/actions/steamcmd
|
||||||
with:
|
with:
|
||||||
|
|||||||
438
Cargo.lock
generated
438
Cargo.lock
generated
@@ -102,7 +102,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom 0.3.4",
|
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"version_check",
|
"version_check",
|
||||||
"zerocopy",
|
"zerocopy",
|
||||||
@@ -268,7 +267,7 @@ dependencies = [
|
|||||||
"objc2-foundation 0.3.2",
|
"objc2-foundation 0.3.2",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.59.0",
|
||||||
"x11rb",
|
"x11rb",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -568,7 +567,7 @@ dependencies = [
|
|||||||
"bevy_utils",
|
"bevy_utils",
|
||||||
"blake3",
|
"blake3",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"downcast-rs 2.0.2",
|
"downcast-rs",
|
||||||
"either",
|
"either",
|
||||||
"petgraph",
|
"petgraph",
|
||||||
"ron 0.10.1",
|
"ron 0.10.1",
|
||||||
@@ -628,7 +627,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
"downcast-rs 2.0.2",
|
"downcast-rs",
|
||||||
"log",
|
"log",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
"variadics_please",
|
"variadics_please",
|
||||||
@@ -659,7 +658,7 @@ dependencies = [
|
|||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"disqualified",
|
"disqualified",
|
||||||
"downcast-rs 2.0.2",
|
"downcast-rs",
|
||||||
"either",
|
"either",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
@@ -731,7 +730,6 @@ dependencies = [
|
|||||||
"bevy_reflect",
|
"bevy_reflect",
|
||||||
"bevy_transform",
|
"bevy_transform",
|
||||||
"coreaudio-sys",
|
"coreaudio-sys",
|
||||||
"cpal",
|
|
||||||
"rodio",
|
"rodio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@@ -763,7 +761,7 @@ dependencies = [
|
|||||||
"bevy_utils",
|
"bevy_utils",
|
||||||
"bevy_window",
|
"bevy_window",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"downcast-rs 2.0.2",
|
"downcast-rs",
|
||||||
"serde",
|
"serde",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
@@ -1166,7 +1164,6 @@ dependencies = [
|
|||||||
"bevy_pbr",
|
"bevy_pbr",
|
||||||
"bevy_picking",
|
"bevy_picking",
|
||||||
"bevy_platform",
|
"bevy_platform",
|
||||||
"bevy_post_process",
|
|
||||||
"bevy_ptr",
|
"bevy_ptr",
|
||||||
"bevy_reflect",
|
"bevy_reflect",
|
||||||
"bevy_render",
|
"bevy_render",
|
||||||
@@ -1383,36 +1380,6 @@ dependencies = [
|
|||||||
"web-time",
|
"web-time",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bevy_post_process"
|
|
||||||
version = "0.17.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6b857972f5d56b43b0dce2c843b75b64d5fbbd0f6177f6ecccd75e7e41f72deb"
|
|
||||||
dependencies = [
|
|
||||||
"bevy_app",
|
|
||||||
"bevy_asset",
|
|
||||||
"bevy_camera",
|
|
||||||
"bevy_color",
|
|
||||||
"bevy_core_pipeline",
|
|
||||||
"bevy_derive",
|
|
||||||
"bevy_ecs",
|
|
||||||
"bevy_image",
|
|
||||||
"bevy_math",
|
|
||||||
"bevy_platform",
|
|
||||||
"bevy_reflect",
|
|
||||||
"bevy_render",
|
|
||||||
"bevy_shader",
|
|
||||||
"bevy_transform",
|
|
||||||
"bevy_utils",
|
|
||||||
"bevy_window",
|
|
||||||
"bitflags 2.10.0",
|
|
||||||
"nonmax",
|
|
||||||
"radsort",
|
|
||||||
"smallvec",
|
|
||||||
"thiserror 2.0.17",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_ptr"
|
name = "bevy_ptr"
|
||||||
version = "0.17.3"
|
version = "0.17.3"
|
||||||
@@ -1432,7 +1399,7 @@ dependencies = [
|
|||||||
"bevy_utils",
|
"bevy_utils",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"disqualified",
|
"disqualified",
|
||||||
"downcast-rs 2.0.2",
|
"downcast-rs",
|
||||||
"erased-serde",
|
"erased-serde",
|
||||||
"foldhash 0.2.0",
|
"foldhash 0.2.0",
|
||||||
"glam 0.30.9",
|
"glam 0.30.9",
|
||||||
@@ -1491,7 +1458,7 @@ dependencies = [
|
|||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"downcast-rs 2.0.2",
|
"downcast-rs",
|
||||||
"encase",
|
"encase",
|
||||||
"fixedbitset",
|
"fixedbitset",
|
||||||
"image",
|
"image",
|
||||||
@@ -2081,9 +2048,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.19.0"
|
version = "3.19.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
@@ -2140,18 +2107,6 @@ dependencies = [
|
|||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "calloop-wayland-source"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
|
|
||||||
dependencies = [
|
|
||||||
"calloop",
|
|
||||||
"rustix 0.38.44",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-client",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.49"
|
version = "1.2.49"
|
||||||
@@ -2864,12 +2819,6 @@ dependencies = [
|
|||||||
"litrs",
|
"litrs",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "downcast-rs"
|
|
||||||
version = "1.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "downcast-rs"
|
name = "downcast-rs"
|
||||||
version = "2.0.2"
|
version = "2.0.2"
|
||||||
@@ -3349,7 +3298,7 @@ dependencies = [
|
|||||||
"vec_map",
|
"vec_map",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"windows 0.62.2",
|
"windows 0.61.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3622,7 +3571,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "happy_feet"
|
name = "happy_feet"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/PROMETHIA-27/happy_feet.git?rev=48a96cc#48a96cc9aedd417448d0a0b82011a66827112740"
|
source = "git+https://github.com/PROMETHIA-27/happy_feet.git?rev=27609d89be74561a3971b1fc7d8c04cdd3e05731#27609d89be74561a3971b1fc7d8c04cdd3e05731"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"avian3d",
|
"avian3d",
|
||||||
"bevy",
|
"bevy",
|
||||||
@@ -3707,7 +3656,6 @@ dependencies = [
|
|||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"ron 0.8.1",
|
"ron 0.8.1",
|
||||||
"serde",
|
"serde",
|
||||||
"shared",
|
|
||||||
"steamworks",
|
"steamworks",
|
||||||
"vergen-gitcl",
|
"vergen-gitcl",
|
||||||
]
|
]
|
||||||
@@ -4074,13 +4022,13 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.10"
|
version = "0.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
|
checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.5.18",
|
"redox_syscall 0.6.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4217,9 +4165,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moxcms"
|
name = "moxcms"
|
||||||
version = "0.7.10"
|
version = "0.7.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "80986bbbcf925ebd3be54c26613d861255284584501595cf418320c078945608"
|
checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"pxfm",
|
"pxfm",
|
||||||
@@ -4996,7 +4944,7 @@ dependencies = [
|
|||||||
"approx",
|
"approx",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"downcast-rs 2.0.2",
|
"downcast-rs",
|
||||||
"either",
|
"either",
|
||||||
"ena",
|
"ena",
|
||||||
"foldhash 0.2.0",
|
"foldhash 0.2.0",
|
||||||
@@ -5027,7 +4975,7 @@ dependencies = [
|
|||||||
"approx",
|
"approx",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"downcast-rs 2.0.2",
|
"downcast-rs",
|
||||||
"either",
|
"either",
|
||||||
"ena",
|
"ena",
|
||||||
"foldhash 0.2.0",
|
"foldhash 0.2.0",
|
||||||
@@ -5313,15 +5261,6 @@ version = "2.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quick-xml"
|
|
||||||
version = "0.37.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.42"
|
version = "1.0.42"
|
||||||
@@ -5490,6 +5429,15 @@ dependencies = [
|
|||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.10.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.12.2"
|
version = "1.12.2"
|
||||||
@@ -5733,31 +5681,12 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scoped-tls"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sctk-adwaita"
|
|
||||||
version = "0.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec"
|
|
||||||
dependencies = [
|
|
||||||
"ab_glyph",
|
|
||||||
"log",
|
|
||||||
"memmap2",
|
|
||||||
"smithay-client-toolkit",
|
|
||||||
"tiny-skia",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "self_cell"
|
name = "self_cell"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@@ -5837,28 +5766,6 @@ dependencies = [
|
|||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "server"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"avian3d",
|
|
||||||
"bevy",
|
|
||||||
"bevy-steamworks",
|
|
||||||
"bevy_common_assets",
|
|
||||||
"bevy_replicon",
|
|
||||||
"bevy_replicon_renet",
|
|
||||||
"bevy_sprite3d",
|
|
||||||
"bevy_trenchbroom",
|
|
||||||
"bevy_trenchbroom_avian",
|
|
||||||
"clap",
|
|
||||||
"happy_feet",
|
|
||||||
"rand 0.8.5",
|
|
||||||
"ron 0.8.1",
|
|
||||||
"serde",
|
|
||||||
"shared",
|
|
||||||
"steamworks",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@@ -5868,29 +5775,6 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shared"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"avian3d",
|
|
||||||
"bevy",
|
|
||||||
"bevy-inspector-egui",
|
|
||||||
"bevy-steamworks",
|
|
||||||
"bevy_asset_loader",
|
|
||||||
"bevy_ballistic",
|
|
||||||
"bevy_common_assets",
|
|
||||||
"bevy_debug_log",
|
|
||||||
"bevy_replicon",
|
|
||||||
"bevy_sprite3d",
|
|
||||||
"bevy_trenchbroom",
|
|
||||||
"happy_feet",
|
|
||||||
"nil 0.14.0",
|
|
||||||
"rand 0.8.5",
|
|
||||||
"ron 0.8.1",
|
|
||||||
"serde",
|
|
||||||
"steamworks",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@@ -5967,31 +5851,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smithay-client-toolkit"
|
|
||||||
version = "0.19.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.10.0",
|
|
||||||
"calloop",
|
|
||||||
"calloop-wayland-source",
|
|
||||||
"cursor-icon",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"memmap2",
|
|
||||||
"rustix 0.38.44",
|
|
||||||
"thiserror 1.0.69",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-client",
|
|
||||||
"wayland-csd-frame",
|
|
||||||
"wayland-cursor",
|
|
||||||
"wayland-protocols",
|
|
||||||
"wayland-protocols-wlr",
|
|
||||||
"wayland-scanner",
|
|
||||||
"xkeysym",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smol_str"
|
name = "smol_str"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -6071,12 +5930,6 @@ version = "0.12.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42862065c9e685d08cc3d9f6c609d4b46bd9684ec7e9420688eb979213469582"
|
checksum = "42862065c9e685d08cc3d9f6c609d4b46bd9684ec7e9420688eb979213469582"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strict-num"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
@@ -6296,31 +6149,6 @@ dependencies = [
|
|||||||
"time-core",
|
"time-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tiny-skia"
|
|
||||||
version = "0.11.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
|
|
||||||
dependencies = [
|
|
||||||
"arrayref",
|
|
||||||
"arrayvec",
|
|
||||||
"bytemuck",
|
|
||||||
"cfg-if",
|
|
||||||
"log",
|
|
||||||
"tiny-skia-path",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tiny-skia-path"
|
|
||||||
version = "0.11.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93"
|
|
||||||
dependencies = [
|
|
||||||
"arrayref",
|
|
||||||
"bytemuck",
|
|
||||||
"strict-num",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@@ -6795,114 +6623,6 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-backend"
|
|
||||||
version = "0.3.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"downcast-rs 1.2.1",
|
|
||||||
"rustix 1.1.2",
|
|
||||||
"scoped-tls",
|
|
||||||
"smallvec",
|
|
||||||
"wayland-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-client"
|
|
||||||
version = "0.31.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.10.0",
|
|
||||||
"rustix 1.1.2",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-scanner",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-csd-frame"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.10.0",
|
|
||||||
"cursor-icon",
|
|
||||||
"wayland-backend",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-cursor"
|
|
||||||
version = "0.31.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "447ccc440a881271b19e9989f75726d60faa09b95b0200a9b7eb5cc47c3eeb29"
|
|
||||||
dependencies = [
|
|
||||||
"rustix 1.1.2",
|
|
||||||
"wayland-client",
|
|
||||||
"xcursor",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-protocols"
|
|
||||||
version = "0.32.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.10.0",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-client",
|
|
||||||
"wayland-scanner",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-protocols-plasma"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a07a14257c077ab3279987c4f8bb987851bf57081b93710381daea94f2c2c032"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.10.0",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-client",
|
|
||||||
"wayland-protocols",
|
|
||||||
"wayland-scanner",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-protocols-wlr"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.10.0",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-client",
|
|
||||||
"wayland-protocols",
|
|
||||||
"wayland-scanner",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-scanner"
|
|
||||||
version = "0.31.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quick-xml",
|
|
||||||
"quote",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-sys"
|
|
||||||
version = "0.31.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142"
|
|
||||||
dependencies = [
|
|
||||||
"dlib",
|
|
||||||
"log",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.83"
|
version = "0.3.83"
|
||||||
@@ -7160,23 +6880,11 @@ version = "0.61.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
|
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-collections 0.2.0",
|
"windows-collections",
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.61.2",
|
||||||
"windows-future 0.2.1",
|
"windows-future",
|
||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
"windows-numerics 0.2.0",
|
"windows-numerics",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows"
|
|
||||||
version = "0.62.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
|
|
||||||
dependencies = [
|
|
||||||
"windows-collections 0.3.2",
|
|
||||||
"windows-core 0.62.2",
|
|
||||||
"windows-future 0.3.2",
|
|
||||||
"windows-numerics 0.3.1",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7188,15 +6896,6 @@ dependencies = [
|
|||||||
"windows-core 0.61.2",
|
"windows-core 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-collections"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
|
|
||||||
dependencies = [
|
|
||||||
"windows-core 0.62.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.54.0"
|
version = "0.54.0"
|
||||||
@@ -7233,19 +6932,6 @@ dependencies = [
|
|||||||
"windows-strings 0.4.2",
|
"windows-strings 0.4.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-core"
|
|
||||||
version = "0.62.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
|
||||||
dependencies = [
|
|
||||||
"windows-implement 0.60.2",
|
|
||||||
"windows-interface 0.59.3",
|
|
||||||
"windows-link 0.2.1",
|
|
||||||
"windows-result 0.4.1",
|
|
||||||
"windows-strings 0.5.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-future"
|
name = "windows-future"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@@ -7254,18 +6940,7 @@ checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.61.2",
|
||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
"windows-threading 0.1.0",
|
"windows-threading",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-future"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
|
|
||||||
dependencies = [
|
|
||||||
"windows-core 0.62.2",
|
|
||||||
"windows-link 0.2.1",
|
|
||||||
"windows-threading 0.2.1",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7334,16 +7009,6 @@ dependencies = [
|
|||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-numerics"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
|
|
||||||
dependencies = [
|
|
||||||
"windows-core 0.62.2",
|
|
||||||
"windows-link 0.2.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-result"
|
name = "windows-result"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@@ -7371,15 +7036,6 @@ dependencies = [
|
|||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-result"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link 0.2.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-strings"
|
name = "windows-strings"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -7399,15 +7055,6 @@ dependencies = [
|
|||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-strings"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link 0.2.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.45.0"
|
version = "0.45.0"
|
||||||
@@ -7510,15 +7157,6 @@ dependencies = [
|
|||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-threading"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link 0.2.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -7663,7 +7301,6 @@ version = "0.30.12"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732"
|
checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
|
||||||
"android-activity",
|
"android-activity",
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
@@ -7678,7 +7315,6 @@ dependencies = [
|
|||||||
"dpi",
|
"dpi",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"memmap2",
|
|
||||||
"ndk 0.9.0",
|
"ndk 0.9.0",
|
||||||
"objc2 0.5.2",
|
"objc2 0.5.2",
|
||||||
"objc2-app-kit 0.2.2",
|
"objc2-app-kit 0.2.2",
|
||||||
@@ -7690,17 +7326,11 @@ dependencies = [
|
|||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"redox_syscall 0.4.1",
|
"redox_syscall 0.4.1",
|
||||||
"rustix 0.38.44",
|
"rustix 0.38.44",
|
||||||
"sctk-adwaita",
|
|
||||||
"smithay-client-toolkit",
|
|
||||||
"smol_str",
|
"smol_str",
|
||||||
"tracing",
|
"tracing",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"wayland-backend",
|
|
||||||
"wayland-client",
|
|
||||||
"wayland-protocols",
|
|
||||||
"wayland-protocols-plasma",
|
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"web-time",
|
"web-time",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
@@ -7771,12 +7401,6 @@ version = "0.13.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
|
checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xcursor"
|
|
||||||
version = "0.3.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xkbcommon-dl"
|
name = "xkbcommon-dl"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
|||||||
@@ -34,19 +34,20 @@ bevy = { version = "0.17.0", default-features = false, features = [
|
|||||||
"bevy_state",
|
"bevy_state",
|
||||||
"bevy_text",
|
"bevy_text",
|
||||||
"bevy_ui",
|
"bevy_ui",
|
||||||
|
"bevy_ui_render",
|
||||||
"bevy_ui_picking_backend",
|
"bevy_ui_picking_backend",
|
||||||
"custom_cursor",
|
|
||||||
"default_font",
|
"default_font",
|
||||||
"hdr",
|
"hdr",
|
||||||
"multi_threaded",
|
"multi_threaded",
|
||||||
"png",
|
"png",
|
||||||
|
"reflect_auto_register",
|
||||||
"smaa_luts",
|
"smaa_luts",
|
||||||
"std",
|
"std",
|
||||||
"sysinfo_plugin",
|
"sysinfo_plugin",
|
||||||
"tonemapping_luts",
|
"tonemapping_luts",
|
||||||
"vorbis",
|
"vorbis",
|
||||||
"webgl2",
|
"webgl2",
|
||||||
"x11",
|
"zstd_rust",
|
||||||
"track_location",
|
"track_location",
|
||||||
] }
|
] }
|
||||||
bevy-inspector-egui = "0.34"
|
bevy-inspector-egui = "0.34"
|
||||||
@@ -63,7 +64,7 @@ bevy_trenchbroom = { version = "0.10", default-features = false, features = [
|
|||||||
] }
|
] }
|
||||||
bevy_trenchbroom_avian = "0.10"
|
bevy_trenchbroom_avian = "0.10"
|
||||||
clap = { version = "=4.5.47", features = ["derive"] }
|
clap = { version = "=4.5.47", features = ["derive"] }
|
||||||
happy_feet = { git = "https://github.com/PROMETHIA-27/happy_feet.git", rev = "48a96cc", features = [
|
happy_feet = { git = "https://github.com/PROMETHIA-27/happy_feet.git", rev = "27609d89be74561a3971b1fc7d8c04cdd3e05731", features = [
|
||||||
"serde",
|
"serde",
|
||||||
] }
|
] }
|
||||||
nil = "0.14.0"
|
nil = "0.14.0"
|
||||||
|
|||||||
@@ -1,214 +0,0 @@
|
|||||||
mod backpack;
|
|
||||||
mod client;
|
|
||||||
mod config;
|
|
||||||
mod control;
|
|
||||||
mod debug;
|
|
||||||
mod enemy;
|
|
||||||
mod heal_effect;
|
|
||||||
mod player;
|
|
||||||
mod sounds;
|
|
||||||
mod steam;
|
|
||||||
mod ui;
|
|
||||||
|
|
||||||
use avian3d::prelude::*;
|
|
||||||
use bevy::{
|
|
||||||
audio::{PlaybackMode, Volume},
|
|
||||||
core_pipeline::tonemapping::Tonemapping,
|
|
||||||
prelude::*,
|
|
||||||
render::view::ColorGrading,
|
|
||||||
};
|
|
||||||
use bevy_common_assets::ron::RonAssetPlugin;
|
|
||||||
use bevy_sprite3d::Sprite3dPlugin;
|
|
||||||
use bevy_trenchbroom::prelude::*;
|
|
||||||
use bevy_trenchbroom_avian::AvianPhysicsBackend;
|
|
||||||
use camera::MainCamera;
|
|
||||||
use heads_database::HeadDatabaseAsset;
|
|
||||||
use loading_assets::AudioAssets;
|
|
||||||
use shared::*;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut app = App::new();
|
|
||||||
|
|
||||||
app.register_type::<DebugVisuals>()
|
|
||||||
.register_type::<TransformInterpolation>();
|
|
||||||
app.insert_resource(DebugVisuals {
|
|
||||||
unlit: false,
|
|
||||||
tonemapping: Tonemapping::None,
|
|
||||||
exposure: 1.,
|
|
||||||
shadows: true,
|
|
||||||
cam_follow: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
app.add_plugins(
|
|
||||||
DefaultPlugins
|
|
||||||
.set(WindowPlugin {
|
|
||||||
primary_window: Some(Window {
|
|
||||||
title: "HEDZ Reloaded".into(),
|
|
||||||
// resolution: (1024., 768.).into(),
|
|
||||||
..default()
|
|
||||||
}),
|
|
||||||
..default()
|
|
||||||
})
|
|
||||||
.set(bevy::log::LogPlugin {
|
|
||||||
filter: "info,lightyear_replication=off,bevy_ecs::hierarchy=off".into(),
|
|
||||||
level: bevy::log::Level::INFO,
|
|
||||||
// provide custom log layer to receive logging events
|
|
||||||
custom_layer: bevy_debug_log::log_capture_layer,
|
|
||||||
..default()
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
app.add_plugins(steam::plugin);
|
|
||||||
|
|
||||||
app.add_plugins(
|
|
||||||
bevy_debug_log::LogViewerPlugin::default()
|
|
||||||
.auto_open_threshold(bevy::log::tracing::level_filters::LevelFilter::OFF),
|
|
||||||
);
|
|
||||||
app.add_plugins(PhysicsPlugins::default());
|
|
||||||
app.add_plugins(Sprite3dPlugin);
|
|
||||||
app.add_plugins(TrenchBroomPlugins(
|
|
||||||
TrenchBroomConfig::new("hedz")
|
|
||||||
.icon(None)
|
|
||||||
.default_solid_spawn_hooks(|| SpawnHooks::new().convex_collider()),
|
|
||||||
));
|
|
||||||
app.add_plugins(TrenchBroomPhysicsPlugin::new(AvianPhysicsBackend));
|
|
||||||
app.add_plugins(RonAssetPlugin::<HeadDatabaseAsset>::new(&["headsdb.ron"]));
|
|
||||||
|
|
||||||
#[cfg(feature = "dbg")]
|
|
||||||
{
|
|
||||||
app.add_plugins(bevy_inspector_egui::bevy_egui::EguiPlugin::default());
|
|
||||||
app.add_plugins(bevy_inspector_egui::quick::WorldInspectorPlugin::new());
|
|
||||||
app.add_plugins(PhysicsDebugPlugin::default());
|
|
||||||
|
|
||||||
// app.add_plugins(bevy::pbr::wireframe::WireframePlugin)
|
|
||||||
// .insert_resource(bevy::pbr::wireframe::WireframeConfig {
|
|
||||||
// global: true,
|
|
||||||
// default_color: bevy::color::palettes::css::WHITE.into(),
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
app.add_plugins(shared::ai::plugin);
|
|
||||||
app.add_plugins(shared::animation::plugin);
|
|
||||||
app.add_plugins(shared::character::plugin);
|
|
||||||
app.add_plugins(shared::cash::plugin);
|
|
||||||
app.add_plugins(shared::player::plugin);
|
|
||||||
app.add_plugins(shared::gates::plugin);
|
|
||||||
app.add_plugins(shared::platforms::plugin);
|
|
||||||
app.add_plugins(shared::movables::plugin);
|
|
||||||
app.add_plugins(shared::utils::billboards::plugin);
|
|
||||||
app.add_plugins(shared::aim::plugin);
|
|
||||||
app.add_plugins(shared::npc::plugin);
|
|
||||||
app.add_plugins(shared::keys::plugin);
|
|
||||||
app.add_plugins(shared::utils::squish_animation::plugin);
|
|
||||||
app.add_plugins(shared::cutscene::plugin);
|
|
||||||
app.add_plugins(shared::control::plugin);
|
|
||||||
app.add_plugins(shared::camera::plugin);
|
|
||||||
app.add_plugins(shared::backpack::plugin);
|
|
||||||
app.add_plugins(shared::loading_assets::LoadingPlugin);
|
|
||||||
app.add_plugins(shared::loading_map::plugin);
|
|
||||||
app.add_plugins(shared::utils::sprite_3d_animation::plugin);
|
|
||||||
app.add_plugins(shared::abilities::plugin);
|
|
||||||
app.add_plugins(shared::heads::plugin);
|
|
||||||
app.add_plugins(shared::hitpoints::plugin);
|
|
||||||
app.add_plugins(shared::cash_heal::plugin);
|
|
||||||
app.add_plugins(shared::utils::plugin);
|
|
||||||
app.add_plugins(shared::water::plugin);
|
|
||||||
app.add_plugins(shared::head_drop::plugin);
|
|
||||||
app.add_plugins(shared::utils::trail::plugin);
|
|
||||||
app.add_plugins(shared::utils::auto_rotate::plugin);
|
|
||||||
app.add_plugins(shared::tb_entities::plugin);
|
|
||||||
app.add_plugins(shared::tick::plugin);
|
|
||||||
app.add_plugins(shared::utils::explosions::plugin);
|
|
||||||
|
|
||||||
// Networking
|
|
||||||
// The client/server plugin must go before the protocol, or else `ProtocolHasher` will not be available.
|
|
||||||
app.add_plugins(client::plugin);
|
|
||||||
app.add_plugins(shared::protocol::plugin);
|
|
||||||
|
|
||||||
app.add_plugins(backpack::plugin);
|
|
||||||
app.add_plugins(config::plugin);
|
|
||||||
app.add_plugins(control::plugin);
|
|
||||||
app.add_plugins(debug::plugin);
|
|
||||||
app.add_plugins(enemy::plugin);
|
|
||||||
app.add_plugins(heal_effect::plugin);
|
|
||||||
app.add_plugins(player::plugin);
|
|
||||||
app.add_plugins(sounds::plugin);
|
|
||||||
app.add_plugins(ui::plugin);
|
|
||||||
|
|
||||||
app.init_state::<GameState>();
|
|
||||||
|
|
||||||
app.insert_resource(AmbientLight {
|
|
||||||
color: Color::WHITE,
|
|
||||||
brightness: 400.,
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
app.insert_resource(ClearColor(Color::BLACK));
|
|
||||||
//TODO: let user control this
|
|
||||||
app.insert_resource(GlobalVolume::new(Volume::Linear(0.4)));
|
|
||||||
|
|
||||||
app.add_systems(Startup, write_trenchbroom_config);
|
|
||||||
app.add_systems(OnEnter(GameState::Playing), music);
|
|
||||||
app.add_systems(Update, (set_materials_unlit, set_tonemapping, set_shadows));
|
|
||||||
|
|
||||||
app.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn music(assets: Res<AudioAssets>, mut commands: Commands) {
|
|
||||||
commands.spawn((
|
|
||||||
Name::new("sfx-music"),
|
|
||||||
AudioPlayer::new(assets.music.clone()),
|
|
||||||
PlaybackSettings {
|
|
||||||
mode: PlaybackMode::Loop,
|
|
||||||
volume: Volume::Linear(0.6),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
));
|
|
||||||
|
|
||||||
commands.spawn((
|
|
||||||
Name::new("sfx-ambient"),
|
|
||||||
AudioPlayer::new(assets.ambient.clone()),
|
|
||||||
PlaybackSettings {
|
|
||||||
mode: PlaybackMode::Loop,
|
|
||||||
volume: Volume::Linear(0.8),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_trenchbroom_config(server: Res<TrenchBroomServer>, type_registry: Res<AppTypeRegistry>) {
|
|
||||||
if let Err(e) = server
|
|
||||||
.config
|
|
||||||
.write_game_config("trenchbroom/hedz", &type_registry.read())
|
|
||||||
{
|
|
||||||
warn!("Failed to write trenchbroom config: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_tonemapping(
|
|
||||||
mut cams: Query<(&mut Tonemapping, &mut ColorGrading), With<MainCamera>>,
|
|
||||||
visuals: Res<DebugVisuals>,
|
|
||||||
) {
|
|
||||||
for (mut tm, mut color) in cams.iter_mut() {
|
|
||||||
*tm = visuals.tonemapping;
|
|
||||||
color.global.exposure = visuals.exposure;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_materials_unlit(
|
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
||||||
visuals: Res<DebugVisuals>,
|
|
||||||
) {
|
|
||||||
if !materials.is_changed() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (_, material) in materials.iter_mut() {
|
|
||||||
material.unlit = visuals.unlit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_shadows(mut lights: Query<&mut DirectionalLight>, visuals: Res<DebugVisuals>) {
|
|
||||||
for mut l in lights.iter_mut() {
|
|
||||||
l.shadows_enabled = visuals.shadows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,27 +4,37 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "hedz_reloaded_server"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["shared/client"]
|
default = ["client"]
|
||||||
dbg = ["avian3d/debug-plugin", "dep:bevy-inspector-egui", "shared/dbg"]
|
client = [
|
||||||
|
"bevy/bevy_audio",
|
||||||
|
"bevy/bevy_window",
|
||||||
|
# depend on `winit`
|
||||||
|
"bevy/bevy_winit",
|
||||||
|
"bevy/x11",
|
||||||
|
"bevy/custom_cursor",
|
||||||
|
"bevy_replicon/client",
|
||||||
|
"bevy_replicon_renet/client",
|
||||||
|
"bevy_trenchbroom/client",
|
||||||
|
]
|
||||||
|
dbg = ["avian3d/debug-plugin", "dep:bevy-inspector-egui"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
avian3d = { workspace = true }
|
avian3d = { workspace = true }
|
||||||
bevy = { workspace = true, default-features = false, features = [
|
bevy = { workspace = true }
|
||||||
"bevy_audio",
|
|
||||||
"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_asset_loader = { workspace = true }
|
bevy_asset_loader = { workspace = true }
|
||||||
bevy_ballistic = { workspace = true }
|
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_replicon = { workspace = true, features = ["client"] }
|
bevy_replicon = { workspace = true }
|
||||||
bevy_replicon_renet = { workspace = true, features = ["client"] }
|
bevy_replicon_renet = { workspace = true }
|
||||||
bevy_sprite3d = { workspace = true }
|
bevy_sprite3d = { workspace = true }
|
||||||
bevy_trenchbroom = { workspace = true, features = ["client"] }
|
bevy_trenchbroom = { workspace = true }
|
||||||
bevy_trenchbroom_avian = { workspace = true }
|
bevy_trenchbroom_avian = { workspace = true }
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
happy_feet = { workspace = true }
|
happy_feet = { workspace = true }
|
||||||
@@ -32,8 +42,11 @@ nil = { workspace = true }
|
|||||||
rand = { workspace = true }
|
rand = { workspace = true }
|
||||||
ron = { workspace = true }
|
ron = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
shared = { workspace = true }
|
|
||||||
steamworks = { workspace = true }
|
steamworks = { workspace = true }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
vergen-gitcl = "1.0"
|
vergen-gitcl = "1.0"
|
||||||
|
|
||||||
|
[lints.clippy]
|
||||||
|
too_many_arguments = "allow"
|
||||||
|
type_complexity = "allow"
|
||||||
@@ -6,17 +6,19 @@ pub mod missile;
|
|||||||
pub mod thrown;
|
pub mod thrown;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
GameState, global_observer,
|
GameState,
|
||||||
|
aim::AimTarget,
|
||||||
|
character::CharacterHierarchy,
|
||||||
|
control::Inputs,
|
||||||
|
global_observer,
|
||||||
|
heads::ActiveHeads,
|
||||||
|
heads_database::HeadsDatabase,
|
||||||
loading_assets::GameAssets,
|
loading_assets::GameAssets,
|
||||||
physics_layers::GameLayer,
|
physics_layers::GameLayer,
|
||||||
player::Player,
|
player::Player,
|
||||||
protocol::PlaySound,
|
protocol::PlaySound,
|
||||||
utils::{billboards::Billboard, explosions::Explosion, sprite_3d_animation::AnimationTimer},
|
utils::{billboards::Billboard, explosions::Explosion, sprite_3d_animation::AnimationTimer},
|
||||||
};
|
};
|
||||||
use crate::{
|
|
||||||
aim::AimTarget, character::CharacterHierarchy, control::Inputs, heads::ActiveHeads,
|
|
||||||
heads_database::HeadsDatabase,
|
|
||||||
};
|
|
||||||
use bevy::{light::NotShadowCaster, prelude::*};
|
use bevy::{light::NotShadowCaster, prelude::*};
|
||||||
use bevy_replicon::prelude::{SendMode, ServerTriggerExt, Signature, ToClients};
|
use bevy_replicon::prelude::{SendMode, ServerTriggerExt, Signature, ToClients};
|
||||||
use bevy_sprite3d::Sprite3d;
|
use bevy_sprite3d::Sprite3d;
|
||||||
3
crates/hedz_reloaded/src/bin/hedz_reloaded_server.rs
Normal file
3
crates/hedz_reloaded/src/bin/hedz_reloaded_server.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub fn main() {
|
||||||
|
hedz_reloaded::launch();
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::{GameState, HEDZ_GREEN, loading_assets::UIAssets};
|
use crate::{
|
||||||
#[cfg(feature = "server")]
|
GameState, HEDZ_GREEN, global_observer, loading_assets::UIAssets, protocol::PlaySound,
|
||||||
use crate::{global_observer, protocol::PlaySound};
|
server_observer,
|
||||||
|
};
|
||||||
use avian3d::prelude::Rotation;
|
use avian3d::prelude::Rotation;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -29,11 +30,9 @@ pub fn plugin(app: &mut App) {
|
|||||||
(rotate, update_ui).run_if(in_state(GameState::Playing)),
|
(rotate, update_ui).run_if(in_state(GameState::Playing)),
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
server_observer!(app, on_cash_collect);
|
||||||
global_observer!(app, on_cash_collect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
fn on_cash_collect(
|
fn on_cash_collect(
|
||||||
_trigger: On<CashCollectEvent>,
|
_trigger: On<CashCollectEvent>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
@@ -1,55 +1,60 @@
|
|||||||
use crate::config::ClientConfig;
|
use crate::{
|
||||||
use avian3d::prelude::{
|
GameState,
|
||||||
Collider, ColliderAabb, ColliderDensity, ColliderMarker, ColliderOf, ColliderTransform,
|
config::NetworkingConfig,
|
||||||
CollisionEventsEnabled, CollisionLayers, Sensor,
|
|
||||||
};
|
|
||||||
use bevy::{
|
|
||||||
ecs::bundle::BundleFromComponents, platform::cell::SyncCell, prelude::*, scene::SceneInstance,
|
|
||||||
};
|
|
||||||
use bevy_replicon::{
|
|
||||||
RepliconPlugins,
|
|
||||||
client::{ClientSystems, confirm_history::ConfirmHistory},
|
|
||||||
prelude::{ClientState, ClientTriggerExt, RepliconChannels},
|
|
||||||
};
|
|
||||||
use bevy_replicon_renet::{
|
|
||||||
RenetChannelsExt, RepliconRenetPlugins,
|
|
||||||
netcode::{ClientAuthentication, NetcodeClientTransport, NetcodeError},
|
|
||||||
renet::{ConnectionConfig, RenetClient},
|
|
||||||
};
|
|
||||||
use bevy_trenchbroom::geometry::Brushes;
|
|
||||||
use nil::prelude::Mutex;
|
|
||||||
use shared::{
|
|
||||||
GameState, global_observer,
|
|
||||||
protocol::{
|
protocol::{
|
||||||
ClientEnteredPlaying, TbMapEntityId, TbMapEntityMapping, messages::DespawnTbMapEntity,
|
ClientEnteredPlaying, TbMapEntityId, TbMapEntityMapping, messages::DespawnTbMapEntity,
|
||||||
},
|
},
|
||||||
tb_entities::{Movable, Platform, PlatformTarget},
|
tb_entities::{Movable, Platform, PlatformTarget},
|
||||||
};
|
};
|
||||||
|
use avian3d::prelude::{
|
||||||
|
Collider, ColliderAabb, ColliderDensity, ColliderMarker, ColliderOf, ColliderTransform,
|
||||||
|
CollisionEventsEnabled, CollisionLayers, Sensor,
|
||||||
|
};
|
||||||
|
use bevy::{ecs::bundle::BundleFromComponents, prelude::*, scene::SceneInstance};
|
||||||
|
use bevy_replicon::{
|
||||||
|
client::{ClientSystems, confirm_history::ConfirmHistory},
|
||||||
|
prelude::{ClientState, ClientTriggerExt, RepliconChannels},
|
||||||
|
};
|
||||||
|
use bevy_replicon_renet::{
|
||||||
|
RenetChannelsExt,
|
||||||
|
netcode::{ClientAuthentication, NetcodeClientTransport, NetcodeError},
|
||||||
|
renet::{ConnectionConfig, RenetClient},
|
||||||
|
};
|
||||||
|
use bevy_trenchbroom::geometry::Brushes;
|
||||||
use std::{
|
use std::{
|
||||||
env::current_exe,
|
|
||||||
fs::File,
|
|
||||||
io::{BufRead, BufReader},
|
|
||||||
net::{Ipv4Addr, UdpSocket},
|
net::{Ipv4Addr, UdpSocket},
|
||||||
process::Stdio,
|
|
||||||
sync::{LazyLock, mpsc},
|
|
||||||
time::SystemTime,
|
time::SystemTime,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Cache of server processes to be cleared at process exit
|
pub mod backpack;
|
||||||
static SERVER_PROCESSES: LazyLock<Mutex<Vec<std::process::Child>>> = LazyLock::new(Mutex::default);
|
pub mod control;
|
||||||
|
pub mod debug;
|
||||||
|
pub mod enemy;
|
||||||
|
pub mod heal_effect;
|
||||||
|
pub mod player;
|
||||||
|
pub mod setup;
|
||||||
|
pub mod sounds;
|
||||||
|
pub mod steam;
|
||||||
|
pub mod ui;
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.add_plugins((RepliconPlugins, RepliconRenetPlugins));
|
app.add_plugins((
|
||||||
|
backpack::plugin,
|
||||||
|
control::plugin,
|
||||||
|
debug::plugin,
|
||||||
|
enemy::plugin,
|
||||||
|
heal_effect::plugin,
|
||||||
|
player::plugin,
|
||||||
|
setup::plugin,
|
||||||
|
sounds::plugin,
|
||||||
|
steam::plugin,
|
||||||
|
ui::plugin,
|
||||||
|
));
|
||||||
|
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
OnEnter(GameState::Connecting),
|
OnEnter(GameState::Connecting),
|
||||||
connect_to_server.run_if(|config: Res<ClientConfig>| config.server.is_some()),
|
connect_to_server.run_if(|config: Res<NetworkingConfig>| config.server.is_some()),
|
||||||
);
|
);
|
||||||
app.add_systems(
|
|
||||||
Update,
|
|
||||||
parse_local_server_stdout.run_if(resource_exists::<LocalServerStdout>),
|
|
||||||
);
|
|
||||||
app.add_systems(Last, close_server_processes);
|
|
||||||
app.add_systems(Update, despawn_absent_map_entities);
|
app.add_systems(Update, despawn_absent_map_entities);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
PreUpdate,
|
PreUpdate,
|
||||||
@@ -58,15 +63,8 @@ pub fn plugin(app: &mut App) {
|
|||||||
.after(ClientSystems::Receive),
|
.after(ClientSystems::Receive),
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: migrate this to connect_on_local_server_started
|
|
||||||
app.add_systems(OnEnter(ClientState::Connected), on_connected_state);
|
app.add_systems(OnEnter(ClientState::Connected), on_connected_state);
|
||||||
app.add_systems(OnExit(ClientState::Connected), on_disconnect);
|
app.add_systems(OnExit(ClientState::Connected), on_disconnect);
|
||||||
app.add_systems(
|
|
||||||
OnEnter(GameState::Connecting),
|
|
||||||
host_local_server.run_if(|config: Res<ClientConfig>| config.server.is_none()),
|
|
||||||
);
|
|
||||||
|
|
||||||
global_observer!(app, connect_on_local_server_started);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -74,6 +72,7 @@ pub fn plugin(app: &mut App) {
|
|||||||
//
|
//
|
||||||
|
|
||||||
fn on_connected_state(mut commands: Commands, mut game_state: ResMut<NextState<GameState>>) {
|
fn on_connected_state(mut commands: Commands, mut game_state: ResMut<NextState<GameState>>) {
|
||||||
|
info!("sent entered playing signal");
|
||||||
commands.client_trigger(ClientEnteredPlaying);
|
commands.client_trigger(ClientEnteredPlaying);
|
||||||
game_state.set(GameState::Playing);
|
game_state.set(GameState::Playing);
|
||||||
}
|
}
|
||||||
@@ -82,24 +81,13 @@ fn on_disconnect() {
|
|||||||
info!("disconnected from the server");
|
info!("disconnected from the server");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_server_processes(mut app_exit: MessageReader<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}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Renet
|
// Renet
|
||||||
//
|
//
|
||||||
|
|
||||||
fn connect_to_server(
|
fn connect_to_server(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
config: Res<ClientConfig>,
|
config: Res<NetworkingConfig>,
|
||||||
channels: Res<RepliconChannels>,
|
channels: Res<RepliconChannels>,
|
||||||
) -> Result {
|
) -> Result {
|
||||||
let server_channels_config = channels.server_configs();
|
let server_channels_config = channels.server_configs();
|
||||||
@@ -117,12 +105,12 @@ fn connect_to_server(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn client_transport(config: &ClientConfig) -> Result<NetcodeClientTransport, NetcodeError> {
|
fn client_transport(config: &NetworkingConfig) -> Result<NetcodeClientTransport, NetcodeError> {
|
||||||
let current_time = SystemTime::now()
|
let current_time = SystemTime::now()
|
||||||
.duration_since(SystemTime::UNIX_EPOCH)
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let client_id = current_time.as_millis() as u64;
|
let client_id = current_time.as_millis() as u64;
|
||||||
let socket = UdpSocket::bind((Ipv4Addr::UNSPECIFIED, config.port))?;
|
let socket = UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0))?;
|
||||||
let server_addr = config
|
let server_addr = config
|
||||||
.server
|
.server
|
||||||
.flatten()
|
.flatten()
|
||||||
@@ -138,76 +126,6 @@ fn client_transport(config: &ClientConfig) -> Result<NetcodeClientTransport, Net
|
|||||||
NetcodeClientTransport::new(current_time, authentication, socket)
|
NetcodeClientTransport::new(current_time, authentication, socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource)]
|
|
||||||
struct LocalServerStdout(SyncCell<mpsc::Receiver<String>>);
|
|
||||||
|
|
||||||
fn host_local_server(mut commands: Commands) -> Result {
|
|
||||||
// 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 server_log_file = File::create("server.log")?;
|
|
||||||
let mut server_process = std::process::Command::new(exe_path)
|
|
||||||
.args(["--timeout", "60", "--close-on-client-disconnect"])
|
|
||||||
.env("NO_COLOR", "1")
|
|
||||||
.stdin(Stdio::null())
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.stderr(server_log_file)
|
|
||||||
.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)));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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);
|
|
||||||
} else {
|
|
||||||
info!("SERVER: {line}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn connect_on_local_server_started(
|
|
||||||
_: On<LocalServerStarted>,
|
|
||||||
commands: Commands,
|
|
||||||
state: Res<State<GameState>>,
|
|
||||||
channels: Res<RepliconChannels>,
|
|
||||||
config: Res<ClientConfig>,
|
|
||||||
) -> Result<()> {
|
|
||||||
if *state == GameState::Connecting {
|
|
||||||
connect_to_server(commands, config, channels)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn migrate_remote_entities(
|
fn migrate_remote_entities(
|
||||||
query: Query<(Entity, &TbMapEntityId), (Added<TbMapEntityId>, With<ConfirmHistory>)>,
|
query: Query<(Entity, &TbMapEntityId), (Added<TbMapEntityId>, With<ConfirmHistory>)>,
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
use crate::{GameState, HEDZ_GREEN, heads::HeadsImages, loading_assets::UIAssets};
|
use crate::{
|
||||||
use bevy::{ecs::spawn::SpawnIter, prelude::*};
|
GameState, HEDZ_GREEN,
|
||||||
use shared::backpack::backpack_ui::{
|
backpack::backpack_ui::{
|
||||||
BACKPACK_HEAD_SLOTS, BackpackCountText, BackpackMarker, BackpackUiState, HeadDamage, HeadImage,
|
BACKPACK_HEAD_SLOTS, BackpackCountText, BackpackMarker, BackpackUiState, HeadDamage,
|
||||||
HeadSelector,
|
HeadImage, HeadSelector,
|
||||||
|
},
|
||||||
|
heads::HeadsImages,
|
||||||
|
loading_assets::UIAssets,
|
||||||
};
|
};
|
||||||
|
use bevy::{ecs::spawn::SpawnIter, prelude::*};
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.add_systems(OnEnter(GameState::Playing), setup);
|
app.add_systems(OnEnter(GameState::Playing), setup);
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
use bevy::prelude::*;
|
use crate::{
|
||||||
use shared::{
|
|
||||||
GameState,
|
GameState,
|
||||||
control::{ControllerSet, Inputs, LookDirMovement},
|
control::{ControllerSet, Inputs, LookDirMovement},
|
||||||
player::{LocalPlayer, PlayerBodyMesh},
|
player::{LocalPlayer, PlayerBodyMesh},
|
||||||
};
|
};
|
||||||
|
use bevy::prelude::*;
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
FixedUpdate,
|
FixedUpdate,
|
||||||
rotate_rig
|
rotate_rig
|
||||||
.before(shared::control::controller_flying::apply_controls)
|
.before(crate::control::controller_flying::apply_controls)
|
||||||
.in_set(ControllerSet::ApplyControlsFly)
|
.in_set(ControllerSet::ApplyControlsFly)
|
||||||
.run_if(in_state(GameState::Playing)),
|
.run_if(in_state(GameState::Playing)),
|
||||||
);
|
);
|
||||||
@@ -1,4 +1,12 @@
|
|||||||
use crate::{GameState, control::CharacterInputEnabled};
|
use crate::{
|
||||||
|
GameState,
|
||||||
|
client::control::CharacterInputEnabled,
|
||||||
|
control::{
|
||||||
|
BackpackButtonPress, CashHealPressed, ClientInputs, ControllerSet, Inputs, LocalInputs,
|
||||||
|
LookDirMovement, SelectLeftPressed, SelectRightPressed,
|
||||||
|
},
|
||||||
|
player::{LocalPlayer, PlayerBodyMesh},
|
||||||
|
};
|
||||||
use bevy::{
|
use bevy::{
|
||||||
input::{
|
input::{
|
||||||
gamepad::{GamepadConnection, GamepadEvent},
|
gamepad::{GamepadConnection, GamepadEvent},
|
||||||
@@ -7,13 +15,6 @@ use bevy::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use bevy_replicon::client::ClientSystems;
|
use bevy_replicon::client::ClientSystems;
|
||||||
use shared::{
|
|
||||||
control::{
|
|
||||||
BackpackButtonPress, CashHealPressed, ClientInputs, ControllerSet, Inputs, LocalInputs,
|
|
||||||
LookDirMovement, SelectLeftPressed, SelectRightPressed,
|
|
||||||
},
|
|
||||||
player::{LocalPlayer, PlayerBodyMesh},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::GameState;
|
use crate::{GameState, control::ControllerSet};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_replicon::client::ClientSystems;
|
use bevy_replicon::client::ClientSystems;
|
||||||
use shared::control::ControllerSet;
|
|
||||||
|
|
||||||
mod controller_flying;
|
mod controller_flying;
|
||||||
pub mod controls;
|
pub mod controls;
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_debug_log::LogViewerVisibility;
|
use bevy_debug_log::LogViewerVisibility;
|
||||||
|
|
||||||
|
// Is supplied by a build script via vergen_gitcl
|
||||||
pub const GIT_HASH: &str = env!("VERGEN_GIT_SHA");
|
pub const GIT_HASH: &str = env!("VERGEN_GIT_SHA");
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
|
use crate::{GameState, tb_entities::EnemySpawn};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use shared::{GameState, tb_entities::EnemySpawn};
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.add_systems(OnExit(GameState::MapLoading), despawn_enemy_spawns);
|
app.add_systems(OnEnter(GameState::Connecting), despawn_enemy_spawns);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Despawn enemy spawners because only the server will ever spawn enemies with them, and they have a
|
/// Despawn enemy spawners because only the server will ever spawn enemies with them, and they have a
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState, abilities::Healing, loading_assets::GameAssets, utils::billboards::Billboard,
|
GameState,
|
||||||
|
abilities::Healing,
|
||||||
|
loading_assets::{AudioAssets, GameAssets},
|
||||||
|
utils::{billboards::Billboard, observers::global_observer},
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use rand::{Rng, thread_rng};
|
use rand::{Rng, thread_rng};
|
||||||
use shared::{loading_assets::AudioAssets, utils::observers::global_observer};
|
|
||||||
|
|
||||||
// Should not be a relationship because lightyear will silently track state for all relationships
|
// Should not be a relationship because lightyear will silently track state for all relationships
|
||||||
// and break if one end of the relationship isn't replicated and is despawned
|
// and break if one end of the relationship isn't replicated and is despawned
|
||||||
@@ -2,12 +2,10 @@ use crate::{
|
|||||||
global_observer,
|
global_observer,
|
||||||
heads_database::{HeadControls, HeadsDatabase},
|
heads_database::{HeadControls, HeadsDatabase},
|
||||||
loading_assets::AudioAssets,
|
loading_assets::AudioAssets,
|
||||||
|
player::{LocalPlayer, PlayerBodyMesh},
|
||||||
|
protocol::{ClientHeadChanged, PlaySound, PlayerId, messages::AssignClientPlayer},
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use shared::{
|
|
||||||
player::{LocalPlayer, PlayerBodyMesh},
|
|
||||||
protocol::{PlaySound, PlayerId, events::ClientHeadChanged, messages::AssignClientPlayer},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.init_state::<PlayerAssignmentState>();
|
app.init_state::<PlayerAssignmentState>();
|
||||||
@@ -17,10 +15,10 @@ pub fn plugin(app: &mut App) {
|
|||||||
receive_player_id.run_if(not(in_state(PlayerAssignmentState::Confirmed))),
|
receive_player_id.run_if(not(in_state(PlayerAssignmentState::Confirmed))),
|
||||||
);
|
);
|
||||||
|
|
||||||
global_observer!(app, on_update_head_mesh);
|
global_observer!(app, on_client_update_head_mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_player_id(
|
pub fn receive_player_id(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut client_assignments: MessageReader<AssignClientPlayer>,
|
mut client_assignments: MessageReader<AssignClientPlayer>,
|
||||||
mut next: ResMut<NextState<PlayerAssignmentState>>,
|
mut next: ResMut<NextState<PlayerAssignmentState>>,
|
||||||
@@ -61,7 +59,7 @@ pub enum PlayerAssignmentState {
|
|||||||
Confirmed,
|
Confirmed,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_update_head_mesh(
|
fn on_client_update_head_mesh(
|
||||||
trigger: On<ClientHeadChanged>,
|
trigger: On<ClientHeadChanged>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
body_mesh: Single<(Entity, &Children), With<PlayerBodyMesh>>,
|
body_mesh: Single<(Entity, &Children), With<PlayerBodyMesh>>,
|
||||||
90
crates/hedz_reloaded/src/client/setup.rs
Normal file
90
crates/hedz_reloaded/src/client/setup.rs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
use crate::{DebugVisuals, GameState, camera::MainCamera, loading_assets::AudioAssets};
|
||||||
|
use bevy::{
|
||||||
|
audio::{PlaybackMode, Volume},
|
||||||
|
core_pipeline::tonemapping::Tonemapping,
|
||||||
|
prelude::*,
|
||||||
|
render::view::ColorGrading,
|
||||||
|
};
|
||||||
|
use bevy_trenchbroom::TrenchBroomServer;
|
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) {
|
||||||
|
#[cfg(feature = "dbg")]
|
||||||
|
{
|
||||||
|
app.add_plugins(bevy_inspector_egui::bevy_egui::EguiPlugin::default());
|
||||||
|
app.add_plugins(bevy_inspector_egui::quick::WorldInspectorPlugin::new());
|
||||||
|
app.add_plugins(avian3d::prelude::PhysicsDebugPlugin::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
app.insert_resource(AmbientLight {
|
||||||
|
color: Color::WHITE,
|
||||||
|
brightness: 400.,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
app.insert_resource(ClearColor(Color::BLACK));
|
||||||
|
//TODO: let user control this
|
||||||
|
app.insert_resource(GlobalVolume::new(Volume::Linear(0.4)));
|
||||||
|
|
||||||
|
app.add_systems(Startup, write_trenchbroom_config);
|
||||||
|
app.add_systems(OnEnter(GameState::Playing), music);
|
||||||
|
app.add_systems(Update, (set_materials_unlit, set_tonemapping, set_shadows));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn music(assets: Res<AudioAssets>, mut commands: Commands) {
|
||||||
|
commands.spawn((
|
||||||
|
Name::new("sfx-music"),
|
||||||
|
AudioPlayer::new(assets.music.clone()),
|
||||||
|
PlaybackSettings {
|
||||||
|
mode: PlaybackMode::Loop,
|
||||||
|
volume: Volume::Linear(0.6),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
Name::new("sfx-ambient"),
|
||||||
|
AudioPlayer::new(assets.ambient.clone()),
|
||||||
|
PlaybackSettings {
|
||||||
|
mode: PlaybackMode::Loop,
|
||||||
|
volume: Volume::Linear(0.8),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_trenchbroom_config(server: Res<TrenchBroomServer>, type_registry: Res<AppTypeRegistry>) {
|
||||||
|
if let Err(e) = server
|
||||||
|
.config
|
||||||
|
.write_game_config("trenchbroom/hedz", &type_registry.read())
|
||||||
|
{
|
||||||
|
warn!("Failed to write trenchbroom config: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_tonemapping(
|
||||||
|
mut cams: Query<(&mut Tonemapping, &mut ColorGrading), With<MainCamera>>,
|
||||||
|
visuals: Res<DebugVisuals>,
|
||||||
|
) {
|
||||||
|
for (mut tm, mut color) in cams.iter_mut() {
|
||||||
|
*tm = visuals.tonemapping;
|
||||||
|
color.global.exposure = visuals.exposure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_materials_unlit(
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
visuals: Res<DebugVisuals>,
|
||||||
|
) {
|
||||||
|
if !materials.is_changed() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (_, material) in materials.iter_mut() {
|
||||||
|
material.unlit = visuals.unlit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_shadows(mut lights: Query<&mut DirectionalLight>, visuals: Res<DebugVisuals>) {
|
||||||
|
for mut l in lights.iter_mut() {
|
||||||
|
l.shadows_enabled = visuals.shadows;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::{global_observer, loading_assets::AudioAssets};
|
use crate::{global_observer, loading_assets::AudioAssets, protocol::PlaySound};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use shared::protocol::PlaySound;
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
global_observer!(app, on_spawn_sounds);
|
global_observer!(app, on_spawn_sounds);
|
||||||
@@ -1,9 +1,28 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_steamworks::{Client, FriendFlags, SteamworksEvent};
|
use bevy_steamworks::{Client, FriendFlags, SteamworksEvent, SteamworksPlugin};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.add_plugins(shared::steam::plugin);
|
let app_id = 1603000;
|
||||||
|
|
||||||
|
// should only be done in production builds
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
if steamworks::restart_app_if_necessary(app_id.into()) {
|
||||||
|
info!("Restarting app via steam");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("steam app init: {app_id}");
|
||||||
|
|
||||||
|
match SteamworksPlugin::init_app(app_id) {
|
||||||
|
Ok(plugin) => {
|
||||||
|
info!("steam app init done");
|
||||||
|
app.add_plugins(plugin);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!("steam init error: {e:?}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
Startup,
|
Startup,
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
use crate::{GameState, control::CharacterInputEnabled};
|
use crate::{
|
||||||
|
GameState, HEDZ_GREEN, HEDZ_PURPLE, client::control::CharacterInputEnabled,
|
||||||
|
loading_assets::UIAssets,
|
||||||
|
};
|
||||||
use bevy::{color::palettes::css::BLACK, prelude::*};
|
use bevy::{color::palettes::css::BLACK, prelude::*};
|
||||||
use shared::{HEDZ_GREEN, HEDZ_PURPLE, loading_assets::UIAssets};
|
|
||||||
|
|
||||||
#[derive(States, Default, Clone, Eq, PartialEq, Debug, Hash)]
|
#[derive(States, Default, Clone, Eq, PartialEq, Debug, Hash)]
|
||||||
#[states(scoped_entities)]
|
#[states(scoped_entities)]
|
||||||
@@ -3,21 +3,23 @@ use clap::Parser;
|
|||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
let config = ClientConfig::parse();
|
let config = NetworkingConfig::parse();
|
||||||
|
|
||||||
app.insert_resource(config);
|
app.insert_resource(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource, Parser, Debug)]
|
#[derive(Resource, Parser, Debug)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
pub struct ClientConfig {
|
pub struct NetworkingConfig {
|
||||||
/// The port to use when connecting.
|
|
||||||
#[arg(long, default_value_t = 0)]
|
|
||||||
pub port: u16,
|
|
||||||
/// The IP/port to connect to.
|
/// The IP/port to connect to.
|
||||||
/// If `None`, host a local server.
|
/// If `None`, host a local server.
|
||||||
/// If Some(None), connect to the default server (`127.0.0.1:31111`)
|
/// If Some(None), connect to the default server (`127.0.0.1:31111`)
|
||||||
/// Otherwise, connect to the given server
|
/// Otherwise, connect to the given server.
|
||||||
|
/// Does nothing on the server.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub server: Option<Option<SocketAddr>>,
|
pub server: Option<Option<SocketAddr>>,
|
||||||
|
/// Whether or not to open a port when opening the client, for other clients
|
||||||
|
/// to connect. Does nothing if `server` is set.
|
||||||
|
#[arg(long)]
|
||||||
|
pub host: bool,
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ use crate::{
|
|||||||
GameState,
|
GameState,
|
||||||
animation::AnimationFlags,
|
animation::AnimationFlags,
|
||||||
control::{ControllerSet, ControllerSettings, Inputs, controller_common::MovementSpeedFactor},
|
control::{ControllerSet, ControllerSettings, Inputs, controller_common::MovementSpeedFactor},
|
||||||
|
protocol::is_server,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -9,7 +10,6 @@ use crate::{
|
|||||||
player::{LocalPlayer, PlayerBodyMesh},
|
player::{LocalPlayer, PlayerBodyMesh},
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_replicon::prelude::ClientState;
|
|
||||||
use happy_feet::prelude::{Grounding, KinematicVelocity, MoveInput};
|
use happy_feet::prelude::{Grounding, KinematicVelocity, MoveInput};
|
||||||
|
|
||||||
pub struct CharacterControllerPlugin;
|
pub struct CharacterControllerPlugin;
|
||||||
@@ -28,8 +28,7 @@ impl Plugin for CharacterControllerPlugin {
|
|||||||
FixedUpdate,
|
FixedUpdate,
|
||||||
apply_controls
|
apply_controls
|
||||||
.in_set(ControllerSet::ApplyControlsRun)
|
.in_set(ControllerSet::ApplyControlsRun)
|
||||||
.run_if(in_state(GameState::Playing))
|
.run_if(in_state(GameState::Playing).and(is_server)),
|
||||||
.run_if(in_state(ClientState::Disconnected)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,10 +81,8 @@ fn apply_controls(
|
|||||||
move_input.set(direction * move_factor.0);
|
move_input.set(direction * move_factor.0);
|
||||||
|
|
||||||
if inputs.jump && grounding.is_grounded() {
|
if inputs.jump && grounding.is_grounded() {
|
||||||
if cfg!(feature = "server") {
|
|
||||||
flags.jumping = true;
|
flags.jumping = true;
|
||||||
flags.jump_count += 1;
|
flags.jump_count += 1;
|
||||||
}
|
|
||||||
happy_feet::movement::jump(settings.jump_force, &mut velocity, &mut grounding, Dir3::Y)
|
happy_feet::movement::jump(settings.jump_force, &mut velocity, &mut grounding, Dir3::Y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,13 +3,10 @@ use crate::{
|
|||||||
head::ActiveHead,
|
head::ActiveHead,
|
||||||
heads_database::{HeadControls, HeadsDatabase},
|
heads_database::{HeadControls, HeadsDatabase},
|
||||||
player::Player,
|
player::Player,
|
||||||
protocol::ClientToController,
|
protocol::{ClientToController, is_server},
|
||||||
};
|
};
|
||||||
use bevy::{ecs::entity::MapEntities, prelude::*};
|
use bevy::{ecs::entity::MapEntities, prelude::*};
|
||||||
use bevy_replicon::{
|
use bevy_replicon::{client::ClientSystems, prelude::FromClient};
|
||||||
client::ClientSystems,
|
|
||||||
prelude::{ClientState, FromClient},
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod controller_common;
|
pub mod controller_common;
|
||||||
@@ -61,7 +58,7 @@ pub fn plugin(app: &mut App) {
|
|||||||
app.add_systems(
|
app.add_systems(
|
||||||
PreUpdate,
|
PreUpdate,
|
||||||
collect_player_inputs
|
collect_player_inputs
|
||||||
.run_if(in_state(ClientState::Disconnected).and(in_state(GameState::Playing)))
|
.run_if(is_server.and(in_state(GameState::Playing)))
|
||||||
.after(ClientSystems::Receive),
|
.after(ClientSystems::Receive),
|
||||||
);
|
);
|
||||||
app.add_systems(Update, head_change.run_if(in_state(GameState::Playing)));
|
app.add_systems(Update, head_change.run_if(in_state(GameState::Playing)));
|
||||||
@@ -128,12 +125,6 @@ pub struct CashHealPressed;
|
|||||||
#[reflect(Resource)]
|
#[reflect(Resource)]
|
||||||
pub struct LookDirMovement(pub Vec2);
|
pub struct LookDirMovement(pub Vec2);
|
||||||
|
|
||||||
#[derive(Resource, Debug, PartialEq, Eq)]
|
|
||||||
pub enum CharacterInputEnabled {
|
|
||||||
On,
|
|
||||||
Off,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component, Clone, PartialEq, Reflect, Serialize, Deserialize)]
|
#[derive(Component, Clone, PartialEq, Reflect, Serialize, Deserialize)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct ControllerSettings {
|
pub struct ControllerSettings {
|
||||||
@@ -154,7 +145,9 @@ fn collect_player_inputs(
|
|||||||
) {
|
) {
|
||||||
for msg in input_messages.read() {
|
for msg in input_messages.read() {
|
||||||
let player = clients.get_controller(msg.client_id);
|
let player = clients.get_controller(msg.client_id);
|
||||||
let mut inputs = players.get_mut(player).unwrap();
|
let Ok(mut inputs) = players.get_mut(player) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
*inputs = msg.message.0;
|
*inputs = msg.message.0;
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,108 @@
|
|||||||
use avian3d::prelude::*;
|
use crate::{
|
||||||
use bevy::{
|
GameState, global_observer,
|
||||||
ecs::{relationship::RelatedSpawner, spawn::SpawnWith},
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
use bevy_replicon::prelude::{Replicated, SendMode, ServerTriggerExt, ToClients};
|
|
||||||
use shared::{
|
|
||||||
global_observer,
|
|
||||||
head_drop::{HeadCollected, HeadDrop, HeadDropEnableTime, HeadDrops, SecretHeadMarker},
|
|
||||||
heads_database::HeadsDatabase,
|
heads_database::HeadsDatabase,
|
||||||
physics_layers::GameLayer,
|
physics_layers::GameLayer,
|
||||||
player::Player,
|
player::Player,
|
||||||
protocol::{GltfSceneRoot, PlaySound},
|
protocol::{GltfSceneRoot, NetworkEnv, PlaySound},
|
||||||
|
server_observer,
|
||||||
|
tb_entities::SecretHead,
|
||||||
utils::{
|
utils::{
|
||||||
billboards::Billboard, one_shot_force::OneShotImpulse, squish_animation::SquishAnimation,
|
billboards::Billboard, one_shot_force::OneShotImpulse, squish_animation::SquishAnimation,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use avian3d::prelude::*;
|
||||||
|
use bevy::{ecs::relationship::RelatedSpawner, prelude::*};
|
||||||
|
use bevy_replicon::prelude::{Replicated, SendMode, ServerTriggerExt, ToClients};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
|
#[derive(Event, Reflect)]
|
||||||
|
pub struct HeadDrops {
|
||||||
|
pub pos: Vec3,
|
||||||
|
pub head_id: usize,
|
||||||
|
pub impulse: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadDrops {
|
||||||
|
pub fn new(pos: Vec3, head_id: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
pos,
|
||||||
|
head_id,
|
||||||
|
impulse: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_static(pos: Vec3, head_id: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
pos,
|
||||||
|
head_id,
|
||||||
|
impulse: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct HeadDrop {
|
||||||
|
pub head_id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct HeadDropEnableTime(pub f32);
|
||||||
|
|
||||||
|
#[derive(Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct SecretHeadMarker;
|
||||||
|
|
||||||
|
#[derive(EntityEvent, Reflect)]
|
||||||
|
pub struct HeadCollected {
|
||||||
|
pub entity: Entity,
|
||||||
|
pub head: usize,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
global_observer!(app, on_head_drop);
|
app.register_type::<HeadDrop>();
|
||||||
|
app.register_type::<HeadDropEnableTime>();
|
||||||
|
app.register_type::<SecretHeadMarker>();
|
||||||
|
|
||||||
|
app.add_systems(
|
||||||
|
Update,
|
||||||
|
enable_collectible.run_if(in_state(GameState::Playing)),
|
||||||
|
);
|
||||||
|
|
||||||
|
app.add_systems(OnEnter(GameState::Playing), spawn);
|
||||||
|
|
||||||
|
server_observer!(app, on_head_drop);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn(mut commands: Commands, query: Query<(Entity, &GlobalTransform, &SecretHead)>) {
|
||||||
|
for (e, t, head) in query {
|
||||||
|
commands.trigger(HeadDrops::new_static(
|
||||||
|
t.translation() + Vec3::new(0., 2., 0.),
|
||||||
|
head.head_id,
|
||||||
|
));
|
||||||
|
|
||||||
|
commands.entity(e).despawn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enable_collectible(
|
||||||
|
mut commands: Commands,
|
||||||
|
query: Query<(Entity, &HeadDropEnableTime)>,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
let now = time.elapsed_secs();
|
||||||
|
for (e, enable_time) in query.iter() {
|
||||||
|
if now > enable_time.0 {
|
||||||
|
commands
|
||||||
|
.entity(e)
|
||||||
|
.insert(CollisionLayers::new(
|
||||||
|
LayerMask(GameLayer::CollectibleSensors.to_bits()),
|
||||||
|
LayerMask::ALL,
|
||||||
|
))
|
||||||
|
.remove::<HeadDropEnableTime>();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_head_drop(
|
fn on_head_drop(
|
||||||
@@ -89,7 +173,12 @@ fn on_collect_head(
|
|||||||
query_player: Query<&Player>,
|
query_player: Query<&Player>,
|
||||||
query_collectable: Query<(&HeadDrop, &ChildOf)>,
|
query_collectable: Query<(&HeadDrop, &ChildOf)>,
|
||||||
query_secret: Query<&SecretHeadMarker>,
|
query_secret: Query<&SecretHeadMarker>,
|
||||||
|
env: NetworkEnv,
|
||||||
) {
|
) {
|
||||||
|
if !env.is_server() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let collectable = trigger.event().collider1;
|
let collectable = trigger.event().collider1;
|
||||||
let collider = trigger.event().collider2;
|
let collider = trigger.event().collider2;
|
||||||
|
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
#[cfg(feature = "server")]
|
use super::{ActiveHeads, HEAD_SLOTS};
|
||||||
use super::ActiveHeads;
|
|
||||||
use super::HEAD_SLOTS;
|
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
use super::HeadsImages;
|
use crate::heads::HeadsImages;
|
||||||
#[cfg(feature = "server")]
|
use crate::{
|
||||||
use crate::player::Player;
|
GameState, backpack::UiHeadState, loading_assets::UIAssets, player::Player, protocol::is_server,
|
||||||
use crate::{GameState, backpack::UiHeadState, loading_assets::UIAssets};
|
};
|
||||||
use bevy::{ecs::spawn::SpawnIter, prelude::*};
|
use bevy::{ecs::spawn::SpawnIter, prelude::*};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
@@ -34,8 +32,10 @@ pub fn plugin(app: &mut App) {
|
|||||||
app.register_type::<UiActiveHeads>();
|
app.register_type::<UiActiveHeads>();
|
||||||
|
|
||||||
app.add_systems(OnEnter(GameState::Playing), setup);
|
app.add_systems(OnEnter(GameState::Playing), setup);
|
||||||
#[cfg(feature = "server")]
|
app.add_systems(
|
||||||
app.add_systems(FixedUpdate, sync.run_if(in_state(GameState::Playing)));
|
FixedUpdate,
|
||||||
|
sync.run_if(in_state(GameState::Playing).and(is_server)),
|
||||||
|
);
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
FixedUpdate,
|
FixedUpdate,
|
||||||
@@ -238,7 +238,6 @@ fn update_health(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
fn sync(
|
fn sync(
|
||||||
active_heads: Query<Ref<ActiveHeads>, With<Player>>,
|
active_heads: Query<Ref<ActiveHeads>, With<Player>>,
|
||||||
mut state: Single<&mut UiActiveHeads>,
|
mut state: Single<&mut UiActiveHeads>,
|
||||||
@@ -7,10 +7,10 @@ use crate::{
|
|||||||
heads_database::HeadsDatabase,
|
heads_database::HeadsDatabase,
|
||||||
hitpoints::Hitpoints,
|
hitpoints::Hitpoints,
|
||||||
player::Player,
|
player::Player,
|
||||||
protocol::{ClientToController, PlaySound},
|
protocol::{ClientToController, PlaySound, is_server},
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_replicon::prelude::{ClientState, FromClient};
|
use bevy_replicon::prelude::FromClient;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod heads_ui;
|
pub mod heads_ui;
|
||||||
@@ -192,7 +192,7 @@ pub fn plugin(app: &mut App) {
|
|||||||
(reload, sync_hp).run_if(in_state(GameState::Playing)),
|
(reload, sync_hp).run_if(in_state(GameState::Playing)),
|
||||||
on_select_active_head,
|
on_select_active_head,
|
||||||
)
|
)
|
||||||
.run_if(in_state(ClientState::Disconnected)),
|
.run_if(is_server),
|
||||||
);
|
);
|
||||||
|
|
||||||
global_observer!(app, on_swap_backpack);
|
global_observer!(app, on_swap_backpack);
|
||||||
@@ -2,10 +2,10 @@ use crate::{
|
|||||||
GameState,
|
GameState,
|
||||||
animation::AnimationFlags,
|
animation::AnimationFlags,
|
||||||
character::{CharacterAnimations, HasCharacterAnimations},
|
character::{CharacterAnimations, HasCharacterAnimations},
|
||||||
protocol::PlaySound,
|
protocol::{PlaySound, is_server},
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_replicon::prelude::{ClientState, SendMode, ServerTriggerExt, ToClients};
|
use bevy_replicon::prelude::{SendMode, ServerTriggerExt, ToClients};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(EntityEvent, Reflect)]
|
#[derive(EntityEvent, Reflect)]
|
||||||
@@ -66,14 +66,10 @@ impl Hitpoints {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.add_systems(
|
app.add_systems(Update, on_hp_added.run_if(is_server))
|
||||||
Update,
|
|
||||||
on_hp_added.run_if(in_state(ClientState::Disconnected)),
|
|
||||||
)
|
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PreUpdate,
|
PreUpdate,
|
||||||
reset_hit_animation_flag
|
reset_hit_animation_flag.run_if(is_server.and(in_state(GameState::Playing))),
|
||||||
.run_if(in_state(ClientState::Disconnected).and(in_state(GameState::Playing))),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
229
crates/hedz_reloaded/src/lib.rs
Normal file
229
crates/hedz_reloaded/src/lib.rs
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
pub mod abilities;
|
||||||
|
pub mod ai;
|
||||||
|
pub mod aim;
|
||||||
|
pub mod animation;
|
||||||
|
pub mod backpack;
|
||||||
|
pub mod camera;
|
||||||
|
pub mod cash;
|
||||||
|
pub mod cash_heal;
|
||||||
|
pub mod character;
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
pub mod client;
|
||||||
|
pub mod config;
|
||||||
|
pub mod control;
|
||||||
|
pub mod cutscene;
|
||||||
|
pub mod gates;
|
||||||
|
pub mod head;
|
||||||
|
pub mod head_drop;
|
||||||
|
pub mod heads;
|
||||||
|
pub mod heads_database;
|
||||||
|
pub mod hitpoints;
|
||||||
|
pub mod keys;
|
||||||
|
pub mod loading_assets;
|
||||||
|
pub mod loading_map;
|
||||||
|
pub mod movables;
|
||||||
|
pub mod npc;
|
||||||
|
pub mod physics_layers;
|
||||||
|
pub mod platforms;
|
||||||
|
pub mod player;
|
||||||
|
pub mod protocol;
|
||||||
|
pub mod server;
|
||||||
|
pub mod tb_entities;
|
||||||
|
pub mod tick;
|
||||||
|
pub mod utils;
|
||||||
|
pub mod water;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
config::NetworkingConfig,
|
||||||
|
heads_database::{HeadDatabaseAsset, HeadsDatabase},
|
||||||
|
protocol::{PlayerId, messages::AssignClientPlayer},
|
||||||
|
tb_entities::SpawnPoint,
|
||||||
|
};
|
||||||
|
use avian3d::{PhysicsPlugins, prelude::TransformInterpolation};
|
||||||
|
#[cfg(not(feature = "client"))]
|
||||||
|
use bevy::app::ScheduleRunnerPlugin;
|
||||||
|
use bevy::{core_pipeline::tonemapping::Tonemapping, prelude::*};
|
||||||
|
use bevy_common_assets::ron::RonAssetPlugin;
|
||||||
|
use bevy_replicon::{RepliconPlugins, prelude::ClientId};
|
||||||
|
use bevy_replicon_renet::RepliconRenetPlugins;
|
||||||
|
use bevy_sprite3d::Sprite3dPlugin;
|
||||||
|
use bevy_trenchbroom::{
|
||||||
|
TrenchBroomPlugins, config::TrenchBroomConfig, prelude::TrenchBroomPhysicsPlugin,
|
||||||
|
};
|
||||||
|
use bevy_trenchbroom_avian::AvianPhysicsBackend;
|
||||||
|
use utils::{billboards, squish_animation};
|
||||||
|
|
||||||
|
pub const HEDZ_GREEN: Srgba = Srgba::rgb(0.0, 1.0, 0.0);
|
||||||
|
pub const HEDZ_PURPLE: Srgba = Srgba::rgb(91. / 256., 4. / 256., 138. / 256.);
|
||||||
|
|
||||||
|
pub fn launch() {
|
||||||
|
let mut app = App::new();
|
||||||
|
|
||||||
|
app.register_type::<DebugVisuals>()
|
||||||
|
.register_type::<TransformInterpolation>();
|
||||||
|
|
||||||
|
app.insert_resource(DebugVisuals {
|
||||||
|
unlit: false,
|
||||||
|
tonemapping: Tonemapping::None,
|
||||||
|
exposure: 1.,
|
||||||
|
shadows: true,
|
||||||
|
cam_follow: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
let default_plugins = DefaultPlugins;
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
let default_plugins = default_plugins.set(WindowPlugin {
|
||||||
|
primary_window: Some(Window {
|
||||||
|
title: "HEDZ Reloaded".into(),
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
app.add_plugins(default_plugins);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "client"))]
|
||||||
|
app.add_plugins(ScheduleRunnerPlugin::default());
|
||||||
|
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
app.add_plugins(
|
||||||
|
bevy_debug_log::LogViewerPlugin::default()
|
||||||
|
.auto_open_threshold(bevy::log::tracing::level_filters::LevelFilter::OFF),
|
||||||
|
);
|
||||||
|
|
||||||
|
app.add_plugins(PhysicsPlugins::default());
|
||||||
|
app.add_plugins((RepliconPlugins, RepliconRenetPlugins));
|
||||||
|
app.add_plugins(Sprite3dPlugin);
|
||||||
|
app.add_plugins(TrenchBroomPlugins(
|
||||||
|
TrenchBroomConfig::new("hedz").icon(None),
|
||||||
|
));
|
||||||
|
app.add_plugins(TrenchBroomPhysicsPlugin::new(AvianPhysicsBackend));
|
||||||
|
app.add_plugins(RonAssetPlugin::<HeadDatabaseAsset>::new(&["headsdb.ron"]));
|
||||||
|
|
||||||
|
app.add_plugins(plugin);
|
||||||
|
|
||||||
|
app.init_state::<GameState>();
|
||||||
|
|
||||||
|
app.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) {
|
||||||
|
app.add_plugins(abilities::plugin);
|
||||||
|
app.add_plugins(ai::plugin);
|
||||||
|
app.add_plugins(animation::plugin);
|
||||||
|
app.add_plugins(character::plugin);
|
||||||
|
app.add_plugins(cash::plugin);
|
||||||
|
app.add_plugins(cash_heal::plugin);
|
||||||
|
app.add_plugins(config::plugin);
|
||||||
|
app.add_plugins(player::plugin);
|
||||||
|
app.add_plugins(gates::plugin);
|
||||||
|
app.add_plugins(platforms::plugin);
|
||||||
|
app.add_plugins(movables::plugin);
|
||||||
|
app.add_plugins(utils::billboards::plugin);
|
||||||
|
app.add_plugins(aim::plugin);
|
||||||
|
app.add_plugins(npc::plugin);
|
||||||
|
app.add_plugins(keys::plugin);
|
||||||
|
app.add_plugins(utils::squish_animation::plugin);
|
||||||
|
app.add_plugins(camera::plugin);
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
app.add_plugins(client::plugin);
|
||||||
|
app.add_plugins(control::plugin);
|
||||||
|
app.add_plugins(cutscene::plugin);
|
||||||
|
app.add_plugins(backpack::plugin);
|
||||||
|
app.add_plugins(loading_assets::LoadingPlugin);
|
||||||
|
app.add_plugins(loading_map::plugin);
|
||||||
|
app.add_plugins(heads::plugin);
|
||||||
|
app.add_plugins(hitpoints::plugin);
|
||||||
|
app.add_plugins(head_drop::plugin);
|
||||||
|
app.add_plugins(protocol::plugin);
|
||||||
|
app.add_plugins(server::plugin);
|
||||||
|
app.add_plugins(tb_entities::plugin);
|
||||||
|
app.add_plugins(tick::plugin);
|
||||||
|
app.add_plugins(utils::plugin);
|
||||||
|
app.add_plugins(utils::auto_rotate::plugin);
|
||||||
|
app.add_plugins(utils::explosions::plugin);
|
||||||
|
app.add_plugins(utils::sprite_3d_animation::plugin);
|
||||||
|
app.add_plugins(utils::trail::plugin);
|
||||||
|
app.add_plugins(water::plugin);
|
||||||
|
|
||||||
|
if cfg!(feature = "client") {
|
||||||
|
app.add_systems(
|
||||||
|
OnEnter(GameState::Waiting),
|
||||||
|
start_solo_client
|
||||||
|
.run_if(|config: Res<NetworkingConfig>| config.server.is_none() && !config.host),
|
||||||
|
);
|
||||||
|
app.add_systems(
|
||||||
|
OnEnter(GameState::Waiting),
|
||||||
|
start_listen_server
|
||||||
|
.run_if(|config: Res<NetworkingConfig>| config.server.is_none() && config.host),
|
||||||
|
);
|
||||||
|
app.add_systems(
|
||||||
|
OnEnter(GameState::Waiting),
|
||||||
|
start_client.run_if(|config: Res<NetworkingConfig>| config.server.is_some()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
app.add_systems(OnEnter(GameState::Waiting), start_dedicated_server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource, Reflect, Debug)]
|
||||||
|
#[reflect(Resource)]
|
||||||
|
pub struct DebugVisuals {
|
||||||
|
pub unlit: bool,
|
||||||
|
pub tonemapping: Tonemapping,
|
||||||
|
pub exposure: f32,
|
||||||
|
pub shadows: bool,
|
||||||
|
pub cam_follow: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(States, Default, Clone, Copy, Eq, PartialEq, Debug, Hash)]
|
||||||
|
pub enum GameState {
|
||||||
|
/// Loading assets from disk
|
||||||
|
#[default]
|
||||||
|
AssetLoading,
|
||||||
|
/// Loading + constructing map
|
||||||
|
MapLoading,
|
||||||
|
/// Waiting to host/connect/play
|
||||||
|
Waiting,
|
||||||
|
/// Connecting to server
|
||||||
|
Connecting,
|
||||||
|
/// Opening server
|
||||||
|
Hosting,
|
||||||
|
/// Running the game
|
||||||
|
Playing,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_solo_client(
|
||||||
|
commands: Commands,
|
||||||
|
mut next: ResMut<NextState<GameState>>,
|
||||||
|
query: Query<&Transform, With<SpawnPoint>>,
|
||||||
|
heads_db: Res<HeadsDatabase>,
|
||||||
|
mut assign_player_id: MessageWriter<AssignClientPlayer>,
|
||||||
|
) {
|
||||||
|
next.set(GameState::Playing);
|
||||||
|
|
||||||
|
player::spawn(commands, ClientId::Server, query, heads_db);
|
||||||
|
|
||||||
|
assign_player_id.write(AssignClientPlayer(PlayerId { id: 0 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_listen_server(
|
||||||
|
commands: Commands,
|
||||||
|
mut next: ResMut<NextState<GameState>>,
|
||||||
|
query: Query<&Transform, With<SpawnPoint>>,
|
||||||
|
heads_db: Res<HeadsDatabase>,
|
||||||
|
mut assign_player_id: MessageWriter<AssignClientPlayer>,
|
||||||
|
) {
|
||||||
|
next.set(GameState::Hosting);
|
||||||
|
|
||||||
|
player::spawn(commands, ClientId::Server, query, heads_db);
|
||||||
|
|
||||||
|
assign_player_id.write(AssignClientPlayer(PlayerId { id: 0 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_client(mut next: ResMut<NextState<GameState>>) {
|
||||||
|
next.set(GameState::Connecting);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_dedicated_server(mut next: ResMut<NextState<GameState>>) {
|
||||||
|
next.set(GameState::Hosting);
|
||||||
|
}
|
||||||
@@ -147,4 +147,6 @@ fn on_exit(
|
|||||||
.expect("headsdb failed to load");
|
.expect("headsdb failed to load");
|
||||||
|
|
||||||
cmds.insert_resource(HeadsDatabase { heads: asset.0 });
|
cmds.insert_resource(HeadsDatabase { heads: asset.0 });
|
||||||
|
|
||||||
|
info!("loaded assets");
|
||||||
}
|
}
|
||||||
@@ -33,13 +33,7 @@ fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||||||
|
|
||||||
commands.entity(t.scene_root_entity).insert(Replicated);
|
commands.entity(t.scene_root_entity).insert(Replicated);
|
||||||
|
|
||||||
const { assert!(cfg!(feature = "client") ^ cfg!(feature = "server")) };
|
next_game_state.set(GameState::Waiting);
|
||||||
|
|
||||||
#[cfg(feature = "client")]
|
|
||||||
next_game_state.set(GameState::Connecting);
|
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
next_game_state.set(GameState::Playing);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
3
crates/hedz_reloaded/src/main.rs
Normal file
3
crates/hedz_reloaded/src/main.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub fn main() {
|
||||||
|
hedz_reloaded::launch();
|
||||||
|
}
|
||||||
@@ -1,23 +1,21 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState, character::HedzCharacter, global_observer, loading_assets::GameAssets,
|
GameState,
|
||||||
utils::billboards::Billboard,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use crate::{
|
|
||||||
ai::Ai,
|
ai::Ai,
|
||||||
character::AnimatedCharacter,
|
character::{AnimatedCharacter, HedzCharacter},
|
||||||
|
global_observer,
|
||||||
head::ActiveHead,
|
head::ActiveHead,
|
||||||
head_drop::HeadDrops,
|
head_drop::HeadDrops,
|
||||||
heads::{ActiveHeads, HEAD_COUNT, HeadState},
|
heads::{ActiveHeads, HEAD_COUNT, HeadState},
|
||||||
heads_database::HeadsDatabase,
|
heads_database::HeadsDatabase,
|
||||||
hitpoints::{Hitpoints, Kill},
|
hitpoints::{Hitpoints, Kill},
|
||||||
keys::KeySpawn,
|
keys::KeySpawn,
|
||||||
protocol::PlaySound,
|
loading_assets::GameAssets,
|
||||||
|
protocol::{PlaySound, is_server},
|
||||||
tb_entities::EnemySpawn,
|
tb_entities::EnemySpawn,
|
||||||
|
utils::billboards::Billboard,
|
||||||
};
|
};
|
||||||
use bevy::{light::NotShadowCaster, prelude::*};
|
use bevy::{light::NotShadowCaster, prelude::*};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Component, Reflect, PartialEq, Serialize, Deserialize)]
|
#[derive(Component, Reflect, PartialEq, Serialize, Deserialize)]
|
||||||
@@ -35,7 +33,6 @@ struct NpcSpawning {
|
|||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct SpawningBeam(pub f32);
|
pub struct SpawningBeam(pub f32);
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
#[derive(Event)]
|
#[derive(Event)]
|
||||||
struct OnCheckSpawns;
|
struct OnCheckSpawns;
|
||||||
|
|
||||||
@@ -44,16 +41,17 @@ pub struct SpawnCharacter(pub Vec3);
|
|||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.init_resource::<NpcSpawning>();
|
app.init_resource::<NpcSpawning>();
|
||||||
#[cfg(feature = "server")]
|
|
||||||
app.add_systems(FixedUpdate, setup.run_if(in_state(GameState::Playing)));
|
app.add_systems(
|
||||||
|
FixedUpdate,
|
||||||
|
setup.run_if(in_state(GameState::Playing).and(is_server)),
|
||||||
|
);
|
||||||
app.add_systems(Update, update_beams.run_if(in_state(GameState::Playing)));
|
app.add_systems(Update, update_beams.run_if(in_state(GameState::Playing)));
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
global_observer!(app, on_spawn_check);
|
global_observer!(app, on_spawn_check);
|
||||||
global_observer!(app, on_spawn);
|
global_observer!(app, on_spawn);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
fn setup(mut commands: Commands, mut spawned: Local<bool>) {
|
fn setup(mut commands: Commands, mut spawned: Local<bool>) {
|
||||||
if *spawned {
|
if *spawned {
|
||||||
return;
|
return;
|
||||||
@@ -65,7 +63,6 @@ fn setup(mut commands: Commands, mut spawned: Local<bool>) {
|
|||||||
*spawned = true;
|
*spawned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
fn on_spawn_check(
|
fn on_spawn_check(
|
||||||
_trigger: On<OnCheckSpawns>,
|
_trigger: On<OnCheckSpawns>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
@@ -120,7 +117,6 @@ fn on_spawn_check(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
fn on_kill(
|
fn on_kill(
|
||||||
trigger: On<Kill>,
|
trigger: On<Kill>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
use crate::{GameState, tick::GameTick};
|
use crate::{
|
||||||
|
GameState,
|
||||||
|
protocol::is_server,
|
||||||
|
tb_entities::{Platform, PlatformTarget},
|
||||||
|
tick::GameTick,
|
||||||
|
};
|
||||||
use avian3d::prelude::{LinearVelocity, Position};
|
use avian3d::prelude::{LinearVelocity, Position};
|
||||||
use bevy::{math::ops::sin, prelude::*};
|
use bevy::{math::ops::sin, prelude::*};
|
||||||
|
use bevy_trenchbroom::prelude::Target;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Component, Reflect, Default, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Component, Reflect, Default, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
@@ -16,6 +22,8 @@ pub fn plugin(app: &mut App) {
|
|||||||
FixedUpdate,
|
FixedUpdate,
|
||||||
move_active.run_if(in_state(GameState::Playing)),
|
move_active.run_if(in_state(GameState::Playing)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.add_systems(OnEnter(GameState::Playing), init.run_if(is_server));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_active(
|
fn move_active(
|
||||||
@@ -33,3 +41,30 @@ fn move_active(
|
|||||||
velocity.0 = (target - prev) / fixed_time.timestep().as_secs_f32();
|
velocity.0 = (target - prev) / fixed_time.timestep().as_secs_f32();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn init(
|
||||||
|
mut commands: Commands,
|
||||||
|
uninit_platforms: Query<
|
||||||
|
(Entity, &Target, &Transform),
|
||||||
|
(Without<ActivePlatform>, With<Platform>),
|
||||||
|
>,
|
||||||
|
targets: Query<(&PlatformTarget, &Transform)>,
|
||||||
|
) {
|
||||||
|
for (e, target, transform) in uninit_platforms.iter() {
|
||||||
|
let Some(target) = targets
|
||||||
|
.iter()
|
||||||
|
.find(|(t, _)| t.targetname == target.target.clone().unwrap_or_default())
|
||||||
|
.map(|(_, t)| t.translation)
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let platform = ActivePlatform {
|
||||||
|
start: transform.translation,
|
||||||
|
target,
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.entity(e).insert(platform);
|
||||||
|
}
|
||||||
|
}
|
||||||
242
crates/hedz_reloaded/src/player.rs
Normal file
242
crates/hedz_reloaded/src/player.rs
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
use crate::{
|
||||||
|
GameState,
|
||||||
|
abilities::PlayerTriggerState,
|
||||||
|
backpack::{Backpack, backpack_ui::BackpackUiState},
|
||||||
|
camera::{CameraArmRotation, CameraTarget},
|
||||||
|
cash::{Cash, CashCollectEvent, CashInventory},
|
||||||
|
character::{AnimatedCharacter, HedzCharacter},
|
||||||
|
control::{Inputs, LocalInputs, controller_common::PlayerCharacterController},
|
||||||
|
global_observer,
|
||||||
|
head::ActiveHead,
|
||||||
|
head_drop::HeadDrops,
|
||||||
|
heads::{ActiveHeads, HeadChanged, HeadState, heads_ui::UiActiveHeads},
|
||||||
|
heads_database::HeadsDatabase,
|
||||||
|
hitpoints::{Hitpoints, Kill},
|
||||||
|
npc::SpawnCharacter,
|
||||||
|
protocol::{ClientHeadChanged, OwnedByClient, PlaySound, PlayerId},
|
||||||
|
tb_entities::SpawnPoint,
|
||||||
|
};
|
||||||
|
use avian3d::prelude::*;
|
||||||
|
use bevy::{
|
||||||
|
input::common_conditions::input_just_pressed,
|
||||||
|
prelude::*,
|
||||||
|
window::{CursorGrabMode, CursorOptions, PrimaryWindow},
|
||||||
|
};
|
||||||
|
use bevy_replicon::prelude::{ClientId, Replicated, SendMode, ServerTriggerExt, ToClients};
|
||||||
|
use happy_feet::debug::DebugInput;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Component, Default, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[require(HedzCharacter, DebugInput = DebugInput, PlayerTriggerState)]
|
||||||
|
pub struct Player;
|
||||||
|
|
||||||
|
#[derive(Component, Debug, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
#[require(LocalInputs, BackpackUiState)]
|
||||||
|
pub struct LocalPlayer;
|
||||||
|
|
||||||
|
#[derive(Component, Default, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[require(Transform, Visibility)]
|
||||||
|
pub struct PlayerBodyMesh;
|
||||||
|
|
||||||
|
/// Server-side only; inserted on each `client` (not the controller) to track player ids.
|
||||||
|
#[derive(Component, Clone, Copy)]
|
||||||
|
pub struct ClientPlayerId(pub PlayerId);
|
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) {
|
||||||
|
app.add_systems(
|
||||||
|
OnEnter(GameState::Playing),
|
||||||
|
(toggle_cursor_system, cursor_recenter),
|
||||||
|
);
|
||||||
|
|
||||||
|
app.add_systems(
|
||||||
|
Update,
|
||||||
|
(
|
||||||
|
collect_cash,
|
||||||
|
setup_animations_marker_for_player,
|
||||||
|
toggle_cursor_system.run_if(input_just_pressed(KeyCode::Escape)),
|
||||||
|
)
|
||||||
|
.run_if(in_state(GameState::Playing)),
|
||||||
|
);
|
||||||
|
|
||||||
|
global_observer!(app, on_update_head_mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn(
|
||||||
|
mut commands: Commands,
|
||||||
|
owner: ClientId,
|
||||||
|
query: Query<&Transform, With<SpawnPoint>>,
|
||||||
|
heads_db: Res<HeadsDatabase>,
|
||||||
|
) -> Option<Entity> {
|
||||||
|
let spawn = query.iter().next()?;
|
||||||
|
|
||||||
|
let transform = Transform::from_translation(spawn.translation + Vec3::new(0., 3., 0.));
|
||||||
|
|
||||||
|
let id = commands
|
||||||
|
.spawn((
|
||||||
|
(
|
||||||
|
Name::from("player"),
|
||||||
|
Player,
|
||||||
|
ActiveHead(0),
|
||||||
|
ActiveHeads::new([
|
||||||
|
Some(HeadState::new(0, heads_db.as_ref())),
|
||||||
|
Some(HeadState::new(3, heads_db.as_ref())),
|
||||||
|
Some(HeadState::new(6, heads_db.as_ref())),
|
||||||
|
Some(HeadState::new(10, heads_db.as_ref())),
|
||||||
|
Some(HeadState::new(9, heads_db.as_ref())),
|
||||||
|
]),
|
||||||
|
Hitpoints::new(100),
|
||||||
|
CashInventory::default(),
|
||||||
|
CameraTarget,
|
||||||
|
transform,
|
||||||
|
Visibility::default(),
|
||||||
|
PlayerCharacterController,
|
||||||
|
PlayerId { id: 0 },
|
||||||
|
),
|
||||||
|
Backpack::default(),
|
||||||
|
BackpackUiState::default(),
|
||||||
|
UiActiveHeads::default(),
|
||||||
|
Inputs::default(),
|
||||||
|
Replicated,
|
||||||
|
))
|
||||||
|
.with_children(|c| {
|
||||||
|
c.spawn((
|
||||||
|
Name::new("player-rig"),
|
||||||
|
PlayerBodyMesh,
|
||||||
|
CameraArmRotation,
|
||||||
|
Replicated,
|
||||||
|
))
|
||||||
|
.with_child((
|
||||||
|
Name::new("player-animated-character"),
|
||||||
|
AnimatedCharacter::new(0),
|
||||||
|
Replicated,
|
||||||
|
));
|
||||||
|
})
|
||||||
|
.observe(on_kill)
|
||||||
|
.id();
|
||||||
|
|
||||||
|
if let Some(owner) = owner.entity() {
|
||||||
|
commands.entity(id).insert(OwnedByClient(owner));
|
||||||
|
}
|
||||||
|
|
||||||
|
commands.server_trigger(ToClients {
|
||||||
|
mode: SendMode::Broadcast,
|
||||||
|
message: PlaySound::Head("angry demonstrator".to_string()),
|
||||||
|
});
|
||||||
|
commands.trigger(SpawnCharacter(transform.translation));
|
||||||
|
|
||||||
|
Some(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_kill(
|
||||||
|
trigger: On<Kill>,
|
||||||
|
mut commands: Commands,
|
||||||
|
mut query: Query<(&Transform, &ActiveHead, &mut ActiveHeads, &mut Hitpoints)>,
|
||||||
|
) {
|
||||||
|
let Ok((transform, active, mut heads, mut hp)) = query.get_mut(trigger.event().entity) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.trigger(HeadDrops::new(transform.translation, active.0));
|
||||||
|
|
||||||
|
if let Some(new_head) = heads.loose_current() {
|
||||||
|
hp.set_health(heads.current().unwrap().health);
|
||||||
|
|
||||||
|
commands.trigger(HeadChanged(new_head));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_update_head_mesh(
|
||||||
|
trigger: On<HeadChanged>,
|
||||||
|
mut commands: Commands,
|
||||||
|
mesh_children: Single<&Children, With<PlayerBodyMesh>>,
|
||||||
|
animated_characters: Query<&AnimatedCharacter>,
|
||||||
|
mut player: Single<&mut ActiveHead, With<Player>>,
|
||||||
|
) -> Result {
|
||||||
|
let animated_char = mesh_children
|
||||||
|
.iter()
|
||||||
|
.find(|child| animated_characters.contains(*child))
|
||||||
|
.ok_or("tried to update head mesh before AnimatedCharacter was readded")?;
|
||||||
|
|
||||||
|
player.0 = trigger.0;
|
||||||
|
|
||||||
|
commands
|
||||||
|
.entity(animated_char)
|
||||||
|
.insert(AnimatedCharacter::new(trigger.0));
|
||||||
|
|
||||||
|
commands.server_trigger(ToClients {
|
||||||
|
mode: SendMode::Broadcast,
|
||||||
|
message: ClientHeadChanged(trigger.0 as u64),
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cursor_recenter(q_windows: Single<&mut Window, With<PrimaryWindow>>) {
|
||||||
|
let mut primary_window = q_windows;
|
||||||
|
let center = Vec2::new(
|
||||||
|
primary_window.resolution.width() / 2.,
|
||||||
|
primary_window.resolution.height() / 2.,
|
||||||
|
);
|
||||||
|
primary_window.set_cursor_position(Some(center));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_grab_cursor(options: &mut CursorOptions) {
|
||||||
|
match options.grab_mode {
|
||||||
|
CursorGrabMode::None => {
|
||||||
|
options.grab_mode = CursorGrabMode::Confined;
|
||||||
|
options.visible = false;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
options.grab_mode = CursorGrabMode::None;
|
||||||
|
options.visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_cursor_system(mut window: Single<&mut CursorOptions, With<PrimaryWindow>>) {
|
||||||
|
toggle_grab_cursor(&mut window);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_cash(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut collision_message_reader: MessageReader<CollisionStart>,
|
||||||
|
query_player: Query<&Player>,
|
||||||
|
query_cash: Query<&Cash>,
|
||||||
|
) {
|
||||||
|
for CollisionStart {
|
||||||
|
collider1: e1,
|
||||||
|
collider2: e2,
|
||||||
|
..
|
||||||
|
} in collision_message_reader.read()
|
||||||
|
{
|
||||||
|
let collect = if query_player.contains(*e1) && query_cash.contains(*e2) {
|
||||||
|
Some(*e2)
|
||||||
|
} else if query_player.contains(*e2) && query_cash.contains(*e1) {
|
||||||
|
Some(*e1)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(cash) = collect {
|
||||||
|
commands.trigger(CashCollectEvent);
|
||||||
|
commands.entity(cash).despawn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_animations_marker_for_player(
|
||||||
|
mut commands: Commands,
|
||||||
|
animation_handles: Query<Entity, Added<AnimationGraphHandle>>,
|
||||||
|
child_of: Query<&ChildOf>,
|
||||||
|
player_rig: Query<&ChildOf, With<PlayerBodyMesh>>,
|
||||||
|
) {
|
||||||
|
for animation_rig in animation_handles.iter() {
|
||||||
|
for ancestor in child_of.iter_ancestors(animation_rig) {
|
||||||
|
if let Ok(rig_child_of) = player_rig.get(ancestor) {
|
||||||
|
commands.entity(rig_child_of.parent());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,9 +31,9 @@ use avian3d::prelude::{
|
|||||||
AngularInertia, AngularVelocity, CenterOfMass, Collider, ColliderDensity, CollisionLayers,
|
AngularInertia, AngularVelocity, CenterOfMass, Collider, ColliderDensity, CollisionLayers,
|
||||||
LinearVelocity, LockedAxes, Mass, Position, RigidBody, Rotation,
|
LinearVelocity, LockedAxes, Mass, Position, RigidBody, Rotation,
|
||||||
};
|
};
|
||||||
use bevy::{platform::collections::HashMap, prelude::*};
|
use bevy::{ecs::system::SystemParam, platform::collections::HashMap, prelude::*};
|
||||||
use bevy_replicon::prelude::{
|
use bevy_replicon::prelude::{
|
||||||
AppRuleExt, Channel, ClientEventAppExt, ClientMessageAppExt, ServerEventAppExt,
|
AppRuleExt, Channel, ClientEventAppExt, ClientMessageAppExt, ClientState, ServerEventAppExt,
|
||||||
ServerMessageAppExt, SyncRelatedAppExt,
|
ServerMessageAppExt, SyncRelatedAppExt,
|
||||||
};
|
};
|
||||||
pub use components::*;
|
pub use components::*;
|
||||||
@@ -150,6 +150,23 @@ pub fn plugin(app: &mut App) {
|
|||||||
global_observer!(app, components::spawn_gltf_scene_roots);
|
global_observer!(app, components::spawn_gltf_scene_roots);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(SystemParam)]
|
||||||
|
pub struct NetworkEnv<'w> {
|
||||||
|
client_state: Res<'w, State<ClientState>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NetworkEnv<'_> {
|
||||||
|
/// Returns true if this process is currently responsible for being the server/host/"source of truth".
|
||||||
|
/// May change over time.
|
||||||
|
pub fn is_server(&self) -> bool {
|
||||||
|
matches!(**self.client_state, ClientState::Disconnected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_server(state: Res<State<ClientState>>) -> bool {
|
||||||
|
matches!(**state, ClientState::Disconnected)
|
||||||
|
}
|
||||||
|
|
||||||
fn set_game_tick(on: On<SetGameTick>, mut tick: ResMut<GameTick>) {
|
fn set_game_tick(on: On<SetGameTick>, mut tick: ResMut<GameTick>) {
|
||||||
tick.0 = on.event().0;
|
tick.0 = on.event().0;
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,4 @@
|
|||||||
use crate::config::ServerConfig;
|
use crate::{
|
||||||
use bevy::prelude::*;
|
|
||||||
use bevy_replicon::{
|
|
||||||
RepliconPlugins,
|
|
||||||
prelude::{
|
|
||||||
ClientId, ConnectedClient, FromClient, RepliconChannels, SendMode, ServerState,
|
|
||||||
ServerTriggerExt, ToClients,
|
|
||||||
},
|
|
||||||
server::AuthorizedClient,
|
|
||||||
};
|
|
||||||
use bevy_replicon_renet::{
|
|
||||||
RenetChannelsExt, RepliconRenetPlugins,
|
|
||||||
netcode::{NetcodeServerTransport, ServerAuthentication},
|
|
||||||
renet::{ConnectionConfig, RenetServer},
|
|
||||||
};
|
|
||||||
use shared::{
|
|
||||||
GameState, global_observer,
|
GameState, global_observer,
|
||||||
heads_database::HeadsDatabase,
|
heads_database::HeadsDatabase,
|
||||||
player::ClientPlayerId,
|
player::ClientPlayerId,
|
||||||
@@ -21,26 +6,32 @@ use shared::{
|
|||||||
tb_entities::SpawnPoint,
|
tb_entities::SpawnPoint,
|
||||||
tick::GameTick,
|
tick::GameTick,
|
||||||
};
|
};
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_replicon::{
|
||||||
|
prelude::{
|
||||||
|
ClientId, ConnectedClient, FromClient, RepliconChannels, SendMode, ServerTriggerExt,
|
||||||
|
ToClients,
|
||||||
|
},
|
||||||
|
server::AuthorizedClient,
|
||||||
|
};
|
||||||
|
use bevy_replicon_renet::{
|
||||||
|
RenetChannelsExt,
|
||||||
|
netcode::{NetcodeServerTransport, ServerAuthentication},
|
||||||
|
renet::{ConnectionConfig, RenetServer},
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
net::{Ipv4Addr, UdpSocket},
|
net::{Ipv4Addr, UdpSocket},
|
||||||
time::SystemTime,
|
time::SystemTime,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.add_plugins((RepliconPlugins, RepliconRenetPlugins));
|
app.add_systems(OnEnter(GameState::Hosting), open_renet_server);
|
||||||
|
|
||||||
app.add_systems(OnEnter(GameState::Playing), setup_timeout_timer);
|
|
||||||
app.add_systems(OnEnter(ServerState::Running), notify_started);
|
|
||||||
app.add_systems(Update, run_timeout.run_if(in_state(GameState::Playing)));
|
|
||||||
|
|
||||||
app.add_systems(OnEnter(GameState::Playing), open_renet_server);
|
|
||||||
|
|
||||||
// Replicon
|
// Replicon
|
||||||
global_observer!(app, on_connected);
|
global_observer!(app, on_connected);
|
||||||
global_observer!(app, on_disconnected);
|
global_observer!(app, on_disconnected);
|
||||||
|
|
||||||
// Server logic
|
// Server logic
|
||||||
global_observer!(app, cancel_timeout);
|
|
||||||
global_observer!(app, on_client_playing);
|
global_observer!(app, on_client_playing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,13 +41,10 @@ fn on_client_playing(
|
|||||||
query: Query<&Transform, With<SpawnPoint>>,
|
query: Query<&Transform, With<SpawnPoint>>,
|
||||||
heads_db: Res<HeadsDatabase>,
|
heads_db: Res<HeadsDatabase>,
|
||||||
) -> Result {
|
) -> Result {
|
||||||
info!("Client has entered playing gamestate");
|
info!("client has entered playing gamestate");
|
||||||
|
|
||||||
let Some(client) = trigger.client_id.entity() else {
|
crate::player::spawn(commands, trigger.client_id, query, heads_db)
|
||||||
return Ok(());
|
.ok_or("failed to spawn player")?;
|
||||||
};
|
|
||||||
|
|
||||||
crate::player::spawn(commands, client, query, heads_db).ok_or("failed to spawn player")?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -68,7 +56,10 @@ fn on_client_playing(
|
|||||||
fn open_renet_server(
|
fn open_renet_server(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
channels: Res<RepliconChannels>,
|
channels: Res<RepliconChannels>,
|
||||||
|
mut next: ResMut<NextState<GameState>>,
|
||||||
) -> Result<(), BevyError> {
|
) -> Result<(), BevyError> {
|
||||||
|
info!("opening server");
|
||||||
|
|
||||||
let server_channels_config = channels.server_configs();
|
let server_channels_config = channels.server_configs();
|
||||||
let client_channels_config = channels.client_configs();
|
let client_channels_config = channels.client_configs();
|
||||||
|
|
||||||
@@ -93,7 +84,9 @@ fn open_renet_server(
|
|||||||
commands.insert_resource(server);
|
commands.insert_resource(server);
|
||||||
commands.insert_resource(transport);
|
commands.insert_resource(transport);
|
||||||
|
|
||||||
info!("Hosting a server on port {port}");
|
info!("hosting a server on port {port}");
|
||||||
|
|
||||||
|
next.set(GameState::Playing);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -125,44 +118,6 @@ fn on_connected(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_disconnected(
|
fn on_disconnected(on: On<Remove, ConnectedClient>) {
|
||||||
on: On<Remove, ConnectedClient>,
|
|
||||||
config: Res<ServerConfig>,
|
|
||||||
mut writer: MessageWriter<AppExit>,
|
|
||||||
) {
|
|
||||||
info!("client {} disconnected", on.entity);
|
info!("client {} disconnected", on.entity);
|
||||||
|
|
||||||
if config.close_on_client_disconnect {
|
|
||||||
info!("client disconnected, exiting");
|
|
||||||
writer.write(AppExit::Success);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn notify_started() {
|
|
||||||
println!("hedz.server_started");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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: MessageWriter<AppExit>,
|
|
||||||
time: Res<Time>,
|
|
||||||
) {
|
|
||||||
timer.0 -= time.delta_secs();
|
|
||||||
|
|
||||||
if timer.0 <= 0.0 {
|
|
||||||
info!("client timed out, exiting");
|
|
||||||
writer.write(AppExit::Success);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cancel_timeout(_trigger: On<Add, ConnectedClient>, mut timer: ResMut<TimeoutTimer>) {
|
|
||||||
info!("client connected, cancelling timeout");
|
|
||||||
timer.0 = f32::INFINITY;
|
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,9 @@ use crate::{
|
|||||||
cash::Cash,
|
cash::Cash,
|
||||||
loading_assets::GameAssets,
|
loading_assets::GameAssets,
|
||||||
physics_layers::GameLayer,
|
physics_layers::GameLayer,
|
||||||
protocol::{SkipReplicateColliders, TbMapIdCounter},
|
protocol::{
|
||||||
|
SkipReplicateColliders, TbMapEntityId, TbMapIdCounter, messages::DespawnTbMapEntity,
|
||||||
|
},
|
||||||
utils::global_observer,
|
utils::global_observer,
|
||||||
};
|
};
|
||||||
use avian3d::{
|
use avian3d::{
|
||||||
@@ -15,6 +17,7 @@ use bevy::{
|
|||||||
math::*,
|
math::*,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
use bevy_replicon::prelude::{ClientId, ConnectedClient, SendMode, ToClients};
|
||||||
use bevy_trenchbroom::prelude::*;
|
use bevy_trenchbroom::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@@ -199,6 +202,7 @@ fn fix_target_tb_entities(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
|
app.register_type::<DespawnedTbEntityCache>();
|
||||||
app.register_type::<SpawnPoint>();
|
app.register_type::<SpawnPoint>();
|
||||||
app.override_class::<Worldspawn>();
|
app.override_class::<Worldspawn>();
|
||||||
app.register_type::<Water>();
|
app.register_type::<Water>();
|
||||||
@@ -215,8 +219,18 @@ pub fn plugin(app: &mut App) {
|
|||||||
app.register_type::<CashSpawn>();
|
app.register_type::<CashSpawn>();
|
||||||
app.register_type::<SecretHead>();
|
app.register_type::<SecretHead>();
|
||||||
|
|
||||||
|
app.init_resource::<DespawnedTbEntityCache>();
|
||||||
|
|
||||||
app.add_systems(OnExit(GameState::MapLoading), fix_target_tb_entities);
|
app.add_systems(OnExit(GameState::MapLoading), fix_target_tb_entities);
|
||||||
|
|
||||||
|
app.add_systems(
|
||||||
|
OnEnter(GameState::MapLoading),
|
||||||
|
|mut cache: ResMut<DespawnedTbEntityCache>| cache.0.clear(),
|
||||||
|
);
|
||||||
|
|
||||||
|
global_observer!(app, add_despawned_entities_to_cache);
|
||||||
|
global_observer!(app, send_new_client_despawned_cache);
|
||||||
|
|
||||||
global_observer!(app, tb_component_setup::<CashSpawn>);
|
global_observer!(app, tb_component_setup::<CashSpawn>);
|
||||||
global_observer!(app, tb_component_setup::<Movable>);
|
global_observer!(app, tb_component_setup::<Movable>);
|
||||||
global_observer!(app, tb_component_setup::<Platform>);
|
global_observer!(app, tb_component_setup::<Platform>);
|
||||||
@@ -235,3 +249,28 @@ fn tb_component_setup<C: Component>(
|
|||||||
.insert_if_new(id)
|
.insert_if_new(id)
|
||||||
.insert(SkipReplicateColliders);
|
.insert(SkipReplicateColliders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_despawned_entities_to_cache(
|
||||||
|
trigger: On<Remove, TbMapEntityId>,
|
||||||
|
id: Query<&TbMapEntityId>,
|
||||||
|
mut cache: ResMut<DespawnedTbEntityCache>,
|
||||||
|
) {
|
||||||
|
cache.0.push(id.get(trigger.event().entity).unwrap().id);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Resource, Reflect)]
|
||||||
|
#[reflect(Resource)]
|
||||||
|
pub struct DespawnedTbEntityCache(pub Vec<u64>);
|
||||||
|
|
||||||
|
fn send_new_client_despawned_cache(
|
||||||
|
on: On<Add, ConnectedClient>,
|
||||||
|
cache: Res<DespawnedTbEntityCache>,
|
||||||
|
mut send: MessageWriter<ToClients<DespawnTbMapEntity>>,
|
||||||
|
) {
|
||||||
|
for &id in cache.0.iter() {
|
||||||
|
send.write(ToClients {
|
||||||
|
mode: SendMode::Direct(ClientId::Client(on.entity)),
|
||||||
|
message: DespawnTbMapEntity(id),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
56
crates/hedz_reloaded/src/utils/observers.rs
Normal file
56
crates/hedz_reloaded/src/utils/observers.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#[macro_export]
|
||||||
|
macro_rules! global_observer {
|
||||||
|
($app:expr, $($system:tt)*) => {{
|
||||||
|
$app.world_mut()
|
||||||
|
.add_observer($($system)*)
|
||||||
|
.insert(global_observer!(@name $($system)*))
|
||||||
|
}};
|
||||||
|
|
||||||
|
(@name $system:ident ::< $($param:ident),+ $(,)? >) => {{
|
||||||
|
let mut name = String::new();
|
||||||
|
name.push_str(stringify!($system));
|
||||||
|
name.push_str("::<");
|
||||||
|
$(
|
||||||
|
name.push_str(std::any::type_name::<$param>());
|
||||||
|
)+
|
||||||
|
name.push_str(">");
|
||||||
|
Name::new(name)
|
||||||
|
}};
|
||||||
|
|
||||||
|
(@name $system:expr) => {
|
||||||
|
Name::new(stringify!($system))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use global_observer;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! server_observer {
|
||||||
|
($app:expr, $($system:tt)*) => {{
|
||||||
|
$app.add_systems(OnEnter(::bevy_replicon::prelude::ClientState::Disconnected), |mut commands: Commands| {
|
||||||
|
commands
|
||||||
|
.add_observer($($system)*)
|
||||||
|
.insert((
|
||||||
|
global_observer!(@name $($system)*),
|
||||||
|
DespawnOnExit(::bevy_replicon::prelude::ClientState::Disconnected),
|
||||||
|
));
|
||||||
|
})
|
||||||
|
}};
|
||||||
|
|
||||||
|
(@name $system:ident ::< $($param:ident),+ $(,)? >) => {{
|
||||||
|
let mut name = String::new();
|
||||||
|
name.push_str(stringify!($system));
|
||||||
|
name.push_str("::<");
|
||||||
|
$(
|
||||||
|
name.push_str(std::any::type_name::<$param>());
|
||||||
|
)+
|
||||||
|
name.push_str(">");
|
||||||
|
Name::new(name)
|
||||||
|
}};
|
||||||
|
|
||||||
|
(@name $system:expr) => {
|
||||||
|
Name::new(stringify!($system))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use server_observer;
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "server"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2024"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["shared/server"]
|
|
||||||
dbg = ["avian3d/debug-plugin", "shared/dbg"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
avian3d = { workspace = true }
|
|
||||||
bevy = { workspace = true, default-features = false }
|
|
||||||
bevy-steamworks = { workspace = true }
|
|
||||||
bevy_common_assets = { workspace = true }
|
|
||||||
bevy_replicon = { workspace = true, features = ["server"] }
|
|
||||||
bevy_replicon_renet = { workspace = true, features = ["server"] }
|
|
||||||
bevy_sprite3d = { workspace = true }
|
|
||||||
bevy_trenchbroom = { workspace = true }
|
|
||||||
bevy_trenchbroom_avian = { workspace = true }
|
|
||||||
clap = { workspace = true }
|
|
||||||
happy_feet = { workspace = true }
|
|
||||||
rand = { workspace = true }
|
|
||||||
ron = { workspace = true }
|
|
||||||
serde = { workspace = true }
|
|
||||||
shared = { workspace = true }
|
|
||||||
steamworks = { workspace = true }
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
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,137 +0,0 @@
|
|||||||
use avian3d::prelude::*;
|
|
||||||
use bevy::{app::plugin_group, core_pipeline::tonemapping::Tonemapping, prelude::*};
|
|
||||||
use bevy_common_assets::ron::RonAssetPlugin;
|
|
||||||
use bevy_sprite3d::Sprite3dPlugin;
|
|
||||||
use bevy_trenchbroom::prelude::*;
|
|
||||||
use bevy_trenchbroom_avian::AvianPhysicsBackend;
|
|
||||||
use shared::{DebugVisuals, GameState, heads_database::HeadDatabaseAsset};
|
|
||||||
|
|
||||||
mod config;
|
|
||||||
mod head_drop;
|
|
||||||
mod platforms;
|
|
||||||
mod player;
|
|
||||||
mod server;
|
|
||||||
mod tb_entities;
|
|
||||||
mod utils;
|
|
||||||
|
|
||||||
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::mesh:::MeshPlugin,
|
|
||||||
bevy::light:::LightPlugin,
|
|
||||||
bevy::camera:::CameraPlugin,
|
|
||||||
bevy::render:::RenderPlugin,
|
|
||||||
bevy::image:::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::gilrs:::GilrsPlugin,
|
|
||||||
bevy::animation:::AnimationPlugin,
|
|
||||||
bevy::gizmos:::GizmoPlugin,
|
|
||||||
bevy::state::app:::StatesPlugin,
|
|
||||||
#[plugin_group]
|
|
||||||
bevy::picking:::DefaultPickingPlugins,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut app = App::new();
|
|
||||||
|
|
||||||
app.register_type::<DebugVisuals>()
|
|
||||||
.register_type::<TransformInterpolation>();
|
|
||||||
app.insert_resource(DebugVisuals {
|
|
||||||
unlit: false,
|
|
||||||
tonemapping: Tonemapping::None,
|
|
||||||
exposure: 1.,
|
|
||||||
shadows: true,
|
|
||||||
cam_follow: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
app.add_plugins(DefaultPlugins.set(bevy::log::LogPlugin {
|
|
||||||
filter: "info,lightyear_replication=off".into(),
|
|
||||||
level: bevy::log::Level::INFO,
|
|
||||||
// provide custom log layer to receive logging events
|
|
||||||
..default()
|
|
||||||
}));
|
|
||||||
|
|
||||||
app.add_plugins(PhysicsPlugins::default());
|
|
||||||
app.add_plugins(Sprite3dPlugin);
|
|
||||||
app.add_plugins(TrenchBroomPlugins(
|
|
||||||
TrenchBroomConfig::new("hedz").icon(None),
|
|
||||||
));
|
|
||||||
app.add_plugins(TrenchBroomPhysicsPlugin::new(AvianPhysicsBackend));
|
|
||||||
app.add_plugins(RonAssetPlugin::<HeadDatabaseAsset>::new(&["headsdb.ron"]));
|
|
||||||
|
|
||||||
app.add_plugins(shared::abilities::plugin);
|
|
||||||
app.add_plugins(shared::ai::plugin);
|
|
||||||
app.add_plugins(shared::aim::plugin);
|
|
||||||
app.add_plugins(shared::animation::plugin);
|
|
||||||
app.add_plugins(shared::backpack::plugin);
|
|
||||||
app.add_plugins(shared::camera::plugin);
|
|
||||||
app.add_plugins(shared::cash::plugin);
|
|
||||||
app.add_plugins(shared::cash_heal::plugin);
|
|
||||||
app.add_plugins(shared::character::plugin);
|
|
||||||
app.add_plugins(shared::control::plugin);
|
|
||||||
app.add_plugins(shared::cutscene::plugin);
|
|
||||||
app.add_plugins(shared::gates::plugin);
|
|
||||||
app.add_plugins(shared::head_drop::plugin);
|
|
||||||
app.add_plugins(shared::heads::plugin);
|
|
||||||
app.add_plugins(shared::hitpoints::plugin);
|
|
||||||
app.add_plugins(shared::keys::plugin);
|
|
||||||
app.add_plugins(shared::loading_assets::LoadingPlugin);
|
|
||||||
app.add_plugins(shared::loading_map::plugin);
|
|
||||||
app.add_plugins(shared::movables::plugin);
|
|
||||||
app.add_plugins(shared::npc::plugin);
|
|
||||||
app.add_plugins(shared::platforms::plugin);
|
|
||||||
app.add_plugins(shared::player::plugin);
|
|
||||||
app.add_plugins(shared::steam::plugin);
|
|
||||||
app.add_plugins(shared::tb_entities::plugin);
|
|
||||||
app.add_plugins(shared::tick::plugin);
|
|
||||||
app.add_plugins(shared::utils::auto_rotate::plugin);
|
|
||||||
app.add_plugins(shared::utils::billboards::plugin);
|
|
||||||
app.add_plugins(shared::utils::explosions::plugin);
|
|
||||||
app.add_plugins(shared::utils::sprite_3d_animation::plugin);
|
|
||||||
app.add_plugins(shared::utils::squish_animation::plugin);
|
|
||||||
app.add_plugins(shared::utils::trail::plugin);
|
|
||||||
app.add_plugins(shared::utils::plugin);
|
|
||||||
app.add_plugins(shared::water::plugin);
|
|
||||||
|
|
||||||
// Networking
|
|
||||||
// The client/server plugin must go before the protocol, or else `ProtocolHasher` will not be available.
|
|
||||||
app.add_plugins(server::plugin);
|
|
||||||
app.add_plugins(shared::protocol::plugin);
|
|
||||||
|
|
||||||
app.add_plugins(config::plugin);
|
|
||||||
app.add_plugins(head_drop::plugin);
|
|
||||||
app.add_plugins(platforms::plugin);
|
|
||||||
app.add_plugins(player::plugin);
|
|
||||||
app.add_plugins(tb_entities::plugin);
|
|
||||||
app.add_plugins(utils::plugin);
|
|
||||||
|
|
||||||
app.init_state::<GameState>();
|
|
||||||
|
|
||||||
app.add_systems(PostStartup, setup_panic_handler);
|
|
||||||
|
|
||||||
app.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_panic_handler() {
|
|
||||||
_ = std::panic::take_hook();
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
use bevy::prelude::*;
|
|
||||||
use bevy_trenchbroom::prelude::Target;
|
|
||||||
use shared::{
|
|
||||||
GameState,
|
|
||||||
platforms::ActivePlatform,
|
|
||||||
tb_entities::{Platform, PlatformTarget},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
|
||||||
app.add_systems(OnEnter(GameState::Playing), init);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn init(
|
|
||||||
mut commands: Commands,
|
|
||||||
uninit_platforms: Query<
|
|
||||||
(Entity, &Target, &Transform),
|
|
||||||
(Without<ActivePlatform>, With<Platform>),
|
|
||||||
>,
|
|
||||||
targets: Query<(&PlatformTarget, &Transform)>,
|
|
||||||
) {
|
|
||||||
for (e, target, transform) in uninit_platforms.iter() {
|
|
||||||
let Some(target) = targets
|
|
||||||
.iter()
|
|
||||||
.find(|(t, _)| t.targetname == target.target.clone().unwrap_or_default())
|
|
||||||
.map(|(_, t)| t.translation)
|
|
||||||
else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let platform = ActivePlatform {
|
|
||||||
start: transform.translation,
|
|
||||||
target,
|
|
||||||
};
|
|
||||||
|
|
||||||
commands.entity(e).insert(platform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
use bevy::prelude::*;
|
|
||||||
use bevy_replicon::prelude::{Replicated, SendMode, ServerTriggerExt, ToClients};
|
|
||||||
use shared::{
|
|
||||||
backpack::{Backpack, backpack_ui::BackpackUiState},
|
|
||||||
camera::{CameraArmRotation, CameraTarget},
|
|
||||||
cash::CashInventory,
|
|
||||||
character::AnimatedCharacter,
|
|
||||||
control::{Inputs, controller_common::PlayerCharacterController},
|
|
||||||
global_observer,
|
|
||||||
head::ActiveHead,
|
|
||||||
head_drop::HeadDrops,
|
|
||||||
heads::{ActiveHeads, HeadChanged, HeadState, heads_ui::UiActiveHeads},
|
|
||||||
heads_database::HeadsDatabase,
|
|
||||||
hitpoints::{Hitpoints, Kill},
|
|
||||||
npc::SpawnCharacter,
|
|
||||||
player::{Player, PlayerBodyMesh},
|
|
||||||
protocol::{OwnedByClient, PlaySound, PlayerId, events::ClientHeadChanged},
|
|
||||||
tb_entities::SpawnPoint,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
|
||||||
global_observer!(app, on_update_head_mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spawn(
|
|
||||||
mut commands: Commands,
|
|
||||||
owner: Entity,
|
|
||||||
query: Query<&Transform, With<SpawnPoint>>,
|
|
||||||
heads_db: Res<HeadsDatabase>,
|
|
||||||
) -> Option<Entity> {
|
|
||||||
let spawn = query.iter().next()?;
|
|
||||||
|
|
||||||
let transform = Transform::from_translation(spawn.translation + Vec3::new(0., 3., 0.));
|
|
||||||
|
|
||||||
let id = commands
|
|
||||||
.spawn((
|
|
||||||
(
|
|
||||||
Name::from("player"),
|
|
||||||
Player,
|
|
||||||
ActiveHead(0),
|
|
||||||
ActiveHeads::new([
|
|
||||||
Some(HeadState::new(0, heads_db.as_ref())),
|
|
||||||
Some(HeadState::new(3, heads_db.as_ref())),
|
|
||||||
Some(HeadState::new(6, heads_db.as_ref())),
|
|
||||||
Some(HeadState::new(10, heads_db.as_ref())),
|
|
||||||
Some(HeadState::new(9, heads_db.as_ref())),
|
|
||||||
]),
|
|
||||||
Hitpoints::new(100),
|
|
||||||
CashInventory::default(),
|
|
||||||
CameraTarget,
|
|
||||||
transform,
|
|
||||||
Visibility::default(),
|
|
||||||
PlayerCharacterController,
|
|
||||||
PlayerId { id: 0 },
|
|
||||||
),
|
|
||||||
Backpack::default(),
|
|
||||||
BackpackUiState::default(),
|
|
||||||
UiActiveHeads::default(),
|
|
||||||
Inputs::default(),
|
|
||||||
Replicated,
|
|
||||||
OwnedByClient(owner),
|
|
||||||
))
|
|
||||||
.with_children(|c| {
|
|
||||||
c.spawn((
|
|
||||||
Name::new("player-rig"),
|
|
||||||
PlayerBodyMesh,
|
|
||||||
CameraArmRotation,
|
|
||||||
Replicated,
|
|
||||||
))
|
|
||||||
.with_child((
|
|
||||||
Name::new("player-animated-character"),
|
|
||||||
AnimatedCharacter::new(0),
|
|
||||||
Replicated,
|
|
||||||
));
|
|
||||||
})
|
|
||||||
.observe(on_kill)
|
|
||||||
.id();
|
|
||||||
|
|
||||||
commands.server_trigger(ToClients {
|
|
||||||
mode: SendMode::Broadcast,
|
|
||||||
message: PlaySound::Head("angry demonstrator".to_string()),
|
|
||||||
});
|
|
||||||
commands.trigger(SpawnCharacter(transform.translation));
|
|
||||||
|
|
||||||
Some(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_kill(
|
|
||||||
trigger: On<Kill>,
|
|
||||||
mut commands: Commands,
|
|
||||||
mut query: Query<(&Transform, &ActiveHead, &mut ActiveHeads, &mut Hitpoints)>,
|
|
||||||
) {
|
|
||||||
let Ok((transform, active, mut heads, mut hp)) = query.get_mut(trigger.event().entity) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
commands.trigger(HeadDrops::new(transform.translation, active.0));
|
|
||||||
|
|
||||||
if let Some(new_head) = heads.loose_current() {
|
|
||||||
hp.set_health(heads.current().unwrap().health);
|
|
||||||
|
|
||||||
commands.trigger(HeadChanged(new_head));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_update_head_mesh(
|
|
||||||
trigger: On<HeadChanged>,
|
|
||||||
mut commands: Commands,
|
|
||||||
mesh_children: Single<&Children, With<PlayerBodyMesh>>,
|
|
||||||
animated_characters: Query<&AnimatedCharacter>,
|
|
||||||
mut player: Single<&mut ActiveHead, With<Player>>,
|
|
||||||
) -> Result {
|
|
||||||
let animated_char = mesh_children
|
|
||||||
.iter()
|
|
||||||
.find(|child| animated_characters.contains(*child))
|
|
||||||
.ok_or("tried to update head mesh before AnimatedCharacter was readded")?;
|
|
||||||
|
|
||||||
player.0 = trigger.0;
|
|
||||||
|
|
||||||
commands
|
|
||||||
.entity(animated_char)
|
|
||||||
.insert(AnimatedCharacter::new(trigger.0));
|
|
||||||
|
|
||||||
commands.server_trigger(ToClients {
|
|
||||||
mode: SendMode::Broadcast,
|
|
||||||
message: ClientHeadChanged(trigger.0 as u64),
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
use bevy::prelude::*;
|
|
||||||
use bevy_replicon::prelude::{ClientId, ConnectedClient, SendMode, ToClients};
|
|
||||||
use shared::{
|
|
||||||
GameState, global_observer,
|
|
||||||
protocol::{TbMapEntityId, messages::DespawnTbMapEntity},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
|
||||||
app.register_type::<DespawnedTbEntityCache>();
|
|
||||||
|
|
||||||
app.init_resource::<DespawnedTbEntityCache>();
|
|
||||||
|
|
||||||
app.add_systems(
|
|
||||||
OnEnter(GameState::MapLoading),
|
|
||||||
|mut cache: ResMut<DespawnedTbEntityCache>| cache.0.clear(),
|
|
||||||
);
|
|
||||||
|
|
||||||
global_observer!(app, add_despawned_entities_to_cache);
|
|
||||||
global_observer!(app, send_new_client_despawned_cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_despawned_entities_to_cache(
|
|
||||||
trigger: On<Remove, TbMapEntityId>,
|
|
||||||
id: Query<&TbMapEntityId>,
|
|
||||||
mut cache: ResMut<DespawnedTbEntityCache>,
|
|
||||||
) {
|
|
||||||
cache.0.push(id.get(trigger.event().entity).unwrap().id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Resource, Reflect)]
|
|
||||||
#[reflect(Resource)]
|
|
||||||
pub struct DespawnedTbEntityCache(pub Vec<u64>);
|
|
||||||
|
|
||||||
fn send_new_client_despawned_cache(
|
|
||||||
on: On<Add, ConnectedClient>,
|
|
||||||
cache: Res<DespawnedTbEntityCache>,
|
|
||||||
mut send: MessageWriter<ToClients<DespawnTbMapEntity>>,
|
|
||||||
) {
|
|
||||||
for &id in cache.0.iter() {
|
|
||||||
send.write(ToClients {
|
|
||||||
mode: SendMode::Direct(ClientId::Client(on.entity)),
|
|
||||||
message: DespawnTbMapEntity(id),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
use bevy::{
|
|
||||||
ecs::{archetype::Archetypes, component::Components, entity::Entities},
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
use shared::global_observer;
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
|
||||||
global_observer!(app, report_entity_components);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Event)]
|
|
||||||
pub struct ReportEntityComponents(pub Entity);
|
|
||||||
|
|
||||||
fn report_entity_components(
|
|
||||||
trigger: On<ReportEntityComponents>,
|
|
||||||
entities: &Entities,
|
|
||||||
components: &Components,
|
|
||||||
archetypes: &Archetypes,
|
|
||||||
) {
|
|
||||||
let Some(location) = entities.get(trigger.event().0) else {
|
|
||||||
warn!("failed to report entity components; had no location");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Some(archetype) = archetypes.get(location.archetype_id) else {
|
|
||||||
warn!("failed to report entity components; had no archetype");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut output = format!("Entity {:?} Components: ", trigger.event().0);
|
|
||||||
for &component in archetype.components() {
|
|
||||||
if let Some(name) = components.get_name(component) {
|
|
||||||
output.push_str(&format!("{name}, "));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("{}; Caller: {}", output, trigger.caller());
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "shared"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2024"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
client = []
|
|
||||||
server = []
|
|
||||||
dbg = []
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
avian3d = { workspace = true }
|
|
||||||
bevy = { workspace = true, default-features = false }
|
|
||||||
bevy-inspector-egui = { workspace = true, optional = true }
|
|
||||||
bevy-steamworks = { workspace = true }
|
|
||||||
bevy_asset_loader = { workspace = true }
|
|
||||||
bevy_ballistic = { workspace = true }
|
|
||||||
bevy_common_assets = { workspace = true }
|
|
||||||
bevy_debug_log = { workspace = true }
|
|
||||||
bevy_replicon = { workspace = true }
|
|
||||||
bevy_sprite3d = { workspace = true }
|
|
||||||
bevy_trenchbroom = { workspace = true }
|
|
||||||
happy_feet = { workspace = true }
|
|
||||||
nil = { workspace = true }
|
|
||||||
rand = { workspace = true }
|
|
||||||
ron = { workspace = true }
|
|
||||||
serde = { workspace = true }
|
|
||||||
steamworks = { workspace = true }
|
|
||||||
|
|
||||||
[lints.clippy]
|
|
||||||
too_many_arguments = "allow"
|
|
||||||
type_complexity = "allow"
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
use crate::{GameState, physics_layers::GameLayer, tb_entities::SecretHead};
|
|
||||||
use avian3d::prelude::*;
|
|
||||||
use bevy::prelude::*;
|
|
||||||
|
|
||||||
#[derive(Event, Reflect)]
|
|
||||||
pub struct HeadDrops {
|
|
||||||
pub pos: Vec3,
|
|
||||||
pub head_id: usize,
|
|
||||||
pub impulse: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HeadDrops {
|
|
||||||
pub fn new(pos: Vec3, head_id: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
pos,
|
|
||||||
head_id,
|
|
||||||
impulse: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_static(pos: Vec3, head_id: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
pos,
|
|
||||||
head_id,
|
|
||||||
impulse: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component, Reflect)]
|
|
||||||
#[reflect(Component)]
|
|
||||||
pub struct HeadDrop {
|
|
||||||
pub head_id: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component, Reflect)]
|
|
||||||
#[reflect(Component)]
|
|
||||||
pub struct HeadDropEnableTime(pub f32);
|
|
||||||
|
|
||||||
#[derive(Component, Reflect)]
|
|
||||||
#[reflect(Component)]
|
|
||||||
pub struct SecretHeadMarker;
|
|
||||||
|
|
||||||
#[derive(EntityEvent, Reflect)]
|
|
||||||
pub struct HeadCollected {
|
|
||||||
pub entity: Entity,
|
|
||||||
pub head: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
|
||||||
app.register_type::<HeadDrop>();
|
|
||||||
app.register_type::<HeadDropEnableTime>();
|
|
||||||
app.register_type::<SecretHeadMarker>();
|
|
||||||
|
|
||||||
app.add_systems(
|
|
||||||
Update,
|
|
||||||
enable_collectible.run_if(in_state(GameState::Playing)),
|
|
||||||
);
|
|
||||||
|
|
||||||
app.add_systems(OnEnter(GameState::Playing), spawn);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spawn(mut commands: Commands, query: Query<(Entity, &GlobalTransform, &SecretHead)>) {
|
|
||||||
for (e, t, head) in query {
|
|
||||||
commands.trigger(HeadDrops::new_static(
|
|
||||||
t.translation() + Vec3::new(0., 2., 0.),
|
|
||||||
head.head_id,
|
|
||||||
));
|
|
||||||
|
|
||||||
commands.entity(e).despawn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enable_collectible(
|
|
||||||
mut commands: Commands,
|
|
||||||
query: Query<(Entity, &HeadDropEnableTime)>,
|
|
||||||
time: Res<Time>,
|
|
||||||
) {
|
|
||||||
let now = time.elapsed_secs();
|
|
||||||
for (e, enable_time) in query.iter() {
|
|
||||||
if now > enable_time.0 {
|
|
||||||
commands
|
|
||||||
.entity(e)
|
|
||||||
.insert(CollisionLayers::new(
|
|
||||||
LayerMask(GameLayer::CollectibleSensors.to_bits()),
|
|
||||||
LayerMask::ALL,
|
|
||||||
))
|
|
||||||
.remove::<HeadDropEnableTime>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
pub mod abilities;
|
|
||||||
pub mod ai;
|
|
||||||
pub mod aim;
|
|
||||||
pub mod animation;
|
|
||||||
pub mod backpack;
|
|
||||||
pub mod camera;
|
|
||||||
pub mod cash;
|
|
||||||
pub mod cash_heal;
|
|
||||||
pub mod character;
|
|
||||||
pub mod control;
|
|
||||||
pub mod cutscene;
|
|
||||||
pub mod gates;
|
|
||||||
pub mod head;
|
|
||||||
pub mod head_drop;
|
|
||||||
pub mod heads;
|
|
||||||
pub mod heads_database;
|
|
||||||
pub mod hitpoints;
|
|
||||||
pub mod keys;
|
|
||||||
pub mod loading_assets;
|
|
||||||
pub mod loading_map;
|
|
||||||
pub mod movables;
|
|
||||||
pub mod npc;
|
|
||||||
pub mod physics_layers;
|
|
||||||
pub mod platforms;
|
|
||||||
pub mod player;
|
|
||||||
pub mod protocol;
|
|
||||||
pub mod steam;
|
|
||||||
pub mod tb_entities;
|
|
||||||
pub mod tick;
|
|
||||||
pub mod utils;
|
|
||||||
pub mod water;
|
|
||||||
|
|
||||||
use bevy::{core_pipeline::tonemapping::Tonemapping, prelude::*};
|
|
||||||
use utils::{billboards, squish_animation};
|
|
||||||
|
|
||||||
pub const HEDZ_GREEN: Srgba = Srgba::rgb(0.0, 1.0, 0.0);
|
|
||||||
pub const HEDZ_PURPLE: Srgba = Srgba::rgb(91. / 256., 4. / 256., 138. / 256.);
|
|
||||||
|
|
||||||
#[derive(Resource, Reflect, Debug)]
|
|
||||||
#[reflect(Resource)]
|
|
||||||
pub struct DebugVisuals {
|
|
||||||
pub unlit: bool,
|
|
||||||
pub tonemapping: Tonemapping,
|
|
||||||
pub exposure: f32,
|
|
||||||
pub shadows: bool,
|
|
||||||
pub cam_follow: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(States, Default, Clone, Copy, Eq, PartialEq, Debug, Hash)]
|
|
||||||
pub enum GameState {
|
|
||||||
#[default]
|
|
||||||
AssetLoading,
|
|
||||||
MapLoading,
|
|
||||||
Connecting,
|
|
||||||
Playing,
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
GameState,
|
|
||||||
abilities::PlayerTriggerState,
|
|
||||||
cash::{Cash, CashCollectEvent},
|
|
||||||
character::HedzCharacter,
|
|
||||||
protocol::PlayerId,
|
|
||||||
};
|
|
||||||
use crate::{backpack::backpack_ui::BackpackUiState, control::LocalInputs};
|
|
||||||
use avian3d::prelude::*;
|
|
||||||
use bevy::{
|
|
||||||
input::common_conditions::input_just_pressed,
|
|
||||||
prelude::*,
|
|
||||||
window::{CursorGrabMode, CursorOptions, PrimaryWindow},
|
|
||||||
};
|
|
||||||
use happy_feet::debug::DebugInput;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Component, Default, Serialize, Deserialize, PartialEq)]
|
|
||||||
#[require(HedzCharacter, DebugInput = DebugInput, PlayerTriggerState)]
|
|
||||||
pub struct Player;
|
|
||||||
|
|
||||||
#[derive(Component, Debug, Reflect)]
|
|
||||||
#[reflect(Component)]
|
|
||||||
#[require(LocalInputs, BackpackUiState)]
|
|
||||||
pub struct LocalPlayer;
|
|
||||||
|
|
||||||
#[derive(Component, Default, Serialize, Deserialize, PartialEq)]
|
|
||||||
#[require(Transform, Visibility)]
|
|
||||||
pub struct PlayerBodyMesh;
|
|
||||||
|
|
||||||
/// Server-side only; inserted on each `client` (not the controller) to track player ids.
|
|
||||||
#[derive(Component, Clone, Copy)]
|
|
||||||
pub struct ClientPlayerId(pub PlayerId);
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
|
||||||
app.add_systems(
|
|
||||||
OnEnter(GameState::Playing),
|
|
||||||
(toggle_cursor_system, cursor_recenter),
|
|
||||||
);
|
|
||||||
app.add_systems(
|
|
||||||
Update,
|
|
||||||
(
|
|
||||||
collect_cash,
|
|
||||||
setup_animations_marker_for_player,
|
|
||||||
toggle_cursor_system.run_if(input_just_pressed(KeyCode::Escape)),
|
|
||||||
)
|
|
||||||
.run_if(in_state(GameState::Playing)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cursor_recenter(q_windows: Single<&mut Window, With<PrimaryWindow>>) {
|
|
||||||
let mut primary_window = q_windows;
|
|
||||||
let center = Vec2::new(
|
|
||||||
primary_window.resolution.width() / 2.,
|
|
||||||
primary_window.resolution.height() / 2.,
|
|
||||||
);
|
|
||||||
primary_window.set_cursor_position(Some(center));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn toggle_grab_cursor(options: &mut CursorOptions) {
|
|
||||||
match options.grab_mode {
|
|
||||||
CursorGrabMode::None => {
|
|
||||||
options.grab_mode = CursorGrabMode::Confined;
|
|
||||||
options.visible = false;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
options.grab_mode = CursorGrabMode::None;
|
|
||||||
options.visible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn toggle_cursor_system(mut window: Single<&mut CursorOptions, With<PrimaryWindow>>) {
|
|
||||||
toggle_grab_cursor(&mut window);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect_cash(
|
|
||||||
mut commands: Commands,
|
|
||||||
mut collision_message_reader: MessageReader<CollisionStart>,
|
|
||||||
query_player: Query<&Player>,
|
|
||||||
query_cash: Query<&Cash>,
|
|
||||||
) {
|
|
||||||
for CollisionStart {
|
|
||||||
collider1: e1,
|
|
||||||
collider2: e2,
|
|
||||||
..
|
|
||||||
} in collision_message_reader.read()
|
|
||||||
{
|
|
||||||
let collect = if query_player.contains(*e1) && query_cash.contains(*e2) {
|
|
||||||
Some(*e2)
|
|
||||||
} else if query_player.contains(*e2) && query_cash.contains(*e1) {
|
|
||||||
Some(*e1)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(cash) = collect {
|
|
||||||
commands.trigger(CashCollectEvent);
|
|
||||||
commands.entity(cash).despawn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_animations_marker_for_player(
|
|
||||||
mut commands: Commands,
|
|
||||||
animation_handles: Query<Entity, Added<AnimationGraphHandle>>,
|
|
||||||
child_of: Query<&ChildOf>,
|
|
||||||
player_rig: Query<&ChildOf, With<PlayerBodyMesh>>,
|
|
||||||
) {
|
|
||||||
for animation_rig in animation_handles.iter() {
|
|
||||||
for ancestor in child_of.iter_ancestors(animation_rig) {
|
|
||||||
if let Ok(rig_child_of) = player_rig.get(ancestor) {
|
|
||||||
commands.entity(rig_child_of.parent());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
use bevy::prelude::*;
|
|
||||||
use bevy_steamworks::SteamworksPlugin;
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
|
||||||
let app_id = 1603000;
|
|
||||||
|
|
||||||
// should only be done in production builds
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
if steamworks::restart_app_if_necessary(app_id.into()) {
|
|
||||||
info!("Restarting app via steam");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("steam app init: {app_id}");
|
|
||||||
|
|
||||||
match SteamworksPlugin::init_app(app_id) {
|
|
||||||
Ok(plugin) => {
|
|
||||||
info!("steam app init done");
|
|
||||||
app.add_plugins(plugin);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
warn!("steam init error: {e:?}");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#[macro_export]
|
|
||||||
macro_rules! global_observer {
|
|
||||||
($app:expr, $($system:tt)*) => {{
|
|
||||||
$app.world_mut()
|
|
||||||
.add_observer($($system)*)
|
|
||||||
.insert(global_observer!(@name $($system)*))
|
|
||||||
}};
|
|
||||||
|
|
||||||
(@name $system:ident ::< $($param:ident),+ $(,)? >) => {{
|
|
||||||
let mut name = String::new();
|
|
||||||
name.push_str(stringify!($system));
|
|
||||||
name.push_str("::<");
|
|
||||||
$(
|
|
||||||
name.push_str(std::any::type_name::<$param>());
|
|
||||||
)+
|
|
||||||
name.push_str(">");
|
|
||||||
Name::new(name)
|
|
||||||
}};
|
|
||||||
|
|
||||||
(@name $system:expr) => {
|
|
||||||
Name::new(stringify!($system))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use global_observer;
|
|
||||||
16
justfile
16
justfile
@@ -5,28 +5,20 @@ 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"
|
client_args := "--bin hedz_reloaded"
|
||||||
server_args := "--bin server --no-default-features --features shared/server"
|
server_args := "--bin hedz_reloaded_server --no-default-features"
|
||||||
|
|
||||||
run *args:
|
run *args:
|
||||||
cargo b {{server_args}}
|
|
||||||
RUST_BACKTRACE=1 cargo r {{client_args}} -- {{args}}
|
|
||||||
|
|
||||||
client *args:
|
|
||||||
RUST_BACKTRACE=1 cargo r {{client_args}} -- {{args}}
|
RUST_BACKTRACE=1 cargo r {{client_args}} -- {{args}}
|
||||||
|
|
||||||
server:
|
server:
|
||||||
RUST_BACKTRACE=1 cargo r {{server_args}}
|
RUST_BACKTRACE=1 cargo r {{server_args}}
|
||||||
|
|
||||||
dbg *args:
|
dbg *args:
|
||||||
cargo b {{server_args}},dbg
|
RUST_BACKTRACE=1 cargo r {{client_args}} --features dbg -- {{args}}
|
||||||
RUST_BACKTRACE=1 cargo r {{client_args}},dbg -- {{args}}
|
|
||||||
|
|
||||||
dbg-client *args:
|
|
||||||
RUST_BACKTRACE=1 cargo r {{client_args}},dbg -- {{args}}
|
|
||||||
|
|
||||||
dbg-server:
|
dbg-server:
|
||||||
RUST_BACKTRACE=1 cargo r {{server_args}},dbg
|
RUST_BACKTRACE=1 cargo r {{server_args}} --features dbg
|
||||||
|
|
||||||
sort:
|
sort:
|
||||||
cargo sort --check --workspace
|
cargo sort --check --workspace
|
||||||
|
|||||||
Reference in New Issue
Block a user