diff --git a/server/.gitkeep b/server/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/server/Cargo.lock b/server/Cargo.lock new file mode 100644 index 000000000..4bba5b658 --- /dev/null +++ b/server/Cargo.lock @@ -0,0 +1,1301 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "assert_type_match" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f548ad2c4031f2902e3edc1f29c29e835829437de49562d8eb5dc5584d3a1043" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bevy_app" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2271a0123a7cc355c3fe98754360c75aa84b29f2a6b1a9f8c00aac427570d174" +dependencies = [ + "bevy_derive", + "bevy_ecs", + "bevy_platform", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "cfg-if", + "ctrlc", + "downcast-rs", + "log", + "thiserror", + "variadics_please", +] + +[[package]] +name = "bevy_derive" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70b6a05c31f54c83d681f1b8699bbaf581f06b25a40c9a6bb815625f731f5ba9" +dependencies = [ + "bevy_macro_utils", + "quote", + "syn", +] + +[[package]] +name = "bevy_ecs" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24637a7c8643cab493f4085cda6bde4895f0e0816699c59006f18819da2ca0b8" +dependencies = [ + "arrayvec", + "bevy_ecs_macros", + "bevy_platform", + "bevy_ptr", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "bitflags", + "bumpalo", + "concurrent-queue", + "derive_more", + "fixedbitset", + "indexmap", + "log", + "nonmax", + "serde", + "slotmap", + "smallvec", + "thiserror", + "variadics_please", +] + +[[package]] +name = "bevy_ecs_macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eb14c18ca71e11c69fbae873c2db129064efac6d52e48d0127d37bfba1acfa8" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bevy_macro_utils" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7272fca0bf30d8ca2571a803598856104b63e5c596d52850f811ed37c5e1e3" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "toml_edit", +] + +[[package]] +name = "bevy_platform" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b29ea749a8e85f98186ab662f607b885b97c804bb14cdb0cdf838164496d474" +dependencies = [ + "critical-section", + "foldhash", + "futures-channel", + "hashbrown", + "js-sys", + "portable-atomic", + "portable-atomic-util", + "serde", + "spin", + "wasm-bindgen", + "wasm-bindgen-futures", +] + +[[package]] +name = "bevy_ptr" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f98cbc6d34bbdb58240b72ed1731931b4991a893b3a3238bb7c42ae054aa676" + +[[package]] +name = "bevy_reflect" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2a977e2b8dba65b6e9c11039c5f9ef108be428f036b3d1cac13ad86ec59f9c" +dependencies = [ + "assert_type_match", + "bevy_platform", + "bevy_ptr", + "bevy_reflect_derive", + "bevy_utils", + "derive_more", + "disqualified", + "downcast-rs", + "erased-serde", + "foldhash", + "glam", + "indexmap", + "serde", + "smallvec", + "smol_str", + "thiserror", + "uuid", + "variadics_please", + "wgpu-types", +] + +[[package]] +name = "bevy_reflect_derive" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "067af30072b1611fda1a577f1cb678b8ea2c9226133068be808dd49aac30cef0" +dependencies = [ + "bevy_macro_utils", + "indexmap", + "proc-macro2", + "quote", + "syn", + "uuid", +] + +[[package]] +name = "bevy_tasks" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990ffedd374dd2c4fe8f0fd4bcefd5617d1ee59164b6c3fcc356a69b48e26e8e" +dependencies = [ + "async-channel", + "async-executor", + "async-task", + "atomic-waker", + "bevy_platform", + "crossbeam-queue", + "derive_more", + "futures-lite", + "heapless", + "pin-project", +] + +[[package]] +name = "bevy_utils" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e258c44d869f9c41ac0f88a16815c67f2569eb9fff4716828a40273d127b6f84" +dependencies = [ + "bevy_platform", + "disqualified", + "thread_local", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +dependencies = [ + "serde_core", +] + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", + "portable-atomic", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "ctrlc" +version = "3.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" +dependencies = [ + "dispatch2", + "nix", + "windows-sys", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", + "unicode-xid", +] + +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "disqualified" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9c272297e804878a2a4b707cfcfc6d2328b5bb936944613b4fdf2b9269afdfd" + +[[package]] +name = "downcast-rs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "glam" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" +dependencies = [ + "serde_core", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "equivalent", + "serde", + "serde_core", +] + +[[package]] +name = "heapless" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" +dependencies = [ + "hash32", + "portable-atomic", + "stable_deref_trait", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "nix" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225e7cfe711e0ba79a68baeddb2982723e4235247aefce1482f2f16c27865b66" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nonmax" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "objc2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "rmp" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "rmp-serde" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155" +dependencies = [ + "rmp", + "serde", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "settled-reach-server" +version = "0.1.0" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bincode", + "rand", + "rand_chacha", + "rmp-serde", + "serde", + "thiserror", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.7+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1" +dependencies = [ + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "unicode-ident" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "uuid" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +dependencies = [ + "getrandom", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "variadics_please" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wgpu-types" +version = "27.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afdcf84c395990db737f2dd91628706cb31e86d72e53482320d368e52b5da5eb" +dependencies = [ + "bitflags", + "bytemuck", + "js-sys", + "log", + "serde", + "thiserror", + "web-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "zerocopy" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/server/Cargo.toml b/server/Cargo.toml new file mode 100644 index 000000000..9b21c6d68 --- /dev/null +++ b/server/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "settled-reach-server" +version = "0.1.0" +edition = "2024" + +[dependencies] +bevy_ecs = "0.18" +bevy_app = "0.18" +serde = { version = "1", features = ["derive"] } +rmp-serde = "1" +bincode = "1" +rand = "0.9" +rand_chacha = "0.9" +thiserror = "2" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/server/src/bridge/mod.rs b/server/src/bridge/mod.rs new file mode 100644 index 000000000..50619a4b1 --- /dev/null +++ b/server/src/bridge/mod.rs @@ -0,0 +1,40 @@ +// Bridge module - Client-server communication +// Implements D-020 subprocess/IPC architecture +// MessagePack serialization for Rust<->Godot communication + +use bevy_app::prelude::*; + +pub mod types; +pub use types::*; + +/// Error type for bridge operations +#[derive(Debug, thiserror::Error)] +pub enum BridgeError { + #[error("serialization error: {0}")] + Serialization(#[from] rmp_serde::encode::Error), + #[error("deserialization error: {0}")] + Deserialization(#[from] rmp_serde::decode::Error), + #[error("transport error: {0}")] + Transport(String), +} + +/// Abstracts transport layer (D-020) +/// Implemented by LocalBridge (stdio) and future NetworkBridge +pub trait SimBridge: Send + Sync { + /// Send an observer snapshot to the client + fn send_snapshot(&self, snapshot: &ObserverSnapshot) -> Result<(), BridgeError>; + + /// Receive player inputs from the client + fn receive_inputs(&self) -> Result, BridgeError>; +} + +/// Bridge plugin for client-server communication +/// Abstracts transport layer (LocalBridge/NetworkBridge) +pub struct BridgePlugin; + +impl Plugin for BridgePlugin { + fn build(&self, _app: &mut App) { + // Stub implementation - will be populated in phase 2 + tracing::debug!("BridgePlugin initialized"); + } +} diff --git a/server/src/bridge/types.rs b/server/src/bridge/types.rs new file mode 100644 index 000000000..c34466c8f --- /dev/null +++ b/server/src/bridge/types.rs @@ -0,0 +1,56 @@ +// Bridge type definitions +// ObserverSnapshot: data crossing the client-server boundary +// PlayerInput: semantic actions from client + +use serde::{Deserialize, Serialize}; + +/// The ONLY data structure crossing the client-server boundary (D-020) +/// Contains all information visible to the observer at a given tick +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ObserverSnapshot { + /// Simulation tick when this snapshot was produced + pub tick: u64, + /// All entities visible to the observer + pub entities: Vec, +} + +/// A visible entity in the simulation +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct VisibleEntity { + pub entity_id: u64, + pub x: f32, + pub y: f32, + pub z: i32, + pub kind: EntityKind, +} + +/// Category of visible entity +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum EntityKind { + Npc, + Object, + Terrain, +} + +/// Semantic player actions, not raw key events (D-020) +/// Timestamped for deterministic processing +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PlayerInput { + /// Tick when this input was issued + pub tick: u64, + /// The action to perform + pub action: PlayerAction, +} + +/// Player action variants +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum PlayerAction { + MoveNorth, + MoveSouth, + MoveEast, + MoveWest, + Interact, + UsePerceptionMode(String), + Pause, + Unpause, +} diff --git a/server/src/cause_chain.rs b/server/src/cause_chain.rs new file mode 100644 index 000000000..456234cb9 --- /dev/null +++ b/server/src/cause_chain.rs @@ -0,0 +1,72 @@ +// Cause chain tracking system +// Production component for information provenance (D-030) +// Tracks monologue triggers, journal entries, debug causality + +use bevy_ecs::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Component, Debug, Clone, Serialize, Deserialize)] +pub struct CauseChain { + pub causes: Vec, +} + +impl CauseChain { + pub fn new() -> Self { + Self { causes: Vec::new() } + } + pub fn with_cause(mut self, cause: Cause) -> Self { + self.causes.push(cause); + self + } + pub fn push(&mut self, cause: Cause) { + self.causes.push(cause); + } + pub fn latest(&self) -> Option<&Cause> { + self.causes.last() + } +} + +impl Default for CauseChain { + fn default() -> Self { + Self::new() + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Cause { + pub tick: u64, + pub kind: CauseKind, + pub description: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub enum CauseKind { + Observed, + Heard, + Informed, + Inferred, + Background, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn chain_preserves_order() { + let chain = CauseChain::new() + .with_cause(Cause { + tick: 1, + kind: CauseKind::Observed, + description: "Saw NPC".into(), + }) + .with_cause(Cause { + tick: 5, + kind: CauseKind::Inferred, + description: "NPC still inside".into(), + }); + assert_eq!(chain.causes.len(), 2); + assert_eq!(chain.latest().unwrap().tick, 5); + assert_eq!(chain.latest().unwrap().kind, CauseKind::Inferred); + } +} diff --git a/server/src/lib.rs b/server/src/lib.rs new file mode 100644 index 000000000..aa7b2f9ee --- /dev/null +++ b/server/src/lib.rs @@ -0,0 +1,9 @@ +// The Settled Reach - Simulation Server +// Rust/bevy_ecs simulation server for D-010 client-server architecture + +pub mod bridge; +pub mod cause_chain; +pub mod npc; +pub mod perception; +pub mod simulation; +pub mod storyteller; diff --git a/server/src/main.rs b/server/src/main.rs new file mode 100644 index 000000000..b38940cf4 --- /dev/null +++ b/server/src/main.rs @@ -0,0 +1,31 @@ +// The Settled Reach - Simulation Server +// Entry point for standalone simulation binary + +use bevy_app::prelude::*; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; + +use settled_reach_server::bridge::BridgePlugin; +use settled_reach_server::simulation::SimulationPlugin; + +fn main() { + // Initialize tracing subscriber for logging + tracing_subscriber::registry() + .with( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| "settled_reach_server=debug".into()), + ) + .with(tracing_subscriber::fmt::layer()) + .init(); + + tracing::info!("The Settled Reach - Simulation Server starting"); + + // Create the bevy App and add plugins + let mut app = App::new(); + app.add_plugins(SimulationPlugin); + app.add_plugins(BridgePlugin); + + // Run one update cycle + app.update(); + + tracing::info!("Simulation server update complete"); +} diff --git a/server/src/npc/mod.rs b/server/src/npc/mod.rs new file mode 100644 index 000000000..a365c29cc --- /dev/null +++ b/server/src/npc/mod.rs @@ -0,0 +1,76 @@ +// NPC module - NPC entity definitions and AI systems +// Implements D-024: 10-axis NPC model + CombatCapability component +// Background tier state machines for schedule, mood, relationships, job + +use bevy_ecs::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Component, Debug)] +pub struct Npc; + +// 7 essential axes (D-024) +#[derive(Component, Debug, Clone, Serialize, Deserialize)] +pub struct Want { + pub description: String, +} + +#[derive(Component, Debug, Clone, Serialize, Deserialize)] +pub struct Secret { + pub description: String, +} + +#[derive(Component, Debug, Clone, Serialize, Deserialize)] +pub struct Relationships { + pub entries: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Relationship { + pub target_name: String, + pub kind: String, + pub trust_level: f32, +} + +#[derive(Component, Debug, Clone, Serialize, Deserialize)] +pub struct ToleranceThreshold { + pub current_stress: f32, + pub threshold: f32, +} + +#[derive(Component, Debug, Clone, Serialize, Deserialize)] +pub struct DailyRoutine { + pub description: String, +} + +#[derive(Component, Debug, Clone, Serialize, Deserialize)] +pub struct InformationInventory { + pub known_facts: Vec, +} + +#[derive(Component, Debug, Clone, Serialize, Deserialize)] +pub struct Contentment { + pub level: f32, +} + +// 3 supporting axes (D-024) +#[derive(Component, Debug, Clone, Serialize, Deserialize)] +pub struct PersonalityTraits { + pub traits: Vec, +} + +#[derive(Component, Debug, Clone, Serialize, Deserialize)] +pub struct TellSystem { + pub tells: Vec, +} + +#[derive(Component, Debug, Clone, Serialize, Deserialize)] +pub struct SkillSet { + pub skills: Vec, + pub combat_trained: bool, +} + +#[derive(Component, Debug, Clone, Serialize, Deserialize)] +pub struct CombatCapability { + pub weapon_proficiency: f32, + pub combat_style: String, +} diff --git a/server/src/perception/mod.rs b/server/src/perception/mod.rs new file mode 100644 index 000000000..d31253691 --- /dev/null +++ b/server/src/perception/mod.rs @@ -0,0 +1,16 @@ +// Perception module - Information boundary system +// Implements D-010 principle 2: every piece of state is tagged with who knows it +// Generates ObserverSnapshot for client rendering + +use bevy_app::prelude::*; + +/// Perception system plugin +/// Manages information boundaries and observer snapshots +pub struct PerceptionPlugin; + +impl Plugin for PerceptionPlugin { + fn build(&self, _app: &mut App) { + // Stub implementation - will be populated in phase 2 + tracing::debug!("PerceptionPlugin initialized"); + } +} diff --git a/server/src/simulation/input.rs b/server/src/simulation/input.rs new file mode 100644 index 000000000..773992fbc --- /dev/null +++ b/server/src/simulation/input.rs @@ -0,0 +1,77 @@ +// Input processing system +// Timestamped player input events for deterministic simulation (D-010 principle 4) +// PlayerInput: semantic actions (MoveNorth, Interact, UsePerceptionMode) + +use crate::bridge::types::PlayerInput; +use bevy_ecs::prelude::*; +use std::collections::VecDeque; + +/// Queue of pending player inputs, ordered by tick +#[derive(Resource, Debug, Default)] +pub struct InputQueue { + queue: VecDeque, +} + +impl InputQueue { + /// Add a new input to the queue + pub fn push(&mut self, input: PlayerInput) { + self.queue.push_back(input); + } + + /// Drain all inputs for ticks <= the given tick + /// Returns inputs in FIFO order + pub fn drain_for_tick(&mut self, tick: u64) -> Vec { + let mut result = Vec::new(); + while let Some(front) = self.queue.front() { + if front.tick <= tick { + result.push(self.queue.pop_front().unwrap()); + } else { + break; + } + } + result + } + + /// Get the current queue length + pub fn len(&self) -> usize { + self.queue.len() + } + + /// Check if the queue is empty + pub fn is_empty(&self) -> bool { + self.queue.is_empty() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::bridge::types::PlayerAction; + + #[test] + fn drain_returns_inputs_up_to_tick() { + let mut queue = InputQueue::default(); + queue.push(PlayerInput { + tick: 1, + action: PlayerAction::MoveNorth, + }); + queue.push(PlayerInput { + tick: 2, + action: PlayerAction::MoveSouth, + }); + queue.push(PlayerInput { + tick: 5, + action: PlayerAction::Interact, + }); + let inputs = queue.drain_for_tick(3); + assert_eq!(inputs.len(), 2); + assert_eq!(queue.len(), 1); + } + + #[test] + fn drain_empty_queue_returns_empty() { + let mut queue = InputQueue::default(); + let inputs = queue.drain_for_tick(10); + assert!(inputs.is_empty()); + } +} diff --git a/server/src/simulation/mod.rs b/server/src/simulation/mod.rs new file mode 100644 index 000000000..b0cd793f4 --- /dev/null +++ b/server/src/simulation/mod.rs @@ -0,0 +1,25 @@ +// Simulation module - Core simulation plugin and systems +// Implements deterministic tick-based simulation (D-010 principle 4) + +use bevy_app::prelude::*; + +pub mod input; +pub mod rng; +pub mod tier; +pub mod time; + +/// Core simulation plugin +/// Manages simulation time, RNG, input processing, and tier transitions +pub struct SimulationPlugin; + +impl Plugin for SimulationPlugin { + fn build(&self, app: &mut App) { + // Initialize core simulation resources + app.init_resource::() + .insert_resource(rng::SimRng::new(0)) + .init_resource::() + .add_systems(Update, time::advance_tick); + + tracing::debug!("SimulationPlugin initialized"); + } +} diff --git a/server/src/simulation/rng.rs b/server/src/simulation/rng.rs new file mode 100644 index 000000000..c02650a1e --- /dev/null +++ b/server/src/simulation/rng.rs @@ -0,0 +1,54 @@ +// Simulation RNG system +// Injectable ChaCha RNG resource for deterministic replay (D-030) +// Ensures same seed produces same outcomes + +use bevy_ecs::prelude::*; +use rand::SeedableRng; +use rand_chacha::ChaCha20Rng; + +/// Simulation RNG resource +/// ChaCha20 RNG with stored seed for deterministic replay +#[derive(Resource)] +pub struct SimRng { + pub rng: ChaCha20Rng, + seed: u64, +} + +impl SimRng { + /// Create a new SimRng with the given seed + pub fn new(seed: u64) -> Self { + Self { + rng: ChaCha20Rng::seed_from_u64(seed), + seed, + } + } + + /// Get the seed used to initialize this RNG + pub fn seed(&self) -> u64 { + self.seed + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rand::Rng; + + #[test] + fn same_seed_same_sequence() { + let mut rng1 = SimRng::new(42); + let mut rng2 = SimRng::new(42); + let vals1: Vec = (0..100).map(|_| rng1.rng.random()).collect(); + let vals2: Vec = (0..100).map(|_| rng2.rng.random()).collect(); + assert_eq!(vals1, vals2); + } + + #[test] + fn different_seed_different_sequence() { + let mut rng1 = SimRng::new(42); + let mut rng2 = SimRng::new(43); + let val1: u32 = rng1.rng.random(); + let val2: u32 = rng2.rng.random(); + assert_ne!(val1, val2); + } +} diff --git a/server/src/simulation/tier.rs b/server/src/simulation/tier.rs new file mode 100644 index 000000000..f002cf899 --- /dev/null +++ b/server/src/simulation/tier.rs @@ -0,0 +1,58 @@ +// Simulation tier system +// Implements D-026: Active/Background/State-saved/Ungenerated tiers +// Timestamp-based LRU eviction for simulation space management + +use bevy_ecs::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum SimulationTier { + Active, + Background, + StateSaved, + Ungenerated, +} + +#[derive(Component, Debug, Clone)] +pub struct LastInteraction { + pub tick: u64, +} + +#[derive(Component, Debug, Clone)] +pub struct ScopeTag { + pub tags: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum ScopeKind { + Neighborhood, + ActiveQuest, + Colleague, + KnownContact, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn tier_can_be_added_and_queried() { + let mut world = bevy_ecs::world::World::new(); + let entity = world.spawn(SimulationTier::Active).id(); + assert_eq!( + *world.get::(entity).unwrap(), + SimulationTier::Active + ); + } + + #[test] + fn tier_can_transition() { + let mut world = bevy_ecs::world::World::new(); + let entity = world.spawn(SimulationTier::Active).id(); + world.entity_mut(entity).insert(SimulationTier::Background); + assert_eq!( + *world.get::(entity).unwrap(), + SimulationTier::Background + ); + } +} diff --git a/server/src/simulation/time.rs b/server/src/simulation/time.rs new file mode 100644 index 000000000..29b37d0f7 --- /dev/null +++ b/server/src/simulation/time.rs @@ -0,0 +1,117 @@ +// Simulation time system +// Implements D-031: 10 ticks = 1 game-minute, 4 day phases +// Injectable time resource for deterministic replay (D-030) + +use bevy_ecs::prelude::*; + +pub const TICKS_PER_GAME_MINUTE: u64 = 10; +pub const MINUTES_PER_PHASE: u64 = 360; +pub const MINUTES_PER_DAY: u64 = 1440; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum DayPhase { + Morning, + Afternoon, + Evening, + Night, +} + +/// Simulation time resource +/// Tracks current tick and pause state for deterministic simulation +#[derive(Resource, Debug, Clone, Default)] +pub struct SimulationTime { + pub tick: u64, + pub paused: bool, +} + +impl SimulationTime { + pub fn game_minutes(&self) -> u64 { + self.tick / TICKS_PER_GAME_MINUTE + } + pub fn time_of_day_minutes(&self) -> u64 { + self.game_minutes() % MINUTES_PER_DAY + } + pub fn day_phase(&self) -> DayPhase { + let tod = self.time_of_day_minutes(); + match tod { + 0..360 => DayPhase::Morning, + 360..720 => DayPhase::Afternoon, + 720..1080 => DayPhase::Evening, + _ => DayPhase::Night, + } + } + pub fn day(&self) -> u64 { + self.game_minutes() / MINUTES_PER_DAY + } +} + +/// Advance the simulation tick if not paused +pub fn advance_tick(mut time: ResMut) { + if !time.paused { + time.tick += 1; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn tick_to_minute_conversion() { + let time = SimulationTime { + tick: 10, + paused: false, + }; + assert_eq!(time.game_minutes(), 1); + } + + #[test] + fn day_phase_boundaries() { + let time = SimulationTime { + tick: 0, + paused: false, + }; + assert_eq!(time.day_phase(), DayPhase::Morning); + let time = SimulationTime { + tick: 360 * TICKS_PER_GAME_MINUTE, + paused: false, + }; + assert_eq!(time.day_phase(), DayPhase::Afternoon); + let time = SimulationTime { + tick: 720 * TICKS_PER_GAME_MINUTE, + paused: false, + }; + assert_eq!(time.day_phase(), DayPhase::Evening); + let time = SimulationTime { + tick: 1080 * TICKS_PER_GAME_MINUTE, + paused: false, + }; + assert_eq!(time.day_phase(), DayPhase::Night); + } + + #[test] + fn pause_prevents_tick_advance() { + let mut world = bevy_ecs::world::World::new(); + world.insert_resource(SimulationTime { + tick: 0, + paused: true, + }); + let mut schedule = bevy_ecs::schedule::Schedule::default(); + schedule.add_systems(advance_tick); + schedule.run(&mut world); + assert_eq!(world.resource::().tick, 0); + } + + #[test] + fn unpause_allows_tick_advance() { + let mut world = bevy_ecs::world::World::new(); + world.insert_resource(SimulationTime { + tick: 0, + paused: false, + }); + let mut schedule = bevy_ecs::schedule::Schedule::default(); + schedule.add_systems(advance_tick); + schedule.run(&mut world); + assert_eq!(world.resource::().tick, 1); + } +} diff --git a/server/src/storyteller/mod.rs b/server/src/storyteller/mod.rs new file mode 100644 index 000000000..34a0fc9f7 --- /dev/null +++ b/server/src/storyteller/mod.rs @@ -0,0 +1,15 @@ +// Storyteller module - Rimworld-style storyteller system +// Event generation, pacing, hubris wall mechanics + +use bevy_app::prelude::*; + +/// Storyteller plugin +/// Manages narrative pacing and event generation +pub struct StorytellerPlugin; + +impl Plugin for StorytellerPlugin { + fn build(&self, _app: &mut App) { + // Stub implementation - will be populated in phase 2 + tracing::debug!("StorytellerPlugin initialized"); + } +} diff --git a/server/tests/serialization.rs b/server/tests/serialization.rs new file mode 100644 index 000000000..6551b76ac --- /dev/null +++ b/server/tests/serialization.rs @@ -0,0 +1,51 @@ +//! IPC serialization round-trip tests (D-030 Layer 1: fixture-based). + +use settled_reach_server::bridge::types::*; + +#[test] +fn observer_snapshot_roundtrip() { + let snapshot = ObserverSnapshot { + tick: 42, + entities: vec![VisibleEntity { + entity_id: 1, + x: 10.0, + y: 20.0, + z: 0, + kind: EntityKind::Npc, + }], + }; + + let bytes = rmp_serde::to_vec(&snapshot).expect("serialize"); + let decoded: ObserverSnapshot = rmp_serde::from_slice(&bytes).expect("deserialize"); + + assert_eq!(decoded.tick, 42); + assert_eq!(decoded.entities.len(), 1); + assert_eq!(decoded.entities[0].entity_id, 1); +} + +#[test] +fn player_input_roundtrip() { + let input = PlayerInput { + tick: 100, + action: PlayerAction::MoveNorth, + }; + + let bytes = rmp_serde::to_vec(&input).expect("serialize"); + let decoded: PlayerInput = rmp_serde::from_slice(&bytes).expect("deserialize"); + + assert_eq!(decoded.tick, 100); +} + +#[test] +fn empty_snapshot_roundtrip() { + let snapshot = ObserverSnapshot { + tick: 0, + entities: vec![], + }; + + let bytes = rmp_serde::to_vec(&snapshot).expect("serialize"); + let decoded: ObserverSnapshot = rmp_serde::from_slice(&bytes).expect("deserialize"); + + assert_eq!(decoded.tick, 0); + assert!(decoded.entities.is_empty()); +} diff --git a/server/tests/smoke.rs b/server/tests/smoke.rs new file mode 100644 index 000000000..d3504457e --- /dev/null +++ b/server/tests/smoke.rs @@ -0,0 +1,22 @@ +//! Smoke test: the simulation world boots and can run a single tick. + +use bevy_app::prelude::*; +use settled_reach_server::simulation::SimulationPlugin; +use settled_reach_server::simulation::time::SimulationTime; + +#[test] +fn world_boots_and_ticks() { + let mut app = App::new(); + app.add_plugins(SimulationPlugin); + + // Verify initial state + let time = app.world().resource::(); + assert_eq!(time.tick, 0); + + // Run one update cycle + app.update(); + + // Verify tick advanced + let time = app.world().resource::(); + assert_eq!(time.tick, 1); +}