diff --git a/.drone.yml b/.drone.yml index ae267b5..49ef008 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,12 +1,24 @@ --- kind: pipeline type: docker -name: test elseware +name: test elseware concurrency: limit: 1 +environment: + CARGO_INCREMENTAL: false + steps: +- name: clean cache + image: rustlang/rust:nightly + volumes: + - name: cache + path: /usr/local/cargo + - name: target-cache + path: /drone/src/target + commands: + - cargo prune - name: build image: rustlang/rust:nightly volumes: @@ -33,7 +45,7 @@ steps: - name: target-cache path: /drone/src/target commands: - - cargo test + - cargo test --jobs 1 volumes: - name: cache diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index c32fc6e..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,2390 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "ages-prs" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "089e6d1d25d8975ac1bf2da0d1556ebdb99fee1a9aec6467d138a6e090b92ff4" -dependencies = [ - "libflate_lz77", -] - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom 0.2.6", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" -dependencies = [ - "backtrace", -] - -[[package]] -name = "async-attributes" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "async-channel" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-executor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "once_cell", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c290043c9a95b05d45e952fb6383c67bcb61471f60cfa21e890dba6654234f43" -dependencies = [ - "async-channel", - "async-executor", - "async-io", - "async-mutex", - "blocking", - "futures-lite", - "num_cpus", - "once_cell", -] - -[[package]] -name = "async-io" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" -dependencies = [ - "concurrent-queue", - "futures-lite", - "libc", - "log", - "once_cell", - "parking", - "polling", - "slab", - "socket2", - "waker-fn", - "winapi", -] - -[[package]] -name = "async-lock" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-mutex" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-native-tls" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e9e7a929bd34c68a82d58a4de7f86fffdaf97fb2af850162a7bb19dd7269b33" -dependencies = [ - "async-std", - "native-tls", - "thiserror", - "url", -] - -[[package]] -name = "async-process" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83137067e3a2a6a06d67168e49e68a0957d215410473a740cea95a2425c0b7c6" -dependencies = [ - "async-io", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "libc", - "once_cell", - "signal-hook", - "winapi", -] - -[[package]] -name = "async-recursion" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "async-std" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52580991739c5cdb36cde8b2a516371c0a3b70dda36d916cc08b82372916808c" -dependencies = [ - "async-attributes", - "async-channel", - "async-global-executor", - "async-io", - "async-lock", - "async-process", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "num_cpus", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-task" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" - -[[package]] -name = "async-trait" -version = "0.1.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "atoi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" -dependencies = [ - "num-traits", -] - -[[package]] -name = "atomic-waker" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" -dependencies = [ - "autocfg 1.1.0", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "barrel" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d67c978b1322c8031145b1f6c236fc371292f52c565bc96018b2971afcbffe1" - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - -[[package]] -name = "bcrypt" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f691e63585950d8c1c43644d11bab9073e40f5060dd2822734ae7c3dc69a3a80" -dependencies = [ - "base64", - "blowfish", - "getrandom 0.2.6", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blocking" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc" -dependencies = [ - "async-channel", - "async-task", - "atomic-waker", - "fastrand", - "futures-lite", - "once_cell", -] - -[[package]] -name = "blowfish" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe3ff3fc1de48c1ac2e3341c4df38b0d1bfb8fdf04632a187c8b75aaa319a7ab" -dependencies = [ - "byteorder", - "cipher", - "opaque-debug", -] - -[[package]] -name = "build_const" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" - -[[package]] -name = "bumpalo" -version = "3.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" - -[[package]] -name = "cache-padded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "libc", - "num-integer", - "num-traits", - "time", - "winapi", -] - -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - -[[package]] -name = "colored" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" -dependencies = [ - "atty", - "lazy_static", - "winapi", -] - -[[package]] -name = "concurrent-queue" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" -dependencies = [ - "cache-padded", -] - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "cpufeatures" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -dependencies = [ - "build_const", -] - -[[package]] -name = "crc" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" - -[[package]] -name = "crossbeam-queue" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" -dependencies = [ - "cfg-if", - "lazy_static", -] - -[[package]] -name = "crypto-common" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "ctor" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn", -] - -[[package]] -name = "digest" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - -[[package]] -name = "elseware" -version = "0.1.0" -dependencies = [ - "ages-prs", - "anyhow", - "async-recursion", - "async-std", - "async-trait", - "barrel", - "bcrypt", - "byteorder", - "chrono", - "crc 1.8.1", - "derive_more", - "enum-utils", - "fern", - "futures", - "lazy_static", - "libpso", - "log", - "rand 0.7.3", - "rand_chacha 0.2.2", - "refinery", - "ron", - "serde", - "serde_json", - "sqlx", - "strum", - "strum_macros", - "thiserror", - "toml", -] - -[[package]] -name = "enum-utils" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed327f716d0d351d86c9fd3398d20ee39ad8f681873cc081da2ca1c10fed398a" -dependencies = [ - "enum-utils-from-str", - "failure", - "proc-macro2", - "quote", - "serde_derive_internals", - "syn", -] - -[[package]] -name = "enum-utils-from-str" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d49be08bad6e4ca87b2b8e74146987d4e5cb3b7512efa50ef505b51a22227ee1" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "event-listener" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" - -[[package]] -name = "failure" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" -dependencies = [ - "backtrace", -] - -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "fastrand" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] - -[[package]] -name = "fern" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69ab0d5aca163e388c3a49d284fed6c3d0810700e77c5ae2756a50ec1a4daaa" -dependencies = [ - "chrono", - "colored", - "log", -] - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" -dependencies = [ - "matches", - "percent-encoding", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - -[[package]] -name = "futures" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" - -[[package]] -name = "futures-executor" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-intrusive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" -dependencies = [ - "futures-core", - "lock_api", - "parking_lot", -] - -[[package]] -name = "futures-io" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" - -[[package]] -name = "futures-lite" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-macro" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" - -[[package]] -name = "futures-task" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" - -[[package]] -name = "futures-util" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.10.2+wasi-snapshot-preview1", -] - -[[package]] -name = "gimli" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" - -[[package]] -name = "gloo-timers" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashlink" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" -dependencies = [ - "hashbrown", -] - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hkdf" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" -dependencies = [ - "autocfg 1.1.0", - "hashbrown", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" - -[[package]] -name = "js-sys" -version = "0.3.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.125" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" - -[[package]] -name = "libflate_lz77" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739e9d7726dc32173fed2d69d17eef3c54682169e4e20ff1d0a45dcd37063cef" - -[[package]] -name = "libpso" -version = "0.1.0" -source = "git+http://git.sharnoth.com/jake/libpso#05222bbf9fe402675447bc163b45e07a327cdb1a" -dependencies = [ - "chrono", - "psopacket", - "rand 0.6.5", -] - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg 1.1.0", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" -dependencies = [ - "cfg-if", - "value-bag", -] - -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - -[[package]] -name = "md-5" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" -dependencies = [ - "digest", -] - -[[package]] -name = "memchr" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" -dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "wasi 0.11.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", -] - -[[package]] -name = "native-tls" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nom" -version = "7.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "ntapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" -dependencies = [ - "winapi", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg 1.1.0", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg 1.1.0", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.28.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40bec70ba014595f99f7aa110b84331ffe1ee9aece7fe6f387cc7e3ecda4d456" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-sys", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" -dependencies = [ - "autocfg 1.1.0", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "parking" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "paste" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" - -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" - -[[package]] -name = "polling" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" -dependencies = [ - "cfg-if", - "libc", - "log", - "wepoll-ffi", - "winapi", -] - -[[package]] -name = "postgres" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb76d6535496f633fa799bb872ffb4790e9cbdedda9d35564ca0252f930c0dd5" -dependencies = [ - "bytes", - "fallible-iterator", - "futures", - "log", - "tokio", - "tokio-postgres", -] - -[[package]] -name = "postgres-protocol" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79ec03bce71f18b4a27c4c64c6ba2ddf74686d69b91d8714fb32ead3adaed713" -dependencies = [ - "base64", - "byteorder", - "bytes", - "fallible-iterator", - "hmac", - "md-5", - "memchr", - "rand 0.8.5", - "sha2", - "stringprep", -] - -[[package]] -name = "postgres-types" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04619f94ba0cc80999f4fc7073607cb825bc739a883cb6d20900fc5e009d6b0d" -dependencies = [ - "bytes", - "fallible-iterator", - "postgres-protocol", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - -[[package]] -name = "proc-macro2" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "psopacket" -version = "1.0.0" -source = "git+http://git.sharnoth.com/jake/libpso#05222bbf9fe402675447bc163b45e07a327cdb1a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "quote" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.8", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc 0.1.0", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.3", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.3.1", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.3", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom 0.2.6", -] - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom 0.2.6", - "redox_syscall", - "thiserror", -] - -[[package]] -name = "refinery" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e29bd9c881127d714f4b5b9fdd9ea7651f3dd254922e959a10f6ada620e841da" -dependencies = [ - "refinery-core", - "refinery-macros", -] - -[[package]] -name = "refinery-core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53260bc01535ea10c553ce0fc410609ba2dc0a9f4c9b4503e0af842dd4a6f89d" -dependencies = [ - "async-trait", - "cfg-if", - "chrono", - "lazy_static", - "log", - "postgres", - "regex", - "serde", - "siphasher", - "thiserror", - "toml", - "url", - "walkdir", -] - -[[package]] -name = "refinery-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a79ff62c9b674b62c06a09cc8becf06cbafba9952afa1d8174e7e15f2c4ed43" -dependencies = [ - "proc-macro2", - "quote", - "refinery-core", - "regex", - "syn", -] - -[[package]] -name = "regex" -version = "1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "ron" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678" -dependencies = [ - "base64", - "bitflags", - "serde", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" -dependencies = [ - "lazy_static", - "winapi", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "security-framework" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" - -[[package]] -name = "serde" -version = "1.0.136" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.136" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_derive_internals" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha-1" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "signal-hook" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" -dependencies = [ - "libc", -] - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "slab" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" - -[[package]] -name = "smallvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" - -[[package]] -name = "socket2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "sqlformat" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" -dependencies = [ - "itertools", - "nom", - "unicode_categories", -] - -[[package]] -name = "sqlx" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551873805652ba0d912fec5bbb0f8b4cdd96baf8e2ebf5970e5671092966019b" -dependencies = [ - "sqlx-core", - "sqlx-macros", -] - -[[package]] -name = "sqlx-core" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48c61941ccf5ddcada342cd59e3e5173b007c509e1e8e990dafc830294d9dc5" -dependencies = [ - "ahash", - "atoi", - "base64", - "bitflags", - "byteorder", - "bytes", - "chrono", - "crc 2.1.0", - "crossbeam-queue", - "dirs", - "either", - "event-listener", - "futures-channel", - "futures-core", - "futures-intrusive", - "futures-util", - "hashlink", - "hex", - "hkdf", - "hmac", - "indexmap", - "itoa", - "libc", - "log", - "md-5", - "memchr", - "once_cell", - "paste", - "percent-encoding", - "rand 0.8.5", - "serde", - "serde_json", - "sha-1", - "sha2", - "smallvec", - "sqlformat", - "sqlx-rt", - "stringprep", - "thiserror", - "url", - "whoami", -] - -[[package]] -name = "sqlx-macros" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0fba2b0cae21fc00fe6046f8baa4c7fcb49e379f0f592b04696607f69ed2e1" -dependencies = [ - "dotenv", - "either", - "heck 0.4.0", - "once_cell", - "proc-macro2", - "quote", - "serde_json", - "sha2", - "sqlx-core", - "sqlx-rt", - "syn", - "url", -] - -[[package]] -name = "sqlx-rt" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4db708cd3e459078f85f39f96a00960bd841f66ee2a669e90bf36907f5a79aae" -dependencies = [ - "async-native-tls", - "async-std", - "native-tls", -] - -[[package]] -name = "stringprep" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "strum" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b89a286a7e3b5720b9a477b23253bc50debac207c8d21505f8e70b36792f11b5" - -[[package]] -name = "strum_macros" -version = "0.19.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e61bb0be289045cb80bfce000512e32d09f8337e54c186725da381377ad1f8d5" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "thiserror" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "time" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "tokio" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f48b6d60512a392e34dbf7fd456249fd2de3c83669ab642e021903f4015185b" -dependencies = [ - "bytes", - "libc", - "memchr", - "mio", - "once_cell", - "pin-project-lite", - "socket2", - "winapi", -] - -[[package]] -name = "tokio-postgres" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6c8b33df661b548dcd8f9bf87debb8c56c05657ed291122e1188698c2ece95" -dependencies = [ - "async-trait", - "byteorder", - "bytes", - "fallible-iterator", - "futures", - "log", - "parking_lot", - "percent-encoding", - "phf", - "pin-project-lite", - "postgres-protocol", - "postgres-types", - "socket2", - "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-util" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" -dependencies = [ - "serde", -] - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - -[[package]] -name = "unicode-normalization" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - -[[package]] -name = "url" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", -] - -[[package]] -name = "value-bag" -version = "1.0.0-alpha.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79923f7731dc61ebfba3633098bf3ac533bbd35ccd8c57e7088d9a5eebe0263f" -dependencies = [ - "ctor", - "version_check", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" -dependencies = [ - "bumpalo", - "lazy_static", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" - -[[package]] -name = "web-sys" -version = "0.3.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - -[[package]] -name = "whoami" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index d62e110..dac1d62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,46 @@ version = "0.1.0" authors = ["Jake Probst "] edition = "2021" -[dependencies] +[workspace] +members = [ + "src/client", + "src/drops", + "src/entity", + "src/items", + "src/location", + "src/maps", + "src/networking", + "src/pktbuilder", + "src/quests", + "src/room", + "src/shops", + "src/stats", + "src/trade", + "src/patch_server", + "src/login_server", + "src/ship_server", +] + +[workspace.dependencies] +entity = { path = "./src/entity" } +maps = { path = "./src/maps" } +networking = { path = "./src/networking" } +shops = { path = "./src/shops" } +stats = { path = "./src/stats" } +items = { path = "./src/items" } +pktbuilder = { path = "./src/pktbuilder" } +quests = { path = "./src/quests" } +location = { path = "./src/location" } +client = { path = "./src/client" } +drops = { path = "./src/drops" } +trade = { path = "./src/trade" } +room = { path = "./src/room" } +patch_server = { path = "./src/patch_server" } +login_server = { path = "./src/login_server" } +ship_server = { path = "./src/ship_server" } + libpso = { git = "http://git.sharnoth.com/jake/libpso" } + async-std = { version = "1.9.0", features = ["unstable", "attributes"] } futures = "0.3.5" rand = "0.7.3" @@ -27,9 +65,33 @@ ages-prs = "0.1" async-trait = "0.1.51" async-recursion= "1.0.0" lazy_static = "1.4.0" -barrel = { version = "0.6.5", features = ["pg"] } refinery = { version = "0.5.0", features = ["postgres"] } -sqlx = { version = "0.5.10", features = ["runtime-async-std-native-tls", "postgres", "json", "chrono"] } +sqlx = { version = "0.6.2", features = ["runtime-async-std-native-tls", "postgres", "json", "chrono"] } strum = "0.19.5" strum_macros = "0.19" anyhow = { version = "1.0.68", features = ["backtrace"] } + +[dependencies] +entity = { workspace = true } +maps = { workspace = true } +networking = { workspace = true } +patch_server = { workspace = true } +login_server = { workspace = true } +ship_server = { workspace = true } + +libpso = { workspace = true } + +async-std = { workspace = true } +bcrypt = { workspace = true } +chrono = { workspace = true } +fern = { workspace = true } +futures = { workspace = true } +log = { workspace = true } + +[dev-dependencies] +drops = { workspace = true } +shops = { workspace = true } +items = { workspace = true } +quests = { workspace = true } +stats = { workspace = true } +async-trait = { workspace = true } \ No newline at end of file diff --git a/src/bin/login.rs b/src/bin/login.rs index f8b6b94..8f8832b 100644 --- a/src/bin/login.rs +++ b/src/bin/login.rs @@ -1,8 +1,8 @@ use log::{info}; -use elseware::entity::gateway::postgres::PostgresGateway; -use elseware::login::login::LoginServerState; -use elseware::login::character::CharacterServerState; -use elseware::common::interserver::AuthToken; +use entity::gateway::postgres::PostgresGateway; +use login_server::login::LoginServerState; +use login_server::character::CharacterServerState; +use networking::interserver::AuthToken; fn main() { let colors = fern::colors::ColoredLevelConfig::new() @@ -38,17 +38,17 @@ fn main() { let login_state = LoginServerState::new(entity_gateway.clone(), charserv_ip); let login_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT).await; + networking::mainloop::run_server(login_state, login_server::login::LOGIN_PORT).await; }); let char_state = CharacterServerState::new(entity_gateway, AuthToken(shipgate_token)); let sub_char_state = char_state.clone(); let character_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT).await; + networking::mainloop::run_server(sub_char_state, login_server::character::CHARACTER_PORT).await; }); let inter_character_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_interserver_listen(char_state, elseware::login::login::COMMUNICATION_PORT).await; + networking::mainloop::run_interserver_listen(char_state, login_server::login::COMMUNICATION_PORT).await; }); info!("[auth/character] starting server"); diff --git a/src/bin/main.rs b/src/bin/main.rs index 0a3ada0..ec67554 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,18 +1,18 @@ use std::net::Ipv4Addr; use log::{info}; -use elseware::common::interserver::AuthToken; -use elseware::login::login::LoginServerState; -use elseware::login::character::CharacterServerState; -use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config, load_motd}; -use elseware::ship::ship::{ShipServerStateBuilder, ShipEvent}; +use networking::interserver::AuthToken; +use login_server::login::LoginServerState; +use login_server::character::CharacterServerState; +use patch_server::{PatchServerState, generate_patch_tree, load_config, load_motd}; +use ship_server::ShipServerStateBuilder; -#[allow(unused_imports)] -use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway}; -use elseware::entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; -use elseware::entity::character::NewCharacterEntity; -use elseware::entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity}; -use elseware::entity::item; +use maps::Holiday; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; +use entity::character::NewCharacterEntity; +use entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity}; +use entity::item; fn setup_logger() { let colors = fern::colors::ColoredLevelConfig::new() @@ -338,73 +338,73 @@ fn main() { let (patch_file_tree, patch_file_lookup) = generate_patch_tree(patch_config.path.as_str()); let patch_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd); let patch_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(patch_state, patch_config.port).await; + networking::mainloop::run_server(patch_state, patch_config.port).await; }); info!("[auth] starting server"); let login_state = LoginServerState::new(entity_gateway.clone(), "127.0.0.1".parse().unwrap()); let login_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT).await; + networking::mainloop::run_server(login_state, login_server::login::LOGIN_PORT).await; }); info!("[character] starting server"); let char_state = CharacterServerState::new(entity_gateway.clone(), AuthToken("".into())); let sub_char_state = char_state.clone(); let character_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT).await; + networking::mainloop::run_server(sub_char_state, login_server::character::CHARACTER_PORT).await; }); let sub_char_state = char_state.clone(); let inter_character_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_interserver_listen(sub_char_state, elseware::login::login::COMMUNICATION_PORT).await; + networking::mainloop::run_interserver_listen(sub_char_state, login_server::login::COMMUNICATION_PORT).await; }); info!("[ship] starting servers"); let ship_state = ShipServerStateBuilder::default() .name("US/Sona-Nyl".into()) .ip(Ipv4Addr::new(127,0,0,1)) - .port(elseware::ship::ship::SHIP_PORT) - .event(ShipEvent::Halloween) + .port(ship_server::SHIP_PORT) + .event(Holiday::Halloween) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); let ship_loop1 = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT).await; + networking::mainloop::run_server(sub_ship_state, ship_server::SHIP_PORT).await; }); let sub_ship_state = ship_state.clone(); let inter_ship_loop1 = async_std::task::spawn(async move { - elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await; + networking::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), login_server::login::COMMUNICATION_PORT).await; }); let ship_state = ShipServerStateBuilder::default() .name("EU/Dylath-Leen".into()) .ip(Ipv4Addr::new(127,0,0,1)) - .port(elseware::ship::ship::SHIP_PORT+2000) - .event(ShipEvent::Christmas) + .port(ship_server::SHIP_PORT+2000) + .event(Holiday::Christmas) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); let ship_loop2 = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT+2000).await; + networking::mainloop::run_server(sub_ship_state, ship_server::SHIP_PORT+2000).await; }); let sub_ship_state = ship_state.clone(); let inter_ship_loop2 = async_std::task::spawn(async move { - elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await; + networking::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), login_server::login::COMMUNICATION_PORT).await; }); let ship_state = ShipServerStateBuilder::default() .name("JP/Thalarion".into()) .ip(Ipv4Addr::new(127,0,0,1)) - .port(elseware::ship::ship::SHIP_PORT+3000) + .port(ship_server::SHIP_PORT+3000) .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); let ship_loop3 = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT+3000).await; + networking::mainloop::run_server(sub_ship_state, ship_server::SHIP_PORT+3000).await; }); let sub_ship_state = ship_state.clone(); let inter_ship_loop3 = async_std::task::spawn(async move { - elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await; + networking::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), login_server::login::COMMUNICATION_PORT).await; }); futures::future::join_all(vec![patch_loop, login_loop, character_loop, inter_character_loop, diff --git a/src/bin/patch.rs b/src/bin/patch.rs index e7304d8..c38f025 100644 --- a/src/bin/patch.rs +++ b/src/bin/patch.rs @@ -1,5 +1,5 @@ -use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config_env, load_motd}; -use log::{info}; +use patch_server::{PatchServerState, generate_patch_tree, load_config_env, load_motd}; +use log::info; fn main() { info!("[patch] starting server"); @@ -9,10 +9,8 @@ fn main() { let patch_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd); let patch_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(patch_state, patch_config.port).await; + networking::mainloop::run_server(patch_state, patch_config.port).await; }); - async_std::task::block_on(async move { - patch_loop.await - }); + async_std::task::block_on(patch_loop); } diff --git a/src/bin/ship.rs b/src/bin/ship.rs index ff1ccc6..b664bda 100644 --- a/src/bin/ship.rs +++ b/src/bin/ship.rs @@ -1,7 +1,7 @@ -use log::{info}; -use elseware::entity::gateway::postgres::PostgresGateway; -use elseware::ship::ship::ShipServerStateBuilder; -use elseware::common::interserver::AuthToken; +use log::info; +use entity::gateway::postgres::PostgresGateway; +use ship_server::ShipServerStateBuilder; +use networking::interserver::AuthToken; fn main() { let colors = fern::colors::ColoredLevelConfig::new() @@ -40,7 +40,7 @@ fn main() { let ship_state = ShipServerStateBuilder::default() .name(ship_name) .ip(ip) - .port(elseware::ship::ship::SHIP_PORT) + .port(ship_server::SHIP_PORT) .gateway(entity_gateway) .auth_token(AuthToken(shipgate_token)) .build(); @@ -49,10 +49,10 @@ fn main() { let sub_ship_state = ship_state.clone(); let ship_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT).await; + networking::mainloop::run_server(sub_ship_state, ship_server::SHIP_PORT).await; }); let inter_ship_loop = async_std::task::spawn(async move { - elseware::common::mainloop::run_interserver_connect(ship_state, shipgate_ip, elseware::login::login::COMMUNICATION_PORT).await; + networking::mainloop::run_interserver_connect(ship_state, shipgate_ip, login_server::login::COMMUNICATION_PORT).await; }); info!("[auth/character] starting server"); diff --git a/src/client/Cargo.toml b/src/client/Cargo.toml new file mode 100644 index 0000000..12f9698 --- /dev/null +++ b/src/client/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "client" +version = "0.1.0" +edition = "2021" + + +[dependencies] +entity = { workspace = true } +maps = { workspace = true } +networking = { workspace = true } +shops = { workspace = true } +items = { workspace = true } + +libpso = { workspace = true } + +async-std = { workspace = true } +futures = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } +chrono = { workspace = true } diff --git a/src/ship/client.rs b/src/client/src/lib.rs similarity index 89% rename from src/ship/client.rs rename to src/client/src/lib.rs index 5495309..43c7a0f 100644 --- a/src/ship/client.rs +++ b/src/client/src/lib.rs @@ -6,15 +6,20 @@ use futures::future::BoxFuture; use libpso::packet::ship::*; use libpso::packet::login::Session; -use crate::common::serverstate::ClientId; -use crate::entity::account::{UserAccountEntity, UserSettingsEntity}; -use crate::entity::character::CharacterEntity; -use crate::entity::item; +use networking::serverstate::ClientId; +use entity::account::{UserAccountEntity, UserSettingsEntity}; +use entity::character::CharacterEntity; +use entity::item; -use crate::ship::ship::ShipError; -use crate::ship::items; -use crate::ship::map::MapArea; -use crate::ship::shops::{WeaponShopItem, ToolShopItem, ArmorShopItem}; +use maps::area::MapArea; +use shops::{WeaponShopItem, ToolShopItem, ArmorShopItem}; + + +#[derive(thiserror::Error, Debug)] +pub enum ClientError { + #[error("not found {0}")] + NotFound(ClientId), +} #[derive(Clone, Default)] @@ -46,7 +51,7 @@ impl Clients { .await; let client = clients .get(&client_id) - .ok_or_else(|| ShipError::ClientNotFound(client_id))? + .ok_or(ClientError::NotFound(client_id))? .read() .await; @@ -69,7 +74,7 @@ impl Clients { for (cindex, client_id) in client_ids.iter().enumerate() { let c = clients .get(client_id) - .ok_or_else(|| ShipError::ClientNotFound(*client_id))? + .ok_or(ClientError::NotFound(*client_id))? .read() .await; client_states[cindex].write(c); @@ -95,7 +100,7 @@ impl Clients { .await; let mut client = clients .get(&client_id) - .ok_or_else(|| ShipError::ClientNotFound(client_id))? + .ok_or(ClientError::NotFound(client_id))? .write() .await; diff --git a/src/drops/Cargo.toml b/src/drops/Cargo.toml new file mode 100644 index 0000000..199e7c6 --- /dev/null +++ b/src/drops/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "drops" +version = "0.1.0" +edition = "2021" + + +[dependencies] +entity = { workspace = true } +maps = { workspace = true } +stats = { workspace = true } + +rand = { workspace = true } +rand_chacha = { workspace = true } +serde = { workspace = true } +enum-utils = { workspace = true } +toml = { workspace = true } +chrono = { workspace = true } \ No newline at end of file diff --git a/src/ship/drops/box_drop_table.rs b/src/drops/src/box_drop_table.rs similarity index 90% rename from src/ship/drops/box_drop_table.rs rename to src/drops/src/box_drop_table.rs index f507d27..01f41eb 100644 --- a/src/ship/drops/box_drop_table.rs +++ b/src/drops/src/box_drop_table.rs @@ -2,18 +2,17 @@ use rand::{Rng}; use rand::distributions::{WeightedIndex, Distribution}; use serde::{Serialize, Deserialize}; -use crate::entity::character::SectionID; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::map::{MapObject, MapObjectType, FixedBoxDropType}; -use crate::ship::drops::rare_drop_table::{RareDropTable, RareDropItem}; -use crate::ship::drops::generic_weapon::GenericWeaponTable; -use crate::ship::drops::generic_armor::GenericArmorTable; -use crate::ship::drops::generic_shield::GenericShieldTable; -use crate::ship::drops::generic_unit::GenericUnitTable; -use crate::ship::drops::tool_table::ToolTable; -use crate::entity::item::ItemDetail; +use entity::character::SectionID; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use crate::{ItemDropType, load_data_file}; +use maps::object::{MapObject, MapObjectType, FixedBoxDropType}; +use crate::rare_drop_table::{RareDropTable, RareDropItem}; +use crate::generic_weapon::GenericWeaponTable; +use crate::generic_armor::GenericArmorTable; +use crate::generic_shield::GenericShieldTable; +use crate::generic_unit::GenericUnitTable; +use crate::tool_table::ToolTable; #[derive(Debug, Serialize, Deserialize)] struct BoxDropRate { @@ -176,8 +175,8 @@ impl BoxDropTable { fn random_box_drop(&self, map_area: &MapArea, rng: &mut R) -> Option { self.rare_drop(map_area, rng).or_else(|| { let rate = self.box_rates.rates_by_area(map_area); - let type_weights = WeightedIndex::new(&[rate.weapon_rate, rate.armor_rate, rate.shield_rate, rate.unit_rate, - rate.tool_rate, rate.meseta_rate, rate.nothing_rate]).unwrap(); + let type_weights = WeightedIndex::new([rate.weapon_rate, rate.armor_rate, rate.shield_rate, rate.unit_rate, + rate.tool_rate, rate.meseta_rate, rate.nothing_rate]).unwrap(); let btype = type_weights.sample(rng); match btype { 0 => self.weapon_table.get_drop(map_area, rng), @@ -204,7 +203,7 @@ impl BoxDropTable { FixedBoxDropType::Specific(value) => { let mut buf: [u8; 16] = [0; 16]; buf[0..4].copy_from_slice(&u32::to_be_bytes(value)); - ItemDetail::parse_item_from_bytes(buf) + ItemDropType::parse_item_from_bytes(buf) }, } } diff --git a/src/ship/drops/generic_armor.rs b/src/drops/src/generic_armor.rs similarity index 85% rename from src/ship/drops/generic_armor.rs rename to src/drops/src/generic_armor.rs index 2bf5895..82e9a58 100644 --- a/src/ship/drops/generic_armor.rs +++ b/src/drops/src/generic_armor.rs @@ -1,14 +1,14 @@ use std::collections::HashMap; use serde::{Serialize, Deserialize}; -use rand::{Rng}; +use rand::Rng; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::item::armor::{ArmorType, Armor}; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::item_stats::{armor_stats, ArmorStats}; +use entity::character::SectionID; +use entity::item::armor::{ArmorType, Armor}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use crate::{ItemDropType, load_data_file}; +use stats::items::{armor_stats, ArmorStats}; #[derive(Debug, Serialize, Deserialize)] @@ -46,8 +46,8 @@ impl GenericArmorTable { } fn armor_type(&self, area_map: &MapArea, rng: &mut R) -> ArmorType { - let rank_weights = WeightedIndex::new(&[self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2, - self.rank_rates.rank3, self.rank_rates.rank4]).unwrap(); + let rank_weights = WeightedIndex::new([self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2, + self.rank_rates.rank3, self.rank_rates.rank4]).unwrap(); let rank = rank_weights.sample(rng) as i32; let armor_level = std::cmp::max(0i32, self.armor_set as i32 - 3i32 + rank + area_map.drop_area_value().unwrap_or(0) as i32); match armor_level { @@ -80,8 +80,8 @@ impl GenericArmorTable { } pub fn slots(&self, _area_map: &MapArea, rng: &mut R) -> usize { - let slot_weights = WeightedIndex::new(&[self.slot_rates.slot0, self.slot_rates.slot1, self.slot_rates.slot2, - self.slot_rates.slot3, self.slot_rates.slot4]).unwrap(); + let slot_weights = WeightedIndex::new([self.slot_rates.slot0, self.slot_rates.slot1, self.slot_rates.slot2, + self.slot_rates.slot3, self.slot_rates.slot4]).unwrap(); slot_weights.sample(rng) } diff --git a/src/ship/drops/generic_shield.rs b/src/drops/src/generic_shield.rs similarity index 88% rename from src/ship/drops/generic_shield.rs rename to src/drops/src/generic_shield.rs index 9eec585..c7bbf1f 100644 --- a/src/ship/drops/generic_shield.rs +++ b/src/drops/src/generic_shield.rs @@ -1,14 +1,14 @@ use std::collections::HashMap; use serde::{Serialize, Deserialize}; -use rand::{Rng}; +use rand::Rng; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::item::shield::{ShieldType, Shield}; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::item_stats::{shield_stats, ShieldStats}; +use entity::item::shield::{ShieldType, Shield}; +use entity::character::SectionID; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use crate::{ItemDropType, load_data_file}; +use stats::items::{shield_stats, ShieldStats}; #[derive(Debug, Serialize, Deserialize)] @@ -36,8 +36,8 @@ impl GenericShieldTable { } fn shield_type(&self, area_map: &MapArea, rng: &mut R) -> ShieldType { - let rank_weights = WeightedIndex::new(&[self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2, - self.rank_rates.rank3, self.rank_rates.rank4]).unwrap(); + let rank_weights = WeightedIndex::new([self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2, + self.rank_rates.rank3, self.rank_rates.rank4]).unwrap(); let rank = rank_weights.sample(rng) as i32; let shield_level = std::cmp::max(0i32, self.shield_set as i32 - 3i32 + rank + area_map.drop_area_value().unwrap_or(0) as i32); match shield_level { diff --git a/src/ship/drops/generic_unit.rs b/src/drops/src/generic_unit.rs similarity index 92% rename from src/ship/drops/generic_unit.rs rename to src/drops/src/generic_unit.rs index 73bc4a6..cc1caa0 100644 --- a/src/ship/drops/generic_unit.rs +++ b/src/drops/src/generic_unit.rs @@ -1,14 +1,14 @@ use std::collections::BTreeMap; use serde::{Serialize, Deserialize}; -use rand::{Rng}; +use rand::Rng; use rand::seq::IteratorRandom; -use crate::entity::item::unit::{UnitType, Unit, UnitModifier}; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::item_stats::{unit_stats, UnitStats}; +use entity::character::SectionID; +use entity::item::unit::{UnitType, Unit, UnitModifier}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use crate::{ItemDropType, load_data_file}; +use stats::items::{unit_stats, UnitStats}; diff --git a/src/ship/drops/generic_weapon.rs b/src/drops/src/generic_weapon.rs similarity index 97% rename from src/ship/drops/generic_weapon.rs rename to src/drops/src/generic_weapon.rs index d1fb2bb..557130c 100644 --- a/src/ship/drops/generic_weapon.rs +++ b/src/drops/src/generic_weapon.rs @@ -1,14 +1,14 @@ use std::collections::{HashMap, BTreeMap}; use serde::{Serialize, Deserialize}; -use rand::{Rng}; +use rand::Rng; use rand::distributions::{WeightedIndex, Distribution}; use rand::seq::SliceRandom; -use crate::entity::item::weapon::{Weapon, WeaponType, Attribute, WeaponAttribute, WeaponSpecial}; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; +use entity::character::SectionID; +use entity::item::weapon::{Weapon, WeaponType, Attribute, WeaponAttribute, WeaponSpecial}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use crate::{ItemDropType, load_data_file}; @@ -240,7 +240,7 @@ impl AttributeTable { fn generate_attribute(&self, pattern: &PercentPatternType, rates: &AttributeRate, rng: &mut R) -> Option { - let attribute_weights = WeightedIndex::new(&[rates.none, rates.native, rates.abeast, rates.machine, rates.dark, rates.hit]).unwrap(); + let attribute_weights = WeightedIndex::new([rates.none, rates.native, rates.abeast, rates.machine, rates.dark, rates.hit]).unwrap(); let attr = match attribute_weights.sample(rng) { 0 => return None, 1 => Attribute::Native, @@ -253,7 +253,7 @@ impl AttributeTable { let percents = self.percent_rates.get_by_pattern(pattern); - let value_weights = WeightedIndex::new(&percents.as_array()).unwrap(); + let value_weights = WeightedIndex::new(percents.as_array()).unwrap(); let value = value_weights.sample(rng); let percent = ((value + 1) * 5) as i8; @@ -477,7 +477,7 @@ impl GenericWeaponTable { let pattern = std::cmp::min(area % ratio.inc, 3); let weights = self.grind_rates.grind_rate[pattern as usize]; - let grind_choice = WeightedIndex::new(&weights).unwrap(); + let grind_choice = WeightedIndex::new(weights).unwrap(); grind_choice.sample(rng) } diff --git a/src/ship/drops/mod.rs b/src/drops/src/lib.rs similarity index 76% rename from src/ship/drops/mod.rs rename to src/drops/src/lib.rs index 5d8062c..32a14db 100644 --- a/src/ship/drops/mod.rs +++ b/src/drops/src/lib.rs @@ -5,7 +5,6 @@ // to their drops -mod drop_table; pub mod rare_drop_table; mod generic_weapon; mod generic_armor; @@ -22,19 +21,19 @@ use std::io::Read; use serde::{Serialize, Deserialize}; use rand::{Rng, SeedableRng}; -use crate::ship::monster::MonsterType; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::generic_weapon::GenericWeaponTable; -use crate::ship::drops::generic_armor::GenericArmorTable; -use crate::ship::drops::generic_shield::GenericShieldTable; -use crate::ship::drops::generic_unit::GenericUnitTable; -use crate::ship::drops::tool_table::ToolTable; -use crate::ship::drops::rare_drop_table::RareDropTable; -use crate::ship::drops::box_drop_table::BoxDropTable; -use crate::ship::map::MapObject; -use crate::entity::item::{weapon, armor, shield, unit, mag, tool, tech}; +use maps::monster::MonsterType; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use entity::character::SectionID; +use crate::generic_weapon::GenericWeaponTable; +use crate::generic_armor::GenericArmorTable; +use crate::generic_shield::GenericShieldTable; +use crate::generic_unit::GenericUnitTable; +use crate::tool_table::ToolTable; +use crate::rare_drop_table::RareDropTable; +use crate::box_drop_table::BoxDropTable; +use maps::object::MapObject; +use entity::item::{ItemType, weapon, armor, shield, unit, mag, tool, tech, esweapon}; fn data_file_path(episode: Episode, difficulty: Difficulty, section_id: SectionID, filename: &str) -> PathBuf { @@ -55,18 +54,6 @@ pub fn load_data_file(episode: Episode, difficul toml::from_str::(s.as_str()).unwrap() } -// this is just copypaste -pub fn load_rare_monster_file(episode: Episode) -> T { - // TODO: where does the rare monster toml file actually live - let mut path = PathBuf::from("data/battle_param/"); - path.push(episode.to_string().to_lowercase() + "_rare_monster.toml"); - - let mut f = File::open(path).unwrap(); - let mut s = String::new(); - f.read_to_string(&mut s); - toml::from_str::(s.as_str()).unwrap() -} - #[derive(Debug, Serialize, Deserialize, Copy, Clone)] pub enum MonsterDropType { #[serde(rename = "weapon")] @@ -102,6 +89,28 @@ pub enum ItemDropType { Meseta(u32), } +impl ItemDropType { + pub fn parse_item_from_bytes(data: [u8; 16]) -> Option { + let item_type = weapon::WeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::Weapon) + .or_else(|_| armor::ArmorType::parse_type([data[0],data[1],data[2]]).map(ItemType::Armor)) + .or_else(|_| shield::ShieldType::parse_type([data[0],data[1],data[2]]).map(ItemType::Shield)) + .or_else(|_| unit::UnitType::parse_type([data[0],data[1],data[2]]).map(ItemType::Unit)) + .or_else(|_| mag::MagType::parse_type([data[0],data[1],data[2]]).map(ItemType::Mag)) + .or_else(|_| tool::ToolType::parse_type([data[0],data[1],data[2]]).map(ItemType::Tool)) + .or_else(|_| esweapon::ESWeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::ESWeapon)).ok()?; + + match item_type { + ItemType::Weapon(_w) => Some(ItemDropType::Weapon(weapon::Weapon::from_bytes(data).ok()?)), + ItemType::Armor(_a) => Some(ItemDropType::Armor(armor::Armor::from_bytes(data).ok()?)), + ItemType::Shield(_s) => Some(ItemDropType::Shield(shield::Shield::from_bytes(data).ok()?)), + ItemType::Unit(_u) => Some(ItemDropType::Unit(unit::Unit::from_bytes(data).ok()?)), + ItemType::Mag(_m) => Some(ItemDropType::Mag(mag::Mag::from_bytes(data).ok()?)), + ItemType::Tool(_t) => Some(ItemDropType::Tool(tool::Tool::from_bytes(data).ok()?)), + _ => None, + } + } +} + #[derive(Clone, Debug)] pub struct ItemDrop { pub map_area: MapArea, @@ -112,7 +121,12 @@ pub struct ItemDrop { } -pub struct DropTable { +pub trait DropTable { + fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option; + fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option; +} + +pub struct StandardDropTable { monster_stats: HashMap, rare_table: RareDropTable, weapon_table: GenericWeaponTable, @@ -124,11 +138,12 @@ pub struct DropTable { rng: rand_chacha::ChaCha20Rng, } -impl DropTable { - pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable { +impl StandardDropTable { + #[allow(clippy::new_ret_no_self)] + pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> Box { let monster_stats: HashMap = load_data_file(episode, difficulty, section_id, "monster_dar.toml"); - - DropTable { + + Box::new(StandardDropTable { monster_stats: monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect(), rare_table: RareDropTable::new(episode, difficulty, section_id), weapon_table: GenericWeaponTable::new(episode, difficulty, section_id), @@ -138,7 +153,7 @@ impl DropTable { tool_table: ToolTable::new(episode, difficulty, section_id), box_table: BoxDropTable::new(episode, difficulty, section_id), rng: rand_chacha::ChaCha20Rng::from_entropy(), - } + }) } pub fn builder() -> DropTableBuilder { @@ -168,8 +183,10 @@ impl DropTable { MonsterDropType::None => None, } } +} - pub fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option { +impl DropTable for StandardDropTable { + fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option { let monster_stat = *self.monster_stats.get(monster)?; let drop_anything = self.rng.gen_range(0, 100); @@ -182,7 +199,7 @@ impl DropTable { } let drop_type = self.rng.gen_range(0, 3); - + match drop_type { 0 => { self.generate_meseta(&monster_stat) @@ -197,7 +214,7 @@ impl DropTable { } } - pub fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option { + fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option { self.box_table.get_drop(map_area, object, &mut self.rng) } } @@ -244,8 +261,8 @@ impl DropTableBuilder { self } - pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable { - DropTable { + pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> Box { + Box::new(StandardDropTable { monster_stats: self.monster_stats.unwrap_or_else(|| { let monster_stats: HashMap = load_data_file(episode, difficulty, section_id, "monster_dar.toml"); monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect() @@ -258,11 +275,10 @@ impl DropTableBuilder { tool_table: self.tool_table.unwrap_or_else(|| ToolTable::new(episode, difficulty, section_id)), box_table: self.box_table.unwrap_or_else(|| BoxDropTable::new(episode, difficulty, section_id)), rng: self.rng.unwrap_or_else(rand_chacha::ChaCha20Rng::from_entropy), - } + }) } } - #[cfg(test)] mod test { use super::*; diff --git a/src/ship/drops/rare_drop_table.rs b/src/drops/src/rare_drop_table.rs similarity index 90% rename from src/ship/drops/rare_drop_table.rs rename to src/drops/src/rare_drop_table.rs index 51151ba..b9ab745 100644 --- a/src/ship/drops/rare_drop_table.rs +++ b/src/drops/src/rare_drop_table.rs @@ -1,20 +1,20 @@ use std::collections::HashMap; use rand::Rng; use serde::{Serialize, Deserialize}; -use crate::entity::item::weapon::{Weapon, WeaponType}; -use crate::entity::item::armor::{Armor, ArmorType}; -use crate::entity::item::shield::{Shield, ShieldType}; -use crate::entity::item::unit::{Unit, UnitType}; -use crate::entity::item::tool::{Tool, ToolType}; -use crate::entity::item::mag::{Mag, MagType}; -use crate::entity::character::SectionID; -use crate::ship::monster::MonsterType; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::drops::generic_weapon::AttributeTable; -use crate::ship::drops::generic_armor::GenericArmorTable; -use crate::ship::drops::generic_shield::GenericShieldTable; +use entity::item::weapon::{Weapon, WeaponType}; +use entity::item::armor::{Armor, ArmorType}; +use entity::item::shield::{Shield, ShieldType}; +use entity::item::unit::{Unit, UnitType}; +use entity::item::tool::{Tool, ToolType}; +use entity::item::mag::{Mag, MagType}; +use entity::character::SectionID; +use maps::monster::MonsterType; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use crate::{ItemDropType, load_data_file}; +use crate::generic_weapon::AttributeTable; +use crate::generic_armor::GenericArmorTable; +use crate::generic_shield::GenericShieldTable; type ItemParseFn = Box Option>; diff --git a/src/ship/drops/tech_table.rs b/src/drops/src/tech_table.rs similarity index 95% rename from src/ship/drops/tech_table.rs rename to src/drops/src/tech_table.rs index 6e6396f..9b1101b 100644 --- a/src/ship/drops/tech_table.rs +++ b/src/drops/src/tech_table.rs @@ -3,11 +3,11 @@ use serde::{Serialize, Deserialize}; use rand::{Rng}; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::item::tech::{Technique, TechniqueDisk}; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; +use entity::item::tech::{Technique, TechniqueDisk}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use entity::character::SectionID; +use crate::{ItemDropType, load_data_file}; diff --git a/src/ship/drops/tool_table.rs b/src/drops/src/tool_table.rs similarity index 94% rename from src/ship/drops/tool_table.rs rename to src/drops/src/tool_table.rs index 69a14cd..9645c34 100644 --- a/src/ship/drops/tool_table.rs +++ b/src/drops/src/tool_table.rs @@ -1,14 +1,14 @@ -use std::collections::{BTreeMap}; +use std::collections::BTreeMap; use serde::{Serialize, Deserialize}; -use rand::{Rng}; +use rand::Rng; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::item::tool::{Tool, ToolType}; -use crate::ship::room::{Difficulty, Episode}; -use crate::ship::map::MapArea; -use crate::entity::character::SectionID; -use crate::ship::drops::{ItemDropType, load_data_file}; -use crate::ship::drops::tech_table::TechniqueTable; +use entity::item::tool::{Tool, ToolType}; +use maps::room::{Difficulty, Episode}; +use maps::area::MapArea; +use entity::character::SectionID; +use crate::{ItemDropType, load_data_file}; +use crate::tech_table::TechniqueTable; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, enum_utils::FromStr)] diff --git a/src/entity/Cargo.toml b/src/entity/Cargo.toml new file mode 100644 index 0000000..ce90e98 --- /dev/null +++ b/src/entity/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "entity" +version = "0.1.0" +edition = "2021" + +[dependencies] +libpso = { workspace = true } +maps = { workspace = true } +chrono = { workspace = true } +anyhow = { workspace = true } +async-std = { workspace = true } +sqlx = { workspace = true } +thiserror = { workspace = true } +serde = { workspace = true } +async-trait = { workspace = true } +enum-utils = { workspace = true } +derive_more = { workspace = true } +refinery = { workspace = true } +lazy_static = { workspace = true } +futures = { workspace = true } +strum = { workspace = true } +strum_macros = { workspace = true } +toml = { workspace = true } diff --git a/src/entity/gateway/postgres/migrations/mod.rs b/src/entity/gateway/postgres/migrations/mod.rs deleted file mode 100644 index 533298a..0000000 --- a/src/entity/gateway/postgres/migrations/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -use refinery::include_migration_mods; - -include_migration_mods!("src/entity/gateway/postgres/migrations"); diff --git a/src/entity/account.rs b/src/entity/src/account.rs similarity index 100% rename from src/entity/account.rs rename to src/entity/src/account.rs diff --git a/src/entity/character.rs b/src/entity/src/character.rs similarity index 98% rename from src/entity/character.rs rename to src/entity/src/character.rs index 080bb1b..643e009 100644 --- a/src/entity/character.rs +++ b/src/entity/src/character.rs @@ -4,8 +4,8 @@ use serde::{Serialize, Deserialize}; use libpso::packet::ship::{UpdateConfig, WriteInfoboard}; use libpso::character::settings::{DEFAULT_PALETTE_CONFIG, DEFAULT_TECH_MENU}; -use crate::entity::item::tech::Technique; -use crate::entity::account::UserAccountId; +use crate::item::tech::Technique; +use crate::account::UserAccountId; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, enum_utils::FromStr, derive_more::Display, Serialize, Deserialize, Default)] pub enum CharacterClass { diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/src/gateway/entitygateway.rs similarity index 93% rename from src/entity/gateway/entitygateway.rs rename to src/entity/src/gateway/entitygateway.rs index 99c65bb..4f7ae67 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/src/gateway/entitygateway.rs @@ -1,13 +1,13 @@ use thiserror::Error; use futures::future::{Future, BoxFuture}; -use crate::entity::account::*; -use crate::entity::character::*; -use crate::entity::item::*; +use crate::account::*; +use crate::character::*; +use crate::item::*; +use crate::room::*; // TODO: better granularity? -//#[derive(Error, Debug)] #[derive(Error, Debug)] pub enum GatewayError { #[error("unknown error")] @@ -147,6 +147,14 @@ pub trait EntityGateway: Send + Sync { async fn set_character_playtime(&mut self, _char_id: &CharacterEntityId, _playtime: u32) -> Result<(), GatewayError> { unimplemented!(); } + + async fn create_room(&mut self, _room: NewRoomEntity) -> Result { + unimplemented!(); + } + + async fn add_room_note(&mut self, _room_id: RoomEntityId, _note: RoomNote) -> Result<(), GatewayError> { + unimplemented!(); + } } diff --git a/src/entity/gateway/inmemory.rs b/src/entity/src/gateway/inmemory.rs similarity index 97% rename from src/entity/gateway/inmemory.rs rename to src/entity/src/gateway/inmemory.rs index 75df8a1..970beed 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/src/gateway/inmemory.rs @@ -2,10 +2,11 @@ use std::collections::BTreeMap; use std::convert::TryInto; use futures::future::{Future, BoxFuture}; -use crate::entity::account::*; -use crate::entity::character::*; -use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError}; -use crate::entity::item::*; +use crate::account::*; +use crate::character::*; +use crate::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError}; +use crate::item::*; +use crate::room::*; use async_std::sync::{Arc, Mutex}; @@ -766,4 +767,21 @@ impl EntityGateway for InMemoryGateway { Err(GatewayError::Error) } } + + // I do not care to replicate this in testing + async fn create_room(&mut self, room: NewRoomEntity) -> Result { + Ok(RoomEntity { + id: RoomEntityId(0), + name: room.name, + section_id: room.section_id, + episode: room.episode, + difficulty: room.difficulty, + mode: room.mode, + }) + } + + // I do not care to replicate this in testing + async fn add_room_note(&mut self, _room_id: RoomEntityId, _note: RoomNote) -> Result<(), GatewayError> { + Ok(()) + } } diff --git a/src/entity/gateway/mod.rs b/src/entity/src/gateway/mod.rs similarity index 100% rename from src/entity/gateway/mod.rs rename to src/entity/src/gateway/mod.rs diff --git a/src/entity/gateway/postgres/migrations/V0001__initial.sql b/src/entity/src/gateway/postgres/migrations/V0001__initial.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0001__initial.sql rename to src/entity/src/gateway/postgres/migrations/V0001__initial.sql diff --git a/src/entity/gateway/postgres/migrations/V0002__equips.sql b/src/entity/src/gateway/postgres/migrations/V0002__equips.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0002__equips.sql rename to src/entity/src/gateway/postgres/migrations/V0002__equips.sql diff --git a/src/entity/gateway/postgres/migrations/V0003__item_notes.sql b/src/entity/src/gateway/postgres/migrations/V0003__item_notes.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0003__item_notes.sql rename to src/entity/src/gateway/postgres/migrations/V0003__item_notes.sql diff --git a/src/entity/gateway/postgres/migrations/V0004__meseta.sql b/src/entity/src/gateway/postgres/migrations/V0004__meseta.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0004__meseta.sql rename to src/entity/src/gateway/postgres/migrations/V0004__meseta.sql diff --git a/src/entity/gateway/postgres/migrations/V0005__trade.sql b/src/entity/src/gateway/postgres/migrations/V0005__trade.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0005__trade.sql rename to src/entity/src/gateway/postgres/migrations/V0005__trade.sql diff --git a/src/entity/gateway/postgres/migrations/V0006__playtime.sql b/src/entity/src/gateway/postgres/migrations/V0006__playtime.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0006__playtime.sql rename to src/entity/src/gateway/postgres/migrations/V0006__playtime.sql diff --git a/src/entity/gateway/postgres/migrations/V0007__player_keyconfig.sql b/src/entity/src/gateway/postgres/migrations/V0007__player_keyconfig.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0007__player_keyconfig.sql rename to src/entity/src/gateway/postgres/migrations/V0007__player_keyconfig.sql diff --git a/src/entity/gateway/postgres/migrations/V0008__playtime_not_null.sql b/src/entity/src/gateway/postgres/migrations/V0008__playtime_not_null.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0008__playtime_not_null.sql rename to src/entity/src/gateway/postgres/migrations/V0008__playtime_not_null.sql diff --git a/src/entity/gateway/postgres/migrations/V0009__no_player_keyconfig.sql b/src/entity/src/gateway/postgres/migrations/V0009__no_player_keyconfig.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0009__no_player_keyconfig.sql rename to src/entity/src/gateway/postgres/migrations/V0009__no_player_keyconfig.sql diff --git a/src/entity/gateway/postgres/migrations/V0010__char_create_timestamp.sql b/src/entity/src/gateway/postgres/migrations/V0010__char_create_timestamp.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0010__char_create_timestamp.sql rename to src/entity/src/gateway/postgres/migrations/V0010__char_create_timestamp.sql diff --git a/src/entity/gateway/postgres/migrations/V0011__shared_bank.sql b/src/entity/src/gateway/postgres/migrations/V0011__shared_bank.sql similarity index 100% rename from src/entity/gateway/postgres/migrations/V0011__shared_bank.sql rename to src/entity/src/gateway/postgres/migrations/V0011__shared_bank.sql diff --git a/src/entity/src/gateway/postgres/migrations/V0012__room.sql b/src/entity/src/gateway/postgres/migrations/V0012__room.sql new file mode 100644 index 0000000..1064ea1 --- /dev/null +++ b/src/entity/src/gateway/postgres/migrations/V0012__room.sql @@ -0,0 +1,14 @@ +create table room ( + id serial primary key not null, + name varchar(32) not null, + section_id char not null, + mode char not null, + episode char not null, + difficulty char not null +); + +create table room_note ( + room integer references room (id) not null, + note jsonb not null, + created_at timestamptz default current_timestamp not null +); diff --git a/src/entity/src/gateway/postgres/migrations/V0013__room2.sql b/src/entity/src/gateway/postgres/migrations/V0013__room2.sql new file mode 100644 index 0000000..f7a6a0a --- /dev/null +++ b/src/entity/src/gateway/postgres/migrations/V0013__room2.sql @@ -0,0 +1,17 @@ +drop table room_note; +drop table room; + +create table room ( + id serial primary key not null, + name varchar(32) not null, + section_id "char" not null, + mode "char" not null, + episode "char" not null, + difficulty "char" not null +); + +create table room_note ( + room integer references room (id) not null, + note jsonb not null, + created_at timestamptz default current_timestamp not null +); diff --git a/src/entity/src/gateway/postgres/migrations/mod.rs b/src/entity/src/gateway/postgres/migrations/mod.rs new file mode 100644 index 0000000..fd67f6f --- /dev/null +++ b/src/entity/src/gateway/postgres/migrations/mod.rs @@ -0,0 +1,3 @@ +use refinery::include_migration_mods; + +include_migration_mods!("src/gateway/postgres/migrations"); diff --git a/src/entity/gateway/postgres/mod.rs b/src/entity/src/gateway/postgres/mod.rs similarity index 100% rename from src/entity/gateway/postgres/mod.rs rename to src/entity/src/gateway/postgres/mod.rs diff --git a/src/entity/gateway/postgres/models.rs b/src/entity/src/gateway/postgres/models.rs similarity index 88% rename from src/entity/gateway/postgres/models.rs rename to src/entity/src/gateway/postgres/models.rs index b017b3b..13c2a6b 100644 --- a/src/entity/gateway/postgres/models.rs +++ b/src/entity/src/gateway/postgres/models.rs @@ -4,10 +4,13 @@ use std::convert::Into; use serde::{Serialize, Deserialize}; use libpso::character::settings; use libpso::util::vec_to_array; -use crate::entity::account::*; -use crate::entity::character::*; -use crate::entity::item::*; -use crate::ship::map::MapArea; +use crate::account::*; +use crate::character::*; +use crate::item::*; +use crate::room::*; +use maps::area::MapArea; +use maps::room::{Episode, Difficulty}; +use maps::monster::MonsterType; #[derive(Debug, sqlx::FromRow)] pub struct PgUserAccount { @@ -577,6 +580,16 @@ pub enum PgItemNoteDetail { }, EnemyDrop { character_id: u32, + room_id: u32, + monster_type: MonsterType, + map_area: MapArea, + x: f32, + y: f32, + z: f32, + }, + BoxDrop { + character_id: u32, + room_id: u32, map_area: MapArea, x: f32, y: f32, @@ -592,14 +605,19 @@ pub enum PgItemNoteDetail { y: f32, z: f32, }, - Consumed, + Consumed { + character_id: u32, + }, FedToMag { + character_id: u32, mag: u32, }, BoughtAtShop { character_id: u32, }, - SoldToShop, + SoldToShop { + character_id: u32, + }, Trade { trade_id: u32, character_to: u32, @@ -612,6 +630,9 @@ pub enum PgItemNoteDetail { Deposit { character_id: u32, bank: BankIdentifier, + }, + FloorLimitReached { + map_area: MapArea, } } @@ -621,8 +642,16 @@ impl From for PgItemNoteDetail { ItemNote::CharacterCreation{character_id} => PgItemNoteDetail::CharacterCreation { character_id: character_id.0, }, - ItemNote::EnemyDrop{character_id, map_area, x, y, z} => PgItemNoteDetail::EnemyDrop { + ItemNote::EnemyDrop{character_id, room_id, monster_type, map_area, x, y, z} => PgItemNoteDetail::EnemyDrop { + character_id: character_id.0, + room_id: room_id.0, + monster_type, + map_area, + x,y,z, + }, + ItemNote::BoxDrop{character_id, room_id, map_area, x, y, z} => PgItemNoteDetail::BoxDrop { character_id: character_id.0, + room_id: room_id.0, map_area, x,y,z, }, @@ -634,14 +663,19 @@ impl From for PgItemNoteDetail { map_area, x,y,z, }, - ItemNote::Consumed => PgItemNoteDetail::Consumed, - ItemNote::FedToMag{mag} => PgItemNoteDetail::FedToMag{ + ItemNote::Consumed{character_id} => PgItemNoteDetail::Consumed { + character_id: character_id.0, + }, + ItemNote::FedToMag{character_id, mag} => PgItemNoteDetail::FedToMag{ + character_id: character_id.0, mag: mag.0 }, ItemNote::BoughtAtShop{character_id} => PgItemNoteDetail::BoughtAtShop { character_id: character_id.0, }, - ItemNote::SoldToShop => PgItemNoteDetail::SoldToShop, + ItemNote::SoldToShop{character_id} => PgItemNoteDetail::SoldToShop { + character_id: character_id.0, + }, ItemNote::Trade{trade_id, character_to, character_from} => PgItemNoteDetail::Trade { trade_id: trade_id.0, character_to: character_to.0, @@ -658,7 +692,12 @@ impl From for PgItemNoteDetail { character_id: character_id.0, bank, } - } + }, + ItemNote::FloorLimitReached { map_area } => { + PgItemNoteDetail::FloorLimitReached { + map_area, + } + }, } } } @@ -669,8 +708,16 @@ impl From for ItemNote { PgItemNoteDetail::CharacterCreation{character_id} => ItemNote::CharacterCreation { character_id: CharacterEntityId(character_id), }, - PgItemNoteDetail::EnemyDrop{character_id, map_area, x, y, z} => ItemNote::EnemyDrop { + PgItemNoteDetail::EnemyDrop{character_id, room_id, monster_type, map_area, x, y, z} => ItemNote::EnemyDrop { + character_id: CharacterEntityId(character_id), + room_id: RoomEntityId(room_id), + monster_type, + map_area, + x,y,z, + }, + PgItemNoteDetail::BoxDrop{character_id, room_id, map_area, x, y, z} => ItemNote::BoxDrop { character_id: CharacterEntityId(character_id), + room_id: RoomEntityId(room_id), map_area, x,y,z, }, @@ -682,14 +729,19 @@ impl From for ItemNote { map_area, x,y,z, }, - PgItemNoteDetail::Consumed => ItemNote::Consumed, - PgItemNoteDetail::FedToMag{mag} => ItemNote::FedToMag{ + PgItemNoteDetail::Consumed{character_id} => ItemNote::Consumed { + character_id: CharacterEntityId(character_id), + }, + PgItemNoteDetail::FedToMag{character_id, mag} => ItemNote::FedToMag{ + character_id: CharacterEntityId(character_id), mag: ItemEntityId(mag) }, PgItemNoteDetail::BoughtAtShop{character_id} => ItemNote::BoughtAtShop { character_id: CharacterEntityId(character_id), }, - PgItemNoteDetail::SoldToShop => ItemNote::SoldToShop, + PgItemNoteDetail::SoldToShop{character_id} => ItemNote::SoldToShop { + character_id: CharacterEntityId(character_id), + }, PgItemNoteDetail::Trade {trade_id, character_to, character_from} => ItemNote::Trade { trade_id: TradeId(trade_id), character_to: CharacterEntityId(character_to), @@ -703,6 +755,9 @@ impl From for ItemNote { character_id: CharacterEntityId(character_id), bank, }, + PgItemNoteDetail::FloorLimitReached { map_area } => ItemNote::FloorLimitReached { + map_area, + }, } } } @@ -869,3 +924,27 @@ impl From for TradeEntity { } } } + + +#[derive(Debug, sqlx::FromRow, Serialize)] +pub struct PgRoomEntity { + id: i32, + name: String, + section_id: i8, + mode: i8, + episode: i8, + difficulty: i8, +} + +impl From for RoomEntity { + fn from(other: PgRoomEntity) -> RoomEntity { + RoomEntity { + id: RoomEntityId(other.id as u32), + name: other.name, + section_id: SectionID::from(other.section_id as u8), + mode: RoomEntityMode::from(other.mode as u8), + episode: Episode::try_from(other.episode as u8).unwrap(), + difficulty: Difficulty::try_from(other.difficulty as u8).unwrap(), + } + } +} diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/src/gateway/postgres/postgres.rs similarity index 92% rename from src/entity/gateway/postgres/postgres.rs rename to src/entity/src/gateway/postgres/postgres.rs index 717f8ca..f1219ba 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/src/gateway/postgres/postgres.rs @@ -1,15 +1,16 @@ // this lint is currently bugged and suggests incorrect code https://github.com/rust-lang/rust-clippy/issues/9123 #![allow(clippy::explicit_auto_deref)] -use std::convert::{From, TryFrom, Into}; +use std::convert::{From, Into}; use futures::future::{Future, BoxFuture}; use futures::stream::{StreamExt, FuturesOrdered}; use async_std::sync::{Arc, Mutex}; use libpso::character::guildcard; -use crate::entity::account::*; -use crate::entity::character::*; -use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError}; -use crate::entity::item::*; +use crate::account::*; +use crate::character::*; +use crate::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError}; +use crate::item::*; +use crate::room::*; use super::models::*; use sqlx::postgres::PgPoolOptions; @@ -18,7 +19,7 @@ use sqlx::Connection; mod embedded { use refinery::embed_migrations; - embed_migrations!("src/entity/gateway/postgres/migrations"); + embed_migrations!("src/gateway/postgres/migrations"); } @@ -178,7 +179,7 @@ async fn create_user(conn: &mut sqlx::PgConnection, user: NewUserAccountEntity) async fn get_user_by_id(conn: &mut sqlx::PgConnection, id: UserAccountId) -> Result { let user = sqlx::query_as::<_, PgUserAccount>("select * from user_accounts where id = $1") - .bind(id.0) + .bind(id.0 as i32) .fetch_one(conn).await?; Ok(user.into()) } @@ -199,8 +200,8 @@ async fn save_user(conn: &mut sqlx::PgConnection, user: &UserAccountEntity) -> R .bind(&user.password) .bind(user.banned_until) .bind(user.muted_until) - .bind(user.flags) - .bind(user.id.0) + .bind(user.flags as i32) + .bind(user.id.0 as i32) .execute(conn).await?; Ok(()) } @@ -209,7 +210,7 @@ async fn create_user_settings(conn: &mut sqlx::PgConnection, settings: NewUserSe { let new_settings = sqlx::query_as::<_, PgUserSettings>("insert into user_settings (user_account, blocked_users, key_config, joystick_config, option_flags, shortcuts, symbol_chats, team_name) values ($1, $2, $3, $4, $5, $6, $7, $8) returning *;") - .bind(settings.user_id.0) + .bind(settings.user_id.0 as i32) .bind(settings.settings.blocked_users.iter().copied().flat_map(|i| i.to_le_bytes().to_vec()).collect::>()) .bind(settings.settings.keyboard_config.to_vec()) .bind(settings.settings.gamepad_config.to_vec()) @@ -224,7 +225,7 @@ async fn create_user_settings(conn: &mut sqlx::PgConnection, settings: NewUserSe async fn get_user_settings_by_user(conn: &mut sqlx::PgConnection, user: &UserAccountEntity) -> Result { let settings = sqlx::query_as::<_, PgUserSettings>("select * from user_settings where user_account = $1") - .bind(user.id.0) + .bind(user.id.0 as i32) .fetch_one(conn).await?; Ok(settings.into()) } @@ -235,11 +236,11 @@ async fn save_user_settings(conn: &mut sqlx::PgConnection, settings: &UserSettin .bind(settings.settings.blocked_users.iter().copied().flat_map(|i| i.to_le_bytes().to_vec()).collect::>()) .bind(&settings.settings.keyboard_config.to_vec()) .bind(&settings.settings.gamepad_config.to_vec()) - .bind(settings.settings.option_flags) + .bind(settings.settings.option_flags as i32) .bind(&settings.settings.shortcuts.to_vec()) .bind(&settings.settings.symbol_chats.to_vec()) .bind(settings.settings.team_name.iter().copied().flat_map(|i| i.to_le_bytes().to_vec()).collect::>()) - .bind(settings.id.0) + .bind(settings.id.0 as i32) .execute(conn).await?; Ok(()) } @@ -262,7 +263,7 @@ async fn create_character(conn: &mut sqlx::PgConnection, char: NewCharacterEntit $26, $27, $28, $29, $30) returning *;"#; let character = sqlx::query_as::<_, PgCharacter>(q) - .bind(char.user_id.0) + .bind(char.user_id.0 as i32) .bind(char.slot as i16) .bind(char.name) .bind(char.exp as i32) @@ -300,7 +301,7 @@ async fn create_character(conn: &mut sqlx::PgConnection, char: NewCharacterEntit async fn get_characters_by_user(conn: &mut sqlx::PgConnection, user: &UserAccountEntity) -> Result<[Option; 4], GatewayError> { let stream = sqlx::query_as::<_, PgCharacter>("select * from player_character where user_account = $1 and slot < 4 order by created_at;") - .bind(user.id.0) + .bind(user.id.0 as i32) .fetch(conn); Ok(stream.fold(core::array::from_fn(|_| None), |mut acc, char| async move { @@ -320,7 +321,7 @@ async fn save_character(conn: &mut sqlx::PgConnection, char: &CharacterEntity) - evade=$24, luck=$25, hp=$26, tp=$27, tech_menu=$28, option_flags=$29, playtime=$30 where id=$31;"#; sqlx::query(q) - .bind(char.user_id.0) // $1 + .bind(char.user_id.0 as i32) // $1 .bind(char.slot as i16) // $2 .bind(&char.name) // $3 .bind(char.exp as i32) // $4 @@ -370,7 +371,7 @@ async fn create_item(conn: &mut sqlx::PgConnection, item: NewItemEntity) -> Resu async fn add_item_note(conn: &mut sqlx::PgConnection, item_id: &ItemEntityId, item_note: ItemNote) -> Result<(), GatewayError> { sqlx::query("insert into item_note(item, note) values ($1, $2)") - .bind(item_id.0) + .bind(item_id.0 as i32) .bind(sqlx::types::Json(PgItemNoteDetail::from(item_note))) .execute(conn).await?; Ok(()) @@ -379,7 +380,7 @@ async fn add_item_note(conn: &mut sqlx::PgConnection, item_id: &ItemEntityId, it async fn feed_mag(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) -> Result<(), GatewayError> { sqlx::query("insert into mag_modifier (mag, modifier) values ($1, $2);") - .bind(mag_item_id.0) + .bind(mag_item_id.0 as i32) .bind(sqlx::types::Json(PgMagModifierDetail::from(mag::MagModifier::FeedMag{food: *tool_item_id}))) .execute(conn).await?; Ok(()) @@ -388,7 +389,7 @@ async fn feed_mag(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId, too async fn change_mag_owner(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId, character: &CharacterEntity) -> Result<(), GatewayError> { sqlx::query("insert into mag_modifier (mag, modifier) values ($1, $2);") - .bind(mag_item_id.0) + .bind(mag_item_id.0 as i32) .bind(sqlx::types::Json(PgMagModifierDetail::from(mag::MagModifier::OwnerChange(character.char_class, character.section_id)))) .execute(conn).await?; Ok(()) @@ -397,7 +398,7 @@ async fn change_mag_owner(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntit async fn use_mag_cell(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) -> Result<(), GatewayError> { sqlx::query("insert into mag_modifier (mag, modifier) values ($1, $2);") - .bind(mag_item_id.0) + .bind(mag_item_id.0 as i32) .bind(sqlx::types::Json(PgMagModifierDetail::from(mag::MagModifier::MagCell(*mag_cell_id)))) .execute(conn).await?; Ok(()) @@ -406,7 +407,7 @@ async fn use_mag_cell(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId, async fn add_weapon_modifier(conn: &mut sqlx::PgConnection, item_id: &ItemEntityId, modifier: &weapon::WeaponModifier) -> Result<(), GatewayError> { sqlx::query("insert into weapon_modifier (weapon, modifier) values ($1, $2);") - .bind(item_id.0) + .bind(item_id.0 as i32) .bind(sqlx::types::Json(modifier)) .execute(conn).await?; Ok(()) @@ -416,7 +417,7 @@ async fn get_character_inventory(conn: &mut sqlx::PgConnection, char_id: &Charac { let conn = Arc::new(Mutex::new(conn.begin().await?)); // this is some degen shit let inventory = sqlx::query_as::<_, PgInventoryEntity>("select * from inventory where pchar = $1") - .bind(char_id.0) + .bind(char_id.0 as i32) .fetch_one(&mut **conn.lock().await).await?; Ok(InventoryEntity::new( @@ -441,14 +442,14 @@ async fn get_character_bank(conn: &mut sqlx::PgConnection, char_id: &CharacterEn let bank = match bank_identifier { BankIdentifier::Character => { sqlx::query_as::<_, PgInventoryEntity>("select * from bank where pchar = $1") - .bind(char_id.0) + .bind(char_id.0 as i32) .fetch_one(&mut **conn.lock().await).await? }, BankIdentifier::Shared(bank_name) => { sqlx::query_as::<_, PgInventoryEntity>("select player_character.id as pchar, shared_bank.items as items from shared_bank join player_character on shared_bank.user_account = player_character.user_account where player_character.id = $1 and shared_bank.name = $2") - .bind(char_id.0) + .bind(char_id.0 as i32) .bind(&bank_name.0) .fetch_optional(&mut **conn.lock().await) .await? @@ -491,7 +492,7 @@ async fn set_character_inventory(conn: &mut sqlx::PgConnection, char_id: &Charac .collect::>(); sqlx::query("insert into inventory (pchar, items) values ($1, $2) on conflict (pchar) do update set items = $2") - .bind(char_id.0) + .bind(char_id.0 as i32) .bind(sqlx::types::Json(inventory)) .execute(conn) .await?; @@ -516,7 +517,7 @@ async fn set_character_bank(conn: &mut sqlx::PgConnection, char_id: &CharacterEn match bank_identifier { BankIdentifier::Character => { sqlx::query("insert into bank (pchar, items, name) values ($1, $2, '') on conflict (pchar, name) do update set items = $2") - .bind(char_id.0) + .bind(char_id.0 as i32) .bind(sqlx::types::Json(bank)) .execute(conn) .await?; @@ -526,7 +527,7 @@ async fn set_character_bank(conn: &mut sqlx::PgConnection, char_id: &CharacterEn select player_character.user_account, $2, $3 from player_character where player_character.id = $1 on conflict (user_account, name) do update set items = $2;") - .bind(char_id.0) + .bind(char_id.0 as i32) .bind(sqlx::types::Json(bank)) .bind(&bank_name.0) .execute(conn) @@ -539,7 +540,7 @@ async fn set_character_bank(conn: &mut sqlx::PgConnection, char_id: &CharacterEn async fn get_character_equips(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId) -> Result { let equips = sqlx::query_as::<_, PgEquipped>("select * from equipped where pchar = $1") - .bind(char_id.0) + .bind(char_id.0 as i32) .fetch_one(conn) .await?; @@ -550,7 +551,7 @@ async fn set_character_equips(conn: &mut sqlx::PgConnection, char_id: &Character { sqlx::query(r#"insert into equipped (pchar, weapon, armor, shield, unit0, unit1, unit2, unit3, mag) values ($1, $2, $3, $4, $5, $6, $7, $8, $9) on conflict (pchar) do update set weapon=$2, armor=$3, shield=$4, unit0=$5, unit1=$6, unit2=$7, unit3=$8, mag=$9"#) - .bind(char_id.0) + .bind(char_id.0 as i32) .bind(equips.weapon.map(|i| i.0 as i32)) .bind(equips.armor.map(|i| i.0 as i32)) .bind(equips.shield.map(|i| i.0 as i32)) @@ -568,7 +569,7 @@ async fn set_character_equips(conn: &mut sqlx::PgConnection, char_id: &Character async fn set_character_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, meseta: Meseta) -> Result<(), GatewayError> { sqlx::query("insert into character_meseta values ($1, $2) on conflict (pchar) do update set meseta = $2") - .bind(char_id.0) + .bind(char_id.0 as i32) .bind(meseta.0 as i32) .execute(conn) .await?; @@ -580,7 +581,7 @@ async fn get_character_meseta(conn: &mut sqlx::PgConnection, char_id: &Character #[derive(sqlx::FromRow)] struct PgMeseta(i32); let meseta = sqlx::query_as::<_, PgMeseta>(r#"select meseta from character_meseta where pchar = $1"#) - .bind(char_id.0) + .bind(char_id.0 as i32) .fetch_one(conn) .await?; Ok(Meseta(meseta.0 as u32)) @@ -591,7 +592,7 @@ async fn set_bank_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntit match bank_identifier { BankIdentifier::Character => { sqlx::query("insert into bank_meseta values ($1, '', $2) on conflict (pchar, bank) do update set meseta = $2") - .bind(char_id.0) + .bind(char_id.0 as i32) .bind(meseta.0 as i32) .execute(conn) .await?; @@ -601,7 +602,7 @@ async fn set_bank_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntit select player_character.user_account, $2, $3 from player_character where player_character.id = $1 on conflict (user_account, name) do update set meseta = $3") - .bind(char_id.0) + .bind(char_id.0 as i32) .bind(&bank_name.0) .bind(meseta.0 as i32) .execute(conn) @@ -620,7 +621,7 @@ async fn get_bank_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntit let meseta = match bank_identifier { BankIdentifier::Character => { sqlx::query_as::<_, PgMeseta>(r#"select meseta from bank_meseta where pchar = $1"#) - .bind(char_id.0) + .bind(char_id.0 as i32) .fetch_one(conn) .await? }, @@ -628,7 +629,7 @@ async fn get_bank_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntit sqlx::query_as::<_, PgMeseta>(r#"select shared_bank_meseta.meseta from shared_bank_meseta join player_character on shared_bank_meseta.user_account = player_character.user_account where player_character.id = $1 and shared_bank_meseta.name = $2"#) - .bind(char_id.0) + .bind(char_id.0 as i32) .bind(&bank_name.0) .fetch_optional(conn) .await? @@ -641,8 +642,8 @@ async fn get_bank_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntit async fn create_trade(conn: &mut sqlx::PgConnection, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result { let trade = sqlx::query_as::<_, PgTradeEntity>(r#"insert into trades (character1, character2) values ($1, $2) returning *;"#) - .bind(char_id1.0) - .bind(char_id2.0) + .bind(char_id1.0 as i32) + .bind(char_id2.0 as i32) .fetch_one(conn) .await?; Ok(trade.into()) @@ -651,8 +652,30 @@ async fn create_trade(conn: &mut sqlx::PgConnection, char_id1: &CharacterEntityI async fn set_character_playtime(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> { sqlx::query(r#"update player_character set playtime=$2 where id=$1;"#) - .bind(char_id.0) - .bind(playtime) + .bind(char_id.0 as i32) + .bind(playtime as i32) + .execute(conn) + .await?; + Ok(()) +} + +async fn create_room(conn: &mut sqlx::PgConnection, room: NewRoomEntity) -> Result { + sqlx::query_as::<_, PgRoomEntity>("insert into room (name, section_id, mode, episode, difficulty) values ($1, $2, $3, $4, $5) returning *") + .bind(room.name) + .bind(u8::from(room.section_id) as i8) + .bind(u8::from(room.mode) as i8) + .bind(u8::from(room.episode) as i8) + .bind(u8::from(room.difficulty) as i8) + .fetch_one(conn) + .await + .map(|room| room.into()) + .map_err(|err| err.into()) +} + +async fn add_room_note(conn: &mut sqlx::PgConnection, room_id: RoomEntityId, note: RoomNote) -> Result<(), GatewayError> { + sqlx::query("insert into room_note (room, note) values ($1, $2)") + .bind(room_id.0 as i32) + .bind(sqlx::types::Json(note)) .execute(conn) .await?; Ok(()) @@ -797,6 +820,14 @@ impl EntityGateway for PostgresGateway { async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> { set_character_playtime(&mut *self.pool.acquire().await?, char_id, playtime).await } + + async fn create_room(&mut self, room: NewRoomEntity) -> Result { + create_room(&mut *self.pool.acquire().await?, room).await + } + + async fn add_room_note(&mut self, room_id: RoomEntityId, note: RoomNote) -> Result<(), GatewayError> { + add_room_note(&mut *self.pool.acquire().await?, room_id, note).await + } } @@ -923,5 +954,13 @@ impl<'c> EntityGateway for PostgresTransaction<'c> { async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> { set_character_playtime(&mut *self.pgtransaction.lock().await, char_id, playtime).await } + + async fn create_room(&mut self, room: NewRoomEntity) -> Result { + create_room(&mut *self.pgtransaction.lock().await, room).await + } + + async fn add_room_note(&mut self, room_id: RoomEntityId, note: RoomNote) -> Result<(), GatewayError> { + add_room_note(&mut *self.pgtransaction.lock().await, room_id, note).await + } } diff --git a/src/entity/item/armor.rs b/src/entity/src/item/armor.rs similarity index 99% rename from src/entity/item/armor.rs rename to src/entity/src/item/armor.rs index 45e9ed4..bd0cc48 100644 --- a/src/entity/item/armor.rs +++ b/src/entity/src/item/armor.rs @@ -1,5 +1,5 @@ use serde::{Serialize, Deserialize}; -use crate::entity::item::ItemEntityId; +use crate::item::ItemEntityId; #[derive(Debug, Copy, Clone)] pub enum ItemParseError { diff --git a/src/entity/item/esweapon.rs b/src/entity/src/item/esweapon.rs similarity index 100% rename from src/entity/item/esweapon.rs rename to src/entity/src/item/esweapon.rs diff --git a/src/entity/item/mag.rs b/src/entity/src/item/mag.rs similarity index 99% rename from src/entity/item/mag.rs rename to src/entity/src/item/mag.rs index 17fa1b4..45d424a 100644 --- a/src/entity/item/mag.rs +++ b/src/entity/src/item/mag.rs @@ -1,9 +1,9 @@ -use thiserror::Error; use std::collections::HashMap; +use thiserror::Error; use serde::{Serialize, Deserialize}; -use crate::entity::item::tool::ToolType; -use crate::entity::character::{CharacterClass, SectionID}; -use crate::entity::item::ItemEntityId; +use crate::item::tool::ToolType; +use crate::character::{CharacterClass, SectionID}; +use crate::item::ItemEntityId; use std::io::Read; use std::cmp::Ordering::{Less, Greater, Equal}; diff --git a/src/entity/item/mod.rs b/src/entity/src/item/mod.rs similarity index 83% rename from src/entity/item/mod.rs rename to src/entity/src/item/mod.rs index 6b7bf53..d418579 100644 --- a/src/entity/item/mod.rs +++ b/src/entity/src/item/mod.rs @@ -9,9 +9,11 @@ pub mod mag; pub mod esweapon; use serde::{Serialize, Deserialize}; -use crate::entity::character::CharacterEntityId; -use crate::ship::map::MapArea; -use crate::ship::drops::ItemDropType; +use crate::character::CharacterEntityId; +use crate::room::RoomEntityId; +use maps::area::MapArea; +use maps::monster::MonsterType; +//use crate::ship::drops::ItemDropType; #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)] pub struct ItemEntityId(pub u32); @@ -35,8 +37,16 @@ pub enum ItemNote { }, EnemyDrop { character_id: CharacterEntityId, - //monster_type: MonsterType, - //droprate: f32, + room_id: RoomEntityId, + monster_type: MonsterType, + map_area: MapArea, + x: f32, + y: f32, + z: f32, + }, + BoxDrop { + character_id: CharacterEntityId, + room_id: RoomEntityId, map_area: MapArea, x: f32, y: f32, @@ -52,15 +62,19 @@ pub enum ItemNote { y: f32, z: f32, }, - Consumed, // TODO: character_id + Consumed { + character_id: CharacterEntityId, + }, FedToMag { - //character_id: CharacterEntityId, + character_id: CharacterEntityId, mag: ItemEntityId, }, BoughtAtShop { character_id: CharacterEntityId, }, - SoldToShop, + SoldToShop { + character_id: CharacterEntityId, + }, Trade { trade_id: TradeId, character_to: CharacterEntityId, @@ -74,6 +88,9 @@ pub enum ItemNote { character_id: CharacterEntityId, bank: BankIdentifier, }, + FloorLimitReached { + map_area: MapArea, + }, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -139,26 +156,6 @@ impl ItemDetail { } } - pub fn parse_item_from_bytes(data: [u8; 16]) -> Option { - let item_type = weapon::WeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::Weapon) - .or_else(|_| armor::ArmorType::parse_type([data[0],data[1],data[2]]).map(ItemType::Armor)) - .or_else(|_| shield::ShieldType::parse_type([data[0],data[1],data[2]]).map(ItemType::Shield)) - .or_else(|_| unit::UnitType::parse_type([data[0],data[1],data[2]]).map(ItemType::Unit)) - .or_else(|_| mag::MagType::parse_type([data[0],data[1],data[2]]).map(ItemType::Mag)) - .or_else(|_| tool::ToolType::parse_type([data[0],data[1],data[2]]).map(ItemType::Tool)) - .or_else(|_| esweapon::ESWeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::ESWeapon)).ok()?; - - match item_type { - ItemType::Weapon(_w) => Some(ItemDropType::Weapon(weapon::Weapon::from_bytes(data).ok()?)), - ItemType::Armor(_a) => Some(ItemDropType::Armor(armor::Armor::from_bytes(data).ok()?)), - ItemType::Shield(_s) => Some(ItemDropType::Shield(shield::Shield::from_bytes(data).ok()?)), - ItemType::Unit(_u) => Some(ItemDropType::Unit(unit::Unit::from_bytes(data).ok()?)), - ItemType::Mag(_m) => Some(ItemDropType::Mag(mag::Mag::from_bytes(data).ok()?)), - ItemType::Tool(_t) => Some(ItemDropType::Tool(tool::Tool::from_bytes(data).ok()?)), - _ => None, - } - } - pub fn as_client_bytes(&self) -> [u8; 16] { match self { ItemDetail::Weapon(w) => w.as_bytes(), diff --git a/src/entity/item/shield.rs b/src/entity/src/item/shield.rs similarity index 100% rename from src/entity/item/shield.rs rename to src/entity/src/item/shield.rs diff --git a/src/entity/item/tech.rs b/src/entity/src/item/tech.rs similarity index 100% rename from src/entity/item/tech.rs rename to src/entity/src/item/tech.rs diff --git a/src/entity/item/tool.rs b/src/entity/src/item/tool.rs similarity index 100% rename from src/entity/item/tool.rs rename to src/entity/src/item/tool.rs diff --git a/src/entity/item/unit.rs b/src/entity/src/item/unit.rs similarity index 100% rename from src/entity/item/unit.rs rename to src/entity/src/item/unit.rs diff --git a/src/entity/item/weapon.rs b/src/entity/src/item/weapon.rs similarity index 99% rename from src/entity/item/weapon.rs rename to src/entity/src/item/weapon.rs index 29a9357..a5753d6 100644 --- a/src/entity/item/weapon.rs +++ b/src/entity/src/item/weapon.rs @@ -1,4 +1,4 @@ -use crate::entity::item::ItemEntityId; +use crate::item::ItemEntityId; use serde::{Serialize, Deserialize}; #[derive(Debug, Copy, Clone)] diff --git a/src/entity/mod.rs b/src/entity/src/lib.rs similarity index 82% rename from src/entity/mod.rs rename to src/entity/src/lib.rs index ba0b6e4..8970e37 100644 --- a/src/entity/mod.rs +++ b/src/entity/src/lib.rs @@ -2,3 +2,4 @@ pub mod gateway; pub mod account; pub mod character; pub mod item; +pub mod room; diff --git a/src/entity/src/room.rs b/src/entity/src/room.rs new file mode 100644 index 0000000..30d3b6b --- /dev/null +++ b/src/entity/src/room.rs @@ -0,0 +1,83 @@ +use serde::{Serialize, Deserialize}; + + +use crate::character::{CharacterEntityId, SectionID}; +use maps::room::{Episode, Difficulty}; + + +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)] +pub struct RoomEntityId(pub u32); + + +#[derive(Debug, Copy, Clone)] +pub enum RoomEntityMode { + Multi, + Single, + Challenge, + Battle, +} + +impl From for RoomEntityMode { + fn from(other: u8) -> RoomEntityMode { + match other { + 0 => RoomEntityMode::Multi, + 1 => RoomEntityMode::Single, + 2 => RoomEntityMode::Challenge, + 3 => RoomEntityMode::Battle, + _ => unreachable!() + } + } +} + +impl From for u8 { + fn from(other: RoomEntityMode) -> u8 { + match other { + RoomEntityMode::Multi => 0, + RoomEntityMode::Single => 1, + RoomEntityMode::Challenge => 2, + RoomEntityMode::Battle => 3, + } + } +} + + +#[derive(Debug, Clone)] +pub struct RoomEntity { + pub id: RoomEntityId, + pub name: String, + pub section_id: SectionID, + pub mode: RoomEntityMode, + pub episode: Episode, + pub difficulty: Difficulty, +} + + + +#[derive(Debug, Clone)] +pub struct NewRoomEntity { + pub name: String, + pub section_id: SectionID, + pub mode: RoomEntityMode, + pub episode: Episode, + pub difficulty: Difficulty, +} + +#[derive(Debug, Copy, Clone, Serialize)] +pub enum RoomNote { + Create { + character_id: CharacterEntityId, + }, + PlayerJoin { + character_id: CharacterEntityId, + }, + PlayerLeave { + character_id: CharacterEntityId, + }, + QuestStart { + // quest id + }, + QuestComplete { + // quest id + }, + +} diff --git a/src/entity/src/team.rs b/src/entity/src/team.rs new file mode 100644 index 0000000..2a5bfac --- /dev/null +++ b/src/entity/src/team.rs @@ -0,0 +1,31 @@ +use serde::{Serialize, Deserialize}; + +use super::account::UserAccountId; + +// [2022-10-23 00:11:18][elseware::common::mainloop::client][WARN] error RecvServerPacket::from_bytes: WrongPacketForServerType(490, [40, 0, 234, 1, 0, 0, 0, 0, 9, 0, 74, 0, 97, 0, 115, 0, 100, 0, 102, 0, 0, 0, 0, 0, 192, 52, 67, 3, 60, 159, 129, 0, 32, 64, 233, 10, 196, 156, 152, 0]) +// [2022-10-23 00:20:14][elseware::common::mainloop::client][WARN] error RecvServerPacket::from_bytes: WrongPacketForServerType(490, [40, 0, 234, 1, 0, 0, 0, 0, 9, 0, 74, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 0, 0, 152, 0]) + + +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)] +pub struct TeamEntityId(pub u32); + +pub struct NewTeamEntity { + pub created_by: UserAccountId, + pub name: String, +} + + +#[derive(Debug, Clone)] +pub struct TeamEntity { + pub id: TeamEntityId, + pub owner: UserAccountId, + pub name: String, + + pub team_flag: [u8; 2048], +} + + + + + + diff --git a/src/items/Cargo.toml b/src/items/Cargo.toml new file mode 100644 index 0000000..84ce90c --- /dev/null +++ b/src/items/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "items" +version = "0.1.0" +edition = "2021" + +[dependencies] +entity = { workspace = true } +maps = { workspace = true } +shops = { workspace = true } +location = { workspace = true } +drops = { workspace = true } + +libpso = { workspace = true } + +enum-utils = { workspace = true } +derive_more = { workspace = true } +serde = { workspace = true } +rand = { workspace = true } +rand_chacha = { workspace = true } +async-recursion = { workspace = true } +async-std = { workspace = true } +async-trait = { workspace = true } +futures = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } \ No newline at end of file diff --git a/src/ship/items/actions.rs b/src/items/src/actions.rs similarity index 88% rename from src/ship/items/actions.rs rename to src/items/src/actions.rs index f9844bb..0b55d6d 100644 --- a/src/ship/items/actions.rs +++ b/src/items/src/actions.rs @@ -1,6 +1,6 @@ // TODO: replace various u32s and usizes denoting item amounts for ItemAmount(u32) for consistency -use crate::ship::items::ClientItemId; -use crate::entity::item::{Meseta, ItemNote}; +use crate::ClientItemId; +use entity::item::{Meseta, ItemNote}; use async_std::sync::Arc; use std::future::Future; use futures::future::BoxFuture; @@ -8,29 +8,33 @@ use std::pin::Pin; use std::iter::IntoIterator; use anyhow::Context; -use libpso::packet::{ship::Message, messages::GameMessage}; -use crate::ship::map::MapArea; -use crate::ship::ship::SendShipPacket; -use crate::entity::character::{CharacterEntity, CharacterEntityId}; -use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; -use crate::ship::items::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail}; -use crate::ship::items::bank::{BankItem, BankItemDetail}; -use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; -use crate::ship::items::floor::{FloorItem, FloorItemDetail}; -use crate::ship::items::apply_item::{apply_item, ApplyItemAction}; -use crate::entity::item::{ItemDetail, NewItemEntity, TradeId}; -use crate::entity::item::tool::Tool; -use crate::entity::item::ItemModifier; -use crate::ship::shops::ShopItem; -use crate::ship::drops::{ItemDrop, ItemDropType}; -use crate::ship::packet::builder; -use crate::ship::location::AreaClient; +use entity::character::{CharacterEntity, CharacterEntityId}; +use entity::gateway::{EntityGateway, EntityGatewayTransaction}; +use entity::item::{ItemDetail, NewItemEntity, TradeId, ItemModifier}; +use entity::item::tool::Tool; +use entity::room::RoomEntityId; +use maps::area::MapArea; +use crate::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail}; +use crate::bank::{BankItem, BankItemDetail}; +use crate::inventory::{InventoryItem, InventoryItemDetail}; +use crate::floor::{FloorItem, FloorItemDetail}; +use crate::apply_item::{apply_item, ApplyItemAction}; +use shops::ShopItem; +use drops::{ItemDrop, ItemDropType}; +use location::AreaClient; +use maps::monster::MonsterType; pub enum TriggerCreateItem { Yes, No } +#[derive(Clone)] +pub enum CreateItem { + Individual(AreaClient, ClientItemId, IndividualItemDetail), + Stacked(AreaClient, ClientItemId, Tool, usize), +} + pub(super) fn take_item_from_floor<'a, EG, TR>( character_id: CharacterEntityId, item_id: ClientItemId @@ -513,7 +517,9 @@ where Box::pin(async move { let mut transaction = inventory_item.with_entity_id(transaction, |mut transaction, entity_id| { async move { - transaction.gateway().add_item_note(&entity_id, ItemNote::Consumed).await?; + transaction.gateway().add_item_note(&entity_id, ItemNote::Consumed { + character_id: character.id, + }).await?; Ok(transaction) }}).await?; @@ -548,7 +554,7 @@ where let mut transaction = tool.with_entity_id(transaction, |mut transaction, entity_id| { async move { transaction.gateway().add_item_note(&entity_id, ItemNote::FedToMag { - //character_id: character.id, + character_id: character.id, mag: mag_entity_id, }).await?; transaction.gateway().feed_mag(&mag_entity_id, &entity_id).await?; @@ -660,7 +666,9 @@ where let mut transaction = inventory_item.with_entity_id(transaction, |mut transaction, entity_id| { async move { - transaction.gateway().add_item_note(&entity_id, ItemNote::SoldToShop).await?; + transaction.gateway().add_item_note(&entity_id, ItemNote::SoldToShop { + character_id, + }).await?; Ok(transaction) }}).await?; transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; @@ -904,7 +912,6 @@ where pub(super) fn convert_item_drop_to_floor_item<'a, EG, TR>( - character_id: CharacterEntityId, item_drop: ItemDrop, ) -> impl Fn((ItemStateProxy, TR), ()) -> BoxFuture<'a, Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>> + Clone @@ -946,13 +953,6 @@ where let entity = transaction.gateway().create_item(NewItemEntity { item: item_detail.clone(), }).await?; - transaction.gateway().add_item_note(&entity.id, ItemNote::EnemyDrop { - character_id, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }).await?; FloorItem { item_id, item: FloorItemDetail::Individual(IndividualItemDetail { @@ -969,13 +969,6 @@ where let entity = transaction.gateway().create_item(NewItemEntity { item: ItemDetail::Tool(tool), }).await?; - transaction.gateway().add_item_note(&entity.id, ItemNote::EnemyDrop { - character_id, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }).await?; FloorItem { item_id, item: FloorItemDetail::Stacked(StackedItemDetail{ @@ -1005,6 +998,88 @@ where } } + +pub(super) fn item_note_enemy_drop<'a, EG, TR>( + character_id: CharacterEntityId, + room_id: RoomEntityId, + monster_type: MonsterType, +) -> impl Fn((ItemStateProxy, TR), FloorItem) + -> BoxFuture<'a, Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>> + Clone +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'a, +{ + move |(item_state, mut transaction), floor_item| { + Box::pin(async move { + match &floor_item.item { + FloorItemDetail::Individual(individual) => { + transaction.gateway().add_item_note(&individual.entity_id, ItemNote::EnemyDrop { + character_id, + room_id, + monster_type, + map_area: floor_item.map_area, + x: floor_item.x, + y: floor_item.y, + z: floor_item.z, + }).await?; + }, + FloorItemDetail::Stacked(stacked) => { + transaction.gateway().add_item_note(&stacked.entity_ids[0], ItemNote::EnemyDrop { + character_id, + room_id, + monster_type, + map_area: floor_item.map_area, + x: floor_item.x, + y: floor_item.y, + z: floor_item.z, + }).await?; + }, + _ => {}, + } + Ok(((item_state, transaction), floor_item)) + }) + } +} + +pub(super) fn item_note_box_drop<'a, EG, TR>( + character_id: CharacterEntityId, + room_id: RoomEntityId, +) -> impl Fn((ItemStateProxy, TR), FloorItem) + -> BoxFuture<'a, Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>> + Clone +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'a, +{ + move |(item_state, mut transaction), floor_item| { + Box::pin(async move { + match &floor_item.item { + FloorItemDetail::Individual(individual) => { + transaction.gateway().add_item_note(&individual.entity_id, ItemNote::BoxDrop { + character_id, + room_id, + map_area: floor_item.map_area, + x: floor_item.x, + y: floor_item.y, + z: floor_item.z, + }).await?; + }, + FloorItemDetail::Stacked(stacked) => { + transaction.gateway().add_item_note(&stacked.entity_ids[0], ItemNote::BoxDrop { + character_id, + room_id, + map_area: floor_item.map_area, + x: floor_item.x, + y: floor_item.y, + z: floor_item.z, + }).await?; + }, + _ => {}, + } + Ok(((item_state, transaction), floor_item)) + }) + } +} + pub(super) fn add_item_to_local_floor<'a, EG, TR>( character_id: CharacterEntityId, ) -> impl Fn((ItemStateProxy, TR), FloorItem) @@ -1072,7 +1147,7 @@ pub(super) fn apply_item_action_packets<'a, EG, TR>( character_id: CharacterEntityId, area_client: AreaClient, ) -> impl Fn((ItemStateProxy, TR), ApplyItemAction) - -> BoxFuture<'a, Result<((ItemStateProxy, TR), Vec), anyhow::Error>> + -> BoxFuture<'a, Result<((ItemStateProxy, TR), Vec), anyhow::Error>> where EG: EntityGateway, TR: EntityGatewayTransaction + 'a, @@ -1089,7 +1164,7 @@ where let (inventory_item_detail, create_item) = if item_detail.is_stackable() { let tool = item_detail.as_tool().ok_or_else(|| ItemStateError::NotATool(ClientItemId(0xFFFFFFFF)))?; - let create_item = builder::message::create_stacked_item(area_client, item_id, &tool, 1).map_err(|_err| ItemStateError::Dummy)?; + let create_item = CreateItem::Stacked(area_client, item_id, tool, 1); let item_detail = StackedItemDetail { entity_ids: vec![new_item.id], tool @@ -1101,7 +1176,7 @@ where entity_id: new_item.id, item: item_detail, }; - let create_item = builder::message::create_individual_item(area_client, item_id, &item_detail).map_err(|_err| ItemStateError::Dummy)?; + let create_item = CreateItem::Individual(area_client, item_id, item_detail.clone()); (InventoryItemDetail::Individual(item_detail), create_item) }; @@ -1115,7 +1190,8 @@ where transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; item_state.set_inventory(inventory).await; - vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item)))] + //vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item)))] + vec![create_item] } else { Vec::new() @@ -1148,3 +1224,25 @@ where }) } } + +pub(super) fn delete_item_from_floor<'a, EG, TR>( + map_area: MapArea +) -> impl Fn((ItemStateProxy, TR), FloorItem) + -> BoxFuture<'a, Result<((ItemStateProxy, TR), ()), anyhow::Error>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + Clone + 'a, +{ + move |(item_state, transaction), floor_item| { + Box::pin(async move { + let transaction = floor_item.with_entity_id(transaction, |mut transaction, entity_id| { + async move { + transaction.gateway().add_item_note(&entity_id, ItemNote::FloorLimitReached { + map_area + }).await?; + Ok(transaction) + }}).await?; + Ok(((item_state, transaction), ())) + }) + } +} diff --git a/src/ship/items/apply_item.rs b/src/items/src/apply_item.rs similarity index 96% rename from src/ship/items/apply_item.rs rename to src/items/src/apply_item.rs index 4c1a636..0f74627 100644 --- a/src/ship/items/apply_item.rs +++ b/src/items/src/apply_item.rs @@ -4,15 +4,15 @@ use thiserror::Error; use anyhow::Context; use rand::SeedableRng; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::character::{CharacterEntity, TechLevel}; -use crate::entity::item::mag::{MagCell, MagCellError}; -use crate::entity::item::tool::{Tool, ToolType}; -use crate::entity::item::tech::TechniqueDisk; -use crate::entity::item::{ItemDetail, ItemEntityId}; -use crate::entity::item::weapon::WeaponModifier; -use crate::ship::items::state::ItemStateProxy; -use crate::ship::items::inventory::InventoryItemDetail; +use entity::gateway::{EntityGateway, GatewayError}; +use entity::character::{CharacterEntity, TechLevel}; +use entity::item::mag::{MagCell, MagCellError}; +use entity::item::tool::{Tool, ToolType}; +use entity::item::tech::TechniqueDisk; +use entity::item::{ItemDetail, ItemEntityId}; +use entity::item::weapon::WeaponModifier; +use crate::state::ItemStateProxy; +use crate::inventory::InventoryItemDetail; #[derive(Error, Debug)] @@ -226,7 +226,7 @@ pub async fn liberta_kit(entity_gateway: &mut EG, used_cell: fn jack_o_lantern() -> Result, anyhow::Error> { - let mag_rate = WeightedIndex::new(&[13, 13, 13, 13, 12, 12, 12, 12]).unwrap(); + let mag_rate = WeightedIndex::new([13, 13, 13, 13, 12, 12, 12, 12]).unwrap(); let mag_type = match mag_rate.sample(&mut rand_chacha::ChaChaRng::from_entropy()) { 0 => ToolType::CellOfMag502, 1 => ToolType::CellOfMag213, diff --git a/src/ship/items/bank.rs b/src/items/src/bank.rs similarity index 93% rename from src/ship/items/bank.rs rename to src/items/src/bank.rs index 73f0e10..e68700a 100644 --- a/src/ship/items/bank.rs +++ b/src/items/src/bank.rs @@ -1,15 +1,15 @@ use std::cmp::Ordering; use libpso::character::character; -use crate::ship::items::ClientItemId; -use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity}; +use crate::ClientItemId; +use entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity}; use std::future::Future; use async_std::sync::{Arc, Mutex}; -use crate::entity::character::CharacterEntityId; -use crate::entity::item::BankIdentifier; -use crate::ship::items::state::ItemStateError; -use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult}; -use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; +use entity::character::CharacterEntityId; +use entity::item::BankIdentifier; +use crate::state::ItemStateError; +use crate::state::{IndividualItemDetail, StackedItemDetail, AddItemResult}; +use crate::inventory::{InventoryItem, InventoryItemDetail}; #[derive(thiserror::Error, Debug)] @@ -325,15 +325,7 @@ impl std::cmp::Eq for BankItemDetail {} impl std::cmp::PartialOrd for BankItemDetail { fn partial_cmp(&self, other: &BankItemDetail) -> Option { - let mut self_bytes = [0u8; 4]; - let mut other_bytes = [0u8; 4]; - self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]); - other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]); - - let self_value = u32::from_be_bytes(self_bytes); - let other_value = u32::from_be_bytes(other_bytes); - - self_value.partial_cmp(&other_value) + Some(self.cmp(other)) } } @@ -344,8 +336,8 @@ impl std::cmp::Ord for BankItemDetail { self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]); other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]); - let self_value = u32::from_le_bytes(self_bytes); - let other_value = u32::from_le_bytes(other_bytes); + let self_value = u32::from_be_bytes(self_bytes); + let other_value = u32::from_be_bytes(other_bytes); self_value.cmp(&other_value) } @@ -362,7 +354,7 @@ impl std::cmp::Eq for BankItem {} impl std::cmp::PartialOrd for BankItem { fn partial_cmp(&self, other: &BankItem) -> Option { - self.item.partial_cmp(&other.item) + Some(self.cmp(other)) } } diff --git a/src/ship/items/floor.rs b/src/items/src/floor.rs similarity index 88% rename from src/ship/items/floor.rs rename to src/items/src/floor.rs index c71b7fd..29b79fa 100644 --- a/src/ship/items/floor.rs +++ b/src/items/src/floor.rs @@ -1,14 +1,14 @@ -use crate::ship::items::ClientItemId; -use crate::entity::item::{Meseta, ItemEntityId, ItemDetail}; +use crate::ClientItemId; +use entity::item::{Meseta, ItemEntityId, ItemDetail}; use std::future::Future; -use crate::ship::map::MapArea; -use crate::entity::character::CharacterEntityId; -use crate::entity::item::mag::Mag; +use maps::area::MapArea; +use entity::character::CharacterEntityId; +use entity::item::mag::Mag; -use crate::ship::items::state::ItemStateError; -use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail}; -use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; +use crate::state::ItemStateError; +use crate::state::{IndividualItemDetail, StackedItemDetail}; +use crate::inventory::{InventoryItem, InventoryItemDetail}; pub enum FloorType { Local, @@ -96,13 +96,13 @@ pub struct FloorState { impl FloorState { pub fn take_item(&mut self, item_id: &ClientItemId) -> Option { let item = self.local.0 - .drain_filter(|item| { + .extract_if(|item| { item.item_id == *item_id }) .next(); item.or_else(|| { self.shared.0 - .drain_filter(|item| { + .extract_if(|item| { item.item_id == *item_id }) .next() diff --git a/src/ship/items/inventory.rs b/src/items/src/inventory.rs similarity index 97% rename from src/ship/items/inventory.rs rename to src/items/src/inventory.rs index da131d8..d8c0da9 100644 --- a/src/ship/items/inventory.rs +++ b/src/items/src/inventory.rs @@ -1,18 +1,18 @@ use std::cmp::Ordering; use libpso::character::character; -use crate::ship::items::ClientItemId; -use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, EquippedEntity}; +use crate::ClientItemId; +use entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, EquippedEntity}; use std::future::Future; use async_std::sync::{Arc, Mutex}; -use crate::entity::character::CharacterEntityId; -use crate::entity::item::tool::ToolType; -use crate::entity::item::mag::Mag; -use crate::entity::item::weapon::Weapon; -use crate::ship::shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem}; -use crate::ship::items::state::ItemStateError; -use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult}; -use crate::ship::items::floor::{FloorItem, FloorItemDetail}; +use entity::character::CharacterEntityId; +use entity::item::tool::ToolType; +use entity::item::mag::Mag; +use entity::item::weapon::Weapon; +use shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem}; +use crate::state::ItemStateError; +use crate::state::{IndividualItemDetail, StackedItemDetail, AddItemResult}; +use crate::floor::{FloorItem, FloorItemDetail}; #[derive(Clone, Debug)] pub enum InventoryItemDetail { diff --git a/src/ship/items/itemstateaction.rs b/src/items/src/itemstateaction.rs similarity index 100% rename from src/ship/items/itemstateaction.rs rename to src/items/src/itemstateaction.rs diff --git a/src/ship/items/mod.rs b/src/items/src/lib.rs similarity index 87% rename from src/ship/items/mod.rs rename to src/items/src/lib.rs index 549ee51..7f4251f 100644 --- a/src/ship/items/mod.rs +++ b/src/items/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(extract_if)] + pub mod state; pub mod actions; pub mod apply_item; @@ -6,6 +8,7 @@ pub mod inventory; pub mod floor; pub mod bank; pub mod tasks; +pub mod trade; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, derive_more::Display)] pub struct ClientItemId(pub u32); diff --git a/src/ship/items/state.rs b/src/items/src/state.rs similarity index 95% rename from src/ship/items/state.rs rename to src/items/src/state.rs index 906762a..aa27143 100644 --- a/src/ship/items/state.rs +++ b/src/items/src/state.rs @@ -4,18 +4,18 @@ use async_std::sync::{Arc, RwLock, Mutex}; use futures::stream::{FuturesOrdered, StreamExt}; use anyhow::Context; -use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::character::{CharacterEntity, CharacterEntityId}; -use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankIdentifier}; -use crate::entity::item::tool::Tool; -use crate::entity::item::weapon::Weapon; -use crate::entity::item::mag::Mag; -use crate::ship::drops::ItemDrop; -use crate::ship::items::ClientItemId; -use crate::ship::items::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState}; -use crate::ship::items::floor::{FloorState, FloorItem, LocalFloor, SharedFloor, FloorType}; -use crate::ship::items::bank::{Bank, BankState, BankItem, BankItemDetail, BankError}; -use crate::ship::location::{AreaClient, RoomId}; +use entity::gateway::{EntityGateway, GatewayError}; +use entity::character::{CharacterEntity, CharacterEntityId}; +use entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankIdentifier}; +use entity::item::tool::Tool; +use entity::item::weapon::Weapon; +use entity::item::mag::Mag; +use drops::ItemDrop; +use crate::ClientItemId; +use crate::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState}; +use crate::floor::{FloorState, FloorItem, LocalFloor, SharedFloor, FloorType}; +use crate::bank::{Bank, BankState, BankItem, BankItemDetail, BankError}; +use location::{AreaClient, RoomId}; #[derive(thiserror::Error, Debug)] pub enum ItemStateError { @@ -50,7 +50,7 @@ pub enum ItemStateError { #[error("stacked item")] StackedItemError(Vec), #[error("apply item {0}")] - ApplyItemError(#[from] crate::ship::items::apply_item::ApplyItemError), + ApplyItemError(#[from] crate::apply_item::ApplyItemError), #[error("item is not a mag {0}")] NotAMag(ClientItemId), #[error("item is not mag food {0}")] diff --git a/src/ship/items/tasks.rs b/src/items/src/tasks.rs similarity index 87% rename from src/ship/items/tasks.rs rename to src/items/src/tasks.rs index 3e0cf6a..cf313fc 100644 --- a/src/ship/items/tasks.rs +++ b/src/items/src/tasks.rs @@ -1,22 +1,23 @@ use futures::future::BoxFuture; -use crate::ship::items::ClientItemId; -use crate::entity::item::Meseta; - -use crate::ship::ship::SendShipPacket; -use crate::ship::map::MapArea; -use crate::entity::character::{CharacterEntity, CharacterEntityId}; -use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; -use crate::ship::items::state::{ItemState, ItemStateProxy, IndividualItemDetail}; -use crate::ship::items::itemstateaction::{ItemStateAction, ItemAction}; -use crate::ship::items::inventory::InventoryItem; -use crate::ship::items::floor::FloorItem; -use crate::entity::item::ItemModifier; -use crate::ship::shops::ShopItem; -use crate::ship::trade::TradeItem; -use crate::ship::location::AreaClient; -use crate::ship::drops::ItemDrop; - -use crate::ship::items::actions; +use crate::ClientItemId; +use entity::item::Meseta; + +use maps::area::MapArea; +use entity::character::{CharacterEntity, CharacterEntityId}; +use entity::gateway::{EntityGateway, EntityGatewayTransaction}; +use entity::item::ItemModifier; +use entity::room::RoomEntityId; +use crate::state::{ItemState, ItemStateProxy, IndividualItemDetail}; +use crate::itemstateaction::{ItemStateAction, ItemAction}; +use crate::inventory::InventoryItem; +use crate::floor::FloorItem; +use shops::ShopItem; +use crate::trade::TradeItem; +use location::AreaClient; +use drops::ItemDrop; +use maps::monster::MonsterType; + +use crate::actions; pub fn pick_up_item<'a, EG>( item_state: &'a mut ItemState, @@ -276,7 +277,7 @@ pub fn use_item<'a, EG> ( area_client: AreaClient, item_id: &'a ClientItemId, amount: u32, -) -> BoxFuture<'a, Result, anyhow::Error>> +) -> BoxFuture<'a, Result, anyhow::Error>> where EG: EntityGateway + 'static, { @@ -370,6 +371,8 @@ where Ok((transaction, result)) }) } + +#[allow(clippy::type_complexity)] pub fn trade_items<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, @@ -465,6 +468,32 @@ pub fn enemy_drops_item<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character_id: CharacterEntityId, + room_id: RoomEntityId, + monster_type: MonsterType, + item_drop: ItemDrop) + -> BoxFuture<'a, Result> +where + EG: EntityGateway + 'static, +{ + entity_gateway.with_transaction(move |transaction| async move { + let item_state_proxy = ItemStateProxy::new(item_state.clone()); + let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default() + .act(actions::convert_item_drop_to_floor_item(item_drop)) + .act(actions::item_note_enemy_drop(character_id, room_id, monster_type)) + .act(actions::add_item_to_local_floor(character_id)) + .commit((item_state_proxy, transaction)) + .await?; + + item_state_proxy.commit().await; + Ok((transaction, floor_item)) + }) +} + +pub fn box_drops_item<'a, EG> ( + item_state: &'a mut ItemState, + entity_gateway: &'a mut EG, + character_id: CharacterEntityId, + room_id: RoomEntityId, item_drop: ItemDrop) -> BoxFuture<'a, Result> where @@ -473,7 +502,8 @@ where entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default() - .act(actions::convert_item_drop_to_floor_item(character_id, item_drop)) + .act(actions::convert_item_drop_to_floor_item(item_drop)) + .act(actions::item_note_box_drop(character_id, room_id)) .act(actions::add_item_to_local_floor(character_id)) .commit((item_state_proxy, transaction)) .await?; @@ -508,3 +538,27 @@ where Ok((transaction, item)) }) } + +pub fn floor_item_limit_reached<'a, EG> ( + item_state: &'a ItemState, + entity_gateway: &'a mut EG, + character: &'a CharacterEntity, + item_id: &'a ClientItemId, + map_area: MapArea +) -> BoxFuture<'a, Result<(), anyhow::Error>> +where + EG: EntityGateway + 'static, + EG::Transaction<'a>: Clone, +{ + entity_gateway.with_transaction(move |transaction| async move { + let item_state_proxy = ItemStateProxy::new(item_state.clone()); + let((item_state_proxy, transaction), result) = ItemStateAction::default() + .act(actions::take_item_from_floor(character.id, *item_id)) + .act(actions::delete_item_from_floor(map_area)) + .commit((item_state_proxy, transaction)) + .await?; + + item_state_proxy.commit().await; + Ok((transaction, result)) + }) +} diff --git a/src/items/src/trade.rs b/src/items/src/trade.rs new file mode 100644 index 0000000..19e49bc --- /dev/null +++ b/src/items/src/trade.rs @@ -0,0 +1,38 @@ +use crate::ClientItemId; + +#[derive(Debug, Clone)] +pub enum TradeItem { + Individual(ClientItemId), + Stacked(ClientItemId, usize), +} + +impl TradeItem { + pub fn stacked(&self) -> Option<(ClientItemId, usize)> { + match self { + TradeItem::Stacked(item_id, amount) => Some((*item_id, *amount)), + _ => None + } + } + + pub fn stacked_mut(&mut self) -> Option<(ClientItemId, &mut usize)> { + match self { + TradeItem::Stacked(item_id, ref mut amount) => Some((*item_id, amount)), + _ => None + } + } + + pub fn item_id(&self) -> ClientItemId { + match self { + TradeItem::Individual(item_id) => *item_id, + TradeItem::Stacked(item_id, _) => *item_id, + } + } + + pub fn amount(&self) -> usize { + match self { + TradeItem::Individual(_) => 1, + TradeItem::Stacked(_, amount) => *amount, + } + } +} + diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 2c3d9c0..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![allow(clippy::type_complexity)] -#![allow(incomplete_features)] -#![feature(inline_const)] -#![feature(drain_filter)] -#![feature(try_blocks)] -#![feature(once_cell)] -#![feature(test)] -#![feature(error_generic_member_access)] -#![feature(provide_any)] - -extern crate test; - -pub mod common; -pub mod entity; -pub mod patch; -pub mod login; -pub mod ship; diff --git a/src/location/Cargo.toml b/src/location/Cargo.toml new file mode 100644 index 0000000..f6768c0 --- /dev/null +++ b/src/location/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "location" +version = "0.1.0" +edition = "2021" + +[dependencies] +networking = { workspace = true } + +async-std = { workspace = true } +derive_more = { workspace = true } +futures= { workspace = true } +thiserror = { workspace = true } \ No newline at end of file diff --git a/src/ship/location.rs b/src/location/src/lib.rs similarity index 99% rename from src/ship/location.rs rename to src/location/src/lib.rs index 5dc805e..3dd0b2b 100644 --- a/src/ship/location.rs +++ b/src/location/src/lib.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::time::SystemTime; use thiserror::Error; -use crate::common::serverstate::ClientId; +use networking::serverstate::ClientId; use async_std::sync::{Arc, RwLock}; use futures::{stream, StreamExt}; diff --git a/src/login/mod.rs b/src/login/mod.rs deleted file mode 100644 index a5b3370..0000000 --- a/src/login/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -#[allow(clippy::module_inception)] -pub mod login; -pub mod character; diff --git a/src/login/models.rs b/src/login/models.rs deleted file mode 100644 index c5fb059..0000000 --- a/src/login/models.rs +++ /dev/null @@ -1,92 +0,0 @@ -use std::time::SystemTime; -use std::io::Write; -//use diesel::sql_types::Timestamp; -use diesel::{Insertable, Queryable, Identifiable, Associations, AsExpression, FromSqlRow}; -//use bcrypt::{DEFAULT_COST, hash}; -use diesel::pg::Pg; -use diesel::sql_types; -use diesel::deserialize::{self, FromSql}; -use diesel::serialize::{self, ToSql, Output, IsNull}; -use diesel::backend::Backend; - -use libpso::character::settings; - -use elseware::schema::*; - -//const ELSEWHERE_COST: u32 = bcrypt::DEFAULT_COST; -const ELSEWHERE_COST: u32 = 5; - -#[derive(Debug, AsExpression, FromSqlRow)] -#[sql_type="sql_types::Binary"] -pub struct EUserSettings(pub settings::UserSettings); - -impl std::ops::Deref for EUserSettings { - type Target = settings::UserSettings; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Queryable, Identifiable, Debug)] -pub struct UserAccount { - pub id: i32, - pub username: String, - pub password: String, - pub guildcard: Option, - pub team_id: Option, - pub banned: bool, - pub muted_until: SystemTime, - pub created_at: SystemTime, -} - -#[derive(Insertable)] -#[table_name="user_accounts"] -pub struct NewUser { - username: String, - password: String, -} - -impl NewUser { - pub fn new(username: String, password: String) -> NewUser { - let crypt_password = bcrypt::hash(password, ELSEWHERE_COST).expect("could not hash password?"); - NewUser { - username: username, - password: crypt_password, - } - } -} - -#[derive(Queryable, Identifiable, Associations)] -#[belongs_to(UserAccount, foreign_key="user_id")] -#[table_name="user_settings"] -pub struct UserSettings { - pub id: i32, - pub user_id: i32, - //settings: Vec, - pub settings: EUserSettings, -} - -#[derive(Insertable, Debug)] -#[table_name="user_settings"] -pub struct NewUserSettings { - pub user_id: i32, - pub settings: EUserSettings, -} - -impl ToSql for EUserSettings { - fn to_sql(&self, out: &mut Output) -> serialize::Result { - out.write_all(&self.0.as_bytes()[..]) - .map(|_| IsNull::No) - .map_err(|e| Box::new(e) as Box) - } -} - -impl FromSql for EUserSettings { - fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result { - let bytes_vec: Vec = as FromSql>::from_sql(bytes)?; - let mut static_bytes = [0u8; 0x1160]; - static_bytes[..0x1160].clone_from_slice(&bytes_vec); - Ok(EUserSettings(settings::UserSettings::from_bytes(static_bytes))) - } -} diff --git a/src/login_server/Cargo.toml b/src/login_server/Cargo.toml new file mode 100644 index 0000000..8ce2441 --- /dev/null +++ b/src/login_server/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "login_server" +version = "0.1.0" +edition = "2021" + +[dependencies] +entity = { workspace = true } +networking = { workspace = true } +pktbuilder = { workspace = true } +stats = { workspace = true } + +libpso = { workspace = true } + +async-std = { workspace = true } +async-trait = { workspace = true } +anyhow = { workspace = true } +bcrypt = { workspace = true } +crc = { workspace = true } +thiserror = { workspace = true } +chrono = { workspace = true } +rand= { workspace = true } diff --git a/src/login/character.rs b/src/login_server/src/character.rs similarity index 96% rename from src/login/character.rs rename to src/login_server/src/character.rs index f23beea..ec9d3d3 100644 --- a/src/login/character.rs +++ b/src/login_server/src/character.rs @@ -12,30 +12,31 @@ use libpso::packet::login::*; use libpso::packet::ship::{MenuDetail, SmallLeftDialog}; use libpso::{PacketParseError, PSOPacket}; use libpso::crypto::bb::PSOBBCipher; -use crate::entity::item; use libpso::character::character; +use entity::item; -use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; -use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; -use crate::common::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage, Ship}; -use crate::common::leveltable::LEVEL_TABLE; +use networking::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; +use networking::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; +use networking::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage, Ship}; +use stats::leveltable::LEVEL_TABLE; use libpso::{utf8_to_array, utf8_to_utf16_array}; -use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::account::{UserAccountId, UserAccountEntity, NewUserSettingsEntity, USERFLAG_NEWCHAR, USERFLAG_DRESSINGROOM}; -use crate::entity::item::{NewItemEntity, ItemDetail, ItemNote, InventoryItemEntity, InventoryEntity, BankEntity, BankIdentifier, EquippedEntity, Meseta}; -use crate::entity::item::weapon::Weapon; -use crate::entity::item::armor::Armor; -use crate::entity::item::tech::Technique; -use crate::entity::item::tool::Tool; -use crate::entity::item::mag::Mag; -use crate::entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel}; +use entity::gateway::{EntityGateway, GatewayError}; +use entity::account::{UserAccountId, UserAccountEntity, NewUserSettingsEntity, USERFLAG_NEWCHAR, USERFLAG_DRESSINGROOM}; +use entity::item::{NewItemEntity, ItemDetail, ItemNote, InventoryItemEntity, InventoryEntity, BankEntity, BankIdentifier, EquippedEntity, Meseta}; +use entity::item::weapon::Weapon; +use entity::item::armor::Armor; +use entity::item::tech::Technique; +use entity::item::tool::Tool; +use entity::item::mag::Mag; +use entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel}; -use crate::login::login::{get_login_status}; -use crate::common::interserver::AuthToken; +use crate::login::get_login_status; +use networking::interserver::AuthToken; + +use pktbuilder::ship::SHIP_MENU_ID; pub const CHARACTER_PORT: u16 = 12001; -pub const SHIP_MENU_ID: u32 = 1; #[derive(thiserror::Error, Debug)] pub enum CharacterError { @@ -484,7 +485,7 @@ impl CharacterServerState { async fn set_flag(&mut self, id: ClientId, setflag: &SetFlag) -> Result, anyhow::Error> { let mut client = self.clients.write().await; let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?; - let mut user = client.user.as_mut().unwrap(); + let user = client.user.as_mut().unwrap(); user.flags = setflag.flags; self.entity_gateway.save_user(user).await.unwrap(); Ok(None.into_iter()) @@ -515,7 +516,7 @@ impl CharacterServerState { async fn character_preview(&mut self, id: ClientId, preview: &CharacterPreview) -> Result, anyhow::Error> { let mut client = self.clients.write().await; let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?; - let mut user = client.user.as_mut().unwrap(); + let user = client.user.as_mut().unwrap(); if user.flags == USERFLAG_NEWCHAR { new_character(&mut self.entity_gateway, user, preview).await? } @@ -834,9 +835,21 @@ impl<'a> SelectScreenCharacterBuilder<'a> { #[cfg(test)] mod test { use super::*; - use crate::entity::account::*; + use entity::account::*; use libpso::character::{settings, character}; - use crate::entity::gateway::{InMemoryGateway, GatewayError}; + use entity::gateway::{InMemoryGateway, EntityGatewayTransaction, GatewayError}; + + #[derive(Clone)] + struct CharTestDb; + + impl EntityGateway for CharTestDb { + type Transaction<'t> = CharTestDb where Self: 't; + } + + impl EntityGatewayTransaction for CharTestDb { + type ParentGateway = CharTestDb; + } + #[async_std::test] async fn test_option_send() { @@ -846,7 +859,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { - type Transaction<'a> = () where Self: 'a; + type Transaction<'a> = CharTestDb where Self: 'a; async fn get_user_settings_by_user(&mut self, user: &UserAccountEntity) -> Result { Ok(UserSettingsEntity { id: UserSettingsId(0), @@ -889,7 +902,7 @@ mod test { #[derive(Clone)] struct TestData; impl EntityGateway for TestData { - type Transaction<'a> = () where Self: 'a; + type Transaction<'a> = CharTestDb where Self: 'a; } let mut server = CharacterServerState::new(TestData {}, AuthToken("".into())); let send = server.handle(ClientId(1), RecvCharacterPacket::Checksum(Checksum {checksum: 1234, diff --git a/src/login_server/src/lib.rs b/src/login_server/src/lib.rs new file mode 100644 index 0000000..0006241 --- /dev/null +++ b/src/login_server/src/lib.rs @@ -0,0 +1,2 @@ +pub mod login; +pub mod character; diff --git a/src/login/login.rs b/src/login_server/src/login.rs similarity index 93% rename from src/login/login.rs rename to src/login_server/src/login.rs index b4fcad6..70bb5a4 100644 --- a/src/login/login.rs +++ b/src/login_server/src/login.rs @@ -11,11 +11,11 @@ use libpso::{PacketParseError, PSOPacket}; use libpso::crypto::bb::PSOBBCipher; use libpso::util::array_to_utf8; -use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; -use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; +use networking::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; +use networking::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; -use crate::entity::gateway::EntityGateway; -use crate::entity::account::{UserAccountEntity}; +use entity::gateway::EntityGateway; +use entity::account::{UserAccountEntity}; pub const LOGIN_PORT: u16 = 12000; pub const COMMUNICATION_PORT: u16 = 12123; @@ -83,21 +83,13 @@ pub async fn get_login_status(entity_gateway: &mut impl EntityGateway, pkt: &Log pub fn check_if_already_online(user: UserAccountEntity) -> Result { Ok(user) - /* - if user.is_currently_online() { - Err(AccountStatus::PayUp) -} - else { - Ok(user) -} - */ } #[derive(Clone)] pub struct LoginServerState { character_server_ip: net::Ipv4Addr, entity_gateway: EG, - clients: HashMap, + clients: HashMap, // TODO: this should be arc/mutex'd? } impl LoginServerState { @@ -119,7 +111,7 @@ impl LoginServerState { let response = SendLoginPacket::LoginResponse(LoginResponse::by_status(AccountStatus::Ok, pkt.session)); let ip = u32::from_ne_bytes(self.character_server_ip.octets()); Ok(vec![response, - SendLoginPacket::RedirectClient(RedirectClient::new(ip, crate::login::character::CHARACTER_PORT))]) + SendLoginPacket::RedirectClient(RedirectClient::new(ip, crate::character::CHARACTER_PORT))]) }, Err(err) => { Ok(vec![SendLoginPacket::LoginResponse(LoginResponse::by_status(err, pkt.session))]) @@ -178,8 +170,8 @@ impl ServerState for LoginServerState { #[cfg(test)] mod test { use super::*; - use crate::entity::account::{UserAccountId}; - use crate::entity::gateway::{EntityGatewayTransaction, GatewayError}; + use entity::account::{UserAccountId}; + use entity::gateway::{EntityGatewayTransaction, GatewayError}; const LOGIN_PACKET: RecvLoginPacket = RecvLoginPacket::Login(Login { tag: 65536, @@ -204,13 +196,16 @@ mod test { character_slot: 0, } }); - - impl EntityGateway for () { - type Transaction<'t> = () where Self: 't; + + #[derive(Clone)] + struct LoginTestDb; + + impl EntityGateway for LoginTestDb { + type Transaction<'t> = LoginTestDb where Self: 't; } - impl EntityGatewayTransaction for () { - type ParentGateway = (); + impl EntityGatewayTransaction for LoginTestDb { + type ParentGateway = LoginTestDb; } #[async_std::test] @@ -221,7 +216,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { - type Transaction<'t> = () where Self: 't; + type Transaction<'t> = LoginTestDb where Self: 't; async fn get_user_by_name(&mut self, name: String) -> Result { assert!(name == "testuser"); Ok(UserAccountEntity { @@ -280,7 +275,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { - type Transaction<'t> = () where Self: 't; + type Transaction<'t> = LoginTestDb where Self: 't; async fn get_user_by_name(&mut self, _name: String) -> Result { Err(GatewayError::Error) } @@ -315,7 +310,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { - type Transaction<'t> = () where Self: 't; + type Transaction<'t> = LoginTestDb where Self: 't; async fn get_user_by_name(&mut self, name: String) -> Result { assert!(name == "testuser"); Ok(UserAccountEntity { @@ -365,7 +360,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { - type Transaction<'t> = () where Self: 't; + type Transaction<'t> = LoginTestDb where Self: 't; async fn get_user_by_name(&mut self, name: String) -> Result { assert!(name == "testuser"); Ok(UserAccountEntity { diff --git a/src/maps/Cargo.toml b/src/maps/Cargo.toml new file mode 100644 index 0000000..db84b6a --- /dev/null +++ b/src/maps/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "maps" +version = "0.1.0" +edition = "2021" + +[dependencies] +byteorder = { workspace = true } +serde = { workspace = true } +thiserror = { workspace = true } +rand = { workspace = true } +rand_chacha = { workspace = true } +toml = { workspace = true } +enum-utils = { workspace = true } +derive_more = { workspace = true } diff --git a/src/ship/map/area.rs b/src/maps/src/area.rs similarity index 99% rename from src/ship/map/area.rs rename to src/maps/src/area.rs index 02361c3..bb64737 100644 --- a/src/ship/map/area.rs +++ b/src/maps/src/area.rs @@ -2,7 +2,7 @@ use serde::{Serialize, Deserialize}; use std::collections::HashMap; use thiserror::Error; -use crate::ship::room::Episode; +use crate::room::Episode; use std::fmt; #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] diff --git a/src/ship/map/enemy.rs b/src/maps/src/enemy.rs similarity index 94% rename from src/ship/map/enemy.rs rename to src/maps/src/enemy.rs index 4989041..54ac36d 100644 --- a/src/ship/map/enemy.rs +++ b/src/maps/src/enemy.rs @@ -1,19 +1,18 @@ // TOOD: `pub(super) for most of these?` use std::io::{Read}; use std::collections::HashMap; +use std::fs::File; +use std::path::PathBuf; use byteorder::{LittleEndian, ReadBytesExt}; use thiserror::Error; - -use crate::ship::ship::ShipEvent; -use crate::ship::monster::MonsterType; -use crate::ship::room::Episode; - -use crate::ship::map::*; - use rand::{Rng, SeedableRng}; use serde::{Serialize, Deserialize}; -use crate::ship::drops::{load_rare_monster_file}; + +use crate::Holiday; +use crate::area::{MapArea, MapAreaError}; +use crate::room::Episode; +use crate::monster::MonsterType; #[derive(Debug, Copy, Clone)] pub struct RawMapEnemy { @@ -69,6 +68,17 @@ impl RawMapEnemy { } +pub fn load_rare_monster_file(episode: Episode) -> T { + // TODO: where does the rare monster toml file actually live + let mut path = PathBuf::from("data/battle_param/"); + path.push(episode.to_string().to_lowercase() + "_rare_monster.toml"); + + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + toml::from_str::(s.as_str()).unwrap() +} + #[derive(Error, Debug)] #[error("")] pub enum MapEnemyError { @@ -76,6 +86,7 @@ pub enum MapEnemyError { MapAreaError(#[from] MapAreaError), } + // making this `pub type` doesn't allow `impl`s to be defined? #[derive(Clone, Debug, Serialize, Deserialize)] pub struct RareMonsterAppearTable { @@ -103,7 +114,7 @@ impl RareMonsterAppearTable { rand_chacha::ChaChaRng::from_entropy().gen::() < *self.appear_rate.get(monster).unwrap_or(&0.0f32) } - pub fn apply(&self, enemy: MapEnemy, event: ShipEvent) -> MapEnemy { + pub fn apply(&self, enemy: MapEnemy, event: Holiday) -> MapEnemy { if enemy.can_be_rare() && self.roll_is_rare(&enemy.monster) { enemy.into_rare(event) } @@ -345,12 +356,12 @@ impl MapEnemy { guaranteed rare monsters don't count towards the limit */ #[must_use] - pub fn into_rare(self, event: ShipEvent) -> MapEnemy { + pub fn into_rare(self, event: Holiday) -> MapEnemy { match (self.monster, self.map_area.to_episode(), event) { (MonsterType::RagRappy, Episode::One, _) => {MapEnemy {monster: MonsterType::AlRappy, shiny:true, ..self}}, - (MonsterType::RagRappy, Episode::Two, ShipEvent::Easter) => {MapEnemy {monster: MonsterType::EasterRappy, shiny:true, ..self}}, - (MonsterType::RagRappy, Episode::Two, ShipEvent::Halloween) => {MapEnemy {monster: MonsterType::HalloRappy, shiny:true, ..self}}, - (MonsterType::RagRappy, Episode::Two, ShipEvent::Christmas) => {MapEnemy {monster: MonsterType::StRappy, shiny:true, ..self}}, + (MonsterType::RagRappy, Episode::Two, Holiday::Easter) => {MapEnemy {monster: MonsterType::EasterRappy, shiny:true, ..self}}, + (MonsterType::RagRappy, Episode::Two, Holiday::Halloween) => {MapEnemy {monster: MonsterType::HalloRappy, shiny:true, ..self}}, + (MonsterType::RagRappy, Episode::Two, Holiday::Christmas) => {MapEnemy {monster: MonsterType::StRappy, shiny:true, ..self}}, (MonsterType::RagRappy, Episode::Two, _) => {MapEnemy {monster: MonsterType::LoveRappy, shiny:true, ..self}}, (MonsterType::Hildebear, _, _) => {MapEnemy {monster: MonsterType::Hildeblue, shiny:true, ..self}}, (MonsterType::PoisonLily, _, _) => {MapEnemy {monster: MonsterType::NarLily, shiny:true, ..self}}, diff --git a/src/maps/src/lib.rs b/src/maps/src/lib.rs new file mode 100644 index 0000000..2da528c --- /dev/null +++ b/src/maps/src/lib.rs @@ -0,0 +1,59 @@ +pub mod area; +pub mod enemy; +pub mod object; +pub mod variant; +pub mod maps; +pub mod monster; +pub mod room; + +#[derive(Clone, Copy)] +pub enum Holiday { + None, + Christmas, + Valentines, + Easter, + Halloween, + Sonic, + NewYear, + Summer, + White, + Wedding, + Fall, + Spring, + Summer2, + Spring2, +} + + +impl From for u32 { + fn from(other: Holiday) -> u32 { + u16::from(other) as u32 + } +} + +impl From for u16 { + fn from(other: Holiday) -> u16 { + u8::from(other) as u16 + } +} + +impl From for u8 { + fn from(other: Holiday) -> u8 { + match other { + Holiday::None => 0, + Holiday::Christmas => 1, + Holiday::Valentines => 3, + Holiday::Easter => 4, + Holiday::Halloween => 5, + Holiday::Sonic => 6, + Holiday::NewYear => 7, + Holiday::Summer => 8, + Holiday::White => 9, + Holiday::Wedding => 10, + Holiday::Fall => 11, + Holiday::Spring => 12, + Holiday::Summer2 => 13, + Holiday::Spring2 => 14, + } + } +} diff --git a/src/ship/map/maps.rs b/src/maps/src/maps.rs similarity index 96% rename from src/ship/map/maps.rs rename to src/maps/src/maps.rs index 05c7e29..2ed7961 100644 --- a/src/ship/map/maps.rs +++ b/src/maps/src/maps.rs @@ -6,14 +6,15 @@ use std::fs::File; use thiserror::Error; -use crate::ship::ship::ShipEvent; -use crate::ship::monster::MonsterType; -use crate::ship::room::{Episode, RoomMode, PlayerMode}; - -// TODO: don't use * -use crate::ship::map::*; - +//use crate::ship::ship::ShipEvent; +use crate::area::MapArea; +use crate::Holiday; +use crate::enemy::{MapEnemy, RawMapEnemy, RareMonsterAppearTable}; +use crate::monster::MonsterType; +use crate::variant::{MapVariant, MapVariantMode}; +use crate::object::{MapObject, RawMapObject}; +use crate::room::{Episode, RoomMode, PlayerMode}; pub fn objects_from_stream(cursor: &mut impl Read, episode: &Episode, map_area: &MapArea) -> Vec> { let mut object_data = Vec::new(); @@ -325,7 +326,7 @@ impl Maps { enemies: Vec>, objects: Vec>, rare_monster_table: &RareMonsterAppearTable, - event: ShipEvent) + event: Holiday) { self.enemy_data = enemies .into_iter() @@ -358,7 +359,7 @@ impl Maps { } } -pub fn generate_free_roam_maps(room_mode: RoomMode, event: ShipEvent) -> Maps { +pub fn generate_free_roam_maps(room_mode: RoomMode, event: Holiday) -> Maps { let rare_monster_table = RareMonsterAppearTable::new(room_mode.episode()); let map_variants = default_map_variants(room_mode.episode(), room_mode.player_mode()); Maps { @@ -375,3 +376,12 @@ pub fn generate_free_roam_maps(room_mode: RoomMode, event: ShipEvent) -> Maps { map_variants, } } + + +pub fn null_free_roam_maps(_room_mode: RoomMode, _event: Holiday) -> Maps { + Maps { + enemy_data: Default::default(), + object_data: Default::default(), + map_variants: Default::default(), + } +} diff --git a/src/ship/monster.rs b/src/maps/src/monster.rs similarity index 98% rename from src/ship/monster.rs rename to src/maps/src/monster.rs index 1bdb5b7..a72288d 100644 --- a/src/ship/monster.rs +++ b/src/maps/src/monster.rs @@ -4,7 +4,7 @@ use std::fs::File; use std::io::Read; use std::path::PathBuf; use serde::{Serialize, Deserialize}; -use crate::ship::room::{Difficulty, Episode, RoomMode}; +use crate::room::{Difficulty, Episode, RoomMode}; #[derive(Debug)] @@ -149,7 +149,7 @@ pub enum MonsterType { } -#[derive(serde::Deserialize, Debug)] +#[derive(Deserialize, Debug)] pub struct MonsterStats { pub atp: u16, pub mst: u16, diff --git a/src/ship/map/object.rs b/src/maps/src/object.rs similarity index 98% rename from src/ship/map/object.rs rename to src/maps/src/object.rs index 81bce6a..0f73442 100644 --- a/src/ship/map/object.rs +++ b/src/maps/src/object.rs @@ -1,13 +1,11 @@ // TOOD: `pub(super) for most of these?` -use std::io::{Read}; +use std::io::Read; use byteorder::{LittleEndian, ReadBytesExt}; -use crate::ship::room::Episode; - -// TODO: don't use * -use crate::ship::map::*; +use crate::room::Episode; +use crate::area::MapArea; #[derive(Debug, Copy, Clone)] diff --git a/src/maps/src/room.rs b/src/maps/src/room.rs new file mode 100644 index 0000000..8370e7c --- /dev/null +++ b/src/maps/src/room.rs @@ -0,0 +1,150 @@ +#[derive(Debug, Copy, Clone, derive_more::Display)] +pub enum Episode { + #[display(fmt="ep1")] + One, + #[display(fmt="ep2")] + Two, + #[display(fmt="ep4")] + Four, +} + +impl TryFrom for Episode { + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + 1 => Ok(Episode::One), + 2 => Ok(Episode::Two), + 3 => Ok(Episode::Four), + _ => Err(()) + } + } +} + +impl From for u8 { + fn from(other: Episode) -> u8 { + match other { + Episode::One => 1, + Episode::Two => 2, + Episode::Four => 3, + } + } +} + +impl Episode { + pub fn from_quest(value: u8) -> Option { + match value { + 0 => Some(Episode::One), + 1 => Some(Episode::Two), + 2 => Some(Episode::Four), + _ => None, + } + } +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)] +pub enum Difficulty { + Normal, + Hard, + VeryHard, + Ultimate, +} + +impl TryFrom for Difficulty { + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Difficulty::Normal), + 1 => Ok(Difficulty::Hard), + 2 => Ok(Difficulty::VeryHard), + 3 => Ok(Difficulty::Ultimate), + _ => Err(()) + } + } +} + +impl From for u8 { + fn from(other: Difficulty) -> u8 { + match other { + Difficulty::Normal => 0, + Difficulty::Hard => 1, + Difficulty::VeryHard => 2, + Difficulty::Ultimate => 3, + } + } +} + +#[derive(Debug, Copy, Clone)] +pub enum PlayerMode { + Single, + Multi, +} + +impl PlayerMode { + pub fn value(&self) -> u8 { + match self { + PlayerMode::Single => 1, + PlayerMode::Multi => 0, + } + } +} + +#[derive(Debug, Copy, Clone, derive_more::Display)] +pub enum RoomMode { + #[display(fmt="single")] + Single { + episode: Episode, + difficulty: Difficulty, + }, + #[display(fmt="multi")] + Multi { + episode: Episode, + difficulty: Difficulty, + }, + #[display(fmt="challenge")] + Challenge { + episode: Episode, + }, + #[display(fmt="battle")] + Battle { + episode: Episode, + difficulty: Difficulty, + } +} + + +impl RoomMode { + pub fn difficulty(&self) -> Difficulty { + match self { + RoomMode::Single {difficulty, ..} => *difficulty, + RoomMode::Multi {difficulty, ..} => *difficulty, + RoomMode::Battle {difficulty, ..} => *difficulty, + RoomMode::Challenge {..} => Difficulty::Normal, + } + } + + pub fn episode(&self) -> Episode { + match self { + RoomMode::Single {episode, ..} => *episode, + RoomMode::Multi {episode, ..} => *episode, + RoomMode::Battle {episode, ..} => *episode, + RoomMode::Challenge {episode, ..} => *episode, + } + } + + pub fn battle(&self) -> bool { + matches!(self, RoomMode::Battle {..}) + } + + pub fn challenge(&self) -> bool { + matches!(self, RoomMode::Challenge {..}) + } + + pub fn player_mode(&self) -> PlayerMode { + match self { + RoomMode::Single {..} => PlayerMode::Single, + _ => PlayerMode::Multi, + } + } +} diff --git a/src/ship/map/variant.rs b/src/maps/src/variant.rs similarity index 99% rename from src/ship/map/variant.rs rename to src/maps/src/variant.rs index 0fa7c65..78fa4bf 100644 --- a/src/ship/map/variant.rs +++ b/src/maps/src/variant.rs @@ -3,7 +3,8 @@ use rand::Rng; // TODO: don't use * -use crate::ship::map::*; +//use crate::map::*; +use crate::area::MapArea; #[derive(Debug, PartialEq, Eq)] pub enum MapVariantMode { diff --git a/src/networking/Cargo.toml b/src/networking/Cargo.toml new file mode 100644 index 0000000..1ecadc9 --- /dev/null +++ b/src/networking/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "networking" +version = "0.1.0" +edition = "2021" + + +[dependencies] +entity = { workspace = true } + +libpso = { workspace = true } + +async-std = { workspace = true } +async-trait = { workspace = true } +futures = { workspace = true } +log = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +derive_more = { workspace = true } \ No newline at end of file diff --git a/src/common/cipherkeys.rs b/src/networking/src/cipherkeys.rs similarity index 100% rename from src/common/cipherkeys.rs rename to src/networking/src/cipherkeys.rs diff --git a/src/common/interserver.rs b/src/networking/src/interserver.rs similarity index 94% rename from src/common/interserver.rs rename to src/networking/src/interserver.rs index 1f6e0ff..be49a9f 100644 --- a/src/common/interserver.rs +++ b/src/networking/src/interserver.rs @@ -2,8 +2,8 @@ use std::net::Ipv4Addr; use async_std::channel; use serde::{Serialize, Deserialize}; use serde::de::DeserializeOwned; -use crate::entity::account::UserAccountId; -use crate::entity::character::CharacterEntityId; +use entity::account::UserAccountId; +use entity::character::CharacterEntityId; #[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct ServerId(pub usize); diff --git a/src/common/mod.rs b/src/networking/src/lib.rs similarity index 96% rename from src/common/mod.rs rename to src/networking/src/lib.rs index d02076e..c8adde9 100644 --- a/src/common/mod.rs +++ b/src/networking/src/lib.rs @@ -1,7 +1,6 @@ pub mod cipherkeys; pub mod serverstate; pub mod mainloop; -pub mod leveltable; pub mod interserver; // https://www.reddit.com/r/rust/comments/33xhhu/how_to_create_an_array_of_structs_that_havent/ diff --git a/src/common/mainloop/client.rs b/src/networking/src/mainloop/client.rs similarity index 97% rename from src/common/mainloop/client.rs rename to src/networking/src/mainloop/client.rs index d7af211..3bcb971 100644 --- a/src/common/mainloop/client.rs +++ b/src/networking/src/mainloop/client.rs @@ -9,8 +9,8 @@ use log::{trace, info, warn, error}; use libpso::crypto::{PSOCipher, NullCipher, CipherError}; use libpso::PacketParseError; -use crate::common::serverstate::ClientId; -use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect}; +use crate::serverstate::ClientId; +use crate::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect}; #[derive(Debug)] @@ -255,7 +255,7 @@ where let (mut socket, addr) = listener.accept().await.unwrap(); id += 1; - let client_id = crate::common::serverstate::ClientId(id); + let client_id = crate::serverstate::ClientId(id); info!("new client {:?} {:?} {:?}", client_id, socket, addr); let (client_tx, client_rx) = async_std::channel::unbounded(); diff --git a/src/common/mainloop/interserver.rs b/src/networking/src/mainloop/interserver.rs similarity index 93% rename from src/common/mainloop/interserver.rs rename to src/networking/src/mainloop/interserver.rs index dbe940d..5e5194b 100644 --- a/src/common/mainloop/interserver.rs +++ b/src/networking/src/mainloop/interserver.rs @@ -8,13 +8,11 @@ use std::collections::HashMap; use serde::Serialize; use serde::de::DeserializeOwned; -use crate::common::interserver::{ServerId, InterserverActor}; +use crate::interserver::{ServerId, InterserverActor}; use libpso::crypto::{PSOCipher, NullCipher, CipherError}; -use crate::common::serverstate::{ServerState, SendServerPacket, RecvServerPacket}; -use crate::login::character::CharacterServerState; -//use crate::ship::ship::ShipServerState; -use crate::entity::gateway::entitygateway::EntityGateway; +use crate::serverstate::{ServerState, SendServerPacket, RecvServerPacket}; +use entity::gateway::entitygateway::EntityGateway; use async_std::channel; use std::fmt::Debug; @@ -149,7 +147,7 @@ where info!("[interserver listen] new server: {:?} {:?}", socket, addr); id += 1; - let server_id = crate::common::interserver::ServerId(id); + let server_id = crate::interserver::ServerId(id); let (client_tx, client_rx) = async_std::channel::unbounded(); state.set_sender(server_id, client_tx.clone()).await; @@ -196,7 +194,7 @@ where } }; id += 1; - let server_id = crate::common::interserver::ServerId(id); + let server_id = crate::interserver::ServerId(id); info!("[interserver connect] found loginserv: {:?} {:?}", server_id, socket); let (client_tx, client_rx) = async_std::channel::unbounded(); @@ -220,12 +218,8 @@ where let mut buf = [0u8; 1]; loop { let peek = socket.peek(&mut buf).await; - match peek { - Ok(len) if len == 0 => { - break - }, - _ => { - } + if let Ok(0) = peek { + break } } } diff --git a/src/common/mainloop/mod.rs b/src/networking/src/mainloop/mod.rs similarity index 100% rename from src/common/mainloop/mod.rs rename to src/networking/src/mainloop/mod.rs diff --git a/src/common/serverstate.rs b/src/networking/src/serverstate.rs similarity index 100% rename from src/common/serverstate.rs rename to src/networking/src/serverstate.rs diff --git a/src/patch/mod.rs b/src/patch/mod.rs deleted file mode 100644 index 323a777..0000000 --- a/src/patch/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[allow(clippy::module_inception)] -pub mod patch; diff --git a/src/patch_server/Cargo.toml b/src/patch_server/Cargo.toml new file mode 100644 index 0000000..f528b04 --- /dev/null +++ b/src/patch_server/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "patch_server" +version = "0.1.0" +edition = "2021" + +[dependencies] +networking = { workspace = true } + +libpso = { workspace = true } + +async-trait = { workspace = true } +rand = { workspace = true } +crc = { workspace = true } +ron = { workspace = true } +serde = { workspace = true } diff --git a/src/patch/patch.rs b/src/patch_server/src/lib.rs similarity index 98% rename from src/patch/patch.rs rename to src/patch_server/src/lib.rs index 26441f8..565530d 100644 --- a/src/patch/patch.rs +++ b/src/patch_server/src/lib.rs @@ -11,8 +11,8 @@ use libpso::crypto::pc::PSOPCCipher; use ron::de::from_str; use serde::Deserialize; -use crate::common::mainloop::{NetworkError}; -use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId}; +use networking::mainloop::{NetworkError}; +use networking::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId}; #[derive(Debug)] pub enum PatchError { diff --git a/src/pktbuilder/Cargo.toml b/src/pktbuilder/Cargo.toml new file mode 100644 index 0000000..9c070f9 --- /dev/null +++ b/src/pktbuilder/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "pktbuilder" +version = "0.1.0" +edition = "2021" + +[dependencies] +quests = { workspace = true } +stats = { workspace = true } +location = { workspace = true } +client = { workspace = true } +items = { workspace = true } +networking = { workspace = true } +maps = { workspace = true } +room = { workspace = true } +shops = { workspace = true } +entity = { workspace = true } + +libpso = { workspace = true } + +anyhow = { workspace = true } +futures = { workspace = true } +thiserror = { workspace = true } \ No newline at end of file diff --git a/src/ship/character.rs b/src/pktbuilder/src/character.rs similarity index 96% rename from src/ship/character.rs rename to src/pktbuilder/src/character.rs index 348f8ac..5d57896 100644 --- a/src/ship/character.rs +++ b/src/pktbuilder/src/character.rs @@ -1,10 +1,9 @@ use libpso::character::character; -use crate::common::leveltable::CharacterStats; -use crate::entity::character::CharacterEntity; -//use crate::ship::items::{CharacterInventory, CharacterBank}; -use crate::ship::items::bank::BankState; -use crate::ship::items::inventory::InventoryState; -use crate::entity::item::Meseta; +use stats::leveltable::CharacterStats; +use entity::character::CharacterEntity; +use items::bank::BankState; +use items::inventory::InventoryState; +use entity::item::Meseta; #[derive(Default)] diff --git a/src/ship/packet/builder/mod.rs b/src/pktbuilder/src/lib.rs similarity index 85% rename from src/ship/packet/builder/mod.rs rename to src/pktbuilder/src/lib.rs index f74015e..bdcd755 100644 --- a/src/ship/packet/builder/mod.rs +++ b/src/pktbuilder/src/lib.rs @@ -3,14 +3,15 @@ pub mod message; pub mod room; pub mod quest; pub mod ship; +pub mod character; use libpso::character::character::Inventory; use libpso::packet::ship::{PlayerHeader, PlayerInfo}; -use crate::common::leveltable::LEVEL_TABLE; -use crate::ship::character::CharacterBytesBuilder; -use crate::ship::ship::ClientState; -use crate::ship::location::AreaClient; -use crate::ship::items::inventory::InventoryState; +use stats::leveltable::LEVEL_TABLE; +use crate::character::CharacterBytesBuilder; +use client::ClientState; +use location::AreaClient; +use items::inventory::InventoryState; pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) -> PlayerHeader { PlayerHeader { diff --git a/src/ship/packet/builder/lobby.rs b/src/pktbuilder/src/lobby.rs similarity index 91% rename from src/ship/packet/builder/lobby.rs rename to src/pktbuilder/src/lobby.rs index af033ca..34587c5 100644 --- a/src/ship/packet/builder/lobby.rs +++ b/src/pktbuilder/src/lobby.rs @@ -1,9 +1,10 @@ use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{Clients, ShipEvent}; -use crate::ship::location::{ClientLocation, LobbyId, ClientLocationError}; -use crate::ship::packet::builder::{player_info}; -use crate::ship::items::state::ItemState; +use networking::serverstate::ClientId; +use maps::Holiday; +use client::Clients; +use location::{ClientLocation, LobbyId, ClientLocationError}; +use crate::player_info; +use items::state::ItemState; use futures::future::join_all; @@ -12,7 +13,7 @@ pub async fn join_lobby(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &ItemState, - event: ShipEvent) + event: Holiday) -> Result { let lobby_clients = client_location.get_clients_in_lobby(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; @@ -52,7 +53,7 @@ pub async fn add_to_lobby(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &ItemState, - event: ShipEvent) + event: Holiday) -> Result { let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let leader = client_location.get_lobby_leader(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; diff --git a/src/ship/packet/builder/message.rs b/src/pktbuilder/src/message.rs similarity index 72% rename from src/ship/packet/builder/message.rs rename to src/pktbuilder/src/message.rs index ac60484..cf843df 100644 --- a/src/ship/packet/builder/message.rs +++ b/src/pktbuilder/src/message.rs @@ -1,21 +1,21 @@ use libpso::packet::messages::*; use libpso::packet::ship::*; -use crate::entity::item; -use crate::common::leveltable::CharacterStats; -use crate::ship::ship::{ShipError}; -use crate::ship::items::ClientItemId; -use crate::ship::items::inventory::InventoryItem; -use crate::ship::items::state::IndividualItemDetail; -use crate::ship::items::bank::BankState; -use crate::ship::items::floor::FloorItem; -use crate::ship::location::AreaClient; +use entity::item; +use stats::leveltable::CharacterStats; +//use crate::ship::ship::{ShipError}; +use items::ClientItemId; +use items::inventory::InventoryItem; +use items::state::IndividualItemDetail; +use items::bank::BankState; +use items::floor::FloorItem; +use location::AreaClient; use std::convert::TryInto; -use crate::ship::shops::ShopItem; +use shops::ShopItem; -pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result { +pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> ItemDrop { let item_bytes = item_drop.as_client_bytes(); - Ok(ItemDrop { + ItemDrop { client, target, map_area: item_drop.map_area.area_value(), @@ -24,37 +24,37 @@ pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result Result { +pub fn create_individual_item(area_client: AreaClient, item_id: ClientItemId, item: &IndividualItemDetail) -> CreateItem { let bytes = item.as_client_bytes(); - Ok(CreateItem { + CreateItem { client: area_client.local_client.id(), target: 0, - item_data: bytes[0..12].try_into()?, + item_data: bytes[0..12].try_into().unwrap(), item_id: item_id.0, - item_data2: bytes[12..16].try_into()?, + item_data2: bytes[12..16].try_into().unwrap(), unknown: 0, - }) + } } // TODO: this doesn't need to be a Result, just unwrap try_intos they are guaranteed to succeed -pub fn create_stacked_item(area_client: AreaClient, item_id: ClientItemId, tool: &item::tool::Tool, amount: usize) -> Result { +pub fn create_stacked_item(area_client: AreaClient, item_id: ClientItemId, tool: &item::tool::Tool, amount: usize) -> CreateItem { let bytes = tool.as_stacked_bytes(amount); - Ok(CreateItem { + CreateItem { client: area_client.local_client.id(), target: 0, - item_data: bytes[0..12].try_into()?, + item_data: bytes[0..12].try_into().unwrap(), item_id: item_id.0, - item_data2: bytes[12..16].try_into()?, + item_data2: bytes[12..16].try_into().unwrap(), unknown: 0, - }) + } } pub fn create_meseta(area_client: AreaClient, amount: usize) -> CreateItem { @@ -69,32 +69,32 @@ pub fn create_meseta(area_client: AreaClient, amount: usize) -> CreateItem { } } -pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &InventoryItem) -> Result { +pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &InventoryItem) -> CreateItem { let bytes = item.item.as_client_bytes(); - Ok(CreateItem { + CreateItem { client: area_client.local_client.id(), target: 0, - item_data: bytes[0..12].try_into()?, + item_data: bytes[0..12].try_into().unwrap(), item_id: item.item_id.0, - item_data2: bytes[12..16].try_into()?, + item_data2: bytes[12..16].try_into().unwrap(), unknown: 0, - }) + } } -pub fn create_withdrawn_inventory_item2(area_client: AreaClient, item: &InventoryItem) -> Result { +pub fn create_withdrawn_inventory_item2(area_client: AreaClient, item: &InventoryItem) -> CreateItem { let bytes = item.item.as_client_bytes(); - Ok(CreateItem { + CreateItem { client: area_client.local_client.id(), target: 0, - item_data: bytes[0..12].try_into()?, + item_data: bytes[0..12].try_into().unwrap(), item_id: item.item_id.0, - item_data2: bytes[12..16].try_into()?, + item_data2: bytes[12..16].try_into().unwrap(), unknown: 0, - }) + } } -pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> Result { - Ok(RemoveItemFromFloor { +pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> RemoveItemFromFloor { + RemoveItemFromFloor { client: area_client.local_client.id(), target: 0, client_id: area_client.local_client.id(), @@ -102,12 +102,12 @@ pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> Resu map_area: item.map_area.area_value(), unknown2: 0, item_id: item.item_id.0, - }) + } } -pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem) -> Result { +pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem) -> DropSplitStack { let item_bytes = item.as_client_bytes(); - Ok(DropSplitStack { + DropSplitStack { client: area_client.local_client.id(), target: 0, variety: 0, @@ -115,16 +115,16 @@ pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem) -> Result Result { +pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem) -> DropSplitStack { let item_bytes = item.as_client_bytes(); - Ok(DropSplitStack { + DropSplitStack { client: area_client.local_client.id(), target: 0, variety: 0, @@ -132,11 +132,11 @@ pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem) -> Res map_area: item.map_area.area_value(), x: item.x, z: item.z, - item_bytes: item_bytes[0..12].try_into()?, + item_bytes: item_bytes[0..12].try_into().unwrap(), item_id: item.item_id.0, - item_bytes2: item_bytes[12..16].try_into()?, + item_bytes2: item_bytes[12..16].try_into().unwrap(), unknown2: 0, - }) + } } pub fn character_gained_exp(area_client: AreaClient, exp: u32) -> GiveCharacterExp { @@ -215,13 +215,13 @@ pub fn shop_list(shop_type: u8, items: &[I]) -> ShopList { } } -pub fn tek_preview(id: ClientItemId, weapon: &item::weapon::Weapon) -> Result { +pub fn tek_preview(id: ClientItemId, weapon: &item::weapon::Weapon) -> TekPreview { let bytes = weapon.as_bytes(); - Ok(TekPreview { + TekPreview { client: 0x79, target: 0, - item_bytes: bytes[0..12].try_into()?, + item_bytes: bytes[0..12].try_into().unwrap(), item_id: id.0, - item_bytes2: bytes[12..16].try_into()?, - }) + item_bytes2: bytes[12..16].try_into().unwrap(), + } } diff --git a/src/ship/packet/builder/quest.rs b/src/pktbuilder/src/quest.rs similarity index 94% rename from src/ship/packet/builder/quest.rs rename to src/pktbuilder/src/quest.rs index f162269..d3f2f4f 100644 --- a/src/ship/packet/builder/quest.rs +++ b/src/pktbuilder/src/quest.rs @@ -1,8 +1,9 @@ -use crate::ship::quests::{Quest, QuestList}; -use crate::ship::ship::{QUEST_CATEGORY_MENU_ID, QUEST_SELECT_MENU_ID}; +use quests::{Quest, QuestList}; use libpso::packet::ship::*; use libpso::{utf8_to_array, utf8_to_utf16_array}; +pub const QUEST_CATEGORY_MENU_ID: u32 = 0xA2; +pub const QUEST_SELECT_MENU_ID: u32 = 0xA3; pub fn quest_category_list(quests: &QuestList) -> QuestCategoryList { let categories = quests.iter() diff --git a/src/ship/packet/builder/room.rs b/src/pktbuilder/src/room.rs similarity index 84% rename from src/ship/packet/builder/room.rs rename to src/pktbuilder/src/room.rs index 2b5c8e5..a7bbe75 100644 --- a/src/ship/packet/builder/room.rs +++ b/src/pktbuilder/src/room.rs @@ -1,11 +1,12 @@ -use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{ShipError, ClientState, Clients, ShipEvent}; -use crate::ship::location::{ClientLocation, RoomId, AreaClient, ClientLocationError}; -use crate::ship::room::RoomState; -use crate::ship::items::state::ItemState; -use crate::ship::packet::builder::{player_header, player_info}; use std::convert::TryInto; +use libpso::packet::ship::*; +use networking::serverstate::ClientId; +use maps::Holiday; +use client::{ClientState, Clients}; +use location::{ClientLocation, RoomId, AreaClient, ClientLocationError}; +use room::RoomState; +use items::state::ItemState; +use crate::{player_header, player_info}; use futures::stream::StreamExt; @@ -14,13 +15,14 @@ pub async fn join_room(id: ClientId, client_location: &ClientLocation, room_id: RoomId, room: &RoomState, - event: ShipEvent) + event: Holiday) -> Result { let all_clients = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; + #[allow(clippy::manual_try_fold)] // I don't think its even possible to make this work here let players = futures::stream::iter(all_clients.iter()) .enumerate() .fold::, _, _>(Ok([PlayerHeader::default(); 4]), |acc, (i, c)| async move { - let header_area_client = client_location.get_local_client(id).await.map_err(|err| ShipError::ClientLocationError(err.into()))?; + let header_area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError {err.into() })?; clients.with(c.client, |client| Box::pin(async move { acc.map(|mut a| { a[i] = player_header(0x10000, client, &header_area_client); @@ -57,7 +59,7 @@ pub async fn add_to_room(_id: ClientId, area_client: &AreaClient, leader: &AreaClient, item_state: &ItemState, - event: ShipEvent) + event: Holiday) -> Result { let inventory = item_state.get_character_inventory(&client.character).await?; Ok(AddToRoom { diff --git a/src/ship/packet/builder/ship.rs b/src/pktbuilder/src/ship.rs similarity index 85% rename from src/ship/packet/builder/ship.rs rename to src/pktbuilder/src/ship.rs index 1411f2a..41c6ea0 100644 --- a/src/ship/packet/builder/ship.rs +++ b/src/pktbuilder/src/ship.rs @@ -1,8 +1,9 @@ use libpso::packet::login::{ShipList, ShipListEntry}; use libpso::utf8_to_utf16_array; -use crate::common::interserver::Ship; -use crate::login::character::SHIP_MENU_ID; +use networking::interserver::Ship; + +pub const SHIP_MENU_ID: u32 = 1; pub fn ship_list(ships: &[Ship]) -> ShipList { let ships = ships.iter() diff --git a/src/pktbuilder/src/team.rs b/src/pktbuilder/src/team.rs new file mode 100644 index 0000000..9ebdfb9 --- /dev/null +++ b/src/pktbuilder/src/team.rs @@ -0,0 +1,107 @@ +use futures::stream::{FuturesOrdered, StreamExt}; +use libpso::packet::ship::*; +use crate::common::serverstate::ClientId; +use crate::entity::gateway::EntityGateway; +use crate::ship::client::{Clients, ClientState}; +use crate::ship::teams::Teams; +use crate::ship::location::ClientLocation; +use crate::ship::ship::ShipError; +use crate::entity::team::TeamEntity; + + +pub fn client_team_state_changed(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> ClientTeamStateChanged { + ClientTeamStateChanged { + unknown: 0, + guildcard: client.user.guildcard(), + team_id: team.id.0, + unknown2: [0;2], + privilege: 0x40, // TODO: improve + team_name: libpso::utf8_to_utf16_array!(team.name, 14), + unknown3: 0x00986C84, // TODO: what if we omit this? + } +} + +fn player_team_info(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> PlayerTeamInfo { + PlayerTeamInfo { + guildcard: client.user.guildcard(), + team_id: team.id.0, + info: 0, + info2: 0, + privilege: 0x40, // TODO: improve + team_name: libpso::utf8_to_utf16_array!(team.name, 14), + unknown: 0x00986C84, // TODO: what if we omit this? + guildcard_again: client.user.guildcard(), + client_id: client_id.0 as u32, + character_name: libpso::utf8_to_utf16_array!(client.character.name, 12), + unknown2: 0, + unknown3: 0, + team_flag: team.team_flag, + } +} + +pub fn team_info_individual(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> TeamInfo { + TeamInfo { + clients: vec![player_team_info(client_id, client, team)] + } +} + + +pub async fn player_team_info_list(id: ClientId, + client_location: &ClientLocation, + clients: &Clients, + teams: &Teams, +) -> Result, ShipError> +where + EG: EntityGateway + Clone + 'static, +{ + Ok(futures::stream::iter(client_location.get_all_clients_by_client(id).await?.into_iter()) + .filter_map(|area_client| { + let clients = clients.clone(); + async move { + clients.with(area_client.client, |client| { + let mut teams = teams.clone(); + Box::pin(async move { + let team = teams.get_team(area_client.client).await.ok()??; + Some(player_team_info(area_client.client, client, &team)) + })}).await.ok()? + }}) + .collect::>() + .await) +} + +pub async fn team_info(id: ClientId, + client_location: &ClientLocation, + clients: &Clients, + teams: &Teams, +) -> Result +where + EG: EntityGateway + Clone + 'static, +{ + Ok(TeamInfo { + clients: player_team_info_list(id, client_location, clients, teams).await?, + }) +} + +pub async fn lobby_team_list(id: ClientId, + client_location: &ClientLocation, + clients: &Clients, + teams: &Teams, +) -> Result +where + EG: EntityGateway + Clone + 'static, +{ + Ok(TeamLobbyList { + clients: player_team_info_list(id, client_location, clients, teams).await?, + }) +} + +pub fn team_invitation_info(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> TeamInvitationInfo { + TeamInvitationInfo { + guildcard: client.user.guildcard(), + team_id: team.id.0, + unknown: [0; 2], + team_name: libpso::utf8_to_utf16_array!(team.name, 14), + unknown2: 0x00986C84, // TODO: what if we omit this? + team_flag: team.team_flag, + } +} diff --git a/src/ship/packet/builder/trade.rs b/src/pktbuilder/src/trade.rs similarity index 100% rename from src/ship/packet/builder/trade.rs rename to src/pktbuilder/src/trade.rs diff --git a/src/quests/Cargo.toml b/src/quests/Cargo.toml new file mode 100644 index 0000000..6cab926 --- /dev/null +++ b/src/quests/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "quests" +version = "0.1.0" +edition = "2021" + +[dependencies] +maps = { workspace = true } + +libpso = { workspace = true } + +async-std = { workspace = true } +ages-prs = { workspace = true } +log = { workspace = true } +byteorder = { workspace = true } +thiserror = { workspace = true } +anyhow = { workspace = true } +toml = { workspace = true } +serde = { workspace = true } diff --git a/src/ship/quests.rs b/src/quests/src/lib.rs similarity index 77% rename from src/ship/quests.rs rename to src/quests/src/lib.rs index 02c1906..91e5d4d 100644 --- a/src/ship/quests.rs +++ b/src/quests/src/lib.rs @@ -10,9 +10,12 @@ use serde::{Serialize, Deserialize}; use ages_prs::{LegacyPrsDecoder, LegacyPrsEncoder}; use byteorder::{LittleEndian, ReadBytesExt}; use libpso::util::array_to_utf16; -use crate::ship::map::{MapArea, MapAreaError, MapObject, MapEnemy, enemy_data_from_stream, objects_from_stream}; -use crate::ship::room::Episode; -use crate::ship::map::area::{MapAreaLookup, MapAreaLookupBuilder}; +use maps::area::{MapArea, MapAreaError}; +use maps::object::MapObject; +use maps::enemy::MapEnemy; +use maps::maps::{objects_from_stream, enemy_data_from_stream}; +use maps::room::{Episode, RoomMode}; +use maps::area::{MapAreaLookup, MapAreaLookupBuilder}; #[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -101,7 +104,7 @@ fn quest_episode(bin: &[u8]) -> Option { for bytes in bin.windows(3) { // set_episode if bytes[0] == 0xF8 && bytes[1] == 0xBC { - return Episode::from_quest(bytes[2]).ok() + return Episode::from_quest(bytes[2]) } } None @@ -152,11 +155,14 @@ fn parse_dat(dat: &[u8], episode: &Episode, map_areas: &MapAreaLookup) -> Result } #[derive(Error, Debug)] -#[error("")] pub enum QuestLoadError { + #[error("io error {0}")] IoError(#[from] std::io::Error), + #[error("parse dat error {0}")] ParseDatError(#[from] ParseDatError), + #[error("could not read metadata")] CouldNotReadMetadata, + #[error("could not load config file")] CouldNotLoadConfigFile, } @@ -233,7 +239,7 @@ pub fn load_quest(bin_path: PathBuf, dat_path: PathBuf, quest_path: PathBuf) -> } -pub fn load_quests(mut quest_path: PathBuf) -> Result { +pub fn load_quests_path(mut quest_path: PathBuf) -> Result { let mut f = File::open(quest_path.clone()).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?; let mut s = String::new(); f.read_to_string(&mut s)?; @@ -242,28 +248,58 @@ pub fn load_quests(mut quest_path: PathBuf) -> Result let ql: BTreeMap = toml::from_str(s.as_str()).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?; Ok(ql.into_iter().map(|(category, category_details)| { - let quests = category_details.quests - .into_iter() - .filter_map(|quest| { - load_quest(quest.bin.into(), quest.dat.into(), quest_path.to_path_buf()) - .and_then(|quest | { - if used_quest_ids.contains(&quest.id) { - warn!("quest id already exists: {}", quest.id); - return None; - } - used_quest_ids.insert(quest.id); - Some(quest) - }) - }); - (QuestCategory{ - index: category_details.list_order, - name: category, - description: category_details.description, - }, quests.collect()) + ( + QuestCategory { + index: category_details.list_order, + name: category, + description: category_details.description, + }, + category_details.quests + .into_iter() + .filter_map(|quest| { + load_quest(quest.bin.into(), quest.dat.into(), quest_path.to_path_buf()) + .and_then(|quest | { + if used_quest_ids.contains(&quest.id) { + warn!("quest id already exists: {}", quest.id); + return None; + } + used_quest_ids.insert(quest.id); + Some(quest) + }) + }) + .collect() + ) }).collect()) } +pub fn load_standard_quests(mode: RoomMode) -> Result { + match mode { + RoomMode::Single {episode, .. } => { + load_quests_path(PathBuf::from_iter(["data", "quests", "bb", &episode.to_string(), "single", "quests.toml"])) + }, + RoomMode::Multi {episode, .. } => { + load_quests_path(PathBuf::from_iter(["data", "quests", "bb", &episode.to_string(), "multi", "quests.toml"])) + }, + _ => { + Ok(BTreeMap::new()) + } + } +} + +pub fn load_government_quests(mode: RoomMode) -> Result { + match mode { + RoomMode::Single {episode, .. } => { + load_quests_path(PathBuf::from_iter(["data", "quests", "bb", &episode.to_string(), "government", "quests.toml"])) + }, + RoomMode::Multi {episode, .. } => { + load_quests_path(PathBuf::from_iter(["data", "quests", "bb", &episode.to_string(), "government", "quests.toml"])) + }, + _ => { + Ok(BTreeMap::new()) + } + } +} diff --git a/src/room/Cargo.toml b/src/room/Cargo.toml new file mode 100644 index 0000000..d081284 --- /dev/null +++ b/src/room/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "room" +version = "0.1.0" +edition = "2021" + +[dependencies] +maps = { workspace = true } +entity = { workspace = true } +quests = { workspace = true } +location = { workspace = true } +drops = { workspace = true } + +rand = { workspace = true } +async-std = { workspace = true } +futures = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } diff --git a/src/room/src/lib.rs b/src/room/src/lib.rs new file mode 100644 index 0000000..fca3669 --- /dev/null +++ b/src/room/src/lib.rs @@ -0,0 +1,274 @@ +use std::collections::HashMap; +use std::convert::{From, Into}; +use async_std::sync::{Arc, RwLock, RwLockReadGuard}; +use futures::future::BoxFuture; +use futures::stream::{FuturesOrdered, Stream}; + +use thiserror::Error; +use rand::Rng; + +use quests::{QuestList, QuestLoadError}; +use maps::maps::Maps; +use drops::DropTable; +use entity::character::SectionID; +use entity::room::{RoomEntityId, RoomEntityMode}; +use maps::monster::{load_monster_stats_table, MonsterType, MonsterStats}; +use maps::area::MapAreaLookup; +use maps::Holiday; +use location::{MAX_ROOMS, RoomId}; + +use maps::room::{Episode, Difficulty, RoomMode}; + +#[derive(Error, Debug)] +pub enum RoomError { + #[error("invalid room id {0}")] + Invalid(u32), +} + + +#[derive(Clone)] +pub struct Rooms([Arc>>; MAX_ROOMS]); + + +impl Default for Rooms { + fn default() -> Rooms { + Rooms(core::array::from_fn(|_| Arc::new(RwLock::new(None)))) + } +} + +impl Rooms { + pub async fn add(&self, room_id: RoomId, room: RoomState) -> Result<(), anyhow::Error> { + *self.0 + .get(room_id.0) + .ok_or(RoomError::Invalid(room_id.0 as u32))? + .write() + .await = Some(room); + Ok(()) + } + + pub async fn remove(&self, room_id: RoomId) { + if let Some(room) = self.0.get(room_id.0) { + *room + .write() + .await = None; + } + } + + pub async fn exists(&self, room_id: RoomId) -> bool { + match self.0.get(room_id.0) { + Some(room) => { + room + .read() + .await + .is_some() + }, + None => false, + } + } + + pub async fn with<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result + where + T: Send, + F: for<'b> FnOnce(&'b RoomState) -> BoxFuture<'b, T> + Send + 'a + { + let room = self.0 + .get(room_id.0) + .ok_or(RoomError::Invalid(room_id.0 as u32))? + .read() + .await; + if let Some(room) = room.as_ref() { + Ok(func(room).await) + } + else { + Err(RoomError::Invalid(room_id.0 as u32).into()) + } + } + + pub async fn with_mut<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result + where + T: Send, + F: for<'b> FnOnce(&'b mut RoomState) -> BoxFuture<'b, T> + Send + 'a + { + let mut room = self.0 + .get(room_id.0) + .ok_or(RoomError::Invalid(room_id.0 as u32))? + .write() + .await; + + if let Some(room) = room.as_mut() { + Ok(func(room).await) + } + else { + Err(RoomError::Invalid(room_id.0 as u32).into()) + } + } + + pub async fn get(&self, room_id: RoomId) -> RwLockReadGuard> { + self.0 + .get(room_id.0) + .unwrap() + .read() + .await + } + + pub fn stream(&self) -> impl Stream>> { + self.0 + .iter() + .map(|room| async move { + room + .read() + .await + }) + .collect::>() + } +} + +#[derive(Debug, Error)] +#[error("")] +pub enum RoomCreationError { + InvalidMode, + InvalidEpisode(u8), + InvalidDifficulty(u8), + CouldNotLoadMonsterStats(RoomMode), + CouldNotLoadQuests, +} + + +pub enum QuestCategoryType { + Standard, + Government, +} + +impl From for QuestCategoryType { + fn from(f: usize) -> QuestCategoryType { + match f { + 0 => QuestCategoryType::Standard, + _ => QuestCategoryType::Government, + } + } +} +impl From for QuestCategoryType { + fn from(f: u32) -> QuestCategoryType { + match f { + 0 => QuestCategoryType::Standard, + _ => QuestCategoryType::Government, + } + } +} + +impl QuestCategoryType { + pub fn value(&self) -> usize { + match self { + QuestCategoryType::Standard => 0, + QuestCategoryType::Government => 1, + } + } +} + +pub struct RoomState { + pub room_id: RoomEntityId, + pub mode: RoomMode, + pub name: String, + pub password: [u16; 16], + pub maps: Maps, + pub drop_table: Box, + pub section_id: SectionID, + pub random_seed: u32, + pub bursting: bool, + pub monster_stats: Box>, + pub map_areas: MapAreaLookup, + pub quest_group: QuestCategoryType, + pub standard_quests: QuestList, + pub government_quests: QuestList, + // enemy info +} + +impl RoomState { + pub fn get_flags_for_room_list(&self) -> u8 { + let mut flags = 0u8; + + match self.mode { + RoomMode::Single {..} => {flags += 0x04} + RoomMode::Battle {..} => {flags += 0x10}, + RoomMode::Challenge {..} => {flags += 0x20}, + _ => {flags += 0x40}, + }; + + if self.password[0] > 0 { + flags += 0x02; + } + flags + } + + pub fn get_episode_for_room_list(&self) -> u8 { + let episode: u8 = self.mode.episode().into(); + + match self.mode { + RoomMode::Single {..} => episode + 0x10, + _ => episode + 0x40, + } + } + + pub fn get_difficulty_for_room_list(&self) -> u8 { + let difficulty: u8 = self.mode.difficulty().into(); + difficulty + 0x22 + } + + pub fn quests(&self) -> &QuestList { + match self.quest_group { + QuestCategoryType::Standard => &self.standard_quests, + QuestCategoryType::Government => &self.government_quests, + } + } + + #[allow(clippy::too_many_arguments, clippy::type_complexity)] + pub fn new (room_id: RoomEntityId, + mode: RoomEntityMode, + episode: Episode, + difficulty: Difficulty, + section_id: SectionID, + name: String, + password: [u16; 16], + event: Holiday, + map_builder: Arc Maps + Send + Sync>>, + drop_table_builder: Arc Box + Send + Sync>>, + standard_quest_builder: Arc Result + Send + Sync>>, + government_quest_builder: Arc Result + Send + Sync>>, + ) -> Result { + let mode = match mode { + RoomEntityMode::Single => RoomMode::Single { + episode, + difficulty, + }, + RoomEntityMode::Multi => RoomMode::Multi { + episode, + difficulty, + }, + RoomEntityMode::Challenge => RoomMode::Challenge { + episode, + }, + RoomEntityMode::Battle => RoomMode::Battle { + episode, + difficulty, + }, + }; + + Ok(RoomState { + room_id, + monster_stats: Box::new(load_monster_stats_table(&mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(mode))?), + mode, + random_seed: rand::thread_rng().gen(), + name, + password, + maps: map_builder(mode, event), + section_id, + drop_table: drop_table_builder(episode, difficulty, section_id), + bursting: false, + map_areas: MapAreaLookup::new(&episode), + quest_group: QuestCategoryType::Standard, + standard_quests: standard_quest_builder(mode)?, + government_quests: government_quest_builder(mode)?, + }) + + } +} diff --git a/src/ship/drops/drop_table.rs b/src/ship/drops/drop_table.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs deleted file mode 100644 index e9251c4..0000000 --- a/src/ship/items/manager.rs +++ /dev/null @@ -1,1380 +0,0 @@ -use crate::ship::items::ClientItemId; -use std::collections::HashMap; -use std::cmp::Ordering; -use std::cell::RefCell; -use thiserror::Error; -use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::character::{CharacterEntity, CharacterEntityId, TechLevel}; -use crate::entity::item::{ItemDetail, ItemNote, BankName}; -use crate::entity::item::{Meseta, NewItemEntity, ItemEntity, InventoryItemEntity, BankItemEntity}; -use crate::entity::item::tool::{Tool, ToolType}; -use crate::entity::item::weapon; -use crate::ship::map::MapArea; -use crate::ship::ship::ItemDropLocation; -use crate::ship::trade::TradeItem; -use crate::ship::drops::{ItemDrop, ItemDropType}; -use crate::ship::location::{AreaClient, RoomId}; -use crate::ship::shops::ShopItem; -use crate::ship::packet::handler::trade::{TradeError, OTHER_MESETA_ITEM_ID}; - -use crate::ship::items::bank::*; -use crate::ship::items::floor::*; -use crate::ship::items::inventory::*; -use crate::ship::items::transaction::{ItemTransaction, ItemAction, TransactionError, TransactionCommitError}; - -#[derive(PartialEq, Eq)] -pub enum FloorType { - Local, - Shared, -} - -pub enum TriggerCreateItem { - Yes, - No -} - -#[derive(Error, Debug)] -#[error("itemmanager")] -pub enum ItemManagerError { - #[error("gateway")] - EntityGatewayError, - #[error("no such item id {0}")] - NoSuchItemId(ClientItemId), - NoCharacter(CharacterEntityId), - NoRoom(RoomId), - CouldNotAddToInventory(ClientItemId), - //ItemBelongsToOtherPlayer, - #[error("shrug")] - Idunnoman, - CouldNotSplitItem(ClientItemId), - #[error("could not drop meseta")] - CouldNotDropMeseta, - InvalidBankName(BankName), - #[error("not enough tools")] - NotEnoughTools(Tool, usize, usize), // have, expected - InventoryItemConsumeError(#[from] InventoryItemConsumeError), - #[error("bank full")] - BankFull, - WrongItemType(ClientItemId), - UseItemError(#[from] use_tool::UseItemError), - #[error("could not buy item")] - CouldNotBuyItem, - #[error("could not add bought item to inventory")] - CouldNotAddBoughtItemToInventory, - ItemIdNotInInventory(ClientItemId), - #[error("cannot get mut item")] - CannotGetMutItem, - #[error("cannot get individual item")] - CannotGetIndividualItem, - InvalidSlot(u8, u8), // slots available, slot attempted - #[error("no armor equipped")] - NoArmorEquipped, - GatewayError(#[from] GatewayError), - #[error("stacked item")] - StackedItemError(Vec), - #[error("item not sellable")] - ItemNotSellable(InventoryItem), - #[error("wallet full")] - WalletFull, - #[error("invalid sale")] - InvalidSale, - ItemTransactionAction(Box), - #[error("invalid trade")] - InvalidTrade, -} - -impl std::convert::From> for ItemManagerError -where - E: std::fmt::Debug + std::marker::Send + std::marker::Sync + std::error::Error + 'static, -{ - fn from(other: TransactionError) -> ItemManagerError { - match other { - TransactionError::Action(err) => { - ItemManagerError::ItemTransactionAction(Box::new(err)) - }, - TransactionError::Commit(err) => { - match err { - TransactionCommitError::Gateway(gw) => { - ItemManagerError::GatewayError(gw) - }, - TransactionCommitError::ItemManager(im) => { - im - } - } - } - } - } -} - - -pub struct ItemManager { - pub(super) id_counter: u32, - - pub(self) character_inventory: HashMap, - pub(self) character_meseta: HashMap, - pub(self) bank_meseta: HashMap, - //character_bank: HashMap>, - pub(self) character_bank: HashMap, - pub(self) character_floor: HashMap, - - pub(self) character_room: HashMap, - pub(self) room_floor: HashMap, - pub(self) room_item_id_counter: RefCell ClientItemId + Send>>>, -} - -impl Default for ItemManager { - fn default() -> ItemManager { - ItemManager { - id_counter: 0, - character_inventory: HashMap::new(), - character_meseta: HashMap::new(), - bank_meseta: HashMap::new(), - character_bank: HashMap::new(), - character_floor: HashMap::new(), - character_room: HashMap::new(), - room_floor: HashMap::new(), - room_item_id_counter: RefCell::new(HashMap::new()), - } - } -} - -impl ItemManager { - pub fn next_global_item_id(&mut self) -> ClientItemId { - self.id_counter += 1; - ClientItemId(self.id_counter) - } - - pub async fn load_character(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> Result<(), anyhow::Error> { - let inventory = entity_gateway.get_character_inventory(&character.id).await?; - let bank = entity_gateway.get_character_bank(&character.id, &BankName("".into())).await?; - let equipped = entity_gateway.get_character_equips(&character.id).await?; - - let inventory_items = inventory.items.into_iter() - .map(|item| -> Result { - Ok(match item { - InventoryItemEntity::Individual(item) => { - InventoryItem::Individual(IndividualInventoryItem { - entity_id: item.id, - item_id: self.next_global_item_id(), - item: item.item, - }) - }, - InventoryItemEntity::Stacked(items) => { - InventoryItem::Stacked(StackedInventoryItem { - entity_ids: items.iter().map(|i| i.id).collect(), - item_id: self.next_global_item_id(), - tool: items.get(0) - .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))? - .item - .clone() - .as_tool() - .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))? - }) - }, - }) - }) - .collect::, _>>()?; - let character_inventory = CharacterInventory::new(inventory_items, &equipped); - - let bank_items = bank.items.into_iter() - .map(|item| -> Result { - Ok(match item { - BankItemEntity::Individual(item) => { - BankItem::Individual(IndividualBankItem { - entity_id: item.id, - item_id: self.next_global_item_id(), - item: item.item, - }) - }, - BankItemEntity::Stacked(items) => { - BankItem::Stacked(StackedBankItem { - entity_ids: items.iter().map(|i| i.id).collect(), - item_id: self.next_global_item_id(), - tool: items.get(0) - .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))? - .item - .clone() - .as_tool() - .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))? - }) - }, - }) - }) - .collect::, _>>()?; - let character_bank = CharacterBank::new(bank_items); - - let character_meseta = entity_gateway.get_character_meseta(&character.id).await?; - let bank_meseta = entity_gateway.get_bank_meseta(&character.id, &BankName("".into())).await?; - - self.character_inventory.insert(character.id, character_inventory); - self.character_bank.insert(character.id, character_bank); - self.character_meseta.insert(character.id, character_meseta); - self.bank_meseta.insert(character.id, bank_meseta); - Ok(()) - } - - pub fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) { - let base_inventory_id = ((area_client.local_client.id() as u32) << 21) | 0x10000; - let inventory = self.character_inventory.get_mut(&character.id).unwrap(); - inventory.initialize_item_ids(base_inventory_id); - let base_bank_id = ((area_client.local_client.id() as u32) << 21) | 0x20000; - let default_bank = self.character_bank.get_mut(&character.id); - if let Some(default_bank ) = default_bank { - default_bank.initialize_item_ids(base_bank_id); - } - self.character_room.insert(character.id, room_id); - self.character_floor.insert(character.id, RoomFloorItems::default()); - self.room_floor.entry(room_id).or_insert_with(RoomFloorItems::default); - - let mut inc = 0x00810000; - self.room_item_id_counter.borrow_mut().entry(room_id).or_insert_with(|| Box::new(move || { - inc += 1; - ClientItemId(inc) - })); - } - - pub fn get_character_inventory(&self, character: &CharacterEntity) -> Result<&CharacterInventory, anyhow::Error> { - Ok(self.character_inventory.get(&character.id) - .ok_or(ItemManagerError::NoCharacter(character.id))?) - } - - pub fn get_character_inventory_mut<'a>(&'a mut self, character: &CharacterEntity) -> Result<&'a mut CharacterInventory, anyhow::Error> { - Ok(self.character_inventory.get_mut(&character.id) - .ok_or(ItemManagerError::NoCharacter(character.id))?) - } - - pub fn get_character_bank(&self, character: &CharacterEntity) -> Result<&CharacterBank, anyhow::Error> { - self.character_bank - .get(&character.id) - .ok_or_else(|| ItemManagerError::NoCharacter(character.id).into()) - } - - pub fn get_character_meseta(&self, character_id: &CharacterEntityId) -> Result<&Meseta, ItemManagerError> { - self.character_meseta.get(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id)) - } - - pub fn get_character_meseta_mut<'a>(&'a mut self, character_id: &CharacterEntityId) -> Result<&'a mut Meseta, ItemManagerError> { - self.character_meseta.get_mut(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id)) - } - - pub fn get_bank_meseta(&self, character_id: &CharacterEntityId) -> Result<&Meseta, ItemManagerError> { - self.bank_meseta.get(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id)) - } - - pub fn get_bank_meseta_mut<'a>(&'a mut self, character_id: &CharacterEntityId) -> Result<&'a mut Meseta, ItemManagerError> { - self.bank_meseta.get_mut(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id)) - } - - pub fn get_character_and_bank_meseta_mut<'a>(&'a mut self, character_id: &CharacterEntityId) -> Result<(&'a mut Meseta, &'a mut Meseta), ItemManagerError> { - Ok(( - self.character_meseta.get_mut(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id))?, - self.bank_meseta.get_mut(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id))? - )) - } - - pub fn remove_character_from_room(&mut self, character: &CharacterEntity) { - self.character_inventory.remove(&character.id); - self.character_floor.remove(&character.id); - if let Some(room) = self.character_room.remove(&character.id).as_ref() { - if self.character_room.iter().any(|(_, r)| r == room) { - self.room_floor.remove(room); - } - } - } - - pub fn get_floor_item_by_id(&self, character: &CharacterEntity, item_id: ClientItemId) -> Result<(&FloorItem, FloorType), anyhow::Error> { - let local_floor = self.character_floor.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let room = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let shared_floor = self.room_floor.get(room).ok_or(ItemManagerError::NoCharacter(character.id))?; - - local_floor.get_item_by_id(item_id).map(|item| (item, FloorType::Local)) - .or_else(|| { - shared_floor.get_item_by_id(item_id).map(|item| (item, FloorType::Shared)) - }) - .ok_or_else(|| ItemManagerError::NoSuchItemId(item_id).into()) - } - - pub async fn character_picks_up_item(&mut self, entity_gateway: &mut EG, character: &mut CharacterEntity, item_id: ClientItemId) - -> Result { - let it = ItemTransaction::new(self, (character, item_id)) - .act(|it, (character, item_id)| -> Result<_, ItemManagerError> { - let local_floor = it.manager.character_floor.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let inventory = it.manager.character_inventory.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let room_id = it.manager.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let shared_floor = it.manager.room_floor.get(room_id).ok_or(ItemManagerError::NoRoom(*room_id))?; - - let floor_item = match local_floor.get_item_by_id(*item_id) { - Some(floor_item) => { - it.action(Box::new(RemoveFromLocalFloor { - character_id: character.id, - item_id: *item_id - })); - floor_item - }, - None => { - match shared_floor.get_item_by_id(*item_id) { - Some(floor_item) => { - it.action(Box::new(RemoveFromSharedFloor { - room_id: *room_id, - item_id: *item_id - })); - floor_item - }, - None => { - return Err(ItemManagerError::NoSuchItemId(*item_id)) - } - } - } - }; - - let create_trigger = match floor_item { - FloorItem::Individual(individual_floor_item) => { - if inventory.space_for_individual_item() { - it.action(Box::new(AddIndividualFloorItemToInventory { - character: (**character).clone(), - item: individual_floor_item.clone() - })) - } - else { - return Err(ItemManagerError::CouldNotAddToInventory(*item_id)); - } - TriggerCreateItem::Yes - }, - FloorItem::Stacked(stacked_floor_item) => { - match inventory.space_for_stacked_item(&stacked_floor_item.tool, stacked_floor_item.entity_ids.len()) { - SpaceForStack::Yes(YesThereIsSpace::NewStack) => { - it.action(Box::new(AddStackedFloorItemToInventory { - character_id: character.id, - item: stacked_floor_item.clone() - })); - TriggerCreateItem::Yes - }, - SpaceForStack::Yes(YesThereIsSpace::ExistingStack) => { - it.action(Box::new(AddStackedFloorItemToInventory { - character_id: character.id, - item: stacked_floor_item.clone() - })); - TriggerCreateItem::No - }, - SpaceForStack::No(_) => { - return Err(ItemManagerError::CouldNotAddToInventory(*item_id)); - }, - } - }, - FloorItem::Meseta(meseta_floor_item) => { - let character_meseta = it.manager.character_meseta.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - if character_meseta.0 >= 999999 { - return Err(ItemManagerError::CouldNotAddToInventory(*item_id)); - } - it.action(Box::new(AddMesetaFloorItemToInventory { - character_id: character.id, - item: meseta_floor_item.clone() - })); - - TriggerCreateItem::No - }, - }; - Ok(create_trigger) - }); - it.commit(self, entity_gateway) - .await - .map_err(|err| err.into()) - } - - pub async fn enemy_drop_item_on_local_floor<'a, EG: EntityGateway>(&'a mut self, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_drop: ItemDrop) -> Result<&'a FloorItem, anyhow::Error> { - let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - enum ItemOrMeseta { - Individual(ItemDetail), - Stacked(Tool), - Meseta(Meseta) - } - - let item = match item_drop.item { - ItemDropType::Weapon(w) => ItemOrMeseta::Individual(ItemDetail::Weapon(w)), - ItemDropType::Armor(w) => ItemOrMeseta::Individual(ItemDetail::Armor(w)), - ItemDropType::Shield(w) => ItemOrMeseta::Individual(ItemDetail::Shield(w)), - ItemDropType::Unit(w) => ItemOrMeseta::Individual(ItemDetail::Unit(w)), - ItemDropType::TechniqueDisk(w) => ItemOrMeseta::Individual(ItemDetail::TechniqueDisk(w)), - ItemDropType::Mag(w) => ItemOrMeseta::Individual(ItemDetail::Mag(w)), - //ItemDropType::IndividualTool(t) => ItemOrMeseta::Individual(ItemDetail::Tool(t)), - //ItemDropType::StackedTool(t, _) => ItemOrMeseta::Stacked(t), - ItemDropType::Tool(t) if t.tool.is_stackable() => ItemOrMeseta::Stacked(t), - ItemDropType::Tool(t) if !t.tool.is_stackable() => ItemOrMeseta::Individual(ItemDetail::Tool(t)), - ItemDropType::Meseta(m) => ItemOrMeseta::Meseta(Meseta(m)), - _ => unreachable!() // rust isnt smart enough to see that the conditional on tool catches everything - }; - - let item_id = self.room_item_id_counter.borrow_mut().get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?(); - let floor_item = match item { - ItemOrMeseta::Individual(item_detail) => { - let entity = entity_gateway.create_item(NewItemEntity { - item: item_detail.clone(), - }).await?; - entity_gateway.add_item_note(&entity.id, ItemNote::EnemyDrop { - character_id: character.id, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }).await?; - FloorItem::Individual(IndividualFloorItem { - entity_id: entity.id, - item_id, - item: item_detail, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }) - }, - ItemOrMeseta::Stacked(tool) => { - let entity = entity_gateway.create_item(NewItemEntity { - item: ItemDetail::Tool(tool), - }).await?; - entity_gateway.add_item_note(&entity.id, ItemNote::EnemyDrop { - character_id: character.id, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }).await?; - FloorItem::Stacked(StackedFloorItem { - entity_ids: vec![entity.id], - item_id, - tool, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }) - }, - ItemOrMeseta::Meseta(meseta) => { - FloorItem::Meseta(MesetaFloorItem { - item_id, - meseta, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }) - }, - }; - - self.character_floor.entry(character.id).or_insert_with(RoomFloorItems::default).add_item(floor_item); - // TODO: make these real errors - self.character_floor.get(&character.id).ok_or(ItemManagerError::Idunnoman)?.get_item_by_id(item_id).ok_or_else(|| ItemManagerError::Idunnoman.into()) - } - - pub async fn player_drop_item_on_shared_floor(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - //inventory_item: InventoryItem, - item_id: ClientItemId, - item_drop_location: (MapArea, f32, f32, f32)) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let shared_floor = self.room_floor.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - let dropped_inventory_item = inventory.take_item_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - - match dropped_inventory_item { - InventoryItem::Individual(individual_inventory_item) => { - let individual_floor_item = shared_floor.drop_individual_inventory_item(individual_inventory_item, item_drop_location); - entity_gateway.add_item_note( - &individual_floor_item.entity_id, - ItemNote::PlayerDrop { - character_id: character.id, - map_area: item_drop_location.0, - x: item_drop_location.1, - y: item_drop_location.2, - z: item_drop_location.3, - } - ).await?; - }, - InventoryItem::Stacked(stacked_inventory_item) => { - let stacked_floor_item = shared_floor.drop_stacked_inventory_item(stacked_inventory_item, item_drop_location); - for entity_id in &stacked_floor_item.entity_ids { - entity_gateway.add_item_note( - entity_id, - ItemNote::PlayerDrop { - character_id: character.id, - map_area: item_drop_location.0, - x: item_drop_location.1, - y: item_drop_location.2, - z: item_drop_location.3, - } - ).await?; - } - }, - } - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(()) - } - - pub async fn player_drops_meseta_on_shared_floor(&mut self, - entity_gateway: &mut EG, - character: &mut CharacterEntity, - drop_location: ItemDropLocation, - amount: u32) - -> Result { - let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let shared_floor = self.room_floor.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let character_meseta = self.character_meseta.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - if character_meseta.0 < amount { - return Err(ItemManagerError::CouldNotDropMeseta.into()) - } - character_meseta.0 -= amount; - entity_gateway.set_character_meseta(&character.id, *character_meseta).await?; - - let item_id = self.room_item_id_counter.borrow_mut().get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?(); - let floor_item = FloorItem::Meseta(MesetaFloorItem { - item_id, - meseta: Meseta(amount), - map_area: drop_location.map_area, - x: drop_location.x, - y: 0.0, - z: drop_location.z, - }); - - shared_floor.add_item(floor_item.clone()); - Ok(floor_item) - } - - pub async fn player_drops_partial_stack_on_shared_floor<'a, EG: EntityGateway>(&'a mut self, - entity_gateway: &'a mut EG, - character: &'a CharacterEntity, - //inventory_item: InventoryItem, - item_id: ClientItemId, - drop_location: ItemDropLocation, - amount: usize) - -> Result<&'a StackedFloorItem, anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let shared_floor = self.room_floor.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item_to_split = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - - let new_item_id = self.room_item_id_counter.borrow_mut().get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?(); - let stacked_floor_item = shared_floor.drop_partial_stacked_inventory_item(item_to_split, amount, new_item_id, (drop_location.map_area, drop_location.x, 0.0, drop_location.z)) - .ok_or(ItemManagerError::CouldNotSplitItem(item_id))?; - - for entity_id in &stacked_floor_item.entity_ids { - entity_gateway.add_item_note( - entity_id, - ItemNote::PlayerDrop { - character_id: character.id, - map_area: drop_location.map_area, - x: drop_location.x, - y: 0.0, - z: drop_location.z, - } - ).await?; - } - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(stacked_floor_item) - } - - pub async fn player_consumes_tool(&mut self, - entity_gateway: &mut EG, - character: &mut CharacterEntity, - item_id: ClientItemId, - amount: usize) - -> Result { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let used_item = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let consumed_item = used_item.consume(amount)?; - - if let ItemDetail::TechniqueDisk(tech_disk) = consumed_item.item() { - // TODO: validate tech level in packet is in bounds [1..30] - character.techs.set_tech(tech_disk.tech, TechLevel(tech_disk.level as u8)); - entity_gateway.save_character(character).await?; - }; - - for entity_id in consumed_item.entity_ids() { - entity_gateway.add_item_note(&entity_id, - ItemNote::Consumed).await?; - } - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(consumed_item) - } - - pub async fn player_deposits_item(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_id: ClientItemId, - amount: usize) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let bank = self.character_bank - .get_mut(&character.id) - .ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item_to_deposit = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let _bank_item = bank.deposit_item(item_to_deposit, amount).ok_or(ItemManagerError::Idunnoman)?; - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - entity_gateway.set_character_bank(&character.id, &bank.as_bank_entity(&character.id, &BankName("".into())), &BankName("".into())).await?; - Ok(()) - } - - pub async fn player_withdraws_item<'a, EG: EntityGateway>(&'a mut self, - entity_gateway: &'a mut EG, - character: &'a CharacterEntity, - item_id: ClientItemId, - amount: usize) - -> Result<&'a InventoryItem, anyhow::Error> { - - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let bank = self.character_bank - .get_mut(&character.id) - .ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item_to_withdraw = bank.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let inventory_item_slot = { - let inventory_item = inventory.withdraw_item(item_to_withdraw, amount).ok_or(ItemManagerError::Idunnoman)?; - inventory_item.1 - }; - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - entity_gateway.set_character_bank(&character.id, &bank.as_bank_entity(&character.id, &BankName("".into())), &BankName("".into())).await?; - inventory.slot(inventory_item_slot).ok_or_else(|| ItemManagerError::Idunnoman.into()) - } - - pub async fn player_feeds_mag_item(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - mag_id: ClientItemId, - tool_id: ClientItemId) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let consumed_tool = { - let item_to_feed = inventory.get_item_handle_by_id(tool_id).ok_or(ItemManagerError::NoSuchItemId(tool_id))?; - item_to_feed.consume(1)? - }; - let mut mag_handle = inventory.get_item_handle_by_id(mag_id).ok_or(ItemManagerError::NoSuchItemId(mag_id))?; - - let individual_item = mag_handle.item_mut() - .ok_or(ItemManagerError::NoSuchItemId(mag_id))? - .individual_mut() - .ok_or(ItemManagerError::WrongItemType(mag_id))?; - let mag = individual_item - .mag_mut() - .ok_or(ItemManagerError::WrongItemType(mag_id))?; - - let consumed_tool_type = match &consumed_tool { - ConsumedItem::Stacked(stacked_consumed_item) => stacked_consumed_item.tool.tool, - _ => return Err(ItemManagerError::WrongItemType(tool_id).into()) - }; - mag.feed(consumed_tool_type); - - for entity_id in consumed_tool.entity_ids() { - entity_gateway.feed_mag(&individual_item.entity_id, &entity_id).await?; - entity_gateway.add_item_note(&entity_id, ItemNote::FedToMag { - mag: individual_item.entity_id, - }).await?; - } - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(()) - } - - pub async fn use_item(&mut self, - used_item: ConsumedItem, - entity_gateway: &mut EG, - character: &mut CharacterEntity) -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - match &used_item.item() { - ItemDetail::Weapon(_w) => { - // something like when items are used to combine/transform them? - //_ => {} - }, - ItemDetail::Tool(t) => { - match t.tool { - ToolType::PowerMaterial => { - use_tool::power_material(entity_gateway, character).await; - }, - ToolType::MindMaterial => { - use_tool::mind_material(entity_gateway, character).await; - }, - ToolType::EvadeMaterial => { - use_tool::evade_material(entity_gateway, character).await; - }, - ToolType::DefMaterial => { - use_tool::def_material(entity_gateway, character).await; - }, - ToolType::LuckMaterial => { - use_tool::luck_material(entity_gateway, character).await; - }, - ToolType::HpMaterial => { - use_tool::hp_material(entity_gateway, character).await; - }, - ToolType::TpMaterial => { - use_tool::tp_material(entity_gateway, character).await; - }, - ToolType::CellOfMag502 => { - use_tool::cell_of_mag_502(entity_gateway, &used_item, inventory).await?; - }, - ToolType::CellOfMag213 => { - use_tool::cell_of_mag_213(entity_gateway, &used_item, inventory).await?; - }, - ToolType::PartsOfRobochao => { - use_tool::parts_of_robochao(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfOpaOpa => { - use_tool::heart_of_opaopa(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfPian => { - use_tool::heart_of_pian(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfChao=> { - use_tool::heart_of_chao(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfAngel => { - use_tool::heart_of_angel(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfHamburger => { - use_tool::kit_of_hamburger(entity_gateway, &used_item, inventory).await?; - }, - ToolType::PanthersSpirit => { - use_tool::panthers_spirit(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfMark3 => { - use_tool::kit_of_mark3(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfMasterSystem=> { - use_tool::kit_of_master_system(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfGenesis => { - use_tool::kit_of_genesis(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfSegaSaturn => { - use_tool::kit_of_sega_saturn(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfDreamcast => { - use_tool::kit_of_dreamcast(entity_gateway, &used_item, inventory).await?; - }, - ToolType::Tablet => { - use_tool::tablet(entity_gateway, &used_item, inventory).await?; - }, - ToolType::DragonScale => { - use_tool::dragon_scale(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeavenStrikerCoat => { - use_tool::heaven_striker_coat(entity_gateway, &used_item, inventory).await?; - }, - ToolType::PioneerParts => { - use_tool::pioneer_parts(entity_gateway, &used_item, inventory).await?; - }, - ToolType::AmitiesMemo => { - use_tool::amities_memo(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfMorolian => { - use_tool::heart_of_morolian(entity_gateway, &used_item, inventory).await?; - }, - ToolType::RappysBeak => { - use_tool::rappys_beak(entity_gateway, &used_item, inventory).await?; - }, - ToolType::YahoosEngine => { - use_tool::yahoos_engine(entity_gateway, &used_item, inventory).await?; - }, - ToolType::DPhotonCore => { - use_tool::d_photon_core(entity_gateway, &used_item, inventory).await?; - }, - ToolType::LibertaKit => { - use_tool::liberta_kit(entity_gateway, &used_item, inventory).await?; - }, - _ => {} - } - } - _ => {} - } - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(()) - } - - pub async fn player_buys_item<'a, EG: EntityGateway>(&'a mut self, - entity_gateway: &'a mut EG, - character: &'a CharacterEntity, - shop_item: &'a (dyn ShopItem + Send + Sync), - item_id: ClientItemId, - amount: usize) - -> Result<&'a InventoryItem, anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item_detail = shop_item.as_item(); - let inventory_item = match item_detail { - ItemDetail::Tool(tool) => { - if tool.is_stackable() { - let mut item_entities = Vec::new(); - for _ in 0..amount { - let item_entity = entity_gateway.create_item(NewItemEntity { - item: ItemDetail::Tool(tool), - }).await?; - entity_gateway.add_item_note(&item_entity.id, ItemNote::BoughtAtShop { - character_id: character.id, - }).await?; - item_entities.push(item_entity); - } - let floor_item = StackedFloorItem { - entity_ids: item_entities.into_iter().map(|i| i.id).collect(), - item_id, - tool, - // TODO: this is gonna choke if I ever require the item being near the player for pickup - map_area: MapArea::Pioneer2Ep1, - x: 0.0, - y: 0.0, - z: 0.0, - }; - let item_id = { - let (picked_up_item, _slot) = inventory.pick_up_stacked_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; - picked_up_item.item_id - }; - inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? - } - else { - let item_entity = entity_gateway.create_item(NewItemEntity { - item: ItemDetail::Tool(tool), - }).await?; - entity_gateway.add_item_note(&item_entity.id, ItemNote::BoughtAtShop { - character_id: character.id, - }).await?; - - let floor_item = IndividualFloorItem { - entity_id: item_entity.id, - item_id, - item: ItemDetail::Tool(tool), - // TODO: this is gonna choke if I ever require the item being near the player for pickup - map_area: MapArea::Pioneer2Ep1, - x: 0.0, - y: 0.0, - z: 0.0, - }; - let item_id = { - let (picked_up_item, _slot) = inventory.pick_up_individual_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; - picked_up_item.item_id - }; - inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? - } - }, - item_detail => { - let item_entity = entity_gateway.create_item(NewItemEntity { - item: item_detail.clone(), - }).await?; - entity_gateway.add_item_note(&item_entity.id, ItemNote::BoughtAtShop { - character_id: character.id, - }).await?; - let floor_item = IndividualFloorItem { - entity_id: item_entity.id, - item_id, - item: item_detail, - // TODO: this is gonna choke if I ever require the item being near the player for pickup - map_area: MapArea::Pioneer2Ep1, - x: 0.0, - y: 0.0, - z: 0.0, - }; - let item_id = { - let (picked_up_item, _slot) = inventory.pick_up_individual_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; - picked_up_item.item_id - }; - inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? - }, - }; - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(inventory_item) - } - - pub async fn player_sells_item(&mut self, - entity_gateway: &mut EG, - character: &mut CharacterEntity, - item_id: ClientItemId, - amount: usize) - -> Result<(), anyhow::Error> { - let character_meseta = self.get_character_meseta(&character.id)?.0; - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let sold_item_handle = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - if let Some(item_sold) = sold_item_handle.item() { - let unit_price = item_sold.get_sell_price()?; { - let total_sale = unit_price * amount as u32; - if character_meseta + total_sale <= 999999 { - match item_sold { - InventoryItem::Individual(i) => { - entity_gateway.add_item_note(&i.entity_id, ItemNote::SoldToShop).await?; - inventory.remove_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - }, - InventoryItem::Stacked(s) => { - match amount.cmp(&s.count()) { - Ordering::Less | Ordering::Equal => { - sold_item_handle.consume(amount)?; - }, - Ordering::Greater => return Err(ItemManagerError::InvalidSale.into()), - }; - }, - } - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - let character_meseta = self.get_character_meseta_mut(&character.id)?; - character_meseta.0 += total_sale; - entity_gateway.set_character_meseta(&character.id, *character_meseta).await?; - } - else { - return Err(ItemManagerError::WalletFull.into()) - } - } - } else { - return Err(ItemManagerError::ItemIdNotInInventory(item_id).into()) - } - Ok(()) - } - - // TODO: check if slot exists before putting units into it - pub async fn player_equips_item(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_id: ClientItemId, - equip_slot: u8) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - inventory.equip(&item_id, equip_slot); - entity_gateway.set_character_equips(&character.id, &inventory.as_equipped_entity()).await?; - Ok(()) - } - - pub async fn player_unequips_item(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_id: ClientItemId) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - inventory.unequip(&item_id); - entity_gateway.set_character_equips(&character.id, &inventory.as_equipped_entity()).await?; - Ok(()) - } - - pub async fn player_sorts_items(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_ids: [u32; 30]) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let sorted_inventory_items: Vec = item_ids.iter() - .filter(|&client_item_id| *client_item_id < 0xFFFFFFFF) - .map(|&client_item_id| inventory.get_item_by_id(ClientItemId(client_item_id))) - .filter(|&x| x.is_some()) - .map(|x| x.cloned().unwrap()) - .collect(); - - inventory.set_items(sorted_inventory_items); - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(()) - } - - pub async fn replace_item_with_tekked(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_id: ClientItemId, - tek: weapon::WeaponModifier) - -> Result { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item = inventory.remove_by_id(item_id) - .ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let individual = item - .individual() - .ok_or(ItemManagerError::WrongItemType(item_id))?; - - let entity_id = individual.entity_id; - let mut weapon = *individual - .weapon() - .ok_or(ItemManagerError::WrongItemType(item_id))?; - - weapon.apply_modifier(&tek); - entity_gateway.add_weapon_modifier(&entity_id, tek).await?; - - inventory.add_item(InventoryItem::Individual(IndividualInventoryItem { - entity_id, - item_id, - item: ItemDetail::Weapon(weapon), - })); - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - - Ok(weapon) - } - - pub async fn trade_items(&mut self, - entity_gateway: &mut EG, - room_id: RoomId, - p1: (&AreaClient, &CharacterEntity, &Vec, usize), - p2: (&AreaClient, &CharacterEntity, &Vec, usize)) - -> Result, anyhow::Error> { - let it = ItemTransaction::new(self, (p1, p2, room_id)) - .act(|it, (p1, p2, room_id)| -> Result<_, anyhow::Error> { - let p1_inventory = it.manager.get_character_inventory(p1.1)?; - let p2_inventory = it.manager.get_character_inventory(p2.1)?; - - [(p2_inventory, p1_inventory, p2.2, p1.2), (p1_inventory, p2_inventory, p1.2, p2.2)].iter() - .map(|(src_inventory, dest_inventory, trade_recv, trade_send)| { - let item_slots_lost_to_trade = trade_send - .iter() - .fold(0, |acc, item| { - match item { - TradeItem::Individual(..) => { - acc + 1 - }, - TradeItem::Stacked(item_id, amount) => { - let stacked_inventory_item = try { - src_inventory - .get_item_by_id(*item_id)? - .stacked() - }; - if let Some(Some(item)) = stacked_inventory_item { - if item.count() == *amount { - acc + 1 - } - else { - acc - } - } - else { - acc - } - } - } - }); - trade_recv - .iter() - .try_fold(dest_inventory.count(), |acc, item| { - match item { - TradeItem::Individual(..) => { - if acc >= (30 + item_slots_lost_to_trade) { - Err(TradeError::NoInventorySpace) - } - else { - Ok(acc + 1) - } - }, - TradeItem::Stacked(item_id, amount) => { - let stacked_inventory_item = src_inventory - .get_item_by_id(*item_id) - .ok_or(TradeError::InvalidItemId(*item_id))? - .stacked() - .ok_or(TradeError::InvalidItemId(*item_id))?; - match dest_inventory.space_for_stacked_item(&stacked_inventory_item.tool, *amount) { - SpaceForStack::Yes(YesThereIsSpace::ExistingStack) => { - Ok(acc) - }, - SpaceForStack::Yes(YesThereIsSpace::NewStack) => { - Ok(acc + 1) - }, - SpaceForStack::No(NoThereIsNotSpace::FullStack) => { - Err(TradeError::NoStackSpace) - }, - SpaceForStack::No(NoThereIsNotSpace::FullInventory) => { - if acc >= (30 + item_slots_lost_to_trade) { - Err(TradeError::NoInventorySpace) - } - else { - Ok(acc + 1) - } - }, - } - } - } - }) - }) - .collect::, _>>()?; - - let trade_items = [(p1, p2, p1_inventory), (p2, p1, p2_inventory)] - .map(|(src_client, dest_client, src_inventory)| { - src_client.2.iter() - .map(|item| -> Option<(Option, Box>)> { - match item { - TradeItem::Individual(item_id) => { - let item = src_inventory.get_item_by_id(*item_id)?.individual()?; - let new_item_id = it.manager.room_item_id_counter.borrow_mut().get_mut(room_id)?(); - Some(( - Some(ItemToTrade { - add_to: *dest_client.0, - remove_from: *src_client.0, - current_item_id: *item_id, - new_item_id, - item_detail: ItemToTradeDetail::Individual(item.item.clone()) - }), - Box::new(TradeIndividualItem { - src_character_id: src_client.1.id, - dest_character_id: dest_client.1.id, - current_item_id: *item_id, - new_item_id, - }), - )) - }, - TradeItem::Stacked(item_id, amount) => { - let item = src_inventory.get_item_by_id(*item_id)?.stacked()?; - if item.count() < *amount { - None - } - else { - let new_item_id = it.manager.room_item_id_counter.borrow_mut().get_mut(room_id)?(); - Some(( - Some(ItemToTrade { - add_to: *dest_client.0, - remove_from: *src_client.0, - current_item_id: *item_id, - new_item_id, - item_detail: ItemToTradeDetail::Stacked(item.tool, *amount) - }), - Box::new(TradeStackedItem { - src_character_id: src_client.1.id, - dest_character_id: dest_client.1.id, - //item_ids: item.entity_ids.iter().cloned().take(*amount).collect(), - current_item_id: *item_id, - new_item_id, - amount: *amount, - }), - )) - } - } - } - }) - .chain( - if src_client.3 > 0 { - Box::new(std::iter::once(Some( - (Some(ItemToTrade { - add_to: *dest_client.0, - remove_from: *src_client.0, - current_item_id: OTHER_MESETA_ITEM_ID, - new_item_id: OTHER_MESETA_ITEM_ID, - item_detail: ItemToTradeDetail::Meseta(src_client.3) - }), - Box::new(TradeMeseta { - src_character_id: src_client.1.id, - dest_character_id: dest_client.1.id, - amount: src_client.3, - }) as Box>)))) as Box> - } - else { - Box::new(std::iter::empty()) as Box> - }) - .collect::>>() - }); - - - if let [Some(p1_trades), Some(p2_trades)] = trade_items { - let (p1_item_trades, p1_item_actions): (Vec<_>, Vec<_>) = p1_trades.into_iter().unzip(); - let (p2_item_trades, p2_item_actions): (Vec<_>, Vec<_>) = p2_trades.into_iter().unzip(); - - let item_trades = p1_item_trades.into_iter().flatten().chain(p2_item_trades.into_iter().flatten()); - let item_actions = p1_item_actions.into_iter().chain(p2_item_actions.into_iter()); - - for action in item_actions { - it.action(action); - } - - Ok(item_trades.collect()) - } - else { - Err(ItemManagerError::InvalidTrade.into()) - } - - }); - it.commit(self, entity_gateway) - .await - .map_err(|err| err.into()) - } -} - -#[derive(Debug)] -pub enum ItemToTradeDetail { - Individual(ItemDetail), - Stacked(Tool, usize), - Meseta(usize), -} - -#[derive(Debug)] -pub struct ItemToTrade { - pub add_to: AreaClient, - pub remove_from: AreaClient, - pub current_item_id: ClientItemId, - pub new_item_id: ClientItemId, - pub item_detail: ItemToTradeDetail, -} - - -#[derive(Debug)] -struct RemoveFromLocalFloor { - character_id: CharacterEntityId, - item_id: ClientItemId, -} - -#[async_trait::async_trait] -impl ItemAction for RemoveFromLocalFloor { - async fn commit(&self, item_manager: &mut ItemManager, _entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let local_floor = item_manager.character_floor.get_mut(&self.character_id).ok_or(ItemManagerError::NoCharacter(self.character_id))?; - local_floor.remove_item(&self.item_id); - Ok(()) - } -} - - -#[derive(Debug)] -struct RemoveFromSharedFloor { - room_id: RoomId, - item_id: ClientItemId, -} - -#[async_trait::async_trait] -impl ItemAction for RemoveFromSharedFloor { - async fn commit(&self, item_manager: &mut ItemManager, _entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let shared_floor = item_manager.room_floor.get_mut(&self.room_id).ok_or(ItemManagerError::NoRoom(self.room_id))?; - shared_floor.remove_item(&self.item_id); - Ok(()) - } -} - - -#[derive(Debug)] -struct AddIndividualFloorItemToInventory{ - character: CharacterEntity, - item: IndividualFloorItem, -} - -#[async_trait::async_trait] -impl ItemAction for AddIndividualFloorItemToInventory { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let inventory = item_manager.character_inventory.get_mut(&self.character.id).ok_or(ItemManagerError::NoCharacter(self.character.id))?; - let inv_item = inventory.add_individual_floor_item(&self.item); - - entity_gateway.add_item_note( - &self.item.entity_id, - ItemNote::Pickup { - character_id: self.character.id, - } - ).await?; - - if inv_item.mag().is_some() { - entity_gateway.change_mag_owner(&self.item.entity_id, &self.character).await?; - } - - entity_gateway.set_character_inventory(&self.character.id, &inventory.as_inventory_entity(&self.character.id)).await?; - Ok(()) - } -} - - -#[derive(Debug)] -struct AddStackedFloorItemToInventory{ - character_id: CharacterEntityId, - item: StackedFloorItem, -} - -#[async_trait::async_trait] -impl ItemAction for AddStackedFloorItemToInventory { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let inventory = item_manager.character_inventory.get_mut(&self.character_id).ok_or(ItemManagerError::NoCharacter(self.character_id))?; - inventory.add_stacked_floor_item(&self.item); - - entity_gateway.set_character_inventory(&self.character_id, &inventory.as_inventory_entity(&self.character_id)).await?; - Ok(()) - } -} - - -#[derive(Debug)] -struct AddMesetaFloorItemToInventory{ - character_id: CharacterEntityId, - item: MesetaFloorItem, -} - -#[async_trait::async_trait] -impl ItemAction for AddMesetaFloorItemToInventory { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let character_meseta = item_manager.character_meseta.get_mut(&self.character_id).ok_or(ItemManagerError::NoCharacter(self.character_id))?; - character_meseta.0 = std::cmp::min(character_meseta.0 + self.item.meseta.0, 999999); - entity_gateway.set_character_meseta(&self.character_id, *character_meseta).await?; - Ok(()) - } -} - - -#[derive(Debug)] -struct TradeIndividualItem { - src_character_id: CharacterEntityId, - dest_character_id: CharacterEntityId, - current_item_id: ClientItemId, - new_item_id: ClientItemId, -} - -#[async_trait::async_trait] -impl ItemAction for TradeIndividualItem { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let src_inventory = item_manager.character_inventory.get_mut(&self.src_character_id).ok_or(ItemManagerError::NoCharacter(self.src_character_id))?; - let inventory_item = src_inventory.take_item_by_id(self.current_item_id).ok_or(ItemManagerError::NoSuchItemId(self.current_item_id))?; - entity_gateway.set_character_inventory(&self.src_character_id, &src_inventory.as_inventory_entity(&self.src_character_id)).await?; - - let dest_inventory = item_manager.character_inventory.get_mut(&self.dest_character_id).ok_or(ItemManagerError::NoCharacter(self.dest_character_id))?; - dest_inventory.add_item_with_new_item_id(inventory_item, self.new_item_id); - entity_gateway.set_character_inventory(&self.dest_character_id, &dest_inventory.as_inventory_entity(&self.dest_character_id)).await?; - - Ok(()) - } -} - -#[derive(Debug)] -struct TradeStackedItem { - src_character_id: CharacterEntityId, - dest_character_id: CharacterEntityId, - current_item_id: ClientItemId, - new_item_id: ClientItemId, - amount: usize, -} - -#[async_trait::async_trait] -impl ItemAction for TradeStackedItem { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let src_inventory = item_manager.character_inventory.get_mut(&self.src_character_id).ok_or(ItemManagerError::NoCharacter(self.src_character_id))?; - let inventory_item = src_inventory.take_stacked_item_by_id(self.current_item_id, self.amount).ok_or(ItemManagerError::NoSuchItemId(self.current_item_id))?; - entity_gateway.set_character_inventory(&self.src_character_id, &src_inventory.as_inventory_entity(&self.src_character_id)).await?; - - let dest_inventory = item_manager.character_inventory.get_mut(&self.dest_character_id).ok_or(ItemManagerError::NoCharacter(self.dest_character_id))?; - dest_inventory.add_item_with_new_item_id(InventoryItem::Stacked(inventory_item), self.new_item_id); - entity_gateway.set_character_inventory(&self.dest_character_id, &dest_inventory.as_inventory_entity(&self.dest_character_id)).await?; - - Ok(()) - } -} - -#[derive(Debug)] -struct TradeMeseta { - src_character_id: CharacterEntityId, - dest_character_id: CharacterEntityId, - amount: usize, -} - -#[async_trait::async_trait] -impl ItemAction for TradeMeseta { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - { - let src_meseta = item_manager.get_character_meseta_mut(&self.src_character_id)?; - src_meseta.0 -= self.amount as u32; - entity_gateway.set_character_meseta(&self.src_character_id, *src_meseta).await?; - } - { - let dest_meseta = item_manager.get_character_meseta_mut(&self.dest_character_id)?; - dest_meseta.0 += self.amount as u32; - entity_gateway.set_character_meseta(&self.dest_character_id, *dest_meseta).await?; - } - Ok(()) - } -} diff --git a/src/ship/map/mod.rs b/src/ship/map/mod.rs deleted file mode 100644 index 693fd46..0000000 --- a/src/ship/map/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub mod area; -pub mod enemy; -pub mod object; -pub mod variant; -pub mod maps; - -// TODO: don't just forward everything to the module scope -pub use area::*; -pub use enemy::*; -pub use object::*; -pub use variant::*; -pub use maps::*; diff --git a/src/ship/mod.rs b/src/ship/mod.rs deleted file mode 100644 index c58edb6..0000000 --- a/src/ship/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[allow(clippy::module_inception)] -pub mod ship; -pub mod location; -pub mod character; -pub mod client; -pub mod room; -pub mod items; -pub mod item_stats; -pub mod map; -pub mod monster; -pub mod drops; -pub mod packet; -pub mod quests; -pub mod shops; -pub mod trade; -pub mod chatcommand; diff --git a/src/ship/packet/handler/mod.rs b/src/ship/packet/handler/mod.rs deleted file mode 100644 index c921d28..0000000 --- a/src/ship/packet/handler/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub mod auth; -pub mod communication; -pub mod direct_message; -pub mod lobby; -pub mod message; -pub mod room; -pub mod settings; -pub mod quest; -pub mod ship; -pub mod trade; diff --git a/src/ship/packet/mod.rs b/src/ship/packet/mod.rs deleted file mode 100644 index 5b46ce1..0000000 --- a/src/ship/packet/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod builder; -pub mod handler; diff --git a/src/ship/room.rs b/src/ship/room.rs deleted file mode 100644 index 87e5585..0000000 --- a/src/ship/room.rs +++ /dev/null @@ -1,429 +0,0 @@ -use std::collections::HashMap; -use std::convert::{From, Into, TryFrom, TryInto}; -use std::path::PathBuf; -use async_std::sync::{Arc, RwLock, RwLockReadGuard}; -use futures::future::BoxFuture; -use futures::stream::{FuturesOrdered, Stream}; - -use thiserror::Error; -use rand::Rng; - -use crate::ship::map::Maps; -use crate::ship::drops::DropTable; -use crate::entity::character::SectionID; -use crate::ship::monster::{load_monster_stats_table, MonsterType, MonsterStats}; -use crate::ship::map::area::MapAreaLookup; -use crate::ship::quests; -use crate::ship::ship::{ShipError, ShipEvent}; -use crate::ship::location::{MAX_ROOMS, RoomId}; - -#[derive(Clone)] -pub struct Rooms([Arc>>; MAX_ROOMS]); - -impl Default for Rooms { - fn default() -> Rooms { - Rooms(core::array::from_fn(|_| Arc::new(RwLock::new(None)))) - } -} - -impl Rooms { - pub async fn add(&self, room_id: RoomId, room: RoomState) -> Result<(), anyhow::Error> { - *self.0 - .get(room_id.0) - .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? - .write() - .await = Some(room); - Ok(()) - } - - pub async fn remove(&self, room_id: RoomId) { - if let Some(room) = self.0.get(room_id.0) { - *room - .write() - .await = None; - } - } - - pub async fn exists(&self, room_id: RoomId) -> bool { - match self.0.get(room_id.0) { - Some(room) => { - room - .read() - .await - .is_some() - }, - None => false, - } - } - - pub async fn with<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result - where - T: Send, - F: for<'b> FnOnce(&'b RoomState) -> BoxFuture<'b, T> + Send + 'a - { - let room = self.0 - .get(room_id.0) - .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? - .read() - .await; - if let Some(room) = room.as_ref() { - Ok(func(room).await) - } - else { - Err(ShipError::InvalidRoom(room_id.0 as u32).into()) - } - } - - pub async fn with_mut<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result - where - T: Send, - F: for<'b> FnOnce(&'b mut RoomState) -> BoxFuture<'b, T> + Send + 'a - { - let mut room = self.0 - .get(room_id.0) - .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? - .write() - .await; - - if let Some(room) = room.as_mut() { - Ok(func(room).await) - } - else { - Err(ShipError::InvalidRoom(room_id.0 as u32).into()) - } - } - - pub async fn get(&self, room_id: RoomId) -> RwLockReadGuard> { - self.0 - .get(room_id.0) - .unwrap() - .read() - .await - } - - pub fn stream(&self) -> impl Stream>> { - self.0 - .iter() - .map(|room| async move { - room - .read() - .await - }) - .collect::>() - } -} - -#[derive(Debug, Error)] -#[error("")] -pub enum RoomCreationError { - InvalidMode, - InvalidEpisode(u8), - InvalidDifficulty(u8), - CouldNotLoadMonsterStats(RoomMode), - CouldNotLoadQuests, -} - -#[derive(Debug, Copy, Clone, derive_more::Display)] -pub enum Episode { - #[display(fmt="ep1")] - One, - #[display(fmt="ep2")] - Two, - #[display(fmt="ep4")] - Four, -} - -#[derive(Debug, Copy, Clone)] -pub enum PlayerMode{ - Single, - Multi, -} - -impl PlayerMode { - pub fn value(&self) -> u8 { - match self { - PlayerMode::Single => 1, - PlayerMode::Multi => 0, - } - } -} - -impl TryFrom for Episode { - type Error = RoomCreationError; - - fn try_from(value: u8) -> Result { - match value { - 1 => Ok(Episode::One), - 2 => Ok(Episode::Two), - 3 => Ok(Episode::Four), - _ => Err(RoomCreationError::InvalidEpisode(value)) - } - } -} - -impl From for u8 { - fn from(other: Episode) -> u8 { - match other { - Episode::One => 1, - Episode::Two => 2, - Episode::Four => 3, - } - } -} - -impl Episode { - pub fn from_quest(value: u8) -> Result { - match value { - 0 => Ok(Episode::One), - 1 => Ok(Episode::Two), - 2 => Ok(Episode::Four), - _ => Err(RoomCreationError::InvalidEpisode(value)) - } - } -} - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)] -pub enum Difficulty { - Normal, - Hard, - VeryHard, - Ultimate, -} - -impl TryFrom for Difficulty { - type Error = RoomCreationError; - - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(Difficulty::Normal), - 1 => Ok(Difficulty::Hard), - 2 => Ok(Difficulty::VeryHard), - 3 => Ok(Difficulty::Ultimate), - _ => Err(RoomCreationError::InvalidDifficulty(value)) - } - } -} - -impl From for u8 { - fn from(other: Difficulty) -> u8 { - match other { - Difficulty::Normal => 0, - Difficulty::Hard => 1, - Difficulty::VeryHard => 2, - Difficulty::Ultimate => 3, - } - } -} - -#[derive(Debug, Copy, Clone, derive_more::Display)] -pub enum RoomMode { - #[display(fmt="single")] - Single { - episode: Episode, - difficulty: Difficulty, - }, - #[display(fmt="multi")] - Multi { - episode: Episode, - difficulty: Difficulty, - }, - #[display(fmt="challenge")] - Challenge { - episode: Episode, - }, - #[display(fmt="battle")] - Battle { - episode: Episode, - difficulty: Difficulty, - } -} - - -impl RoomMode { - pub fn difficulty(&self) -> Difficulty { - match self { - RoomMode::Single {difficulty, ..} => *difficulty, - RoomMode::Multi {difficulty, ..} => *difficulty, - RoomMode::Battle {difficulty, ..} => *difficulty, - RoomMode::Challenge {..} => Difficulty::Normal, - } - } - - pub fn episode(&self) -> Episode { - match self { - RoomMode::Single {episode, ..} => *episode, - RoomMode::Multi {episode, ..} => *episode, - RoomMode::Battle {episode, ..} => *episode, - RoomMode::Challenge {episode, ..} => *episode, - } - } - - pub fn battle(&self) -> bool { - matches!(self, RoomMode::Battle {..}) - } - - pub fn challenge(&self) -> bool { - matches!(self, RoomMode::Challenge {..}) - } - - pub fn player_mode(&self) -> PlayerMode { - match self { - RoomMode::Single {..} => PlayerMode::Single, - _ => PlayerMode::Multi, - } - } -} -pub enum QuestCategoryType { - Standard, - Government, -} - -impl From for QuestCategoryType { - fn from(f: usize) -> QuestCategoryType { - match f { - 0 => QuestCategoryType::Standard, - 1 => QuestCategoryType::Government, - _ => QuestCategoryType::Standard, // TODO: panic? - } - } -} - -impl QuestCategoryType { - pub fn value(&self) -> usize { - match self { - QuestCategoryType::Standard => 0, - QuestCategoryType::Government => 1, - } - } -} - -pub struct RoomState { - pub mode: RoomMode, - pub name: String, - pub password: [u16; 16], - pub maps: Maps, - pub drop_table: Box, - pub section_id: SectionID, - pub random_seed: u32, - pub bursting: bool, - pub monster_stats: Box>, - pub map_areas: MapAreaLookup, - pub quest_group: QuestCategoryType, - pub quests: Vec, - // items on ground - // enemy info -} - -impl RoomState { - pub fn get_flags_for_room_list(&self) -> u8 { - let mut flags = 0u8; - - match self.mode { - RoomMode::Single {..} => {flags += 0x04} - RoomMode::Battle {..} => {flags += 0x10}, - RoomMode::Challenge {..} => {flags += 0x20}, - _ => {flags += 0x40}, - }; - - if self.password[0] > 0 { - flags += 0x02; - } - flags - } - - pub fn get_episode_for_room_list(&self) -> u8 { - let episode: u8 = self.mode.episode().into(); - - match self.mode { - RoomMode::Single {..} => episode + 0x10, - _ => episode + 0x40, - } - } - - pub fn get_difficulty_for_room_list(&self) -> u8 { - let difficulty: u8 = self.mode.difficulty().into(); - difficulty + 0x22 - } - - pub fn set_quest_group(&mut self, group: usize) { - self.quest_group = QuestCategoryType::from(group); - } - - pub fn from_create_room(create_room: &libpso::packet::ship::CreateRoom, - map_builder: Arc Maps + Send + Sync>>, - drop_table_builder: Arc DropTable + Send + Sync>>, - section_id: SectionID, - event: ShipEvent) - -> Result { - if [create_room.battle, create_room.challenge, create_room.single_player].iter().sum::() > 1 { - return Err(RoomCreationError::InvalidMode) - } - - let room_mode = if create_room.battle == 1 { - RoomMode::Battle { - episode: create_room.episode.try_into()?, - difficulty: create_room.difficulty.try_into()?, - } - } - else if create_room.challenge == 1 { - RoomMode::Challenge { - episode: create_room.episode.try_into()?, - } - } - else if create_room.single_player == 1 { - RoomMode::Single { - episode: create_room.episode.try_into()?, - difficulty: create_room.difficulty.try_into()?, - } - } - else { // normal multimode - RoomMode::Multi { - episode: create_room.episode.try_into()?, - difficulty: create_room.difficulty.try_into()?, - } - }; - - - // push the usual set of quests for the selected mode - let mut qpath = PathBuf::from("data/quests/bb"); - qpath.push(room_mode.episode().to_string()); - qpath.push(room_mode.to_string()); - qpath.push("quests.toml"); - let mut room_quests = Vec::new(); - let quest_list = match quests::load_quests(qpath) { - Ok(qlist) => qlist, - Err(_) => return Err(RoomCreationError::CouldNotLoadQuests), - }; - - room_quests.push(quest_list); - - // if multiplayer also push the government quests - if let RoomMode::Multi {..} = room_mode { - qpath = PathBuf::from("data/quests/bb/"); - qpath.push(room_mode.episode().to_string()); - qpath.push("government/quests.toml"); - - let quest_list = match quests::load_quests(qpath) { - Ok(qlist) => qlist, - Err(_) => return Err(RoomCreationError::CouldNotLoadQuests), - }; - - room_quests.push(quest_list); - } - - Ok(RoomState { - monster_stats: Box::new(load_monster_stats_table(&room_mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(room_mode))?), - mode: room_mode, - random_seed: rand::thread_rng().gen(), - name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(), - password: create_room.password, - maps: map_builder(room_mode, event), - section_id, - drop_table: Box::new(drop_table_builder(room_mode.episode(), room_mode.difficulty(), section_id)), - bursting: false, - map_areas: MapAreaLookup::new(&room_mode.episode()), - quest_group: QuestCategoryType::Standard, - quests: room_quests, - }) - } -} diff --git a/src/ship/shops/mod.rs b/src/ship/shops/mod.rs deleted file mode 100644 index 573b667..0000000 --- a/src/ship/shops/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -mod weapon; -mod tool; -mod armor; - -use crate::entity::item::ItemDetail; - -pub trait ShopItem { - fn price(&self) -> usize; - fn as_bytes(&self) -> [u8; 12]; - fn as_item(&self) -> ItemDetail; -} - -pub enum ShopType { - Weapon, - Tool, - Armor -} - -pub use weapon::{WeaponShop, WeaponShopItem}; -pub use tool::{ToolShop, ToolShopItem}; -pub use armor::{ArmorShop, ArmorShopItem}; diff --git a/src/ship_server/Cargo.toml b/src/ship_server/Cargo.toml new file mode 100644 index 0000000..604dda8 --- /dev/null +++ b/src/ship_server/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "ship_server" +version = "0.1.0" +edition = "2021" + +[dependencies] +networking = { workspace = true } +trade = { workspace = true } +maps = { workspace = true } +location = { workspace = true } +room = { workspace = true } +shops = { workspace = true } +client = { workspace = true } +pktbuilder = { workspace = true } +items = { workspace = true } +entity = { workspace = true } +drops = { workspace = true } +quests = { workspace = true } +stats = { workspace = true } + +login_server = { workspace = true } + +libpso = { workspace = true } + +async-std = { workspace = true } +async-trait = { workspace = true } +log = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } +rand = { workspace = true } +serde = { workspace = true } +futures = { workspace = true } diff --git a/src/ship/packet/handler/auth.rs b/src/ship_server/src/auth.rs similarity index 87% rename from src/ship/packet/handler/auth.rs rename to src/ship_server/src/auth.rs index 698de75..b8f746e 100644 --- a/src/ship/packet/handler/auth.rs +++ b/src/ship_server/src/auth.rs @@ -1,11 +1,12 @@ use libpso::packet::login::{Login, LoginResponse, AccountStatus, Session}; use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients}; -use crate::login::login::get_login_status; -use crate::entity::gateway::EntityGateway; -use crate::ship::items::state::ItemState; -use crate::common::interserver::ShipMessage; +use networking::serverstate::ClientId; +use crate::{SendShipPacket, ShipError}; +use client::{Clients, ClientState}; +use login_server::login::get_login_status; +use entity::gateway::EntityGateway; +use items::state::ItemState; +use networking::interserver::ShipMessage; #[allow(clippy::too_many_arguments)] pub async fn validate_login(id: ClientId, diff --git a/src/ship/chatcommand.rs b/src/ship_server/src/chatcommand.rs similarity index 90% rename from src/ship/chatcommand.rs rename to src/ship_server/src/chatcommand.rs index 97d5054..a2d3ff1 100644 --- a/src/ship/chatcommand.rs +++ b/src/ship_server/src/chatcommand.rs @@ -1,11 +1,11 @@ use libpso::packet::ship::PlayerChat; -use crate::entity::gateway::EntityGateway; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{ShipServerState, SendShipPacket}; -use crate::ship::client::Clients; -use crate::ship::items::state::ItemState; -use crate::entity::item::{BankName, BankIdentifier}; -use crate::ship::packet::builder::message::bank_item_list; +use entity::gateway::EntityGateway; +use networking::serverstate::ClientId; +use crate::{ShipServerState, SendShipPacket}; +use client::Clients; +use items::state::ItemState; +use entity::item::{BankName, BankIdentifier}; +use pktbuilder::message::bank_item_list; async fn default_bank<'a, EG>(id: ClientId, entity_gateway: &mut EG, diff --git a/src/ship/packet/handler/communication.rs b/src/ship_server/src/communication.rs similarity index 92% rename from src/ship/packet/handler/communication.rs rename to src/ship_server/src/communication.rs index c0ac3e5..4949acd 100644 --- a/src/ship/packet/handler/communication.rs +++ b/src/ship_server/src/communication.rs @@ -1,8 +1,8 @@ use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, Clients}; -use crate::ship::location::{ClientLocation}; -use crate::entity::gateway::EntityGateway; +use networking::serverstate::ClientId; +use crate::{SendShipPacket, Clients}; +use location::ClientLocation; +use entity::gateway::EntityGateway; use futures::future::join_all; diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship_server/src/direct_message.rs similarity index 89% rename from src/ship/packet/handler/direct_message.rs rename to src/ship_server/src/direct_message.rs index 81f0146..9ec6f52 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship_server/src/direct_message.rs @@ -1,24 +1,25 @@ use log::warn; +use async_std::sync::Arc; use rand::Rng; use rand::seq::SliceRandom; use libpso::packet::ship::*; use libpso::packet::messages::*; -use crate::common::leveltable::LEVEL_TABLE; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemShops}; -use crate::ship::location::ClientLocation; -use crate::ship::drops::ItemDrop; -use crate::ship::room::Rooms; -use crate::ship::items::ClientItemId; -use crate::entity::gateway::EntityGateway; -use crate::entity::item; +use stats::leveltable::LEVEL_TABLE; +use networking::serverstate::ClientId; +use crate::{SendShipPacket, ShipError, Clients}; +use location::ClientLocation; +use drops::ItemDrop; +use room::Rooms; +use items::ClientItemId; +use entity::gateway::EntityGateway; +use entity::item; use libpso::utf8_to_utf16_array; -use crate::ship::packet::builder; -use crate::ship::shops::{ShopItem, ToolShopItem, ArmorShopItem}; -use crate::ship::items::state::{ItemState, ItemStateError}; -use crate::ship::items::floor::{FloorType, FloorItemDetail}; -use crate::ship::items::actions::TriggerCreateItem; -use crate::ship::items::tasks::{pick_up_item, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, buy_shop_item, enemy_drops_item, take_meseta, apply_modifier}; +use pktbuilder as builder; +use shops::{ItemShops, ShopItem, ToolShopItem, ArmorShopItem}; +use items::state::{ItemState, ItemStateError}; +use items::floor::{FloorType, FloorItemDetail}; +use items::actions::TriggerCreateItem; +use items::tasks::{pick_up_item, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, buy_shop_item, enemy_drops_item, box_drops_item, take_meseta, apply_modifier}; const BANK_ACTION_DEPOSIT: u8 = 0; const BANK_ACTION_WITHDRAW: u8 = 1; @@ -89,8 +90,8 @@ where EG: EntityGateway + 'static, { let room_id = client_location.get_room(id).await?; - let monster = rooms.with(room_id, |room| Box::pin(async move { - room.maps.enemy_by_id(request_item.enemy_id as usize) + let (room_entity_id, monster) = rooms.with(room_id, |room| Box::pin(async move { + Ok::<_, anyhow::Error>((room.room_id, room.maps.enemy_by_id(request_item.enemy_id as usize)?)) })).await??; if monster.dropped_item { @@ -121,8 +122,8 @@ where client.character.id })).await?; - let floor_item = enemy_drops_item(item_state, entity_gateway, character_id, item_drop).await?; - let item_drop_msg = builder::message::item_drop(request_item.client, request_item.target, &floor_item)?; + let floor_item = enemy_drops_item(item_state, entity_gateway, character_id, room_entity_id, monster.monster, item_drop).await?; + let item_drop_msg = builder::message::item_drop(request_item.client, request_item.target, &floor_item); item_drop_packets.push((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg))))); } @@ -149,10 +150,10 @@ where let mut item_state = item_state.clone(); Box::pin(async move { let (item, floor_type) = item_state.get_floor_item(&client.character.id, &ClientItemId(pickup_item.item_id)).await?; - let remove_item = builder::message::remove_item_from_floor(area_client, &item)?; + let remove_item = builder::message::remove_item_from_floor(area_client, &item); let create_item = match &item.item { - FloorItemDetail::Individual(individual_floor_item) => Some(builder::message::create_individual_item(area_client, item.item_id, individual_floor_item)?), - FloorItemDetail::Stacked(stacked_floor_item) => Some(builder::message::create_stacked_item(area_client, item.item_id, &stacked_floor_item.tool, stacked_floor_item.count())?), + FloorItemDetail::Individual(individual_floor_item) => Some(builder::message::create_individual_item(area_client, item.item_id, individual_floor_item)), + FloorItemDetail::Stacked(stacked_floor_item) => Some(builder::message::create_stacked_item(area_client, item.item_id, &stacked_floor_item.tool, stacked_floor_item.count())), FloorItemDetail::Meseta(_) => None, }; @@ -200,8 +201,8 @@ where EG: EntityGateway + Clone + 'static { let room_id = client_location.get_room(id).await?; - let box_object = rooms.with(room_id, |room| Box::pin(async move { - room.maps.object_by_id(box_drop_request.object_id as usize) + let (room_entity_id, box_object) = rooms.with(room_id, |room| Box::pin(async move { + Ok::<_, anyhow::Error>((room.room_id, room.maps.object_by_id(box_drop_request.object_id as usize)?)) })).await??; if box_object.dropped_item { @@ -232,9 +233,9 @@ where let character_id = clients.with(area_client.client, |client| Box::pin(async move { client.character.id })).await?; - let floor_item = enemy_drops_item(item_state, entity_gateway, character_id, item_drop).await?; + let floor_item = box_drops_item(item_state, entity_gateway, character_id, room_entity_id, item_drop).await?; //let floor_item = enemy_drops_item(item_state, &mut entity_gateway, client.character.id, item_drop).await?; - let item_drop_msg = builder::message::item_drop(box_drop_request.client, box_drop_request.target, &floor_item)?; + let item_drop_msg = builder::message::item_drop(box_drop_request.client, box_drop_request.target, &floor_item); item_drop_packets.push((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg))))) } @@ -293,7 +294,7 @@ where } else { let item_added_to_inventory = withdraw_item(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32).await?; - let item_created = builder::message::create_withdrawn_inventory_item2(area_client, &item_added_to_inventory)?; + let item_created = builder::message::create_withdrawn_inventory_item2(area_client, &item_added_to_inventory); vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(item_created)))] } }, @@ -320,45 +321,30 @@ pub async fn shop_request(id: ClientId, client_location: &ClientLocation, clients: &Clients, rooms: &Rooms, - shops: &ItemShops) + shops: &Arc>) -> Result, anyhow::Error> { - //let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let room_id = client_location.get_room(id).await?; - /* - let room = rooms.get(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? - .as_ref() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; - */ let difficulty = rooms.with(room_id, |room| Box::pin(async move { room.mode.difficulty() })).await?; let shop_list = clients.with_mut(id, |client| { - let mut shops = shops.clone(); + let shops = shops.clone(); Box::pin(async move { let level = LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) as usize; match shop_request.shop_type { SHOP_OPTION_WEAPON => { - client.weapon_shop = shops.weapon_shop.get_mut(&(difficulty, client.character.section_id)) - .ok_or(ShipError::ShopError)? - .lock() + client.weapon_shop = shops.generate_weapon_list(difficulty, client.character.section_id, level) .await - .generate_weapon_list(level); + .ok_or(ShipError::ShopError)?; Ok(builder::message::shop_list(shop_request.shop_type, &client.weapon_shop)) }, SHOP_OPTION_TOOL => { - client.tool_shop = shops.tool_shop - .lock() - .await - .generate_tool_list(level); + client.tool_shop = shops.generate_tool_list(level).await; Ok(builder::message::shop_list(shop_request.shop_type, &client.tool_shop)) }, SHOP_OPTION_ARMOR => { - client.armor_shop = shops.armor_shop - .lock() - .await - .generate_armor_list(level); + client.armor_shop = shops.generate_armor_list(level).await; Ok(builder::message::shop_list(shop_request.shop_type, &client.armor_shop)) }, _ => { @@ -440,7 +426,7 @@ where _ => {} } } - Ok::<_, anyhow::Error>(builder::message::create_withdrawn_inventory_item(area_client, &inventory_item)?) + Ok::<_, anyhow::Error>(builder::message::create_withdrawn_inventory_item(area_client, &inventory_item)) })}).await??; let other_clients_in_area = client_location.get_client_neighbors(id).await?; @@ -503,7 +489,7 @@ where }); take_meseta(&mut item_state, &mut entity_gateway, &client.character.id, item::Meseta(100)).await?; - Ok::<_, anyhow::Error>(builder::message::tek_preview(ClientItemId(tek_request.item_id), &weapon)?) + Ok::<_, anyhow::Error>(builder::message::tek_preview(ClientItemId(tek_request.item_id), &weapon)) })}).await??; @@ -539,7 +525,7 @@ where }; let weapon = apply_modifier(&mut item_state, &mut entity_gateway, &client.character, item_id, item::ItemModifier::WeaponModifier(modifier)).await?; - let create_item_pkt = builder::message::create_individual_item(area_client, item_id, &weapon)?; + let create_item_pkt = builder::message::create_individual_item(area_client, item_id, &weapon); Ok(neighbors.into_iter() .map(move |c| { diff --git a/src/ship/ship.rs b/src/ship_server/src/lib.rs similarity index 70% rename from src/ship/ship.rs rename to src/ship_server/src/lib.rs index 8a1c6fa..f6d0ed1 100644 --- a/src/ship/ship.rs +++ b/src/ship_server/src/lib.rs @@ -1,9 +1,20 @@ -#![allow(dead_code, unused_must_use)] +#![allow(clippy::type_complexity)] +mod auth; +mod communication; +mod direct_message; +mod lobby; +mod message; +mod room; +mod settings; +mod quest; +mod ship; +pub mod trade; +mod chatcommand; + use std::net::Ipv4Addr; -use std::collections::HashMap; use async_std::channel; -use async_std::sync::{Arc, Mutex, RwLock}; +use async_std::sync::{Arc, RwLock}; use rand::Rng; use thiserror::Error; @@ -14,79 +25,29 @@ use libpso::{PacketParseError, PSOPacket}; use libpso::crypto::bb::PSOBBCipher; use libpso::packet::ship::{BLOCK_MENU_ID, ROOM_MENU_ID}; -use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; -use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; -use crate::common::interserver::{AuthToken, Ship, ServerId, InterserverActor, LoginMessage, ShipMessage}; -use crate::login::character::SHIP_MENU_ID; -use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::character::SectionID; -use crate::ship::location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; -use crate::ship::drops::DropTable; -use crate::ship::items; -use crate::ship::room; -use crate::ship::map::{Maps, MapsError, MapAreaError, generate_free_roam_maps}; -use crate::ship::packet::handler; -use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop}; -use crate::ship::trade::TradeState; -use crate::ship::chatcommand; - -// TODO: remove once stuff settles down -pub use crate::ship::client::*; +use networking::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; +use networking::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; +use networking::interserver::{AuthToken, Ship, ServerId, InterserverActor, LoginMessage, ShipMessage}; +use pktbuilder::ship::SHIP_MENU_ID; +use entity::gateway::{EntityGateway, GatewayError}; +use entity::character::SectionID; +use entity::room::RoomNote; +use location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; +use drops::{DropTable, StandardDropTable}; +use ::room::{Rooms, RoomCreationError}; +use maps::room::{RoomMode, Episode, Difficulty}; +use quests::{load_standard_quests, load_government_quests}; +use quests::{QuestList, QuestLoadError}; +use maps::Holiday; +use maps::area::MapAreaError; +use maps::maps::{Maps, MapsError, generate_free_roam_maps}; +use shops::{ItemShops, StandardItemShops}; +use ::trade::{TradeState, TradeStateError}; +use pktbuilder::quest::{QUEST_CATEGORY_MENU_ID, QUEST_SELECT_MENU_ID}; + +pub use client::{Clients, ClientState}; pub const SHIP_PORT: u16 = 23423; -pub const QUEST_CATEGORY_MENU_ID: u32 = 0xA2; -pub const QUEST_SELECT_MENU_ID: u32 = 0xA3; - -#[derive(Clone, Copy)] -pub enum ShipEvent { - None, - Christmas, - Valentines, - Easter, - Halloween, - Sonic, - NewYear, - Summer, - White, - Wedding, - Fall, - Spring, - Summer2, - Spring2, -} - -impl From for u32 { - fn from(other: ShipEvent) -> u32 { - u16::from(other) as u32 - } -} - -impl From for u16 { - fn from(other: ShipEvent) -> u16 { - u8::from(other) as u16 - } -} - -impl From for u8 { - fn from(other: ShipEvent) -> u8 { - match other { - ShipEvent::None => 0, - ShipEvent::Christmas => 1, - ShipEvent::Valentines => 3, - ShipEvent::Easter => 4, - ShipEvent::Halloween => 5, - ShipEvent::Sonic => 6, - ShipEvent::NewYear => 7, - ShipEvent::Summer => 8, - ShipEvent::White => 9, - ShipEvent::Wedding => 10, - ShipEvent::Fall => 11, - ShipEvent::Spring => 12, - ShipEvent::Summer2 => 13, - ShipEvent::Spring2 => 14, - } - } -} #[derive(Error, Debug)] @@ -138,7 +99,7 @@ pub enum ShipError { #[error("gateway error {0}")] GatewayError(#[from] GatewayError), #[error("unknown monster {0}")] - UnknownMonster(crate::ship::monster::MonsterType), + UnknownMonster(maps::monster::MonsterType), #[error("invalid ship {0}")] InvalidShip(usize), #[error("invalid block {0}")] @@ -146,13 +107,13 @@ pub enum ShipError { #[error("invalid item {0}")] InvalidItem(items::ClientItemId), #[error("trade error {0}")] - TradeError(#[from] crate::ship::packet::handler::trade::TradeError), + TradeError(#[from] trade::TradeError), #[error("trade state error {0}")] - TradeStateError(#[from] crate::ship::trade::TradeStateError), + TradeStateError(#[from] TradeStateError), #[error("message error {0}")] - MessageError(#[from] crate::ship::packet::handler::direct_message::MessageError), + MessageError(#[from] crate::direct_message::MessageError), #[error("room creation error {0}")] - RoomCreationError(#[from] room::RoomCreationError), + RoomCreationError(#[from] RoomCreationError), #[error("channel send error {0}")] SendError(#[from] async_std::channel::SendError), } @@ -166,6 +127,7 @@ impl> From for ShipError { */ + #[derive(Debug)] pub enum RecvShipPacket { Login(Login), @@ -292,6 +254,7 @@ pub enum SendShipPacket { TradeSuccessful(TradeSuccessful), LobbyEvent(LobbyEvent), LargeDialog(LargeDialog), + RightText(RightText), } impl SendServerPacket for SendShipPacket { @@ -336,34 +299,7 @@ impl SendServerPacket for SendShipPacket { SendShipPacket::TradeSuccessful(pkt) => pkt.as_bytes(), SendShipPacket::LobbyEvent(pkt) => pkt.as_bytes(), SendShipPacket::LargeDialog(pkt) => pkt.as_bytes(), - } - } -} - -#[derive(Clone)] -pub struct ItemShops { - pub weapon_shop: HashMap<(room::Difficulty, SectionID), Arc>>>, - pub tool_shop: Arc>>, - pub armor_shop: Arc>>, -} - -impl Default for ItemShops { - fn default() -> ItemShops { - let difficulty = [room::Difficulty::Normal, room::Difficulty::Hard, room::Difficulty::VeryHard, room::Difficulty::Ultimate]; - let section_id = [SectionID::Viridia, SectionID::Greenill, SectionID::Skyly, SectionID::Bluefull, SectionID::Purplenum, - SectionID::Pinkal, SectionID::Redria, SectionID::Oran, SectionID::Yellowboze, SectionID::Whitill]; - - let mut weapon_shop = HashMap::new(); - for d in difficulty.iter() { - for id in section_id.iter() { - weapon_shop.insert((*d, *id), Arc::new(Mutex::new(WeaponShop::new(*d, *id)))); - } - } - - ItemShops { - weapon_shop, - tool_shop: Arc::new(Mutex::new(ToolShop::default())), - armor_shop: Arc::new(Mutex::new(ArmorShop::default())), + SendShipPacket::RightText(pkt) => pkt.as_bytes(), } } } @@ -375,9 +311,12 @@ pub struct ShipServerStateBuilder { ip: Option, port: Option, auth_token: Option, - event: Option, - map_builder: Option Maps + Send + Sync>>, - drop_table_builder: Option DropTable + Send + Sync>>, + event: Option, + shops: Option>, + map_builder: Option Maps + Send + Sync>>, + drop_table_builder: Option Box + Send + Sync>>, + standard_quest_builder: Option Result + Send + Sync>>, + government_quest_builder: Option Result + Send + Sync>>, num_blocks: usize, } @@ -390,8 +329,11 @@ impl Default for ShipServerStateBuilder port: None, auth_token: None, event: None, + shops: None, map_builder: None, drop_table_builder: None, + standard_quest_builder: None, + government_quest_builder: None, num_blocks: 2, } } @@ -429,23 +371,41 @@ impl ShipServerStateBuilder { } #[must_use] - pub fn event(mut self, event: ShipEvent) -> ShipServerStateBuilder { + pub fn event(mut self, event: Holiday) -> ShipServerStateBuilder { self.event = Some(event); self } #[must_use] - pub fn map_builder(mut self, map_builder: Box Maps + Send + Sync>) -> ShipServerStateBuilder { + pub fn map_builder(mut self, map_builder: Box Maps + Send + Sync>) -> ShipServerStateBuilder { self.map_builder = Some(map_builder); self } #[must_use] - pub fn drop_table_builder(mut self, drop_table_builder: Box DropTable + Send + Sync>) -> ShipServerStateBuilder { + pub fn drop_table_builder(mut self, drop_table_builder: Box Box + Send + Sync>) -> ShipServerStateBuilder { self.drop_table_builder = Some(drop_table_builder); self } + #[must_use] + pub fn standard_quest_builder(mut self, standard_quest_builder: Box Result + Send + Sync>) -> ShipServerStateBuilder { + self.standard_quest_builder = Some(standard_quest_builder); + self + } + + #[must_use] + pub fn government_quest_builder(mut self, government_quest_builder: Box Result + Send + Sync>) -> ShipServerStateBuilder { + self.government_quest_builder = Some(government_quest_builder); + self + } + + #[must_use] + pub fn item_shops(mut self, item_shops: impl ItemShops + Send + Sync + 'static) -> ShipServerStateBuilder { + self.shops = Some(Box::new(item_shops)); + self + } + #[must_use] pub fn blocks(mut self, num_blocks: usize) -> ShipServerStateBuilder { self.num_blocks = num_blocks; @@ -461,11 +421,13 @@ impl ShipServerStateBuilder { item_state: items::state::ItemState::default(), ip: self.ip.unwrap_or_else(|| Ipv4Addr::new(127,0,0,1)), port: self.port.unwrap_or(SHIP_PORT), - shops: ItemShops::default(), + shops: Arc::new(self.shops.unwrap_or_else(|| Box::::default())), blocks: Blocks(blocks), - event: self.event.unwrap_or(ShipEvent::None), - map_builder: Arc::new(self.map_builder.unwrap_or(Box::new(generate_free_roam_maps))), - drop_table_builder: Arc::new(self.drop_table_builder.unwrap_or(Box::new(DropTable::new))), + event: self.event.unwrap_or(Holiday::None), + map_builder: Arc::new(self.map_builder.unwrap_or_else(|| Box::new(generate_free_roam_maps))), + drop_table_builder: Arc::new(self.drop_table_builder.unwrap_or_else(|| Box::new(StandardDropTable::new))), + standard_quest_builder: Arc::new(self.standard_quest_builder.unwrap_or_else(|| Box::new(load_standard_quests))), + government_quest_builder: Arc::new(self.government_quest_builder.unwrap_or_else(|| Box::new(load_government_quests))), auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())), ship_list: Arc::new(RwLock::new(Vec::new())), @@ -479,7 +441,7 @@ impl ShipServerStateBuilder { #[derive(Clone, Default)] pub struct Block { client_location: ClientLocation, - pub rooms: room::Rooms, + pub rooms: Rooms, } #[derive(Clone)] @@ -502,9 +464,9 @@ pub struct ShipServerState { pub clients: Clients, name: String, pub(crate) item_state: items::state::ItemState, - shops: ItemShops, + shops: Arc>, pub blocks: Blocks, - event: ShipEvent, + event: Holiday, ip: Ipv4Addr, port: u16, @@ -513,8 +475,10 @@ pub struct ShipServerState { ship_list: Arc>>, shipgate_sender: Option>, trades: TradeState, - map_builder: Arc Maps + Send + Sync>>, - drop_table_builder: Arc DropTable + Send + Sync>>, + map_builder: Arc Maps + Send + Sync>>, + drop_table_builder: Arc Box + Send + Sync>>, + standard_quest_builder: Arc Result + Send + Sync>>, + government_quest_builder: Arc Result + Send + Sync>>, } impl ShipServerState { @@ -526,54 +490,58 @@ impl ShipServerState { Ok(match msg.msg { GameMessage::RequestExp(request_exp) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::request_exp(id, request_exp, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms).await? + message::request_exp(id, request_exp, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms).await? }, GameMessage::PlayerDropItem(player_drop_item) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? + message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? }, GameMessage::DropCoordinates(drop_coordinates) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::drop_coordinates(id, drop_coordinates, &block.client_location, &self.clients, &block.rooms).await? + message::drop_coordinates(id, drop_coordinates, &block.client_location, &self.clients, &block.rooms).await? }, GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerChangedMap(_) | GameMessage::PlayerChangedMap2(_) | GameMessage::TellOtherPlayerMyLocation(_) | GameMessage::PlayerWarpingToFloor(_) | GameMessage::PlayerTeleported(_) | GameMessage::PlayerStopped(_) | GameMessage::PlayerLoadedIn(_) | GameMessage::PlayerWalking(_) | GameMessage::PlayerRunning(_) | GameMessage::PlayerWarped(_) | GameMessage::PlayerChangedFloor(_) | GameMessage::InitializeSpeechNpc(_) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::update_player_position(id, msg, &self.clients, &block.client_location, &block.rooms).await? + message::update_player_position(id, msg, &self.clients, &block.client_location, &block.rooms).await? }, GameMessage::ChargeAttack(charge_attack) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::charge_attack(id, charge_attack, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + message::charge_attack(id, charge_attack, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerUseItem(player_use_item) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::player_uses_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + message::player_uses_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerFeedMag(player_feed_mag) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::message::player_feed_mag(id, player_feed_mag, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + message::player_feed_mag(id, player_feed_mag, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerEquipItem(player_equip_item) => { - handler::message::player_equips_item(id, player_equip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + message::player_equips_item(id, player_equip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerUnequipItem(player_unequip_item) => { - handler::message::player_unequips_item(id, player_unequip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + message::player_unequips_item(id, player_unequip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::SortItems(sort_items) => { - handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerSoldItem(player_sold_item) => { - handler::message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + }, + GameMessage::FloorItemLimitItemDeletion(floor_item_limit_delete) => { + let block = self.blocks.get_from_client(id, &self.clients).await?; + message::floor_item_limit_deletion(id, floor_item_limit_delete, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? }, _ => { let cmsg = msg.clone(); @@ -592,37 +560,37 @@ impl ShipServerState { let block = self.blocks.get_from_client(id, &self.clients).await?; Ok(match msg.msg { GameMessage::GuildcardSend(guildcard_send) => { - handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients).await? + direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients).await? }, GameMessage::RequestItem(request_item) => { - handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? + direct_message::request_item(id, request_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? }, GameMessage::PickupItem(pickup_item) => { - handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::BoxDropRequest(box_drop_request) => { - handler::direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? + direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? }, GameMessage::BankRequest(_bank_request) => { - handler::direct_message::send_bank_list(id, &self.clients, &mut self.item_state).await? + direct_message::send_bank_list(id, &self.clients, &mut self.item_state).await? }, GameMessage::BankInteraction(bank_interaction) => { - handler::direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::ShopRequest(shop_request) => { - handler::direct_message::shop_request(id, shop_request, &block.client_location, &self.clients, &block.rooms, &self.shops).await? + direct_message::shop_request(id, shop_request, &block.client_location, &self.clients, &block.rooms, &self.shops).await? }, GameMessage::BuyItem(buy_item) => { - handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::TekRequest(tek_request) => { - handler::direct_message::request_tek_item(id, tek_request, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + direct_message::request_tek_item(id, tek_request, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::TekAccept(tek_accept) => { - handler::direct_message::accept_tek_item(id, tek_accept, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + direct_message::accept_tek_item(id, tek_accept, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::TradeRequest(trade_request) => { - handler::trade::trade_request(id, trade_request, target, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? + trade::trade_request(id, trade_request, target, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? }, _ => { let cmsg = msg.clone(); @@ -668,7 +636,7 @@ impl ServerState for ShipServerState { Ok(match pkt { RecvShipPacket::Login(login) => { - handler::auth::validate_login(id, login, &mut self.entity_gateway, &mut self.clients, &mut self.item_state, &self.shipgate_sender, &self.name, self.blocks.0.len()) + auth::validate_login(id, login, &mut self.entity_gateway, &mut self.clients, &mut self.item_state, &self.shipgate_sender, &self.name, self.blocks.0.len()) .await? .into_iter() .map(move |pkt| (id, pkt)) @@ -677,7 +645,7 @@ impl ServerState for ShipServerState { RecvShipPacket::QuestDetailRequest(questdetailrequest) => { let block = self.blocks.get_from_client(id, &self.clients).await?; match questdetailrequest.menu { - QUEST_SELECT_MENU_ID => handler::quest::quest_detail(id, questdetailrequest, &block.client_location, &block.rooms).await?, + QUEST_SELECT_MENU_ID => quest::quest_detail(id, questdetailrequest, &block.client_location, &block.rooms).await?, _ => unreachable!(), } }, @@ -685,27 +653,27 @@ impl ServerState for ShipServerState { let block = self.blocks.get_from_client(id, &self.clients).await?; match menuselect.menu { SHIP_MENU_ID => { - let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().flatten(); - let select_ship = handler::ship::selected_ship(id, menuselect, &self.ship_list).await?; + let leave_lobby = lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().flatten(); + let select_ship = ship::selected_ship(id, menuselect, &self.ship_list).await?; leave_lobby.chain(select_ship).collect() } BLOCK_MENU_ID => { - let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().flatten(); - let select_block = handler::lobby::block_selected(id, menuselect, &self.clients, &self.item_state).await?.into_iter(); + let leave_lobby = lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().flatten(); + let select_block = lobby::block_selected(id, menuselect, &self.clients, &self.item_state).await?.into_iter(); leave_lobby.chain(select_block).collect() } - ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.event).await?, - QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &block.client_location, &block.rooms).await?, + ROOM_MENU_ID => room::join_room(id, menuselect, &mut self.entity_gateway, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.event).await?, + QUEST_CATEGORY_MENU_ID => quest::select_quest_category(id, menuselect, &block.client_location, &block.rooms).await?, _ => unreachable!(), } }, RecvShipPacket::QuestMenuSelect(questmenuselect) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::quest::player_chose_quest(id, questmenuselect, &self.clients, &block.client_location, &block.rooms, self.event).await? + quest::player_chose_quest(id, questmenuselect, &self.clients, &block.client_location, &block.rooms, self.event).await? }, RecvShipPacket::MenuDetail(menudetail) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients).await? + lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients).await? }, RecvShipPacket::RoomPasswordReq(room_password_req) => { let block = self.blocks.get_from_client(id, &self.clients).await?; @@ -719,7 +687,7 @@ impl ServerState for ShipServerState { menu: room_password_req.menu, item: room_password_req.item, }; - handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.event).await? + room::join_room(id, menuselect, &mut self.entity_gateway, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.event).await? } else { vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))] @@ -727,7 +695,7 @@ impl ServerState for ShipServerState { }, RecvShipPacket::CharData(chardata) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state, self.event).await? + lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state, self.event).await? }, RecvShipPacket::Message(msg) => { self.message(id, msg).await? @@ -745,38 +713,40 @@ impl ServerState for ShipServerState { }, None => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::communication::player_chat(id, msg, &block.client_location, &self.clients).await? + communication::player_chat(id, msg, &block.client_location, &self.clients).await? } } }, RecvShipPacket::CreateRoom(create_room) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::room::create_room(id, create_room, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.map_builder.clone(), self.drop_table_builder.clone(), self.event).await? + room::create_room(id, create_room, &mut self.entity_gateway, &mut block.client_location, &self.clients, &mut self.item_state, + &block.rooms, self.map_builder.clone(), self.drop_table_builder.clone(), + self.standard_quest_builder.clone(), self.government_quest_builder.clone(), self.event).await? }, RecvShipPacket::RoomNameRequest(_req) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::room::room_name_request(id, &block.client_location, &block.rooms).await? + room::room_name_request(id, &block.client_location, &block.rooms).await? }, RecvShipPacket::UpdateTechMenu(pkt) => { - handler::settings::update_tech_menu(id, pkt, &self.clients, &mut self.entity_gateway).await? + settings::update_tech_menu(id, pkt, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::UpdateConfig(pkt) => { - handler::settings::update_config(id, pkt, &self.clients, &mut self.entity_gateway).await? + settings::update_config(id, pkt, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::ViewInfoboardRequest(_pkt) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::communication::request_infoboard(id, &block.client_location, &self.clients).await? + communication::request_infoboard(id, &block.client_location, &self.clients).await? }, RecvShipPacket::WriteInfoboard(pkt) => { - handler::communication::write_infoboard(id, pkt, &self.clients, &mut self.entity_gateway).await? + communication::write_infoboard(id, pkt, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::RoomListRequest(_req) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::room::request_room_list(id, &block.client_location, &block.rooms).await + room::request_room_list(id, &block.client_location, &block.rooms).await }, RecvShipPacket::Like62ButCooler(cool62) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::room::cool_62(id, cool62, &block.client_location).await? + room::cool_62(id, cool62, &block.client_location).await? }, RecvShipPacket::ClientCharacterData(_) => { // TOOD: validate this in some way? @@ -784,57 +754,57 @@ impl ServerState for ShipServerState { }, RecvShipPacket::DoneBursting(_) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::room::done_bursting(id, &block.client_location, &block.rooms).await? + room::done_bursting(id, &block.client_location, &block.rooms).await? }, RecvShipPacket::DoneBursting2(_) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::room::done_bursting(id, &block.client_location, &block.rooms).await? + room::done_bursting(id, &block.client_location, &block.rooms).await? }, RecvShipPacket::LobbySelect(pkt) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, &mut self.entity_gateway, self.event).await? + lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, &mut self.entity_gateway, self.event).await? }, RecvShipPacket::RequestQuestList(rql) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::quest::send_quest_category_list(id, rql, &block.client_location, &block.rooms).await? + quest::send_quest_category_list(id, rql, &block.client_location, &block.rooms).await? }, RecvShipPacket::QuestFileRequest(quest_file_request) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::quest::quest_file_request(id, quest_file_request, &block.client_location, &mut block.rooms).await? + quest::quest_file_request(id, quest_file_request, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::QuestChunkAck(quest_chunk_ack) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::quest::quest_chunk_ack(id, quest_chunk_ack, &block.client_location, &block.rooms).await? + quest::quest_chunk_ack(id, quest_chunk_ack, &block.client_location, &block.rooms).await? }, RecvShipPacket::DoneLoadingQuest(_) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::quest::done_loading_quest(id, &self.clients, &block.client_location).await? + quest::done_loading_quest(id, &self.clients, &block.client_location).await? }, RecvShipPacket::FullCharacterData(_full_character_data) => { Vec::new() }, RecvShipPacket::SaveOptions(save_options) => { - handler::settings::save_options(id, save_options, &self.clients, &mut self.entity_gateway).await? + settings::save_options(id, save_options, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::RequestShipList(_) => { - handler::ship::ship_list(id, &self.ship_list).await + ship::ship_list(id, &self.ship_list).await }, RecvShipPacket::RequestShipBlockList(_) => { - handler::ship::block_list(id, &self.name, self.blocks.0.len()) + ship::block_list(id, &self.name, self.blocks.0.len()) }, RecvShipPacket::ItemsToTrade(items_to_trade) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::trade::items_to_trade(id, items_to_trade, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? + trade::items_to_trade(id, items_to_trade, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? }, RecvShipPacket::TradeConfirmed(_) => { let block = self.blocks.get_from_client(id, &self.clients).await?; - handler::trade::trade_confirmed(id, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? + trade::trade_confirmed(id, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? }, RecvShipPacket::KeyboardConfig(keyboard_config) => { - handler::settings::keyboard_config(id, keyboard_config, &self.clients, &mut self.entity_gateway).await? + settings::keyboard_config(id, keyboard_config, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::GamepadConfig(gamepad_config) => { - handler::settings::gamepad_config(id, gamepad_config, &self.clients, &mut self.entity_gateway).await? + settings::gamepad_config(id, gamepad_config, &self.clients, &mut self.entity_gateway).await? }, }) } @@ -846,6 +816,16 @@ impl ServerState for ShipServerState { let pkt = match block.client_location.get_area(id).await? { RoomLobby::Room(room) => { + let character_id = self.clients.with(id, |client| Box::pin(async { + client.character.id + })).await?; + block.rooms.with(room, |room| { + let mut entity_gateway = self.entity_gateway.clone(); + Box::pin(async move { + entity_gateway.add_room_note(room.room_id, RoomNote::PlayerJoin { + character_id, + }).await + })}).await??; if neighbors.is_empty() { block.rooms.remove(room).await; } @@ -860,9 +840,9 @@ impl ServerState for ShipServerState { if let Some(mut client) = self.clients.remove(&id).await { client.user.at_ship = false; - self.entity_gateway.save_user(&client.user).await; + self.entity_gateway.save_user(&client.user).await?; if let Some(shipgate_sender) = self.shipgate_sender.as_ref() { - shipgate_sender.send(ShipMessage::RemoveUser(client.user.id)).await; + shipgate_sender.send(ShipMessage::RemoveUser(client.user.id)).await?; } self.item_state.remove_character_from_room(&client.character).await } diff --git a/src/ship/packet/handler/lobby.rs b/src/ship_server/src/lobby.rs similarity index 82% rename from src/ship/packet/handler/lobby.rs rename to src/ship_server/src/lobby.rs index 9d7ca08..8e6090a 100644 --- a/src/ship/packet/handler/lobby.rs +++ b/src/ship_server/src/lobby.rs @@ -1,14 +1,16 @@ use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::common::leveltable::LEVEL_TABLE; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, ShipEvent}; -use crate::ship::room::Rooms; -use crate::ship::character::{FullCharacterBytesBuilder}; -use crate::ship::location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError, RoomId}; -use crate::ship::packet; -use crate::ship::items::state::ItemState; -use crate::entity::gateway::EntityGateway; -use crate::ship::map::MapArea; +use networking::serverstate::ClientId; +use stats::leveltable::LEVEL_TABLE; +use crate::{SendShipPacket, ShipError}; +use maps::Holiday; +use client::Clients; +use room::Rooms; +use pktbuilder::character::FullCharacterBytesBuilder; +use location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError, RoomId}; +use items::state::ItemState; +use entity::gateway::EntityGateway; +use entity::room::RoomNote; +use maps::area::MapArea; use futures::future::join_all; // this function needs a better home @@ -56,11 +58,11 @@ pub async fn send_player_to_lobby(id: ClientId, client_location: &mut ClientLocation, clients: &Clients, item_state: &ItemState, - event: ShipEvent) + event: Holiday) -> Result, anyhow::Error> { let lobby = client_location.add_client_to_next_available_lobby(id, LobbyId(0)).await.map_err(|_| ShipError::TooManyClients)?; - let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state, event).await?; - let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state, event).await?; + let join_lobby = pktbuilder::lobby::join_lobby(id, lobby, client_location, clients, item_state, event).await?; + let addto = pktbuilder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state, event).await?; let neighbors = client_location.get_client_neighbors(id).await.unwrap(); Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] .into_iter() @@ -76,7 +78,7 @@ pub async fn change_lobby(id: ClientId, item_state: &mut ItemState, rooms: &Rooms, entity_gateway: &mut EG, - event: ShipEvent) + event: Holiday) -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, @@ -89,17 +91,28 @@ where } }, RoomLobby::Room(old_room) => { + let room_entity_id = rooms.with(old_room, |room| Box::pin(async { + room.room_id + })).await?; if client_location.get_client_neighbors(id).await?.is_empty() { rooms.remove(old_room).await; } + + let character_id = clients.with(id, |client| Box::pin(async { + client.character.id + })).await?; clients.with(id, |client| { let mut item_state = item_state.clone(); + let mut entity_gateway = entity_gateway.clone(); Box::pin(async move { item_state.remove_character_from_room(&client.character).await; - })}).await?; + entity_gateway.add_room_note(room_entity_id, RoomNote::PlayerLeave { + character_id + }).await + })}).await??; }, } - let leave_lobby = packet::builder::lobby::remove_from_lobby(id, client_location).await?; + let leave_lobby = pktbuilder::lobby::remove_from_lobby(id, client_location).await?; let old_neighbors = client_location.get_client_neighbors(id).await.unwrap(); let mut lobby = LobbyId(requested_lobby as usize); if client_location.add_client_to_lobby(id, lobby).await.is_err() { @@ -119,8 +132,8 @@ where Box::pin(async move { item_state.load_character(&mut entity_gateway, &client.character).await })}).await??; - let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state, event).await?; - let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state, event).await?; + let join_lobby = pktbuilder::lobby::join_lobby(id, lobby, client_location, clients, item_state, event).await?; + let addto = pktbuilder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state, event).await?; let neighbors = client_location.get_client_neighbors(id).await?; Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] .into_iter() diff --git a/src/ship/packet/handler/message.rs b/src/ship_server/src/message.rs similarity index 90% rename from src/ship/packet/handler/message.rs rename to src/ship_server/src/message.rs index f4e4d69..31a6541 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship_server/src/message.rs @@ -1,16 +1,17 @@ use libpso::packet::ship::*; use libpso::packet::messages::*; -use crate::entity::gateway::EntityGateway; -use crate::entity::item::Meseta; -use crate::common::serverstate::ClientId; -use crate::common::leveltable::LEVEL_TABLE; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemDropLocation}; -use crate::ship::room::Rooms; -use crate::ship::location::{ClientLocation, ClientLocationError}; -use crate::ship::items::ClientItemId; -use crate::ship::packet::builder; -use crate::ship::items::state::ItemState; -use crate::ship::items::tasks::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item, sort_inventory, use_item, feed_mag, sell_item, take_meseta}; +use entity::gateway::EntityGateway; +use entity::item::Meseta; +use networking::serverstate::ClientId; +use stats::leveltable::LEVEL_TABLE; +use crate::{SendShipPacket, ShipError}; +use client::{Clients, ItemDropLocation}; +use ::room::Rooms; +use location::{ClientLocation, ClientLocationError}; +use items::ClientItemId; +use pktbuilder as builder; +use items::state::ItemState; +use items::tasks::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item, sort_inventory, use_item, feed_mag, sell_item, take_meseta, floor_item_limit_reached}; pub async fn request_exp(id: ClientId, request_exp: RequestExp, @@ -162,7 +163,7 @@ where drop_meseta(&mut item_state, &mut entity_gateway, &client.character, drop_location.map_area, (drop_location.x, drop_location.z), no_longer_has_item.amount).await })}).await??; - let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta)?; + let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta); let no_longer_has_meseta_pkt = builder::message::player_no_longer_has_meseta(area_client, no_longer_has_item.amount); let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; @@ -198,7 +199,7 @@ where no_longer_has_item.amount) .await })}).await??; - let dropped_item_pkt = builder::message::drop_split_stack(area_client, &dropped_item)?; + let dropped_item_pkt = builder::message::drop_split_stack(area_client, &dropped_item); let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(clients_in_area.into_iter() @@ -348,6 +349,15 @@ where })}).await?? .into_iter() .flat_map(move |pkt| { + let pkt = match pkt { + items::actions::CreateItem::Individual(area_client, item_id, item_detail) => { + builder::message::create_individual_item(area_client, item_id, &item_detail) + }, + items::actions::CreateItem::Stacked(area_client, item_id, tool, amount) => { + builder::message::create_stacked_item(area_client, item_id, &tool, amount) + } + }; + let pkt = SendShipPacket::Message(Message::new(GameMessage::CreateItem(pkt))); let player_use_tool = player_use_tool.clone(); neighbors.clone().map(move |client| { vec![(client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerUseItem(player_use_tool.clone())))), (client.client, pkt.clone())] @@ -500,3 +510,28 @@ where })}).await??; Ok(Vec::new()) // TODO: send the packet to other clients } + +pub async fn floor_item_limit_deletion (id: ClientId, + floor_item_limit_delete: FloorItemLimitItemDeletion, + entity_gateway: &mut EG, + client_location: &ClientLocation, + clients: &Clients, + rooms: &Rooms, + item_state: &mut ItemState) + -> Result, anyhow::Error> +where + EG: EntityGateway + Clone + 'static, +{ + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let map_area = rooms.with(room_id, |room| Box::pin(async move { + room.map_areas.get_area_map(floor_item_limit_delete.map_area) + })).await??; + + clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let item_state = item_state.clone(); + Box::pin(async move { + floor_item_limit_reached(&item_state, &mut entity_gateway, &client.character, &ClientItemId(floor_item_limit_delete.item_id), map_area).await + })}).await??; + Ok(Vec::new()) +} diff --git a/src/ship/packet/handler/quest.rs b/src/ship_server/src/quest.rs similarity index 91% rename from src/ship/packet/handler/quest.rs rename to src/ship_server/src/quest.rs index e451f9f..b40c718 100644 --- a/src/ship/packet/handler/quest.rs +++ b/src/ship_server/src/quest.rs @@ -1,12 +1,14 @@ use std::io::{Cursor, Read, Seek, SeekFrom}; use futures::stream::{FuturesOrdered, StreamExt}; use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, ShipEvent}; -use crate::ship::room::Rooms; -use crate::ship::map::enemy::RareMonsterAppearTable; -use crate::ship::location::{ClientLocation}; -use crate::ship::packet::builder::quest; +use networking::serverstate::ClientId; +use crate::{SendShipPacket, ShipError}; +use client::Clients; +use maps::Holiday; +use room::Rooms; +use maps::enemy::RareMonsterAppearTable; +use location::{ClientLocation}; +use pktbuilder::quest; use libpso::util::array_to_utf8; enum QuestFileType { @@ -46,8 +48,9 @@ pub async fn send_quest_category_list(id: ClientId, let room_id = client_location.get_room(id).await?; let rql = rql.clone(); rooms.with_mut(room_id, |room| Box::pin(async move { - let qcl = quest::quest_category_list(&room.quests[rql.flag.clamp(0, (room.quests.len() - 1) as u32) as usize]); - room.set_quest_group(rql.flag as usize); + //let qcl = quest::quest_category_list(&room.quests[rql.flag.clamp(0, (room.quests.len() - 1) as u32) as usize]); + room.quest_group = rql.flag.into(); + let qcl = quest::quest_category_list(room.quests()); Ok(vec![(id, SendShipPacket::QuestCategoryList(qcl))]) })).await? } @@ -59,10 +62,10 @@ pub async fn select_quest_category(id: ClientId, -> Result, anyhow::Error> { let room_id = client_location.get_room(id).await?; rooms.with(room_id, |room| Box::pin(async move { - let (_, category_quests) = room.quests[room.quest_group.value()].iter() + let (_, category_quests) = room.quests() + .iter() .nth(menuselect.item as usize) .ok_or_else(|| ShipError::InvalidQuestCategory(menuselect.item as u16))?; - let ql = quest::quest_list(menuselect.item, category_quests); Ok(vec![(id, SendShipPacket::QuestOptionList(ql))]) })).await? @@ -76,7 +79,7 @@ pub async fn quest_detail(id: ClientId, -> Result, anyhow::Error> { let room_id = client_location.get_room(id).await?; rooms.with(room_id, |room| Box::pin(async move { - let (_, category_quests) = room.quests[room.quest_group.value()].iter() + let (_, category_quests) = room.quests().iter() .nth(questdetailrequest.category as usize) .ok_or_else(|| ShipError::InvalidQuestCategory(questdetailrequest.category))?; @@ -96,7 +99,7 @@ pub async fn player_chose_quest(id: ClientId, clients: &Clients, client_location: &ClientLocation, rooms: &Rooms, - event: ShipEvent) + event: Holiday) -> Result, anyhow::Error> { let room_id = client_location.get_room(id).await?; @@ -105,7 +108,7 @@ pub async fn player_chose_quest(id: ClientId, rooms.with_mut(room_id, |room| { let clients = clients.clone(); Box::pin(async move { - let quest = room.quests[room.quest_group.value()].iter() + let quest = room.quests().iter() .nth(questmenuselect.category as usize) .ok_or_else(|| ShipError::InvalidQuestCategory(questmenuselect.category))? .1 @@ -149,7 +152,7 @@ pub async fn quest_file_request(id: ClientId, let quest_file_request = quest_file_request.clone(); rooms.with(room_id, |room| Box::pin(async move { let (category_id, quest_id, datatype) = parse_filename(&quest_file_request.filename)?; - let (_, category_quests) = room.quests[room.quest_group.value()].iter() + let (_, category_quests) = room.quests().iter() .nth(category_id as usize) .ok_or_else(|| ShipError::InvalidQuestCategory(category_id))?; @@ -182,7 +185,7 @@ pub async fn quest_chunk_ack(id: ClientId, let quest_chunk_ack = quest_chunk_ack.clone(); rooms.with(room_id, |room| Box::pin(async move { let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?; - let (_, category_quests) = room.quests[room.quest_group.value()].iter() + let (_, category_quests) = room.quests().iter() .nth(category_id as usize) .ok_or_else(|| ShipError::InvalidQuestCategory(category_id))?; diff --git a/src/ship/packet/handler/room.rs b/src/ship_server/src/room.rs similarity index 67% rename from src/ship/packet/handler/room.rs rename to src/ship_server/src/room.rs index 4cdf611..254fdd0 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship_server/src/room.rs @@ -1,36 +1,50 @@ -use std::convert::{TryFrom, Into}; +use std::convert::Into; use futures::stream::StreamExt; use async_std::sync::Arc; use libpso::packet::ship::*; use libpso::packet::messages::*; -use crate::common::serverstate::ClientId; -use crate::common::leveltable::LEVEL_TABLE; -use crate::entity::character::SectionID; -use crate::ship::drops::DropTable; -use crate::ship::ship::{SendShipPacket, Clients, ShipEvent}; -use crate::ship::room::{Rooms, Episode, Difficulty, RoomState, RoomMode}; -use crate::ship::map::Maps; -use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; -use crate::ship::packet::builder; -use crate::ship::items::state::ItemState; +use networking::serverstate::ClientId; +use stats::leveltable::LEVEL_TABLE; +use entity::gateway::EntityGateway; +use entity::character::SectionID; +use entity::room::{NewRoomEntity, RoomEntityMode, RoomNote}; +use drops::DropTable; +use crate::SendShipPacket; +use client::Clients; +use room::{Rooms, RoomState, RoomCreationError}; +use maps::Holiday; +use maps::room::{Episode, Difficulty, RoomMode}; +use maps::maps::Maps; +use location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; +use pktbuilder as builder; +use items::state::ItemState; +use quests::{QuestList, QuestLoadError}; #[allow(clippy::too_many_arguments)] -pub async fn create_room(id: ClientId, - create_room: CreateRoom, - client_location: &mut ClientLocation, - clients: &Clients, - item_state: &mut ItemState, - rooms: &Rooms, - map_builder: Arc Maps + Send + Sync>>, - drop_table_builder: Arc DropTable + Send + Sync>>, - event: ShipEvent) - -> Result, anyhow::Error> { +pub async fn create_room(id: ClientId, + create_room: CreateRoom, + entity_gateway: &mut EG, + client_location: &mut ClientLocation, + clients: &Clients, + item_state: &mut ItemState, + rooms: &Rooms, + map_builder: Arc Maps + Send + Sync>>, + drop_table_builder: Arc Box + Send + Sync>>, + standard_quest_builder: Arc Result + Send + Sync>>, + government_quest_builder: Arc Result + Send + Sync>>, + event: Holiday) + -> Result, anyhow::Error> +where + EG: EntityGateway + Clone + 'static, +{ let level = clients.with(id, |client| Box::pin(async move { LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) })).await?; - match Difficulty::try_from(create_room.difficulty)? { + let difficulty = create_room.difficulty.try_into() + .map_err(|()| RoomCreationError::InvalidDifficulty(create_room.difficulty))?; + match difficulty { Difficulty::Ultimate if level < 80 => { return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 80 \nto create Ultimate rooms.".into())))]) }, @@ -44,15 +58,43 @@ pub async fn create_room(id: ClientId, }; let area = client_location.get_area(id).await?; - let area_client = client_location.get_local_client(id).await?; + let old_area_client = client_location.get_local_client(id).await?; let lobby_neighbors = client_location.get_client_neighbors(id).await?; let room_id = client_location.create_new_room(id).await?; + let new_area_client = client_location.get_local_client(id).await?; + + let name = String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).to_string(); + let mode = match (create_room.battle, create_room.challenge, create_room.single_player) { + (1, 0, 0) => RoomEntityMode::Battle, + (0, 1, 0) => RoomEntityMode::Challenge, + (0, 0, 1) => RoomEntityMode::Single, + _ => RoomEntityMode::Multi, + }; + let episode = create_room.episode.try_into() + .map_err(|()| RoomCreationError::InvalidEpisode(create_room.episode))?; + //let difficulty = create_room.difficulty.try_into()?; + let room = clients.with(id, |client| { let mut item_state = item_state.clone(); + let mut entity_gateway = entity_gateway.clone(); Box::pin(async move { - item_state.add_character_to_room(room_id, &client.character, area_client).await; - let mut room = RoomState::from_create_room(&create_room, map_builder, drop_table_builder, client.character.section_id, event)?; + item_state.add_character_to_room(room_id, &client.character, new_area_client).await; + let room_entity = entity_gateway.create_room(NewRoomEntity { + name: name.clone(), + section_id: client.character.section_id, + mode, + episode, + difficulty, + }).await?; + + entity_gateway.add_room_note(room_entity.id, RoomNote::Create { + character_id: client.character.id, + }).await?; + + let mut room = RoomState::new(room_entity.id, mode, episode, difficulty, + client.character.section_id, name, create_room.password, event, + map_builder, drop_table_builder, standard_quest_builder, government_quest_builder)?; room.bursting = true; Ok::<_, anyhow::Error>(room) })}).await??; @@ -62,7 +104,7 @@ pub async fn create_room(id: ClientId, let mut result = vec![(id, SendShipPacket::JoinRoom(join_room))]; if let Ok(leader) = client_location.get_area_leader(area).await { - let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); + let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(old_area_client.local_client.id(), leader.local_client.id())); result.extend(lobby_neighbors .into_iter() .map(move |c| { @@ -90,14 +132,19 @@ pub async fn room_name_request(id: ClientId, } } -pub async fn join_room(id: ClientId, - pkt: MenuSelect, - client_location: &mut ClientLocation, - clients: &Clients, - item_state: &mut ItemState, - rooms: &Rooms, - event: ShipEvent) - -> Result, anyhow::Error> { +#[allow(clippy::too_many_arguments)] +pub async fn join_room(id: ClientId, + pkt: MenuSelect, + entity_gateway: &mut EG, + client_location: &mut ClientLocation, + clients: &Clients, + item_state: &mut ItemState, + rooms: &Rooms, + event: Holiday) + -> Result, anyhow::Error> +where + EG: EntityGateway + Clone + 'static, +{ let room_id = RoomId(pkt.item as usize); if !rooms.exists(room_id).await { return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("This room no longer exists!".into())))]) @@ -105,8 +152,8 @@ pub async fn join_room(id: ClientId, let level = clients.with(id, |client| Box::pin(async move { LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) })).await?; - let (difficulty, bursting) = rooms.with(room_id, |room| Box::pin(async move { - (room.mode.difficulty(), room.bursting) + let (difficulty, bursting, room_entity_id) = rooms.with(room_id, |room| Box::pin(async move { + (room.mode.difficulty(), room.bursting, room.room_id) })).await?; match difficulty { @@ -135,9 +182,14 @@ pub async fn join_room(id: ClientId, clients.with(id, |client| { let mut item_state = item_state.clone(); + let mut entity_gateway = entity_gateway.clone(); Box::pin(async move { + entity_gateway.add_room_note(room_entity_id, RoomNote::PlayerJoin { + character_id: client.character.id, + }).await?; item_state.add_character_to_room(room_id, &client.character, area_client).await; - })}).await?; + Ok::<_, anyhow::Error>(()) + })}).await??; let join_room = rooms.with(room_id, |room| { let clients = clients.clone(); @@ -154,7 +206,7 @@ pub async fn join_room(id: ClientId, rooms.with_mut(room_id, |room| Box::pin(async move { room.bursting = true; })).await?; - + Ok(vec![(id, SendShipPacket::JoinRoom(join_room))] .into_iter() .chain(original_room_clients.into_iter() diff --git a/src/ship/packet/handler/settings.rs b/src/ship_server/src/settings.rs similarity index 96% rename from src/ship/packet/handler/settings.rs rename to src/ship_server/src/settings.rs index de7bfaa..b21491b 100644 --- a/src/ship/packet/handler/settings.rs +++ b/src/ship_server/src/settings.rs @@ -1,7 +1,7 @@ use libpso::packet::ship::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, Clients}; -use crate::entity::gateway::EntityGateway; +use networking::serverstate::ClientId; +use crate::{SendShipPacket, Clients}; +use entity::gateway::EntityGateway; pub async fn update_config(id: ClientId, update_config: UpdateConfig, diff --git a/src/ship/packet/handler/ship.rs b/src/ship_server/src/ship.rs similarity index 87% rename from src/ship/packet/handler/ship.rs rename to src/ship_server/src/ship.rs index a63ebdf..a006004 100644 --- a/src/ship/packet/handler/ship.rs +++ b/src/ship_server/src/ship.rs @@ -1,10 +1,10 @@ use async_std::sync::{Arc, RwLock}; use libpso::packet::ship::*; use libpso::packet::login::RedirectClient; -use crate::common::serverstate::ClientId; -use crate::common::interserver::Ship; -use crate::ship::ship::{SendShipPacket, ShipError}; -use crate::ship::packet::builder; +use networking::serverstate::ClientId; +use networking::interserver::Ship; +use crate::{SendShipPacket, ShipError}; +use pktbuilder as builder; pub async fn ship_list(id: ClientId, ship_list: &Arc>>) -> Vec<(ClientId, SendShipPacket)> { let ship_list = ship_list diff --git a/src/ship/packet/handler/trade.rs b/src/ship_server/src/trade.rs similarity index 97% rename from src/ship/packet/handler/trade.rs rename to src/ship_server/src/trade.rs index c1cb2d0..b57b218 100644 --- a/src/ship/packet/handler/trade.rs +++ b/src/ship_server/src/trade.rs @@ -1,19 +1,19 @@ use std::convert::TryInto; use libpso::packet::ship::*; use libpso::packet::messages::*; -use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, Clients}; -use crate::ship::location::{ClientLocation}; -use crate::ship::items::ClientItemId; -use crate::ship::items::state::{ItemState, ItemStateError}; -use crate::ship::items::inventory::InventoryItemDetail; -use crate::ship::trade::{TradeItem, TradeState, TradeStatus}; -use crate::entity::gateway::EntityGateway; -use crate::ship::packet::builder; -use crate::ship::items::tasks::trade_items; -use crate::ship::location::{AreaClient, RoomId}; -use crate::entity::item::Meseta; -use crate::ship::trade::ClientTradeState; +use networking::serverstate::ClientId; +use crate::{SendShipPacket, ShipError, Clients}; +use location::{ClientLocation}; +use items::ClientItemId; +use items::state::{ItemState, ItemStateError}; +use items::inventory::InventoryItemDetail; +use items::trade::TradeItem; +use entity::gateway::EntityGateway; +use pktbuilder as builder; +use items::tasks::trade_items; +use location::{AreaClient, RoomId}; +use entity::item::Meseta; +use trade::{ClientTradeState, TradeState, TradeStatus}; pub const MESETA_ITEM_ID: ClientItemId = ClientItemId(0xFFFFFF01); pub const OTHER_MESETA_ITEM_ID: ClientItemId = ClientItemId(0xFFFFFFFF); @@ -450,8 +450,8 @@ where enum TradeReady/*<'a>*/ { OnePlayer, BothPlayers(RoomId, - (AreaClient, crate::ship::trade::ClientTradeState), - (AreaClient, crate::ship::trade::ClientTradeState)), + (AreaClient, ClientTradeState), + (AreaClient, ClientTradeState)), //(AreaClient, &'a crate::ship::ship::ClientState, crate::ship::trade::ClientTradeState), //(AreaClient, &'a crate::ship::ship::ClientState, crate::ship::trade::ClientTradeState)), } @@ -527,10 +527,10 @@ where .map(|(client, item)| { match item.item { InventoryItemDetail::Individual(individual_item) => { - GameMessage::CreateItem(builder::message::create_individual_item(client, item.item_id, &individual_item).unwrap()) + GameMessage::CreateItem(builder::message::create_individual_item(client, item.item_id, &individual_item)) }, InventoryItemDetail::Stacked(stacked_item) => { - GameMessage::CreateItem(builder::message::create_stacked_item(client, item.item_id, &stacked_item.tool, stacked_item.count()).unwrap()) + GameMessage::CreateItem(builder::message::create_stacked_item(client, item.item_id, &stacked_item.tool, stacked_item.count())) } } }); diff --git a/src/shops/Cargo.toml b/src/shops/Cargo.toml new file mode 100644 index 0000000..25e3055 --- /dev/null +++ b/src/shops/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "shops" +version = "0.1.0" +edition = "2021" + +[dependencies] +maps = { workspace = true } +stats = { workspace = true } +entity = { workspace = true } + +async-std = { workspace = true } +async-trait = { workspace = true } +futures = { workspace = true } +rand = { workspace = true } +rand_chacha = { workspace = true } +toml = { workspace = true } +serde = { workspace = true } \ No newline at end of file diff --git a/src/ship/shops/armor.rs b/src/shops/src/armor.rs similarity index 95% rename from src/ship/shops/armor.rs rename to src/shops/src/armor.rs index d1d8b47..f424877 100644 --- a/src/ship/shops/armor.rs +++ b/src/shops/src/armor.rs @@ -5,12 +5,12 @@ use std::convert::TryInto; use serde::Deserialize; use rand::{Rng, SeedableRng}; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::item::ItemDetail; -use crate::entity::item::armor::{Armor, ArmorType}; -use crate::entity::item::shield::{Shield, ShieldType}; -use crate::entity::item::unit::{Unit, UnitType}; -use crate::ship::shops::ShopItem; -use crate::ship::item_stats::{ARMOR_STATS, SHIELD_STATS, UNIT_STATS}; +use entity::item::ItemDetail; +use entity::item::armor::{Armor, ArmorType}; +use entity::item::shield::{Shield, ShieldType}; +use entity::item::unit::{Unit, UnitType}; +use crate::ShopItem; +use stats::items::{ARMOR_STATS, SHIELD_STATS, UNIT_STATS}; // #[derive(Debug)] // pub enum ArmorShopItem { @@ -342,8 +342,8 @@ impl ArmorShop { pub fn generate_armor_list(&mut self, character_level: usize) -> Vec { self.generate_frame_list(character_level).into_iter() - .chain(self.generate_barrier_list(character_level).into_iter()) - .chain(self.generate_unit_list(character_level).into_iter()) + .chain(self.generate_barrier_list(character_level)) + .chain(self.generate_unit_list(character_level)) .collect() } } diff --git a/src/shops/src/lib.rs b/src/shops/src/lib.rs new file mode 100644 index 0000000..94abdec --- /dev/null +++ b/src/shops/src/lib.rs @@ -0,0 +1,95 @@ +mod weapon; +mod tool; +mod armor; + +use async_std::sync::{Arc, Mutex}; +use futures::future::OptionFuture; +use std::collections::HashMap; +use entity::item::ItemDetail; +use maps::room::Difficulty; +use entity::character::SectionID; + +pub use weapon::{WeaponShop, WeaponShopItem}; +pub use tool::{ToolShop, ToolShopItem}; +pub use armor::{ArmorShop, ArmorShopItem}; + +pub trait ShopItem { + fn price(&self) -> usize; + fn as_bytes(&self) -> [u8; 12]; + fn as_item(&self) -> ItemDetail; +} + +#[async_trait::async_trait] +pub trait ItemShops { + async fn generate_weapon_list(&self, difficulty: Difficulty, section_id: SectionID, char_level: usize) -> Option>; + async fn generate_tool_list(&self, char_level: usize) -> Vec; + async fn generate_armor_list(&self, char_level: usize) -> Vec; +} + + +#[derive(Clone)] +pub struct StandardItemShops { + weapon_shop: HashMap<(Difficulty, SectionID), Arc>>>, + tool_shop: Arc>>, + armor_shop: Arc>>, +} + +impl Default for StandardItemShops { + fn default() -> StandardItemShops { + let difficulty = [Difficulty::Normal, Difficulty::Hard, Difficulty::VeryHard, Difficulty::Ultimate]; + let section_id = [SectionID::Viridia, SectionID::Greenill, SectionID::Skyly, SectionID::Bluefull, SectionID::Purplenum, + SectionID::Pinkal, SectionID::Redria, SectionID::Oran, SectionID::Yellowboze, SectionID::Whitill]; + + let mut weapon_shop = HashMap::new(); + for d in difficulty.iter() { + for id in section_id.iter() { + weapon_shop.insert((*d, *id), Arc::new(Mutex::new(WeaponShop::new(*d, *id)))); + } + } + + StandardItemShops { + weapon_shop, + tool_shop: Arc::new(Mutex::new(ToolShop::default())), + armor_shop: Arc::new(Mutex::new(ArmorShop::default())), + } + } +} + +#[async_trait::async_trait] +impl ItemShops for StandardItemShops { + async fn generate_weapon_list(&self, difficulty: Difficulty, section_id: SectionID, char_level: usize) -> Option> { + OptionFuture::from( + self.weapon_shop + .get(&(difficulty, section_id)) + .map(|shop| async { + shop + .lock() + .await + .generate_weapon_list(char_level) + })).await + } + + async fn generate_tool_list(&self, char_level: usize) -> Vec { + self.tool_shop + .lock() + .await + .generate_tool_list(char_level) + } + + async fn generate_armor_list(&self, char_level: usize) -> Vec { + self.armor_shop + .lock() + .await + .generate_armor_list(char_level) + } +} + + + + +pub enum ShopType { + Weapon, + Tool, + Armor +} + diff --git a/src/ship/shops/tool.rs b/src/shops/src/tool.rs similarity index 92% rename from src/ship/shops/tool.rs rename to src/shops/src/tool.rs index b5f9718..b068d19 100644 --- a/src/ship/shops/tool.rs +++ b/src/shops/src/tool.rs @@ -6,11 +6,11 @@ use std::convert::TryInto; use serde::Deserialize; use rand::{Rng, SeedableRng}; use rand::distributions::{WeightedIndex, Distribution}; -use crate::entity::item::ItemDetail; -use crate::entity::item::tool::{Tool, ToolType}; -use crate::entity::item::tech::{Technique, TechniqueDisk}; -use crate::ship::shops::ShopItem; -use crate::ship::item_stats::{TOOL_STATS, TECH_STATS}; +use entity::item::ItemDetail; +use entity::item::tool::{Tool, ToolType}; +use entity::item::tech::{Technique, TechniqueDisk}; +use crate::ShopItem; +use stats::items::{TOOL_STATS, TECH_STATS}; #[derive(Debug, PartialEq, Eq)] @@ -36,16 +36,7 @@ impl Ord for ToolShopItem { impl PartialOrd for ToolShopItem { fn partial_cmp(&self, other: &ToolShopItem) -> Option { - let a = match self { - ToolShopItem::Tool(t) => Tool{tool : *t}.as_individual_bytes(), - ToolShopItem::Tech(t) => t.as_bytes(), - }; - let b = match other { - ToolShopItem::Tool(t) => Tool{tool : *t}.as_individual_bytes(), - ToolShopItem::Tech(t) => t.as_bytes(), - }; - - a.partial_cmp(&b) + Some(self.cmp(other)) } } @@ -285,7 +276,7 @@ impl ToolShop { pub fn generate_tool_list(&mut self, character_level: usize) -> Vec { let mut tools = Vec::new().into_iter() .chain(self.tools.0.clone().into_iter().map(ToolShopItem::Tool)) - .chain(self.generate_techs(character_level).into_iter()) + .chain(self.generate_techs(character_level)) .collect::>(); tools.sort(); tools diff --git a/src/ship/shops/weapon.rs b/src/shops/src/weapon.rs similarity index 96% rename from src/ship/shops/weapon.rs rename to src/shops/src/weapon.rs index 14509c8..06a8c1e 100644 --- a/src/ship/shops/weapon.rs +++ b/src/shops/src/weapon.rs @@ -8,12 +8,12 @@ use serde::Deserialize; use rand::{Rng, SeedableRng}; use rand::distributions::{WeightedIndex, Distribution}; use rand::seq::{SliceRandom, IteratorRandom}; -use crate::entity::character::SectionID; -use crate::ship::room::Difficulty; -use crate::entity::item::ItemDetail; -use crate::entity::item::weapon::{Weapon, WeaponType, WeaponSpecial, Attribute, WeaponAttribute}; -use crate::ship::shops::ShopItem; -use crate::ship::item_stats::WEAPON_STATS; +use entity::character::SectionID; +use maps::room::Difficulty; +use entity::item::ItemDetail; +use entity::item::weapon::{Weapon, WeaponType, WeaponSpecial, Attribute, WeaponAttribute}; +use crate::ShopItem; +use stats::items::WEAPON_STATS; const TIER1_SPECIAL: [WeaponSpecial; 8] = [WeaponSpecial::Draw, WeaponSpecial::Heart, WeaponSpecial::Ice, WeaponSpecial::Bind, @@ -412,7 +412,7 @@ impl WeaponShop { .last() .unwrap(); - let attr_choice = WeightedIndex::new(&[tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap(); + let attr_choice = WeightedIndex::new([tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap(); let attr = match attr_choice.sample(&mut self.rng) { 0 => return None, 1 => Attribute::Native, @@ -439,7 +439,7 @@ impl WeaponShop { .last() .unwrap(); - let attr_choice = WeightedIndex::new(&[tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap(); + let attr_choice = WeightedIndex::new([tier.none, tier.native, tier.abeast, tier.machine, tier.dark, tier.hit]).unwrap(); let attr = match attr_choice.sample(&mut self.rng) { 0 => return None, 1 => Attribute::Native, diff --git a/src/stats/Cargo.toml b/src/stats/Cargo.toml new file mode 100644 index 0000000..6cebc62 --- /dev/null +++ b/src/stats/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "stats" +version = "0.1.0" +edition = "2021" + +[dependencies] +entity = { workspace = true } +toml = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +lazy_static = { workspace = true } diff --git a/src/ship/item_stats.rs b/src/stats/src/items.rs similarity index 95% rename from src/ship/item_stats.rs rename to src/stats/src/items.rs index 919c076..13d0855 100644 --- a/src/ship/item_stats.rs +++ b/src/stats/src/items.rs @@ -4,13 +4,13 @@ use serde::{Serialize, Deserialize}; use std::fs::File; use std::io::Read; -use crate::entity::item::weapon::WeaponType; -use crate::entity::item::armor::ArmorType; -use crate::entity::item::shield::ShieldType; -use crate::entity::item::unit::UnitType; -use crate::entity::item::mag::MagType; -use crate::entity::item::tool::ToolType; -use crate::entity::item::tech::Technique; +use entity::item::weapon::WeaponType; +use entity::item::armor::ArmorType; +use entity::item::shield::ShieldType; +use entity::item::unit::UnitType; +use entity::item::mag::MagType; +use entity::item::tool::ToolType; +use entity::item::tech::Technique; lazy_static::lazy_static! { diff --git a/src/common/leveltable.rs b/src/stats/src/leveltable.rs similarity index 99% rename from src/common/leveltable.rs rename to src/stats/src/leveltable.rs index 9fb1465..7b06966 100644 --- a/src/common/leveltable.rs +++ b/src/stats/src/leveltable.rs @@ -1,6 +1,6 @@ use std::fs::File; use serde_json::Value; -use crate::entity::character::CharacterClass; +use entity::character::CharacterClass; use std::sync::LazyLock; pub static LEVEL_TABLE: LazyLock = LazyLock::new(CharacterLevelTable::default); diff --git a/src/stats/src/lib.rs b/src/stats/src/lib.rs new file mode 100644 index 0000000..0564e34 --- /dev/null +++ b/src/stats/src/lib.rs @@ -0,0 +1,4 @@ +#![feature(lazy_cell)] + +pub mod items; +pub mod leveltable; diff --git a/src/trade/Cargo.toml b/src/trade/Cargo.toml new file mode 100644 index 0000000..9d588b4 --- /dev/null +++ b/src/trade/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "trade" +version = "0.1.0" +edition = "2021" + + +[dependencies] +networking = { workspace = true } +items = { workspace = true } + +async-std = { workspace = true } +futures = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } \ No newline at end of file diff --git a/src/ship/trade.rs b/src/trade/src/lib.rs similarity index 79% rename from src/ship/trade.rs rename to src/trade/src/lib.rs index abe1cd2..319652c 100644 --- a/src/ship/trade.rs +++ b/src/trade/src/lib.rs @@ -1,45 +1,8 @@ use std::collections::HashMap; -use crate::common::serverstate::ClientId; -use crate::ship::items; +use networking::serverstate::ClientId; use async_std::sync::{Arc, Mutex, MutexGuard}; use futures::future::{Future, OptionFuture}; - -#[derive(Debug, Clone)] -pub enum TradeItem { - Individual(items::ClientItemId), - Stacked(items::ClientItemId, usize), -} - -impl TradeItem { - pub fn stacked(&self) -> Option<(items::ClientItemId, usize)> { - match self { - TradeItem::Stacked(item_id, amount) => Some((*item_id, *amount)), - _ => None - } - } - - pub fn stacked_mut(&mut self) -> Option<(items::ClientItemId, &mut usize)> { - match self { - TradeItem::Stacked(item_id, ref mut amount) => Some((*item_id, amount)), - _ => None - } - } - - pub fn item_id(&self) -> items::ClientItemId { - match self { - TradeItem::Individual(item_id) => *item_id, - TradeItem::Stacked(item_id, _) => *item_id, - } - } - - pub fn amount(&self) -> usize { - match self { - TradeItem::Individual(_) => 1, - TradeItem::Stacked(_, amount) => *amount, - } - } -} - +use items::trade::TradeItem; #[derive(Debug, Clone, Eq, PartialEq)] pub enum TradeStatus { diff --git a/tests/common.rs b/tests/common.rs index e9dccd0..ebab507 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -1,22 +1,83 @@ #![allow(dead_code)] -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::EntityGateway; -use elseware::entity::account::{UserAccountEntity, NewUserAccountEntity, NewUserSettingsEntity}; -use elseware::entity::character::{CharacterEntity, NewCharacterEntity}; -use elseware::entity::item::{Meseta, BankName, BankIdentifier}; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::ship::room::Difficulty; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::EntityGateway; +use entity::account::{UserAccountEntity, NewUserAccountEntity, NewUserSettingsEntity}; +use entity::character::{CharacterEntity, NewCharacterEntity, SectionID}; +use entity::item::{Meseta, BankIdentifier}; +use ship_server::{ShipServerState, ShipServerStateBuilder, RecvShipPacket}; +use maps::room::{RoomMode, Difficulty, Episode}; +use maps::area::MapArea; +use maps::maps::null_free_roam_maps; +use maps::object::MapObject; +use maps::monster::MonsterType; +use quests::{QuestList, QuestLoadError}; +use drops::{DropTable, ItemDropType}; +use shops::{ItemShops, WeaponShopItem, ToolShopItem, ArmorShopItem}; -use elseware::entity::item; +use entity::item; use libpso::packet::ship::*; use libpso::packet::login::{Login, Session}; use libpso::{utf8_to_array, utf8_to_utf16_array}; +fn null_quest_builder(_mode: RoomMode) -> Result { + Ok(Default::default()) +} + +struct NullDropTable; + +impl DropTable for NullDropTable { + fn get_drop(&mut self, _map_area: &MapArea, _monster: &MonsterType) -> Option { + None + } + fn get_box_drop(&mut self, _map_area: &MapArea, _object: &MapObject) -> Option { + None + } +} + +pub fn null_drop_table_builder(_episode: Episode, _difficult: Difficulty, _section_id: SectionID) -> Box { + Box::new(NullDropTable) +} + +struct NullItemShops; + +#[async_trait::async_trait] +impl ItemShops for NullItemShops { + async fn generate_weapon_list(&self, _difficulty: Difficulty, _section_id: SectionID, _char_level: usize) -> Option> { + Some(Vec::new()) + } + async fn generate_tool_list(&self, _char_level: usize) -> Vec { + Vec::new() + } + async fn generate_armor_list(&self, _char_level: usize) -> Vec { + Vec::new() + } +} + +pub fn standard_ship_buildable(gateway: EG) -> ShipServerStateBuilder { + ShipServerState::builder() + .gateway(gateway) + .standard_quest_builder(Box::new(null_quest_builder)) + .government_quest_builder(Box::new(null_quest_builder)) + .drop_table_builder(Box::new(null_drop_table_builder)) + .map_builder(Box::new(null_free_roam_maps)) + .item_shops(NullItemShops) +} + +pub fn standard_ship(gateway: EG) -> ShipServerState { + ShipServerState::builder() + .gateway(gateway) + .standard_quest_builder(Box::new(null_quest_builder)) + .government_quest_builder(Box::new(null_quest_builder)) + .drop_table_builder(Box::new(null_drop_table_builder)) + .map_builder(Box::new(null_free_roam_maps)) + .item_shops(NullItemShops) + .build() +} //TODO: remove kb_conf_preset -pub async fn new_user_character(entity_gateway: &mut EG, username: &str, password: &str, kb_conf_preset: usize) -> (UserAccountEntity, CharacterEntity) { +pub async fn new_user_character(entity_gateway: &mut EG, username: &str, password: &str) -> (UserAccountEntity, CharacterEntity) { let new_user = NewUserAccountEntity { email: format!("{}@pso.com", username), username: username.into(), @@ -100,9 +161,23 @@ pub async fn join_room(ship: &mut ShipServerState pub struct WeaponBuilder { weapon: item::weapon::WeaponType, grind: u8, + special: Option, + attributes: [Option; 3], + tekked: bool, } + impl WeaponBuilder { + fn new(weapon: item::weapon::WeaponType) -> WeaponBuilder { + WeaponBuilder { + weapon, + grind: 0, + special: None, + attributes: [None; 3], + tekked: true, + } + } + pub fn grind(self, grind: u8) -> WeaponBuilder { WeaponBuilder { grind, @@ -110,28 +185,267 @@ impl WeaponBuilder { } } + pub fn special(self, special: item::weapon::WeaponSpecial) -> WeaponBuilder { + WeaponBuilder { + special: Some(special), + ..self + } + } + + pub fn attr(mut self, attr: item::weapon::Attribute, value: i8) -> WeaponBuilder { + self.attributes + .iter_mut() + .find(|k| k.is_none()) + .map(|empty_attr| { + *empty_attr = Some(item::weapon::WeaponAttribute { + attr, + value, + }) + }); + + self + } + + pub fn untekked(self) -> WeaponBuilder { + WeaponBuilder { + tekked: false, + ..self + } + } + pub fn as_new(self) -> item::NewItemEntity { item::NewItemEntity { item: item::ItemDetail::Weapon( item::weapon::Weapon { weapon: self.weapon, grind: self.grind, - special: None, - attrs: [None, None, None], - tekked: true, + special: self.special, + attrs: self.attributes, + tekked: self.tekked, + } + ) + } + } +} + +pub struct ArmorBuilder { + armor: item::armor::ArmorType, + dfp: u8, + evp: u8, + slots: u8, +} + +impl ArmorBuilder { + pub fn new(armor: item::armor::ArmorType) -> ArmorBuilder { + ArmorBuilder { + armor: armor, + dfp: 0, + evp: 0, + slots: 0, + } + } + + pub fn slots(self, slots: u8) -> ArmorBuilder { + ArmorBuilder { + slots, + ..self + } + } + + pub fn dfp(self, dfp: u8) -> ArmorBuilder { + ArmorBuilder { + dfp, + ..self + } + } + + pub fn evp(self, evp: u8) -> ArmorBuilder { + ArmorBuilder { + evp, + ..self + } + } + + pub fn as_new(self) -> item::NewItemEntity { + item::NewItemEntity { + item: item::ItemDetail::Armor( + item::armor::Armor { + armor: self.armor, + dfp: self.dfp, + evp: self.evp, + slots: self.slots, + } + ) + } + } +} + +pub struct ShieldBuilder { + shield: item::shield::ShieldType, + dfp: u8, + evp: u8, +} + +impl ShieldBuilder { + pub fn new(shield: item::shield::ShieldType) -> ShieldBuilder { + ShieldBuilder { + shield: shield, + dfp: 0, + evp: 0, + } + } + + pub fn dfp(self, dfp: u8) -> ShieldBuilder { + ShieldBuilder { + dfp, + ..self + } + } + + pub fn evp(self, evp: u8) -> ShieldBuilder { + ShieldBuilder { + evp, + ..self + } + } + + pub fn as_new(self) -> item::NewItemEntity { + item::NewItemEntity { + item: item::ItemDetail::Shield( + item::shield::Shield { + shield: self.shield, + dfp: self.dfp, + evp: self.evp, + } + ) + } + } +} + + +pub struct UnitBuilder { + unit: item::unit::UnitType, + modifier: Option, +} + +impl UnitBuilder { + pub fn modifier(self, modifier: item::unit::UnitModifier) -> UnitBuilder { + UnitBuilder { + modifier: Some(modifier), + ..self + } + } + + pub fn as_new(self) -> item::NewItemEntity { + item::NewItemEntity { + item: item::ItemDetail::Unit( + item::unit::Unit { + unit: self.unit, + modifier: self.modifier, + } + ) + } + } +} + + +pub struct MagBuilder { +} + +impl MagBuilder { + pub fn as_new(self) -> item::NewItemEntity { + item::NewItemEntity { + item: item::ItemDetail::Mag( + item::mag::Mag::baby_mag(0) + ) + } + } +} + + + +pub struct ToolBuilder { + tool: item::tool::ToolType, +} + +impl ToolBuilder { + pub fn as_new(self) -> item::NewItemEntity { + item::NewItemEntity { + item: item::ItemDetail::Tool ( + item::tool::Tool { + tool: self.tool, + } + ), + } + } +} + +pub struct TechBuilder { + tech: item::tech::Technique, + level: u32, +} + + +impl TechBuilder { + pub fn level(self, level: u32) -> TechBuilder { + TechBuilder { + level, + ..self + } + } + + pub fn as_new(self) -> item::NewItemEntity { + item::NewItemEntity { + item: item::ItemDetail::TechniqueDisk ( + item::tech::TechniqueDisk { + tech: self.tech, + level: self.level, } ) } } } + pub struct ItemBuilder; impl ItemBuilder { pub fn weapon(weapon: item::weapon::WeaponType) -> WeaponBuilder { - WeaponBuilder { - weapon, - grind: 0, + WeaponBuilder::new(weapon) + } + + pub fn armor(armor: item::armor::ArmorType) -> ArmorBuilder { + ArmorBuilder::new(armor) + } + + pub fn shield(shield: item::shield::ShieldType) -> ShieldBuilder { + ShieldBuilder::new(shield) + } + + pub fn unit(unit: item::unit::UnitType) -> UnitBuilder { + UnitBuilder { + unit: unit, + modifier: None, } } + + pub fn baby_mag() -> MagBuilder { + MagBuilder { + } + } + + pub fn tool(tool: item::tool::ToolType) -> ToolBuilder { + ToolBuilder { + tool: tool, + } + } + + pub fn tech(tech: item::tech::Technique) -> TechBuilder { + TechBuilder { + tech: tech, + level: 0, + } + } + + } diff --git a/tests/test_bank.rs b/tests/test_bank.rs index 71fc8f5..7f825af 100644 --- a/tests/test_bank.rs +++ b/tests/test_bank.rs @@ -1,8 +1,9 @@ use std::collections::BTreeSet; -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::{RecvShipPacket, SendShipPacket}; +use shops::StandardItemShops; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -15,27 +16,17 @@ use common::*; async fn test_bank_items_sent_in_character_login() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let item = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![item]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; let packets = ship.handle(ClientId(1), RecvShipPacket::MenuSelect(MenuSelect { @@ -50,30 +41,20 @@ async fn test_bank_items_sent_in_character_login() { async fn test_request_bank_items() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut bank = Vec::new(); for _ in 0..3 { bank.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -98,26 +79,20 @@ async fn test_request_bank_items() { async fn test_request_stacked_bank_items() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut monomates = Vec::new(); for _ in 0..3usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool ( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -141,48 +116,26 @@ async fn test_request_stacked_bank_items() { async fn test_request_bank_items_sorted() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let item1 = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap(); let monomate = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool ( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap(); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap(); let item2 = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Calibur, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(); + ItemBuilder::weapon(item::weapon::WeaponType::Calibur) + .as_new() + ).await.unwrap(); let bank = vec![item::BankItemEntity::Individual(item1), vec![monomate].into(), item2.into()]; entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -207,39 +160,21 @@ async fn test_request_bank_items_sorted() { async fn test_deposit_individual_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let item0 = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(); + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap(); let item1 = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap(); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![item0, item1])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -286,26 +221,20 @@ async fn test_deposit_individual_item() { async fn test_deposit_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut monomates = Vec::new(); for _ in 0..3usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![monomates])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -347,26 +276,20 @@ async fn test_deposit_stacked_item() { async fn test_deposit_partial_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut monomates = Vec::new(); for _ in 0..3usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![monomates])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -417,37 +340,27 @@ async fn test_deposit_partial_stacked_item() { async fn test_deposit_stacked_item_with_stack_already_in_bank() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut bank_monomates = Vec::new(); let mut inventory_monomates = Vec::new(); for _ in 0..2usize { inventory_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); bank_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![inventory_monomates])).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![bank_monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -489,38 +402,28 @@ async fn test_deposit_stacked_item_with_stack_already_in_bank() { async fn test_deposit_stacked_item_with_full_stack_in_bank() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut inventory_monomates = Vec::new(); for _ in 0..2usize { inventory_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut bank_monomates = Vec::new(); for _ in 0..10 { bank_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![inventory_monomates])).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![bank_monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -561,44 +464,26 @@ async fn test_deposit_stacked_item_with_full_stack_in_bank() { async fn test_deposit_individual_item_in_full_bank() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut inventory = Vec::new(); inventory.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); let mut bank = Vec::new(); for _ in 0..200usize { bank.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(inventory)).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -635,42 +520,28 @@ async fn test_deposit_individual_item_in_full_bank() { async fn test_deposit_stacked_item_in_full_bank() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut monomates = Vec::new(); for _ in 0..2usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut full_bank = Vec::new(); for _ in 0..200usize { full_bank.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![monomates])).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(full_bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -708,55 +579,37 @@ async fn test_deposit_stacked_item_in_full_bank() { async fn test_deposit_stacked_item_in_full_bank_with_partial_stack() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut monomates = Vec::new(); for _ in 0..2usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut bank_monomates = Vec::new(); for _ in 0..2usize { bank_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut almost_full_bank: Vec = Vec::new(); for _ in 0..199usize { almost_full_bank.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap().into()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap().into()); } almost_full_bank.push(bank_monomates.into()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![monomates])).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(almost_full_bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -791,12 +644,10 @@ async fn test_deposit_stacked_item_in_full_bank_with_partial_stack() { async fn test_deposit_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -827,13 +678,11 @@ async fn test_deposit_meseta() { async fn test_deposit_too_much_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(300)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(999980)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -866,13 +715,11 @@ async fn test_deposit_too_much_meseta() { async fn test_deposit_meseta_when_bank_is_maxed() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(300)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -906,28 +753,18 @@ async fn test_deposit_meseta_when_bank_is_maxed() { async fn test_withdraw_individual_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut bank = Vec::new(); bank.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap()); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -968,26 +805,20 @@ async fn test_withdraw_individual_item() { async fn test_withdraw_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut monomates = Vec::new(); for _ in 0..3usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1028,25 +859,19 @@ async fn test_withdraw_stacked_item() { async fn test_withdraw_partial_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut monomates = Vec::new(); for _ in 0..3usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1094,37 +919,27 @@ async fn test_withdraw_partial_stacked_item() { async fn test_withdraw_stacked_item_with_stack_already_in_inventory() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut inventory_monomates = Vec::new(); let mut bank_monomates = Vec::new(); for _ in 0..2usize { inventory_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); bank_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![inventory_monomates])).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![bank_monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1168,38 +983,28 @@ async fn test_withdraw_stacked_item_with_stack_already_in_inventory() { async fn test_withdraw_stacked_item_with_full_stack_in_inventory() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut bank_monomates = Vec::new(); for _ in 0..2usize { bank_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut inventory_monomates = Vec::new(); for _ in 0..10usize { inventory_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![inventory_monomates])).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![bank_monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1240,44 +1045,26 @@ async fn test_withdraw_stacked_item_with_full_stack_in_inventory() { async fn test_withdraw_individual_item_in_full_inventory() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut bank = Vec::new(); bank.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); let mut inventory = Vec::new(); for _ in 0..30usize { inventory.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(inventory)).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(bank), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1310,42 +1097,28 @@ async fn test_withdraw_individual_item_in_full_inventory() { async fn test_withdraw_stacked_item_in_full_inventory() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut monomates = Vec::new(); for _ in 0..2usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut inventory = Vec::new(); for _ in 0..30usize { inventory.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(inventory)).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1384,55 +1157,37 @@ async fn test_withdraw_stacked_item_in_full_inventory() { async fn test_withdraw_stacked_item_in_full_inventory_with_partial_stack() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut bank_item = Vec::new(); for _ in 0..2usize { bank_item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![bank_item]), &item::BankIdentifier::Character).await.unwrap(); let mut items = Vec::new(); for _i in 0..29usize { items.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap().into()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .as_new() + ).await.unwrap().into()); } let mut item29 = Vec::new(); for _ in 0..2usize { item29.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } items.push(item::InventoryItemEntity::Stacked(item29)); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1470,12 +1225,10 @@ async fn test_withdraw_stacked_item_in_full_inventory_with_partial_stack() { async fn test_withdraw_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1506,13 +1259,11 @@ async fn test_withdraw_meseta() { async fn test_withdraw_too_much_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(999980)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1545,13 +1296,11 @@ async fn test_withdraw_too_much_meseta() { async fn test_withdraw_meseta_inventory_is_maxed() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1586,13 +1335,13 @@ async fn test_withdraw_meseta_inventory_is_maxed() { async fn test_withdraw_meseta_and_buy_a_few_monomates_with_it() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(100)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1638,7 +1387,7 @@ async fn test_withdraw_meseta_and_buy_a_few_monomates_with_it() { async fn test_deposit_items_into_shared_banks() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let item0 = entity_gateway.create_item(ItemBuilder::weapon(item::weapon::WeaponType::Saber).as_new()).await.unwrap(); let item1 = entity_gateway.create_item(ItemBuilder::weapon(item::weapon::WeaponType::Buster).as_new()).await.unwrap(); @@ -1649,9 +1398,7 @@ async fn test_deposit_items_into_shared_banks() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![item0, item1, item2, item3, item4, item5])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1762,12 +1509,10 @@ async fn test_deposit_items_into_shared_banks() { async fn test_deposit_meseta_into_shared_banks() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1839,7 +1584,7 @@ async fn test_deposit_meseta_into_shared_banks() { async fn test_withdraw_items_from_shared_banks() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let item0 = entity_gateway.create_item(ItemBuilder::weapon(item::weapon::WeaponType::Saber).as_new()).await.unwrap(); let item1 = entity_gateway.create_item(ItemBuilder::weapon(item::weapon::WeaponType::Buster).as_new()).await.unwrap(); @@ -1852,9 +1597,7 @@ async fn test_withdraw_items_from_shared_banks() { entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![item2, item3]), &item::BankIdentifier::Shared(item::BankName("asdf".into()))).await.unwrap(); entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![item4, item5]), &item::BankIdentifier::Shared(item::BankName("qwer".into()))).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1951,14 +1694,12 @@ async fn test_withdraw_items_from_shared_banks() { async fn test_withdraw_meseta_from_shared_banks() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Character, item::Meseta(300)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Shared(item::BankName("asdf".into())), item::Meseta(300)).await.unwrap(); entity_gateway.set_bank_meseta(&char1.id, &item::BankIdentifier::Shared(item::BankName("qwer".into())), item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; diff --git a/tests/test_character.rs b/tests/test_character.rs index ca16eac..237ded9 100644 --- a/tests/test_character.rs +++ b/tests/test_character.rs @@ -1,8 +1,8 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use ship_server::RecvShipPacket; -use libpso::character::settings::{DEFAULT_KEYBOARD_CONFIG1, DEFAULT_KEYBOARD_CONFIG2, DEFAULT_KEYBOARD_CONFIG3, DEFAULT_KEYBOARD_CONFIG4}; +use libpso::character::settings::{DEFAULT_KEYBOARD_CONFIG1, DEFAULT_KEYBOARD_CONFIG4}; use libpso::packet::ship::*; #[path = "common.rs"] @@ -13,11 +13,9 @@ use common::*; async fn test_save_options() { let mut entity_gateway = InMemoryGateway::default(); - let (user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -35,11 +33,9 @@ async fn test_save_options() { async fn test_change_keyboard_mappings() { let mut entity_gateway = InMemoryGateway::default(); - let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 2).await; + let (user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; diff --git a/tests/test_exp_gain.rs b/tests/test_exp_gain.rs index 0317e9d..db71ec9 100644 --- a/tests/test_exp_gain.rs +++ b/tests/test_exp_gain.rs @@ -1,13 +1,12 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::common::leveltable::CharacterLevelTable; -use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; -use elseware::ship::monster::MonsterType; -use elseware::ship::location::RoomId; -use elseware::ship::map::variant::{MapVariant, MapVariantMode}; -use elseware::ship::map::maps::Maps; -use elseware::ship::map::area::MapArea; -use elseware::ship::map::enemy::MapEnemy; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use stats::leveltable::CharacterLevelTable; +use ship_server::{SendShipPacket, RecvShipPacket}; +use maps::variant::{MapVariant, MapVariantMode}; +use maps::maps::Maps; +use maps::area::MapArea; +use maps::enemy::MapEnemy; +use maps::monster::MonsterType; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -20,18 +19,17 @@ use common::*; async fn test_character_gains_exp() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], - Vec::new(), - ) - })) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -54,20 +52,19 @@ async fn test_character_gains_exp() { async fn test_character_levels_up() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 49; entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], - Vec::new(), - ) - })) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -93,18 +90,17 @@ async fn test_character_levels_up() { async fn test_character_levels_up_multiple_times() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::DarkFalz, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::DarkFalz2, MapArea::DarkFalz))], - Vec::new(), - ) - })) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::DarkFalz, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::DarkFalz2, MapArea::DarkFalz))], + Vec::new(), + ) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -129,19 +125,18 @@ async fn test_character_levels_up_multiple_times() { async fn test_one_character_gets_full_exp_and_other_attacker_gets_partial() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], - Vec::new(), - ) - })) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; diff --git a/tests/test_item_actions.rs b/tests/test_item_actions.rs index 77d52bc..1237063 100644 --- a/tests/test_item_actions.rs +++ b/tests/test_item_actions.rs @@ -1,7 +1,7 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::entity::item; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use ship_server::RecvShipPacket; +use entity::item; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -14,37 +14,25 @@ use common::*; async fn test_equip_unit_from_equip_menu() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Armor( - item::armor::Armor{ - armor: item::armor::ArmorType::Frame, - dfp: 0, - evp: 0, - slots: 4, - }), - }).await.unwrap()); + ItemBuilder::armor(item::armor::ArmorType::Frame) + .slots(4) + .as_new() + ).await.unwrap()); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit{ - unit: item::unit::UnitType::KnightPower, - modifier: None, - }), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::KnightPower) + .as_new() + ).await.unwrap()); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit{ - unit: item::unit::UnitType::KnightPower, - modifier: Some(item::unit::UnitModifier::Plus), - }), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::KnightPower) + .modifier(item::unit::UnitModifier::Plus) + .as_new() + ).await.unwrap()); let equipped = item::EquippedEntity { weapon: None, @@ -56,9 +44,7 @@ async fn test_equip_unit_from_equip_menu() { entity_gateway.set_character_equips(&char1.id, &equipped).await.unwrap(); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -91,37 +77,25 @@ async fn test_equip_unit_from_equip_menu() { async fn test_unequip_armor_with_units() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Armor( - item::armor::Armor{ - armor: item::armor::ArmorType::Frame, - dfp: 0, - evp: 0, - slots: 4, - }), - }).await.unwrap()); + ItemBuilder::armor(item::armor::ArmorType::Frame) + .slots(4) + .as_new() + ).await.unwrap()); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit{ - unit: item::unit::UnitType::KnightPower, - modifier: None, - }), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::KnightPower) + .as_new() + ).await.unwrap()); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit{ - unit: item::unit::UnitType::KnightPower, - modifier: Some(item::unit::UnitModifier::Plus), - }), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::KnightPower) + .modifier(item::unit::UnitModifier::Plus) + .as_new() + ).await.unwrap()); let equipped = item::EquippedEntity { weapon: None, @@ -133,9 +107,7 @@ async fn test_unequip_armor_with_units() { entity_gateway.set_character_equips(&char1.id, &equipped).await.unwrap(); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -159,43 +131,29 @@ async fn test_unequip_armor_with_units() { async fn test_sort_items() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Armor( - item::armor::Armor{ - armor: item::armor::ArmorType::Frame, - dfp: 0, - evp: 0, - slots: 4, - }), - }).await.unwrap()); + ItemBuilder::armor(item::armor::ArmorType::Frame) + .slots(4) + .as_new() + ).await.unwrap()); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit{ - unit: item::unit::UnitType::KnightPower, - modifier: None, - }), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::KnightPower) + .as_new() + ).await.unwrap()); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit{ - unit: item::unit::UnitType::KnightPower, - modifier: Some(item::unit::UnitModifier::Plus), - }), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::KnightPower) + .modifier(item::unit::UnitModifier::Plus) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -216,8 +174,8 @@ async fn test_sort_items() { ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::SortItems(SortItems { client: 255, target: 255, - item_ids: [0x10001u32, 0x10002, 0x10000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + item_ids: [0x10001u32, 0x10002, 0x10000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], })))).await.unwrap(); diff --git a/tests/test_item_drop.rs b/tests/test_item_drop.rs index 02b01b1..91f179b 100644 --- a/tests/test_item_drop.rs +++ b/tests/test_item_drop.rs @@ -1,15 +1,14 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::character::SectionID; -use elseware::common::leveltable::CharacterLevelTable; -use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; -use elseware::ship::room::{Episode, Difficulty}; -use elseware::ship::monster::MonsterType; -use elseware::ship::location::RoomId; -use elseware::ship::drops::{DropTable, MonsterDropStats, MonsterDropType}; -use elseware::ship::drops::rare_drop_table::{RareDropTable, RareDropRate, RareDropItem}; -use elseware::ship::map::{Maps, MapVariant, MapArea, MapVariantMode, MapEnemy}; -use elseware::entity::item::weapon::WeaponType; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::InMemoryGateway; +use ship_server::{SendShipPacket, RecvShipPacket}; +use maps::monster::MonsterType; +use drops::{StandardDropTable, MonsterDropStats, MonsterDropType}; +use drops::rare_drop_table::{RareDropTable, RareDropRate, RareDropItem}; +use maps::maps::Maps; +use maps::area::MapArea; +use maps::variant::{MapVariant, MapVariantMode}; +use maps::enemy::MapEnemy; +use entity::item::weapon::WeaponType; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -21,34 +20,33 @@ use common::*; #[async_std::test] async fn test_enemy_drops_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], - Vec::new(), - ) - })) - .drop_table_builder(Box::new(|episode, difficulty, section_id| { - DropTable::builder() - .monster_stat(MonsterType::Hildebear, MonsterDropStats { - dar: 100, - drop_type: MonsterDropType::Weapon, - min_meseta: 0, - max_meseta: 0, - }) - .rare_table(RareDropTable::builder() - .rate(MonsterType::Hildebear, RareDropRate { - rate: 1.0, - item: RareDropItem::Weapon(WeaponType::DarkFlow) - }) - .build(episode, difficulty, section_id)) - .build(episode, difficulty, section_id) - })) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .drop_table_builder(Box::new(|episode, difficulty, section_id| { + StandardDropTable::builder() + .monster_stat(MonsterType::Hildebear, MonsterDropStats { + dar: 100, + drop_type: MonsterDropType::Weapon, + min_meseta: 0, + max_meseta: 0, + }) + .rare_table(RareDropTable::builder() + .rate(MonsterType::Hildebear, RareDropRate { + rate: 1.0, + item: RareDropItem::Weapon(WeaponType::DarkFlow) + }) + .build(episode, difficulty, section_id)) + .build(episode, difficulty, section_id) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -76,35 +74,34 @@ async fn test_enemy_drops_item() { #[async_std::test] async fn test_enemy_drops_item_for_two_players() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], - Vec::new(), - ) - })) - .drop_table_builder(Box::new(|episode, difficulty, section_id| { - DropTable::builder() - .monster_stat(MonsterType::Hildebear, MonsterDropStats { - dar: 100, - drop_type: MonsterDropType::Weapon, - min_meseta: 0, - max_meseta: 0, - }) - .rare_table(RareDropTable::builder() - .rate(MonsterType::Hildebear, RareDropRate { - rate: 1.0, - item: RareDropItem::Weapon(WeaponType::DarkFlow) - }) - .build(episode, difficulty, section_id)) - .build(episode, difficulty, section_id) - })) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .drop_table_builder(Box::new(|episode, difficulty, section_id| { + StandardDropTable::builder() + .monster_stat(MonsterType::Hildebear, MonsterDropStats { + dar: 100, + drop_type: MonsterDropType::Weapon, + min_meseta: 0, + max_meseta: 0, + }) + .rare_table(RareDropTable::builder() + .rate(MonsterType::Hildebear, RareDropRate { + rate: 1.0, + item: RareDropItem::Weapon(WeaponType::DarkFlow) + }) + .build(episode, difficulty, section_id)) + .build(episode, difficulty, section_id) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -144,35 +141,34 @@ async fn test_enemy_drops_item_for_two_players() { #[async_std::test] async fn test_enemy_drops_item_for_two_players_and_pick_up() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .map_builder(Box::new(|_room_mode, _event| { - Maps::new( - vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], - vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], - Vec::new(), - ) - })) - .drop_table_builder(Box::new(|episode, difficulty, section_id| { - DropTable::builder() - .monster_stat(MonsterType::Hildebear, MonsterDropStats { - dar: 100, - drop_type: MonsterDropType::Weapon, - min_meseta: 0, - max_meseta: 0, - }) - .rare_table(RareDropTable::builder() - .rate(MonsterType::Hildebear, RareDropRate { - rate: 1.0, - item: RareDropItem::Weapon(WeaponType::DarkFlow) - }) - .build(episode, difficulty, section_id)) - .build(episode, difficulty, section_id) - })) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .drop_table_builder(Box::new(|episode, difficulty, section_id| { + StandardDropTable::builder() + .monster_stat(MonsterType::Hildebear, MonsterDropStats { + dar: 100, + drop_type: MonsterDropType::Weapon, + min_meseta: 0, + max_meseta: 0, + }) + .rare_table(RareDropTable::builder() + .rate(MonsterType::Hildebear, RareDropRate { + rate: 1.0, + item: RareDropItem::Weapon(WeaponType::DarkFlow) + }) + .build(episode, difficulty, section_id)) + .build(episode, difficulty, section_id) + })) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; diff --git a/tests/test_item_id.rs b/tests/test_item_id.rs index f8ba644..3302806 100644 --- a/tests/test_item_id.rs +++ b/tests/test_item_id.rs @@ -1,9 +1,7 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::entity::character::TechLevel; -//use elseware::ship::items::{ClientItemId, ActiveItemEntityId, HeldItemType, FloorItemType}; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::RecvShipPacket; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -16,21 +14,17 @@ use common::*; #[async_std::test] async fn test_use_monomate_after_leaving_and_rejoining_room() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_items = Vec::new(); for tool in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter() { let mut item = Vec::new(); for _ in 0..2usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p1_items.push(item::InventoryItemEntity::Stacked(item)); } @@ -42,22 +36,16 @@ async fn test_use_monomate_after_leaving_and_rejoining_room() { let mut item = Vec::new(); for _ in 0..2usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p2_items.push(item::InventoryItemEntity::Stacked(item)); } entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -111,22 +99,18 @@ async fn test_use_monomate_after_leaving_and_rejoining_room() { #[async_std::test] async fn test_using_some_monomates_after_a_convoluted_series_of_leaves_and_joins() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - let (_user3, char3) = new_user_character(&mut entity_gateway, "a3", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + let (_user3, char3) = new_user_character(&mut entity_gateway, "a3", "a").await; let mut p1_items = Vec::new(); for tool in vec![item::tool::ToolType::Monofluid, item::tool::ToolType::Difluid, item::tool::ToolType::Trifluid].into_iter() { let mut item = Vec::new(); for _ in 0..2usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p1_items.push(item::InventoryItemEntity::Stacked(item)); } @@ -137,13 +121,9 @@ async fn test_using_some_monomates_after_a_convoluted_series_of_leaves_and_joins let mut item = Vec::new(); for _ in 0..6usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p2_items.push(item::InventoryItemEntity::Stacked(item)); } @@ -154,24 +134,14 @@ async fn test_using_some_monomates_after_a_convoluted_series_of_leaves_and_joins p3_items.push( item::InventoryItemEntity::Individual( entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap() + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap() )); } entity_gateway.set_character_inventory(&char3.id, &item::InventoryEntity::new(p3_items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; log_in_char(&mut ship, ClientId(3), "a3", "a").await; @@ -300,20 +270,16 @@ async fn test_using_some_monomates_after_a_convoluted_series_of_leaves_and_joins #[async_std::test] async fn test_depositing_a_full_stack_then_withdrawing_part() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_items = Vec::new(); for tool in vec![item::tool::ToolType::Monofluid, item::tool::ToolType::Difluid, item::tool::ToolType::Trifluid].into_iter() { let mut item = Vec::new(); for _ in 0..5usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p1_items.push(item::InventoryItemEntity::Stacked(item)); } @@ -322,19 +288,13 @@ async fn test_depositing_a_full_stack_then_withdrawing_part() { let mut monomates = Vec::new(); for _ in 0..3usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_bank(&char1.id, &item::BankEntity::new(vec![monomates]), &item::BankIdentifier::Character).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; diff --git a/tests/test_item_pickup.rs b/tests/test_item_pickup.rs index 820e167..ccef78a 100644 --- a/tests/test_item_pickup.rs +++ b/tests/test_item_pickup.rs @@ -1,7 +1,7 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::RecvShipPacket; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -14,29 +14,19 @@ use common::*; async fn test_pick_up_individual_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -85,31 +75,23 @@ async fn test_pick_up_individual_item() { async fn test_pick_up_item_stack_of_items_already_in_inventory() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_monomate = Vec::new(); p1_monomate.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); let mut p2_items = Vec::new(); for (_slot, tool) in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter().enumerate() { let mut item = Vec::new(); for _ in 0..5usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p2_items.push(item); } @@ -117,9 +99,7 @@ async fn test_pick_up_item_stack_of_items_already_in_inventory() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_monomate])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -161,24 +141,18 @@ async fn test_pick_up_item_stack_of_items_already_in_inventory() { async fn test_pick_up_item_stack_of_items_not_already_held() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p2_monomate = Vec::new(); p2_monomate.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_monomate])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -220,31 +194,21 @@ async fn test_pick_up_item_stack_of_items_not_already_held() { async fn test_pick_up_meseta_when_inventory_full() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_items = Vec::new(); for _ in 0..30usize { p1_items.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_items)).await.unwrap(); entity_gateway.set_character_meseta(&char2.id, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -262,6 +226,7 @@ async fn test_pick_up_meseta_when_inventory_full() { room: 0, x: 0.0, z: 0.0, + amount: 23, })))).await.unwrap(); ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { @@ -292,50 +257,32 @@ async fn test_pick_up_meseta_when_inventory_full() { async fn test_pick_up_partial_stacked_item_when_inventory_is_otherwise_full() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_inv = Vec::new(); for _slot in 0..29usize { p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap().into()); + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap().into()); } p1_inv.push(item::InventoryItemEntity::Stacked(vec![entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()])); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()])); let mut p2_monomates = Vec::new(); p2_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_monomates])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -375,45 +322,27 @@ async fn test_pick_up_partial_stacked_item_when_inventory_is_otherwise_full() { async fn test_can_not_pick_up_item_when_inventory_full() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_inv = Vec::new(); for _slot in 0..30usize { p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap()); } let mut p2_inv = Vec::new(); p2_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -465,13 +394,11 @@ async fn test_can_not_pick_up_item_when_inventory_full() { async fn test_can_not_drop_more_meseta_than_is_held() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -486,6 +413,7 @@ async fn test_can_not_drop_more_meseta_than_is_held() { room: 0, x: 0.0, z: 0.0, + amount: 301, })))).await.unwrap(); let split_attempt = ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { @@ -504,38 +432,28 @@ async fn test_can_not_drop_more_meseta_than_is_held() { async fn test_pick_up_stack_that_would_exceed_stack_limit() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_monomates = Vec::new(); for _ in 0..6usize { p1_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let mut p2_monomates = Vec::new(); for _ in 0..6usize { p2_monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_monomates])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_monomates])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -578,15 +496,13 @@ async fn test_pick_up_stack_that_would_exceed_stack_limit() { async fn test_can_not_pick_up_meseta_when_full() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); entity_gateway.set_character_meseta(&char2.id, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -604,6 +520,7 @@ async fn test_can_not_pick_up_meseta_when_full() { room: 0, x: 0.0, z: 0.0, + amount: 23, })))).await.unwrap(); ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { @@ -632,15 +549,13 @@ async fn test_can_not_pick_up_meseta_when_full() { async fn test_meseta_caps_at_999999_when_trying_to_pick_up_more() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(999998)).await.unwrap(); entity_gateway.set_character_meseta(&char2.id, item::Meseta(300)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -658,6 +573,7 @@ async fn test_meseta_caps_at_999999_when_trying_to_pick_up_more() { room: 0, x: 0.0, z: 0.0, + amount: 23, })))).await.unwrap(); ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { @@ -685,26 +601,20 @@ async fn test_meseta_caps_at_999999_when_trying_to_pick_up_more() { async fn test_player_drops_partial_stack_and_other_player_picks_it_up() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut monomates = Vec::new(); for _ in 0..5usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![monomates])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -722,6 +632,7 @@ async fn test_player_drops_partial_stack_and_other_player_picks_it_up() { room: 0, x: 0.0, z: 0.0, + amount: 2, })))).await.unwrap(); ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { diff --git a/tests/test_item_use.rs b/tests/test_item_use.rs index b6b8502..274a344 100644 --- a/tests/test_item_use.rs +++ b/tests/test_item_use.rs @@ -1,9 +1,8 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::entity::character::TechLevel; -//use elseware::ship::items::{ClientItemId, ActiveItemEntityId, HeldItemType, FloorItemType}; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::RecvShipPacket; +use entity::character::TechLevel; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -17,29 +16,23 @@ use common::*; async fn test_use_monomate() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_items = Vec::new(); for tool in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter() { let mut item = Vec::new(); for _ in 0..2usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p1_items.push(item::InventoryItemEntity::Stacked(item)); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -64,29 +57,23 @@ async fn test_use_monomate() { async fn test_use_monomate_twice() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_items = Vec::new(); for tool in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter() { let mut item = Vec::new(); for _ in 0..3usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p1_items.push(item::InventoryItemEntity::Stacked(item)); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -116,25 +103,19 @@ async fn test_use_monomate_twice() { async fn test_use_last_monomate() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); for tool in vec![item::tool::ToolType::Monomate, item::tool::ToolType::Monofluid].into_iter() { p1_inv.push(item::InventoryItemEntity::Stacked(vec![entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()])); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()])); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -158,23 +139,17 @@ async fn test_use_last_monomate() { async fn test_use_nonstackable_tool() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_items = Vec::new(); p1_items.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::HuntersReport, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::HuntersReport) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_items)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -193,29 +168,23 @@ async fn test_use_nonstackable_tool() { async fn test_use_materials() { let mut entity_gateway = InMemoryGateway::default(); - let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); for tool in vec![item::tool::ToolType::PowerMaterial, item::tool::ToolType::LuckMaterial].into_iter() { let mut item = Vec::new(); for _ in 0..5usize { item.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: tool - } - ), - }).await.unwrap()); + ItemBuilder::tool(tool) + .as_new() + ).await.unwrap()); } p1_inv.push(item::InventoryItemEntity::Stacked(item)); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -255,32 +224,23 @@ async fn test_use_materials() { #[async_std::test] async fn test_jackolantern() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let p1_inv = vec![ item::InventoryItemEntity::Stacked( vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::JackOLantern, - } - ), - }).await.unwrap(), - entity_gateway.create_item(item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::JackOLantern, - } - ), - }).await.unwrap(), + ItemBuilder::tool(item::tool::ToolType::JackOLantern) + .as_new() + ).await.unwrap(), + entity_gateway.create_item( + ItemBuilder::tool(item::tool::ToolType::JackOLantern) + .as_new() + ).await.unwrap(), ])]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -310,46 +270,29 @@ async fn test_jackolantern() { async fn test_use_barta_1() { let mut entity_gateway = InMemoryGateway::default(); - let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::TechniqueDisk( - item::tech::TechniqueDisk { - tech: item::tech::Technique::Foie, - level: 3, - } - ) - } + ItemBuilder::tech(item::tech::Technique::Foie) + .level(3) + .as_new() ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::TechniqueDisk( - item::tech::TechniqueDisk { - tech: item::tech::Technique::Barta, - level: 4, - } - ) - } + ItemBuilder::tech(item::tech::Technique::Barta) + .level(4) + .as_new() ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::TechniqueDisk( - item::tech::TechniqueDisk { - tech: item::tech::Technique::Zonde, - level: 5, - } - ) - } + ItemBuilder::tech(item::tech::Technique::Zonde) + .level(5) + .as_new() ).await.unwrap() ]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -380,31 +323,19 @@ async fn test_use_barta_1() { async fn test_use_monogrinder() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let saber = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(); + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap(); let mut grinders = Vec::new(); for _ in 0..3usize { grinders.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monogrinder, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monogrinder) + .as_new() + ).await.unwrap()); } let equipped = item::EquippedEntity { @@ -418,9 +349,7 @@ async fn test_use_monogrinder() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![item::InventoryItemEntity::Individual(saber), item::InventoryItemEntity::Stacked(grinders)])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; diff --git a/tests/test_mags.rs b/tests/test_mags.rs index 1a7d687..8ffc6a9 100644 --- a/tests/test_mags.rs +++ b/tests/test_mags.rs @@ -1,8 +1,8 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket}; -use elseware::entity::character::{CharacterClass, SectionID}; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::RecvShipPacket; +use entity::character::{CharacterClass, SectionID}; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -15,25 +15,19 @@ use common::*; async fn test_mag_feed() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mag = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Mag( - item::mag::Mag::baby_mag(0) - ), - }).await.unwrap(); + ItemBuilder::baby_mag() + .as_new() + ).await.unwrap(); let mut monomates = Vec::new(); for _ in 0..7usize { monomates.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap()); } let equipped = item::EquippedEntity { @@ -50,9 +44,7 @@ async fn test_mag_feed() { inventory.push(item::InventoryItemEntity::Stacked(monomates)); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(inventory)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -87,8 +79,8 @@ async fn test_mag_feed() { async fn test_mag_change_owner() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a").await; char1.char_class = CharacterClass::RAmarl; char1.section_id = SectionID::Redria; entity_gateway.save_character(&char1).await.unwrap(); @@ -97,17 +89,13 @@ async fn test_mag_change_owner() { entity_gateway.save_character(&char2).await.unwrap(); let mag = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Mag( - item::mag::Mag::baby_mag(0) - ), - }).await.unwrap(); + ItemBuilder::baby_mag() + .as_new() + ).await.unwrap(); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![mag])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -152,34 +140,24 @@ async fn test_mag_change_owner() { async fn test_mag_cell() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mag = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Mag( - item::mag::Mag::baby_mag(0) - ), - }).await.unwrap(); + ItemBuilder::baby_mag() + .as_new() + ).await.unwrap(); for _ in 0..1000usize { let fed_tool = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool ( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ), - }).await.unwrap(); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap(); entity_gateway.feed_mag(&mag.id, &fed_tool.id).await.unwrap(); } let mag_cell = entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::CellOfMag502, - } - ), - }).await.unwrap(); + ItemBuilder::tool(item::tool::ToolType::CellOfMag502) + .as_new() + ).await.unwrap(); let equipped = item::EquippedEntity { weapon: None, @@ -191,9 +169,7 @@ async fn test_mag_cell() { entity_gateway.set_character_equips(&char1.id, &equipped).await.unwrap(); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![mag, mag_cell])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; diff --git a/tests/test_rooms.rs b/tests/test_rooms.rs index 00b512d..5e65574 100644 --- a/tests/test_rooms.rs +++ b/tests/test_rooms.rs @@ -1,8 +1,6 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; -use elseware::ship::location::RoomId; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use ship_server::{RecvShipPacket, SendShipPacket}; use libpso::packet::ship::*; //use libpso::packet::messages::*; @@ -15,10 +13,10 @@ use common::*; #[async_std::test] async fn test_set_valid_quest_group() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .standard_quest_builder(Box::new(quests::load_standard_quests)) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -35,10 +33,11 @@ async fn test_set_valid_quest_group() { #[async_std::test] async fn test_set_invalid_quest_group() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .standard_quest_builder(Box::new(quests::load_standard_quests)) + .government_quest_builder(Box::new(quests::load_government_quests)) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -57,13 +56,11 @@ async fn test_set_invalid_quest_group() { #[async_std::test] async fn test_get_room_info() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; _char1.name = String::from("GODmar"); entity_gateway.save_character(&_char1).await.unwrap(); - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -80,11 +77,9 @@ async fn test_get_room_info() { #[async_std::test] async fn test_cannot_get_room_info_after_room_is_closed() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -102,11 +97,9 @@ async fn test_cannot_get_room_info_after_room_is_closed() { #[async_std::test] async fn test_cannot_join_room_after_its_closed() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; diff --git a/tests/test_shops.rs b/tests/test_shops.rs index cf230c9..59540b7 100644 --- a/tests/test_shops.rs +++ b/tests/test_shops.rs @@ -1,9 +1,10 @@ -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError}; -use elseware::ship::room::Difficulty; -use elseware::ship::items::state::ItemStateError; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::{RecvShipPacket, SendShipPacket}; +use maps::room::Difficulty; +use items::state::ItemStateError; +use shops::StandardItemShops; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -16,13 +17,13 @@ use common::*; async fn test_player_opens_weapon_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -46,13 +47,13 @@ async fn test_player_opens_weapon_shop() { async fn test_player_opens_tool_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -76,13 +77,13 @@ async fn test_player_opens_tool_shop() { async fn test_player_opens_armor_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -106,14 +107,14 @@ async fn test_player_opens_armor_shop() { async fn test_player_buys_from_weapon_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -144,14 +145,14 @@ async fn test_player_buys_from_weapon_shop() { async fn test_player_buys_from_tool_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -181,14 +182,14 @@ async fn test_player_buys_from_tool_shop() { async fn test_player_buys_multiple_from_tool_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -222,14 +223,14 @@ async fn test_player_buys_multiple_from_tool_shop() { async fn test_player_buys_from_armor_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -259,30 +260,23 @@ async fn test_player_buys_from_armor_shop() { async fn test_player_sells_3_attr_weapon_to_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 5, - special: Some(item::weapon::WeaponSpecial::Charge), - attrs: [Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Hit, value: 100}), - Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 100}), - Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Native, value: 100}),], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .grind(5) + .special(item::weapon::WeaponSpecial::Charge) + .attr(item::weapon::Attribute::Hit, 100) + .attr(item::weapon::Attribute::Dark, 100) + .attr(item::weapon::Attribute::Native, 100) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -303,15 +297,15 @@ async fn test_player_sells_3_attr_weapon_to_shop() { async fn test_other_clients_see_purchase() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; char1.exp = 80000000; entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); entity_gateway.save_character(&char1).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -346,23 +340,19 @@ async fn test_other_clients_see_purchase() { async fn test_other_clients_see_stacked_purchase() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate - } - ), - }).await.unwrap(); - - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await.unwrap(); + + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -397,11 +387,9 @@ async fn test_other_clients_see_stacked_purchase() { async fn test_buying_item_without_enough_mseseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Normal).await; @@ -432,14 +420,14 @@ async fn test_buying_item_without_enough_mseseta() { async fn test_player_double_buys_from_tool_shop() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -497,14 +485,14 @@ async fn test_player_double_buys_from_tool_shop() { async fn test_techs_disappear_from_shop_when_bought() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -559,14 +547,14 @@ async fn test_techs_disappear_from_shop_when_bought() { async fn test_units_disappear_from_shop_when_bought() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; char1.exp = 80000000; entity_gateway.save_character(&char1).await.unwrap(); entity_gateway.set_character_meseta(&char1.id, item::Meseta(999999)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship_buildable(entity_gateway.clone()) + .item_shops(StandardItemShops::default()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; @@ -620,30 +608,24 @@ async fn test_units_disappear_from_shop_when_bought() { async fn test_player_sells_untekked_weapon() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Vulcan, - grind: 5, - special: Some(item::weapon::WeaponSpecial::Charge), - attrs: [Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Hit, value: 100}), - Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 100}), - Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Native, value: 100}),], - tekked: false, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Vulcan) + .untekked() + .grind(5) + .special(item::weapon::WeaponSpecial::Charge) + .attr(item::weapon::Attribute::Hit, 100) + .attr(item::weapon::Attribute::Dark, 100) + .attr(item::weapon::Attribute::Native, 100) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -664,30 +646,22 @@ async fn test_player_sells_untekked_weapon() { async fn test_player_sells_rare_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::DarkFlow, - grind: 5, - special: None, - attrs: [Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Hit, value: 100}), - Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 100}), - Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Native, value: 100}),], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::DarkFlow) + .grind(5) + .attr(item::weapon::Attribute::Hit, 100) + .attr(item::weapon::Attribute::Dark, 100) + .attr(item::weapon::Attribute::Native, 100) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -708,29 +682,23 @@ async fn test_player_sells_rare_item() { async fn test_player_sells_partial_photon_drop_stack() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); let mut photon_drops = Vec::new(); for _ in 0..7usize { photon_drops.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::PhotonDrop, - } - ), - }).await.unwrap()); + ItemBuilder::tool(item::tool::ToolType::PhotonDrop) + .as_new() + ).await.unwrap()); } p1_inv.push(item::InventoryItemEntity::Stacked(photon_drops)); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -751,27 +719,18 @@ async fn test_player_sells_partial_photon_drop_stack() { async fn test_player_sells_basic_frame() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Armor( - item::armor::Armor { - armor: item::armor::ArmorType::Frame, - dfp: 0, - evp: 0, - slots: 0, - } - ), - }).await.unwrap()); + ItemBuilder::armor(item::armor::ArmorType::Frame) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -792,27 +751,21 @@ async fn test_player_sells_basic_frame() { async fn test_player_sells_max_frame() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Armor( - item::armor::Armor { - armor: item::armor::ArmorType::Frame, - dfp: 2, - evp: 2, - slots: 4, - } - ), - }).await.unwrap()); + ItemBuilder::armor(item::armor::ArmorType::Frame) + .dfp(2) + .evp(2) + .slots(4) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -833,26 +786,18 @@ async fn test_player_sells_max_frame() { async fn test_player_sells_basic_barrier() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Shield( - item::shield::Shield { - shield: item::shield::ShieldType::Barrier, - dfp: 0, - evp: 0, - } - ), - }).await.unwrap()); + ItemBuilder::shield(item::shield::ShieldType::Barrier) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -873,26 +818,20 @@ async fn test_player_sells_basic_barrier() { async fn test_player_sells_max_barrier() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Shield( - item::shield::Shield { - shield: item::shield::ShieldType::Barrier, - dfp: 5, - evp: 5, - } - ), - }).await.unwrap()); + ItemBuilder::shield(item::shield::ShieldType::Barrier) + .dfp(5) + .evp(5) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -913,25 +852,19 @@ async fn test_player_sells_max_barrier() { async fn test_player_sells_1_star_minusminus_unit() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit { - unit: item::unit::UnitType::PriestMind, - modifier: Some(item::unit::UnitModifier::MinusMinus), - } - ), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::PriestMind) + .modifier(item::unit::UnitModifier::MinusMinus) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -952,25 +885,19 @@ async fn test_player_sells_1_star_minusminus_unit() { async fn test_player_sells_5_star_plusplus_unit() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit { - unit: item::unit::UnitType::GeneralHp, - modifier: Some(item::unit::UnitModifier::PlusPlus), - } - ), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::GeneralHp) + .modifier(item::unit::UnitModifier::PlusPlus) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -991,27 +918,21 @@ async fn test_player_sells_5_star_plusplus_unit() { async fn test_player_sells_rare_frame() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Armor( - item::armor::Armor { - armor: item::armor::ArmorType::StinkFrame, - dfp: 10, - evp: 20, - slots: 3, - } - ), - }).await.unwrap()); + ItemBuilder::armor(item::armor::ArmorType::StinkFrame) + .dfp(10) + .evp(20) + .slots(3) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1032,26 +953,20 @@ async fn test_player_sells_rare_frame() { async fn test_player_sells_rare_barrier() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Shield( - item::shield::Shield { - shield: item::shield::ShieldType::RedRing, - dfp: 10, - evp: 20, - } - ), - }).await.unwrap()); + ItemBuilder::shield(item::shield::ShieldType::RedRing) + .dfp(10) + .evp(20) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1072,25 +987,18 @@ async fn test_player_sells_rare_barrier() { async fn test_player_sells_rare_unit() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit { - unit: item::unit::UnitType::V101, - modifier: None, - } - ), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::V101) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1111,26 +1019,19 @@ async fn test_player_sells_rare_unit() { async fn test_player_cant_sell_if_meseta_would_go_over_max() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; entity_gateway.set_character_meseta(&char1.id, item::Meseta(999995)).await.unwrap(); let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Unit( - item::unit::Unit { - unit: item::unit::UnitType::V101, - modifier: None, - } - ), - }).await.unwrap()); + ItemBuilder::unit(item::unit::UnitType::V101) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; diff --git a/tests/test_trade.rs b/tests/test_trade.rs index 4155a46..8266892 100644 --- a/tests/test_trade.rs +++ b/tests/test_trade.rs @@ -1,10 +1,10 @@ use std::convert::TryInto; -use elseware::common::serverstate::{ClientId, ServerState}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; -use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError}; -use elseware::entity::item::{Meseta, ItemEntity}; -use elseware::ship::packet::handler::trade::TradeError; +use networking::serverstate::{ClientId, ServerState}; +use entity::gateway::{EntityGateway, InMemoryGateway}; +use entity::item; +use ship_server::{ShipServerState, RecvShipPacket, SendShipPacket}; +use entity::item::{Meseta, ItemEntity, InventoryItemEntity}; +use ship_server::trade::TradeError; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -62,7 +62,7 @@ struct TradeItemBuilder { } impl TradeItemBuilder { - fn individual(mut self, item: &elseware::entity::item::InventoryItemEntity, item_id: u32) -> Self { + fn individual(mut self, item: &InventoryItemEntity, item_id: u32) -> Self { let idata = item.with_individual(|i| i.item.as_client_bytes()).unwrap(); self.items[self.count] = TradeItem { item_data: idata[0..12].try_into().unwrap(), @@ -74,7 +74,7 @@ impl TradeItemBuilder { self } - fn stacked(mut self, item: &elseware::entity::item::InventoryItemEntity, item_id: u32, amount: u8) -> Self { + fn stacked(mut self, item: &InventoryItemEntity, item_id: u32, amount: u8) -> Self { let idata = item .with_stacked(|i| i[0].item.tool().unwrap().as_stacked_bytes(i.len())) .map(|mut data| { @@ -113,29 +113,19 @@ impl TradeItemBuilder { async fn test_trade_one_individual_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -214,29 +204,19 @@ async fn test_trade_one_individual_item() { async fn test_trade_player2_to_player1() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p2_inv = Vec::new(); p2_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -315,29 +295,19 @@ async fn test_trade_player2_to_player1() { async fn test_reverse_trade_ack_order() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -416,20 +386,16 @@ async fn test_reverse_trade_ack_order() { async fn test_trade_one_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -439,9 +405,7 @@ async fn test_trade_one_stacked_item() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -520,20 +484,16 @@ async fn test_trade_one_stacked_item() { async fn test_trade_partial_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -543,9 +503,7 @@ async fn test_trade_partial_stacked_item() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -627,42 +585,24 @@ async fn test_trade_partial_stacked_item() { async fn test_trade_individual_both() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()]; + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap()]; let p2_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()]; + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -792,20 +732,16 @@ async fn test_trade_individual_both() { async fn test_trade_stacked_both() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -816,13 +752,9 @@ async fn test_trade_stacked_both() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monofluid, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monofluid) + .as_new() + ).await }})) .await .into_iter() @@ -832,9 +764,7 @@ async fn test_trade_stacked_both() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -962,20 +892,16 @@ async fn test_trade_stacked_both() { async fn test_trade_partial_stack_both() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -986,13 +912,9 @@ async fn test_trade_partial_stack_both() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monofluid, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monofluid) + .as_new() + ).await }})) .await .into_iter() @@ -1002,9 +924,7 @@ async fn test_trade_partial_stack_both() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -1138,20 +1058,16 @@ async fn test_trade_partial_stack_both() { async fn test_trade_same_stacked_item_to_eachother() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack = futures::future::join_all((0..3).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -1162,13 +1078,9 @@ async fn test_trade_same_stacked_item_to_eachother() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -1178,9 +1090,7 @@ async fn test_trade_same_stacked_item_to_eachother() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -1310,20 +1220,16 @@ async fn test_trade_same_stacked_item_to_eachother() { async fn test_trade_stacked_when_already_have_partial_stack() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack = futures::future::join_all((0..3).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -1334,13 +1240,9 @@ async fn test_trade_stacked_when_already_have_partial_stack() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -1350,9 +1252,7 @@ async fn test_trade_stacked_when_already_have_partial_stack() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -1450,34 +1350,22 @@ async fn test_trade_stacked_when_already_have_partial_stack() { async fn test_trade_individual_for_stacked() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()]; + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap()]; let p2_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -1487,9 +1375,7 @@ async fn test_trade_individual_for_stacked() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -1620,68 +1506,34 @@ async fn test_trade_individual_for_stacked() { async fn test_trade_multiple_individual() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Buster, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Buster) + .as_new() + ).await.unwrap(), ]; let p2_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Autogun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Autogun) + .as_new() + ).await.unwrap(), ]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -1878,20 +1730,16 @@ async fn test_trade_multiple_individual() { async fn test_trade_multiple_stacked() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack1 = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -1901,13 +1749,9 @@ async fn test_trade_multiple_stacked() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Dimate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Dimate) + .as_new() + ).await }})) .await .into_iter() @@ -1918,13 +1762,9 @@ async fn test_trade_multiple_stacked() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monofluid, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monofluid) + .as_new() + ).await }})) .await .into_iter() @@ -1934,13 +1774,9 @@ async fn test_trade_multiple_stacked() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Difluid, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Difluid) + .as_new() + ).await }})) .await .into_iter() @@ -1950,9 +1786,7 @@ async fn test_trade_multiple_stacked() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack1, p1_stack2])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack1, p2_stack2])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2145,24 +1979,15 @@ async fn test_trade_multiple_stacked() { async fn test_trade_not_enough_inventory_space_individual() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_inv = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() ).await }})) .await @@ -2174,17 +1999,8 @@ async fn test_trade_not_enough_inventory_space_individual() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() ).await }})) .await @@ -2195,9 +2011,7 @@ async fn test_trade_not_enough_inventory_space_individual() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2268,20 +2082,16 @@ async fn test_trade_not_enough_inventory_space_individual() { async fn test_trade_not_enough_inventory_space_stacked() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -2292,17 +2102,8 @@ async fn test_trade_not_enough_inventory_space_stacked() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() ).await }})) .await @@ -2313,9 +2114,7 @@ async fn test_trade_not_enough_inventory_space_stacked() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2385,20 +2184,16 @@ async fn test_trade_not_enough_inventory_space_stacked() { async fn test_trade_stack_too_big() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack = futures::future::join_all((0..8).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -2409,13 +2204,9 @@ async fn test_trade_stack_too_big() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -2425,9 +2216,7 @@ async fn test_trade_stack_too_big() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2501,14 +2290,12 @@ async fn test_trade_stack_too_big() { async fn test_trade_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; entity_gateway.set_character_meseta(&char1.id, Meseta(2323)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2582,15 +2369,13 @@ async fn test_trade_meseta() { async fn test_trade_too_much_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; entity_gateway.set_character_meseta(&char1.id, Meseta(4000)).await.unwrap(); entity_gateway.set_character_meseta(&char2.id, Meseta(999000)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2634,15 +2419,13 @@ async fn test_trade_too_much_meseta() { async fn test_trade_invalid_amount_of_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; entity_gateway.set_character_meseta(&char1.id, Meseta(4000)).await.unwrap(); entity_gateway.set_character_meseta(&char2.id, Meseta(999000)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2686,15 +2469,13 @@ async fn test_trade_invalid_amount_of_meseta() { async fn test_trade_meseta_request_and_items_dont_match() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; entity_gateway.set_character_meseta(&char1.id, Meseta(4000)).await.unwrap(); entity_gateway.set_character_meseta(&char2.id, Meseta(999000)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2738,12 +2519,10 @@ async fn test_trade_meseta_request_and_items_dont_match() { async fn test_player_declined_trade() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2769,29 +2548,19 @@ async fn test_player_declined_trade() { async fn test_back_out_of_trade_last_minute() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2835,24 +2604,15 @@ async fn test_back_out_of_trade_last_minute() { async fn test_valid_trade_when_both_inventories_are_full() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_inv = futures::future::join_all((0..30).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() ).await }})) .await @@ -2864,17 +2624,8 @@ async fn test_valid_trade_when_both_inventories_are_full() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() ).await }})) .await @@ -2885,9 +2636,7 @@ async fn test_valid_trade_when_both_inventories_are_full() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -2977,24 +2726,15 @@ async fn test_valid_trade_when_both_inventories_are_full() { async fn test_invalid_trade_when_both_inventories_are_full() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_inv = futures::future::join_all((0..30).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() ).await }})) .await @@ -3006,17 +2746,8 @@ async fn test_invalid_trade_when_both_inventories_are_full() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - } + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() ).await }})) .await @@ -3027,9 +2758,7 @@ async fn test_invalid_trade_when_both_inventories_are_full() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3129,13 +2858,11 @@ async fn test_invalid_trade_when_both_inventories_are_full() { async fn test_client_tries_to_start_two_trades() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - let (_user2, _char3) = new_user_character(&mut entity_gateway, "a3", "a", 1).await; + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + let (_user2, _char3) = new_user_character(&mut entity_gateway, "a3", "a").await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; log_in_char(&mut ship, ClientId(3), "a3", "a").await; @@ -3162,13 +2889,11 @@ async fn test_client_tries_to_start_two_trades() { async fn test_client_tries_trading_with_client_already_trading() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; - let (_user2, _char3) = new_user_character(&mut entity_gateway, "a3", "a", 1).await; + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + let (_user2, _char3) = new_user_character(&mut entity_gateway, "a3", "a").await; - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; log_in_char(&mut ship, ClientId(3), "a3", "a").await; @@ -3201,31 +2926,21 @@ async fn test_client_tries_trading_with_client_already_trading() { async fn test_add_then_remove_individual_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_inv = Vec::new(); for _ in 0..2 { p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); } entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3314,20 +3029,16 @@ async fn test_add_then_remove_individual_item() { async fn test_add_then_remove_stacked_item() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack1 = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -3338,13 +3049,9 @@ async fn test_add_then_remove_stacked_item() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monofluid, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monofluid) + .as_new() + ).await }})) .await .into_iter() @@ -3354,9 +3061,7 @@ async fn test_add_then_remove_stacked_item() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack1, p1_stack2])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3449,20 +3154,16 @@ async fn test_add_then_remove_stacked_item() { async fn test_add_then_remove_partial_stack() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack1 = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -3473,13 +3174,9 @@ async fn test_add_then_remove_partial_stack() { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monofluid, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monofluid) + .as_new() + ).await }})) .await .into_iter() @@ -3489,9 +3186,7 @@ async fn test_add_then_remove_partial_stack() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack1, p1_stack2])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3573,14 +3268,12 @@ async fn test_add_then_remove_partial_stack() { async fn test_add_then_remove_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; entity_gateway.set_character_meseta(&char1.id, Meseta(2323)).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3659,29 +3352,19 @@ async fn test_add_then_remove_meseta() { async fn test_items_to_trade_data_does_not_match() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3742,29 +3425,19 @@ async fn test_items_to_trade_data_does_not_match() { async fn test_items_to_trade_id_does_not_match() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3813,20 +3486,16 @@ async fn test_items_to_trade_id_does_not_match() { async fn test_stack_is_same_amount_in_request_and_items_to_trade() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -3836,9 +3505,7 @@ async fn test_stack_is_same_amount_in_request_and_items_to_trade() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3887,20 +3554,16 @@ async fn test_stack_is_same_amount_in_request_and_items_to_trade() { async fn test_stack_is_same_amount_in_request_and_items_to_trade2() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_stack = futures::future::join_all((0..2).map(|_| { let mut entity_gateway = entity_gateway.clone(); async move { entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Tool( - item::tool::Tool { - tool: item::tool::ToolType::Monomate, - } - ) - }).await + ItemBuilder::tool(item::tool::ToolType::Monomate) + .as_new() + ).await }})) .await .into_iter() @@ -3910,9 +3573,7 @@ async fn test_stack_is_same_amount_in_request_and_items_to_trade2() { entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -3961,54 +3622,28 @@ async fn test_stack_is_same_amount_in_request_and_items_to_trade2() { async fn test_items_to_trade_count_less_than() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Brand, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Brand) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Buster, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Buster) + .as_new() + ).await.unwrap(), ]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -4063,56 +3698,30 @@ async fn test_items_to_trade_count_less_than() { async fn test_items_to_trade_count_greater_than() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; entity_gateway.set_character_meseta(&char1.id, Meseta(23)).await.unwrap(); let p1_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Brand, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Brand) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Buster, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Buster) + .as_new() + ).await.unwrap(), ]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -4173,54 +3782,28 @@ async fn test_items_to_trade_count_greater_than() { async fn test_items_to_trade_count_mismatch_with_meseta() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let p1_inv = vec![ entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Saber, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Saber) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Brand, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Brand) + .as_new() + ).await.unwrap(), entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Buster, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap(), + ItemBuilder::weapon(item::weapon::WeaponType::Buster) + .as_new() + ).await.unwrap(), ]; entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -4275,29 +3858,19 @@ async fn test_items_to_trade_count_mismatch_with_meseta() { async fn test_dropping_item_after_trade() { let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; - let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await; let mut p1_inv = Vec::new(); p1_inv.push(entity_gateway.create_item( - item::NewItemEntity { - item: item::ItemDetail::Weapon( - item::weapon::Weapon { - weapon: item::weapon::WeaponType::Handgun, - grind: 0, - special: None, - attrs: [None, None, None], - tekked: true, - } - ), - }).await.unwrap()); + ItemBuilder::weapon(item::weapon::WeaponType::Handgun) + .as_new() + ).await.unwrap()); entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::::new())).await.unwrap(); - let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + let mut ship = standard_ship(entity_gateway.clone()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await;