diff --git a/.gitignore b/.gitignore index df71e48..fa940c2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ /gameserver.toml /wicked-waifus-protocol-internal/generated /wicked-waifus-protocol/generated +/data/assets/config-server +/data/assets/game-data \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 0ccd9cb..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +0,0 @@ -[submodule "data/assets/config-server"] - path = data/assets/config-server - url = https://git.xeondev.com/wickedwaifus/wicked-waifus-config-server-files.git -[submodule "data/assets/game-data"] - path = data/assets/game-data - url = https://git.xeondev.com/wickedwaifus/wicked-waifus-data.git diff --git a/Cargo.lock b/Cargo.lock index 1df49b8..44fc312 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -45,15 +45,24 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +dependencies = [ + "derive_arbitrary", +] [[package]] name = "async-trait" -version = "0.1.85" +version = "0.1.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" +checksum = "d556ec1359574147ec0c4fc5eb525f3f23263a592b1a9c07e0a75b427de55c97" dependencies = [ "proc-macro2", "quote", @@ -197,9 +206,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" dependencies = [ "serde", ] @@ -224,9 +233,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byteorder" @@ -236,9 +245,28 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "bzip2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47" +dependencies = [ + "bzip2-sys", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] [[package]] name = "cbc" @@ -251,10 +279,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.10" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -290,10 +320,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] -name = "cpufeatures" -version = "0.2.16" +name = "constant_time_eq" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -393,6 +429,12 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "deflate64" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" + [[package]] name = "der" version = "0.7.9" @@ -413,6 +455,17 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "digest" version = "0.10.7" @@ -444,18 +497,18 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" dependencies = [ "serde", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" @@ -497,9 +550,19 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fixedbitset" -version = "0.4.2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +dependencies = [ + "crc32fast", + "miniz_oxide", +] [[package]] name = "flume" @@ -640,16 +703,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.0-rc.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a78f88e84d239c7f2619ae8b091603c26208e1cb322571f5a29d6806f56ee5e" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ "cfg-if", - "js-sys", "libc", - "rustix", "wasi 0.13.3+wasi-0.2.2", - "wasm-bindgen", "windows-targets 0.52.6", ] @@ -660,10 +720,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] -name = "h2" -version = "0.4.7" +name = "git2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +checksum = "3fda788993cc341f69012feba8bf45c0ba4f3291fcc08e214b4d5a7332d88aff" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "h2" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" dependencies = [ "atomic-waker", "bytes", @@ -785,9 +860,9 @@ checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -797,9 +872,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", @@ -982,9 +1057,9 @@ dependencies = [ [[package]] name = "inout" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "block-padding", "generic-array", @@ -992,27 +1067,26 @@ dependencies = [ [[package]] name = "itertools" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] -name = "js-sys" -version = "0.3.77" +name = "jobserver" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ - "once_cell", - "wasm-bindgen", + "libc", ] [[package]] @@ -1038,9 +1112,23 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.169" +version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" + +[[package]] +name = "libgit2-sys" +version = "0.18.0+1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1a117465e7e1597e8febea8bb0c410f1c7fb93b1e1cddf34363f8390367ffec" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] [[package]] name = "libm" @@ -1069,16 +1157,42 @@ dependencies = [ ] [[package]] -name = "linux-raw-sys" -version = "0.4.15" +name = "libssh2-sys" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" [[package]] name = "litemap" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" [[package]] name = "lock_api" @@ -1091,10 +1205,26 @@ dependencies = [ ] [[package]] -name = "log" -version = "0.4.25" +name = "lockfree-object-pool" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" + +[[package]] +name = "log" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" + +[[package]] +name = "lzma-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" +dependencies = [ + "byteorder", + "crc", +] [[package]] name = "matchers" @@ -1154,9 +1284,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" dependencies = [ "adler2", ] @@ -1252,9 +1382,27 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] [[package]] name = "overload" @@ -1297,6 +1445,16 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1314,9 +1472,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" -version = "0.6.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset", "indexmap", @@ -1324,18 +1482,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.8" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.8" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", @@ -1377,9 +1535,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "powerfmt" @@ -1398,9 +1556,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.29" +version = "0.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" +checksum = "f1ccf34da56fc294e7d4ccf69a85992b7dfb826b7cf57bac6a70bba3494cc08a" dependencies = [ "proc-macro2", "syn", @@ -1408,18 +1566,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.13.4" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" dependencies = [ "bytes", "prost-derive", @@ -1427,9 +1585,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.4" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f3e5beed80eb580c68e2c600937ac2c4eedabdfd5ef1e5b7ea4f3fba84497b" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ "heck", "itertools", @@ -1447,9 +1605,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.13.4" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", "itertools", @@ -1460,18 +1618,18 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.13.4" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2f1e56baa61e93533aebc21af4d2134b70f66275e0fcdf3cbe43d77ff7e8fc" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" dependencies = [ "prost", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" dependencies = [ "proc-macro2", ] @@ -1489,13 +1647,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0-beta.3" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fccbfebb3972a41a31c605a59207d9fba5489b9a87d9d87024cb6df73a32ec7" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ - "rand_chacha 0.9.0-beta.1", - "rand_core 0.9.0-beta.1", - "zerocopy 0.8.14", + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy 0.8.23", ] [[package]] @@ -1510,12 +1668,12 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.9.0-beta.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16da77124f4ee9fabd55ce6540866e9101431863b4876de58b68797f331adf2" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.0-beta.1", + "rand_core 0.9.3", ] [[package]] @@ -1529,12 +1687,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.0-beta.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a98fa0b8309344136abe6244130311e76997e546f76fae8054422a7539b43df7" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.0-rc.0", - "zerocopy 0.8.14", + "getrandom 0.3.1", ] [[package]] @@ -1569,9 +1726,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ "bitflags", ] @@ -1622,15 +1779,14 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "ring" -version = "0.17.8" +version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" dependencies = [ "cc", "cfg-if", "getrandom 0.2.15", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] @@ -1663,9 +1819,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "0.38.44" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "dade4812df5c384711475be5fcd8c162555352945401aed22a35bffeab61f657" dependencies = [ "bitflags", "errno", @@ -1676,10 +1832,11 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.21" +version = "0.23.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" +checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" dependencies = [ + "log", "once_cell", "ring", "rustls-pki-types", @@ -1699,9 +1856,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" [[package]] name = "rustls-webpki" @@ -1716,15 +1873,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "scopeguard" @@ -1734,18 +1891,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" dependencies = [ "proc-macro2", "quote", @@ -1754,9 +1911,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.137" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -1766,9 +1923,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" dependencies = [ "itoa", "serde", @@ -1776,9 +1933,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", @@ -1862,6 +2019,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "slab" version = "0.4.9" @@ -1873,9 +2036,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" dependencies = [ "serde", ] @@ -1950,7 +2113,7 @@ dependencies = [ "serde_json", "sha2", "smallvec", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-stream", "tracing", @@ -2034,7 +2197,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.11", + "thiserror 2.0.12", "tracing", "whoami", ] @@ -2071,7 +2234,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.11", + "thiserror 2.0.12", "tracing", "whoami", ] @@ -2124,9 +2287,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.96" +version = "2.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" dependencies = [ "proc-macro2", "quote", @@ -2152,13 +2315,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.15.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" dependencies = [ "cfg-if", "fastrand", - "getrandom 0.2.15", + "getrandom 0.3.1", "once_cell", "rustix", "windows-sys 0.59.0", @@ -2175,11 +2338,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl 2.0.12", ] [[package]] @@ -2195,9 +2358,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -2216,9 +2379,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.37" +version = "0.3.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8" dependencies = [ "deranged", "num-conv", @@ -2229,9 +2392,9 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" [[package]] name = "tinystr" @@ -2245,9 +2408,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] @@ -2260,9 +2423,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.43.0" +version = "1.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +checksum = "9975ea0f48b5aa3972bf2d888c238182458437cc2a19374b81b25cdf1023fb3a" dependencies = [ "backtrace", "bytes", @@ -2314,9 +2477,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", "serde_spanned", @@ -2335,9 +2498,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap", "serde", @@ -2478,9 +2641,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicase" @@ -2496,9 +2659,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-normalization" @@ -2515,12 +2678,50 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +[[package]] +name = "unreal-niggery-rs" +version = "0.1.0" +source = "git+https://git.xeondev.com/xavo95/unreal-niggery-rs.git#dde535bafb2a16ce6b45d481e93a9dc6389c676b" +dependencies = [ + "widestring", +] + [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "3.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06f78313c985f2fba11100dd06d60dd402d0cabb458af4d94791b8e09c025323" +dependencies = [ + "base64", + "flate2", + "log", + "percent-encoding", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "ureq-proto", + "utf-8", + "webpki-roots", +] + +[[package]] +name = "ureq-proto" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64adb55464bad1ab1aa9229133d0d59d2f679180f4d15f0d9debe616f541f25e" +dependencies = [ + "base64", + "http", + "httparse", + "log", +] + [[package]] name = "url" version = "2.5.4" @@ -2532,6 +2733,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf16_iter" version = "1.0.5" @@ -2546,11 +2753,11 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.12.1" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" +checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.3.1", ] [[package]] @@ -2592,68 +2799,11 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - [[package]] name = "webpki-roots" -version = "0.26.7" +version = "0.26.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" dependencies = [ "rustls-pki-types", ] @@ -2668,6 +2818,17 @@ dependencies = [ "wasite", ] +[[package]] +name = "wicked-waifus-asset-updater" +version = "0.1.0" +dependencies = [ + "git2", + "thiserror 1.0.69", + "tracing", + "ureq", + "zip-extract", +] + [[package]] name = "wicked-waifus-commons" version = "0.1.0" @@ -2687,6 +2848,7 @@ dependencies = [ "tokio", "toml", "tracing", + "wicked-waifus-asset-updater", "wicked-waifus-commons", "wicked-waifus-http", ] @@ -2700,6 +2862,7 @@ dependencies = [ "serde_json", "serde_repr", "thiserror 1.0.69", + "tracing", ] [[package]] @@ -2717,19 +2880,23 @@ dependencies = [ "anyhow", "dashmap 6.1.0", "hex", + "indexmap", "paste", - "rand 0.9.0-beta.3", + "rand 0.9.0", "serde", "thiserror 1.0.69", "tokio", "tracing", + "unreal-niggery-rs", "uuid", + "wicked-waifus-asset-updater", "wicked-waifus-commons", "wicked-waifus-data", "wicked-waifus-database", "wicked-waifus-network", "wicked-waifus-protocol", "wicked-waifus-protocol-internal", + "widestring", ] [[package]] @@ -2807,7 +2974,7 @@ dependencies = [ [[package]] name = "wicked-waifus-protocol" version = "0.1.0" -source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#82ec48a57c30e41f9bbe86fd0626b5ed830ff6ed" +source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#042098295ad1498bd24b7ccfa1d4bc7276fa5ca9" dependencies = [ "byteorder", "crc32fast", @@ -2825,7 +2992,7 @@ dependencies = [ [[package]] name = "wicked-waifus-protocol-derive" version = "0.1.0" -source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#82ec48a57c30e41f9bbe86fd0626b5ed830ff6ed" +source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#042098295ad1498bd24b7ccfa1d4bc7276fa5ca9" dependencies = [ "proc-macro2", "quote", @@ -2861,6 +3028,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -3033,9 +3206,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.24" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" dependencies = [ "memchr", ] @@ -3097,11 +3270,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.14" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468" +checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" dependencies = [ - "zerocopy-derive 0.8.14", + "zerocopy-derive 0.8.23", ] [[package]] @@ -3117,9 +3290,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.14" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1" +checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" dependencies = [ "proc-macro2", "quote", @@ -3128,18 +3301,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", @@ -3152,6 +3325,20 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "zeromq" @@ -3201,3 +3388,85 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zip" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b280484c454e74e5fff658bbf7df8fdbe7a07c6b2de4a53def232c15ef138f3a" +dependencies = [ + "aes", + "arbitrary", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "deflate64", + "displaydoc", + "flate2", + "hmac", + "indexmap", + "lzma-rs", + "memchr", + "pbkdf2", + "rand 0.8.5", + "sha1", + "thiserror 2.0.12", + "time", + "zeroize", + "zopfli", + "zstd", +] + +[[package]] +name = "zip-extract" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a8c9e90f27d1435088a7b540b6cc8ae6ee525d992a695f16012d2f365b3d3c" +dependencies = [ + "log", + "thiserror 1.0.69", + "zip", +] + +[[package]] +name = "zopfli" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +dependencies = [ + "bumpalo", + "crc32fast", + "lockfree-object-pool", + "log", + "once_cell", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3051792fbdc2e1e143244dc28c60f73d8470e93f3f9cbd0ead44da5ed802722" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.14+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb060d4926e4ac3a3ad15d864e99ceb5f343c6b34f5bd6d81ae6ed417311be5" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 8dedfdc..699b7ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["wicked-waifus-commons", "wicked-waifus-config-server", "wicked-waifus-hotpatch-server", "wicked-waifus-login-server", "wicked-waifus-gateway-server", "wicked-waifus-gateway-server/kcp", "wicked-waifus-database", "wicked-waifus-http", "wicked-waifus-protokey", "wicked-waifus-protocol-internal", "wicked-waifus-game-server", "wicked-waifus-network", "wicked-waifus-data"] +members = ["wicked-waifus-asset-updater", "wicked-waifus-commons", "wicked-waifus-config-server", "wicked-waifus-hotpatch-server", "wicked-waifus-login-server", "wicked-waifus-gateway-server", "wicked-waifus-gateway-server/kcp", "wicked-waifus-database", "wicked-waifus-http", "wicked-waifus-protokey", "wicked-waifus-protocol-internal", "wicked-waifus-game-server", "wicked-waifus-network", "wicked-waifus-data"] resolver = "2" [workspace.package] @@ -47,6 +47,7 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } # Internal kcp = { path = "wicked-waifus-gateway-server/kcp" } +wicked-waifus-asset-updater = { path = "wicked-waifus-asset-updater" } wicked-waifus-commons = { path = "wicked-waifus-commons" } wicked-waifus-http = { path = "wicked-waifus-http" } wicked-waifus-data = { path = "wicked-waifus-data" } diff --git a/data/assets/config-server b/data/assets/config-server deleted file mode 160000 index 146c610..0000000 --- a/data/assets/config-server +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 146c610632c8d9c3948c6a64ffc6cfe0258bcced diff --git a/data/assets/game-data b/data/assets/game-data deleted file mode 160000 index c00cdae..0000000 --- a/data/assets/game-data +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c00cdaefddc9c81ae6d79589c31ee169d59f2382 diff --git a/wicked-waifus-asset-updater/Cargo.toml b/wicked-waifus-asset-updater/Cargo.toml new file mode 100644 index 0000000..e83ed7e --- /dev/null +++ b/wicked-waifus-asset-updater/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "wicked-waifus-asset-updater" +edition = "2021" +version.workspace = true + +[dependencies] +git2 = "0.20.0" +ureq = "3.0.5" +zip-extract = "0.2.1" + +tracing.workspace = true +thiserror.workspace = true diff --git a/wicked-waifus-asset-updater/src/lib.rs b/wicked-waifus-asset-updater/src/lib.rs new file mode 100644 index 0000000..87064b3 --- /dev/null +++ b/wicked-waifus-asset-updater/src/lib.rs @@ -0,0 +1,145 @@ +use std::io::{Cursor, Read, Write}; +use std::path::Path; + +use git2::{FetchOptions, RemoteCallbacks, Repository}; +use git2::build::RepoBuilder; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("UReq error: {0}")] + UReq(#[from] ureq::Error), + #[error("IO error: {0}")] + Io(#[from] std::io::Error), + #[error("ZipExtract error: {0}")] + ZipExtract(#[from] zip_extract::ZipExtractError), + #[error("Git error: {0}")] + Git(#[from] git2::Error), + #[error("Option conversion error")] + Option(), +} + +pub fn update_from_releases + std::fmt::Display>(object_url: T, + target_folder: T, + max_buffer: usize) -> Result<(), Error> { + let path = Path::new(target_folder.as_ref()); + std::fs::create_dir_all(path)?; + let version = path.join("version.txt"); + let new_version = object_url.as_ref(); + if version.exists() { + tracing::debug!("Version marker exists, checking version"); + let old_version = std::fs::read_to_string(&version)?; + if old_version.eq(new_version) { + tracing::debug!("The version to download is the current one, skipping ..."); + return Ok(()) + } else { + tracing::debug!("The old version is: {old_version}, new version: {new_version}") + } + + } else { + tracing::debug!("Version marker doesn't exist, fetching resources for first time") + } + + tracing::debug!("Starting the download of static assets from {object_url}"); + let mut bytes: Vec = Vec::with_capacity(max_buffer); + let agent = ureq::config::Config::builder() + .timeout_send_body(Some(std::time::Duration::from_secs(60))) + .timeout_recv_body(Some(std::time::Duration::from_secs(60))) + .build() + .new_agent(); + + let response = agent.get(new_version).call()?; + response.into_body().as_reader().read_to_end(&mut bytes)?; + tracing::debug!("Downloading assets from: {object_url} finished, extracting into {target_folder}"); + zip_extract::extract(Cursor::new(bytes), path, true)?; + tracing::debug!("Resources extracted"); + + let mut file = std::fs::File::create(&version)?; + file.write_all(new_version.as_bytes())?; + + Ok(()) +} + +pub fn clone_or_update_repository + std::fmt::Display>(repository_url: T, + repository_path: T, + ref_name: T, + discard_local_changes: bool) -> Result<(), Error> { + // Open existing repository or clone if not existing + let path = Path::new(repository_path.as_ref()); + let repository = match path.exists() { + true => { + tracing::debug!("Path {repository_path} exists, opening repository"); + Repository::open(repository_path.as_ref()) + } + false => clone_repository(repository_url.as_ref(), path) + }?; + // TODO: Fetch remote updates???? + // Get reference + let (object, reference) = repository.revparse_ext(ref_name.as_ref())?; + tracing::debug!("Reference {ref_name} found in repository"); + let update_needed = match &reference { + Some(reference) => repository.head()?.eq(reference), + None => repository.head()?.target().ok_or(Error::Option())?.eq(&object.id()), + }; + // If we are already in commit, no need to modify anything + if update_needed { + // Discard all local changes + if discard_local_changes { + tracing::debug!("discard_local_changes was set to true, changes will be discarded"); + repository.checkout_head(None)?; + } else { + tracing::warn!("discard_local_changes was set to false, changes will be kept"); + } + // Checkout required remote + repository.checkout_tree(&object, None)?; + // Checkout the needed commit + match reference { + Some(repo_reference) => repository.set_head(repo_reference.name().unwrap())?, + None => repository.set_head_detached(object.id())?, + } + tracing::debug!("Repository has been updated to {ref_name}"); + } else { + tracing::debug!("Repository is already at the desired reference, no update needed"); + }; + Ok(()) +} + +fn clone_repository(repository_url: &str, path: &Path) -> Result { + tracing::debug!( + "Path {path:?} doesn't exists, cloning repository at {repository_url}" + ); + + let mut remote_callbacks = RemoteCallbacks::new(); + remote_callbacks.sideband_progress(|data| { + tracing::debug!("remote: {}", std::str::from_utf8(data).unwrap()); + std::io::stdout().flush().unwrap(); + true + }); + remote_callbacks.transfer_progress(|stats| { + if stats.received_objects() == stats.total_objects() { + tracing::debug!( + "Resolving deltas {}/{}\r", + stats.indexed_deltas(), + stats.total_deltas() + ); + } else if stats.total_objects() > 0 { + tracing::debug!( + "Received {}/{} objects ({}) in {} bytes\r", + stats.received_objects(), + stats.total_objects(), + stats.indexed_objects(), + stats.received_bytes() + ); + } + std::io::stdout().flush().unwrap(); + true + }); + + let mut fetch_options = FetchOptions::new(); + fetch_options.remote_callbacks(remote_callbacks); + + let result = RepoBuilder::new() + .fetch_options(fetch_options) + .clone(repository_url, path); + + result +} \ No newline at end of file diff --git a/wicked-waifus-commons/src/time_util.rs b/wicked-waifus-commons/src/time_util.rs index 050c89f..abdbefb 100644 --- a/wicked-waifus-commons/src/time_util.rs +++ b/wicked-waifus-commons/src/time_util.rs @@ -1,5 +1,17 @@ use std::time::{SystemTime, UNIX_EPOCH}; +const SECONDS_PER_MINUTE: u64 = 60; +const SECONDS_PER_HOUR: u64 = 60 * SECONDS_PER_MINUTE; +const SECONDS_PER_DAY: u64 = 24 * SECONDS_PER_HOUR; + +pub fn unix_days() -> i32 { + (SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() + / SECONDS_PER_DAY) as i32 +} + pub fn unix_timestamp() -> u64 { SystemTime::now() .duration_since(UNIX_EPOCH) diff --git a/wicked-waifus-config-server/Cargo.toml b/wicked-waifus-config-server/Cargo.toml index b5195c2..4c233eb 100644 --- a/wicked-waifus-config-server/Cargo.toml +++ b/wicked-waifus-config-server/Cargo.toml @@ -18,5 +18,6 @@ anyhow.workspace = true tracing.workspace = true # Internal +wicked-waifus-asset-updater.workspace = true wicked-waifus-commons.workspace = true wicked-waifus-http.workspace = true diff --git a/wicked-waifus-config-server/configserver.default.toml b/wicked-waifus-config-server/configserver.default.toml index 22aaac3..fce5666 100644 --- a/wicked-waifus-config-server/configserver.default.toml +++ b/wicked-waifus-config-server/configserver.default.toml @@ -7,4 +7,9 @@ iv = "fprc5lBWADQB7tim0R2JxQ==" [serve] serve_web_path = "/" -serve_dir_path = "data/assets/config-server" \ No newline at end of file +serve_dir_path = "data/assets/config-server" + +[asset_config] +repository_url = "https://git.xeondev.com/wickedwaifus/wicked-waifus-config-server-files.git" +reference = "4d51547b78" +discard_local_changes = true \ No newline at end of file diff --git a/wicked-waifus-config-server/src/main.rs b/wicked-waifus-config-server/src/main.rs index ea022c1..fcbbe1b 100644 --- a/wicked-waifus-config-server/src/main.rs +++ b/wicked-waifus-config-server/src/main.rs @@ -15,11 +15,19 @@ pub struct ServeConfig { pub serve_dir_path: String, } +#[derive(Deserialize)] +pub struct AssetConfig { + pub repository_url: String, + pub reference: String, + pub discard_local_changes: bool, +} + #[derive(Deserialize)] pub struct ServerConfig { pub network: NetworkSettings, pub encryption: AesSettings, pub serve: ServeConfig, + pub asset_config: Option, } impl TomlConfig for ServerConfig { @@ -34,6 +42,15 @@ async fn main() -> Result<()> { ::wicked_waifus_commons::splash::print_splash(); ::wicked_waifus_commons::logging::init_axum(::tracing::Level::DEBUG); + if let Some(asset_config) = &CONFIG.asset_config { + wicked_waifus_asset_updater::clone_or_update_repository( + &asset_config.repository_url, + &CONFIG.serve.serve_dir_path, + &asset_config.reference, + asset_config.discard_local_changes, + ).unwrap(); + } + tracing::debug!( "Serving files from {} at {}", &CONFIG.serve.serve_web_path, diff --git a/wicked-waifus-data/Cargo.toml b/wicked-waifus-data/Cargo.toml index f0f92e1..89602c1 100644 --- a/wicked-waifus-data/Cargo.toml +++ b/wicked-waifus-data/Cargo.toml @@ -3,9 +3,13 @@ name = "wicked-waifus-data" edition = "2021" version.workspace = true +[features] +strict_json_fields = [] + [dependencies] serde.workspace = true serde_json.workspace = true serde_repr.workspace = true paste.workspace = true thiserror.workspace = true +tracing.workspace = true diff --git a/wicked-waifus-data/src/achievement.rs b/wicked-waifus-data/src/achievement.rs new file mode 100644 index 0000000..8b184c5 --- /dev/null +++ b/wicked-waifus-data/src/achievement.rs @@ -0,0 +1,21 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AchievementData { + pub id: i32, + pub group_id: i32, + pub level: i32, + #[cfg(feature = "strict_json_fields")] + pub name: String, + #[cfg(feature = "strict_json_fields")] + pub desc: String, + #[cfg(feature = "strict_json_fields")] + pub icon_path: String, + pub override_drop_id: i32, + pub hidden: bool, + pub next_link: i32, + pub client_trigger: bool, + pub third_party_trophy_id: i32, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/adventure_task.rs b/wicked-waifus-data/src/adventure_task.rs index dfe142e..0b050b8 100644 --- a/wicked-waifus-data/src/adventure_task.rs +++ b/wicked-waifus-data/src/adventure_task.rs @@ -1,15 +1,19 @@ +#[cfg(feature = "strict_json_fields")] use std::collections::HashMap; use serde::Deserialize; -#[derive(Debug, Deserialize, Clone)] +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct AdventureTaskData { pub id: i32, pub chapter_id: i32, + #[cfg(feature = "strict_json_fields")] pub task_text: String, pub record_id: Vec, pub need_progress: i32, pub drop_ids: i32, pub path_id: i32, + #[cfg(feature = "strict_json_fields")] pub jump_to: HashMap, } \ No newline at end of file diff --git a/wicked-waifus-data/src/ai_base.rs b/wicked-waifus-data/src/ai_base.rs new file mode 100644 index 0000000..3a0b3e0 --- /dev/null +++ b/wicked-waifus-data/src/ai_base.rs @@ -0,0 +1,41 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SubBehaviorConfigs { + #[cfg(feature = "strict_json_fields")] + pub ai_alert: Option, + #[cfg(feature = "strict_json_fields")] + pub ai_base_skill: Option, + #[cfg(feature = "strict_json_fields")] + pub ai_battle_wander: Option, + #[cfg(feature = "strict_json_fields")] + pub ai_flee: Option, + #[cfg(feature = "strict_json_fields")] + pub ai_hate: Option, + #[cfg(feature = "strict_json_fields")] + pub ai_patrol: Option, + #[cfg(feature = "strict_json_fields")] + pub ai_sense: Option, + #[cfg(feature = "strict_json_fields")] + pub ai_wander: Option, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AiBaseData { + pub id: i32, + pub state_machine: String, + #[cfg(feature = "strict_json_fields")] + pub ai_controller: String, + #[cfg(feature = "strict_json_fields")] + pub behavior_tree: String, + #[cfg(feature = "strict_json_fields")] + pub sub_behavior_configs: SubBehaviorConfigs, + #[cfg(feature = "strict_json_fields")] + pub team: bool, + #[cfg(feature = "strict_json_fields")] + pub monster_type: i32, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/ai_state_machine_config.rs b/wicked-waifus-data/src/ai_state_machine_config.rs new file mode 100644 index 0000000..7574bc2 --- /dev/null +++ b/wicked-waifus-data/src/ai_state_machine_config.rs @@ -0,0 +1,10 @@ +use serde::Deserialize; +use crate::StateMachineJson; + +#[derive(Clone, Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AiStateMachineConfigData { + pub id: String, + pub state_machine_json: StateMachineJson, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/area.rs b/wicked-waifus-data/src/area.rs index ef39c53..8ae7615 100644 --- a/wicked-waifus-data/src/area.rs +++ b/wicked-waifus-data/src/area.rs @@ -1,15 +1,19 @@ use std::collections::HashMap; use serde::Deserialize; -#[derive(Debug, Deserialize, Clone)] +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct AreaData { pub area_id: i32, pub level: i32, pub country_id: i32, pub delivery_mark_id: i32, + #[cfg(feature = "strict_json_fields")] pub area_name: String, pub map_config_id: i32, + pub dungeon_id: i32, + #[cfg(feature = "strict_json_fields")] pub title: String, pub father: i32, pub tag: Vec, @@ -22,9 +26,10 @@ pub struct AreaData { pub wu_yin_qu_id: i32, pub state_id: i32, pub atmosphere_id: i32, + #[cfg(feature = "strict_json_fields")] pub edge_wall_name: String, pub delivery_mark_type: i32, pub sort_index: i32, - pub enter_area_tags: HashMap, - pub leave_area_tags: HashMap, + pub enter_area_tags: HashMap, + pub leave_area_tags: HashMap, } \ No newline at end of file diff --git a/wicked-waifus-data/src/base_property.rs b/wicked-waifus-data/src/base_property.rs index 351921e..362518f 100644 --- a/wicked-waifus-data/src/base_property.rs +++ b/wicked-waifus-data/src/base_property.rs @@ -1,6 +1,7 @@ use serde::Deserialize; -#[derive(Deserialize)] +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct BasePropertyData { pub id: i32, diff --git a/wicked-waifus-data/src/blueprint_config.rs b/wicked-waifus-data/src/blueprint_config.rs new file mode 100644 index 0000000..c4a1d2c --- /dev/null +++ b/wicked-waifus-data/src/blueprint_config.rs @@ -0,0 +1,19 @@ +use serde::Deserialize; + +use crate::{EntityLogic, EntityType}; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BlueprintConfigData { + pub id: i32, + pub blueprint_type: String, + pub entity_type: EntityType, + pub entity_logic: EntityLogic, + #[cfg(feature = "strict_json_fields")] + pub model_id: i32, + #[cfg(feature = "strict_json_fields")] + pub half_height: i32, + #[cfg(feature = "strict_json_fields")] + pub track_height: i32, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/calabash_develop_reward.rs b/wicked-waifus-data/src/calabash_develop_reward.rs new file mode 100644 index 0000000..f42893d --- /dev/null +++ b/wicked-waifus-data/src/calabash_develop_reward.rs @@ -0,0 +1,22 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CalabashDevelopRewardData { + pub monster_id: i32, + pub develop_condition: Vec, + pub monster_info_id: i32, + pub all_exp: i32, + pub sort_id: i32, + pub monster_probe_id: i32, + #[cfg(feature = "strict_json_fields")] + pub hand_book_bp: String, + pub monster_body_type: i32, + #[cfg(feature = "strict_json_fields")] + pub hand_book_camera: String, + #[cfg(feature = "strict_json_fields")] + pub monster_number: String, + pub interaction_radius: i32, + pub is_show: bool, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/calabash_level.rs b/wicked-waifus-data/src/calabash_level.rs new file mode 100644 index 0000000..12e81f7 --- /dev/null +++ b/wicked-waifus-data/src/calabash_level.rs @@ -0,0 +1,24 @@ +use std::collections::HashMap; + +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CalabashLevelData { + pub level: i32, + pub level_up_exp: i32, + pub level_up_condition: i32, + pub temp_catch_gain: i32, + pub buff_ids: Vec, + #[cfg(feature = "strict_json_fields")] + pub buff_description: String, + #[cfg(feature = "strict_json_fields")] + pub level_up_description: String, + #[cfg(feature = "strict_json_fields")] + pub quality_description: String, + pub buff_description_map: HashMap, + pub cost: i32, + pub reward_id: i32, + pub quality_drop_weight: HashMap, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/damage.rs b/wicked-waifus-data/src/damage.rs new file mode 100644 index 0000000..664e13f --- /dev/null +++ b/wicked-waifus-data/src/damage.rs @@ -0,0 +1,43 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DamageData { + pub id: i64, + pub calculate_type: i32, + pub element: i32, + pub damage_text_type: i32, + pub payload_id: i32, + pub r#type: i32, + pub sub_type: Vec, + pub smash_type: i32, + pub cure_base_value: Vec, + pub related_property: i32, + pub rate_lv: Vec, + pub hardness_lv: Vec, + pub tough_lv: Vec, + pub energy: Vec, + pub special_energy1: Vec, + pub special_energy2: Vec, + pub special_energy3: Vec, + pub special_energy4: Vec, + pub element_power_type: i32, + pub element_power: Vec, + pub formula_type: i32, + pub formula_param1: Vec, + pub formula_param2: Vec, + pub formula_param3: Vec, + pub formula_param4: Vec, + pub formula_param5: Vec, + pub formula_param6: Vec, + pub formula_param7: Vec, + pub formula_param8: Vec, + pub formula_param9: Vec, + pub formula_param10: Vec, + pub immune_type: i32, + pub percent0: Vec, + pub percent1: Vec, + pub fluctuation_lower: Vec, + pub fluctuation_upper: Vec, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/dragon_pool.rs b/wicked-waifus-data/src/dragon_pool.rs index 8f72df6..210acfe 100644 --- a/wicked-waifus-data/src/dragon_pool.rs +++ b/wicked-waifus-data/src/dragon_pool.rs @@ -1,6 +1,7 @@ use serde::Deserialize; -#[derive(Debug, Deserialize, Clone)] +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct DragonPoolData { pub id: i32, diff --git a/wicked-waifus-data/src/drop_package.rs b/wicked-waifus-data/src/drop_package.rs new file mode 100644 index 0000000..7274a2b --- /dev/null +++ b/wicked-waifus-data/src/drop_package.rs @@ -0,0 +1,14 @@ +use std::collections::HashMap; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DropPackageData { + pub id: i32, + pub show_bg: bool, + #[cfg(feature = "strict_json_fields")] + pub title: String, + pub drop_plan: i32, + pub drop_preview: HashMap, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/dungeon_detection.rs b/wicked-waifus-data/src/dungeon_detection.rs new file mode 100644 index 0000000..e0a2ac5 --- /dev/null +++ b/wicked-waifus-data/src/dungeon_detection.rs @@ -0,0 +1,48 @@ +use std::collections::HashMap; + +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DungeonDetectionData { + pub id: i32, + pub dungeon_id: i32, + pub name: String, + pub role_id: i32, + pub guide_id: i32, + #[cfg(feature = "strict_json_fields")] + pub level_play_list: Vec>, + #[cfg(feature = "strict_json_fields")] + pub instance_sub_type_description: String, + pub type_description1: i32, + pub secondary: i32, + pub mat_type: i32, + #[cfg(feature = "strict_json_fields")] + pub type_description2: String, + #[cfg(feature = "strict_json_fields")] + pub attributes_description_lock: String, + #[cfg(feature = "strict_json_fields")] + pub attributes_description_unlock: String, + #[cfg(feature = "strict_json_fields")] + pub big_icon: String, + #[cfg(feature = "strict_json_fields")] + pub icon: String, + #[cfg(feature = "strict_json_fields")] + pub lock_big_icon: String, + #[cfg(feature = "strict_json_fields")] + pub temporary_icon_un_lock: String, + #[cfg(feature = "strict_json_fields")] + pub temporary_iconlock: String, + pub show_reward: i32, + pub show_reward_map: HashMap, + pub begin_time_stamp: i32, + pub pre_open_id: i32, + pub lock_con: i32, + #[cfg(feature = "strict_json_fields")] + pub phantom_id: Vec>, + pub sub_dungeon_id: i32, + pub sort_id: i32, + #[cfg(feature = "strict_json_fields")] + pub new_content: String, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/exchange_reward.rs b/wicked-waifus-data/src/exchange_reward.rs new file mode 100644 index 0000000..63db543 --- /dev/null +++ b/wicked-waifus-data/src/exchange_reward.rs @@ -0,0 +1,15 @@ +use std::collections::HashMap; + +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ExchangeRewardData { + pub id: i32, + pub shared_id: i32, + pub max_count: i32, + pub cost: HashMap, + pub reward_id: HashMap, + pub preview_reward: HashMap, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/exchange_shared.rs b/wicked-waifus-data/src/exchange_shared.rs new file mode 100644 index 0000000..c1ed5d8 --- /dev/null +++ b/wicked-waifus-data/src/exchange_shared.rs @@ -0,0 +1,13 @@ +use std::collections::HashMap; + +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ExchangeSharedData { + pub id: i32, + pub max_count: i32, + pub cost: HashMap, + pub reset_time_id: i32, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/explore_progress.rs b/wicked-waifus-data/src/explore_progress.rs new file mode 100644 index 0000000..cad388c --- /dev/null +++ b/wicked-waifus-data/src/explore_progress.rs @@ -0,0 +1,26 @@ +use std::collections::HashMap; + +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ExploreProgressData { + pub id: i32, + pub area: i32, + pub explore_type: i32, + pub sub_type_score: HashMap, + pub phantom_skill_id: i32, + #[cfg(feature = "strict_json_fields")] + pub unlock_text_id: String, + #[cfg(feature = "strict_json_fields")] + pub lock_text_id: String, + pub unlock_condition: i32, + #[cfg(feature = "strict_json_fields")] + pub special_player_map: HashMap, + pub is_recommend: bool, + pub is_show_progress: bool, + pub is_show_track: bool, + #[cfg(feature = "strict_json_fields")] + pub special_player_desc: String, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/explore_tools.rs b/wicked-waifus-data/src/explore_tools.rs index 69c777b..49d0a98 100644 --- a/wicked-waifus-data/src/explore_tools.rs +++ b/wicked-waifus-data/src/explore_tools.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use serde::Deserialize; #[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct ExploreToolsData { pub phantom_skill_id: i32, diff --git a/wicked-waifus-data/src/favor_goods.rs b/wicked-waifus-data/src/favor_goods.rs new file mode 100644 index 0000000..ced7b09 --- /dev/null +++ b/wicked-waifus-data/src/favor_goods.rs @@ -0,0 +1,24 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FavorGoodsData { + pub id: i32, + pub role_id: i32, + pub sort: i32, + #[cfg(feature = "strict_json_fields")] + pub title: String, + #[cfg(feature = "strict_json_fields")] + pub content: String, + #[cfg(feature = "strict_json_fields")] + pub pic: String, + pub cond_group_id: i32, + pub r#type: i32, + #[cfg(feature = "strict_json_fields")] + pub motion_img: String, + #[cfg(feature = "strict_json_fields")] + pub ani_blueprint: String, + #[cfg(feature = "strict_json_fields")] + pub ani_montage: String, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/favor_level.rs b/wicked-waifus-data/src/favor_level.rs new file mode 100644 index 0000000..ef0f178 --- /dev/null +++ b/wicked-waifus-data/src/favor_level.rs @@ -0,0 +1,9 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FavorLevelData { + pub level: i32, + pub level_up_exp: i32, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/favor_story.rs b/wicked-waifus-data/src/favor_story.rs new file mode 100644 index 0000000..fcd6a8a --- /dev/null +++ b/wicked-waifus-data/src/favor_story.rs @@ -0,0 +1,22 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FavorStoryData { + pub id: i32, + pub role_id: i32, + pub sort: i32, + #[cfg(feature = "strict_json_fields")] + pub title: String, + #[cfg(feature = "strict_json_fields")] + pub content: String, + pub cond_group_id: i32, + pub r#type: i32, + #[cfg(feature = "strict_json_fields")] + pub motion_img: String, + #[cfg(feature = "strict_json_fields")] + pub ani_blueprint: String, + #[cfg(feature = "strict_json_fields")] + pub ani_montage: String, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/favor_word.rs b/wicked-waifus-data/src/favor_word.rs new file mode 100644 index 0000000..e9d0008 --- /dev/null +++ b/wicked-waifus-data/src/favor_word.rs @@ -0,0 +1,36 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FavorWordData { + pub id: i32, + pub role_id: i32, + pub r#type: i32, + pub sort: i32, + #[cfg(feature = "strict_json_fields")] + pub title: String, + #[cfg(feature = "strict_json_fields")] + pub content: String, + #[cfg(feature = "strict_json_fields")] + pub voice: String, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "CVCn")] + pub cv_cn: String, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "CVJp")] + pub cv_jp: String, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "CVEn")] + pub cv_en: String, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "CVKo")] + pub cv_ko: String, + pub cond_group_id: i32, + #[cfg(feature = "strict_json_fields")] + pub motion_img: String, + #[cfg(feature = "strict_json_fields")] + pub ani_blueprint: String, + #[cfg(feature = "strict_json_fields")] + pub ani_montage: String, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/forge_formula.rs b/wicked-waifus-data/src/forge_formula.rs new file mode 100644 index 0000000..6b6ac81 --- /dev/null +++ b/wicked-waifus-data/src/forge_formula.rs @@ -0,0 +1,22 @@ +use serde::Deserialize; +use crate::ConsumeItem; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ForgeFormulaData { + pub id: i32, + pub formula_item_id: i32, + pub item_id: i32, + pub type_id: i32, + pub unlock: bool, + pub sort_id: i32, + #[cfg(feature = "strict_json_fields")] + pub name: String, + pub consume_items: Vec, + #[cfg(feature = "strict_json_fields")] + pub forge_content: String, + #[cfg(feature = "strict_json_fields")] + pub background: String, + pub role_list: Vec, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/function_condition.rs b/wicked-waifus-data/src/function_condition.rs index 301ba14..891fac2 100644 --- a/wicked-waifus-data/src/function_condition.rs +++ b/wicked-waifus-data/src/function_condition.rs @@ -1,10 +1,25 @@ use serde::Deserialize; #[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct FunctionConditionData { pub function_id: i32, + #[cfg(feature = "strict_json_fields")] pub name: String, pub is_on: bool, pub open_condition_id: i32, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "ShowUIType")] + pub show_ui_type: i32, + #[cfg(feature = "strict_json_fields")] + pub delay: i32, + #[cfg(feature = "strict_json_fields")] + pub title: String, + #[cfg(feature = "strict_json_fields")] + pub desc: String, + #[cfg(feature = "strict_json_fields")] + pub icon: String, + #[cfg(feature = "strict_json_fields")] + pub icon_sprite: String, } diff --git a/wicked-waifus-data/src/gacha.rs b/wicked-waifus-data/src/gacha.rs index fc1257d..5eeee75 100644 --- a/wicked-waifus-data/src/gacha.rs +++ b/wicked-waifus-data/src/gacha.rs @@ -1,6 +1,7 @@ use serde::Deserialize; #[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct GachaData { pub id: i32, diff --git a/wicked-waifus-data/src/gacha_pool.rs b/wicked-waifus-data/src/gacha_pool.rs index 664cc0d..7e12a7b 100644 --- a/wicked-waifus-data/src/gacha_pool.rs +++ b/wicked-waifus-data/src/gacha_pool.rs @@ -1,6 +1,7 @@ use serde::Deserialize; #[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct GachaPoolData { pub id: i32, diff --git a/wicked-waifus-data/src/gacha_view_info.rs b/wicked-waifus-data/src/gacha_view_info.rs index 27cf5d6..37e3aaa 100644 --- a/wicked-waifus-data/src/gacha_view_info.rs +++ b/wicked-waifus-data/src/gacha_view_info.rs @@ -2,20 +2,34 @@ use serde::Deserialize; use crate::GachaViewTypeInfoId; #[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct GachaViewInfoData { pub id: i32, pub r#type: GachaViewTypeInfoId, pub summary_title: String, pub summary_describe: String, - // TODO: Effect path pub theme_color: String, + #[cfg(feature = "strict_json_fields")] + pub effect_location: RawVectorData, + #[cfg(feature = "strict_json_fields")] + pub effect_path: String, + #[cfg(feature = "strict_json_fields")] + pub text_texture: String, + #[cfg(feature = "strict_json_fields")] pub content_texture_path: String, + #[cfg(feature = "strict_json_fields")] pub content_texture_bg_path: String, + #[cfg(feature = "strict_json_fields")] pub under_bg_texture_path: String, + #[cfg(feature = "strict_json_fields")] pub tag_not_selected_sprite_path: String, + #[cfg(feature = "strict_json_fields")] pub tag_selected_sprite_path: String, + #[cfg(feature = "strict_json_fields")] pub weapon_prefab_path: String, + #[cfg(feature = "strict_json_fields")] + pub spine_prefab_resource: String, pub up_list: Vec, pub show_id_list: Vec, pub preview_id_list: Vec, diff --git a/wicked-waifus-data/src/guide_group.rs b/wicked-waifus-data/src/guide_group.rs new file mode 100644 index 0000000..55f1691 --- /dev/null +++ b/wicked-waifus-data/src/guide_group.rs @@ -0,0 +1,16 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GuideGroupData { + pub id: i32, + pub step: Vec, + pub open_limit_condition: i32, + pub auto_open_condition: i32, + pub limit_repeat: Vec, + pub dungeon_id: Vec, + pub reset_in_dungeon: bool, + pub online_mode: i32, + pub priority: i32, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/guide_tutorial.rs b/wicked-waifus-data/src/guide_tutorial.rs index 6e67134..32458d5 100644 --- a/wicked-waifus-data/src/guide_tutorial.rs +++ b/wicked-waifus-data/src/guide_tutorial.rs @@ -1,11 +1,20 @@ use serde::Deserialize; #[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct GuideTutorialData { - pub id: i32, - pub tutorial_type: i32, - pub tutorial_order: i32, - pub page_id: Vec, - pub tutorial_tip: bool, - } \ No newline at end of file + pub id: i32, + pub tutorial_type: i32, + pub tutorial_order: i32, + pub page_id: Vec, + pub page_replace_condition_group_id: i32, + pub replace_page_id: Vec, + #[cfg(feature = "strict_json_fields")] + pub group_name: String, + pub tutorial_tip: bool, + pub drop_id: i32, + pub disable_drop_reward: bool, + pub require_read_all: bool, + pub exclude_from_wiki: bool, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/instance_dungeon.rs b/wicked-waifus-data/src/instance_dungeon.rs index af2f5e1..4865a67 100644 --- a/wicked-waifus-data/src/instance_dungeon.rs +++ b/wicked-waifus-data/src/instance_dungeon.rs @@ -5,29 +5,49 @@ use serde::Deserialize; use crate::{EntranceEntityData, VectorData}; #[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct InstanceDungeonData { pub id: i32, pub map_config_id: i32, + #[cfg(feature = "strict_json_fields")] pub map_name: String, pub inst_type: i32, pub inst_sub_type: i32, + pub online_type: i32, pub custom_types: Vec, pub mini_map_id: i32, pub sub_levels: Vec, pub fight_formation_id: i32, + pub role_type_list: Vec, pub trial_role_info: Vec, + pub trial_formation_id: Option, pub revive_id: i32, pub born_position: VectorData, pub born_rotation: VectorData, pub recover_world_location: Vec, + pub exit_dungeon_confirm_id: Vec, pub entrance_entities: Vec, pub exit_entities: Vec, + #[cfg(feature = "strict_json_fields")] + pub dungeon_desc: String, + pub title: i32, + #[cfg(feature = "strict_json_fields")] + pub banner_path: String, + pub monster_preview: Vec, + #[cfg(feature = "strict_json_fields")] + pub monster_tips: String, pub first_reward_id: i32, pub reward_id: i32, pub repeat_reward_id: i32, + pub exchange_reward_id: i32, + pub shared_treasure_group: Vec, pub enter_control_id: i32, pub enter_condition: Vec, + #[cfg(feature = "strict_json_fields")] + pub enter_condition_text: String, + #[cfg(feature = "strict_json_fields")] + pub difficulty_icon: String, pub entity_level: i32, pub recommend_level: HashMap, pub recommend_role: Vec, diff --git a/wicked-waifus-data/src/item_exchange_content.rs b/wicked-waifus-data/src/item_exchange_content.rs new file mode 100644 index 0000000..77815c1 --- /dev/null +++ b/wicked-waifus-data/src/item_exchange_content.rs @@ -0,0 +1,13 @@ +use std::collections::HashMap; + +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ItemExchangeContentData { + pub item_id: i32, + pub times: i32, + pub gain_count: i32, + pub consume: HashMap, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/level_entity_config.rs b/wicked-waifus-data/src/level_entity_config.rs index c02f709..c0a8f1b 100644 --- a/wicked-waifus-data/src/level_entity_config.rs +++ b/wicked-waifus-data/src/level_entity_config.rs @@ -1,13 +1,16 @@ use serde::Deserialize; -use crate::{ComponentsData, RawVectorData}; +use crate::RawVectorData; +use crate::pb_components::ComponentsData; #[derive(Deserialize, Debug)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct LevelEntityConfigData { pub id: i32, pub map_id: i32, pub entity_id: i64, pub blueprint_type: String, + #[cfg(feature = "strict_json_fields")] pub name: String, pub in_sleep: bool, pub is_hidden: bool, diff --git a/wicked-waifus-data/src/level_play_data.rs b/wicked-waifus-data/src/level_play_data.rs new file mode 100644 index 0000000..5b6c6cf --- /dev/null +++ b/wicked-waifus-data/src/level_play_data.rs @@ -0,0 +1,11 @@ +use serde::Deserialize; +use crate::LevelPlayDataDetail; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct LevelPlayDataData { // Json file contains Data in name, so it has to be DataData + pub level_play_id: i32, + pub data: LevelPlayDataDetail, +} + diff --git a/wicked-waifus-data/src/level_play_node_data.rs b/wicked-waifus-data/src/level_play_node_data.rs new file mode 100644 index 0000000..f76a893 --- /dev/null +++ b/wicked-waifus-data/src/level_play_node_data.rs @@ -0,0 +1,11 @@ +use serde::Deserialize; +use crate::node_data::NodeDataDetail; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct LevelPlayNodeDataData { // Json file contains Data in name, so it has to be DataData + pub key: String, + pub data: NodeDataDetail, +} + diff --git a/wicked-waifus-data/src/lib.rs b/wicked-waifus-data/src/lib.rs index 7fec598..cfaaadd 100644 --- a/wicked-waifus-data/src/lib.rs +++ b/wicked-waifus-data/src/lib.rs @@ -3,9 +3,15 @@ use std::io::BufReader; use paste::paste; +pub use level_entity_config::LevelEntityConfigData; pub use misc_data::*; +pub mod node_data; +pub mod pb_components; +pub mod text_map_data; + mod misc_data; + #[derive(thiserror::Error, Debug)] pub enum LoadDataError { #[error("I/O error: {0}")] @@ -35,9 +41,12 @@ macro_rules! json_data { fn load_json_data(base_path: &str) -> Result<(), LoadDataError> { $(paste! { - let file = File::open(&format!("{}/{}.json", base_path, stringify!($table_type)))?; + let path = format!("{}/{}.json", base_path, stringify!($table_type)); + tracing::debug!("Loading data started: {path}"); + let file = File::open(&path)?; let reader = BufReader::new(file); let _ = [<$table_type:snake _data>]::TABLE.set(serde_json::from_reader(reader)?); + tracing::info!("Loading data finished: {path}"); })* Ok(()) @@ -64,7 +73,7 @@ macro_rules! json_hash_table_data { TABLE.get().unwrap().iter() } - pub fn get(k: &$key_type) -> Option<&Data> { + pub fn get(k: &$key_type) -> Option<&'static Data> { TABLE.get().unwrap().get(k) } } @@ -72,14 +81,19 @@ macro_rules! json_hash_table_data { fn load_json_hash_table_data(base_path: &str) -> Result<(), LoadDataError> { $(paste! { - let file = File::open(&format!("{}/{}.json", base_path, stringify!($table_type)))?; + let path = format!("{}/{}.json", base_path, stringify!($table_type)); + tracing::debug!("Loading data started: {path}"); + let file = File::open(&path)?; let reader = BufReader::new(file); + // Key.clone() is required for String keys, for other types like ints, it doesn't + // have any effect since clone is *value let _ = [<$table_type:snake _data>]::TABLE.set( serde_json::from_reader::, Vec<[<$table_type:snake _data>]::Data>>(reader)? .into_iter() - .map(|element| (element.$key_param, element)) + .map(|element| (element.$key_param.clone(), element)) .collect::>() ); + tracing::info!("Loading data finished: {path}"); })* Ok(()) @@ -90,105 +104,112 @@ macro_rules! json_hash_table_data { pub fn load_all_json_data(base_path: &str) -> Result<(), LoadDataError> { load_json_data(base_path)?; load_json_hash_table_data(base_path)?; + load_json_entity_level_config_data(base_path)?; Ok(()) } json_data! { + Achievement; AdventureTask; Area; BaseProperty; + CalabashDevelopReward; + CalabashLevel; + Damage; + DungeonDetection; + ExchangeReward; + ExchangeShared; + ExploreProgress; ExploreTools; + FavorGoods; + FavorLevel; + FavorStory; + FavorWord; + ForgeFormula; FunctionCondition; Gacha; GachaPool; GachaViewInfo; + GuideGroup; GuideTutorial; InstanceDungeon; + ItemExchangeContent; + // LevelPlayData; + LevelPlayNodeData; + LivenessTask; LordGym; + MonsterDetection; + MonsterPropertyGrowth; + Motion; + QuestNodeData; + ResonanceAmplification; + ResonantChain; + RoleBreach; + RoleExpItem; RoleInfo; + RoleLevelConsume; + RolePropertyGrowth; + SilentAreaDetection; + SynthesisFormula; Teleporter; + WeaponBreach; WeaponConf; + WeaponExpItem; + WeaponLevel; + WeaponPropertyGrowth; + WeaponReson; } json_hash_table_data! { + AiBase, id, i32; + AiStateMachineConfig, id, String; + BlueprintConfig, blueprint_type, String; DragonPool, id, i32; - LevelEntityConfig, entity_id, i64; - // TemplateConfig, blueprint_type, String; + DropPackage, id, i32; + TemplateConfig, blueprint_type, String; } -mod textmap; +mod level_entity_config; -pub mod text_map_data { - use std::collections::{HashMap, HashSet}; - use std::fs::File; - use std::io::BufReader; +pub mod level_entity_config_data { + use std::collections::HashMap; use std::sync::OnceLock; - use crate::LoadDataError; - use crate::textmap::TextMapData; - use crate::gacha_view_info_data; + pub(crate) type Data = super::LevelEntityConfigData; + pub(crate) static TABLE: OnceLock> = OnceLock::new(); - static EMPTY: OnceLock> = OnceLock::new(); - static TABLE: OnceLock>> = OnceLock::new(); - - pub fn load_textmaps(base_path: &str) -> Result<(), LoadDataError> { - // TODO: Ideally we would expose a function here to allow other components to add to the - // filter, since right now only gacha uses it, we can do this - let filters = get_filters(); - let languages = std::fs::read_dir(base_path)? - .filter_map(|entry| entry.ok()) - .filter(|entry| entry.path().is_dir()) - .collect::>(); - let mut result: HashMap> = HashMap::new(); - for language in languages { - let lang_id = language.file_name().to_str().unwrap().to_string(); - let file = File::open(&format!("{base_path}/{lang_id}/multi_text/MultiText.json"))?; - let reader = BufReader::new(file); - result.insert( - lang_id, - serde_json::from_reader::, Vec>(reader)? - .into_iter() - .filter(|element| filters.contains(&element.id)) - .map(|element| (element.id, element.content)) - .collect::>(), - ); - } - let _ = TABLE.set(result); - Ok(()) + pub fn iter() -> std::collections::hash_map::Iter<'static, String, Data> { + TABLE.get().unwrap().iter() } - pub fn get_textmap(language: i32) -> &'static HashMap { - let (text_code, _audio_code) = get_language_from_i32(language); - TABLE.get_or_init(|| HashMap::new()) - .get(text_code) - .unwrap_or(EMPTY.get_or_init(|| HashMap::new())) + pub fn get(map_id: i32, entity_id: i64) -> Option<&'static Data> { + TABLE.get().unwrap().get(&create_key_internal(map_id, entity_id)) } - fn get_language_from_i32(language: i32) -> (&'static str, &'static str) { - match language { - 0 => ("zh-Hans", "zh"), - 1 => ("en", "en"), - 2 => ("ja", "ja"), - 3 => ("ko", "ko"), - 4 => ("ru", "en"), - 5 => ("zh-Hant", "zh"), - 6 => ("de", "en"), - 7 => ("es", "en"), - 8 => ("pt", "en"), - 9 => ("id", "en"), - 10 => ("fr", "en"), - 11 => ("vi", "en"), - 12 => ("th", "en"), - _ => ("en", "en"), - } + #[inline(always)] + pub fn create_key(element: &Data) -> String { + create_key_internal(element.map_id, element.entity_id) } - fn get_filters() -> HashSet { - let mut filters = HashSet::new(); - for gacha_view_info in gacha_view_info_data::iter() { - filters.insert(gacha_view_info.summary_title.clone()); - filters.insert(gacha_view_info.summary_describe.clone()); - } - filters + #[inline(always)] + fn create_key_internal(map_id: i32, entity_id: i64) -> String { + format!("{}_{}", map_id, entity_id) } +} + +fn load_json_entity_level_config_data(base_path: &str) -> Result<(), LoadDataError> { + let path = format!("{}/LevelEntityConfig.json", base_path); + tracing::debug!("Loading data started: {path}"); + let file = File::open(&path)?; + let reader = BufReader::new(file); + let _ = level_entity_config_data::TABLE.set( + serde_json::from_reader::, Vec>(reader)? + .into_iter() + .map(|element| (level_entity_config_data::create_key(&element), element)) + .collect::>() + ); + tracing::info!("Loading data finished: {path}"); + + + Ok(()) } \ No newline at end of file diff --git a/wicked-waifus-data/src/liveness_task.rs b/wicked-waifus-data/src/liveness_task.rs new file mode 100644 index 0000000..0a7f17c --- /dev/null +++ b/wicked-waifus-data/src/liveness_task.rs @@ -0,0 +1,18 @@ +use std::collections::HashMap; + +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct LivenessTaskData { + pub task_id: i32, + #[cfg(feature = "strict_json_fields")] + pub task_name: String, + pub update_type: i32, + pub task_reward: HashMap, + #[cfg(feature = "strict_json_fields")] + pub task_func: Vec, + pub unlock_condition: i32, + pub sort_rank: i32, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/lord_gym.rs b/wicked-waifus-data/src/lord_gym.rs index 95a302a..ba92580 100644 --- a/wicked-waifus-data/src/lord_gym.rs +++ b/wicked-waifus-data/src/lord_gym.rs @@ -1,20 +1,28 @@ use serde::Deserialize; #[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct LordGymData { pub id: i32, pub difficulty: i32, pub reward_id: i32, pub play_id: i32, + #[cfg(feature = "strict_json_fields")] pub gym_title: String, + #[cfg(feature = "strict_json_fields")] + pub new_gym_title: String, + #[cfg(feature = "strict_json_fields")] pub icon_path: String, + #[cfg(feature = "strict_json_fields")] pub play_description: String, pub help_id: i32, pub monster_list: Vec, pub monster_level: i32, pub lock_con: i32, + #[cfg(feature = "strict_json_fields")] pub lock_description: String, pub filter_type: i32, + pub is_new: bool, pub is_debug: bool, } \ No newline at end of file diff --git a/wicked-waifus-data/src/misc_data.rs b/wicked-waifus-data/src/misc_data.rs index 0cd450d..1890a10 100644 --- a/wicked-waifus-data/src/misc_data.rs +++ b/wicked-waifus-data/src/misc_data.rs @@ -1,6 +1,9 @@ use serde::Deserialize; use serde_repr::Deserialize_repr; +use crate::pb_components::action::Action; +use crate::pb_components::condition::Condition; + #[derive(Deserialize)] #[serde(rename_all = "PascalCase")] pub struct PropValueData { @@ -53,7 +56,7 @@ impl RawVectorData { #[serde(rename_all = "PascalCase")] pub struct EntranceEntityData { pub dungeon_id: i32, - pub entrance_entity_id: i32, + pub entrance_entity_id: i64, } #[derive(Deserialize_repr, PartialEq, Debug, Copy, Clone)] @@ -67,186 +70,423 @@ pub enum GachaViewTypeInfoId { BeginnersChoiceConvene = 6, } -#[derive(Deserialize, Debug, Clone)] +#[derive(Debug, Deserialize, Clone)] #[serde(rename_all = "PascalCase")] -pub struct Category { - pub main_type: Option, - pub monster_match_type: Option, +pub struct ConsumeItem { + pub item_id: i32, + pub count: i32, } -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "PascalCase")] -pub struct ScanFunction { - pub scan_id: Option, - pub is_concealed: Option, +#[derive(Deserialize, PartialEq, Debug, Copy, Clone)] +pub enum EntityType { + AdsorptionFoundation, + AdviseItem, + AiAlertNotifier, + AiGearController, + AiMovementGear, + AirPassage, + AiSceneItem, + Animal, + Animal2, + AnnunciatorCenter, + AnnunciatorWire, + AreaOccupation, + Audio, + AudioBox, + BatchBulletCaster, + BeamCastBullet, + BeamCaster, + BeamCrystal, + BeamDeliver, + BeamReceiver, + BondageTrap, + BuffConsumer, + BuffProducer, + BurstCrystalFoundation, + Chair, + Chair2, + ChallengeInteract, + Chessboard, + Chessman, + ClientTrigger, + Collect, + Collect2, + Collect3, + CollectAnimal, + CollectAnimalPart, + CombatAnimal, + CombatAnimal2, + CombinedVisibleGroup, + ControlConnector, + ConveyorBelt, + CookTool, + CustomAoiEditor, + Destructible, + DestructibleControl, + DestructibleExploreInteractor, + DestructibleSceneBullet, + DestructibleTrigger, + Disc, + Drop, + DungeonEntry, + DynamicPortalCreater, + EffectArea, + EnrichmentArea, + EntityBundle, + EntityList, + EntityPackage, + ExploreSkillInteractor, + FishingBoat, + FollowShooter, + FollowShooter2, + FollowTrack, + FollowTrackFoundation, + Gramophone, + GravityFlip, + GroupAi, + HackingTypeFollowShooter, + HookLockPoint, + HookSoundBox, + HookWithRange, + HorseBettingTuanzi, + InhaledItem, + InteractFoundation, + InteractFoundationWithSceneItemAttribute, + InteractGear, + InteractGearGroup, + InteractiveConditionListener, + Item, + ItemFoundation, + JigsawFoundation, + JigsawItem, + KiteHook, + LevelPlay, + LevelPlayReward, + LevelQteTrigger, + LevitateMagnet, + LifePointCenter, + Lift, + LightDeliver, + LocationSafety, + Monitor, + Monster, + MonsterGachaBase, + MonsterGachaItem, + MoveableTrigger, + NoRenderPortal, + Npc, + Npc2, + PasserbyNpc, + PhotoTarget, + PhysicsSwing, + Portal, + Position, + ProgressBarController, + ProgressBarControllerWithAttribute, + PullingObject, + Range, + RangeTriggerTargetGear, + ReboundPlateGear, + RefreshGroup, + RenderSpecifiedRange, + Resurrection, + RollingFireball, + Rotator, + SceneAura, + SceneBullet, + SceneBulletCanHit, + SceneBulletWithMovement, + SceneItemStateHint, + SimpleInteract, + SimpleNPc, + SkyboxTrigger, + SoundBox, + SpawnMonster, + SpawnPasserbyNpc, + Spline, + SummonGongduolaPoint, + StateSceneItem, + StateTrigger, + StatueFoundation, + SuiGuangHook, + TargetGear, + TargetGearGroup, + TargetGearGroup2, + TargetGearPro, + TargetGearWithLevelPrefabPerform, + TeleControl, + TeleControl3, + TeleControlGroup, + Teleporter, + TemporaryTeleporter, + TimelineTrackController, + TimeStop, + Trample, + Trample2, + Trample3, + TreasureBox, + Trigger, + TriggerConditionListener, + TurntableController, + VacuumCleaner, + VarManager, + Vehicle, + Vehicle2, + VehicleNpc, + VehicleSceneItem, + VisibleTrigger, + Vision, + VisionItem, + VisionTreasureBox, + WalkingPatternController, + WaterCollection, + WaterSpout, + Weapon, } -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "PascalCase")] -pub struct WorldLevelBonusType { - pub r#type: Option, - pub world_level_bonus_id: Option, +#[derive(Deserialize, PartialEq, Debug, Copy, Clone)] +pub enum EntityLogic { + Item, + Animal, + Monster, + Vehicle, + Npc, + Vision, + ClientOnly, + ServerOnly, + Custom, } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] -pub struct BaseInfoComponent { - pub tid_name: Option, - pub category: Option, - pub camp: Option, - pub online_interact_type: Option, - pub scan_function: Option, - pub aoi_layer: Option, - pub entity_property_id: Option, - pub focus_priority: Option, - pub aoi_zradius: Option, - // TODO: Add more +#[derive(Debug, Deserialize)] +pub enum LevelPlayType { + Challenge, + SilentArea, + Dungeon, + MonsterTreasure, + Quest, + Riddle, } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] -pub struct AiComponent { - pub disabled: Option, - pub ai_id: Option, - // TODO: Add more +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct LevelPlayOpenCondition { + pub conditions: Option>, } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] -pub struct AttributeComponent { - pub property_id: Option, - pub level: Option, - pub world_level_bonus_type: Option, - pub rage_mode_id: Option, - pub hardness_mode_id: Option, - pub monster_prop_extra_rate_id: Option, - pub world_level_bonus_id: Option, - pub fight_music: Option, - // TODO: Add more +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct LevelPlayActive { + pub active_type: i32, } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] -pub struct TeleportPosition { - pub x: Option, - pub y: Option, - pub z: Option, - pub a: Option, +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct LevelPlayRewardConfigResetTypeMidNight { + pub count: i32, } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "PascalCase")] -pub struct TeleportComponent { - pub disabled: Option, - pub teleporter_id: Option, - #[serde(rename = "TeleportPos")] - pub teleport_position: Option, +#[derive(Debug, Deserialize)] +#[serde(tag = "Type")] +pub enum LevelPlayRewardConfigResetType { + MidNight(LevelPlayRewardConfigResetTypeMidNight), } -#[derive(Deserialize, Debug)] +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct LevelPlayRewardConfigInteract { + pub reward_id: i32, + pub reward_entity_id: i64, + pub reward_complete_actions: Vec, + pub first_complete_actions: Option>, + pub reset: Option, +} + +#[derive(Debug, Deserialize)] +#[serde(tag = "Type")] +pub enum LevelPlayRewardConfig { + None, + Interact(LevelPlayRewardConfigInteract), +} + +#[derive(Debug, Deserialize)] +pub enum FixedDateTime { + Daily, + Weekly +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct LevelPlayRefreshConfigFixedDateTime { + pub update_type: FixedDateTime, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct LevelPlayRefreshConfigCompleted { + pub min_refresh_cd: i32, + pub max_refresh_cd: i32, +} + +#[derive(Debug, Deserialize)] +#[serde(tag = "Type")] +pub enum LevelPlayRefreshConfig { + None, + FixedDateTime(LevelPlayRefreshConfigFixedDateTime), + Completed(LevelPlayRefreshConfigCompleted), +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct LevelPlayTrack { + pub track_radius: i32, + pub track_priority: i32, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct LevelPlayMark { + pub mark_id: i32, + pub map_bg_path: String, +} + +#[derive(Debug, Deserialize)] +pub enum OnlineType { + Multiplayer, + Local, + Hang, +} + +#[derive(Debug, Deserialize)] +pub enum ObjType { + LevelPlay, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct LevelPlayDataDetail { // Json file contains Data in name, so it has to be DataData + pub id: i32, + pub key: String, + #[cfg(feature = "strict_json_fields")] + pub internal_dest: String, + pub level_id: i32, + #[cfg(feature = "strict_json_fields")] + pub tid_name: String, + pub r#type: LevelPlayType, + pub instance_id: i32, + pub level_play_entity_id: i64, + pub level_additive_id: i32, + pub enter_radius: i32, + pub leave_radius: i32, + pub delay_refresh: bool, + pub delay_destroy: bool, + pub level_play_open_condition: LevelPlayOpenCondition, + pub level_play_active: LevelPlayActive, + pub level_play_reward_config: LevelPlayRewardConfig, + pub level_play_refresh_config: LevelPlayRefreshConfig, + pub level_play_track: LevelPlayTrack, + pub level_play_mark: Option, + pub enter_in_range_actions: Option>, + pub pack_id: i32, + pub online_type: OnlineType, + pub obj_type: ObjType, + #[cfg(feature = "strict_json_fields")] + pub children: Option>, + #[cfg(feature = "strict_json_fields")] + pub reference: Vec, + #[cfg(feature = "strict_json_fields")] + pub weak_reference: Option>, + pub exploratory_degree: Option, +} + +#[derive(Clone, Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] -pub struct ComponentsData { - pub base_info_component: Option, - pub ai_component: Option, - pub attribute_component: Option, - pub teleport_component: Option, - // TODO: Implement this ones - // pub scene_actor_ref_component: Option, - // pub effect_area_component: Option, - // pub entity_state_component: Option, - // pub condition_listener_component: Option, - // pub interact_component: Option, - // pub npc_perform_component: Option, - // pub var_component: Option, - // pub entity_visible_component: Option, - // pub level_ai_component: Option, - // pub trigger_component: Option, - // pub range_component: Option, - // pub spline_component: Option, - // pub bubble_component: Option, - // pub reward_component: Option, - // pub refresh_component: Option, - // pub passerby_npc_spawn_component: Option, - // pub vision_capture_component: Option, - // pub refresh_group_component: Option, - // pub collect_component: Option, - // pub target_gear_component: Option, - // pub fight_interact_component: Option, - // pub guide_line_creator_component: Option, - // pub photo_target_component: Option, - // pub model_component: Option, - // pub entity_group_component: Option, - // pub scene_item_life_cycle_component: Option, - // pub entity_state_audio_component: Option, - // pub animal_component: Option, - // pub monster_component: Option, - // pub nearby_tracking_component: Option, - // pub follow_track_component: Option, - // pub jigsaw_foundation: Option, - // pub treasure_box_component: Option, - // pub hook_lock_point: Option, - // pub explore_skill_interact_component: Option, - // pub attach_target_component: Option, - // pub target_gear_group_component: Option, - // pub spawn_monster_component: Option, - // pub skybox_component: Option, - // pub destructible_item: Option, - // pub fan_component: Option, - // pub state_hint_component: Option, - // pub buff_consumer_component: Option, - // pub reset_entities_pos_component: Option, - // pub group_ai_component: Option, - // pub pulling_object_foundation: Option, - // pub lift_component: Option, - // pub scene_item_movement_component: Option, - // pub reset_self_pos_component: Option, - // pub jigsaw_item: Option, - // pub level_play_component: Option, - // pub interact_gear_component: Option, - // pub ai_gear_strategy_component: Option, - // pub pick_interact_component: Option, - // pub level_sequence_frame_event_component: Option, - // pub air_wall_spawner_component: Option, - // pub progress_bar_control_component: Option, - // pub batch_bullet_caster_component: Option, - // pub client_trigger_component: Option, - // pub enrichment_area_component: Option, - // pub vehicle_component: Option, - // pub item_foundation2: Option, - // pub tele_control2: Option, - // pub interact_audio_component: Option, - // pub level_qte_component: Option, - // pub resurrection_component: Option, - // pub ai_alert_notify_component: Option, - // pub trample_component: Option, - // pub dungeon_entry_component: Option, - // pub level_prefab_perform_component: Option, - // pub render_specified_range_component: Option, - // pub walking_pattern_component: Option, - // pub no_render_portal_component: Option, - // pub adsorb_component: Option, - // pub beam_cast_component: Option, - // pub beam_receive_component: Option, - // pub timeline_track_control_component: Option, - // pub scene_bullet_component: Option, - // pub edit_custom_aoi_component: Option, - // pub combat_component: Option, - // pub location_safety_component: Option, - // pub turntable_control_component: Option, - // pub scene_item_ai_component: Option, - // pub buff_producer_component: Option, - // pub portal_component: Option, - // pub inhalation_ability_component: Option, - // pub inhaled_item_component: Option, - // pub monster_gacha_base_component: Option, - // pub monster_gacha_item_component: Option, - // pub time_stop_component: Option, - // pub hit_component: Option, - // pub levitate_magnet_component: Option, - // pub rebound_component: Option, - // pub rotator_component2: Option, - // pub conveyor_belt_component: Option, - // pub dynamic_portal_creator_component: Option, - // pub connector_component: Option, - // pub monitor_component: Option, +pub struct StateMachineTransition { + pub from: i32, + pub to: i32, + pub transition_prediction_type: i32, + pub weight: i32, + #[cfg(feature = "strict_json_fields")] + pub conditions: Vec, // TODO: Implement conditions +} + +#[derive(Clone, Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct StateMachineNodeCommon { + pub uuid: i32, + #[cfg(feature = "strict_json_fields")] + pub is_anim_state_machine: Option, + #[cfg(feature = "strict_json_fields")] + pub is_conduit_node: Option, + #[cfg(feature = "strict_json_fields")] + pub is_any_state: Option, + #[cfg(feature = "strict_json_fields")] + pub name: String, + #[cfg(feature = "strict_json_fields")] + pub take_control_type: i32, + #[cfg(feature = "strict_json_fields")] + pub transition_rule: i32, + pub children: Option>, + pub transitions: Option>, + #[cfg(feature = "strict_json_fields")] + pub on_enter_actions: Option>, // TODO: Implement actions + #[cfg(feature = "strict_json_fields")] + pub on_exit_actions: Option>, // TODO: Implement actions + #[cfg(feature = "strict_json_fields")] + pub bind_states: Option>, // TODO: Implement bindStates + #[cfg(feature = "strict_json_fields")] + pub task: Option, // TODO: Implement bindStates +} + +#[derive(Clone, Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct StateMachineNodeReferenced { + pub reference_uuid: i32, + #[serde(flatten)] + pub common: StateMachineNodeCommon, +} + +#[derive(Clone, Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct StateMachineNodeOverrideCommon { + pub override_common_uuid: i32, + #[serde(flatten)] + pub common: StateMachineNodeCommon, +} + +#[derive(Clone, Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct StateMachineNodeCustom { + #[serde(flatten)] + pub common: StateMachineNodeCommon, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(untagged)] +pub enum StateMachineNode { + Reference(StateMachineNodeReferenced), + Override(StateMachineNodeOverrideCommon), + Custom(StateMachineNodeCustom), +} + +#[derive(Clone, Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct StateMachineJson { + pub version: u32, + pub state_machines: Vec, + pub nodes: Vec, } \ No newline at end of file diff --git a/wicked-waifus-data/src/monster_detection.rs b/wicked-waifus-data/src/monster_detection.rs new file mode 100644 index 0000000..fbd2848 --- /dev/null +++ b/wicked-waifus-data/src/monster_detection.rs @@ -0,0 +1,31 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MonsterDetectionData { + pub id: i32, + pub blueprint_type: String, + pub mark_id: i32, + #[cfg(feature = "strict_json_fields")] + pub name: String, + pub show_reward: i32, + pub entity_config_id: i32, + pub danger_type: i32, + pub type_description2: i32, + #[cfg(feature = "strict_json_fields")] + pub attributes_description_lock: String, + #[cfg(feature = "strict_json_fields")] + pub attributes_description_unlock: String, + #[cfg(feature = "strict_json_fields")] + pub big_icon: String, + #[cfg(feature = "strict_json_fields")] + pub icon: String, + #[cfg(feature = "strict_json_fields")] + pub temporary_icon_un_lock: String, + #[cfg(feature = "strict_json_fields")] + pub temporary_iconlock: String, + pub begin_time_stamp: i32, + pub lock_con: i32, + pub monster_info_id: i32, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/monster_property_growth.rs b/wicked-waifus-data/src/monster_property_growth.rs new file mode 100644 index 0000000..2dcdccf --- /dev/null +++ b/wicked-waifus-data/src/monster_property_growth.rs @@ -0,0 +1,19 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MonsterPropertyGrowthData { + pub id: i32, + pub curve_id: i32, + pub level: i32, + pub life_max_ratio: i32, + pub atk_ratio: i32, + pub def_ratio: i32, + pub hardness_max_ratio: i32, + pub hardness_ratio: i32, + pub hardness_recover_ratio: i32, + pub rage_max_ratio: i32, + pub rage_ratio: i32, + pub rage_recover_ratio: i32, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/motion.rs b/wicked-waifus-data/src/motion.rs new file mode 100644 index 0000000..ee9e774 --- /dev/null +++ b/wicked-waifus-data/src/motion.rs @@ -0,0 +1,23 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MotionData { + pub id: i32, + pub role_id: i32, + pub skin_id: i32, + pub r#type: i32, + pub sort: i32, + #[cfg(feature = "strict_json_fields")] + pub title: String, + #[cfg(feature = "strict_json_fields")] + pub content: String, + #[cfg(feature = "strict_json_fields")] + pub motion_img: String, + #[cfg(feature = "strict_json_fields")] + pub ani_blueprint: String, + #[cfg(feature = "strict_json_fields")] + pub ani_montage: String, + pub cond_group_id: i32, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/node_data/mod.rs b/wicked-waifus-data/src/node_data/mod.rs new file mode 100644 index 0000000..d93e15c --- /dev/null +++ b/wicked-waifus-data/src/node_data/mod.rs @@ -0,0 +1,265 @@ +use serde::Deserialize; + +use crate::pb_components::action::Action; +use crate::pb_components::common::Location; +use crate::pb_components::condition::{Condition, Conditions}; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TrackTypeLocations { + pub locations: Vec, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TrackTypeEntities { + pub entity_ids: Vec, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TrackTypeCaptureVisions { + pub vision_drop_entities: Vec, +} + +#[derive(Deserialize, Debug)] +#[serde(tag = "Type")] +pub enum TrackType { + Locations(TrackTypeLocations), + Entities(TrackTypeEntities), + CaptureVisions(TrackTypeCaptureVisions), +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TrackTarget { + pub track_type: TrackType, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailCommon { + pub id: i32, + // In ps we don't care about description + #[cfg(feature = "strict_json_fields")] + pub desc: String, + // ParentNodeId is not defined for child items. i.e.: QuestSucceed/ConditionSelector sub items + pub parent_node_id: Option, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct PosRollbackCfg { + pub range_entity_id: i64, + pub position_entity_id: i64, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct SaveConfig { + pub disable_rollback_while_reconnect: Option, + pub enable_rollback_while_switch_online_mode: Option, + pub enter_actions: Option>, + pub pos_rollback_cfg: Option, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailSequence { + #[serde(flatten)] + pub common: NodeDataDetailCommon, + pub children: Option>, + #[cfg(feature = "strict_json_fields")] + pub save_config: Option, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "UIConfig")] + pub ui_config: Option, + #[cfg(feature = "strict_json_fields")] + pub information_view: Option, + #[cfg(feature = "strict_json_fields")] + pub statistics: Option, + #[cfg(feature = "strict_json_fields")] + pub enable_system: Option, + #[cfg(feature = "strict_json_fields")] + pub special_game_play_config: Option, + #[cfg(feature = "strict_json_fields")] + pub reward_config: Option, + #[cfg(feature = "strict_json_fields")] + pub fix_processor: Option, + #[cfg(feature = "strict_json_fields")] + pub budget_camera_type: Option, + pub disable_online: Option, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailChildQuest { + #[serde(flatten)] + pub common: NodeDataDetailCommon, + pub condition: Option, + // In ps we don't care about tid tip + #[cfg(feature = "strict_json_fields")] + pub tid_tip: Option, + pub track_target: Option, + pub enter_actions: Option>, + pub finish_actions: Option>, + #[cfg(feature = "strict_json_fields")] + pub fix_processor: Option, + pub reward_id: Option, + // In ps we don't care about this + #[cfg(feature = "strict_json_fields")] + pub reward_get_ui_type: Option, + // In ps we don't care about this + #[cfg(feature = "strict_json_fields")] + pub show_tip_before_enter_actions: Option, + // In ps we don't care about this + #[cfg(feature = "strict_json_fields")] + pub hide_ui: Option, + // In ps we don't care about this + #[cfg(feature = "strict_json_fields")] + pub hide_tip: Option, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailSelect { + #[serde(flatten)] + pub common: NodeDataDetailCommon, + pub children: Option>, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailParallelSelect { + #[serde(flatten)] + pub common: NodeDataDetailCommon, + pub count: i32, + pub children: Option>, + #[cfg(feature = "strict_json_fields")] + pub save_config: Option, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "UIConfig")] + pub ui_config: Option, + #[cfg(feature = "strict_json_fields")] + pub statistics: Option, + #[cfg(feature = "strict_json_fields")] + pub occupation_config: Option, + #[cfg(feature = "strict_json_fields")] + pub start_wave: Option, + #[cfg(feature = "strict_json_fields")] + pub composite_track_view_mode: Option, + #[cfg(feature = "strict_json_fields")] + pub enable_system: Option, + #[cfg(feature = "strict_json_fields")] + pub information_view: Option, + pub disable_online: Option, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ConditionSelectorSlot { + pub condition: Conditions, + pub node: Option, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailConditionSelector { + #[serde(flatten)] + pub common: NodeDataDetailCommon, + pub slots: Vec, + #[cfg(feature = "strict_json_fields")] + pub save_config: Option, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "UIConfig")] + pub ui_config: Option, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailRepeater { + #[serde(flatten)] + pub common: NodeDataDetailCommon, + pub max_repeat_times: Option, + pub exit_condition: Option, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailCondition { + #[serde(flatten)] + pub common: NodeDataDetailCommon, + pub condition: Conditions, + pub wait_until_true: Option, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailAction { + #[serde(flatten)] + pub common: NodeDataDetailCommon, + pub actions: Vec, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailQuestSucceed { + #[serde(flatten)] + pub common: NodeDataDetailCommon, + pub finish_actions: Option>, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailQuestFailed { + #[serde(flatten)] + pub common: NodeDataDetailCommon, + #[cfg(feature = "strict_json_fields")] + pub failed_condition: Option, + pub finish_actions: Option>, + pub auto_failed: Option, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailAlways { + #[serde(flatten)] + pub common: NodeDataDetailCommon, + pub child: Option>, +} + +#[derive(Debug, Deserialize)] +#[serde(tag = "Type")] +pub enum NodeDataDetail { + Sequence(NodeDataDetailSequence), + ChildQuest(NodeDataDetailChildQuest), + Select(NodeDataDetailSelect), + ParallelSelect(NodeDataDetailParallelSelect), + ConditionSelector(NodeDataDetailConditionSelector), + Repeater(NodeDataDetailRepeater), + Condition(NodeDataDetailCondition), + Action(NodeDataDetailAction), + QuestSucceed(NodeDataDetailQuestSucceed), + QuestFailed(NodeDataDetailQuestFailed), + AlwaysFalse(NodeDataDetailAlways), + AlwaysTrue(NodeDataDetailAlways), +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/action.rs b/wicked-waifus-data/src/pb_components/action.rs new file mode 100644 index 0000000..79d3e93 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/action.rs @@ -0,0 +1,2304 @@ +use serde::Deserialize; + +use crate::pb_components::common::Point; +use crate::pb_components::flow::Flow; +use crate::pb_components::teleport::TeleportPosition; +use crate::pb_components::timer::TimerType; +use crate::pb_components::var::{OpType, Var}; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NotifyMonsterPlayStandbyTags { + pub standby_tags: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +pub enum SetType { + Add, + Remove, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BattleTag { + pub entity_id: i64, + pub set_type: SetType, + pub gameplay_tag: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetBattleTag { + pub set_tags: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NotifyGatherToEntity { + pub entity_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum PerceptionBehaviorOption { + NotifyGatherToEntity(NotifyGatherToEntity), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NotifyMonsterPerception { + pub perception_behavior_option: PerceptionBehaviorOption, + pub entity_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum StateOption { + NotifyMonsterPlayStandbyTags(NotifyMonsterPlayStandbyTags), + SetBattleTag(SetBattleTag), + NotifyMonsterPerception(NotifyMonsterPerception), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetBattleStateParams { + pub state_option: StateOption, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BattleTags { + pub entity_id: i64, + pub tag_config_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetBattleTags { + pub configs: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetMonsterMoveTarget { + pub target_entity_id: i64, + pub monster_entity_ids: Vec, + pub move_event: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum BattleOption { + SetBattleTags(SetBattleTags), + SetMonsterMoveTarget(SetMonsterMoveTarget), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ExecBattleAction { + pub battle_option: BattleOption, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct WaitBattleCondition { + // TODO: Implement this one + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ActionFields { + pub params: T, + pub action_guid: Option, + pub action_id: Option, + pub r#async: Option, + pub disabled: Option, + pub finish_send_self_event: Option, // TODO: Enum?? +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CollectParams { + pub target_entity: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct LeisureInteractOptionBounce { + pub height: i64, + pub time: f32, + pub motion_curve: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct LeisureInteractOptionCatapultParams { + pub p1: Point, + pub p2: Point, + pub time: Option, + pub gravity: Option, + pub motion_curve: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct LeisureInteractOptionCatapult { + pub param: LeisureInteractOptionCatapultParams, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct LeisureInteractOptionHookLock { + pub entity_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct LeisureInteractOptionManipulate { + pub target_entity_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum LeisureInteractOption { + SitDown, + SitOnGround, + StandControl, + StandControl2, + Bounce(LeisureInteractOptionBounce), + Soar, + Catapult(LeisureInteractOptionCatapult), + SuperCatapult(LeisureInteractOptionCatapult), + HookLock(LeisureInteractOptionHookLock), + Manipulate(LeisureInteractOptionManipulate), + Glide, + GetUp, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct LeisureInteract { + pub option: LeisureInteractOption, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct UnlockTeleportTrigger { + pub teleport_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnableTemporaryTeleport { + pub enable: bool, + pub range_entity: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct OpenSystemBoard { + pub system_type: String, + pub board_id: i32, + pub gramophone_id: Option, + pub action_montage: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct OpenSystemFunction { + pub function_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ChangeSelfEntityState { + pub entity_state: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlayerOperationRestrictionEnableAll {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlayerOperationRestrictionDisableAll { + pub display_mode: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DisableExploreSkill { + pub place_temporary_teleport: Option, + pub explore_skill_list: Option>, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SkillOptionDisableSection { + pub display_mode: String, + pub disable_explore_skill: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SkillOptionDisable { + pub display_mode: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum SkillOption { + DisableSection(SkillOptionDisableSection), + Disable(SkillOptionDisable), + Enable, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MoveOptionDisable { + pub forward: bool, + pub back: bool, + pub left: bool, + pub right: bool, + pub force_walk: Option, + pub forbid_sprint: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum MoveOption { + Disable(MoveOptionDisable), + Enable, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum CameraOption { + Disable, + Enable, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnableSectionalUi { + #[serde(default)] + pub show_mini_map: bool, + #[serde(default)] + pub show_quest_track: bool, + #[serde(default)] + pub show_esc: bool, + #[serde(default)] + pub show_system: bool, + #[serde(default)] + pub show_screen_effect: bool, + #[serde(default)] + pub show_other: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum UiOption { + Disable, + Enable, + EnableSectionalUi(EnableSectionalUi), +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum SceneInteractionOption { + Disable, + Enable, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlayerOperationRestrictionDisableModule { + pub skill_option: Option, + pub move_option: Option, + pub camera_option: Option, + pub ui_option: Option, + pub scene_interaction_option: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum SetPlayerOperationRestriction { + EnableAll(PlayerOperationRestrictionEnableAll), + DisableAll(PlayerOperationRestrictionDisableAll), + DisableModule(PlayerOperationRestrictionDisableModule), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Wait { + pub time: f32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ChangeEntityStateDirectly { + pub entity_id: i64, + pub state: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ChangeEntityStateBatchDirectly { + pub entity_id: i64, + pub entity_ids: Vec, + pub state: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ChangeEntityStateLoop { + pub entity_id: i64, + pub circulation: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum ChangeEntityState { + Directly(ChangeEntityStateDirectly), + BatchDirectly(ChangeEntityStateBatchDirectly), + Loop(ChangeEntityStateLoop), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Log { + pub level: String, + pub content: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnableNearbyTracking { + pub is_enable: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CenterTextFlow { + pub flow_list_name: String, + pub flow_id: i32, + pub state_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TransitionOptionCenterText { + pub center_text_flow: CenterTextFlow, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TransitionOptionFadeInScreen {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TransitionOptionSeamless { + pub effect_da_path: String, + pub least_time: i32, + pub effect_expand_time: i32, + pub effect_collapse_time: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TransitionOptionPlayMp4 { + #[serde(rename = "Mp4Path")] + pub mp4_path: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum TransitionOption { // TODO: Extract + CenterText(TransitionOptionCenterText), + FadeInScreen(TransitionOptionFadeInScreen), + Seamless(TransitionOptionSeamless), + PlayMp4(TransitionOptionPlayMp4), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TeleportDungeon { + pub is_regroup: bool, + pub dungeon_id: i32, + pub location_entity_id: Option, + pub transition_option: Option, + pub is_need_secondary_confirmation: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DestroySelf {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CameraLookAt { + pub pos: Point, + pub fade_in_time: f32, + pub stay_time: f32, + pub fade_out_time: f32, + pub lock_camera: Option, + pub cancel_buffer: Option, + pub cancel_blend_out: Option, + pub ban_input: Option, + pub camera_pos: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnterOrbitalCamera { + // TODO: Implement this one + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ExitOrbitalCamera { + // TODO: Implement this one + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SendAiEvent { + pub event_type: String, // TODO: Check if enum +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetInteractionLockState { + pub is_lock: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AwakeEntity { + pub entity_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ChangeLiftTarget { + pub is_self: bool, + pub location: i32, + pub entity_id: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CalculateVar { + pub var1: Var, + pub var2: Var, + pub op: OpType, + pub result: Var, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AddBuffToPlayer { + pub buff_ids: Vec, + pub persist_on_destroy_buff_ids: Option>, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RemoveBuffFromPlayer { + pub buff_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SingleEntityBuffs { + pub entity_id: i64, + pub buff_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MultipleEntitiesBuff { + pub entity_ids: Vec, + pub buff_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SelfEntityBuff { + pub buff_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum AddBuffToEntity { + SingleEntityBuffs(SingleEntityBuffs), + MultipleEntitiesBuff(MultipleEntitiesBuff), + SelfEntityBuff(SelfEntityBuff), +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum RemoveBuffFromEntity { + SingleEntityBuffs(SingleEntityBuffs), + MultipleEntitiesBuff(MultipleEntitiesBuff), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Prompt { + pub general_text_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetEntityVisible { + pub visible: bool, + pub entity_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DestroyEntity { + pub entity_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SimpleGuide { + pub guide_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum GuideTypes { + BeginnerGuide(SimpleGuide), + AttackGuide(SimpleGuide), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CameraShakeConstant {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CameraShakeLinearOverRange { + pub center_entity_id: i64, + pub min_range: i32, + pub max_range: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum CameraShakeConfig { + Constant(CameraShakeConstant), + LinearOverRange(CameraShakeLinearOverRange), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TriggerCameraShake { + pub camera_shake_bp: String, + pub camera_shake_config: CameraShakeConfig, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetVar { + pub var_left: Var, + pub var_right: Var, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct VehicleEnterTypePlayer { + pub target_vehicle: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct VehicleEnterTypeNpc { + pub target_npc: i64, + pub target_vehicle: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum VehicleEnterType { + Player(VehicleEnterTypePlayer), + Npc(VehicleEnterTypeNpc), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct VehicleEnter { + pub entering_target: VehicleEnterType, + pub seat: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct VehicleExitPlayer { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct LockEntity { + pub entity_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct UnlockEntity { + pub entity_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TipOption { + pub r#type: i32, + pub tid_text: Option, + pub tid_main_text: Option, + pub tid_sub_text: Option, + pub main_text: Option, + pub sub_text: Option, + pub warning_text: Option, + pub id: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CommonTip { + pub tip_option: TipOption, + pub duration: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TipOption2 { + pub r#type: i32, + pub count_down_num: i32, + pub tid_count_down_txt: String, + pub is_block_player: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CommonTip2 { + pub tip_option: TipOption2, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EventConfigGlobal { + pub ak_event: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EventConfigTarget { + pub ak_event: String, + pub entity_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum EventConfig { + Global(EventConfigGlobal), + Target(EventConfigTarget), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PostAkEvent { + pub event_config: EventConfig, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct VehicleEnterNpc { + pub target: i32, + pub seat: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ExitTypeTeleport { + pub pos: Point, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum ExitType { + Teleport(ExitTypeTeleport) +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct VehicleExitNpc { + pub target_npc: i32, + pub exit_type: ExitType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlayerLookAt { + pub pos: Point, + pub camera_move: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlayBubble { + pub entity_id: i64, + pub flow: Flow, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AddPlayBubble { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ClearPlayBubble { + pub entity_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnableLevelPlayConfig { + pub level_play_id: i64, + pub enable: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnableLevelPlay { + pub configs: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ClaimLevelPlayReward {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ExecRiskHarvestEffect { + pub id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SettlementDungeon {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ExitDungeon { + pub is_need_secondary_confirmation: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FinishDungeon { + pub is_success: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DungeonEventConfig { + pub is_success: bool, +} + +#[derive(Deserialize, Debug, Clone)] +pub enum TimeStampType { + DungeonBegin, + DungeonFinish, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RecordTimeStamp { + pub time_stamp_type: TimeStampType, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum RecordDungeonEventConfig { + RecordTimeStamp(RecordTimeStamp) +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RecordDungeonEvent { + pub event_config: RecordDungeonEventConfig, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RecoverDurability { + pub entity_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Ease { + pub r#type: i32, + pub duration: f32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FadeInScreen { + pub ease: Option, + pub screen_type: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FadeOutScreen { + pub ease: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ChangeNpcPerformState { + pub entity_id: i64, + pub state: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EntityTurnToTarget { + pub r#type: i32, // Type 2 has entity id, Type 3 has pos, type 4 has nothing + pub entity_id: Option, + pub pos: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EntityTurnTo { + pub entity_id: i64, + pub target: EntityTurnToTarget, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EntityLookAt { + pub entity_id: i64, + pub pos: Point, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ToggleMapMarkStateShow { + pub mark_id: i64, + pub is_focus_on_first_show: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ToggleMapMarkStateHide { + pub mark_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum ToggleMapMarkState { + Show(ToggleMapMarkStateShow), + Hide(ToggleMapMarkStateHide), + Disable(ToggleMapMarkStateHide), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RandomVar { + pub left_var: Var, + pub right_var: Var, + pub result: Var, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ModifySceneItemAttributeTagTarget { + pub is_add_tag: bool, + pub entity_ids: Vec, + pub performance_tag: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ModifySceneItemAttributeTagSelf { + pub is_add_tag: bool, + pub performance_tag: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum ModifySceneItemAttributeTag { + Target(ModifySceneItemAttributeTagTarget), + #[serde(rename = "Self")] + SelfType(ModifySceneItemAttributeTagSelf), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct VehicleWaterfallClimbing { + pub spline_entity_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AppointedVehicleType { + pub vehicle_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum VehicleType { + FishingBoat, + Gongduola, + Appointed(AppointedVehicleType), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct VehicleTeleport { + pub target_vehicle: VehicleType, + pub pos: Point, + pub rot: Option, + pub appointed_dock: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RogueGotoNextFloor {} + +#[derive(Deserialize, Debug, Clone)] +pub enum RogueRewardReceiveType { + ReceiveByEnergy +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RogueReceiveReward { + pub rogue_reward_receive_type: Option, +} + +#[derive(Deserialize, Debug, Clone)] +pub enum RogueSelectRoomConfigType { + Role +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RogueSelectRoomConfig { + pub r#type: RogueSelectRoomConfigType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RogueSelectRoom { + pub config: RogueSelectRoomConfig, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RogueActivatePortal {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MowingTowerGotoNextFloor {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SlashAndTowerGotoNextFloor {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ActionMontageNormal { + pub path: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "MontageType")] +pub enum ActionMontage { + Normal(ActionMontageNormal), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlayMontage { + pub entity_id: i64, + pub action_montage: ActionMontage, + pub duration: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SystemTypeConfirmBox { + pub id: i64, + pub return_var: Var, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SystemTypeFishingItemDelivery { + pub preset_id: i64, + pub return_var: Var, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SystemTypeSoaringChallenge { + pub score: Var, + pub rank_s: i32, + pub rank_a: i32, + pub rank_b: i32, + pub return_var: Var, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum SystemType { + ConfirmBox(SystemTypeConfirmBox), + FishingItemDelivery(SystemTypeFishingItemDelivery), + SoaringChallenge(SystemTypeSoaringChallenge), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct OpenSystemBoardWithReturn { + pub system_type: SystemType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SystemOptionAchievementSystem { + pub id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct UnlockCookBook { + pub cook_book_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GeographicalAtlas { + pub id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlotPhoto { + pub id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Noun { + pub id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum UnlockOption { + UnlockCookBook(UnlockCookBook), + GeographicalAtlas(GeographicalAtlas), + PlotPhoto(PlotPhoto), + Noun(Noun), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SystemOptionUnlockOption { + pub unlock_option: UnlockOption, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MemoirsSystem { + pub id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum SystemOption { + AchievementSystem(SystemOptionAchievementSystem), + CookSystem(SystemOptionUnlockOption), + AtlasSystem(SystemOptionUnlockOption), + MemoirsSystem(MemoirsSystem), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct UnlockSystemItem { + pub system_option: SystemOption, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SportsStateConfigSlide { + pub slide_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SportsStateConfigSki { + // TODO: Implement this one + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum SportsStateConfig { + Slide(SportsStateConfigSlide), + Ski(SportsStateConfigSki), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetSportsState { + pub config: SportsStateConfig, +} + +#[derive(Deserialize, Debug, Clone)] +pub enum Color { + Red, + Blue, + Yellow, + Green, + White, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ColorConfig { + pub color: Color, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GameplayConfigSignalDevice { + pub config: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GameplayConfigSignalBreak { + pub signal_break_id: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GameplayConfigRenjuChess { + pub chessboard: i64, + // TODO:Implement this + #[cfg(feature = "strict_json_fields")] + pub camera_config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ColorBoard { + pub config: Vec, + pub colors: Vec, + pub target_color: Color, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MaxStepRewardRule { + pub paint_count: i32, + pub add_step: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GameplayConfigLifePoint { + pub color_board: ColorBoard, + pub step_limit: i32, + pub tid_desc: String, + pub max_step_reward_rule: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GameplayConfigMorseCode { + pub morse_code_id: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GameplayConfigCipher { + pub cipher_id: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GameplayConfigBrokenRock { + pub id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum GameplayConfig { + SignalDevice(GameplayConfigSignalDevice), + SignalDevice2(GameplayConfigSignalDevice), + SignalBreak(GameplayConfigSignalBreak), + RenjuChess(GameplayConfigRenjuChess), + LifePoint(GameplayConfigLifePoint), + MorseCode(GameplayConfigMorseCode), + Cipher(GameplayConfigCipher), + BrokenRock(GameplayConfigBrokenRock), + FishingRoulette, + DaolingAuthentication, + SundialPuzzle, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct OpenSimpleGameplay { + pub gameplay_config: GameplayConfig, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlayEffectPos { + pub r#type: i32, // TODO: Enum?? Type 0 is offset, type 1 is entity id, type 2 is pos + pub offset: Option, + pub entity_id: Option, + pub pos: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlayEffect { + pub path: String, + pub pos2: PlayEffectPos, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RestorePlayerCameraAdjustment {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AdjustPlayerCamera { + // TODO:Implement this + #[cfg(feature = "strict_json_fields")] + pub option: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TeammateTeleportConfig { + pub r#type: i32, + pub time_out: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TelePortConfig { + pub r#type: i32, // TODO: Enum?? + pub target_pos: Option, + pub entity_ids: Option>, + pub transition_option: Option, + pub teammate_teleport_config: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetPlayerPos { + pub tele_port_config: TelePortConfig, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MoveTargetEntity { + pub entity_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum MoveTarget { + Entity(MoveTargetEntity), + Player, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MoveWithSpline { + pub move_target: MoveTarget, + pub spline_entity_id: i64, + pub is_look_dir: Option, + pub start_point_index: Option, + pub end_point_index: Option, + // TODO:Implement this + #[cfg(feature = "strict_json_fields")] + pub check_climb: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnableSplineMoveModel { + // TODO:Implement this + #[cfg(feature = "strict_json_fields")] + pub check_climb: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ToggleScanSplineEffect { + // TODO:Implement this + #[cfg(feature = "strict_json_fields")] + pub check_climb: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MoveSceneItem { + pub entity_id: i64, + // TODO:Implement this + #[cfg(feature = "strict_json_fields")] + pub move_config: serde_json::Value, + pub stop_before_move: Option, + pub bypass_client_response: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct StopSceneItemMove { + pub entity_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FireBullet { + // TODO:Implement this + #[cfg(feature = "strict_json_fields")] + pub r#type: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ClearFishingCabinInSaleItems {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AcceptFishingEntrust { + // TODO:Implement this + #[cfg(feature = "strict_json_fields")] + pub r#type: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DestroyFishingBoat { + // TODO:Implement this + #[cfg(feature = "strict_json_fields")] + pub r#type: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetJigsawItem { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetJigsawFoundation { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetTeleControl { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetEntityClientVisible { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ToggleHighlightExploreUi { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ExecAlertSystemAction { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AddFlowInteractOption { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RemoveFlowInteractOption { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnableHostility { + pub is_enable: bool, + pub entity_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ChangePhantomFormation { + pub formation_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RestorePhantomFormation { + pub retain_phantom: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ChangeTimerType { + pub r#type: OpType, + pub time: Option, + pub var_for_time: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ChangeTimer { + pub change_type: ChangeTimerType, + pub timer_type: TimerType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ToggleTimerPauseState { + pub is_pause: bool, + pub timer_type: TimerType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ChangeFightTeam {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AddTrialFollowShooter { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RemoveTrialFollowShooter { + pub id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AddTrialCharacter { + pub character_id: i64, + pub auto_change: Option, + pub character_group: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RemoveTrialCharacter { + pub character_id: i64, + pub character_group: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetAreaState { + pub area_id: i32, + pub state: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SwitchSubLevels { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ChangeTeamPosition { + pub position_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Item { + pub item_id: i64, + pub count: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GetItem { + pub items: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CreatePrefab { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DestroyPrefab { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlayDynamicSettlement { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct UsePhantomSkill { + pub skill_type: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct HideTargetRange { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ChangeOtherState { + pub entity_id: i64, + pub state: Flow, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetRegionConfigMpc { + pub region_mpc_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum SetRegionConfig { + Mpc(SetRegionConfigMpc), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetReviveRegion { + pub set_revive_type: SetType, + pub revive_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ExecResurrection { + pub revive_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ShowTargetRange { + pub delay_show: bool, + pub range_entities: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetTime { + pub hour: i32, + pub min: i32, + pub show_ui: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetTimeLockState { + pub lock_state: String, // TODO: Enum Lock Unlock +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnableSystem { + pub system_type: i32, + pub is_enable: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnableAoiNotify { + pub state: String, // TODO: Enum +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetForceLock { + pub entity_id: i64, + pub is_locked: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlayRegisteredMontage { + pub entity_id: i64, + pub montage_id: i64, + pub is_abp_montage: bool, + pub repeat_times: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AudioConfig { + pub group: String, + pub state: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetAudioState { + pub audio_config: AudioConfig, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct HideGroup { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ShowHidedGroup { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct HideSpecificEntities { + pub entity_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ShowSpecificEntities { + pub entity_ids: Vec, + pub delay_show: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RemovePreloadResource { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Preload { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnableAI { + pub entity_ids: Vec, + pub is_enable: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SwitchDataLayers { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DestroyQuest { + pub quest_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DestroyQuestItem { + pub item_id: i64, + pub count: i32, + pub is_all: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PromptQuestChapterUI { + pub chapter_state: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TakePlotPhoto {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetWuYinQuState { + pub wu_yin_qu_name: String, + pub state: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RunActions { + pub action_list: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +pub enum OccupationType { + Request, + Release, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ManualOccupations { + pub occupation_type: OccupationType, + pub occupations: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetWeather { + pub weather_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SendNpcMail { + pub mail_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnableFunction { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FocusOnMapMark { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CharacterLookAt { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AddGuestCharacter { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RemoveGuestCharacter { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TeleportToAndEnterVehicle { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetAreaTimeState { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ResetPlayerCameraFocus { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ResetLevelPlay { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct VehicleSprint { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct VehicleMoveWithPathLine { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Name")] +pub enum Action { + SetBattleState(ActionFields), + ExecBattleAction(ActionFields), + WaitBattleCondition(ActionFields), + PlayFlow(ActionFields), + Collect(ActionFields), + LeisureInteract(ActionFields), + UnlockTeleportTrigger(ActionFields), + EnableTemporaryTeleport(ActionFields), + OpenSystemBoard(ActionFields), + OpenSystemFunction(ActionFields), + ChangeSelfEntityState(ActionFields), + SetPlayerOperationRestriction(ActionFields), + Wait(ActionFields), + ChangeEntityState(ActionFields), + Log(ActionFields), + EnableNearbyTracking(ActionFields), + TeleportDungeon(ActionFields), + DestroySelf(ActionFields), + CameraLookAt(ActionFields), + EnterOrbitalCamera(ActionFields), + ExitOrbitalCamera(ActionFields), + SendAiEvent(ActionFields), + SetInteractionLockState(ActionFields), + AwakeEntity(ActionFields), + ChangeLiftTarget(ActionFields), + CalculateVar(ActionFields), + AddBuffToPlayer(ActionFields), + RemoveBuffFromPlayer(ActionFields), + AddBuffToEntity(ActionFields), + RemoveBuffFromEntity(ActionFields), + Prompt(ActionFields), + SetEntityVisible(ActionFields), + DestroyEntity(ActionFields), + GuideTrigger(ActionFields), + TriggerCameraShake(ActionFields), + SetVar(ActionFields), + VehicleEnter(ActionFields), + VehicleExitPlayer(ActionFields), + LockEntity(ActionFields), + UnlockEntity(ActionFields), + CommonTip(ActionFields), + CommonTip2(ActionFields), + PostAkEvent(ActionFields), + VehicleEnterNpc(ActionFields), + VehicleExitNpc(ActionFields), + PlayerLookAt(ActionFields), + PlayBubble(ActionFields), + AddPlayBubble(ActionFields), + ClearPlayBubble(ActionFields), + ExecRiskHarvestEffect(ActionFields), + EnableLevelPlay(ActionFields), + ClaimLevelPlayReward(ActionFields), + SettlementDungeon(ActionFields), + ExitDungeon(ActionFields), + FinishDungeon(ActionFields), + RecordDungeonEvent(ActionFields), + RecoverDurability(ActionFields), + FadeInScreen(ActionFields), + FadeOutScreen(ActionFields), + ChangeNpcPerformState(ActionFields), + EntityTurnTo(ActionFields), + EntityLookAt(ActionFields), + ToggleMapMarkState(ActionFields), + RandomVar(ActionFields), + ModifySceneItemAttributeTag(ActionFields), + VehicleWaterfallClimbing(ActionFields), + VehicleTeleport(ActionFields), + RogueGotoNextFloor(ActionFields), + RogueReceiveReward(ActionFields), + RogueSelectRoom(ActionFields), + RogueActivatePortal(ActionFields), + MowingTowerGotoNextFloor(ActionFields), + SlashAndTowerGotoNextFloor(ActionFields), + PlayMontage(ActionFields), + OpenSystemBoardWithReturn(ActionFields), + UnlockSystemItem(ActionFields), + SetSportsState(ActionFields), + OpenSimpleGameplay(ActionFields), + PlayEffect(ActionFields), + RestorePlayerCameraAdjustment(ActionFields), + AdjustPlayerCamera(ActionFields), + SetPlayerPos(ActionFields), + MoveWithSpline(ActionFields), + EnableSplineMoveModel(ActionFields), + ToggleScanSplineEffect(ActionFields), + MoveSceneItem(ActionFields), + StopSceneItemMove(ActionFields), + FireBullet(ActionFields), + ClearFishingCabinInSaleItems(ActionFields), + AcceptFishingEntrust(ActionFields), + DestroyFishingBoat(ActionFields), + SetJigsawItem(ActionFields), + SetJigsawFoundation(ActionFields), + SetTeleControl(ActionFields), + SetEntityClientVisible(ActionFields), + ToggleHighlightExploreUi(ActionFields), + ExecAlertSystemAction(ActionFields), + AddFlowInteractOption(ActionFields), + RemoveFlowInteractOption(ActionFields), + EnableHostility(ActionFields), + ChangePhantomFormation(ActionFields), + RestorePhantomFormation(ActionFields), + ChangeTimer(ActionFields), + ToggleTimerPauseState(ActionFields), + ChangeFightTeam(ActionFields), + AddTrialFollowShooter(ActionFields), + RemoveTrialFollowShooter(ActionFields), + AddTrialCharacter(ActionFields), + RemoveTrialCharacter(ActionFields), + SetAreaState(ActionFields), + SwitchSubLevels(ActionFields), + ChangeTeamPosition(ActionFields), + GetItem(ActionFields), + CreatePrefab(ActionFields), + DestroyPrefab(ActionFields), + CompleteGuide(ActionFields), + PlayDynamicSettlement(ActionFields), + UsePhantomSkill(ActionFields), + HideTargetRange(ActionFields), + ChangeOtherState(ActionFields), + SetRegionConfig(ActionFields), + SetReviveRegion(ActionFields), + ExecResurrection(ActionFields), + ShowTargetRange(ActionFields), + SetTime(ActionFields), + SetTimeLockState(ActionFields), + EnableSystem(ActionFields), + EnableAoiNotify(ActionFields), + SetForceLock(ActionFields), + PlayRegisteredMontage(ActionFields), + SetAudioState(ActionFields), + HideGroup(ActionFields), + ShowHidedGroup(ActionFields), + HideSpecificEntities(ActionFields), + ShowSpecificEntities(ActionFields), + RemovePreloadResource(ActionFields), + Preload(ActionFields), + EnableAI(ActionFields), + SwitchDataLayers(ActionFields), + DestroyQuest(ActionFields), + DestroyQuestItem(ActionFields), + PromptQuestChapterUI(ActionFields), + TakePlotPhoto(ActionFields), + SetWuYinQuState(ActionFields), + RunActions(ActionFields), + ManualOccupations(ActionFields), + SetWeather(ActionFields), + SendNpcMail(ActionFields), + EnableFunction(ActionFields), + FocusOnMapMark(ActionFields), + CharacterLookAt(ActionFields), + AddGuestCharacter(ActionFields), + RemoveGuestCharacter(ActionFields), + TeleportToAndEnterVehicle(ActionFields), + SetAreaTimeState(ActionFields), + ResetPlayerCameraFocus(ActionFields), + ResetLevelPlay(ActionFields), + VehicleSprint(ActionFields), + VehicleMoveWithPathLine(ActionFields), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Actions { + pub point: i32, + pub actions: Vec, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/ai.rs b/wicked-waifus-data/src/pb_components/ai.rs new file mode 100644 index 0000000..b14f057 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/ai.rs @@ -0,0 +1,60 @@ +use serde::Deserialize; +use crate::pb_components::action::Actions; +use crate::pb_components::condition::Conditions; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct InitState { + pub wander: Option, + pub standby_tags: Option>, + pub r#type: Option, + pub birth_tag: Option, + pub conditions: Option>, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Patrol { + pub is_circle: Option, + pub spline_entity_id: Option, + pub actions: Option> +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EntityPos { + pub key: String, + pub entity_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EntityId { + pub key: String, + pub entity_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum BlackBoard { + EntityPos(EntityPos), + EntityId(EntityId), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AiComponent { + pub disabled: Option, + pub ai_id: Option, + pub ai_team_level_id: Option, + pub center_point: Option, + pub init_black_board: Option>, + pub init_state: Option, + pub patrol: Option, + pub weapon_id: Option, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/attribute.rs b/wicked-waifus-data/src/pb_components/attribute.rs new file mode 100644 index 0000000..005eba3 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/attribute.rs @@ -0,0 +1,41 @@ +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct WorldLevelBonusType { + pub r#type: Option, + pub world_level_bonus_id: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FightMusic { + pub fight_music: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FightMusics { + pub r#type: Option, + pub element: Option>, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AttributeComponent { + pub disabled: Option, + pub append_buff_ids: Option>, + pub property_id: Option, + pub level: Option, + pub world_level_bonus_type: Option, + pub rage_mode_id: Option, + pub hardness_mode_id: Option, + pub monster_prop_extra_rate_id: Option, + pub world_level_bonus_id: Option, + pub fight_music: Option, + pub fight_musics: Option, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/base_info.rs b/wicked-waifus-data/src/pb_components/base_info.rs new file mode 100644 index 0000000..04f8dda --- /dev/null +++ b/wicked-waifus-data/src/pb_components/base_info.rs @@ -0,0 +1,90 @@ +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Category { + pub main_type: Option, + pub monster_match_type: Option, + pub trace_match_type: Option, + pub entity_plot_binding_type: Option, + pub exploratory_degree: Option, + pub hide_in_flow_type: Option, + pub destructible_type: Option, + pub vehicle_type: Option, + pub npc_type: Option, + pub animal_type: Option, // non use except of null so type not exact + pub collect_type: Option, + pub pull_statue_match_type: Option, + pub control_match_type: Option, + pub item_foundation: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TraceEffect { + pub target: Option, + pub effect: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ScanFunction { + pub scan_id: Option, + pub is_concealed: Option, + pub trace_effect: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct HeadStateViewConfig { + pub head_state_view_type: Option, + #[serde(rename = "ZOffset")] + pub z_offset: Option, + pub forward_offset: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CustomAoiZRadius { + pub up: Option, + pub down: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BaseInfoComponent { + pub disabled: Option, + pub tid_name: Option, + pub category: Option, + pub camp: Option, + pub head_info: Option, + pub pack_id: Option, + pub data_layers: Option>, + pub is_show_name_on_head: Option, + pub head_state_view_config: Option, + #[cfg(feature = "strict_json_fields")] + pub fix_processor: Option, // TODO: Implement this shit + pub online_interact_type: Option, + pub scan_function: Option, + pub aoi_layer: Option, + pub entity_property_id: Option, + pub focus_priority: Option, + #[serde(rename = "AoiZRadius")] + pub aoi_zradius: Option, + #[serde(rename = "CustomAoiZRadius")] + pub custom_aoi_zradius: Option, + pub child_entity_ids: Option>, + pub not_allow_hided_by_target_range: Option, + pub occupation: Option, + pub is_online_standalone: Option, + pub entity_update_strategy: Option, + pub specified_online_standalone_parent_uids: Option>, + pub lower_npc_density: Option, + pub map_icon: Option, +} diff --git a/wicked-waifus-data/src/pb_components/common.rs b/wicked-waifus-data/src/pb_components/common.rs new file mode 100644 index 0000000..e999e83 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/common.rs @@ -0,0 +1,19 @@ +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Point { + pub x: Option, + pub y: Option, + pub z: Option, +} + +#[derive(Debug, Deserialize, Clone)] +#[serde(rename_all = "PascalCase")] +pub struct Location { + pub x: Option, + pub y: Option, + pub z: Option, + pub a: Option, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/condition.rs b/wicked-waifus-data/src/pb_components/condition.rs new file mode 100644 index 0000000..d3bc171 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/condition.rs @@ -0,0 +1,1182 @@ +use serde::Deserialize; + +use crate::pb_components::common::{Location, Point}; +use crate::pb_components::flow::Flow; +use crate::pb_components::interact::MatchRoleOption; +use crate::pb_components::timer::TimerType; +use crate::pb_components::var::{CompareType, Var}; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareTimePeriod { + pub compare: CompareType, + pub time_period: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckChildQuestFinished { + pub quest_id: i64, + pub child_quest_id: i64, + pub compare: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareEntityState { + pub entity_id: i64, + pub compare: CompareType, + pub state: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckEntityStateSingle { + pub entity_id: i64, + pub state: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckEntityState { + pub conditions: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareVarSingle { + pub var1: Var, + pub compare: CompareType, + pub var2: Var, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareVarMultiple { + pub conditions: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum CompareVar { + CompareVarSingle(CompareVarSingle), + CompareVarMultiple(CompareVarMultiple), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareWeather { + pub compare: CompareType, + pub weather_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareQuestState { + pub quest_id: i64, + pub compare: CompareType, + pub state: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareEntitySelfState { + pub compare: CompareType, + pub state: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckPlayerStateRestriction { + pub restriction_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct HourMinutes { + pub hour: i32, + pub min: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct HourToHour { + pub compare: CompareType, + pub start: HourMinutes, + pub end: HourMinutes, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ComparePlayerMotionState { + pub compare: CompareType, + pub motion_state: String, // enum?? +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ComparePlayerMotionState2 { + pub compare: CompareType, + pub motion_state: String, // enum?? +} + +#[derive(Deserialize, Debug, Clone)] +pub enum CheckAiStateType { + AnimalSitDown, + AnimalStandUp, + AnimalRandomAction, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckAiState { + pub compare: CompareType, + pub state_type: CheckAiStateType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PreLevelPlay { + pub pre_level_play: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckLevelPlay { + pub level_play_ids: Vec, + pub complete_number: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckLevelPlayState { + pub level_id: i32, + pub compare: CompareType, + pub state: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckLevelPlayCompleteNumber { + pub level_id: i32, + pub compare: CompareType, + pub number: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareLevelPlayRewardState { + pub compare: CompareType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Item { + pub item_id: i32, + pub count: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckItems { + pub compare: CompareType, + pub items: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct HandInItems { + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GetItem { + pub items: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct OnlinePlayerConditionTargetOptionTypeParticipator { + pub any_player: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct OnlinePlayerConditionTargetOptionTypeHost {} + + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum OnlinePlayerConditionTargetOption { + Participator(OnlinePlayerConditionTargetOptionTypeParticipator), + Host(OnlinePlayerConditionTargetOptionTypeHost), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct HasBuff { + pub buff_id: i64, + pub compare: CompareType, + pub online_player_condition_target_option: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareLift { + pub is_self: bool, + pub location: i32, + pub compare: CompareType, + pub entity_id: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckJigsawItemMove { + pub item_entity_id: i64, + pub compare: CompareType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlaceIndex { + pub row_index: i32, + pub column_index: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckJigsawItemPlaceIndex { + pub item_entity_id: i64, + pub foundation_entity_id: i64, + pub place_index: PlaceIndex, + pub compare: CompareType, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum JigsawCondition { + CheckJigsawItemMove(CheckJigsawItemMove), + CheckJigsawItemPlaceIndex(CheckJigsawItemPlaceIndex), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckJigsawInfo { + pub jigsaw_condition: JigsawCondition, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckInCombat { + pub in_combat: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DetectCombatState { + pub entity_id: i64, + pub state: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DetectCombatState2 { + pub count: i32, + pub conditions: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct UsingVehicle { + pub check_is_being_used: bool, + pub seat: i32, + pub target_vehicle: Option, +} + +#[derive(Deserialize, Debug, Clone)] +pub enum VehicleType { + FishingBoat, + Gongduola, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PlayerInVehicle { + pub check_type: bool, + pub online_player_condition_target_option: Option, + pub vehicle_type: Option, // TODO: Review this +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum CheckVehicleConditionType { + UsingVehicle(UsingVehicle), + PlayerInVehicle(PlayerInVehicle), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckVehicleCondition { + pub condition: CheckVehicleConditionType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckSystemFunction { + pub system_id: i32, + pub compare: CompareType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CollectionShopFull { + pub shop_type: String, // TODO: Enum +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TrackMoonBuilding { + pub building_id: i32, + pub is_built: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TrackMoonPopularity { + pub compare: CompareType, + pub popularity: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum CheckSystemStateType { + CollectionShopFull(CollectionShopFull), + TrackMoonBuilding(TrackMoonBuilding), + TrackMoonPopularity(TrackMoonPopularity), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckSystemState { + pub config: CheckSystemStateType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckCollectAnimalParts { + pub check_type: i32, + pub slots: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckCurrentRole { + pub compare: CompareType, + pub role_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareExploreLevel { + pub compare: CompareType, + pub level: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ExploreLevel { + pub explore_level: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareDungeonId { + pub compare: CompareType, + pub dungeon_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DungeonId { + pub dungeon_id: i32, + pub count: Option, + pub is_exit_dungeon: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DungeonSubType { + pub dungeon_sub_type: i32, + pub count: Option, + pub is_exit_dungeon: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum DungeonType { + DungeonId(DungeonId), + DungeonSubType(DungeonSubType), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct EnterDungeon { + pub enter_type: DungeonType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct LeaveDungeon {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FinishDungeon { + pub condition: DungeonType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareCalabashLevel { + pub compare: CompareType, + pub calabash_level: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckCalabashDevelopReward { + pub monster_id: i64, + pub develop: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckLordGymFinish { + pub lord_gym_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GroupConditionElement { + pub entity_id: i64, + pub state: String, + pub is_locked: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GroupCondition { + pub conditions: Vec, + pub count: i32, + pub compare: CompareType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareEntityGroupState { + pub group_condition: GroupCondition, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckEntityLocked { + pub entities: Vec, + pub is_locked: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckRogueAbilitySelect { + pub board_id: i32, + pub is_received: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareFishingBoatState { + pub is_stop: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompleteCertainFishingEntrust { + pub id: i32, + pub count: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareFishingPrestigeLevel { + pub compare: CompareType, + pub prestige_level: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckCertainFishingItemCount { + pub id: i32, + pub compare: CompareType, + pub count: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareFishingTechLevel { + pub tech_id: i32, + pub compare: CompareType, + pub tech_level: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ListenEntitySelfEvent { + pub event_key: String, // TODO: enum?? +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckHookLockPoint { + pub entity_ids: Option>, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckEntitesExist { + pub entity_ids: Vec, + pub is_exist: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckEntityHasSceneItemAttributeTag { + pub check_type: i32, + pub entity_id: i64, + pub tags: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +pub enum AttributeOptionType { + Health, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AttributeOption { + pub r#type: AttributeOptionType, + pub min: i32, + pub max: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BattleConditionAttributePlayer { + pub option: AttributeOption, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BattleConditionAttributeMonster { + pub option: AttributeOption, + pub entity_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BattleConditionBattleTag { + pub entity_id: i64, + pub tag_config_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum BattleCondition { + Player(BattleConditionAttributePlayer), + Monster(BattleConditionAttributeMonster), + BattleTag(BattleConditionBattleTag), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckTargetBattleAttribute { + pub count: i32, + pub option: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckAlertAreaEnabled { + pub area_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareAlertValue { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct ReachArea { + pub pos: Point, + pub range: i32, + pub range_entity_id: Option, + pub entity_id: Option, + pub range_entities: Option>, + pub pre_conditions: Option, + pub match_role_option: Option>, + pub effect_path: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct Kill { + pub exist_targets: Vec, + pub targets_to_awake: Vec, + pub prefab_var: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct DoInteract { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AddFlowInteractOption { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct MonsterCreator { + pub monster_creator_entity_ids: Vec, + pub prefab_var: Option, + pub show_monster_merged_hp_bar: Option, + pub tid_monster_group_name: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct CheckBySkillId { + pub skill_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct CheckBySkillGenre { + pub skill_genre: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct CheckVisionId { + pub vision_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum UseSkillType { + CheckBySkillId(CheckBySkillId), + CheckBySkillGenre(CheckBySkillGenre), + CheckVisionSummonId(CheckVisionId), + CheckVisionShowId(CheckVisionId), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct UseSkill { + pub check: UseSkillType, + pub is_wait_finish: Option, + pub pre_conditions: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct GetSkill { + pub skill_type: SkillType, + pub skill_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct Parkour { + pub config: String, + pub spline_entity_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Timer { + pub time: Option, + pub timer_type: TimerType, + pub var_for_time: Option, + // TODO UiConfig +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct Guide { + pub guide_group_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct PlayFlow { + pub flow: Flow, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct InformationViewCheck { + pub information_view_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ShowUi { + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, + pub keep_ui_open: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckUiGame { + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct StartTime { + pub hour: i32, + pub minute: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ScheduleTime { + pub start_time: StartTime, +} + +#[derive(Deserialize, Debug, Clone)] +pub enum SkillType { + UltimateSkill, + ESkill, + VisionSkill, + NormalSkill, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SkillOption { + pub r#type: SkillType, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckPlayerSkillReady { + pub skill_option: SkillOption, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct WaitTime { + pub days: i32, + pub hours: i32, + pub minutes: i32, + pub seconds: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TakePhoto { + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ParallaxAlign { + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckDirection { + pub direction: Point, + pub angle_interval: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckConditionGroup { + pub condition: Conditions, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckTreasureBeenClaimed { + pub entity_id: i64, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RangeSphere { + pub center: Location, + pub radius: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckInRange { + pub range_entities: Vec, + pub in_range: bool, +} + +#[derive(Deserialize, Debug, Clone)] +pub enum KuroGender { + #[serde(rename = "男")] + Male, + #[serde(rename = "女")] + Female, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckPlayerGender { + pub gender: KuroGender, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckPlayerInput { + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckFormationRoleInfo { + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct AwakeAndLoadEntity { + pub entity_ids: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +pub enum ChessWinner { + Computer, + Player, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckChessWinner { + pub chessboard_id: i64, + pub winner: ChessWinner, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct WalkingPattern { + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckDataLayer { + pub data_layer_id: i64, + pub is_load: bool, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckFinishLoading { + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct VisionSetActivated { + pub set_type: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct HasVisionGetTargetLevel { + pub target_level: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum Quest { + VisionSetActivated(VisionSetActivated), + HasVisionGetTargetLevel(HasVisionGetTargetLevel), + DoVisionIdentify, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct VisionSystem { + pub quest: Quest, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ReadMail { + pub mail_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ReceiveTelecom { + pub telecom_id: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckActivityState { + pub activity_id: i32, + pub compare: CompareType, + pub activity_state: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum Condition { + CompareTimePeriod(CompareTimePeriod), + CheckChildQuestFinished(CheckChildQuestFinished), + CompareEntityState(CompareEntityState), + CheckEntityState(CheckEntityState), + CompareVar(CompareVar), + CompareWeather(CompareWeather), + CompareQuestState(CompareQuestState), + CompareEntitySelfState(CompareEntitySelfState), + CheckPlayerStateRestriction(CheckPlayerStateRestriction), + HourToHour(HourToHour), + ComparePlayerMotionState(ComparePlayerMotionState), + ComparePlayerMotionState2(ComparePlayerMotionState2), + CheckAiState(CheckAiState), + PreLevelPlay(PreLevelPlay), + CheckLevelPlay(CheckLevelPlay), + CheckLevelPlayState(CheckLevelPlayState), + CheckLevelPlayCompleteNumber(CheckLevelPlayCompleteNumber), + CompareLevelPlayRewardState(CompareLevelPlayRewardState), + CheckItems(CheckItems), + HandInItems(HandInItems), + GetItem(GetItem), + UseItem(Item), + HasBuff(HasBuff), + CompareLift(CompareLift), + CheckJigsawInfo(CheckJigsawInfo), + CheckInCombat(CheckInCombat), + DetectCombatState(DetectCombatState), + DetectCombatState2(DetectCombatState2), + CheckVehicleCondition(CheckVehicleCondition), + CheckSystemFunction(CheckSystemFunction), + CheckSystemState(CheckSystemState), + CheckCollectAnimalParts(CheckCollectAnimalParts), + CheckCurrentRole(CheckCurrentRole), + CompareExploreLevel(CompareExploreLevel), + ExploreLevel(ExploreLevel), + CompareDungeonId(CompareDungeonId), + EnterDungeon(EnterDungeon), + LeaveDungeon(LeaveDungeon), + FinishDungeon(FinishDungeon), + CompareCalabashLevel(CompareCalabashLevel), + CheckCalabashDevelopReward(CheckCalabashDevelopReward), + CheckLordGymFinish(CheckLordGymFinish), + CompareEntityGroupState(CompareEntityGroupState), + CheckEntityLocked(CheckEntityLocked), + CheckRogueAbilitySelect(CheckRogueAbilitySelect), + CompareFishingBoatState(CompareFishingBoatState), + CompleteCertainFishingEntrust(CompleteCertainFishingEntrust), + CompareFishingPrestigeLevel(CompareFishingPrestigeLevel), + CheckCertainFishingItemCount(CheckCertainFishingItemCount), + CompareFishingTechLevel(CompareFishingTechLevel), + ListenEntitySelfEvent(ListenEntitySelfEvent), + CheckHookLockPoint(CheckHookLockPoint), + CheckEntitesExist(CheckEntitesExist), + CheckEntityHasSceneItemAttributeTag(CheckEntityHasSceneItemAttributeTag), + CheckTargetBattleAttribute(CheckTargetBattleAttribute), + CheckAlertAreaEnabled(CheckAlertAreaEnabled), + CompareAlertValue(CheckAlertAreaEnabled), + ReachArea(ReachArea), + Kill(Kill), + DoInteract(DoInteract), + MonsterCreator(MonsterCreator), + UseSkill(UseSkill), + GetSkill(GetSkill), + Parkour(Parkour), + Timer(Timer), + Guide(Guide), + PlayFlow(PlayFlow), + InformationViewCheck(InformationViewCheck), + ShowUi(ShowUi), + CheckUiGame(CheckUiGame), + ScheduleTime(ScheduleTime), + CheckPlayerSkillReady(CheckPlayerSkillReady), + WaitTime(WaitTime), + TakePhoto(TakePhoto), + ParallaxAlign(ParallaxAlign), + WaitBattleCondition(CheckTargetBattleAttribute), + CheckDirection(CheckDirection), + CheckConditionGroup(CheckConditionGroup), + CheckTreasureBeenClaimed(CheckTreasureBeenClaimed), + RangeSphere(RangeSphere), + CheckInRange(CheckInRange), + CheckPlayerGender(CheckPlayerGender), + CheckPlayerInput(CheckPlayerInput), + CheckFormationRoleInfo(CheckFormationRoleInfo), + AwakeAndLoadEntity(AwakeAndLoadEntity), + CheckChessWinner(CheckChessWinner), + WalkingPattern(WalkingPattern), + CheckDataLayer(CheckDataLayer), + CheckFinishLoading(CheckFinishLoading), + VisionSystem(VisionSystem), + ReadMail(ReadMail), + ReceiveTelecom(ReceiveTelecom), + CheckActivityState(CheckActivityState), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Conditions { + pub r#type: i32, + pub conditions: Vec, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/entity_state.rs b/wicked-waifus-data/src/pb_components/entity_state.rs new file mode 100644 index 0000000..a4dcdb0 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/entity_state.rs @@ -0,0 +1,60 @@ +use serde::Deserialize; +use crate::pb_components::action::Action; +use crate::pb_components::condition::Conditions; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct ConditionAction { + pub condition: Conditions, + pub action: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct DelayChangeState { + pub time: f32, + pub new_state: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct StateConfigs { + pub duration: f32, + pub state: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct StateChangeBehaviors { + pub state: String, + pub action: Option>, + pub condition_action: Option>, + pub delay_change_state: Option +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct LockConfig { + pub lock_type: Option, // TODO: Enum + pub is_init_lock: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase", deny_unknown_fields)] +pub struct EntityStateComponent { + pub disabled: Option, + pub r#type: Option, + pub state: Option, + pub state_change_condition: Option, + pub state_change_behaviors: Option>, + pub state_configs: Option>, + pub cycle_states: Option>, + pub prefab_performance_type: Option, + pub lock_config: Option, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/flow.rs b/wicked-waifus-data/src/pb_components/flow.rs new file mode 100644 index 0000000..00cd263 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/flow.rs @@ -0,0 +1,11 @@ +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Flow { + pub flow_list_name: String, + pub flow_id: i32, + pub state_id: Option, + pub flow_guid: Option +} diff --git a/wicked-waifus-data/src/pb_components/interact.rs b/wicked-waifus-data/src/pb_components/interact.rs new file mode 100644 index 0000000..0b60298 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/interact.rs @@ -0,0 +1,87 @@ +use serde::Deserialize; +use crate::pb_components::action::Action; +use crate::pb_components::common::Point; +use crate::pb_components::flow::Flow; +use crate::pb_components::option::GameOption; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MatchRoleOption { + pub r#type: String, + pub id: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SectorRange { + pub begin: Option, + pub end: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RandomInteract { + pub random_count: Option, + #[cfg(feature = "strict_json_fields")] + pub options: Option, // TODO +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Npc {} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct LeisureInteraction { + pub begin: i32, + pub end: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum SectorRangeFromPlayerToEntity { + Npc(Npc), + LeisureInteraction(LeisureInteraction), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Actions { + pub actions: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Flows { + pub flow: Flow, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct InteractComponent { + pub disabled: Option, + pub pre_flow: Option, + pub do_intact_type: Option, + pub options: Option>, + pub match_role_option: Option>, + pub range: Option, + pub is_wait_for_turn_around_complete: Option, + pub turn_around_type: Option, + pub interact_default_icon: Option, + pub tid_content: Option, + pub interact_point_offset: Option, + pub sector_range: Option, + pub random_interact: Option, + pub sector_range_from_player_to_entity: Option, + pub interact_icon: Option, + pub quest_ids: Option>, + pub exit_range: Option, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/mod.rs b/wicked-waifus-data/src/pb_components/mod.rs new file mode 100644 index 0000000..105daf9 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/mod.rs @@ -0,0 +1,235 @@ +use serde::Deserialize; + +pub mod action; +pub mod ai; +pub mod attribute; +pub mod base_info; +pub mod common; +pub mod condition; +pub mod entity_state; +pub mod flow; +pub mod interact; +pub mod monster; +pub mod option; +pub mod reward; +pub mod teleport; +pub mod timer; +pub mod var; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ComponentsData { + pub base_info_component: Option, + pub ai_component: Option, + pub attribute_component: Option, + pub teleport_component: Option, + pub monster_component: Option, + pub interact_component: Option, + pub entity_state_component: Option, + pub reward_component: Option, + // TODO: Implement this ones + #[cfg(feature = "strict_json_fields")] + pub scene_actor_ref_component: Option, + #[cfg(feature = "strict_json_fields")] + pub effect_area_component: Option, + #[cfg(feature = "strict_json_fields")] + pub condition_listener_component: Option, + #[cfg(feature = "strict_json_fields")] + pub npc_perform_component: Option, + #[cfg(feature = "strict_json_fields")] + pub var_component: Option, + #[cfg(feature = "strict_json_fields")] + pub entity_visible_component: Option, + #[cfg(feature = "strict_json_fields")] + pub level_ai_component: Option, + #[cfg(feature = "strict_json_fields")] + pub trigger_component: Option, + #[cfg(feature = "strict_json_fields")] + pub range_component: Option, + #[cfg(feature = "strict_json_fields")] + pub spline_component: Option, + #[cfg(feature = "strict_json_fields")] + pub bubble_component: Option, + #[cfg(feature = "strict_json_fields")] + pub refresh_component: Option, + #[cfg(feature = "strict_json_fields")] + pub passerby_npc_spawn_component: Option, + #[cfg(feature = "strict_json_fields")] + pub vision_capture_component: Option, + #[cfg(feature = "strict_json_fields")] + pub refresh_group_component: Option, + #[cfg(feature = "strict_json_fields")] + pub collect_component: Option, + #[cfg(feature = "strict_json_fields")] + pub target_gear_component: Option, + #[cfg(feature = "strict_json_fields")] + pub fight_interact_component: Option, + #[cfg(feature = "strict_json_fields")] + pub guide_line_creator_component: Option, + #[cfg(feature = "strict_json_fields")] + pub photo_target_component: Option, + #[cfg(feature = "strict_json_fields")] + pub model_component: Option, + #[cfg(feature = "strict_json_fields")] + pub entity_group_component: Option, + #[cfg(feature = "strict_json_fields")] + pub scene_item_life_cycle_component: Option, + #[cfg(feature = "strict_json_fields")] + pub entity_state_audio_component: Option, + #[cfg(feature = "strict_json_fields")] + pub animal_component: Option, + #[cfg(feature = "strict_json_fields")] + pub nearby_tracking_component: Option, + #[cfg(feature = "strict_json_fields")] + pub follow_track_component: Option, + #[cfg(feature = "strict_json_fields")] + pub jigsaw_foundation: Option, + #[cfg(feature = "strict_json_fields")] + pub treasure_box_component: Option, + #[cfg(feature = "strict_json_fields")] + pub hook_lock_point: Option, + #[cfg(feature = "strict_json_fields")] + pub explore_skill_interact_component: Option, + #[cfg(feature = "strict_json_fields")] + pub attach_target_component: Option, + #[cfg(feature = "strict_json_fields")] + pub target_gear_group_component: Option, + #[cfg(feature = "strict_json_fields")] + pub spawn_monster_component: Option, + #[cfg(feature = "strict_json_fields")] + pub skybox_component: Option, + #[cfg(feature = "strict_json_fields")] + pub destructible_item: Option, + #[cfg(feature = "strict_json_fields")] + pub fan_component: Option, + #[cfg(feature = "strict_json_fields")] + pub state_hint_component: Option, + #[cfg(feature = "strict_json_fields")] + pub buff_consumer_component: Option, + #[cfg(feature = "strict_json_fields")] + pub reset_entities_pos_component: Option, + #[cfg(feature = "strict_json_fields")] + pub group_ai_component: Option, + #[cfg(feature = "strict_json_fields")] + pub pulling_object_foundation: Option, + #[cfg(feature = "strict_json_fields")] + pub lift_component: Option, + #[cfg(feature = "strict_json_fields")] + pub scene_item_movement_component: Option, + #[cfg(feature = "strict_json_fields")] + pub reset_self_pos_component: Option, + #[cfg(feature = "strict_json_fields")] + pub jigsaw_item: Option, + #[cfg(feature = "strict_json_fields")] + pub level_play_component: Option, + #[cfg(feature = "strict_json_fields")] + pub interact_gear_component: Option, + #[cfg(feature = "strict_json_fields")] + pub ai_gear_strategy_component: Option, + #[cfg(feature = "strict_json_fields")] + pub pick_interact_component: Option, + #[cfg(feature = "strict_json_fields")] + pub level_sequence_frame_event_component: Option, + #[cfg(feature = "strict_json_fields")] + pub air_wall_spawner_component: Option, + #[cfg(feature = "strict_json_fields")] + pub progress_bar_control_component: Option, + #[cfg(feature = "strict_json_fields")] + pub batch_bullet_caster_component: Option, + #[cfg(feature = "strict_json_fields")] + pub client_trigger_component: Option, + #[cfg(feature = "strict_json_fields")] + pub enrichment_area_component: Option, + #[cfg(feature = "strict_json_fields")] + pub vehicle_component: Option, + #[cfg(feature = "strict_json_fields")] + pub item_foundation2: Option, + #[cfg(feature = "strict_json_fields")] + pub tele_control2: Option, + #[cfg(feature = "strict_json_fields")] + pub interact_audio_component: Option, + #[cfg(feature = "strict_json_fields")] + pub level_qte_component: Option, + #[cfg(feature = "strict_json_fields")] + pub resurrection_component: Option, + #[cfg(feature = "strict_json_fields")] + pub ai_alert_notify_component: Option, + #[cfg(feature = "strict_json_fields")] + pub trample_component: Option, + #[cfg(feature = "strict_json_fields")] + pub dungeon_entry_component: Option, + #[cfg(feature = "strict_json_fields")] + pub level_prefab_perform_component: Option, + #[cfg(feature = "strict_json_fields")] + pub render_specified_range_component: Option, + #[cfg(feature = "strict_json_fields")] + pub walking_pattern_component: Option, + #[cfg(feature = "strict_json_fields")] + pub no_render_portal_component: Option, + #[cfg(feature = "strict_json_fields")] + pub adsorb_component: Option, + #[cfg(feature = "strict_json_fields")] + pub beam_cast_component: Option, + #[cfg(feature = "strict_json_fields")] + pub beam_receive_component: Option, + #[cfg(feature = "strict_json_fields")] + pub timeline_track_control_component: Option, + #[cfg(feature = "strict_json_fields")] + pub scene_bullet_component: Option, + #[cfg(feature = "strict_json_fields")] + pub edit_custom_aoi_component: Option, + #[cfg(feature = "strict_json_fields")] + pub combat_component: Option, + #[cfg(feature = "strict_json_fields")] + pub location_safety_component: Option, + #[cfg(feature = "strict_json_fields")] + pub turntable_control_component: Option, + #[cfg(feature = "strict_json_fields")] + pub scene_item_ai_component: Option, + #[cfg(feature = "strict_json_fields")] + pub buff_producer_component: Option, + #[cfg(feature = "strict_json_fields")] + pub portal_component: Option, + #[cfg(feature = "strict_json_fields")] + pub inhalation_ability_component: Option, + #[cfg(feature = "strict_json_fields")] + pub inhaled_item_component: Option, + #[cfg(feature = "strict_json_fields")] + pub monster_gacha_base_component: Option, + #[cfg(feature = "strict_json_fields")] + pub monster_gacha_item_component: Option, + #[cfg(feature = "strict_json_fields")] + pub time_stop_component: Option, + #[cfg(feature = "strict_json_fields")] + pub hit_component: Option, + #[cfg(feature = "strict_json_fields")] + pub levitate_magnet_component: Option, + #[cfg(feature = "strict_json_fields")] + pub rebound_component: Option, + #[cfg(feature = "strict_json_fields")] + pub rotator_component2: Option, + #[cfg(feature = "strict_json_fields")] + pub conveyor_belt_component: Option, + #[cfg(feature = "strict_json_fields")] + pub dynamic_portal_creator_component: Option, + #[cfg(feature = "strict_json_fields")] + pub connector_component: Option, + #[cfg(feature = "strict_json_fields")] + pub monitor_component: Option, +} + +impl ComponentsData { + pub fn merge_with_template(&self, template: &Self) -> Self { + Self { + base_info_component: self.base_info_component.as_ref().or(template.base_info_component.as_ref()).cloned(), + ai_component: self.ai_component.as_ref().or(template.ai_component.as_ref()).cloned(), + attribute_component: self.attribute_component.as_ref().or(template.attribute_component.as_ref()).cloned(), + teleport_component: self.teleport_component.as_ref().or(template.teleport_component.as_ref()).cloned(), + monster_component: self.monster_component.as_ref().or(template.monster_component.as_ref()).cloned(), + interact_component: self.interact_component.as_ref().or(template.interact_component.as_ref()).cloned(), + entity_state_component: self.entity_state_component.as_ref().or(template.entity_state_component.as_ref()).cloned(), + reward_component: self.reward_component.as_ref().or(template.reward_component.as_ref()).cloned(), + } + } +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/monster.rs b/wicked-waifus-data/src/pb_components/monster.rs new file mode 100644 index 0000000..2e2eca6 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/monster.rs @@ -0,0 +1,40 @@ +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BossViewConfig { + pub boss_state_view_type: Option, + pub boss_state_info_show_type: Option, + pub tid_level_text: Option, + pub tid_boss_sub_title: Option, + pub show_distance: Option, + pub only_show_in_battle_state: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ShowOnDeath { + pub r#type: Option, + pub effect_id: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct PerformConfig { + pub show_on_death: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MonsterComponent { + pub disabled: Option, + pub init_gas_tag: Option>, + pub special_hate_and_sense_config: Option, + pub boss_view_config: Option, + pub perform_config: Option, + pub fight_config_id: Option, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/option.rs b/wicked-waifus-data/src/pb_components/option.rs new file mode 100644 index 0000000..d8791fe --- /dev/null +++ b/wicked-waifus-data/src/pb_components/option.rs @@ -0,0 +1,27 @@ +use serde::Deserialize; +use crate::pb_components::condition::Conditions; +use crate::pb_components::interact::{Actions, Flows}; + +#[derive(Deserialize, Debug)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SitDown {} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum OptionType { + Actions(Actions), + Flow(Flows), +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct GameOption { + pub tid_content: Option, + pub guid: Option, + pub uniqueness_test: Option, + pub r#type: Option, + pub condition: Option, + pub icon: Option +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/reward.rs b/wicked-waifus-data/src/pb_components/reward.rs new file mode 100644 index 0000000..e71ea0d --- /dev/null +++ b/wicked-waifus-data/src/pb_components/reward.rs @@ -0,0 +1,11 @@ +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RewardComponent { + pub disabled: Option, + pub reward_id: Option, + pub reward_type: Option, + pub drop_on_event: Option, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/teleport.rs b/wicked-waifus-data/src/pb_components/teleport.rs new file mode 100644 index 0000000..a7d3191 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/teleport.rs @@ -0,0 +1,21 @@ +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TeleportPosition { + pub x: Option, + pub y: Option, + pub z: Option, + pub a: Option, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TeleportComponent { + pub disabled: Option, + pub teleporter_id: Option, + #[serde(rename = "TeleportPos")] + pub teleport_position: Option, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/timer.rs b/wicked-waifus-data/src/pb_components/timer.rs new file mode 100644 index 0000000..37643f6 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/timer.rs @@ -0,0 +1,12 @@ +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +pub enum TimerType { + CountDownChallenge, + WaitTime, + GameStartCountDown, + PublicTime, + BehaviorTreeTimer1, + BehaviorTreeTimer2, + BehaviorTreeTimer3, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/var.rs b/wicked-waifus-data/src/pb_components/var.rs new file mode 100644 index 0000000..be76fec --- /dev/null +++ b/wicked-waifus-data/src/pb_components/var.rs @@ -0,0 +1,102 @@ +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +pub enum CompareType { + Ne, // Not equal + Eq, // Equal + Ge, // Greater or equal + Gt, // Greater than + Le, // Less or equal + Lt, // Less than +} + +impl CompareType { + pub fn cmp(self, left: &T, right: &T) -> bool { + match self { + CompareType::Ne => left.ne(right), + CompareType::Eq => left.eq(right), + CompareType::Ge => left.ge(right), + CompareType::Gt => left.gt(right), + CompareType::Le => left.le(right), + CompareType::Lt => left.lt(right), + } + } +} + +#[derive(Deserialize, Debug, Clone)] +pub enum OpType { + Add, // Addition + Sub, // Subtraction + Mut, // Multiplication ?? + Reduce, // Reduce ?? ?? ?? + Set, // Assign +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ConstantWrapper { + pub value: T, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Type")] +pub enum Constant { + Boolean(ConstantWrapper), + Int(ConstantWrapper), + String(ConstantWrapper), + Float(ConstantWrapper), +} + +#[derive(Deserialize, Debug, Clone)] +pub enum VarType { + Boolean, + Int, + String, + Float, + Prefab +} + +#[derive(Deserialize, Debug, Clone)] +pub enum RefType { + Entity, + Quest, + LevelPlay, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Other { + pub r#type: VarType, + pub ref_type: RefType, + pub ref_id: i64, + pub name: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct Global { + pub r#type: VarType, + pub keyword: String, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SelfVar { + pub r#type: VarType, + pub name: String, +} + + +#[derive(Deserialize, Debug, Clone)] +#[serde(tag = "Source")] +pub enum Var { + Constant(Constant), + Other(Other), + Global(Global), + #[serde(rename = "Self")] + SelfVar(SelfVar), +} \ No newline at end of file diff --git a/wicked-waifus-data/src/quest_node_data.rs b/wicked-waifus-data/src/quest_node_data.rs new file mode 100644 index 0000000..2e04f99 --- /dev/null +++ b/wicked-waifus-data/src/quest_node_data.rs @@ -0,0 +1,11 @@ +use serde::Deserialize; +use crate::node_data::NodeDataDetail; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct QuestNodeDataData { // Json file contains Data in name, so it has to be DataData + pub key: String, + pub data: NodeDataDetail, +} + diff --git a/wicked-waifus-data/src/resonance_amplification.rs b/wicked-waifus-data/src/resonance_amplification.rs new file mode 100644 index 0000000..4eb2d3f --- /dev/null +++ b/wicked-waifus-data/src/resonance_amplification.rs @@ -0,0 +1,10 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ResonanceAmplificationData { + pub id: i32, + pub attr: i32, + pub life_seat_boost_factor: Vec, +} diff --git a/wicked-waifus-data/src/resonant_chain.rs b/wicked-waifus-data/src/resonant_chain.rs new file mode 100644 index 0000000..a3e0a02 --- /dev/null +++ b/wicked-waifus-data/src/resonant_chain.rs @@ -0,0 +1,28 @@ +use std::collections::HashMap; + +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ResonantChainData { + pub id: i32, + pub group_id: i32, + pub group_index: i32, + pub node_type: i32, + #[cfg(feature = "strict_json_fields")] + pub node_index: String, + #[cfg(feature = "strict_json_fields")] + pub node_name: String, + #[cfg(feature = "strict_json_fields")] + pub attributes_description: String, + #[cfg(feature = "strict_json_fields")] + pub bg_description: String, + pub buff_ids: Vec, + pub add_prop: Vec, + pub activate_consume: HashMap, + #[cfg(feature = "strict_json_fields")] + pub attributes_description_params: Vec, + #[cfg(feature = "strict_json_fields")] + pub node_icon: String, +} diff --git a/wicked-waifus-data/src/role_breach.rs b/wicked-waifus-data/src/role_breach.rs new file mode 100644 index 0000000..08b4e8b --- /dev/null +++ b/wicked-waifus-data/src/role_breach.rs @@ -0,0 +1,16 @@ +use std::collections::HashMap; + +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RoleBreachData { + pub id: i32, + pub breach_group_id: i32, + pub breach_level: i32, + pub max_level: i32, + pub breach_consume: HashMap, + pub breach_reward: i32, + pub condition_id: i32, +} diff --git a/wicked-waifus-data/src/role_exp_item.rs b/wicked-waifus-data/src/role_exp_item.rs new file mode 100644 index 0000000..91a4668 --- /dev/null +++ b/wicked-waifus-data/src/role_exp_item.rs @@ -0,0 +1,9 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RoleExpItemData { + pub id: i32, + pub basic_exp: i32, +} diff --git a/wicked-waifus-data/src/role_info.rs b/wicked-waifus-data/src/role_info.rs index 91582cc..83aaf1e 100644 --- a/wicked-waifus-data/src/role_info.rs +++ b/wicked-waifus-data/src/role_info.rs @@ -3,14 +3,18 @@ use std::collections::HashMap; use serde::Deserialize; #[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct RoleInfoData { pub id: i32, pub quality_id: i32, pub role_type: i32, pub is_trial: bool, + #[cfg(feature = "strict_json_fields")] pub name: String, + #[cfg(feature = "strict_json_fields")] pub nick_name: String, + #[cfg(feature = "strict_json_fields")] pub introduction: String, pub tag: Vec, pub parent_id: i32, @@ -18,9 +22,35 @@ pub struct RoleInfoData { pub show_property: Vec, pub element_id: i32, pub skin_id: i32, + #[cfg(feature = "strict_json_fields")] + pub role_head_icon_circle: String, + #[cfg(feature = "strict_json_fields")] + pub role_head_icon_large: String, + #[cfg(feature = "strict_json_fields")] + pub role_head_icon_big: String, + #[cfg(feature = "strict_json_fields")] + pub card: String, + #[cfg(feature = "strict_json_fields")] + pub role_head_icon: String, + #[cfg(feature = "strict_json_fields")] + pub formation_role_card: String, + #[cfg(feature = "strict_json_fields")] + pub role_stand: String, + #[cfg(feature = "strict_json_fields")] + pub role_portrait: String, pub spillover_item: HashMap, + #[cfg(feature = "strict_json_fields")] + pub mesh_id: i32, + #[cfg(feature = "strict_json_fields")] + pub ui_mesh_id: i32, + #[cfg(feature = "strict_json_fields")] + pub role_body: String, pub breach_model: i32, pub special_energy_bar_id: i32, + #[cfg(feature = "strict_json_fields")] + pub camera_config: String, + #[cfg(feature = "strict_json_fields")] + pub camera_float_height: i32, pub entity_property: i32, pub max_level: i32, pub level_consume_id: i32, @@ -33,10 +63,45 @@ pub struct RoleInfoData { pub exchange_consume: HashMap, pub init_weapon_item_id: i32, pub weapon_type: i32, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "SkillDAPath")] + pub skill_da_path: String, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "SkillLockDAPath")] + pub skill_lock_da_path: String, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "UiScenePerformanceABP")] + pub ui_scene_performance_abp: String, + pub lock_on_default_id: i32, + pub lock_on_look_on_id: i32, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "SkillEffectDA")] + pub skill_effect_da: String, + #[cfg(feature = "strict_json_fields")] + pub foot_step_state: String, pub party_id: i32, + #[cfg(feature = "strict_json_fields")] + pub attributes_description: String, + #[cfg(feature = "strict_json_fields")] + pub icon: String, pub item_quality_id: i32, + #[cfg(feature = "strict_json_fields")] + pub obtained_show_description: String, pub num_limit: i32, + pub show_in_bag: bool, + #[cfg(feature = "strict_json_fields")] + pub weapon_scale: Vec, + #[cfg(feature = "strict_json_fields")] + pub intervene: bool, + #[cfg(feature = "strict_json_fields")] + pub character_voice: String, pub trial_role: i32, pub is_aim: bool, pub role_guide: i32, + #[cfg(feature = "strict_json_fields")] + pub red_dot_disable_rule: i32, + #[cfg(feature = "strict_json_fields")] + pub skin_damage: Vec, + #[cfg(feature = "strict_json_fields")] + pub hide_hu_lu: bool, } diff --git a/wicked-waifus-data/src/role_level_consume.rs b/wicked-waifus-data/src/role_level_consume.rs new file mode 100644 index 0000000..0d8b779 --- /dev/null +++ b/wicked-waifus-data/src/role_level_consume.rs @@ -0,0 +1,11 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RoleLevelConsumeData { + pub id: i32, + pub consume_group_id: i32, + pub level: i32, + pub exp_count: i32, +} diff --git a/wicked-waifus-data/src/role_property_growth.rs b/wicked-waifus-data/src/role_property_growth.rs new file mode 100644 index 0000000..c343446 --- /dev/null +++ b/wicked-waifus-data/src/role_property_growth.rs @@ -0,0 +1,13 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RolePropertyGrowthData { + pub id: i32, + pub level: i32, + pub breach_level: i32, + pub life_max_ratio: i32, + pub atk_ratio: i32, + pub def_ratio: i32, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/silent_area_detection.rs b/wicked-waifus-data/src/silent_area_detection.rs new file mode 100644 index 0000000..b4f28a7 --- /dev/null +++ b/wicked-waifus-data/src/silent_area_detection.rs @@ -0,0 +1,47 @@ +use std::collections::HashMap; + +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SilentAreaDetectionData { + pub id: i32, + #[cfg(feature = "strict_json_fields")] + pub name: String, + pub guide_id: i32, + pub level_play_list: Vec, + #[cfg(feature = "strict_json_fields")] + pub instance_sub_type_description: String, + pub danger_type: i32, + pub secondary: i32, + pub type_description2: i32, + pub mat_type: i32, + #[cfg(feature = "strict_json_fields")] + pub attributes_description_lock: String, + #[cfg(feature = "strict_json_fields")] + pub attributes_description_unlock: String, + #[cfg(feature = "strict_json_fields")] + pub big_icon: String, + #[cfg(feature = "strict_json_fields")] + pub icon: String, + #[cfg(feature = "strict_json_fields")] + pub lock_big_icon: String, + #[cfg(feature = "strict_json_fields")] + pub temporary_icon_un_lock: String, + #[cfg(feature = "strict_json_fields")] + pub temporary_iconlock: String, + pub show_reward: i32, + pub show_reward_map: HashMap, + pub begin_time_stamp: i32, + pub pre_open_id: i32, + pub mark_id: i32, + pub lock_con: i32, + #[cfg(feature = "strict_json_fields")] + pub phantom_id: Vec>, + pub first_drop_id: i32, + pub additional_id: i32, + pub sort_id: i32, + #[cfg(feature = "strict_json_fields")] + pub new_content: String, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/synthesis_formula.rs b/wicked-waifus-data/src/synthesis_formula.rs new file mode 100644 index 0000000..e7348f5 --- /dev/null +++ b/wicked-waifus-data/src/synthesis_formula.rs @@ -0,0 +1,29 @@ +use serde::Deserialize; +use crate::ConsumeItem; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SynthesisFormulaData { + pub id: i32, + pub formula_item_id: i32, + pub item_id: i32, + pub formula_type: i32, + pub item_group: i32, + #[cfg(feature = "strict_json_fields")] + pub name: String, + pub consume_items: Vec, + pub sort_id: i32, + pub unlock_condition: i32, + pub proficiency: i32, + pub max_proficiency_count: i32, + pub type_id: i32, + pub unlock: bool, + pub limit_count: i32, + pub permanent_limit: bool, + pub role_list: Vec, + #[cfg(feature = "strict_json_fields")] + pub compose_content: String, + #[cfg(feature = "strict_json_fields")] + pub compose_background: String, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/teleporter.rs b/wicked-waifus-data/src/teleporter.rs index 06f91aa..b007916 100644 --- a/wicked-waifus-data/src/teleporter.rs +++ b/wicked-waifus-data/src/teleporter.rs @@ -1,15 +1,16 @@ use serde::Deserialize; -#[derive(Debug, Deserialize, Clone)] +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct TeleporterData { pub id: i32, pub map_id: i32, pub object_id: i32, - pub area_id: i32, pub fog_id: i32, pub r#type: i32, pub teleport_entity_config_id: i64, + #[cfg(feature = "strict_json_fields")] pub plot: String, pub after_network_action: i32, pub show_world_map: bool, diff --git a/wicked-waifus-data/src/template_config.rs b/wicked-waifus-data/src/template_config.rs index 85d0e4e..560c34c 100644 --- a/wicked-waifus-data/src/template_config.rs +++ b/wicked-waifus-data/src/template_config.rs @@ -1,11 +1,13 @@ use serde::Deserialize; -use crate::ComponentsData; +use crate::pb_components::ComponentsData; -#[derive(Debug, Deserialize, Clone)] +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct TemplateConfigData { pub id: i32, pub blueprint_type: String, + #[cfg(feature = "strict_json_fields")] pub name: String, pub components_data: ComponentsData, } \ No newline at end of file diff --git a/wicked-waifus-data/src/text_map_data/mod.rs b/wicked-waifus-data/src/text_map_data/mod.rs new file mode 100644 index 0000000..b7d76d1 --- /dev/null +++ b/wicked-waifus-data/src/text_map_data/mod.rs @@ -0,0 +1,78 @@ +use std::collections::{HashMap, HashSet}; +use std::fs::File; +use std::io::BufReader; +use std::sync::{LazyLock, Mutex, OnceLock}; +use serde::Deserialize; +use crate::LoadDataError; + +static FILTERS: LazyLock>> = LazyLock::new(|| Mutex::new(HashSet::new())); +static EMPTY: OnceLock> = OnceLock::new(); +static TABLE: OnceLock>> = OnceLock::new(); + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TextMapData { + pub id: String, + pub content: String, +} + +pub fn register_filter(filter: String) { + match TABLE.get() { + None => { FILTERS.lock().unwrap().insert(filter); } + Some(_) => { + // TODO: Implement error if filter is added after textmap was loaded already + } + }; +} + +pub fn load_textmaps(base_path: &str) -> Result<(), LoadDataError> { + let languages = std::fs::read_dir(base_path)? + .filter_map(|entry| entry.ok()) + .filter(|entry| entry.path().is_dir()) + .collect::>(); + let mut result: HashMap> = HashMap::new(); + let mut filters = FILTERS.lock().unwrap(); + for language in languages { + let lang_id = language.file_name().to_str().unwrap().to_string(); + let file = File::open(&format!("{base_path}/{lang_id}/multi_text/MultiText.json"))?; + let reader = BufReader::new(file); + result.insert( + lang_id, + serde_json::from_reader::, Vec>(reader)? + .into_iter() + .filter(|element| filters.contains(&element.id)) + .map(|element| (element.id, element.content)) + .collect::>(), + ); + } + let _ = TABLE.set(result); + filters.clear(); + Ok(()) +} + +pub fn get_textmap(language: i32) -> &'static HashMap { + let (text_code, _audio_code) = get_language_from_i32(language); + TABLE.get_or_init(|| HashMap::new()) + .get(text_code) + .unwrap_or(EMPTY.get_or_init(|| HashMap::new())) +} + +fn get_language_from_i32(language: i32) -> (&'static str, &'static str) { + match language { + 0 => ("zh-Hans", "zh"), + 1 => ("en", "en"), + 2 => ("ja", "ja"), + 3 => ("ko", "ko"), + 4 => ("ru", "en"), + 5 => ("zh-Hant", "zh"), + 6 => ("de", "en"), + 7 => ("es", "en"), + 8 => ("pt", "en"), + 9 => ("id", "en"), + 10 => ("fr", "en"), + 11 => ("vi", "en"), + 12 => ("th", "en"), + _ => ("en", "en"), + } +} \ No newline at end of file diff --git a/wicked-waifus-data/src/textmap.rs b/wicked-waifus-data/src/textmap.rs deleted file mode 100644 index 147356e..0000000 --- a/wicked-waifus-data/src/textmap.rs +++ /dev/null @@ -1,8 +0,0 @@ -use serde::Deserialize; - -#[derive(Deserialize, Clone)] -#[serde(rename_all = "PascalCase")] -pub struct TextMapData { - pub id: String, - pub content: String, -} diff --git a/wicked-waifus-data/src/weapon_breach.rs b/wicked-waifus-data/src/weapon_breach.rs new file mode 100644 index 0000000..df50a63 --- /dev/null +++ b/wicked-waifus-data/src/weapon_breach.rs @@ -0,0 +1,16 @@ +use std::collections::HashMap; + +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct WeaponBreachData { + pub id: i32, + pub breach_id: i32, + pub level: i32, + pub condition_id: i32, + pub level_limit: i32, + pub consume: HashMap, + pub gold_consume: i32, +} diff --git a/wicked-waifus-data/src/weapon_conf.rs b/wicked-waifus-data/src/weapon_conf.rs index 4d403fa..ae6e1f7 100644 --- a/wicked-waifus-data/src/weapon_conf.rs +++ b/wicked-waifus-data/src/weapon_conf.rs @@ -3,13 +3,18 @@ use serde::Deserialize; use crate::PropValueData; #[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] pub struct WeaponConfData { pub item_id: i32, + #[cfg(feature = "strict_json_fields")] pub weapon_name: String, pub quality_id: i32, + pub weapon_type: i32, + #[cfg(feature = "strict_json_fields")] pub model_id: i32, pub transform_id: i32, + #[cfg(feature = "strict_json_fields")] pub models: Vec, pub reson_level_limit: i32, pub first_prop_id: PropValueData, diff --git a/wicked-waifus-data/src/weapon_exp_item.rs b/wicked-waifus-data/src/weapon_exp_item.rs new file mode 100644 index 0000000..837a802 --- /dev/null +++ b/wicked-waifus-data/src/weapon_exp_item.rs @@ -0,0 +1,10 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct WeaponExpItemData { + pub id: i32, + pub cost: i32, + pub basic_exp: i32, +} diff --git a/wicked-waifus-data/src/weapon_level.rs b/wicked-waifus-data/src/weapon_level.rs new file mode 100644 index 0000000..51ca900 --- /dev/null +++ b/wicked-waifus-data/src/weapon_level.rs @@ -0,0 +1,11 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct WeaponLevelData { + pub id: i32, + pub level_id: i32, + pub level: i32, + pub exp: i32, +} diff --git a/wicked-waifus-data/src/weapon_property_growth.rs b/wicked-waifus-data/src/weapon_property_growth.rs new file mode 100644 index 0000000..95bdbc2 --- /dev/null +++ b/wicked-waifus-data/src/weapon_property_growth.rs @@ -0,0 +1,12 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct WeaponPropertyGrowthData { + pub id: i32, + pub curve_id: i32, + pub level: i32, + pub breach_level: i32, + pub curve_value: i32, +} \ No newline at end of file diff --git a/wicked-waifus-data/src/weapon_reson.rs b/wicked-waifus-data/src/weapon_reson.rs new file mode 100644 index 0000000..8f08444 --- /dev/null +++ b/wicked-waifus-data/src/weapon_reson.rs @@ -0,0 +1,17 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct WeaponResonData { + pub id: i32, + pub reson_id: i32, + pub level: i32, + #[cfg(feature = "strict_json_fields")] + pub name: String, + #[cfg(feature = "strict_json_fields")] + pub effect: Vec, + pub consume: i32, + pub gold_consume: i32, + pub alternative_consume: Vec, +} \ No newline at end of file diff --git a/wicked-waifus-game-server/Cargo.toml b/wicked-waifus-game-server/Cargo.toml index d6798ba..5af89f5 100644 --- a/wicked-waifus-game-server/Cargo.toml +++ b/wicked-waifus-game-server/Cargo.toml @@ -11,8 +11,11 @@ tokio.workspace = true serde.workspace = true # Util +indexmap = "2.7.1" uuid = { version = "1.11.0", features = ["v4"] } rand = "0.9.0-alpha.2" +unreal-niggery-rs = { git = "https://git.xeondev.com/xavo95/unreal-niggery-rs.git" } +widestring = "1.1.0" # Used for debug #serde_json = "1.0.135" @@ -26,6 +29,7 @@ hex.workspace = true tracing.workspace = true # Internal +wicked-waifus-asset-updater.workspace = true wicked-waifus-commons.workspace = true wicked-waifus-data.workspace = true wicked-waifus-database.workspace = true diff --git a/wicked-waifus-game-server/gameserver.default.toml b/wicked-waifus-game-server/gameserver.default.toml index c054998..210406c 100644 --- a/wicked-waifus-game-server/gameserver.default.toml +++ b/wicked-waifus-game-server/gameserver.default.toml @@ -13,6 +13,23 @@ addr = "tcp://127.0.0.1:10004" addr = "tcp://127.0.0.1:10003" [game_server_config] +resources_path = "data/assets/game-data" load_textmaps = true # Do not change yet, issues to be solved -quadrant_size = 1000000 \ No newline at end of file +quadrant_size = 1000000 + +[asset_config] +asset_url = "https://git.xeondev.com/wickedwaifus/wicked-waifus-data/releases/download/pioneer_2.2.3/bundle.zip" +buffer_size = 268435456 + +[default_unlocks] +unlock_all_roles = true +unlock_all_roles_max_level = false +unlock_all_roles_all_sequences = false +unlock_all_mc_elements = true +unlock_all_weapons = false +unlock_all_adventures = false +unlock_all_functions = true +unlock_all_guides = false +unlock_all_tutorials = false +unlock_all_teleporter = false diff --git a/wicked-waifus-game-server/scripts/debug_disable.js b/wicked-waifus-game-server/scripts/debug_disable.js new file mode 100644 index 0000000..03a829a --- /dev/null +++ b/wicked-waifus-game-server/scripts/debug_disable.js @@ -0,0 +1,3 @@ +const UiManager_1 = require("../Ui/UiManager"); +const BattleView = UiManager_1.UiManager.GetViewByName("BattleView"); +BattleView.ort(9).GetText(0).SetUIActive(false); \ No newline at end of file diff --git a/wicked-waifus-game-server/src/config.rs b/wicked-waifus-game-server/src/config.rs index 890cc10..58270d4 100644 --- a/wicked-waifus-game-server/src/config.rs +++ b/wicked-waifus-game-server/src/config.rs @@ -1,5 +1,8 @@ +use std::sync::OnceLock; + use serde::Deserialize; +use wicked_waifus_commons::config_util; use wicked_waifus_commons::config_util::TomlConfig; use wicked_waifus_database::DatabaseSettings; use wicked_waifus_network::config::ServiceEndPoint; @@ -11,14 +14,43 @@ pub struct ServiceConfig { pub service_end_point: ServiceEndPoint, pub gateway_end_point: ServiceEndPoint, pub game_server_config: GameServerConfig, + pub asset_config: AssetConfig, + pub default_unlocks: DefaultUnlocks, } #[derive(Deserialize)] pub struct GameServerConfig { + pub resources_path: String, pub load_textmaps: bool, pub quadrant_size: f32, } +#[derive(Deserialize)] +pub struct AssetConfig { + pub asset_url: String, + pub buffer_size: usize, +} + +#[derive(Deserialize)] +pub struct DefaultUnlocks { + pub unlock_all_roles: bool, + pub unlock_all_roles_max_level: bool, + pub unlock_all_roles_all_sequences: bool, + pub unlock_all_mc_elements: bool, + pub unlock_all_weapons: bool, // TODO: + pub unlock_all_adventures: bool, + pub unlock_all_functions: bool, + pub unlock_all_guides: bool, + pub unlock_all_tutorials: bool, + pub unlock_all_teleporter: bool, +} + impl TomlConfig for ServiceConfig { const DEFAULT_TOML: &str = include_str!("../gameserver.default.toml"); } + +static CONFIG: OnceLock = OnceLock::new(); + +pub fn get_config() -> &'static ServiceConfig { + CONFIG.get_or_init(|| config_util::load_or_create("gameserver.toml")) +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/components/attribute.rs b/wicked-waifus-game-server/src/logic/components/attribute.rs index 68eee6d..89a4b06 100644 --- a/wicked-waifus-game-server/src/logic/components/attribute.rs +++ b/wicked-waifus-game-server/src/logic/components/attribute.rs @@ -10,6 +10,8 @@ use crate::logic::utils::load_role_info::attribute_from_data; pub struct Attribute { pub attr_map: HashMap, + pub hardness_mode_id: i32, + pub rage_mode_id: i32, } impl Component for Attribute { @@ -40,9 +42,13 @@ impl Attribute { } #[inline(always)] - pub fn from_data(base_property: &BasePropertyData) -> Self { + pub fn from_data(base_property: &BasePropertyData, + hardness_mode_id: Option, + rage_mode_id: Option) -> Self { Self { attr_map: attribute_from_data(base_property), + hardness_mode_id: hardness_mode_id.unwrap_or_default(), + rage_mode_id: rage_mode_id.unwrap_or_default(), } } @@ -58,8 +64,8 @@ impl Attribute { value_increment: *incr, }) .collect(), - hardness_mode_id: 0, - rage_mode_id: 0, + hardness_mode_id: self.hardness_mode_id, + rage_mode_id: self.rage_mode_id, } } } diff --git a/wicked-waifus-game-server/src/logic/components/concomitant.rs b/wicked-waifus-game-server/src/logic/components/concomitant.rs new file mode 100644 index 0000000..9b6d436 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/components/concomitant.rs @@ -0,0 +1,22 @@ +use wicked_waifus_protocol::{ConcomitantsComponentPb, EntityComponentPb}; +use wicked_waifus_protocol::entity_component_pb::ComponentPb; + +use crate::logic::ecs::component::Component; + +pub struct Concomitant { + pub vision_entity_id: i64, + pub custom_entity_ids: Vec, + pub phantom_role_id: i64, +} + +impl Component for Concomitant { + fn set_pb_data(&self, pb: &mut wicked_waifus_protocol::EntityPb) { + pb.component_pbs.push(EntityComponentPb { + component_pb: Some(ComponentPb::ConcomitantsComponentPb(ConcomitantsComponentPb { + vision_entity_id: self.vision_entity_id, + custom_entity_ids: self.custom_entity_ids.clone(), + phantom_role_id: self.phantom_role_id, + })), + }) + } +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/components/entity_config.rs b/wicked-waifus-game-server/src/logic/components/entity_config.rs index 69adefb..1864edc 100644 --- a/wicked-waifus-game-server/src/logic/components/entity_config.rs +++ b/wicked-waifus-game-server/src/logic/components/entity_config.rs @@ -1,8 +1,9 @@ use wicked_waifus_protocol::{EEntityType, EntityConfigType, EntityState}; - +use wicked_waifus_protocol::entity_pb::D3s; use crate::logic::ecs::component::Component; pub struct EntityConfig { + pub camp: i32, pub config_id: i32, pub config_type: EntityConfigType, pub entity_type: EEntityType, @@ -11,6 +12,7 @@ pub struct EntityConfig { impl Component for EntityConfig { fn set_pb_data(&self, pb: &mut wicked_waifus_protocol::EntityPb) { + pb.d3s = Some(D3s::Camp(self.camp)); pb.config_id = self.config_id; pb.config_type = self.config_type.into(); pb.entity_type = self.entity_type.into(); diff --git a/wicked-waifus-game-server/src/logic/components/fight_buff.rs b/wicked-waifus-game-server/src/logic/components/fight_buff.rs index 86584c3..a7311a6 100644 --- a/wicked-waifus-game-server/src/logic/components/fight_buff.rs +++ b/wicked-waifus-game-server/src/logic/components/fight_buff.rs @@ -1,24 +1,25 @@ -use wicked_waifus_protocol::{BuffEffectCd, EntityComponentPb, FightBuffComponentPb, FightBuffInformation}; use wicked_waifus_protocol::entity_component_pb::ComponentPb; +use wicked_waifus_protocol::{ + BuffEffectCd, EntityComponentPb, FightBuffComponentPb, FightBuffInformation, +}; use crate::logic::ecs::component::Component; -use crate::logic::utils::buff_util::add_buff_to_manager; #[derive(Default, Clone)] pub struct FightBuff { pub fight_buff_infos: Vec, - pub permanent_fight_buff_infos: Vec, pub list_buff_effect_cd: Vec, } impl FightBuff { fn get_pb_data(pb: &wicked_waifus_protocol::EntityPb) -> Vec<&FightBuffComponentPb> { - pb.component_pbs.iter() + pb.component_pbs + .iter() .filter_map(|pb| { if let Some(value) = &pb.component_pb { match value { ComponentPb::FightBuffComponent(result) => Some(result), - _ => None + _ => None, } } else { None @@ -31,43 +32,13 @@ impl FightBuff { let pb_data = Self::get_pb_data(pb); match pb_data.get(0) { None => Self::default(), - Some(pb) => { - Self { - fight_buff_infos: pb.fight_buff_infos.clone(), - list_buff_effect_cd: pb.list_buff_effect_cd.clone(), - ..Default::default() - } - } + Some(pb) => Self { + fight_buff_infos: pb.fight_buff_infos.clone(), + list_buff_effect_cd: pb.list_buff_effect_cd.clone(), + ..Default::default() + }, } } - - pub fn add_permanent_buff(&mut self, id: i64) { - self.permanent_fight_buff_infos.push(FightBuffInformation { - handle_id: 0, // TODO: Although permanent buffs dont require a handle it would be best to have them - buff_id: id, - level: 1, - stack_count: 1, - instigator_id: 0, - entity_id: 0, - apply_type: 0, - duration: -1f32, - left_duration: -1f32, - context: vec![], - is_active: true, - server_id: 0, - message_id: 0, - }) - } - - pub fn add_generic_permanent_buffs(&mut self) { - self.add_permanent_buff(3003); // Remove wall run prohibition - self.add_permanent_buff(3004); // Remove gliding prohibition - self.add_permanent_buff(1213); // Reduce stamina while flying - self.add_permanent_buff(1214); // Reduce stamina while flying in sprint - self.add_permanent_buff(1215); // Reduce stamina while flying up in sprint - self.add_permanent_buff(1216); // Reduce stamina while flying down in sprint - self.add_permanent_buff(640012051); // Allow flying - } } impl Component for FightBuff { @@ -77,27 +48,17 @@ impl Component for FightBuff { if let Some(value) = &component_pb.component_pb { match value { ComponentPb::FightBuffComponent(_) => false, - _ => true + _ => true, } } else { true } }); - // Fix Instigator and Entity Id for permanent buffs - let mut fight_buff_infos = self.fight_buff_infos.clone(); - let mut permanent_buffs = self.permanent_fight_buff_infos.clone(); - for buf in &mut permanent_buffs { - buf.instigator_id = pb.id; - buf.entity_id = pb.id; - add_buff_to_manager(buf); - fight_buff_infos.push(buf.clone()); - } - // Add new FightBuffComponent pb.component_pbs.push(EntityComponentPb { component_pb: Some(ComponentPb::FightBuffComponent(FightBuffComponentPb { - fight_buff_infos, + fight_buff_infos: self.fight_buff_infos.clone(), list_buff_effect_cd: self.list_buff_effect_cd.clone(), })), }); diff --git a/wicked-waifus-game-server/src/logic/components/fsm.rs b/wicked-waifus-game-server/src/logic/components/fsm.rs index 35097fc..3f7eb26 100644 --- a/wicked-waifus-game-server/src/logic/components/fsm.rs +++ b/wicked-waifus-game-server/src/logic/components/fsm.rs @@ -1,25 +1,116 @@ -use crate::logic::ecs::component::Component; -use wicked_waifus_protocol::entity_component_pb::ComponentPb; -use wicked_waifus_protocol::{DFsm, DFsmBlackBoard, EntityComponentPb, EntityFsmComponentPb, FsmCustomBlackboardDatas}; +use std::string::ToString; +use std::sync::OnceLock; +use indexmap::IndexMap; +use wicked_waifus_protocol::{DFsm, DFsmBlackBoard, EntityComponentPb, EntityFsmComponentPb, FsmCustomBlackboardDatas}; +use wicked_waifus_protocol::entity_component_pb::ComponentPb; + +use wicked_waifus_data::{ai_base_data, ai_state_machine_config_data, AiStateMachineConfigData, StateMachineJson, StateMachineNode, StateMachineNodeCommon}; + +use crate::logic::ecs::component::Component; + +static COMMON_FSM: OnceLock = OnceLock::new(); + +#[derive(Default)] pub struct Fsm { - pub fsms: Vec, pub hash_code: i32, pub common_hash_code: i32, - pub black_board: Vec, - pub fsm_custom_blackboard_datas: Option, + pub state_list: Vec, + pub node_list: IndexMap, } impl Component for Fsm { fn set_pb_data(&self, pb: &mut wicked_waifus_protocol::EntityPb) { pb.component_pbs.push(EntityComponentPb { component_pb: Some(ComponentPb::EntityFsmComponentPb(EntityFsmComponentPb { - fsms: self.fsms.clone(), + fsms: self.get_initial_fsm(), hash_code: self.hash_code, common_hash_code: self.common_hash_code, - black_board: self.black_board.clone(), - fsm_custom_blackboard_datas: self.fsm_custom_blackboard_datas.clone(), + black_board: self.get_black_board(), + fsm_custom_blackboard_datas: self.get_fsm_custom_blackboard_datas(), })), }) } } + +impl Fsm { + pub fn from_ai_id(ai_id: i32) -> Self { + let ai_base = ai_base_data::get(&ai_id); + let Some(base) = ai_base else { + tracing::error!("Ai Base not found for AI ID: {}", ai_id); + return Self::default(); + }; + + let common_state_machine: &StateMachineJson = &get_common_fsm().state_machine_json; + // Should always be defined since it comes from bindata + let Some(state_machine_config_data) = ai_state_machine_config_data::get(&base.state_machine) else { + tracing::error!("State machine config not found for AI ID: {}", ai_id); + return Self::default(); + }; + let state_machine_config: &StateMachineJson = &state_machine_config_data.state_machine_json; + let mut fsm_tree: IndexMap = IndexMap::with_capacity(state_machine_config.nodes.len()); + for state_machine in &state_machine_config.state_machines { + for node in &state_machine_config.nodes { + match node { + StateMachineNode::Reference(_node) => { + // TODO: + // common_state_machine.nodes.iter() + // .filter_map(|state_machine_node| match state_machine_node { + // StateMachineNode::Reference(_) => None, + // StateMachineNode::Override(_) => None, + // StateMachineNode::Custom(custom) => Some(custom) + // }) + // .find() + } + StateMachineNode::Override(node) => { + // TODO: + tracing::warn!( + "FSM: {state_machine} with override node {} for {} unimplemented", + node.common.uuid, + node.override_common_uuid + ); + } + StateMachineNode::Custom(node) => { + fsm_tree.insert(node.common.uuid, node.common.clone()); + } + } + } + } + Self { + hash_code: state_machine_config.version as i32, + common_hash_code: common_state_machine.version as i32, + state_list: state_machine_config.state_machines.clone(), + node_list: fsm_tree, + } + } + + fn get_initial_fsm(&self) -> Vec { + self.node_list.iter() + .filter_map(|(&id, node)| { + self.state_list.contains(&id).then(|| DFsm { + fsm_id: id, + current_state: node.children.as_ref() + .and_then(|c| c.get(0).cloned()) + .unwrap_or_default(), + flag: 0, // TODO: + k_ts: 0, // TODO: + }) + }).collect::>() + } + + fn get_black_board(&self) -> Vec { + vec![] + } + + fn get_fsm_custom_blackboard_datas(&self) -> Option { + None + } +} + +fn get_common_fsm() -> &'static AiStateMachineConfigData { + COMMON_FSM.get_or_init(|| { + let name = "SM_Common".to_string(); + // Common shall be always defined + ai_state_machine_config_data::get(&name).cloned().unwrap() + }) +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/components/mod.rs b/wicked-waifus-game-server/src/logic/components/mod.rs index 6fc4cff..8998a70 100644 --- a/wicked-waifus-game-server/src/logic/components/mod.rs +++ b/wicked-waifus-game-server/src/logic/components/mod.rs @@ -3,7 +3,7 @@ mod entity_config; mod equip; mod movement; mod owner_player; -mod player_entity_marker; +mod player_owned_entity_marker; mod position; mod visibility; mod vision_skill; @@ -15,13 +15,15 @@ mod state_tag; mod tag; mod autonomous; mod interact; +mod concomitant; +mod summoner; pub use attribute::Attribute; pub use entity_config::EntityConfig; pub use equip::Equip; pub use movement::Movement; pub use owner_player::OwnerPlayer; -pub use player_entity_marker::PlayerEntityMarker; +pub use player_owned_entity_marker::PlayerOwnedEntityMarker; pub use position::Position; pub use visibility::Visibility; pub use vision_skill::VisionSkill; @@ -33,3 +35,5 @@ pub use state_tag::StateTag; pub use tag::Tag; pub use autonomous::Autonomous; pub use interact::Interact; +pub use concomitant::Concomitant; +pub use summoner::Summoner; diff --git a/wicked-waifus-game-server/src/logic/components/player_entity_marker.rs b/wicked-waifus-game-server/src/logic/components/player_owned_entity_marker.rs similarity index 50% rename from wicked-waifus-game-server/src/logic/components/player_entity_marker.rs rename to wicked-waifus-game-server/src/logic/components/player_owned_entity_marker.rs index 48593d3..d11d95d 100644 --- a/wicked-waifus-game-server/src/logic/components/player_entity_marker.rs +++ b/wicked-waifus-game-server/src/logic/components/player_owned_entity_marker.rs @@ -2,10 +2,12 @@ use wicked_waifus_protocol::EEntityType; use crate::logic::ecs::component::Component; -pub struct PlayerEntityMarker; +pub struct PlayerOwnedEntityMarker { + pub entity_type: EEntityType, +} -impl Component for PlayerEntityMarker { +impl Component for PlayerOwnedEntityMarker { fn set_pb_data(&self, pb: &mut wicked_waifus_protocol::EntityPb) { - pb.entity_type = EEntityType::Player.into(); + pb.entity_type = self.entity_type.into(); } } diff --git a/wicked-waifus-game-server/src/logic/components/summoner.rs b/wicked-waifus-game-server/src/logic/components/summoner.rs new file mode 100644 index 0000000..9f1bf54 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/components/summoner.rs @@ -0,0 +1,24 @@ +use wicked_waifus_protocol::{EntityComponentPb, summon::SummonerComponentPb}; +use wicked_waifus_protocol::entity_component_pb::ComponentPb; + +use crate::logic::ecs::component::Component; + +pub struct Summoner { + pub summon_cfg_id: i32, + pub summon_skill_id: i32, + pub summon_type: i32, +} + +impl Component for Summoner { + fn set_pb_data(&self, pb: &mut wicked_waifus_protocol::EntityPb) { + pb.component_pbs.push(EntityComponentPb { + component_pb: Some(ComponentPb::SummonerComponent(SummonerComponentPb { + summoner_id: pb.id + 1, + summon_cfg_id: self.summon_cfg_id, + summon_skill_id: self.summon_skill_id, + player_id: pb.player_id, + r#type: self.summon_type, + })), + }) + } +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/components/visibility.rs b/wicked-waifus-game-server/src/logic/components/visibility.rs index d736e90..0d6f6a5 100644 --- a/wicked-waifus-game-server/src/logic/components/visibility.rs +++ b/wicked-waifus-game-server/src/logic/components/visibility.rs @@ -1,9 +1,13 @@ use crate::logic::ecs::component::Component; -pub struct Visibility(pub bool); +pub struct Visibility { + pub is_visible: bool, + pub is_actor_visible: bool, +} impl Component for Visibility { fn set_pb_data(&self, pb: &mut wicked_waifus_protocol::EntityPb) { - pb.is_visible = self.0; + pb.is_visible = self.is_visible; + pb.is_actor_visible = self.is_actor_visible; } } diff --git a/wicked-waifus-game-server/src/logic/ecs/buf.rs b/wicked-waifus-game-server/src/logic/ecs/buf.rs new file mode 100644 index 0000000..6ae527b --- /dev/null +++ b/wicked-waifus-game-server/src/logic/ecs/buf.rs @@ -0,0 +1,94 @@ +use std::collections::{HashMap, VecDeque}; +use std::sync::atomic::{AtomicI32, Ordering}; +use wicked_waifus_protocol::FightBuffInformation; + +pub struct BufManager { + active_buf_set: HashMap, + next_handle: AtomicI32, + recycled_handles: HashMap>, +} + +impl BufManager { + const PERMANENT_ROLE_BUFFS: &'static [i64] = &[ + 3003, // Remove wall run prohibition + 3004, // Remove gliding prohibition + 1213, // Reduce stamina while flying + 1214, // Reduce stamina while flying in sprint + 1215, // Reduce stamina while flying up in sprint + 1216, // Reduce stamina while flying down in sprint + 640012051, // Allow flying -> tag: 1151923109 + ]; + + pub fn create(&mut self, buf: &mut FightBuffInformation) { + let handle = self + .recycled_handles + .get_mut(&buf.handle_id) + .and_then(|ids| ids.pop_front()) + .unwrap_or_else(|| self.next_handle.fetch_add(1, Ordering::Relaxed)); + + buf.handle_id = handle; + buf.server_id = handle; + buf.message_id = handle as i64; + + self.active_buf_set.entry(handle).or_insert(buf.clone()); + } + + #[inline(always)] + pub fn remove_entity_buffs(&mut self, entity_id: i64) { + let handles = self.active_buf_set.iter() + .filter(|(_, buff)| buff.entity_id == entity_id) + .map(|(&handle, _)| handle) + .collect::>(); + for handle in handles { + self.remove(handle); + } + } + + #[inline(always)] + pub fn remove(&mut self, handle: i32) -> bool { + if let Some(buf) = self.active_buf_set.remove(&handle) { + self.recycled_handles + .entry(handle) + .or_default() + .push_back(buf.handle_id); + true + } else { + false + } + } + + pub fn create_permanent_buffs(&mut self, origin_id: i64) -> Vec { + Self::PERMANENT_ROLE_BUFFS + .iter() + .map(|&id| { + let mut buff = FightBuffInformation { + handle_id: 0, + buff_id: id, + level: 1, + stack_count: 1, + instigator_id: origin_id, + entity_id: origin_id, + apply_type: 0, + duration: -1f32, + left_duration: -1f32, + context: vec![], + is_active: true, + server_id: 0, + message_id: 0, + }; + self.create(&mut buff); + buff + }) + .collect::>() + } +} + +impl Default for BufManager { + fn default() -> Self { + Self { + active_buf_set: Default::default(), + next_handle: AtomicI32::new(1), + recycled_handles: Default::default(), + } + } +} diff --git a/wicked-waifus-game-server/src/logic/ecs/component.rs b/wicked-waifus-game-server/src/logic/ecs/component.rs index ec2974f..e501af9 100644 --- a/wicked-waifus-game-server/src/logic/ecs/component.rs +++ b/wicked-waifus-game-server/src/logic/ecs/component.rs @@ -28,7 +28,7 @@ impl_component_container! { OwnerPlayer; Visibility; Attribute; - PlayerEntityMarker; + PlayerOwnedEntityMarker; Movement; Equip; VisionSkill; @@ -40,6 +40,8 @@ impl_component_container! { Tag; Autonomous; Interact; + Concomitant; + Summoner; } pub trait Component { diff --git a/wicked-waifus-game-server/src/logic/ecs/entity.rs b/wicked-waifus-game-server/src/logic/ecs/entity.rs index 164cc7e..9353506 100644 --- a/wicked-waifus-game-server/src/logic/ecs/entity.rs +++ b/wicked-waifus-game-server/src/logic/ecs/entity.rs @@ -124,12 +124,12 @@ impl<'comp> EntityBuilder<'comp> { Self(entity, components) } - pub fn with(self, component: ComponentContainer) -> Self { + pub fn with(&mut self, component: ComponentContainer) -> &mut Self { self.1.push(RefCell::new(component)); self } - pub fn build(self) -> Entity { + pub fn build(&self) -> Entity { self.0 } } diff --git a/wicked-waifus-game-server/src/logic/ecs/mod.rs b/wicked-waifus-game-server/src/logic/ecs/mod.rs index 2a9b916..e48d54f 100644 --- a/wicked-waifus-game-server/src/logic/ecs/mod.rs +++ b/wicked-waifus-game-server/src/logic/ecs/mod.rs @@ -1,6 +1,7 @@ pub mod component; pub mod entity; pub mod world; +pub mod buf; #[macro_export] macro_rules! find_component { diff --git a/wicked-waifus-game-server/src/logic/ecs/world.rs b/wicked-waifus-game-server/src/logic/ecs/world.rs index 0ceee0a..3692c68 100644 --- a/wicked-waifus-game-server/src/logic/ecs/world.rs +++ b/wicked-waifus-game-server/src/logic/ecs/world.rs @@ -1,13 +1,16 @@ use super::component::ComponentContainer; use super::entity::{Entity, EntityBuilder, EntityManager}; +use crate::logic::ecs::buf::BufManager; use crate::logic::player::InWorldPlayer; use std::cell::{RefCell, RefMut}; use std::collections::hash_map::{Keys, Values}; use std::collections::HashMap; +use wicked_waifus_protocol::FightBuffInformation; pub struct WorldEntity { components: HashMap>>, entity_manager: EntityManager, + buff_manager: BufManager, } pub struct World { @@ -52,13 +55,11 @@ impl World { } impl WorldEntity { - pub fn create_entity( - &mut self, - config_id: i32, - entity_type: i32, - map_id: i32, - ) -> EntityBuilder { - let entity = self.entity_manager.create(config_id, entity_type, map_id); + pub fn create_entity(&mut self, config_id: i32, entity_type: i32, map_id: i32) -> Entity { + self.entity_manager.create(config_id, entity_type, map_id) + } + + pub fn create_builder(&mut self, entity: Entity) -> EntityBuilder { EntityBuilder::builder( entity, self.components @@ -102,12 +103,17 @@ impl WorldEntity { } pub fn remove_entity(&mut self, entity_id: i32) -> bool { + self.buff_manager.remove_entity_buffs(entity_id as i64); self.components.remove(&entity_id).is_some() && self.entity_manager.remove(entity_id) } pub fn active_entity_empty(&self) -> bool { self.entity_manager.active_entity_empty() } + + pub fn generate_role_permanent_buffs(&mut self, entity_id: i64) -> Vec { + self.buff_manager.create_permanent_buffs(entity_id) + } } impl Default for WorldEntity { @@ -115,6 +121,7 @@ impl Default for WorldEntity { Self { components: HashMap::new(), entity_manager: EntityManager::default(), + buff_manager: BufManager::default(), } } } diff --git a/wicked-waifus-game-server/src/logic/gacha/gacha_pool.rs b/wicked-waifus-game-server/src/logic/gacha/gacha_pool.rs index c0b7397..6d6d19f 100644 --- a/wicked-waifus-game-server/src/logic/gacha/gacha_pool.rs +++ b/wicked-waifus-game-server/src/logic/gacha/gacha_pool.rs @@ -1,16 +1,18 @@ use rand::prelude::IndexedRandom; use rand::Rng; - -use wicked_waifus_data::GachaViewTypeInfoId::{BeginnersChoiceConvene, - FeaturedResonatorConvene, - FeaturedWeaponConvene, - NoviceConvene, - StandardResonatorConvene, - StandardWeaponConvene, -}; use wicked_waifus_protocol::{ErrorCode, GachaResult, GachaReward}; +use wicked_waifus_data::GachaViewTypeInfoId::{BeginnersChoiceConvene, + FeaturedResonatorConvene, + FeaturedWeaponConvene, + NoviceConvene, + StandardResonatorConvene, + StandardWeaponConvene, +}; + use crate::logic::gacha::pool_info::PoolInfo; +use crate::logic::player::Player; +use crate::logic::role::Role; pub struct PoolRates { pub three_star: f32, @@ -51,25 +53,26 @@ impl GachaPool { } } - pub fn pull(&mut self, rng: &mut T) -> Result { + pub fn pull(&mut self, + rng: &mut T, + player: &mut Player) -> Result { self.check_limits()?; let result = if (self.info.pool_type == BeginnersChoiceConvene) && (self.info.pool_id > 50) && (self.info.pool_id < 60) { - let item_id = self.info.guaranteed_character_id.unwrap(); GachaResult { gacha_reward: Some(GachaReward { item_id, item_count: 1 }), extra_rewards: self.calculate_extra_rewards(2), - transform_rewards: Vec::new(), + transform_rewards: Self::get_transform_rewards(player, item_id), bottom: None, } } else { let rarity = self.determine_rarity(&self.calculate_probabilities(), rng); - let item_id= match self.info.pool_type { + let item_id = match self.info.pool_type { FeaturedResonatorConvene => { let item_id = if rarity == 2 { - if self.rate_up || rng.gen_bool(0.5) { + if self.rate_up || rng.random_bool(0.5) { self.rate_up = false; self.info.guaranteed_character_id.unwrap_or(0) } else { @@ -89,7 +92,7 @@ impl GachaPool { GachaResult { gacha_reward: Some(GachaReward { item_id, item_count: 1 }), extra_rewards: self.calculate_extra_rewards(rarity), - transform_rewards: Vec::new(), + transform_rewards: Self::get_transform_rewards(player, item_id), bottom: None, } }; @@ -98,6 +101,26 @@ impl GachaPool { Ok(result) } + fn get_transform_rewards(player: &mut Player, item_id: i32) -> Vec { + let mut transform_rewards = Vec::new(); + let required_role_ids: Vec = Role::get_all_roles_except_mc(); + match player.role_list.get(&item_id) { + None => { + if required_role_ids.contains(&item_id) { + player.role_list.insert(item_id, Role::new(item_id)); + } + } + Some(role) => { + // TODO: Even if we have, we can't get more than six wavebands, make a check + transform_rewards.push(GachaReward { + item_id: 10000000 + role.role_id, + item_count: 1, + }) // TODO: get from role data + } + } + transform_rewards + } + fn get_random_item(&self, rarity: usize, rng: &mut impl Rng) -> i32 { let items: &[i32] = match rarity { 0 => &[21010013, 21020013, 21030013, 21040013, 21050013, 21010023, 21020023, 21030023, 21040023, 21050023, 21010043, 21020043, 21030043, 21040043, 21050043], @@ -147,7 +170,7 @@ impl GachaPool { } fn determine_rarity(&self, prob: &[f32; 3], rng: &mut impl Rng) -> usize { - let roll: f32 = rng.gen_range(0.0..100.0); + let roll: f32 = rng.random_range(0.0..100.0); match (roll < prob[2], roll < prob[2] + prob[1]) { (true, _) => 2, // 5-star (_, true) => 1, // 4-star diff --git a/wicked-waifus-game-server/src/logic/gacha/service.rs b/wicked-waifus-game-server/src/logic/gacha/service.rs index 2204afa..68597d1 100644 --- a/wicked-waifus-game-server/src/logic/gacha/service.rs +++ b/wicked-waifus-game-server/src/logic/gacha/service.rs @@ -17,6 +17,7 @@ use wicked_waifus_protocol::{ErrorCode, GachaResult}; use crate::logic::gacha::category::PoolCategory; use crate::logic::gacha::gacha_pool::GachaPool; use crate::logic::gacha::pool_info::PoolInfo; +use crate::logic::player::Player; pub struct GachaService { pools: HashMap, @@ -57,7 +58,10 @@ impl GachaService { pools } - pub fn pull(&mut self, pool_id: i32, times: i32) -> Result, ErrorCode> { + pub fn pull(&mut self, + player: &mut Player, + pool_id: i32, + times: i32) -> Result, ErrorCode> { let pool = self.pools.get_mut(&pool_id) .ok_or(ErrorCode::ErrGachaPoolConfigNotFound)?; @@ -69,7 +73,7 @@ impl GachaService { let mut results = Vec::new(); for _ in 0..times { - match pool.pull(&mut self.rng) { + match pool.pull(&mut self.rng, player) { Ok(result) => results.push(result), Err(error_code) => return Err(error_code), } @@ -85,6 +89,7 @@ impl GachaService { .collect() } + #[allow(dead_code)] pub fn get_all_pools(&self) -> Vec<(i32, &PoolInfo)> { self.pools.iter() .map(|(id, pool)| (*id, &pool.info)) diff --git a/wicked-waifus-game-server/src/logic/handler/advice.rs b/wicked-waifus-game-server/src/logic/handler/advice.rs new file mode 100644 index 0000000..92291d7 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/handler/advice.rs @@ -0,0 +1,13 @@ +use wicked_waifus_protocol::{AdviceSetRequest, AdviceSetResponse, ErrorCode}; +use crate::logic::player::Player; + +pub fn on_advice_set_request( + player: &mut Player, + request: AdviceSetRequest, + response: &mut AdviceSetResponse, +) { + player.advise.is_show = request.is_show; + + response.is_show = request.is_show; + response.error_code = ErrorCode::Success.into(); +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/handler/animal.rs b/wicked-waifus-game-server/src/logic/handler/animal.rs new file mode 100644 index 0000000..a2c7b45 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/handler/animal.rs @@ -0,0 +1,65 @@ +use wicked_waifus_protocol::{AnimalDestroyRequest, AnimalDestroyResponse, AnimalDieRequest, AnimalDieResponse, AnimalDropRequest, AnimalDropResponse, EEntityType, ERemoveEntityType, EntityLivingStatusNotify, ErrorCode, LivingStatus}; + +use crate::logic::ecs::component::ComponentContainer; +use crate::logic::player::Player; +use crate::logic::utils::world_util; +use crate::query_components; + +pub fn on_animal_die_request( + player: &mut Player, + request: AnimalDieRequest, + response: &mut AnimalDieResponse, +) { + tracing::warn!("AnimalDieRequest not fully implemented"); + player.notify(EntityLivingStatusNotify { + id: request.entity_id, + living_status: LivingStatus::Dead.into(), + drop_vision_item: vec![], + }); + get_animal_reward(); + response.error_code = ErrorCode::Success.into(); +} + +pub fn on_animal_drop_request( + _player: &mut Player, + _request: AnimalDropRequest, + response: &mut AnimalDropResponse, +) { + tracing::warn!("AnimalDropRequest not fully implemented"); + // Example for: 16818 - 166901770 + get_animal_reward(); + response.error_code = ErrorCode::Success.into(); +} + +pub fn on_animal_destroy_request( + player: &mut Player, + request: AnimalDestroyRequest, + response: &mut AnimalDestroyResponse, +) { + { + let entity_id = request.entity_id; + let world_ref = player.world.borrow(); + let world = world_ref.get_world_entity(); + let (Some(config), ) = query_components!(world,entity_id,EntityConfig) else { + response.error_code = ErrorCode::ErrAnimalEntityNotExist.into(); + return; + }; + if config.entity_type != EEntityType::Animal { + response.error_code = ErrorCode::ErrNotAnimalEntity.into(); + } + } + world_util::remove_entity(player, request.entity_id, ERemoveEntityType::RemoveTypeNormal); + response.error_code = ErrorCode::Success.into(); +} + +fn get_animal_reward() { + // TODO: + // get entity->config_id, + // from level entity get reference, + // merge level entity with template, + // extract reward component + // get by reward id from DropPackage.json + // NormalItemUpdateNotify + // UpdateHandBookActiveStateMapNotify + // ItemRewardNotify +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/handler/chat.rs b/wicked-waifus-game-server/src/logic/handler/chat.rs index 8af2a0e..b653d63 100644 --- a/wicked-waifus-game-server/src/logic/handler/chat.rs +++ b/wicked-waifus-game-server/src/logic/handler/chat.rs @@ -1,8 +1,6 @@ use tracing::debug; -use wicked_waifus_protocol::{ErrorCode, PrivateChatHistoryRequest, PrivateChatHistoryResponse, - PrivateChatOperateRequest, PrivateChatOperateResponse, - PrivateChatOperateType, PrivateChatRequest, PrivateChatResponse}; +use wicked_waifus_protocol::{ErrorCode, PrivateChatDataRequest, PrivateChatDataResponse, PrivateChatHistoryRequest, PrivateChatHistoryResponse, PrivateChatOperateRequest, PrivateChatOperateResponse, PrivateChatOperateType, PrivateChatRequest, PrivateChatResponse}; use crate::logic::player::Player; @@ -43,20 +41,12 @@ pub fn on_private_chat_request( }; } -pub fn on_private_chat_operate_request( - _player: &Player, - request: PrivateChatOperateRequest, - response: &mut PrivateChatOperateResponse, +pub fn on_private_chat_data_request( + _: &Player, + _: PrivateChatDataRequest, + _: &mut PrivateChatDataResponse, ) { - let operate_type = PrivateChatOperateType::try_from(request.operate_type).unwrap(); - if operate_type == PrivateChatOperateType::ReadMsg && request.target_player_id == 0 { - // TODO: Additional actions? - response.error_code = ErrorCode::Success.into(); - } else { - // TODO: Additional checks - debug!("on_private_chat_operate_request called for unimplemented case: {:?}", request); - response.error_code = ErrorCode::Success.into(); - } + } pub fn on_private_chat_history_request( @@ -75,3 +65,20 @@ pub fn on_private_chat_history_request( Err(error_code) => response.error_code = error_code } } + + +pub fn on_private_chat_operate_request( + _player: &Player, + request: PrivateChatOperateRequest, + response: &mut PrivateChatOperateResponse, +) { + let operate_type = PrivateChatOperateType::try_from(request.operate_type).unwrap(); + if operate_type == PrivateChatOperateType::ReadMsg && request.target_player_id == 0 { + // TODO: Additional actions? + response.error_code = ErrorCode::Success.into(); + } else { + // TODO: Additional checks + debug!("on_private_chat_operate_request called for unimplemented case: {:?}", request); + response.error_code = ErrorCode::Success.into(); + } +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/handler/combat.rs b/wicked-waifus-game-server/src/logic/handler/combat.rs index 2a58c63..901d4c3 100644 --- a/wicked-waifus-game-server/src/logic/handler/combat.rs +++ b/wicked-waifus-game-server/src/logic/handler/combat.rs @@ -1,10 +1,16 @@ -use crate::logic::player::Player; use wicked_waifus_protocol::combat_message::{ - combat_receive_data, combat_request_data, combat_response_data, combat_send_data, - CombatReceiveData, CombatRequestData, CombatResponseData, CombatSendPackRequest, - CombatSendPackResponse, + combat_notify_data, combat_receive_data, combat_request_data, combat_response_data, + combat_send_data, CombatNotifyData, CombatReceiveData, CombatRequestData, CombatResponseData, + CombatSendPackRequest, CombatSendPackResponse, }; -use wicked_waifus_protocol::{ErrorCode, SwitchRoleRequest, SwitchRoleResponse}; +use wicked_waifus_protocol::{AttributeChangedNotify, CombatCommon, DamageExecuteRequest, DamageExecuteResponse, EAttributeType, ERemoveEntityType, EntityRemoveNotify, ErrorCode, GameplayAttributeData, SwitchRoleRequest, SwitchRoleResponse}; + +use wicked_waifus_data::damage_data; + +use crate::logic::ecs::component::ComponentContainer; +use crate::logic::player::Player; +use crate::logic::utils::world_util; +use crate::query_components; #[inline(always)] fn create_combat_response( @@ -22,6 +28,21 @@ fn create_combat_response( } } +#[inline(always)] +fn create_combat_notify( + combat_common: CombatCommon, + message: combat_notify_data::Message, +) -> CombatReceiveData { + CombatReceiveData { + message: Some(combat_receive_data::Message::CombatNotifyData( + CombatNotifyData { + combat_common: Some(combat_common), + message: Some(message), + }, + )), + } +} + pub fn on_combat_message_combat_send_pack_request( player: &mut Player, request: CombatSendPackRequest, @@ -34,6 +55,9 @@ pub fn on_combat_message_combat_send_pack_request( combat_request_data::Message::SwitchRoleRequest(ref request) => { handle_switch_role_request(player, request_data, request, response); } + combat_request_data::Message::DamageExecuteRequest(ref request) => { + handle_damage_execute_request(player, request_data, request, response); + } _ => {} } } @@ -71,3 +95,87 @@ fn handle_switch_role_request( response.error_code = ErrorCode::Success.into(); } + +fn handle_damage_execute_request( + player: &mut Player, + combat_request: &CombatRequestData, + request: &DamageExecuteRequest, + response: &mut CombatSendPackResponse, +) { + let receive_pack = response + .receive_pack_notify + .get_or_insert_with(Default::default); + + let mut world_ref = player.world.borrow_mut(); + let world = world_ref.get_mut_world_entity(); + let config_id = world.get_config_id(request.attacker_entity_id.try_into().unwrap()); + let mut damage = 1; // TODO: Fix the formula with real parameters(10 field equation) + if config_id.to_string().len() == 4 { + if let Some(damage_data) = damage_data::iter().find(|d| d.id == request.damage_id) { + let attribute = query_components!(world, request.attacker_entity_id, Attribute) + .0 + .unwrap(); + if let Ok(related_attribute) = EAttributeType::try_from(damage_data.related_property) { + if let Some((value, _)) = attribute.attr_map.get(&related_attribute) { + if let Some(&rate_lv) = damage_data.rate_lv.iter().find(|&lvl| *lvl == request.skill_level) { + let hardness_lv = damage_data.hardness_lv[0]; + tracing::info!( + "atk: {}, damage_id: {}, role_id: {}, rate_lv: {}, hardness_lv: {}", + value, + request.damage_id, + config_id, + rate_lv, + hardness_lv + ); + damage = if hardness_lv == 0 || rate_lv <= 0 { + 1 + } else { + ((rate_lv as f32 / hardness_lv as f32) * 100.0 + (*value as f32)) as i32 + }; + } + } + }; + } + } + receive_pack.data.push(create_combat_response( + combat_request, + combat_response_data::Message::DamageExecuteResponse(DamageExecuteResponse { + error_code: ErrorCode::Success.into(), + attacker_entity_id: request.attacker_entity_id, + target_entity_id: request.target_entity_id, + part_index: request.part_index, + damage, + ..Default::default() + }), + )); + if let Some((value, _)) = query_components!(world, request.target_entity_id, Attribute) + .0 + .unwrap() + .attr_map + .get(&EAttributeType::Life) + { + let updated_value = match value - damage >= 0 { + true => value - damage, + false => 0, + }; + receive_pack.data.push(create_combat_notify( + CombatCommon { + entity_id: request.target_entity_id, + ..Default::default() + }, + combat_notify_data::Message::AttributeChangedNotify(AttributeChangedNotify { + id: request.target_entity_id, + attributes: vec![GameplayAttributeData { + current_value: updated_value, + value_increment: updated_value, + attribute_type: EAttributeType::Life.into(), + }], + }), + )); + if updated_value == 0 { + world_util::remove_entity(player, request.target_entity_id, ERemoveEntityType::HpIsZero); + } + } + + response.error_code = ErrorCode::Success.into(); +} diff --git a/wicked-waifus-game-server/src/logic/handler/coop.rs b/wicked-waifus-game-server/src/logic/handler/coop.rs new file mode 100644 index 0000000..5848b4c --- /dev/null +++ b/wicked-waifus-game-server/src/logic/handler/coop.rs @@ -0,0 +1,18 @@ +use wicked_waifus_protocol::{ErrorCode, LobbyListRequest, LobbyListResponse}; +use crate::logic::player::Player; + +pub fn on_lobby_list_request( + _player: &mut Player, + request: LobbyListRequest, + response: &mut LobbyListResponse, +) { + match request.is_friend { + true => { + tracing::debug!("Requesting list of friends lobbies"); + } + false => { + tracing::debug!("Requesting list of open lobbies"); + } + } + response.error_code = ErrorCode::Success.into(); +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/handler/dummy.rs b/wicked-waifus-game-server/src/logic/handler/dummy.rs index 257b137..3169208 100644 --- a/wicked-waifus-game-server/src/logic/handler/dummy.rs +++ b/wicked-waifus-game-server/src/logic/handler/dummy.rs @@ -12,7 +12,9 @@ macro_rules! dummy_handler { _player: &Player, _request: [<$type_name Request>], _response: &mut [<$type_name Response>], - ) {} + ) { + tracing::warn!("Unhandled dummy request: {}", stringify!([<$type_name:snake _request>])); + } })* }; } @@ -21,35 +23,32 @@ macro_rules! dummy_handler { dummy_handler! { RoleVisionRecommendData; RoleVisionRecommendAttr; - PlayerMotion; GetFormationData; FishingData; EnergySync; GetDetectionLabelInfo; - TutorialInfo; - MonthCard; InfluenceInfo; ForgeInfo; AchievementInfo; ExchangeReward; Liveness; - WebSign; PhotoMemory; WeaponSkin; VisionEquipGroupInfo; UpdatePlayStationBlockAccount; AdventureManual; - MapTraceInfo; Tower; ExploreProgress; ReportData; - UpdateVoxelEnv; SimpleTrackReportAsync; TowerSeasonUpdate; - FriendAll; - NormalItem; - WeaponItem; - PhantomItem; ValidTimeItem; - ItemExchangeInfo; + PayShopInfo; + InitRange; + Activity; + BattlePass; + SlashAndTowerInfo; + EntityPatrolStop; + Advice; + PlayerTitleData; } \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/handler/entity.rs b/wicked-waifus-game-server/src/logic/handler/entity.rs index b63f63c..7626be5 100644 --- a/wicked-waifus-game-server/src/logic/handler/entity.rs +++ b/wicked-waifus-game-server/src/logic/handler/entity.rs @@ -1,9 +1,10 @@ -use wicked_waifus_protocol::{EntityActiveRequest, EntityActiveResponse, EntityLoadCompleteRequest, - EntityLoadCompleteResponse, EntityOnLandedRequest, - EntityOnLandedResponse, EntityPb, EntityPositionRequest, - EntityPositionResponse, ErrorCode, MovePackagePush}; +use wicked_waifus_protocol::{EntityAccessInfo, EntityAccessRangeRequest, EntityAccessRangeResponse, EntityActiveRequest, EntityActiveResponse, EntityFollowTrackRequest, EntityFollowTrackResponse, EntityInteractRequest, EntityInteractResponse, EntityOnLandedRequest, EntityOnLandedResponse, EntityPb, EntityPositionRequest, EntityPositionResponse, ErrorCode, GetRewardTreasureBoxRequest, GetRewardTreasureBoxResponse, MovePackagePush}; + +use wicked_waifus_data::pb_components::option::OptionType; use crate::{logic, logic::ecs::component::ComponentContainer, logic::player::Player, query_components}; +use crate::logic::utils::action_utils::perform_action; +use crate::logic::utils::condition_utils::check_condition; pub fn on_entity_active_request( player: &Player, @@ -80,18 +81,6 @@ pub fn on_entity_position_request( ); } -pub fn on_entity_load_complete_request( - _: &Player, - request: EntityLoadCompleteRequest, - _: &mut EntityLoadCompleteResponse, -) { - // TODO: Implement this - tracing::debug!( - "EntityLoadCompleteRequest: for ids {:?}", - request.entity_ids - ); -} - pub fn on_move_package_push(player: &mut Player, push: MovePackagePush) { for moving_entity in push.moving_entities { // Query components borrows world component so lets wrap it @@ -121,8 +110,7 @@ pub fn on_move_package_push(player: &mut Player, push: MovePackagePush) { .extend(moving_entity.move_infos); } - // TODO: review instance id vs map id in world - let map = logic::utils::quadrant_util::get_map(player.location.instance_id); + let map = logic::utils::quadrant_util::get_map(player.basic_info.cur_map_id); let quadrant_id = map.get_quadrant_id( player.location.position.position.x * 100.0, player.location.position.position.y * 100.0, @@ -133,7 +121,122 @@ pub fn on_move_package_push(player: &mut Player, push: MovePackagePush) { let (entities_to_remove, entities_to_add) = map.get_update_entities(player.quadrant_id, quadrant_id); player.quadrant_id = quadrant_id; logic::utils::world_util::remove_entities(player, &entities_to_remove); - logic::utils::world_util::add_entities(player, &entities_to_add); + logic::utils::world_util::add_entities(player, &entities_to_add, false); } } } + +pub fn on_entity_access_range_request( + _: &Player, + request: EntityAccessRangeRequest, + response: &mut EntityAccessRangeResponse, +) { + // TODO: from world fetch entity by request.entity_id + // TODO: Compute the distance between player and entity.entity_id + response.error_code = ErrorCode::Success.into(); + response.entity_id = request.entity_id; + let mut infos = Vec::new(); + for range_request in request.entities_to_check { + infos.push(EntityAccessInfo { + entity_id: range_request, + range_type: request.range_type, + uo_1: Default::default(), + }) + } + response.info = infos; +} + +pub fn on_entity_interact_request( + player: &mut Player, + request: EntityInteractRequest, + response: &mut EntityInteractResponse, +) { + let config_id = get_config_id_from_entity_id(player, request.entity_id); + tracing::debug!("EntityInteractRequest with ID: {} and ConfigID {}", request.entity_id, config_id); + + // TODO: add cases outside LevelEntityConfig if exist + let Some(entity) = wicked_waifus_data::level_entity_config_data::get(player.basic_info.cur_map_id, config_id) else { + response.error_code = ErrorCode::ErrEntityNotFound.into(); + return; + }; + + let Some(template_config) = wicked_waifus_data::template_config_data::get(&entity.blueprint_type) else { + response.error_code = ErrorCode::ErrEntityNotFound.into(); + return; + }; + + let Some(interact_component) = entity.components_data.interact_component.as_ref() + .or(template_config.components_data.interact_component.as_ref()).cloned() else { + response.error_code = ErrorCode::ErrInteractComponentNotExist.into(); + return; + }; + + let Some(options) = interact_component.options else { + response.error_code = ErrorCode::ErrActionNoInteractConfig.into(); + return; + }; + for option in options { + let mut check = true; + if let Some(conditions) = option.condition { + for element in conditions.conditions { + check = check_condition(player, request.entity_id, &entity, template_config, element); + if !check { + break; + } + } + } + if check { + if let Some(option_type) = option.r#type { + match option_type { + OptionType::Actions(actions) => { + for action in actions.actions { + perform_action(player, request.entity_id, &entity, template_config, action); + } + } + OptionType::Flow(_) => { + tracing::warn!("Option Type: Flow not implemented"); + } + }; + } + } + } + + response.error_code = ErrorCode::Success.into(); + response.interacting = true; +} + +pub fn on_entity_follow_track_request( + player: &Player, + request: EntityFollowTrackRequest, + response: &mut EntityFollowTrackResponse, +) { + let config_id = get_config_id_from_entity_id(player, request.entity_id); + let position = { + let world_ref = player.world.borrow(); + let world = world_ref.get_world_entity(); + let position = query_components!(world, request.entity_id, Position).0.unwrap(); + position.0.clone() + }; + tracing::debug!( + "EntityFollowTrackRequest with ID: {} and ConfigID {config_id} and position {position:?}", + request.entity_id + ); + + response.error_code = ErrorCode::Success.into(); +} + +pub fn on_get_reward_treasure_box_request( + player: &Player, + request: GetRewardTreasureBoxRequest, + _response: &mut GetRewardTreasureBoxResponse, +) { + let config_id = get_config_id_from_entity_id(player, request.entity_id); + tracing::debug!("GetRewardTreasureBoxRequest with ID: {} and ConfigID {config_id}", request.entity_id); +} + +fn get_config_id_from_entity_id(player: &Player, entity_id: i64) -> i64 { + let world_ref = player.world.borrow(); + let world = world_ref.get_world_entity(); + let entity_config = query_components!(world, entity_id, EntityConfig).0.unwrap(); + entity_config.config_id as i64 +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/handler/friend.rs b/wicked-waifus-game-server/src/logic/handler/friend.rs index 1a47c24..7689e0a 100644 --- a/wicked-waifus-game-server/src/logic/handler/friend.rs +++ b/wicked-waifus-game-server/src/logic/handler/friend.rs @@ -1,28 +1,84 @@ -use wicked_waifus_protocol::{FriendApplySendRequest, FriendApplySendResponse, - FriendRecentlyTeamRequest, FriendRecentlyTeamResponse, - PlayerBasicInfoGetRequest, PlayerBasicInfoGetResponse}; use crate::logic::player::Player; +use wicked_waifus_protocol::{ + ErrorCode, FriendAllRequest, FriendAllResponse, FriendInfo, PlayerBasicInfoGetRequest, + PlayerBasicInfoGetResponse, PlayerDetails, +}; -pub fn on_friend_apply_send_request( +pub fn on_friend_all_request( _player: &Player, - _request: FriendApplySendRequest, - _response: &mut FriendApplySendResponse, + _: FriendAllRequest, + response: &mut FriendAllResponse, ) { + // TODO: Fill from player + response.friend_apply_list = vec![]; + // TODO: Fill from player + let mut friends = vec![]; + friends.push(FriendInfo { + info: Some(get_bot_details()), + remark: "".to_string(), + }); + response.friend_info_list = friends; + response.error_code = ErrorCode::Success.into(); } -pub fn on_friend_recently_team_request( - _player: &Player, - _request: FriendRecentlyTeamRequest, - _response: &mut FriendRecentlyTeamResponse, -) { - -} +// pub fn on_friend_apply_send_request( +// _player: &Player, +// _request: FriendApplySendRequest, +// _response: &mut FriendApplySendResponse, +// ) { +// +// } +// +// pub fn on_friend_recently_team_request( +// _player: &Player, +// _request: FriendRecentlyTeamRequest, +// _response: &mut FriendRecentlyTeamResponse, +// ) { +// +// } pub fn on_player_basic_info_get_request( _player: &Player, - _request: PlayerBasicInfoGetRequest, - _response: &mut PlayerBasicInfoGetResponse, + request: PlayerBasicInfoGetRequest, + response: &mut PlayerBasicInfoGetResponse, ) { + if request.id == 1337 { + response.info = Some(get_bot_details()); + response.error_code = ErrorCode::Success.into(); + } else { + // TODO: Search in database + response.error_code = ErrorCode::GmErrPlayerNotFound.into(); + } +} -} \ No newline at end of file +fn get_bot_details() -> PlayerDetails { + PlayerDetails { + player_id: 1337, + name: "BestWaifu".to_string(), + level: 90, + origin_world_level: 8, + cur_world_level: 8, + head_id: 82001203, + head_frame_id: 0, + signature: "Ara Ara ~".to_string(), + is_online: true, + is_can_lobby_online: false, + last_offline_time: wicked_waifus_commons::time_util::unix_timestamp() as i64, + team_member_count: 0, + level_gap: 0, + birthday: 0, + role_show_list: vec![], + card_show_list: vec![], + cur_card: 0, + display_birthday: false, + y0a: 0, + sdk_user_id: "Encore_PS5".to_string(), + sdk_online_id: "Encore_PS5".to_string(), + sdk_account_id: "Encore_PS5".to_string(), + cross_play_enabled: true, + limit_state: 0, + jtc: 0, + ztc2: 0, + } +} diff --git a/wicked-waifus-game-server/src/logic/handler/gacha.rs b/wicked-waifus-game-server/src/logic/handler/gacha.rs index 380d7bc..8e0128e 100644 --- a/wicked-waifus-game-server/src/logic/handler/gacha.rs +++ b/wicked-waifus-game-server/src/logic/handler/gacha.rs @@ -24,7 +24,7 @@ pub fn on_gacha_request( // TODO: ensure we have enough elements before pulling - match gacha_service.pull(request.gacha_id, request.gacha_times) { + match gacha_service.pull(player, request.gacha_id, request.gacha_times) { Ok(results) => { match consume_tides(player, request.gacha_id, request.gacha_times) { Ok(_) => { diff --git a/wicked-waifus-game-server/src/logic/handler/guide.rs b/wicked-waifus-game-server/src/logic/handler/guide.rs index 02ca28c..6c27cbc 100644 --- a/wicked-waifus-game-server/src/logic/handler/guide.rs +++ b/wicked-waifus-game-server/src/logic/handler/guide.rs @@ -1,4 +1,4 @@ -use wicked_waifus_protocol::{ErrorCode, GuideInfoRequest, GuideInfoResponse, GuideTriggerRequest, GuideTriggerResponse}; +use wicked_waifus_protocol::{ErrorCode, GuideFinishRequest, GuideFinishResponse, GuideInfoRequest, GuideInfoResponse, GuideTriggerRequest, GuideTriggerResponse}; use crate::logic::player::Player; @@ -7,7 +7,9 @@ pub fn on_guide_info_request( _: GuideInfoRequest, response: &mut GuideInfoResponse, ) { - response.guide_group_finish_list = player.guides.finished_guides.clone(); + response.guide_group_finish_list = player.guides.finished_guides.iter() + .cloned() + .collect(); } pub fn on_guide_trigger_request( @@ -15,7 +17,40 @@ pub fn on_guide_trigger_request( request: GuideTriggerRequest, response: &mut GuideTriggerResponse, ) { - // TODO: Implement this properly checking if guide exist in bindata - player.guides.finished_guides.push(request.group_id); - response.error_code = ErrorCode::Success.into(); + response.error_code = check_if_guide_exists_and_is_repeatable(player, request.group_id); + if response.error_code == >::into(ErrorCode::Success) { + // TODO: We need to check if guide can be repeated or not + // if player.guides.started_guides.contains(&request.group_id) { + // response.error_code = ErrorCode::GuideGroupDoing.into(); + // return; + // } + player.guides.started_guides.insert(request.group_id); + } } + +pub fn on_guide_finish_request( + player: &mut Player, + request: GuideFinishRequest, + response: &mut GuideFinishResponse, +) { + response.error_code = check_if_guide_exists_and_is_repeatable(player, request.group_id); + if response.error_code == >::into(ErrorCode::Success) { + if !player.guides.started_guides.contains(&request.group_id) { + response.error_code = ErrorCode::GuideGroupNoClient.into(); + return; + } + player.guides.started_guides.remove(&request.group_id); + player.guides.finished_guides.insert(request.group_id); + } +} + +fn check_if_guide_exists_and_is_repeatable(player: &Player, guide_id: i32) -> i32 { + let Some(guide) = wicked_waifus_data::guide_group_data::iter().find(|guide| guide.id == guide_id) else { + return ErrorCode::GuideGroupIdNoMatch.into(); + }; + // TODO: We need to check if guide can be repeated or not + if player.guides.finished_guides.contains(&guide.id) { + return ErrorCode::GuideGroupIsNotRepeat.into(); + } + ErrorCode::Success.into() +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/handler/inventory.rs b/wicked-waifus-game-server/src/logic/handler/inventory.rs new file mode 100644 index 0000000..cf8334e --- /dev/null +++ b/wicked-waifus-game-server/src/logic/handler/inventory.rs @@ -0,0 +1,46 @@ +use wicked_waifus_protocol::{ItemExchangeInfo, ItemExchangeInfoRequest, ItemExchangeInfoResponse, NormalItemRequest, NormalItemResponse, PhantomItemRequest, PhantomItemResponse, WeaponItemRequest, WeaponItemResponse}; + +use crate::logic::player::Player; + +pub fn on_normal_item_request( + player: &mut Player, + _: NormalItemRequest, + response: &mut NormalItemResponse, +) { + tracing::debug!("Received NormalItemRequest, returning player inventory"); + response.normal_item_list = player.inventory.to_normal_item_list(); +} + +pub fn on_weapon_item_request( + _player: &mut Player, + _: WeaponItemRequest, + _response: &mut WeaponItemResponse, +) { + // TODO: Implement this + tracing::warn!("Unhandled WeaponItemRequest"); +} + +pub fn on_phantom_item_request( + _player: &mut Player, + _: PhantomItemRequest, + _response: &mut PhantomItemResponse, +) { + // TODO: Implement this + tracing::warn!("Unhandled PhantomItemRequest"); +} + +pub fn on_item_exchange_info_request( + _player: &mut Player, + _: ItemExchangeInfoRequest, + response: &mut ItemExchangeInfoResponse, +) { + response.item_exchange_infos = wicked_waifus_data::item_exchange_content_data::iter() + .map(|item_exchange_content_data| ItemExchangeInfo { + item_id: item_exchange_content_data.item_id, + today_times: 0, // TODO: For stats only, not used for PS so far + total_times: 0, // TODO: For stats only, not used for PS so far + daily_limit: 0, // At the time of writing there is no limits + total_limit: 0, // At the time of writing there is no limits + }) + .collect(); +} diff --git a/wicked-waifus-game-server/src/logic/handler/lord_gym.rs b/wicked-waifus-game-server/src/logic/handler/lord_gym.rs index ee082b5..0e84f26 100644 --- a/wicked-waifus-game-server/src/logic/handler/lord_gym.rs +++ b/wicked-waifus-game-server/src/logic/handler/lord_gym.rs @@ -1,4 +1,4 @@ -use wicked_waifus_protocol::{ErrorCode, LordGymInfoRequest, LordGymInfoResponse}; +use wicked_waifus_protocol::{LordGymInfoRequest, LordGymInfoResponse}; use crate::logic::player::Player; @@ -7,6 +7,6 @@ pub fn on_lord_gym_info_request( request: LordGymInfoRequest, _response: &mut LordGymInfoResponse, ) { - tracing::debug!("LordGymInfoRequest unhandled: for {:?}", request); + tracing::warn!("LordGymInfoRequest unhandled: for {:?}", request); // TODO: Implement relational DB(SeaORM?) and fetch the data from the player } diff --git a/wicked-waifus-game-server/src/logic/handler/map.rs b/wicked-waifus-game-server/src/logic/handler/map.rs index 791c002..f5b1094 100644 --- a/wicked-waifus-game-server/src/logic/handler/map.rs +++ b/wicked-waifus-game-server/src/logic/handler/map.rs @@ -1,4 +1,11 @@ -use wicked_waifus_protocol::{DarkCoastDeliveryRequest, DarkCoastDeliveryResponse, DragonPoolDropItems, ErrorCode, ItemDict, ItemEntry, MapUnlockFieldInfoRequest, MapUnlockFieldInfoResponse}; +use wicked_waifus_protocol::{ + DarkCoastDeliveryRequest, DarkCoastDeliveryResponse, DragonPoolDropItems, EntityAccessInfo, + ErrorCode, ItemDict, ItemEntry, MapCancelTraceRequest, MapCancelTraceResponse, + MapTraceInfoRequest, MapTraceInfoResponse, MapTraceRequest, MapTraceResponse, + MapUnlockFieldInfoRequest, MapUnlockFieldInfoResponse, PlayerAccessEffectAreaRequest, + PlayerAccessEffectAreaResponse, +}; + use crate::logic::player::Player; pub fn on_dark_coast_delivery_request( @@ -18,7 +25,9 @@ pub fn on_dark_coast_delivery_request( dragon_pool_id: request.dragon_pool_id, q_ss: value.dark_coast_delivery_list.clone(), drop_items: vec![ItemDict { - items: value.drop_ids.iter() + items: value + .drop_ids + .iter() .map(|id| ItemEntry { item_id: *id, item_count: 1, @@ -30,6 +39,35 @@ pub fn on_dark_coast_delivery_request( } } +pub fn on_map_cancel_trace_request( + player: &mut Player, + request: MapCancelTraceRequest, + response: &mut MapCancelTraceResponse, +) { + player.map_trace.traces.remove(&request.mark_id); + response.mark_id = request.mark_id; + response.error_code = ErrorCode::Success.into(); +} + +pub fn on_map_trace_request( + player: &mut Player, + request: MapTraceRequest, + response: &mut MapTraceResponse, +) { + player.map_trace.traces.insert(request.mark_id); + response.mark_id = request.mark_id; + response.error_code = ErrorCode::Success.into(); +} + +pub fn on_map_trace_info_request( + player: &Player, + _: MapTraceInfoRequest, + response: &mut MapTraceInfoResponse, +) { + response.mark_id_list = player.map_trace.traces.iter().cloned().collect(); + response.error_code = ErrorCode::Success.into(); +} + pub fn on_map_unlock_field_info_request( _player: &mut Player, _: MapUnlockFieldInfoRequest, @@ -40,4 +78,20 @@ pub fn on_map_unlock_field_info_request( response.field_id = wicked_waifus_data::area_data::iter() .map(|area| area.area_id) .collect::>(); -} \ No newline at end of file +} + +pub fn on_player_access_effect_area_request( + _player: &Player, + request: PlayerAccessEffectAreaRequest, + response: &mut PlayerAccessEffectAreaResponse, +) { + // TODO: from world fetch entity by request.entity_id + // TODO: Compute the distance between player and entity.entity_id + response.error_code = ErrorCode::Success.into(); + response.entity_id = request.entity_id; + response.info = Some(EntityAccessInfo { + entity_id: request.entity_id, + range_type: request.range_type, + uo_1: Default::default(), + }); +} diff --git a/wicked-waifus-game-server/src/logic/handler/misc.rs b/wicked-waifus-game-server/src/logic/handler/misc.rs index f37c442..a56eff0 100644 --- a/wicked-waifus-game-server/src/logic/handler/misc.rs +++ b/wicked-waifus-game-server/src/logic/handler/misc.rs @@ -1,11 +1,26 @@ -use wicked_waifus_protocol::{ - ErrorCode, Zih, InputSettingRequest, InputSettingResponse, InputSettingUpdateRequest, - InputSettingUpdateResponse, LanguageSettingUpdateRequest, LanguageSettingUpdateResponse, - ServerPlayStationPlayOnlyStateRequest, ServerPlayStationPlayOnlyStateResponse, VersionInfoPush, -}; +use wicked_waifus_protocol::{ErrorCode, InputSettingRequest, InputSettingResponse, InputSettingUpdateRequest, InputSettingUpdateResponse, LanguageSettingUpdateRequest, LanguageSettingUpdateResponse, MonthCardRequest, MonthCardResponse, ServerPlayStationPlayOnlyStateRequest, ServerPlayStationPlayOnlyStateResponse, UpdateVoxelEnvRequest, UpdateVoxelEnvResponse, VersionInfoPush, WebSignRequest, WebSignResponse, Zih}; use crate::logic::player::Player; +pub fn on_month_card_request( + player: &mut Player, + _: MonthCardRequest, + response: &mut MonthCardResponse, +) { + // TODO: Check if we should send MonthCardUseNotify + response.days = player.month_card.days; + response.is_daily_got = wicked_waifus_commons::time_util::unix_days() == player.month_card.last_received_day; + response.error_code = ErrorCode::Success.into(); +} + +pub fn on_web_sign_request( + _: &mut Player, + _: WebSignRequest, + response: &mut WebSignResponse, +) { + response.notice_sign = "Welcome to Wicked Waifus PS provided by Reversed Rooms Dev Team".to_string(); +} + pub fn on_input_setting_request( _: &Player, _: InputSettingRequest, @@ -47,3 +62,12 @@ pub fn on_version_info_push(_player: &Player, push: VersionInfoPush) { push.resource_version ); } + +pub fn on_update_voxel_env_request( + _: &Player, + request: UpdateVoxelEnvRequest, + response: &mut UpdateVoxelEnvResponse, +) { + response.server_cave_mode = request.server_cave_mode; + response.error_code = ErrorCode::Success.into(); +} diff --git a/wicked-waifus-game-server/src/logic/handler/mod.rs b/wicked-waifus-game-server/src/logic/handler/mod.rs index 8e93cc3..a2d03bb 100644 --- a/wicked-waifus-game-server/src/logic/handler/mod.rs +++ b/wicked-waifus-game-server/src/logic/handler/mod.rs @@ -1,9 +1,13 @@ +pub use advice::*; +pub use animal::*; pub use chat::*; pub use combat::*; +pub use coop::*; pub use dummy::*; pub use entity::*; pub use friend::*; pub use gacha::*; +pub use inventory::*; pub use guide::*; pub use lord_gym::*; pub use mail::*; @@ -16,13 +20,17 @@ pub use skill::*; pub use teleport::*; pub use tutorial::*; +mod advice; +mod animal; mod chat; mod combat; +mod coop; mod dummy; mod entity; mod friend; mod gacha; mod guide; +mod inventory; mod lord_gym; mod mail; mod map; @@ -103,25 +111,42 @@ macro_rules! handle_push { } handle_request! { + // Advice + Advice; + AdviceSet; + + // Animal + AnimalDie; + AnimalDrop; + AnimalDestroy; + // Chat (TODO: Review TODOs) PrivateChat; - PrivateChatOperate; + PrivateChatData; PrivateChatHistory; + PrivateChatOperate; // Combat (TODO: Review this on_..., port some from go) CombatSendPack, combat_message; // CombatMessagePostInfo, combat_message; // TODO: Review this niggerianism, Encrypted shadow data - // Friend (TODO: Implement them) - FriendApplySend; - FriendRecentlyTeam; - PlayerBasicInfoGet; + // Coop + LobbyList; // Entity (TODO: Review this on_..., port some from go) EntityActive; EntityOnLanded; EntityPosition; - EntityLoadComplete; + EntityAccessRange; + EntityInteract; + EntityFollowTrack; + GetRewardTreasureBox; + + // Friend (TODO: Implement them) + FriendAll; + // FriendApplySend; + // FriendRecentlyTeam; + PlayerBasicInfoGet; // Gacha Gacha; @@ -131,6 +156,14 @@ handle_request! { // Guide GuideInfo; GuideTrigger; + GuideFinish; + + // Inventory + NormalItem; + WeaponItem; + PhantomItem; + ValidTimeItem; + ItemExchangeInfo; // Lord Gym (TODO: Review this on_..., port some from go) LordGymInfo; @@ -140,21 +173,25 @@ handle_request! { // Map DarkCoastDelivery; + MapCancelTrace; + MapTrace; + MapTraceInfo; MapUnlockFieldInfo; + PlayerAccessEffectArea; + // LevelPlayStateListAsyncRequest // Example: "x9l": [{"inst_id": 902,"level_play_ids": [166700009,157700000]}] // Misc (TODO: Review this on_..., port some from go) - // Advice; InputSetting; InputSettingUpdate; LanguageSettingUpdate; ServerPlayStationPlayOnlyState; // Player (TODO: Review this on_..., port some from go) - // PlayerMotion; // ModifySignature; // ModifyName; // ChangeHeadPhoto; + PlayerTitleData; // Role (TODO: Review this on_..., port some from go) RoleShowListUpdate; @@ -175,7 +212,7 @@ handle_request! { // PayInfo; // PayGiftInfo; // PayShopItemUpdate; - // PayShopInfo; + PayShopInfo; // PayShopUpdate; // MonthCard; @@ -195,12 +232,18 @@ handle_request! { // Tutorial TutorialInfo; - // TutorialUnlock; + TutorialReceive; + TutorialUnlock; // TODO: Implement all this properly, workaround for game enter + EntityPatrolStop; + InitRange; + Activity; + BattlePass; + SlashAndTowerInfo; + // Role RoleVisionRecommendData; - RoleVisionRecommendData; RoleVisionRecommendAttr; PlayerMotion; @@ -223,23 +266,12 @@ handle_request! { VisionEquipGroupInfo; UpdatePlayStationBlockAccount; AdventureManual; - MapTraceInfo; Tower; ExploreProgress; ReportData; UpdateVoxelEnv; SimpleTrackReportAsync; TowerSeasonUpdate; - - // Friend - FriendAll; - - // Inventory - NormalItem; - WeaponItem; - PhantomItem; - ValidTimeItem; - ItemExchangeInfo; } handle_push! { diff --git a/wicked-waifus-game-server/src/logic/handler/role.rs b/wicked-waifus-game-server/src/logic/handler/role.rs index 2163581..f17cf8a 100644 --- a/wicked-waifus-game-server/src/logic/handler/role.rs +++ b/wicked-waifus-game-server/src/logic/handler/role.rs @@ -1,6 +1,11 @@ use std::collections::HashSet; -use wicked_waifus_protocol::{ClientCurrentRoleReportRequest, ClientCurrentRoleReportResponse, ERemoveEntityType, ErrorCode, FormationAttrRequest, FormationAttrResponse, RoleFavorListRequest, RoleFavorListResponse, RoleShowListUpdateRequest, RoleShowListUpdateResponse, UpdateFormationRequest, UpdateFormationResponse}; +use wicked_waifus_protocol::{ + ClientCurrentRoleReportRequest, ClientCurrentRoleReportResponse, ERemoveEntityType, ErrorCode, + FormationAttrRequest, FormationAttrResponse, PlayerMotionRequest, PlayerMotionResponse, + RoleFavorListRequest, RoleFavorListResponse, RoleShowListUpdateRequest, + RoleShowListUpdateResponse, UpdateFormationRequest, UpdateFormationResponse, +}; use crate::logic::player::Player; use crate::logic::role::{Role, RoleFormation}; @@ -98,7 +103,7 @@ pub fn on_update_formation_request( if !added_roles.is_empty() { // add new roles - player.notify(player.build_player_entity_add_notify(added_roles, world)); + player.notify(player.build_player_entity_add_notify(added_roles)); } // send update group formation notify @@ -135,4 +140,15 @@ pub fn on_update_formation_request( player.notify(player.build_update_formation_notify()); response.error_code = ErrorCode::Success.into(); -} \ No newline at end of file +} + +pub fn on_player_motion_request( + _: &Player, + request: PlayerMotionRequest, + response: &mut PlayerMotionResponse, +) { + match wicked_waifus_data::motion_data::iter().find(|&motion| motion.id == request.motion) { + None => response.error_id = ErrorCode::UnKnownError.into(), + Some(_) => response.error_id = ErrorCode::Success.into(), + } +} diff --git a/wicked-waifus-game-server/src/logic/handler/scene.rs b/wicked-waifus-game-server/src/logic/handler/scene.rs index b6a256f..ac4a153 100644 --- a/wicked-waifus-game-server/src/logic/handler/scene.rs +++ b/wicked-waifus-game-server/src/logic/handler/scene.rs @@ -1,10 +1,9 @@ -use wicked_waifus_protocol::{ - ErrorCode, SceneLoadingFinishRequest, SceneLoadingFinishResponse, SceneTraceRequest, - SceneTraceResponse, UpdateSceneDateRequest, UpdateSceneDateResponse, - AccessPathTimeServerConfigRequest, AccessPathTimeServerConfigResponse, - PlayerHeadDataRequest, PlayerHeadDataResponse, UnlockRoleSkinListRequest, - UnlockRoleSkinListResponse -}; +use wicked_waifus_protocol::{ErrorCode, SceneLoadingFinishRequest, SceneLoadingFinishResponse, SceneTraceRequest, SceneTraceResponse, UpdateSceneDateRequest, UpdateSceneDateResponse, AccessPathTimeServerConfigRequest, AccessPathTimeServerConfigResponse, PlayerHeadDataRequest, PlayerHeadDataResponse, UnlockRoleSkinListRequest, UnlockRoleSkinListResponse, JsPatchNotify}; + +const WATER_MASK: &str = include_str!("../../../scripts/watermask-disable.js"); +const UID_FIX: &str = include_str!("../../../scripts/uidfix.js"); +const CENSORSHIP_FIX: &str = include_str!("../../../scripts/censorshipfix.js"); +const DEBUG_DISABLE: &str = include_str!("../../../scripts/debug_disable.js"); use crate::logic::player::Player; @@ -17,10 +16,25 @@ pub fn on_scene_trace_request( } pub fn on_scene_loading_finish_request( - _player: &Player, + player: &Player, _request: SceneLoadingFinishRequest, response: &mut SceneLoadingFinishResponse, ) { + player.notify(JsPatchNotify { + content: WATER_MASK.to_string(), + }); + player.notify(JsPatchNotify { + content: UID_FIX + .replace("{PLAYER_USERNAME}", &player.basic_info.name) + .replace("{SELECTED_COLOR}", "50FC71"), + }); + player.notify(JsPatchNotify { + content: CENSORSHIP_FIX.to_string(), + }); + player.notify(JsPatchNotify { + content: DEBUG_DISABLE.to_string(), + }); + // TODO: Implement this if needed response.error_code = ErrorCode::Success.into(); } diff --git a/wicked-waifus-game-server/src/logic/handler/skill.rs b/wicked-waifus-game-server/src/logic/handler/skill.rs index 10f1e32..244a092 100644 --- a/wicked-waifus-game-server/src/logic/handler/skill.rs +++ b/wicked-waifus-game-server/src/logic/handler/skill.rs @@ -48,6 +48,12 @@ pub fn on_explore_skill_roulette_set_request( match illegal_skill { true => response.error_code = ErrorCode::ErrRouletteFuncIdInvaild.into(), false => { + player.explore_tools.roulette = request.skill_roulettes.get(0).unwrap().skill_ids.iter() + .map(|&skill_id| skill_id) + .collect::>() + .as_slice() + .try_into() + .unwrap(); response.error_code = ErrorCode::Success.into(); response.skill_roulettes = request.skill_roulettes; } diff --git a/wicked-waifus-game-server/src/logic/handler/teleport.rs b/wicked-waifus-game-server/src/logic/handler/teleport.rs index cb4f9c9..5cc9c17 100644 --- a/wicked-waifus-game-server/src/logic/handler/teleport.rs +++ b/wicked-waifus-game-server/src/logic/handler/teleport.rs @@ -1,18 +1,20 @@ -use wicked_waifus_protocol::{ErrorCode, TeleportDataRequest, TeleportDataResponse, TeleportNotify, TeleportReason, TeleportTransferRequest, TeleportTransferResponse, TeleportFinishRequest, TeleportFinishResponse, TransitionOptionPb, TransitionType, LeaveSceneNotify, JoinSceneNotify}; -use wicked_waifus_data::{ComponentsData, level_entity_config_data, RawVectorData, TeleportComponent}; +use wicked_waifus_protocol::{ErrorCode, JoinSceneNotify, LeaveSceneNotify, TeleportDataRequest, TeleportDataResponse, TeleportFinishRequest, TeleportFinishResponse, TeleportNotify, TeleportReason, TeleportTransferRequest, TeleportTransferResponse, TransitionOptionPb}; +use wicked_waifus_data::{level_entity_config_data, RawVectorData}; +use wicked_waifus_data::pb_components::teleport::TeleportComponent; + +use crate::logic::math::Vector3f; use crate::logic::player::Player; use crate::logic::utils::world_util; pub fn on_teleport_data_request( - _player: &mut Player, + player: &mut Player, _: TeleportDataRequest, response: &mut TeleportDataResponse, ) { - // TODO: [WWPS-1] Real implementation should fetch completed / uncompleted from db, lets return completed response.error_code = ErrorCode::Success.into(); - response.ids = wicked_waifus_data::teleporter_data::iter() - .map(|teleporter| teleporter.id) + response.ids = player.teleports.teleports_data.iter() + .map(|teleport| teleport.id) .collect::>(); } @@ -29,7 +31,7 @@ pub fn on_teleport_transfer_request( }; println!("received transfer request for teleport entity id: {}", &teleport.teleport_entity_config_id); - let Some(tp) = level_entity_config_data::get(&teleport.teleport_entity_config_id) else { + let Some(tp) = level_entity_config_data::get(teleport.map_id, teleport.teleport_entity_config_id) else { response.error_code = ErrorCode::ErrTeleportEntityNotExist.into(); return; }; @@ -48,26 +50,20 @@ pub fn on_teleport_transfer_request( } else { response.error_code = ErrorCode::Success.into(); response.map_id = teleport.map_id; - let (x, y, z) = get_teleport_position( - &tp.transform, - teleport_component, - ); - response.pos_x = x; - response.pos_y = y; - response.pos_z = z; + let teleport_position = get_teleport_position(&tp.transform, teleport_component); + response.pos_x = teleport_position.x; + response.pos_y = teleport_position.y; + response.pos_z = teleport_position.z; response.pitch = 0f32; response.yaw = 0f32; response.roll = 0f32; - // TODO: simplify (player.world.curr_map_id, palyer.basic_info.cur_map_id and player.location.instance_id) - - if player.location.instance_id == teleport.map_id { + if player.basic_info.cur_map_id == teleport.map_id { player.notify(TeleportNotify { map_id: teleport.map_id, - pos_x: x, - pos_y: y, - pos_z: z, - pos_a: 0.0, + pos: Some(teleport_position.to_protobuf()), + rot: None, + gravity: None, reason: TeleportReason::Gm.into(), game_ctx: None, transition_option: Some(TransitionOptionPb::default()), @@ -81,6 +77,7 @@ pub fn on_teleport_transfer_request( transition_option: Some(TransitionOptionPb::default()), }); let scene_info = world_util::build_scene_information(&player); + // TODO: Trigger initial join world flow?? player.notify(JoinSceneNotify { scene_info: Some(scene_info), max_entity_id: i64::MAX, @@ -100,18 +97,10 @@ pub fn on_teleport_finish_request( response.error_code = ErrorCode::Success.into(); } -fn get_teleport_position(transform: &[RawVectorData], component: &TeleportComponent) -> (f32, f32, f32) { - // TODO: Review this formula, allegedly - // - transform[0] is position component - // - transform[2] is rotation component - // - transform[2] is scale component - let (x, y, z) = (transform[0].x / 100.0, transform[0].y / 100.0, transform[0].z / 100.0); - match &component.teleport_position { - None => (x, y, z), - Some(teleport_position) => ( - x + (teleport_position.x.unwrap_or_default()), - y + (teleport_position.y.unwrap_or_default()), - z + (teleport_position.z.unwrap_or_default()), - ) +fn get_teleport_position(transform: &[RawVectorData], component: &TeleportComponent) -> Vector3f { + let mut entity_position = Vector3f::from_raw_scaled(&transform[0], &transform[2]); + if let Some(teleport_position) = &component.teleport_position { + entity_position.add_teleport_position(teleport_position); } + entity_position } \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/handler/tutorial.rs b/wicked-waifus-game-server/src/logic/handler/tutorial.rs index 432d052..bcd8208 100644 --- a/wicked-waifus-game-server/src/logic/handler/tutorial.rs +++ b/wicked-waifus-game-server/src/logic/handler/tutorial.rs @@ -1,12 +1,94 @@ -use wicked_waifus_protocol::{ErrorCode, TutorialUnlockRequest, TutorialUnlockResponse}; +use std::collections::HashMap; +use wicked_waifus_protocol::{ + ErrorCode, TutorialInfo, TutorialInfoRequest, TutorialInfoResponse, TutorialReceiveRequest, + TutorialReceiveResponse, TutorialUnlockRequest, TutorialUnlockResponse, +}; use crate::logic::player::Player; +pub fn on_tutorial_info_request( + player: &mut Player, + _: TutorialInfoRequest, + response: &mut TutorialInfoResponse, +) { + response.unlock_list = player + .tutorials + .tutorials + .iter() + .map(|tutorial| TutorialInfo { + id: tutorial.id, + create_time: tutorial.create_time, + get_award: tutorial.get_award, + }) + .collect(); +} + +pub fn on_tutorial_receive_request( + player: &mut Player, + request: TutorialReceiveRequest, + response: &mut TutorialReceiveResponse, +) { + let Some(tutorial_data) = + wicked_waifus_data::guide_tutorial_data::iter().find(|tutorial| tutorial.id == request.id) + else { + response.error_code = ErrorCode::GuideTutorialConfigNotFind.into(); + return; + }; + + let Some(tutorial) = player + .tutorials + .tutorials + .iter() + .find(|tutorial| tutorial.id == request.id) else { + + response.error_code = ErrorCode::GuideTutorialNotUnlock.into(); + return; + }; + + if tutorial.get_award { + response.error_code = ErrorCode::GuideTutorialIsReceive.into(); + return; + } + + // TODO: Search the rewards in drop_package + tracing::debug!("Tutorial receive request with drop: {}", tutorial_data.drop_id); + + // TODO: Fill in the item map + response.error_code = ErrorCode::Success.into(); + response.item_map = HashMap::new(); +} + pub fn on_tutorial_unlock_request( player: &mut Player, request: TutorialUnlockRequest, response: &mut TutorialUnlockResponse, ) { - // TODO: Implement this properly checking if guide exist in bindata + let Some(_) = + wicked_waifus_data::guide_tutorial_data::iter().find(|tutorial| tutorial.id == request.id) + else { + response.error_code = ErrorCode::GuideTutorialConfigNotFind.into(); + return; + }; + + if let Some(tutorial) = player + .tutorials + .tutorials + .iter() + .find(|tutorial| tutorial.id == request.id) + { + if tutorial.get_award { + response.error_code = ErrorCode::GuideTutorialIsReceive.into(); + } else { + response.error_code = ErrorCode::GuideTutorialIsUnlock.into(); + } + return; + } + + let tutorial = player.unlock_tutorial(request.id); + response.un_lock_info = Some(TutorialInfo { + id: tutorial.id, + create_time: tutorial.create_time, + get_award: tutorial.get_award, + }); response.error_code = ErrorCode::Success.into(); } diff --git a/wicked-waifus-game-server/src/logic/math/area_range.rs b/wicked-waifus-game-server/src/logic/math/area_range.rs new file mode 100644 index 0000000..b546cda --- /dev/null +++ b/wicked-waifus-game-server/src/logic/math/area_range.rs @@ -0,0 +1,55 @@ +use crate::logic::math::Vector3f; + +pub struct Area { + pub center: Vector3f, + pub radius: f32, +} + +pub struct SquareArea(pub Area); +pub struct CircleArea(pub Area); +pub struct CubeArea(pub Area); +pub struct SphereArea(pub Area); + +pub trait Ranger { + fn in_range(&self, entity: Vector3f) -> bool; +} + +impl Ranger for SquareArea { + /// Computation of range in a square is done via 2D simple bound checks. + fn in_range(&self, pos: Vector3f) -> bool { + (self.0.center.x - self.0.radius <= pos.x && pos.x <= self.0.center.x + self.0.radius) && + (self.0.center.y - self.0.radius <= pos.y && pos.y <= self.0.center.y + self.0.radius) + } +} + +impl Ranger for CircleArea { + /// Computation of range in a sphere is done via 2D Euclidean distance formula. + fn in_range(&self, pos: Vector3f) -> bool { + // TODO: Check for overflows in squaring?? + let distance_squared = (pos.x - self.0.center.x).powi(2) + + (pos.y - self.0.center.y).powi(2); + let radius_squared = self.0.radius * self.0.radius; + distance_squared <= radius_squared + } +} + +impl Ranger for CubeArea { + /// Computation of range in a cube is done via 3D simple bound checks. + fn in_range(&self, pos: Vector3f) -> bool { + (self.0.center.x - self.0.radius <= pos.x && pos.x <= self.0.center.x + self.0.radius) && + (self.0.center.y - self.0.radius <= pos.y && pos.y <= self.0.center.y + self.0.radius) && + (self.0.center.z - self.0.radius <= pos.z && pos.z <= self.0.center.z + self.0.radius) + } +} + +impl Ranger for SphereArea { + /// Computation of range in a sphere is done via 3D Euclidean distance formula. + fn in_range(&self, pos: Vector3f) -> bool { + // TODO: Check for overflows in squaring?? + let distance_squared = (pos.x - self.0.center.x).powi(2) + + (pos.y - self.0.center.y).powi(2) + + (pos.z - self.0.center.z).powi(2); + let radius_squared = self.0.radius * self.0.radius; + distance_squared <= radius_squared + } +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/math/mod.rs b/wicked-waifus-game-server/src/logic/math/mod.rs index 4810fe7..4d0ad07 100644 --- a/wicked-waifus-game-server/src/logic/math/mod.rs +++ b/wicked-waifus-game-server/src/logic/math/mod.rs @@ -1,5 +1,6 @@ mod transform; mod vector; +mod area_range; pub use transform::Transform; pub use vector::Vector3f; diff --git a/wicked-waifus-game-server/src/logic/math/transform.rs b/wicked-waifus-game-server/src/logic/math/transform.rs index c227d9c..c5d067c 100644 --- a/wicked-waifus-game-server/src/logic/math/transform.rs +++ b/wicked-waifus-game-server/src/logic/math/transform.rs @@ -51,11 +51,13 @@ impl Transform { } impl From<&[RawVectorData]> for Transform { + // - transform[0] is position component + // - transform[1] is rotation component + // - transform[2] is scale component fn from(transform: &[RawVectorData]) -> Self { Self { - position: Vector3f::from(&transform[0]), - rotation: Vector3f::from(&transform[1]), - ..Default::default() + position: Vector3f::from_raw_scaled(&transform[0], &transform[2]), + rotation: Vector3f::from_raw_scaled(&transform[1], &transform[2]), } } } \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/math/vector.rs b/wicked-waifus-game-server/src/logic/math/vector.rs index d4c8588..87c6970 100644 --- a/wicked-waifus-game-server/src/logic/math/vector.rs +++ b/wicked-waifus-game-server/src/logic/math/vector.rs @@ -1,5 +1,6 @@ use wicked_waifus_data::RawVectorData; use wicked_waifus_protocol::Vector; +use wicked_waifus_data::pb_components::teleport::TeleportPosition; use wicked_waifus_protocol_internal::VectorData; #[derive(Default, Clone, PartialEq, Debug)] @@ -41,14 +42,18 @@ impl Vector3f { z: data.get_z(), } } -} -impl From<&RawVectorData> for Vector3f { - fn from(transform: &RawVectorData) -> Self { + pub fn from_raw_scaled(transform: &RawVectorData, scale: &RawVectorData) -> Self { Self { - x: transform.x / 100.0, - y: transform.y / 100.0, - z: transform.z / 100.0, + x: transform.x / scale.x, + y: transform.y / scale.y, + z: transform.z / scale.z, } } + + pub fn add_teleport_position(&mut self, teleport_position: &TeleportPosition) { + self.x += teleport_position.x.unwrap_or_default(); + self.y += teleport_position.y.unwrap_or_default(); + self.z += teleport_position.z.unwrap_or_default(); + } } \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/player/basic_info.rs b/wicked-waifus-game-server/src/logic/player/basic_info.rs index b68227a..fcf496a 100644 --- a/wicked-waifus-game-server/src/logic/player/basic_info.rs +++ b/wicked-waifus-game-server/src/logic/player/basic_info.rs @@ -2,6 +2,7 @@ use wicked_waifus_protocol::{ player_attr, BasicInfoNotify, PlayerAttr, PlayerAttrKey, PlayerAttrType, }; use wicked_waifus_protocol_internal::PlayerBasicData; +use crate::logic::player::player_inventory::PlayerInventory; pub struct PlayerBasicInfo { pub id: i32, @@ -16,18 +17,28 @@ pub struct PlayerBasicInfo { } impl PlayerBasicInfo { - pub fn build_notify(&self) -> BasicInfoNotify { + pub fn build_notify(&self, inventory: &PlayerInventory) -> BasicInfoNotify { BasicInfoNotify { id: self.id, attributes: vec![ - build_str_attr(PlayerAttrKey::Name, self.name.as_str()), build_int_attr(PlayerAttrKey::Level, self.level), build_int_attr(PlayerAttrKey::Exp, self.exp), - build_int_attr(PlayerAttrKey::Sex, self.sex), + build_int_attr(PlayerAttrKey::Coin, inventory.get_shell_credits()), + build_int_attr(PlayerAttrKey::RareCoin, inventory.get_astrite()), build_int_attr(PlayerAttrKey::HeadPhoto, self.head_photo), build_int_attr(PlayerAttrKey::HeadFrame, self.head_frame), + build_int_attr(PlayerAttrKey::AreaId, 1), // TODO: + build_str_attr(PlayerAttrKey::Name, self.name.as_str()), + build_str_attr(PlayerAttrKey::Sign, ""), // TODO: + build_int_attr(PlayerAttrKey::Sex, self.sex), + build_int_attr(PlayerAttrKey::OriginWorldLevel, 1), // TODO: + build_int_attr(PlayerAttrKey::CurWorldLevel, 1), // TODO: + build_int_attr(PlayerAttrKey::WorldLevelTimeStamp, 0), // TODO: + build_int_attr(PlayerAttrKey::CashCoin, inventory.get_lunite()), + build_int_attr(PlayerAttrKey::WorldPermission, 0), // TODO: ], - // TODO: Impl card unlock list + card_unlock_list: vec![], // TODO: 80060000 + cur_card_id: 0, // TODO: 80060000 ..Default::default() } } @@ -61,6 +72,22 @@ impl PlayerBasicInfo { } } +impl Default for PlayerBasicInfo { + fn default() -> Self { + Self { + id: 0, + name: "".to_string(), + sex: 0, + level: 0, + exp: 0, + head_photo: 0, + head_frame: 0, + cur_map_id: 0, + role_show_list: vec![], + } + } +} + #[inline] fn build_int_attr(key: PlayerAttrKey, value: i32) -> PlayerAttr { PlayerAttr { diff --git a/wicked-waifus-game-server/src/logic/player/explore_tools.rs b/wicked-waifus-game-server/src/logic/player/explore_tools.rs index 29e5d76..fe1d388 100644 --- a/wicked-waifus-game-server/src/logic/player/explore_tools.rs +++ b/wicked-waifus-game-server/src/logic/player/explore_tools.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use wicked_waifus_data::explore_tools_data; -use wicked_waifus_protocol::{ExploreSkillRoulette, ExploreSkillRouletteUpdateNotify, ExploreToolAllNotify}; +use wicked_waifus_protocol::{ExploreSkillRoulette, ExploreSkillRouletteUpdateNotify, ExploreToolAllNotify, VisionExploreSkillNotify}; use wicked_waifus_protocol_internal::PlayerExploreToolsData; type Roulette = [i32; 8]; @@ -33,6 +33,7 @@ impl ExploreTools { } pub fn build_explore_tool_all_notify(&self) -> ExploreToolAllNotify { + // TODO: NewUnlock handling ExploreToolAllNotify { skill_list: self.unlocked_explore_skills.iter().cloned().collect(), explore_skill: self.active_explore_skill, @@ -40,6 +41,12 @@ impl ExploreTools { } } + pub fn build_vision_explore_skill_notify(&self) -> VisionExploreSkillNotify { + VisionExploreSkillNotify { + explore_skill: self.active_explore_skill + } + } + pub fn build_roulette_update_notify(&self) -> ExploreSkillRouletteUpdateNotify { ExploreSkillRouletteUpdateNotify { roulette_info: vec![ExploreSkillRoulette { diff --git a/wicked-waifus-game-server/src/logic/player/guides.rs b/wicked-waifus-game-server/src/logic/player/guides.rs deleted file mode 100644 index ffec5fe..0000000 --- a/wicked-waifus-game-server/src/logic/player/guides.rs +++ /dev/null @@ -1,27 +0,0 @@ -use wicked_waifus_protocol_internal::PlayerGuides; - -pub struct Guides { - pub finished_guides: Vec, -} - -impl Guides { - pub fn load_from_save(data: PlayerGuides) -> Self { - Guides { - finished_guides: data.finished_guides, - } - } - - pub fn build_save_data(&self) -> PlayerGuides { - PlayerGuides { - finished_guides: self.finished_guides.clone(), - } - } -} - -impl Default for Guides { - fn default() -> Self { - Self { - finished_guides: Vec::new(), - } - } -} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/player/mod.rs b/wicked-waifus-game-server/src/logic/player/mod.rs index 097c0fe..1c7975b 100644 --- a/wicked-waifus-game-server/src/logic/player/mod.rs +++ b/wicked-waifus-game-server/src/logic/player/mod.rs @@ -1,46 +1,77 @@ +pub use in_world_player::InWorldPlayer; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; use std::sync::Arc; - -pub use in_world_player::InWorldPlayer; -use wicked_waifus_protocol_internal::{PlayerBasicData, PlayerRoleData, PlayerSaveData}; -use wicked_waifus_protocol::{AdventreTask, AdventureManualData, AdventureUpdateNotify, AdviceSettingNotify, ControlInfoNotify, EEntityType, EntityAddNotify, EntityConfigType, EntityPb, EntityRemoveInfo, EntityRemoveNotify, EntityState, ERemoveEntityType, FightFormationNotifyInfo, FightRoleInfo, FightRoleInfos, FormationRoleInfo, GroupFormation, InstDataNotify, ItemPkgOpenNotify, LivingStatus, MapUnlockFieldNotify, PbGetRoleListNotify, PlayerFightFormations, ProtocolUnit, RoleChangeUnlockNotify, UpdateFormationNotify, UpdateGroupFormationNotify}; -use wicked_waifus_protocol::message::Message; use wicked_waifus_commons::time_util; -use wicked_waifus_data::base_property_data; -use wicked_waifus_data::role_info_data; +use wicked_waifus_data::motion_data; +use wicked_waifus_protocol::message::Message; +use wicked_waifus_protocol::player_attr::Value; +use wicked_waifus_protocol::{ + AdventreTask, AdventureManualData, AdventureUpdateNotify, AdviceSettingNotify, BuffItemNotify, + ControlInfoNotify, EEntityType, ERemoveEntityType, EnergyInfo, EnergyUpdateNotify, + EntityAddNotify, EntityConfigType, EntityPb, EntityRemoveInfo, EntityRemoveNotify, EntityState, + FavorItem, FightFormationNotifyInfo, FightRoleInfo, FightRoleInfos, FormationRoleInfo, + GroupFormation, HostTeleportUnlockNotify, InstDataNotify, ItemPkgOpenNotify, + LevelPlayInfoNotify, LivingStatus, MailInfosNotify, MapUnlockFieldNotify, + MonthCardDailyRewardNotify, MoonChasingTargetGetCountNotify, + MoonChasingTrackMoonHandbookRewardNotify, NormalItemUpdateNotify, PassiveSkillNotify, + PbGetRoleListNotify, PlayerAttr, PlayerAttrKey, PlayerAttrNotify, PlayerAttrType, + PlayerFightFormations, PlayerVarNotify, ProtocolUnit, PushContextIdNotify, + PushDataCompleteNotify, RoguelikeCurrencyNotify, RoleChangeUnlockNotify, RoleFavor, + RoleFavorListNotify, RoleMotion, RoleMotionListNotify, SettingNotify, TeleportUpdateNotify, + UpdateFormationNotify, UpdateGroupFormationNotify, +}; +use wicked_waifus_protocol_internal::{PlayerBasicData, PlayerRoleData, PlayerSaveData}; -use crate::{create_player_entity_pb, query_components}; -use crate::logic::{ - components::{ - Attribute, EntityConfig, Equip, FightBuff, Movement, OwnerPlayer, PlayerEntityMarker, - Position, Visibility, VisionSkill, - }, - ecs::component::ComponentContainer, +use super::{ + ecs::world::World, + role::{Role, RoleFormation}, }; use crate::logic::components::RoleSkin; use crate::logic::ecs::world::WorldEntity; use crate::logic::player::basic_info::PlayerBasicInfo; use crate::logic::player::explore_tools::ExploreTools; use crate::logic::player::location::PlayerLocation; +use crate::logic::player::player_adventure::PlayerAdventureStatus; +use crate::logic::player::player_advice::PlayerAdviceConfig; use crate::logic::player::player_chat::PlayerChat; use crate::logic::player::player_func::PlayerFunc; -use crate::logic::player::guides::Guides; -use crate::session::Session; - -use super::{ - ecs::world::World, - role::{Role, RoleFormation}, +use crate::logic::player::player_guides::PlayerGuides; +pub use crate::logic::player::player_inventory::ItemUsage; +use crate::logic::player::player_inventory::PlayerInventory; +use crate::logic::player::player_map_trace::PlayerMapTrace; +pub use crate::logic::player::player_mc_element::Element; +use crate::logic::player::player_mc_element::PlayerMcElement; +use crate::logic::player::player_month_card::PlayerMonthCard; +use crate::logic::player::player_teleports::{PlayerTeleport, PlayerTeleports}; +use crate::logic::player::player_tutorials::{PlayerTutorial, PlayerTutorials}; +use crate::logic::{ + components::{ + Attribute, EntityConfig, Equip, FightBuff, Movement, OwnerPlayer, PlayerOwnedEntityMarker, + Position, Visibility, VisionSkill, + }, + ecs::component::ComponentContainer, }; +use crate::session::Session; +use crate::{config, create_player_entity_pb, query_components}; +use crate::logic::player::Element::Spectro; mod basic_info; mod explore_tools; mod in_world_player; mod location; -mod player_func; +mod player_adventure; +mod player_advice; mod player_chat; -mod guides; +mod player_func; +mod player_guides; +mod player_inventory; +mod player_map_trace; +mod player_mc_element; +mod player_month_card; +mod player_teleports; +mod player_tutorials; pub struct Player { session: Option>, @@ -53,7 +84,15 @@ pub struct Player { pub func: PlayerFunc, pub explore_tools: ExploreTools, pub player_chat: PlayerChat, - pub guides: Guides, + pub guides: PlayerGuides, + pub advise: PlayerAdviceConfig, + pub adventure_status: PlayerAdventureStatus, + pub inventory: PlayerInventory, + pub teleports: PlayerTeleports, + pub tutorials: PlayerTutorials, + pub map_trace: PlayerMapTrace, + pub month_card: PlayerMonthCard, + pub mc_element: PlayerMcElement, // Runtime pub world: Rc>, pub last_save_time: u64, @@ -72,83 +111,108 @@ impl Player { pub fn notify_general_data(&self) { self.notify(self.build_adventure_task_notify()); self.notify(AdviceSettingNotify { - is_show: true, + is_show: self.advise.is_show, }); - self.notify(self.basic_info.build_notify()); + self.notify(self.basic_info.build_notify(&self.inventory)); + // CalabashMsgNotify + CalabashLevelRewardsNotify self.notify(ControlInfoNotify { forbid_list: vec![], // Disable function prohibition }); - // CalabashMsgNotify + CalabashLevelRewardsNotify + self.notify(self.explore_tools.build_explore_tool_all_notify()); + self.notify(self.explore_tools.build_vision_explore_skill_notify()); + self.notify(self.explore_tools.build_roulette_update_notify()); + self.notify(self.build_role_favor_list_notify()); self.notify(self.func.build_func_open_notify()); - // RoleFavorListNotify self.notify(InstDataNotify { enter_infos: vec![], // TODO: No effect in normal world, to implement for dungeon::logic() }); self.notify(ItemPkgOpenNotify { open_pkg: (0..8).collect(), }); - // TODO: [WWPS-1] Real implementation should fetch completed / uncompleted from db, lets return completed - for i in 0..40 { - self.notify(MapUnlockFieldNotify { - field_id: i, - }); - } - self.notify(self.build_role_list_notify()); - self.notify(self.explore_tools.build_explore_tool_all_notify()); - self.notify(self.explore_tools.build_roulette_update_notify()); - // VisionExploreSkillNotify self.notify(RoleChangeUnlockNotify { - unlock_role_ids: vec![ - Role::MAIN_CHARACTER_FEMALE_SPECTRO_ID, - Role::MAIN_CHARACTER_MALE_SPECTRO_ID, - Role::MAIN_CHARACTER_MALE_HAVOC_ID, - Role::MAIN_CHARACTER_FEMALE_HAVOC_ID, - ], + // TODO: element persistance + unlock_role_ids: Role::get_mc_unlock_variations(vec![ + Element::Spectro, + Element::Havoc, + Element::Aero, + ]), next_allow_change_time: 0, }); - // EnergyUpdateNotify - // LevelPlayInfoNotify - // MailInfoNotify + self.notify(self.build_role_list_notify()); + // TODO + self.notify(BuffItemNotify { + item_buff_list: vec![], + cr_1: vec![], + }); + // TODO: + self.notify(EnergyUpdateNotify { + update_info: vec![ + EnergyInfo { + energy_count: 240, + last_renew_energy_time: 0, + energy_type: 5, + }, + EnergyInfo { + energy_count: 480, + last_renew_energy_time: 0, + energy_type: 6, + }, + ], + }); + // TODO: + self.notify(LevelPlayInfoNotify { + level_play_info: vec![], + }); // PayShopInfoNotify - // PlayerVarNotify - // RoguelikeCurrencyNotify - // RoleMotionListNotify - // SettingNotify + // TODO: + self.notify(PlayerVarNotify { + var_infos: Default::default(), + }); + self.notify(RoguelikeCurrencyNotify {}); + self.notify(self.build_motion_list_notify()); + self.notify(PassiveSkillNotify { + role_passive_skill_info_list: vec![], // TODO: + }); + + // TODO: + self.notify(MailInfosNotify { mail_infos: vec![] }); + // TODO: + self.notify(SettingNotify { + mobile_button_settings: vec![], + }); + // TODO: + self.notify(MoonChasingTrackMoonHandbookRewardNotify { ids: vec![] }); + // TODO: + self.notify(MoonChasingTargetGetCountNotify { + target_get_count: 0, + }); + // TODO: [WWPS-1] Real implementation should fetch completed / uncompleted from db, lets return completed + // for i in 0..80 { + // self.notify(MapUnlockFieldNotify { field_id: i }); + // } + self.notify(PushContextIdNotify { id: 0 }); + self.notify(PushDataCompleteNotify {}); } fn init_role_and_formation(&mut self) { self.role_list.clear(); - let mut role = match self.basic_info.sex { - 0 => Role::new(Role::MAIN_CHARACTER_FEMALE_SPECTRO_ID), - 1 => Role::new(Role::MAIN_CHARACTER_MALE_SPECTRO_ID), - _ => unreachable!(), - }; - + let mut role = Role::get_mc_based_on_sex(self.basic_info.sex, Spectro); role.name = self.basic_info.name.clone(); - self.role_list.insert(role.role_id, role); - let required_role_ids: Vec = role_info_data::iter() - .filter(|role_info| role_info.role_type == 1) - .map(|role_info| role_info.id) - .collect(); - let formation = vec![1506, 1206, 1505]; - - required_role_ids.iter().for_each(|&role_id| { - if !self.role_list.keys().any(|&k| k == role_id) { + if config::get_config().default_unlocks.unlock_all_roles { + Role::get_all_roles_except_mc().iter().for_each(|&role_id| { + if !self.role_list.keys().any(|&k| k == role_id) { + self.role_list.insert(role_id, Role::new(role_id)); + } + }); + } else { + RoleFormation::default_roles().iter().for_each(|&role_id| { self.role_list.insert(role_id, Role::new(role_id)); - } - }); + }); + } - self.formation_list.insert( - 1, - RoleFormation { - id: 1, - cur_role: *formation.iter().next().unwrap(), - role_ids: formation, - is_current: true, - }, - ); + self.formation_list.insert(1, RoleFormation::default()); self.cur_formation_id = 1; self.formation_list.values_mut().for_each(|formation| { @@ -215,35 +279,94 @@ impl Player { } pub fn build_adventure_task_notify(&self) -> AdventureUpdateNotify { - // TODO: [WWPS-1] Real implementation should fetch completed / uncompleted from db, lets return completed - let adventure_task_data = wicked_waifus_data::adventure_task_data::iter(); - AdventureUpdateNotify { - adventure_manual_data: vec![ - AdventureManualData { - adventre_task: adventure_task_data - .map(|task| AdventreTask { - id:task.id, - adventre_progress: 1, - state:2, + adventure_manual_data: self + .adventure_status + .status + .iter() + .map(|global_status| AdventureManualData { + adventre_task: global_status + .adventure_task_status + .iter() + .map(|status| AdventreTask { + id: status.id, + state: status.state, + adventre_progress: status.progress, }) - .collect(), - now_chapter:9, - received_chapter:9, - } - ], + .collect::>(), + now_chapter: global_status.now_chapter, + received_chapter: global_status.received_chapter, + }) + .collect::>(), } } - pub fn build_player_entity_add_notify( - &self, - role_list: Vec, - world: &mut WorldEntity, - ) -> EntityAddNotify { + pub fn build_role_favor_list_notify(&self) -> RoleFavorListNotify { + RoleFavorListNotify { + favor_list: self + .role_list + .iter() + .map(|(_, role)| RoleFavor { + role_id: role.role_id, + level: role.favor_level, + exp: role.favor_exp, + word_ids: wicked_waifus_data::favor_word_data::iter() + .filter(|&word| word.role_id == role.role_id && word.cond_group_id == 0) // TODO: handle conditions + .map(|word| FavorItem { + id: word.id, + status: 2, + }) + .collect(), + story_ids: wicked_waifus_data::favor_story_data::iter() + .filter(|&story| story.role_id == role.role_id && story.cond_group_id == 0) // TODO: handle conditions + .map(|story| FavorItem { + id: story.id, + status: 2, + }) + .collect(), + goods_ids: wicked_waifus_data::favor_goods_data::iter() + .filter(|&goods| goods.role_id == role.role_id && goods.cond_group_id == 0) // TODO: handle conditions + .map(|goods| FavorItem { + id: goods.id, + status: 2, + }) + .collect(), + favor_quest: None, // TODO: + }) + .collect(), + role_condition_info_map: Default::default(), + } + } + + pub fn build_motion_list_notify(&self) -> RoleMotionListNotify { + RoleMotionListNotify { + motion_list: self + .role_list + .iter() + .map(|(_, role)| { + RoleMotion { + role_id: role.role_id, + motion_ids: motion_data::iter() + .filter(|motion| { + role.role_id == motion.role_id && motion.cond_group_id == 0 + }) // TODO: handle conditions + .map(|motion| FavorItem { + id: motion.id, + status: 2, + }) + .collect::>(), + } + }) + .collect::>(), + role_condition_info_map: Default::default(), + } + } + + pub fn build_player_entity_add_notify(&self, role_list: Vec) -> EntityAddNotify { create_player_entity_pb!( role_list, self.basic_info.cur_map_id, - world, + self, self.basic_info.id, self.location.position.clone(), self.explore_tools @@ -283,12 +406,13 @@ impl Player { .iter() .map(|&role_id| { let entity_id = world.get_entity_id(role_id); - let role_skin = query_components!(world, entity_id, RoleSkin).0.unwrap(); + let role_skin = + query_components!(world, entity_id, RoleSkin).0.unwrap(); FightRoleInfo { role_id, entity_id: world.get_entity_id(role_id), on_stage_without_control: false, - role_skin_id: role_skin.skin_id, + // role_skin_id: role_skin.skin_id, } }) .collect(), @@ -343,6 +467,65 @@ impl Player { } } + pub fn unlock_teleport(&mut self, teleport_id: i32) { + let teleporter = wicked_waifus_data::teleporter_data::iter() + .find(|teleporter| teleporter.id == teleport_id) + .map(|teleporter| PlayerTeleport { + id: teleporter.id, + map_id: teleporter.map_id, + entity_config_id: teleporter.teleport_entity_config_id, + }); + + if let Some(teleporter) = teleporter { + self.teleports.teleports_data.push(teleporter); + + self.notify(HostTeleportUnlockNotify { + host_player_id: self.basic_info.id, + host_teleport_id: teleport_id, + }); + + self.notify(TeleportUpdateNotify { + ids: vec![teleport_id], + }); + } + } + + pub fn unlock_tutorial(&mut self, tutorial_id: i32) -> PlayerTutorial { + let tutorial = PlayerTutorial { + id: tutorial_id, + create_time: time_util::unix_timestamp() as u32, + get_award: false, + }; + self.tutorials.tutorials.push(tutorial.clone()); + tutorial + } + + pub fn notify_month_card(&mut self) { + if self.month_card.days > -1 && time_util::unix_days() != self.month_card.last_received_day + { + let astrites = self.inventory.add_astrite(90); + self.month_card.days -= 1; + self.month_card.last_received_day = time_util::unix_days(); + + self.notify(PlayerAttrNotify { + attributes: vec![PlayerAttr { + key: PlayerAttrKey::RareCoin.into(), + value_type: PlayerAttrType::Int32.into(), + value: Some(Value::Int32Value(astrites)), + }], + }); + self.notify(NormalItemUpdateNotify { + normal_item_list: self.inventory.to_normal_item_list_filtered(vec![3]), + no_tips: false, + }); + self.notify(MonthCardDailyRewardNotify { + item_id: 3, + count: 90, + days: self.month_card.days, + }); + } + } + pub fn load_from_save(save_data: PlayerSaveData) -> Self { let role_data = save_data.role_data.unwrap_or_default(); @@ -380,7 +563,39 @@ impl Player { .unwrap_or_default(), guides: save_data .guides - .map(Guides::load_from_save) + .map(PlayerGuides::load_from_save) + .unwrap_or_default(), + advise: save_data + .advise + .map(PlayerAdviceConfig::load_from_save) + .unwrap_or_default(), + adventure_status: save_data + .adventure_status + .map(PlayerAdventureStatus::load_from_save) + .unwrap_or_default(), + inventory: save_data + .inventory + .map(PlayerInventory::load_from_save) + .unwrap_or_default(), + teleports: save_data + .teleports + .map(PlayerTeleports::load_from_save) + .unwrap_or_default(), + tutorials: save_data + .tutorials + .map(PlayerTutorials::load_from_save) + .unwrap_or_default(), + map_trace: save_data + .map_trace + .map(PlayerMapTrace::load_from_save) + .unwrap_or_default(), + month_card: save_data + .month_card + .map(PlayerMonthCard::load_from_save) + .unwrap_or_default(), + mc_element: save_data + .mc_element + .map(PlayerMcElement::load_from_save) .unwrap_or_default(), world: Rc::new(RefCell::new(World::new())), last_save_time: time_util::unix_timestamp(), @@ -409,6 +624,14 @@ impl Player { explore_tools_data: Some(self.explore_tools.build_save_data()), chat_data: Some(self.player_chat.build_save_data()), guides: Some(self.guides.build_save_data()), + advise: Some(self.advise.build_save_data()), + adventure_status: Some(self.adventure_status.build_save_data()), + inventory: Some(self.inventory.build_save_data()), + teleports: Some(self.teleports.build_save_data()), + tutorials: Some(self.tutorials.build_save_data()), + map_trace: Some(self.map_trace.build_save_data()), + month_card: Some(self.month_card.build_save_data()), + mc_element: Some(self.mc_element.build_save_data()), } } @@ -417,12 +640,12 @@ impl Player { } pub fn build_role_list_notify(&self) -> PbGetRoleListNotify { + // TODO: There is a bug we are investigating with several resonators, this is a workaround PbGetRoleListNotify { role_list: self .role_list .iter() .map(|(_, role)| role.to_protobuf()) - .take(3) // TODO: There is a bug we are investigating with several resonators, this is a workaround .collect(), } } @@ -440,36 +663,27 @@ impl Player { pub fn respond(&self, content: impl ProtocolUnit, rpc_id: u16) { if let Some(session) = self.session.as_ref() { let data = content.encode_to_vec().into_boxed_slice(); - tracing::debug!("Push to gateway MSG_ID: {}, LEN: {}, DATA: {}", content.get_message_id(), data.len(), hex::encode(&data)); let response = Message::Response { sequence_number: 0, message_id: content.get_message_id(), rpc_id, payload: Some(data), }; - // let (name, value) = ("PbGetRoleListNotify", serde_json::to_string_pretty(&list).unwrap()); - // tracing::debug!("trying to log unhandled data for message {name} with:\n{value}"); session.forward_to_gateway(response); } } pub fn create_default_save_data(id: i32, name: String, sex: i32) -> PlayerSaveData { - let role_id = match sex { - 0 => Role::MAIN_CHARACTER_FEMALE_SPECTRO_ID, // 1502 - 1 => Role::MAIN_CHARACTER_MALE_SPECTRO_ID, // 1501 - _ => Role::MAIN_CHARACTER_MALE_SPECTRO_ID, // Default to male - }; - PlayerSaveData { basic_data: Some(PlayerBasicData { id, name, sex, level: 1, - head_photo: 1603, - head_frame: 80060009, + head_photo: 82001603, + head_frame: 0, cur_map_id: 8, - role_show_list: vec![role_id], + role_show_list: vec![Role::get_mc_id_based_on_sex(sex, Spectro)], ..Default::default() }), ..Default::default() diff --git a/wicked-waifus-game-server/src/logic/player/player_adventure.rs b/wicked-waifus-game-server/src/logic/player/player_adventure.rs new file mode 100644 index 0000000..e6ee5f7 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/player/player_adventure.rs @@ -0,0 +1,109 @@ +use wicked_waifus_protocol_internal::{PlayerAdventureGlobalStatusData, PlayerAdventureStatusData, PlayerAdventureTaskStatusData}; + +use crate::config; + +pub struct PlayerAdventureTaskStatus { + pub id: i32, + pub state: i32, + pub progress: i32, +} + +pub struct PlayerAdventureGlobalStatus { + pub adventure_task_status: Vec, + pub now_chapter: i32, + pub received_chapter: i32, +} + +pub struct PlayerAdventureStatus { + pub status: Vec, +} + +impl PlayerAdventureStatus { + pub fn load_from_save(data: PlayerAdventureStatusData) -> Self { + Self { + status: data.status.iter() + .map(|global_status| { + PlayerAdventureGlobalStatus { + adventure_task_status: global_status.status.iter() + .map(|status| { + PlayerAdventureTaskStatus { + id: status.id, + state: status.state, + progress: status.progress, + } + }) + .collect::>(), + now_chapter: global_status.now_chapter, + received_chapter: global_status.received_chapter, + } + }) + .collect::>(), + } + } + + pub fn build_save_data(&self) -> PlayerAdventureStatusData { + PlayerAdventureStatusData { + status: self.status.iter() + .map(|global_status| { + PlayerAdventureGlobalStatusData { + status: global_status.adventure_task_status.iter() + .map(|status| { + PlayerAdventureTaskStatusData { + id: status.id, + state: status.state, + progress: status.progress, + } + }) + .collect::>(), + now_chapter: global_status.now_chapter, + received_chapter: global_status.received_chapter, + } + }) + .collect::>(), + } + } +} + +impl Default for PlayerAdventureStatus { + fn default() -> Self { + if config::get_config().default_unlocks.unlock_all_adventures { + let mut max_chapter = 1; + for task_data in wicked_waifus_data::adventure_task_data::iter() { + if task_data.chapter_id > max_chapter { + max_chapter = task_data.chapter_id; + } + } + Self { + status: vec![ + PlayerAdventureGlobalStatus { + adventure_task_status: wicked_waifus_data::adventure_task_data::iter() + .map(|task| PlayerAdventureTaskStatus { + id: task.id, + state: 2, + progress: task.need_progress, + }) + .collect::>(), + now_chapter: max_chapter, + received_chapter: max_chapter, + } + ], + } + } else { + Self { + status: vec![ + PlayerAdventureGlobalStatus { + adventure_task_status: wicked_waifus_data::adventure_task_data::iter() + .map(|task| PlayerAdventureTaskStatus { + id: task.id, + state: 0, + progress: 0, + }) + .collect::>(), + now_chapter: 1, + received_chapter: 0, + } + ], + } + } + } +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/player/player_advice.rs b/wicked-waifus-game-server/src/logic/player/player_advice.rs new file mode 100644 index 0000000..17d357b --- /dev/null +++ b/wicked-waifus-game-server/src/logic/player/player_advice.rs @@ -0,0 +1,27 @@ +use wicked_waifus_protocol_internal::PlayerAdviceData; + +pub struct PlayerAdviceConfig { + pub is_show: bool, +} + +impl PlayerAdviceConfig { + pub fn load_from_save(data: PlayerAdviceData) -> Self { + PlayerAdviceConfig { + is_show: data.is_show, + } + } + + pub fn build_save_data(&self) -> PlayerAdviceData { + PlayerAdviceData { + is_show: self.is_show, + } + } +} + +impl Default for PlayerAdviceConfig { + fn default() -> Self { + Self { + is_show: true, + } + } +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/player/player_func.rs b/wicked-waifus-game-server/src/logic/player/player_func.rs index c26611d..5951ca8 100644 --- a/wicked-waifus-game-server/src/logic/player/player_func.rs +++ b/wicked-waifus-game-server/src/logic/player/player_func.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use wicked_waifus_data::function_condition_data; use wicked_waifus_protocol::{FuncOpenNotify, Function}; use wicked_waifus_protocol_internal::PlayerFuncData; +use crate::config; pub struct PlayerFunc { pub func_map: HashMap, @@ -41,11 +42,19 @@ impl PlayerFunc { impl Default for PlayerFunc { fn default() -> Self { - Self { - func_map: function_condition_data::iter() - .filter(|fc| (fc.open_condition_id == 0 && fc.is_on) || (fc.function_id == 10009)) // TODO: remove this when required functions are implemented - .map(|fc| (fc.function_id, 2)) - .collect(), + if config::get_config().default_unlocks.unlock_all_functions { + Self { + func_map: function_condition_data::iter() + .map(|fc| (fc.function_id, 2)) + .collect(), + } + } else { + Self { + func_map: function_condition_data::iter() + .filter(|fc| fc.open_condition_id == 0) + .map(|fc| (fc.function_id, 2)) + .collect(), + } } } } diff --git a/wicked-waifus-game-server/src/logic/player/player_guides.rs b/wicked-waifus-game-server/src/logic/player/player_guides.rs new file mode 100644 index 0000000..4a8c2dd --- /dev/null +++ b/wicked-waifus-game-server/src/logic/player/player_guides.rs @@ -0,0 +1,41 @@ +use std::collections::HashSet; + +use wicked_waifus_protocol_internal::PlayerGuidesData; + +use crate::config; + +pub struct PlayerGuides { + pub started_guides: HashSet, + pub finished_guides: HashSet, +} + +impl PlayerGuides { + pub fn load_from_save(data: PlayerGuidesData) -> Self { + PlayerGuides { + started_guides: data.started_guides.iter().cloned().collect(), + finished_guides: data.finished_guides.iter().cloned().collect(), + } + } + + pub fn build_save_data(&self) -> PlayerGuidesData { + PlayerGuidesData { + started_guides: self.started_guides.iter().cloned().collect(), + finished_guides: self.finished_guides.iter().cloned().collect(), + } + } +} + +impl Default for PlayerGuides { + fn default() -> Self { + let finished_guides = if config::get_config().default_unlocks.unlock_all_guides { + let guide_group_data = wicked_waifus_data::guide_group_data::iter(); + guide_group_data.map(|group| group.id).collect() + } else { + HashSet::new() + }; + Self { + started_guides: HashSet::new(), + finished_guides, + } + } +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/player/player_inventory.rs b/wicked-waifus-game-server/src/logic/player/player_inventory.rs new file mode 100644 index 0000000..c265df2 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/player/player_inventory.rs @@ -0,0 +1,154 @@ +use std::collections::HashMap; + +use wicked_waifus_protocol::NormalItem; + +use wicked_waifus_protocol_internal::PlayerInventoryData; + +pub struct PlayerInventory { + items: HashMap, +} + +pub struct ItemUsage { + pub id: i32, + pub quantity: i32, +} + +#[derive(thiserror::Error, Debug)] +pub enum InventoryError { + #[error("Item with id: {0} doesn't exist in inventory")] + ItemNotFound(i32), + #[error("There isn't enough quantity of item with id: {0}, current: {1}, requested: {2}")] + ItemNotEnough(i32, i32, i32), + #[error("There isn't enough quantity of some of the items required")] + ItemsNotEnough(), +} + +impl PlayerInventory { + const UNION_EXP_ID: i32 = 1; + const SHELL_CREDIT_ID: i32 = 2; + const ASTRITE_ID: i32 = 3; + const LUNITE_ID: i32 = 4; + const WAVEPLATE_ID: i32 = 5; + const WAVEPLATE_CRYSTAL_ID: i32 = 6; + + pub fn load_from_save(data: PlayerInventoryData) -> Self { + Self { + items: data.items.clone(), + } + } + + pub fn build_save_data(&self) -> PlayerInventoryData { + PlayerInventoryData { + items: self.items.clone(), + } + } + + pub fn add_item(&mut self, id: i32, quantity: i32) -> i32 { + self.add_internal(id, quantity) + } + + pub fn add_items(&mut self, usages: &[ItemUsage]) -> HashMap { + self.add_many_internal(usages) + } + + pub fn consume_item(&mut self, id: i32, quantity: i32) -> Result { + Ok(*self.consume_items(&[ItemUsage { id, quantity: -quantity }])?.get(&id).unwrap()) + } + + pub fn consume_items(&mut self, usages: &[ItemUsage]) -> Result, InventoryError> { + if !self.has_enough_items(usages) { + return Err(InventoryError::ItemsNotEnough()); + } + Ok(self.add_many_internal(usages)) + } + + // TODO: Check if this is item or not + #[inline(always)] + pub fn get_union_exp(&self) -> i32 { + self.items.get(&Self::UNION_EXP_ID).copied().unwrap_or(0) + } + + #[inline(always)] + pub fn get_shell_credits(&self) -> i32 { + self.items.get(&Self::SHELL_CREDIT_ID).copied().unwrap_or(0) + } + + #[inline(always)] + pub fn add_astrite(&mut self, count: i32) -> i32 { + self.add_internal(Self::ASTRITE_ID, count) + } + + #[inline(always)] + pub fn get_astrite(&self) -> i32 { + self.items.get(&Self::ASTRITE_ID).copied().unwrap_or(0) + } + + #[inline(always)] + pub fn get_lunite(&self) -> i32 { + self.items.get(&Self::LUNITE_ID).copied().unwrap_or(0) + } + + // TODO: Check if this is item or not + #[inline(always)] + pub fn get_waveplate(&self) -> i32 { + self.items.get(&Self::WAVEPLATE_ID).copied().unwrap_or(0) + } + + // TODO: Check if this is item or not + #[inline(always)] + pub fn get_waveplate_crystal(&self) -> i32 { + self.items.get(&Self::WAVEPLATE_CRYSTAL_ID).copied().unwrap_or(0) + } + + pub fn to_normal_item_list(&self) -> Vec { + self.items.iter() + .filter(|(&id, _)| Self::WAVEPLATE_ID != id && Self::WAVEPLATE_CRYSTAL_ID != id) + // TODO: Implement expiration + .map(|(&id, &count)| NormalItem { id, count, expire_time: 0 }) + .collect::>() + } + + pub fn to_normal_item_list_filtered(&self, ids: Vec) -> Vec { + self.items.iter() + .filter(|(&id, _)| ids.contains(&id)) + // TODO: Implement expiration + .map(|(&id, &count)| NormalItem { id, count, expire_time: 0 }) + .collect::>() + } + + #[inline(always)] + fn add_internal(&mut self, id: i32, quantity: i32) -> i32 { + *self.items.entry(id) + .and_modify(|count| *count += quantity) + .or_insert(quantity) + } + + #[inline(always)] + fn add_many_internal(&mut self, usages: &[ItemUsage]) -> HashMap { + usages.iter() + .filter(|usage| usage.quantity != 0) + .map(|delta| (delta.id, self.add_internal(delta.id, delta.quantity))) + .collect::>() + } + + #[inline(always)] + fn has_enough_item(&self, id: i32, quantity: i32) -> bool { + self.items.get(&id).copied().unwrap_or(0) >= quantity + } + + #[inline(always)] + fn has_enough_items(&self, items_delta: &[ItemUsage]) -> bool { + items_delta.iter() + .fold(true, |is_enough, delta| { + is_enough && self.has_enough_item(delta.id, -delta.quantity) + }) + } +} + +impl Default for PlayerInventory { + fn default() -> Self { + Self { + items: HashMap::new(), + } + } +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/player/player_map_trace.rs b/wicked-waifus-game-server/src/logic/player/player_map_trace.rs new file mode 100644 index 0000000..d25c231 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/player/player_map_trace.rs @@ -0,0 +1,28 @@ +use std::collections::HashSet; +use wicked_waifus_protocol_internal::PlayerMapTraceData; + +pub struct PlayerMapTrace { + pub traces: HashSet, +} + +impl PlayerMapTrace { + pub fn load_from_save(data: PlayerMapTraceData) -> Self { + Self { + traces: data.traces.iter().cloned().collect(), + } + } + + pub fn build_save_data(&self) -> PlayerMapTraceData { + PlayerMapTraceData { + traces: self.traces.iter().cloned().collect(), + } + } +} + +impl Default for PlayerMapTrace { + fn default() -> Self { + Self { + traces: HashSet::new(), + } + } +} diff --git a/wicked-waifus-game-server/src/logic/player/player_mc_element.rs b/wicked-waifus-game-server/src/logic/player/player_mc_element.rs new file mode 100644 index 0000000..720d394 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/player/player_mc_element.rs @@ -0,0 +1,82 @@ +use crate::config; +use crate::logic::player::player_mc_element::Element::{ + Aero, Electro, Fusion, Glacio, Havoc, Spectro, +}; +use wicked_waifus_protocol_internal::PlayerMcElementData; + +pub enum Element { + Glacio, + Fusion, + Electro, + Aero, + Spectro, + Havoc, +} + +pub struct PlayerMcElement { + pub unlocked_elements: Vec, + pub current_element: Element, +} + +impl PlayerMcElement { + pub fn load_from_save(data: PlayerMcElementData) -> Self { + Self { + unlocked_elements: data + .unlocked_elements + .iter() + .map(|&element| Element::from(element)) + .collect(), + current_element: Element::from(data.current_element), + } + } + + pub fn build_save_data(&self) -> PlayerMcElementData { + PlayerMcElementData { + unlocked_elements: self + .unlocked_elements + .iter() + .map(|element| element.into()) + .collect(), + current_element: (&self.current_element).into(), + } + } +} + +impl From for Element { + fn from(value: i32) -> Self { + match value { + 0 => Glacio, + 1 => Fusion, + 2 => Electro, + 3 => Aero, + 4 => Spectro, + 5 => Havoc, + _ => unreachable!(), + } + } +} + +impl Into for &Element { + fn into(self) -> i32 { + match self { + Glacio => 0, + Fusion => 1, + Electro => 2, + Aero => 3, + Spectro => 4, + Havoc => 5, + } + } +} + +impl Default for PlayerMcElement { + fn default() -> Self { + Self { + unlocked_elements: match config::get_config().default_unlocks.unlock_all_mc_elements { + true => vec![Spectro, Havoc, Aero], + false => vec![Spectro], + }, + current_element: Spectro, + } + } +} diff --git a/wicked-waifus-game-server/src/logic/player/player_month_card.rs b/wicked-waifus-game-server/src/logic/player/player_month_card.rs new file mode 100644 index 0000000..a39c291 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/player/player_month_card.rs @@ -0,0 +1,31 @@ +use wicked_waifus_protocol_internal::PlayerMonthCardData; + +pub struct PlayerMonthCard { + pub days: i32, + pub last_received_day: i32 +} + +impl PlayerMonthCard { + pub fn load_from_save(data: PlayerMonthCardData) -> Self { + Self { + days: data.days, + last_received_day: data.last_received_day, + } + } + + pub fn build_save_data(&self) -> PlayerMonthCardData { + PlayerMonthCardData { + days: self.days, + last_received_day: self.last_received_day, + } + } +} + +impl Default for PlayerMonthCard { + fn default() -> Self { + Self { + days: 3650, + last_received_day: wicked_waifus_commons::time_util::unix_days() - 1, + } + } +} diff --git a/wicked-waifus-game-server/src/logic/player/player_teleports.rs b/wicked-waifus-game-server/src/logic/player/player_teleports.rs new file mode 100644 index 0000000..2679309 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/player/player_teleports.rs @@ -0,0 +1,63 @@ +use wicked_waifus_protocol_internal::{PlayerTeleportData, PlayerTeleportsData}; + +use crate::config; + +pub struct PlayerTeleport { + pub id: i32, + pub map_id: i32, + pub entity_config_id: i64, +} + +pub struct PlayerTeleports { + pub teleports_data: Vec, +} + +impl PlayerTeleports { + pub fn load_from_save(data: PlayerTeleportsData) -> Self { + Self { + teleports_data: data + .teleport_data + .iter() + .map(|teleport| PlayerTeleport { + id: teleport.id, + map_id: teleport.map_id, + entity_config_id: teleport.entity_config_id, + }) + .collect::>(), + } + } + + pub fn build_save_data(&self) -> PlayerTeleportsData { + PlayerTeleportsData { + teleport_data: self + .teleports_data + .iter() + .map(|teleport| PlayerTeleportData { + id: teleport.id, + map_id: teleport.map_id, + entity_config_id: teleport.entity_config_id, + }) + .collect::>(), + } + } +} + +impl Default for PlayerTeleports { + fn default() -> Self { + if config::get_config().default_unlocks.unlock_all_teleporter { + Self { + teleports_data: wicked_waifus_data::teleporter_data::iter() + .map(|teleporter| PlayerTeleport { + id: teleporter.id, + map_id: teleporter.map_id, + entity_config_id: teleporter.teleport_entity_config_id, + }) + .collect::>(), + } + } else { + Self { + teleports_data: vec![], + } + } + } +} diff --git a/wicked-waifus-game-server/src/logic/player/player_tutorials.rs b/wicked-waifus-game-server/src/logic/player/player_tutorials.rs new file mode 100644 index 0000000..2ee5c05 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/player/player_tutorials.rs @@ -0,0 +1,64 @@ +use wicked_waifus_protocol_internal::{ + PlayerTutorialData, PlayerTutorialsData, +}; + +use crate::config; + +#[derive(Clone)] +pub struct PlayerTutorial { + pub id: i32, + pub create_time: u32, + pub get_award: bool, +} + +pub struct PlayerTutorials { + pub tutorials: Vec, +} + +impl PlayerTutorials { + pub fn load_from_save(data: PlayerTutorialsData) -> Self { + Self { + tutorials: data + .tutorials + .iter() + .map(|tutorial| PlayerTutorial { + id: tutorial.id, + create_time: tutorial.create_time, + get_award: tutorial.get_award, + }) + .collect::>(), + } + } + + pub fn build_save_data(&self) -> PlayerTutorialsData { + PlayerTutorialsData { + tutorials: self + .tutorials + .iter() + .map(|tutorial| PlayerTutorialData { + id: tutorial.id, + create_time: tutorial.create_time, + get_award: tutorial.get_award, + }) + .collect::>(), + } + } +} + +impl Default for PlayerTutorials { + fn default() -> Self { + if config::get_config().default_unlocks.unlock_all_tutorials { + Self { + tutorials: wicked_waifus_data::guide_tutorial_data::iter() + .map(|tutorial| PlayerTutorial { + id: tutorial.id, + create_time: wicked_waifus_commons::time_util::unix_timestamp() as u32, + get_award: false, + }) + .collect::>(), + } + } else { + Self { tutorials: vec![] } + } + } +} diff --git a/wicked-waifus-game-server/src/logic/role/formation.rs b/wicked-waifus-game-server/src/logic/role/formation.rs index 2c7647b..6319b7f 100644 --- a/wicked-waifus-game-server/src/logic/role/formation.rs +++ b/wicked-waifus-game-server/src/logic/role/formation.rs @@ -7,7 +7,14 @@ pub struct RoleFormation { pub is_current: bool, } +// Will be updated every version +const DEFAULT_FORMATION: &[i32] = &[1203, 1502, 1607]; + impl RoleFormation { + pub fn default_roles() -> &'static [i32] { + DEFAULT_FORMATION + } + pub fn load_from_save(data: RoleFormationData) -> Self { Self { id: data.formation_id, @@ -26,3 +33,14 @@ impl RoleFormation { } } } + +impl Default for RoleFormation { + fn default() -> Self { + Self { + id: 1, + cur_role: DEFAULT_FORMATION[0], + role_ids: DEFAULT_FORMATION.to_vec(), + is_current: true, + } + } +} diff --git a/wicked-waifus-game-server/src/logic/role/mod.rs b/wicked-waifus-game-server/src/logic/role/mod.rs index 391f01c..98e76aa 100644 --- a/wicked-waifus-game-server/src/logic/role/mod.rs +++ b/wicked-waifus-game-server/src/logic/role/mod.rs @@ -1,11 +1,31 @@ use std::collections::HashMap; -use crate::logic::utils::load_role_info::load_key_value; -use wicked_waifus_commons::time_util; -pub use formation::RoleFormation; -use wicked_waifus_data::{base_property_data, role_info_data}; use wicked_waifus_protocol::{ArrayIntInt, RoleInfo}; -use wicked_waifus_protocol_internal::RoleData; + +use crate::config; +use crate::logic::utils::growth_utils::get_role_props_by_level; +use crate::logic::utils::load_role_info::load_key_value; +pub use formation::RoleFormation; +use wicked_waifus_commons::time_util; +use wicked_waifus_data::{role_info_data, BasePropertyData}; +use wicked_waifus_protocol_internal::{RoleData, RoleStats}; +use crate::logic::player::Element; + +const MAIN_CHARACTER_MALE_SPECTRO_ID: i32 = 1501; +const MAIN_CHARACTER_FEMALE_SPECTRO_ID: i32 = 1502; +const MAIN_CHARACTER_MALE_HAVOC_ID: i32 = 1605; +const MAIN_CHARACTER_FEMALE_HAVOC_ID: i32 = 1604; +const MAIN_CHARACTER_MALE_AERO_ID: i32 = 1406; +const MAIN_CHARACTER_FEMALE_AERO_ID: i32 = 1408; + +const MAIN_CHARACTER_ARRAY: &[i32] = &[ + MAIN_CHARACTER_MALE_SPECTRO_ID, + MAIN_CHARACTER_FEMALE_SPECTRO_ID, + MAIN_CHARACTER_MALE_HAVOC_ID, + MAIN_CHARACTER_FEMALE_HAVOC_ID, + MAIN_CHARACTER_MALE_AERO_ID, + MAIN_CHARACTER_FEMALE_AERO_ID, +]; mod formation; pub struct Role { @@ -20,41 +40,136 @@ pub struct Role { pub create_time: u32, pub equip_weapon: i32, pub skin_id: i32, + pub resonant_chain_group_index: i32, + pub hp: i32, + pub energy: i32, + pub special_energy_1: i32, + pub special_energy_2: i32, + pub special_energy_3: i32, + pub special_energy_4: i32, + pub element_energy: i32, + pub favor_level: i32, + pub favor_exp: i32, } impl Role { - pub const MAIN_CHARACTER_MALE_SPECTRO_ID: i32 = 1501; - pub const MAIN_CHARACTER_FEMALE_SPECTRO_ID: i32 = 1502; - pub const MAIN_CHARACTER_MALE_HAVOC_ID: i32 = 1605; - pub const MAIN_CHARACTER_FEMALE_HAVOC_ID: i32 = 1604; + #[inline(always)] + pub fn get_all_roles_except_mc() -> Vec { + role_info_data::iter() + .filter(|role| role.role_type == 1 && !MAIN_CHARACTER_ARRAY.contains(&role.id)) + .map(|role| role.id) + .collect() + } + + #[inline(always)] + pub fn get_mc_id_based_on_sex(sex: i32, current_element: Element) -> i32 { + match current_element { + Element::Glacio => unreachable!(), + Element::Fusion => unreachable!(), + Element::Electro => unreachable!(), + Element::Aero => match sex { + 0 => MAIN_CHARACTER_MALE_AERO_ID, + 1 => MAIN_CHARACTER_FEMALE_AERO_ID, + _ => unreachable!(), + } + Element::Spectro => match sex { + 0 => MAIN_CHARACTER_FEMALE_SPECTRO_ID, + 1 => MAIN_CHARACTER_MALE_SPECTRO_ID, + _ => unreachable!(), + } + Element::Havoc => match sex { + 0 => MAIN_CHARACTER_MALE_HAVOC_ID, + 1 => MAIN_CHARACTER_FEMALE_HAVOC_ID, + _ => unreachable!(), + } + } + } + + #[inline(always)] + pub fn get_mc_based_on_sex(sex: i32, current_element: Element) -> Self { + Role::new(Self::get_mc_id_based_on_sex(sex, current_element)) + } + + pub fn get_mc_unlock_variations(unlocked_elements: Vec) -> Vec { + let mut variations: Vec = Vec::new(); + for element in unlocked_elements { + match element { + Element::Glacio => {}, + Element::Fusion => {}, + Element::Electro => {}, + Element::Aero => { + variations.push(MAIN_CHARACTER_MALE_AERO_ID); + variations.push(MAIN_CHARACTER_FEMALE_AERO_ID); + }, + Element::Spectro => { + variations.push(MAIN_CHARACTER_MALE_SPECTRO_ID); + variations.push(MAIN_CHARACTER_FEMALE_SPECTRO_ID); + }, + Element::Havoc => { + variations.push(MAIN_CHARACTER_MALE_HAVOC_ID); + variations.push(MAIN_CHARACTER_FEMALE_HAVOC_ID); + }, + } + } + variations + } pub fn new(role_id: i32) -> Self { let data = role_info_data::iter().find(|d| d.id == role_id).unwrap(); + let default_unlocks = &config::get_config().default_unlocks; + let (level, breakthrough) = if default_unlocks.unlock_all_roles_max_level { + (data.max_level, 6) + } else { + (1, 0) + }; + let resonant_chain_group_index = if default_unlocks.unlock_all_roles_all_sequences { + 6 + } else { + 0 + }; + let base_stats = &get_role_props_by_level(role_id, level, breakthrough); Self { role_id, name: String::with_capacity(0), - level: data.max_level, - exp: 0, - breakthrough: 0, + level, + exp: 0, // TODO: Compute based on level?? + breakthrough, skill_map: HashMap::new(), // TODO! star: 0, favor: 0, create_time: time_util::unix_timestamp() as u32, equip_weapon: data.init_weapon_item_id, - skin_id: data.skin_id + skin_id: data.skin_id, + resonant_chain_group_index, + hp: base_stats.life, + energy: base_stats.energy, + special_energy_1: base_stats.special_energy_1, + special_energy_2: base_stats.special_energy_2, + special_energy_3: base_stats.special_energy_3, + special_energy_4: base_stats.special_energy_4, + element_energy: base_stats.element_energy, + favor_level: 0, + favor_exp: 0, } } - pub fn to_protobuf(&self) -> RoleInfo { - let base_prop: HashMap = load_key_value( - base_property_data::iter() - .find(|d| d.id == self.role_id) - .unwrap_or_else(|| { - base_property_data::iter().find(|d| d.id == 1102).unwrap() - }), - ); + pub fn get_base_properties(&self) -> BasePropertyData { + // Overwrite dynamic attributes with stores values + let mut base_stats = get_role_props_by_level(self.role_id, self.level, self.breakthrough); + // TODO: Integrity check, value has to be between 0 and max + base_stats.life = self.hp; + base_stats.energy = self.energy; + base_stats.special_energy_1 = self.special_energy_1; + base_stats.special_energy_2 = self.special_energy_2; + base_stats.special_energy_3 = self.special_energy_3; + base_stats.special_energy_4 = self.special_energy_4; + base_stats.element_energy = self.element_energy; + base_stats + } + pub fn to_protobuf(&self) -> RoleInfo { + let base_prop: HashMap = load_key_value(&self.get_base_properties()); RoleInfo { role_id: self.role_id, name: self.name.clone(), @@ -67,13 +182,12 @@ impl Role { .iter() .map(|(k, v)| ArrayIntInt { key: *k, value: *v }) .collect(), - star: self.star, - favor: self.favor, base_prop: base_prop .iter() .map(|(&k, &v)| ArrayIntInt { key: k, value: v }) .collect(), skin_id: self.skin_id, + resonant_chain_group_index: self.resonant_chain_group_index, ..Default::default() } } @@ -92,7 +206,17 @@ impl Role { favor: data.favor, create_time: data.create_time, equip_weapon: data.equip_weapon, - skin_id: data.skin_id + skin_id: data.skin_id, + resonant_chain_group_index: data.resonant_chain_group_index, + hp: data.stats.unwrap().hp, + energy: data.stats.unwrap().energy, + special_energy_1: data.stats.unwrap().special_energy_1, + special_energy_2: data.stats.unwrap().special_energy_2, + special_energy_3: data.stats.unwrap().special_energy_3, + special_energy_4: data.stats.unwrap().special_energy_4, + element_energy: data.stats.unwrap().element_energy, + favor_level: data.favor_level, + favor_exp: data.favor_exp, }, ) } @@ -105,11 +229,27 @@ impl Role { exp: self.exp, breakthrough: self.breakthrough, skill_map: self.skill_map.clone(), + // phantom_map: Default::default(), star: self.star, favor: self.favor, create_time: self.create_time, + // cur_model: 0, + // models: vec![], + // skill_node_state: vec![], + resonant_chain_group_index: self.resonant_chain_group_index, equip_weapon: self.equip_weapon, skin_id: self.skin_id, + stats: Some(RoleStats { + hp: self.hp, + energy: self.energy, + special_energy_1: self.special_energy_1, + special_energy_2: self.special_energy_2, + special_energy_3: self.special_energy_3, + special_energy_4: self.special_energy_4, + element_energy: self.element_energy, + }), + favor_level: self.favor_level, + favor_exp: self.favor_exp, ..Default::default() } } diff --git a/wicked-waifus-game-server/src/logic/systems/movement.rs b/wicked-waifus-game-server/src/logic/systems/movement.rs index d7d5742..c9cc356 100644 --- a/wicked-waifus-game-server/src/logic/systems/movement.rs +++ b/wicked-waifus-game-server/src/logic/systems/movement.rs @@ -50,7 +50,7 @@ impl System for MovementSystem { if let (Some(_), Some(owner)) = query_components!( world_entity, i64::from(entity), - PlayerEntityMarker, + PlayerOwnedEntityMarker, OwnerPlayer ) { if let Some(player) = players.iter_mut().find(|pl| pl.basic_info.id == owner.0) { diff --git a/wicked-waifus-game-server/src/logic/thread_mgr.rs b/wicked-waifus-game-server/src/logic/thread_mgr.rs index 84853c7..4455981 100644 --- a/wicked-waifus-game-server/src/logic/thread_mgr.rs +++ b/wicked-waifus-game-server/src/logic/thread_mgr.rs @@ -1,9 +1,6 @@ use wicked_waifus_commons::time_util; use wicked_waifus_protocol_internal::PlayerSaveData; -use wicked_waifus_protocol::{ - message::Message, AfterJoinSceneNotify, EnterGameResponse, JoinSceneNotify, JsPatchNotify, - PushDataCompleteNotify, SilenceNpcNotify, TransitionOptionPb, -}; +use wicked_waifus_protocol::{message::Message, AfterJoinSceneNotify, EnterGameResponse, JoinSceneNotify, SilenceNpcNotify, TransitionOptionPb}; use std::collections::hash_map::Entry::Vacant; use std::{ cell::RefCell, @@ -16,15 +13,10 @@ use std::{ thread, time::Duration, }; - use super::{ecs::world::World, player::Player, utils::world_util}; use crate::logic::ecs::world::WorldEntity; use crate::{logic, player_save_task::{self, PlayerSaveReason}, session::Session}; -const WATER_MASK: &str = include_str!("../../scripts/watermask-disable.js"); -const UID_FIX: &str = include_str!("../../scripts/uidfix.js"); -const CENSORSHIP_FIX: &str = include_str!("../../scripts/censorshipfix.js"); - pub enum LogicInput { AddPlayer { player_id: i32, @@ -185,31 +177,17 @@ fn handle_logic_input(state: &mut LogicState, input: LogicInput) { player.notify(AfterJoinSceneNotify::default()); player.notify(player.build_update_formation_notify()); - player.notify(PushDataCompleteNotify {}); - // TODO: maybe move somewhere else? - // TODO: Add the possibility to customize size and text from options - player.notify(JsPatchNotify { - content: WATER_MASK.to_string(), - }); - player.notify(JsPatchNotify { - content: UID_FIX - .replace("{PLAYER_USERNAME}", &player.basic_info.name) - .replace("{SELECTED_COLOR}", "50FC71"), - }); - player.notify(JsPatchNotify { - content: CENSORSHIP_FIX.to_string(), - }); - - let map = logic::utils::quadrant_util::get_map(player.location.instance_id); + let map = logic::utils::quadrant_util::get_map(player.basic_info.cur_map_id); let quadrant_id = map.get_quadrant_id( player.location.position.position.x * 100.0, player.location.position.position.y * 100.0, ); player.quadrant_id = quadrant_id; + player.notify_month_card(); let entities = map.get_initial_entities(quadrant_id); - world_util::add_entities(&player, &entities); + world_util::add_entities(&player, &entities, false); drop(player); @@ -235,7 +213,7 @@ fn handle_logic_input(state: &mut LogicState, input: LogicInput) { let _ = state.worlds.remove(&player_id); // TODO: kick co-op players from removed world - // TODO: Remove all entitie + // TODO: Remove all entities player_save_task::push( player_id, diff --git a/wicked-waifus-game-server/src/logic/utils/action_utils.rs b/wicked-waifus-game-server/src/logic/utils/action_utils.rs new file mode 100644 index 0000000..0fb3365 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/utils/action_utils.rs @@ -0,0 +1,290 @@ +use std::collections::HashMap; + +use wicked_waifus_protocol::{CommonTagData, EntityCommonTagNotify, EntityStateReadyNotify, ItemRewardNotify, Ls2, NormalItemUpdateNotify, RewardItemInfo}; + +use wicked_waifus_data::pb_components::action::{Action, ChangeSelfEntityState, UnlockTeleportTrigger}; +use wicked_waifus_data::pb_components::entity_state::EntityStateComponent; + +use crate::logic::ecs::component::ComponentContainer; +use crate::logic::player::{ItemUsage, Player}; +use crate::logic::utils::tag_utils; +use crate::query_components; + +macro_rules! unimplemented_action { + ($action:ident) => { + { + tracing::warn!("Action not implemented for: {:?}", $action); + } + } +} + +pub fn perform_action(player: &mut Player, + entity_id: i64, + level_entity_data: &wicked_waifus_data::LevelEntityConfigData, + template_config: &wicked_waifus_data::TemplateConfigData, + element: Action) { + match element { + Action::SetBattleState(action) => unimplemented_action! { action }, + Action::ExecBattleAction(action) => unimplemented_action! { action }, + Action::WaitBattleCondition(action) => unimplemented_action! { action }, + Action::PlayFlow(action) => unimplemented_action! { action }, + Action::Collect(_) => collect_action(player, level_entity_data, template_config), + Action::LeisureInteract(action) => unimplemented_action! { action }, + Action::UnlockTeleportTrigger(action) => unlock_teleport_trigger(player, action.params), + Action::EnableTemporaryTeleport(action) => unimplemented_action! { action }, + Action::OpenSystemBoard(action) => unimplemented_action! { action }, + Action::OpenSystemFunction(action) => unimplemented_action! { action }, + Action::ChangeSelfEntityState(action) => change_self_entity_state(player, entity_id, level_entity_data, template_config, action.params), + Action::SetPlayerOperationRestriction(action) => unimplemented_action! { action }, + Action::Wait(action) => unimplemented_action! { action }, + Action::ChangeEntityState(action) => unimplemented_action! { action }, + Action::Log(action) => unimplemented_action! { action }, + Action::EnableNearbyTracking(action) => unimplemented_action! { action }, + Action::TeleportDungeon(action) => unimplemented_action! { action }, + Action::DestroySelf(action) => unimplemented_action! { action }, + Action::CameraLookAt(action) => unimplemented_action! { action }, + Action::EnterOrbitalCamera(action) => unimplemented_action! { action }, + Action::ExitOrbitalCamera(action) => unimplemented_action! { action }, + Action::SendAiEvent(action) => unimplemented_action! { action }, + Action::SetInteractionLockState(action) => unimplemented_action! { action }, + Action::AwakeEntity(action) => unimplemented_action! { action }, + Action::ChangeLiftTarget(action) => unimplemented_action! { action }, + Action::CalculateVar(action) => unimplemented_action! { action }, + Action::AddBuffToPlayer(action) => unimplemented_action! { action }, + Action::RemoveBuffFromPlayer(action) => unimplemented_action! { action }, + Action::AddBuffToEntity(action) => unimplemented_action! { action }, + Action::RemoveBuffFromEntity(action) => unimplemented_action! { action }, + Action::Prompt(action) => unimplemented_action! { action }, + Action::SetEntityVisible(action) => unimplemented_action! { action }, + Action::DestroyEntity(action) => unimplemented_action! { action }, + Action::GuideTrigger(action) => unimplemented_action! { action }, + Action::TriggerCameraShake(action) => unimplemented_action! { action }, + Action::SetVar(action) => unimplemented_action! { action }, + Action::VehicleEnter(action) => unimplemented_action! { action }, + Action::VehicleExitPlayer(action) => unimplemented_action! { action }, + Action::LockEntity(action) => unimplemented_action! { action }, + Action::UnlockEntity(action) => unimplemented_action! { action }, + Action::CommonTip(action) => unimplemented_action! { action }, + Action::CommonTip2(action) => unimplemented_action! { action }, + Action::PostAkEvent(action) => unimplemented_action! { action }, + Action::VehicleEnterNpc(action) => unimplemented_action! { action }, + Action::VehicleExitNpc(action) => unimplemented_action! { action }, + Action::PlayerLookAt(action) => unimplemented_action! { action }, + Action::PlayBubble(action) => unimplemented_action! { action }, + Action::AddPlayBubble(action) => unimplemented_action! { action }, + Action::ClearPlayBubble(action) => unimplemented_action! { action }, + Action::ExecRiskHarvestEffect(action) => unimplemented_action! { action }, + Action::EnableLevelPlay(action) => unimplemented_action! { action }, + Action::ClaimLevelPlayReward(action) => unimplemented_action! { action }, + Action::SettlementDungeon(action) => unimplemented_action! { action }, + Action::ExitDungeon(action) => unimplemented_action! { action }, + Action::FinishDungeon(action) => unimplemented_action! { action }, + Action::RecordDungeonEvent(action) => unimplemented_action! { action }, + Action::RecoverDurability(action) => unimplemented_action! { action }, + Action::FadeInScreen(action) => unimplemented_action! { action }, + Action::FadeOutScreen(action) => unimplemented_action! { action }, + Action::ChangeNpcPerformState(action) => unimplemented_action! { action }, + Action::EntityTurnTo(action) => unimplemented_action! { action }, + Action::EntityLookAt(action) => unimplemented_action! { action }, + Action::ToggleMapMarkState(action) => unimplemented_action! { action }, + Action::RandomVar(action) => unimplemented_action! { action }, + Action::ModifySceneItemAttributeTag(action) => unimplemented_action! { action }, + Action::VehicleWaterfallClimbing(action) => unimplemented_action! { action }, + Action::VehicleTeleport(action) => unimplemented_action! { action }, + Action::RogueGotoNextFloor(action) => unimplemented_action! { action }, + Action::RogueReceiveReward(action) => unimplemented_action! { action }, + Action::RogueSelectRoom(action) => unimplemented_action! { action }, + Action::RogueActivatePortal(action) => unimplemented_action! { action }, + Action::MowingTowerGotoNextFloor(action) => unimplemented_action! { action }, + Action::SlashAndTowerGotoNextFloor(action) => unimplemented_action! { action }, + Action::PlayMontage(action) => unimplemented_action! { action }, + Action::OpenSystemBoardWithReturn(action) => unimplemented_action! { action }, + Action::UnlockSystemItem(action) => unimplemented_action! { action }, + Action::SetSportsState(action) => unimplemented_action! { action }, + Action::OpenSimpleGameplay(action) => unimplemented_action! { action }, + Action::PlayEffect(action) => unimplemented_action! { action }, + Action::RestorePlayerCameraAdjustment(action) => unimplemented_action! { action }, + Action::AdjustPlayerCamera(action) => unimplemented_action! { action }, + Action::SetPlayerPos(action) => unimplemented_action! { action }, + Action::MoveWithSpline(action) => unimplemented_action! { action }, + Action::EnableSplineMoveModel(action) => unimplemented_action! { action }, + Action::ToggleScanSplineEffect(action) => unimplemented_action! { action }, + Action::MoveSceneItem(action) => unimplemented_action! { action }, + Action::StopSceneItemMove(action) => unimplemented_action! { action }, + Action::FireBullet(action) => unimplemented_action! { action }, + Action::ClearFishingCabinInSaleItems(action) => unimplemented_action! { action }, + Action::AcceptFishingEntrust(action) => unimplemented_action! { action }, + Action::DestroyFishingBoat(action) => unimplemented_action! { action }, + Action::SetJigsawItem(action) => unimplemented_action! { action }, + Action::SetJigsawFoundation(action) => unimplemented_action! { action }, + Action::SetTeleControl(action) => unimplemented_action! { action }, + Action::SetEntityClientVisible(action) => unimplemented_action! { action }, + Action::ToggleHighlightExploreUi(action) => unimplemented_action! { action }, + Action::ExecAlertSystemAction(action) => unimplemented_action! { action }, + Action::AddFlowInteractOption(action) => unimplemented_action! { action }, + Action::RemoveFlowInteractOption(action) => unimplemented_action! { action }, + Action::EnableHostility(action) => unimplemented_action! { action }, + Action::ChangePhantomFormation(action) => unimplemented_action! { action }, + Action::RestorePhantomFormation(action) => unimplemented_action! { action }, + Action::ChangeTimer(action) => unimplemented_action! { action }, + Action::ToggleTimerPauseState(action) => unimplemented_action! { action }, + Action::ChangeFightTeam(action) => unimplemented_action! { action }, + Action::AddTrialFollowShooter(action) => unimplemented_action! { action }, + Action::RemoveTrialFollowShooter(action) => unimplemented_action! { action }, + Action::AddTrialCharacter(action) => unimplemented_action! { action }, + Action::RemoveTrialCharacter(action) => unimplemented_action! { action }, + Action::SetAreaState(action) => unimplemented_action! { action }, + Action::SwitchSubLevels(action) => unimplemented_action! { action }, + Action::ChangeTeamPosition(action) => unimplemented_action! { action }, + Action::GetItem(action) => unimplemented_action! { action }, + Action::CreatePrefab(action) => unimplemented_action! { action }, + Action::DestroyPrefab(action) => unimplemented_action! { action }, + Action::CompleteGuide(action) => unimplemented_action! { action }, + Action::PlayDynamicSettlement(action) => unimplemented_action! { action }, + Action::UsePhantomSkill(action) => unimplemented_action! { action }, + Action::HideTargetRange(action) => unimplemented_action! { action }, + Action::ChangeOtherState(action) => unimplemented_action! { action }, + Action::SetRegionConfig(action) => unimplemented_action! { action }, + Action::SetReviveRegion(action) => unimplemented_action! { action }, + Action::ExecResurrection(action) => unimplemented_action! { action }, + Action::ShowTargetRange(action) => unimplemented_action! { action }, + Action::SetTime(action) => unimplemented_action! { action }, + Action::SetTimeLockState(action) => unimplemented_action! { action }, + Action::EnableSystem(action) => unimplemented_action! { action }, + Action::EnableAoiNotify(action) => unimplemented_action! { action }, + Action::SetForceLock(action) => unimplemented_action! { action }, + Action::PlayRegisteredMontage(action) => unimplemented_action! { action }, + Action::SetAudioState(action) => unimplemented_action! { action }, + Action::HideGroup(action) => unimplemented_action! { action }, + Action::ShowHidedGroup(action) => unimplemented_action! { action }, + Action::HideSpecificEntities(action) => unimplemented_action! { action }, + Action::ShowSpecificEntities(action) => unimplemented_action! { action }, + Action::RemovePreloadResource(action) => unimplemented_action! { action }, + Action::Preload(action) => unimplemented_action! { action }, + Action::EnableAI(action) => unimplemented_action! { action }, + Action::SwitchDataLayers(action) => unimplemented_action! { action }, + Action::DestroyQuest(action) => unimplemented_action! { action }, + Action::DestroyQuestItem(action) => unimplemented_action! { action }, + Action::PromptQuestChapterUI(action) => unimplemented_action! { action }, + Action::TakePlotPhoto(action) => unimplemented_action! { action }, + Action::SetWuYinQuState(action) => unimplemented_action! { action }, + Action::RunActions(action) => unimplemented_action! { action }, + Action::ManualOccupations(action) => unimplemented_action! { action }, + Action::SetWeather(action) => unimplemented_action! { action }, + Action::SendNpcMail(action) => unimplemented_action! { action }, + Action::EnableFunction(action) => unimplemented_action! { action }, + Action::FocusOnMapMark(action) => unimplemented_action! { action }, + Action::CharacterLookAt(action) => unimplemented_action! { action }, + Action::AddGuestCharacter(action) => unimplemented_action! { action }, + Action::RemoveGuestCharacter(action) => unimplemented_action! { action }, + Action::TeleportToAndEnterVehicle(action) => unimplemented_action! { action }, + Action::SetAreaTimeState(action) => unimplemented_action! { action }, + Action::ResetPlayerCameraFocus(action) => unimplemented_action! { action }, + Action::ResetLevelPlay(action) => unimplemented_action! { action }, + Action::VehicleSprint(action) => unimplemented_action! { action }, + Action::VehicleMoveWithPathLine(action) => unimplemented_action! { action }, + } +} + +fn collect_action(player: &mut Player, + level_entity_data: &wicked_waifus_data::LevelEntityConfigData, + template_config: &wicked_waifus_data::TemplateConfigData) { + if let Some(reward_component) = level_entity_data.components_data.reward_component + .as_ref() + .or(template_config.components_data.reward_component.as_ref()) { + if reward_component.disabled.unwrap_or(false) { + return; + } + // TODO: check the use of reward_type and drop_on_event + // Seems type 0 is reward from preview, while 1 and 2 is unknown + if let Some(reward_id) = reward_component.reward_id { + let drop = wicked_waifus_data::drop_package_data::get(&reward_id).unwrap(); + let usages = drop.drop_preview.iter() + .map(|(&id, &quantity)| ItemUsage { id, quantity }) + .collect::>(); + let updated_items = player.inventory.add_items(&usages); + let normal_item_list = player.inventory.to_normal_item_list_filtered( + updated_items.keys().cloned().collect::>() + ); + player.notify(NormalItemUpdateNotify { normal_item_list, no_tips: false }); + // UpdateHandBookActiveStateMapNotify + let mut rewards: HashMap = HashMap::new(); + rewards.insert(0, Ls2 { + item_list: drop.drop_preview.iter() + .map(|(&id, &quantity)| RewardItemInfo { + show_plan_id: 0, // TODO: Check how to get this + item_id: id, + count: quantity, + incr_id: 0, + }) + .collect::>(), + }); + player.notify(ItemRewardNotify { + drop_id: reward_id, + reason: 15000, + magnification: 1, + reward_items: rewards, + }); + } + // TODO: Should we remove entity?? get pcap + } +} + +#[inline(always)] +fn unlock_teleport_trigger(player: &mut Player, action: UnlockTeleportTrigger) { + player.unlock_teleport(action.teleport_id) +} + +fn change_self_entity_state(player: &mut Player, + entity_id: i64, + level_entity_data: &wicked_waifus_data::LevelEntityConfigData, + template_config: &wicked_waifus_data::TemplateConfigData, + action: ChangeSelfEntityState) { + let state = tag_utils::get_tag_id_by_name(action.entity_state.as_str()); + + // TODO: update Tag::CommonEntityTags too?? + let old_state = { + let world_ref = player.world.borrow(); + let world = world_ref.get_world_entity(); + let mut state_tag = query_components!(world, entity_id, StateTag).0.unwrap(); + let old_state = state_tag.state_tag_id; + tracing::debug!("ChangeSelfEntityState: old state {old_state} -> new state: {state}"); + state_tag.state_tag_id = state; + old_state + }; + + if let Some(entity_state_component) = level_entity_data.components_data.entity_state_component.as_ref() + .or(template_config.components_data.entity_state_component.as_ref()).cloned() { + let entity_state_component: EntityStateComponent = entity_state_component; // TODO: Remove this line, used for casting only + + // TODO: implement rest of cases + if let Some(state_change_behaviors) = entity_state_component.state_change_behaviors { + for state_change_behavior in state_change_behaviors { + // TODO: implement rest of cases + let expected = tag_utils::get_tag_id_by_name(state_change_behavior.state.as_str()); + + if expected == state { + if let Some(actions) = state_change_behavior.action { + for sub in actions { + perform_action(player, entity_id, level_entity_data, template_config, sub); + } + } + } + } + } + } + + player.notify(EntityCommonTagNotify { + id: entity_id, + tags: vec![ + CommonTagData { tag_id: old_state, remove_tag_ids: false }, // Remove + CommonTagData { tag_id: state, remove_tag_ids: true }, // Add + ], + }); + + player.notify(EntityStateReadyNotify { + entity_id, + tag_id: state, + ready: true, // TODO: Always true? or shall we compare it to something?? + }); +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/utils/buff_util.rs b/wicked-waifus-game-server/src/logic/utils/buff_util.rs deleted file mode 100644 index a7fb1ef..0000000 --- a/wicked-waifus-game-server/src/logic/utils/buff_util.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::sync::OnceLock; - -use wicked_waifus_protocol::FightBuffInformation; - -static mut BUFF_MANAGER: OnceLock> = OnceLock::new(); - -pub fn add_buff_to_manager(buff: &mut FightBuffInformation) { - let _ = unsafe { BUFF_MANAGER.get_or_init(|| vec![]) }; - let manager = unsafe { BUFF_MANAGER.get_mut() }.unwrap(); - let handle = rand::random::(); // TODO: rework this - buff.handle_id = handle; - buff.server_id = handle; - buff.message_id= handle as i64; - manager.push(buff.clone()); -} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/utils/condition_utils.rs b/wicked-waifus-game-server/src/logic/utils/condition_utils.rs new file mode 100644 index 0000000..ea9fa50 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/utils/condition_utils.rs @@ -0,0 +1,147 @@ +use wicked_waifus_data::pb_components::condition::{CheckConditionGroup, CompareEntityState, Condition}; + +use crate::logic::ecs::component::ComponentContainer; +use crate::logic::player::Player; +use crate::logic::utils::tag_utils; +use crate::query_components; + +macro_rules! unimplemented_condition { + ($condition:ident) => { + { + tracing::warn!("Condition check not implemented for: {:?}", $condition); + true + } + } +} + +pub fn check_condition(player: &Player, + entity_id: i64, + level_entity_data: &wicked_waifus_data::LevelEntityConfigData, + template_config: &wicked_waifus_data::TemplateConfigData, + element: Condition) -> bool { + match element { + Condition::CompareTimePeriod(condition) => unimplemented_condition! { condition }, + Condition::CheckChildQuestFinished(condition) => unimplemented_condition! { condition }, + Condition::CompareEntityState(condition) => compare_entity_state(player, entity_id, condition), + Condition::CheckEntityState(condition) => unimplemented_condition! { condition }, + Condition::CompareVar(condition) => unimplemented_condition! { condition }, + Condition::CompareWeather(condition) => unimplemented_condition! { condition }, + Condition::CompareQuestState(condition) => unimplemented_condition! { condition }, + Condition::CompareEntitySelfState(condition) => unimplemented_condition! { condition }, + Condition::CheckPlayerStateRestriction(condition) => unimplemented_condition! { condition }, + Condition::HourToHour(condition) => unimplemented_condition! { condition }, + Condition::ComparePlayerMotionState(condition) => unimplemented_condition! { condition }, + Condition::ComparePlayerMotionState2(condition) => unimplemented_condition! { condition }, + Condition::CheckAiState(condition) => unimplemented_condition! { condition }, + Condition::PreLevelPlay(condition) => unimplemented_condition! { condition }, + Condition::CheckLevelPlay(condition) => unimplemented_condition! { condition }, + Condition::CheckLevelPlayState(condition) => unimplemented_condition! { condition }, + Condition::CheckLevelPlayCompleteNumber(condition) => unimplemented_condition! { condition }, + Condition::CompareLevelPlayRewardState(condition) => unimplemented_condition! { condition }, + Condition::CheckItems(condition) => unimplemented_condition! { condition }, + Condition::HandInItems(condition) => unimplemented_condition! { condition }, + Condition::GetItem(condition) => unimplemented_condition! { condition }, + Condition::UseItem(condition) => unimplemented_condition! { condition }, + Condition::HasBuff(condition) => unimplemented_condition! { condition }, + Condition::CompareLift(condition) => unimplemented_condition! { condition }, + Condition::CheckJigsawInfo(condition) => unimplemented_condition! { condition }, + Condition::CheckInCombat(condition) => unimplemented_condition! { condition }, + Condition::DetectCombatState(condition) => unimplemented_condition! { condition }, + Condition::DetectCombatState2(condition) => unimplemented_condition! { condition }, + Condition::CheckVehicleCondition(condition) => unimplemented_condition! { condition }, + Condition::CheckSystemFunction(condition) => unimplemented_condition! { condition }, + Condition::CheckSystemState(condition) => unimplemented_condition! { condition }, + Condition::CheckCollectAnimalParts(condition) => unimplemented_condition! { condition }, + Condition::CheckCurrentRole(condition) => unimplemented_condition! { condition }, + Condition::CompareExploreLevel(condition) => unimplemented_condition! { condition }, + Condition::ExploreLevel(condition) => unimplemented_condition! { condition }, + Condition::CompareDungeonId(condition) => unimplemented_condition! { condition }, + Condition::EnterDungeon(condition) => unimplemented_condition! { condition }, + Condition::LeaveDungeon(condition) => unimplemented_condition! { condition }, + Condition::FinishDungeon(condition) => unimplemented_condition! { condition }, + Condition::CompareCalabashLevel(condition) => unimplemented_condition! { condition }, + Condition::CheckCalabashDevelopReward(condition) => unimplemented_condition! { condition }, + Condition::CheckLordGymFinish(condition) => unimplemented_condition! { condition }, + Condition::CompareEntityGroupState(condition) => unimplemented_condition! { condition }, + Condition::CheckEntityLocked(condition) => unimplemented_condition! { condition }, + Condition::CheckRogueAbilitySelect(condition) => unimplemented_condition! { condition }, + Condition::CompareFishingBoatState(condition) => unimplemented_condition! { condition }, + Condition::CompleteCertainFishingEntrust(condition) => unimplemented_condition! { condition }, + Condition::CompareFishingPrestigeLevel(condition) => unimplemented_condition! { condition }, + Condition::CheckCertainFishingItemCount(condition) => unimplemented_condition! { condition }, + Condition::CompareFishingTechLevel(condition) => unimplemented_condition! { condition }, + Condition::ListenEntitySelfEvent(condition) => unimplemented_condition! { condition }, + Condition::CheckHookLockPoint(condition) => unimplemented_condition! { condition }, + Condition::CheckEntitesExist(condition) => unimplemented_condition! { condition }, + Condition::CheckEntityHasSceneItemAttributeTag(condition) => unimplemented_condition! { condition }, + Condition::CheckTargetBattleAttribute(condition) => unimplemented_condition! { condition }, + Condition::CheckAlertAreaEnabled(condition) => unimplemented_condition! { condition }, + Condition::CompareAlertValue(condition) => unimplemented_condition! { condition }, + Condition::ReachArea(condition) => unimplemented_condition! { condition }, + Condition::Kill(condition) => unimplemented_condition! { condition }, + Condition::DoInteract(condition) => unimplemented_condition! { condition }, + Condition::MonsterCreator(condition) => unimplemented_condition! { condition }, + Condition::UseSkill(condition) => unimplemented_condition! { condition }, + Condition::GetSkill(condition) => unimplemented_condition! { condition }, + Condition::Parkour(condition) => unimplemented_condition! { condition }, + Condition::Timer(condition) => unimplemented_condition! { condition }, + Condition::Guide(condition) => unimplemented_condition! { condition }, + Condition::PlayFlow(condition) => unimplemented_condition! { condition }, + Condition::InformationViewCheck(condition) => unimplemented_condition! { condition }, + Condition::ShowUi(condition) => unimplemented_condition! { condition }, + Condition::CheckUiGame(condition) => unimplemented_condition! { condition }, + Condition::ScheduleTime(condition) => unimplemented_condition! { condition }, + Condition::CheckPlayerSkillReady(condition) => unimplemented_condition! { condition }, + Condition::WaitTime(condition) => unimplemented_condition! { condition }, + Condition::TakePhoto(condition) => unimplemented_condition! { condition }, + Condition::ParallaxAlign(condition) => unimplemented_condition! { condition }, + Condition::WaitBattleCondition(condition) => unimplemented_condition! { condition }, + Condition::CheckDirection(condition) => unimplemented_condition! { condition }, + Condition::CheckConditionGroup(condition) => check_condition_group(player, entity_id, level_entity_data, template_config, condition), + Condition::CheckTreasureBeenClaimed(condition) => unimplemented_condition! { condition }, + Condition::RangeSphere(condition) => unimplemented_condition! { condition }, + Condition::CheckInRange(condition) => unimplemented_condition! { condition }, + Condition::CheckPlayerGender(condition) => unimplemented_condition! { condition }, + Condition::CheckPlayerInput(condition) => unimplemented_condition! { condition }, + Condition::CheckFormationRoleInfo(condition) => unimplemented_condition! { condition }, + Condition::AwakeAndLoadEntity(condition) => unimplemented_condition! { condition }, + Condition::CheckChessWinner(condition) => unimplemented_condition! { condition }, + Condition::WalkingPattern(condition) => unimplemented_condition! { condition }, + Condition::CheckDataLayer(condition) => unimplemented_condition! { condition }, + Condition::CheckFinishLoading(condition) => unimplemented_condition! { condition }, + Condition::VisionSystem(condition) => unimplemented_condition! { condition }, + Condition::ReadMail(condition) => unimplemented_condition! { condition }, + Condition::ReceiveTelecom(condition) => unimplemented_condition! { condition }, + Condition::CheckActivityState(condition) => unimplemented_condition! { condition }, + } +} + +fn compare_entity_state(player: &Player, entity_id: i64, condition: CompareEntityState) -> bool { + let actual = { + let world_ref = player.world.borrow(); + let world = world_ref.get_world_entity(); + let state_tag = query_components!(world, entity_id, StateTag).0.unwrap(); + state_tag.state_tag_id + }; + let expected = tag_utils::get_tag_id_by_name(condition.state.as_str()); + // In theory, we can only check for equal or not equal + tracing::debug!("CompareEntityState: type {:?}, actual: {actual}, expected: {expected}", condition.compare); + condition.compare.cmp(&expected, &actual) +} + +fn check_condition_group(player: &Player, + entity_id: i64, + level_entity_data: &wicked_waifus_data::LevelEntityConfigData, + template_config: &wicked_waifus_data::TemplateConfigData, + condition: CheckConditionGroup) -> bool { + + let mut check = true; + // TODO: Investigate if type has a meaning + for element in condition.condition.conditions { + check = check_condition(player, entity_id, level_entity_data, template_config, element); + if !check { + break; + } + } + check +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/utils/entity_serializer.rs b/wicked-waifus-game-server/src/logic/utils/entity_serializer.rs index 88c83d4..04dfa92 100644 --- a/wicked-waifus-game-server/src/logic/utils/entity_serializer.rs +++ b/wicked-waifus-game-server/src/logic/utils/entity_serializer.rs @@ -10,7 +10,7 @@ pub fn build_scene_add_on_init_data(player: &Player) -> PlayerSceneAoiData { let mut world_ref = player.world.borrow_mut(); let world = world_ref.get_mut_world_entity(); - let entities = query_hn_with!(world, PlayerEntityMarker) + let entities = query_hn_with!(world, PlayerOwnedEntityMarker) .into_iter() .map(|(entity_id, _)| { let res_map: (EEntityType, i32); @@ -20,6 +20,9 @@ pub fn build_scene_add_on_init_data(player: &Player) -> PlayerSceneAoiData { Ok(EEntityType::Player) => { res_map = (EEntityType::Player, entity_id); } + Ok(EEntityType::Monster) => { + res_map = (EEntityType::Monster, entity_id); + } _ => { res_map = (EEntityType::default(), -1); } @@ -46,10 +49,10 @@ pub fn build_scene_add_on_init_data(player: &Player) -> PlayerSceneAoiData { .get(&player.cur_formation_id) .unwrap() .cur_role; - vis.0 = if config_id == cur_role_id { - true + (vis.is_visible, vis.is_actor_visible) = if config_id == cur_role_id { + (true, true) } else { - false + (false, true) }; } ); @@ -67,6 +70,28 @@ pub fn build_scene_add_on_init_data(player: &Player) -> PlayerSceneAoiData { aoi_data.entities.push(pb); } } + EEntityType::Monster => { + let config_id = world.get_config_id(entity_id); + modify_component!( + world.get_entity_components(entity_id), + Visibility, + |vis: &mut Visibility| { + vis.is_visible = false; + vis.is_actor_visible = true; + } + ); + if world.get_entity(config_id).entity_type == EEntityType::Monster as i32 { + let mut pb = EntityPb { + id: entity_id as i64, + ..Default::default() + }; + world + .get_entity_components(entity_id) + .into_iter() + .for_each(|comp| comp.set_pb_data(&mut pb)); + aoi_data.entities.push(pb); + } + } _ => {} }; }); diff --git a/wicked-waifus-game-server/src/logic/utils/growth_utils.rs b/wicked-waifus-game-server/src/logic/utils/growth_utils.rs new file mode 100644 index 0000000..ccb2edc --- /dev/null +++ b/wicked-waifus-game-server/src/logic/utils/growth_utils.rs @@ -0,0 +1,54 @@ +use wicked_waifus_data::{BasePropertyData, base_property_data, monster_property_growth_data, role_property_growth_data}; + +pub fn get_role_props_by_level(id: i32, level: i32, breach: i32) -> BasePropertyData { + let mut base_props = get_role_props_or_default(id).clone(); + let role_props_growth = role_property_growth_data::iter() + .find(|d| d.level == level && d.breach_level == breach) + .unwrap_or_else(|| { + role_property_growth_data::iter().find(|d| d.level == 1 && d.breach_level == 0).unwrap() + }); + base_props.lv = level; + compute_scaled_stat(&mut base_props.life_max, role_props_growth.life_max_ratio); + compute_scaled_stat(&mut base_props.life, role_props_growth.life_max_ratio); + compute_scaled_stat(&mut base_props.atk, role_props_growth.atk_ratio); + compute_scaled_stat(&mut base_props.def, role_props_growth.def_ratio); + base_props +} + +pub fn get_monster_props_by_level(id: i32, level: i32) -> BasePropertyData { + let mut base_props = base_property_data::iter() + .find(|d| d.id == id) + .unwrap() // TODO: Default?? + .clone(); + // TODO: Check if curve_id matters + let monster_props_growth = monster_property_growth_data::iter() + .find(|d| d.level == level) + .unwrap(); // TODO: Default?? + // Compute scaled properties + base_props.lv = level; + compute_scaled_stat(&mut base_props.life_max, monster_props_growth.life_max_ratio); + compute_scaled_stat(&mut base_props.life, monster_props_growth.life_max_ratio); + compute_scaled_stat(&mut base_props.atk, monster_props_growth.atk_ratio); + compute_scaled_stat(&mut base_props.def, monster_props_growth.def_ratio); + compute_scaled_stat(&mut base_props.hardness_max, monster_props_growth.hardness_max_ratio); + compute_scaled_stat(&mut base_props.hardness, monster_props_growth.hardness_ratio); + compute_scaled_stat(&mut base_props.hardness_recover, monster_props_growth.hardness_recover_ratio); + compute_scaled_stat(&mut base_props.rage_max, monster_props_growth.rage_max_ratio); + compute_scaled_stat(&mut base_props.rage, monster_props_growth.rage_ratio); + compute_scaled_stat(&mut base_props.rage_recover, monster_props_growth.rage_recover_ratio); + base_props +} + +#[inline(always)] +fn get_role_props_or_default(id: i32) -> &'static BasePropertyData { + base_property_data::iter() + .find(|d| d.id == id) + .unwrap_or_else(|| { + base_property_data::iter().find(|d| d.id == 1102).unwrap() + }) +} + +#[inline(always)] +fn compute_scaled_stat(stat: &mut i32, ratio: i32) { + *stat = (*stat as f32 * (ratio as f32 / 10000f32)).trunc() as i32; +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/utils/mod.rs b/wicked-waifus-game-server/src/logic/utils/mod.rs index bb79bbb..c7eec47 100644 --- a/wicked-waifus-game-server/src/logic/utils/mod.rs +++ b/wicked-waifus-game-server/src/logic/utils/mod.rs @@ -1,5 +1,8 @@ +pub mod action_utils; +pub mod condition_utils; pub mod entity_serializer; pub mod load_role_info; pub mod world_util; pub mod quadrant_util; -pub mod buff_util; +pub mod growth_utils; +pub mod tag_utils; diff --git a/wicked-waifus-game-server/src/logic/utils/tag_utils.rs b/wicked-waifus-game-server/src/logic/utils/tag_utils.rs new file mode 100644 index 0000000..f0a9ef8 --- /dev/null +++ b/wicked-waifus-game-server/src/logic/utils/tag_utils.rs @@ -0,0 +1,463 @@ +use std::collections::HashMap; +use std::sync::OnceLock; +use unreal_niggery_rs::fnv::ue_gas_fnv_hash; +use widestring::U16CString; + +// TODO: Make it nicer +static TAG_ID_2_UGLY_TAG_ID_MAP: OnceLock> = OnceLock::new(); + +fn get_tag_ugly_map() -> &'static HashMap { + TAG_ID_2_UGLY_TAG_ID_MAP.get_or_init(|| { + let mut map = HashMap::new(); + map.insert(665060676, -689911122); + map.insert(13355129, -69562997); + map.insert(49156645, 1840856189); + map.insert(370674185, -1276475545); + map.insert(-525201732, -1152048753); + map.insert(2027348094, 1790413286); + map.insert(961074105, 1260157389); + map.insert(-2099843012, -1826297010); + map.insert(1397292199, -1568691815); + map.insert(774686413, -113743209); + map.insert(1734115005, -271538568); + map.insert(-1288554675, 2130437044); + map.insert(470725697, -486371353); + map.insert(1135424583, -1613060918); + map.insert(-1756432600, -1010422269); + map.insert(424820279, -775801180); + map.insert(393181306, 1405023713); + map.insert(425393345, 1374049690); + map.insert(392103684, 1407752023); + map.insert(-580925275, 194372208); + map.insert(-630985694, 1927555813); + map.insert(-1302760285, -156068301); + map.insert(1819813309, 14053290); + map.insert(-629833554, -406038058); + map.insert(1518081744, 47342951); + map.insert(1217118505, -622084499); + map.insert(1819282155, 14626356); + map.insert(-474393396, -1675110648); + map.insert(1785992494, 52868081); + map.insert(-249709009, -645909457); + map.insert(-2037408248, 656763530); + map.insert(-611701538, 2022139738); + map.insert(1576773129, 137146547); + map.insert(-1965290406, 733548879); + map.insert(-587210031, -2104162139); + map.insert(1481766230, 1351981059); + map.insert(-1154652795, 805813271); + map.insert(-453678106, 1796827379); + map.insert(1224208285, -1244697559); + map.insert(-2003576838, 2021823143); + map.insert(-529913911, -438164993); + map.insert(-832937275, 76208893); + map.insert(-126845436, -866909296); + map.insert(862334797, 872289374); + map.insert(1157582676, 913890514); + map.insert(-1317968655, -230099629); + map.insert(2143157660, -1003002967); + map.insert(1174008769, -45472554); + map.insert(-204403872, -1990127501); + map.insert(-86960539, -435160877); + map.insert(-187626253, 320752608); + map.insert(1281565910, -1442625623); + map.insert(-103738158, -494082337); + map.insert(-137293396, 1823399296); + map.insert(-1918592765, 390382345); + map.insert(173718599, -302052991); + map.insert(-1956728175, -1418998110); + map.insert(-1154042118, -1990424178); + map.insert(70208229, 1973732993); + map.insert(-1471372527, -415940818); + map.insert(53430610, 651875007); + map.insert(981361735, -2043059048); + map.insert(-267978591, 1566090491); + map.insert(-1201496076, 1341891966); + map.insert(-848554606, -396007441); + map.insert(-531577394, -1400032326); + map.insert(577598557, 1267859545); + map.insert(486113160, 352800915); + map.insert(-1166942422, -674731505); + map.insert(-2041844563, -2085310779); + map.insert(226022706, 414541970); + map.insert(1902237086, 539102901); + map.insert(242800325, -1112012100); + map.insert(-386011928, 589539912); + map.insert(1607376467, -1597014724); + map.insert(-689712984, -1277883221); + map.insert(1925944892, 1745511332); + map.insert(-672935365, 122403501); + map.insert(-1451562381, 1542622464); + map.insert(-430210564, -430713724); + map.insert(-1081752169, -1270649661); + map.insert(-747953645, 171980748); + map.insert(-1098529788, 1358408597); + map.insert(-112258427, 1272257853); + map.insert(140165478, 504823315); + map.insert(-2125122591, -1745523076); + map.insert(493939829, -355027021); + map.insert(-2141900210, -1768442878); + map.insert(-1033385202, 1349398014); + map.insert(1401336715, -304522885); + map.insert(157391473, -1482919292); + map.insert(-1853456626, -994528279); + map.insert(1892376481, 889011356); + map.insert(-1174644857, 1816828193); + map.insert(1899754925, 2109620403); + map.insert(-790187737, 1586950367); + map.insert(-55364334, -2081380125); + map.insert(-800509757, -1185700782); + map.insert(-1401283028, -1188774954); + map.insert(-218066089, -2100275822); + map.insert(-817028279, -1844487312); + map.insert(1060091695, 2072133518); + map.insert(-485434250, 789375747); + map.insert(368412207, 58038063); + map.insert(701760940, -904268886); + map.insert(307256062, -1478017893); + map.insert(-2075859399, 1216434886); + map.insert(-1806886341, -357398774); + map.insert(1172946339, -2102223839); + map.insert(-1952820222, 1978188771); + map.insert(-852521511, -1526644763); + map.insert(1358521800, 1427834034); + map.insert(158588675, 763761550); + map.insert(-2074599444, -1198670133); + map.insert(-209014483, 368968432); + map.insert(-259347340, -1062644945); + map.insert(-2037857146, -1466695739); + map.insert(-435027775, -1863796018); + map.insert(-280405967, 1589347351); + map.insert(1565413014, 560811306); + map.insert(-1805699460, -1705137615); + map.insert(-281391705, -1344102960); + map.insert(-314108300, 1258759358); + map.insert(-1990301155, -62383492); + map.insert(-1639773015, 1844046195); + map.insert(-1400491751, 333293220); + map.insert(980973022, 1797522437); + map.insert(-1435432100, -1136810679); + map.insert(278949826, -1036428494); + map.insert(-1280481268, -606847648); + map.insert(-271903711, -1853949812); + map.insert(791481790, -222989044); + map.insert(546903702, 192904472); + map.insert(-709669824, -1877342310); + map.insert(-2058324884, 1955625746); + map.insert(563411175, 101389469); + map.insert(-1913681574, -2131576173); + map.insert(2110864211, 1094674564); + map.insert(1080142473, -1277799466); + map.insert(-211693756, 15540193); + map.insert(694342234, 1588099942); + map.insert(-1887823866, 812611386); + map.insert(1070176822, 408374927); + map.insert(-304319129, 1681750315); + map.insert(-1683838781, 1026540573); + map.insert(-2093382636, 1140061280); + map.insert(-969094738, -578729732); + map.insert(841807591, -1607079827); + map.insert(-1486655338, 2120377741); + map.insert(1759370121, 333807435); + map.insert(497266872, 1344563570); + map.insert(-318838109, 1582048197); + map.insert(1114577074, -282170304); + map.insert(1097799455, -231837447); + map.insert(-2064582042, -2109601336); + map.insert(959059560, 24538217); + map.insert(1107890930, 603906963); + map.insert(848802264, 418437304); + map.insert(-2053453370, 875530122); + map.insert(-1699694465, -1823492319); + map.insert(183092517, -1350837709); + map.insert(1326224593, 1472055437); + map.insert(40689781, 226094310); + map.insert(705402042, 472143335); + map.insert(-932127130, -1305855555); + map.insert(-1334012412, -2126344565); + map.insert(905517881, -867166067); + map.insert(1331241167, -222336037); + map.insert(602417116, -514118785); + map.insert(-759765322, -534507561); + map.insert(-287966531, 51874908); + map.insert(751278535, -1266787716); + map.insert(-139502861, -1634233604); + map.insert(-122725242, -1583900747); + map.insert(-1343050340, 1825811806); + map.insert(-1690783492, -1477854423); + map.insert(185517816, -260864652); + map.insert(400181908, 1241254763); + map.insert(-130517364, -1310523673); + map.insert(-80184507, 2143452515); + map.insert(863897449, -1892522443); + map.insert(-375948769, 658901258); + map.insert(-614170189, 1806698795); + map.insert(1057026748, 676806477); + map.insert(1073804367, -667588790); + map.insert(1023471510, -1488507281); + map.insert(1107359605, 1411524773); + map.insert(87371004, -1053542412); + map.insert(583447238, 1592665882); + map.insert(-456332999, -287939229); + map.insert(-553311636, -398516443); + map.insert(-243523922, 548707911); + map.insert(330268744, 241673361); + map.insert(1516643825, -620837896); + map.insert(1146272460, -1628716537); + map.insert(-2066747393, 2099589164); + map.insert(1993130336, 1796295089); + map.insert(883607282, 1959811945); + map.insert(-994689315, -456549250); + map.insert(-458174252, 80703303); + map.insert(642608494, -716495061); + map.insert(1745178531, 24811116); + map.insert(-681618322, -1512559524); + map.insert(52615856, 1856783591); + map.insert(1303861755, -504693325); + map.insert(1287084136, -248076681); + map.insert(1337416993, 1622182973); + map.insert(153281570, -592321149); + map.insert(-1290477339, -423142073); + map.insert(-1307254958, 14093179); + map.insert(-1324032577, 233789033); + map.insert(102948713, 2058689260); + map.insert(742590194, 1268730766); + map.insert(759367813, 593157434); + map.insert(709034956, -1919206536); + map.insert(170059189, 1501349413); + map.insert(-671977242, -1869056139); + map.insert(-655199623, 1723498109); + map.insert(-705532480, -2086101569); + map.insert(69393475, 2117271668); + map.insert(1932704444, -1888005530); + map.insert(1949482063, 1608785026); + map.insert(1966259682, -979436480); + map.insert(1991286752, -1939887438); + map.insert(2021363266, -1649229993); + map.insert(-682095170, -1988260054); + map.insert(-2137487096, 286654908); + map.insert(18812195, 782154013); + map.insert(878256835, 1393738129); + map.insert(895034454, 1343405272); + map.insert(911812073, 1360182891); + map.insert(-688826522, 1811251412); + map.insert(216452587, 2105079841); + map.insert(233230206, 2054746984); + map.insert(250007825, 2071524603); + map.insert(266785444, -2139554598); + map.insert(283563063, -2122776979); + map.insert(300340682, 2121857460); + map.insert(-1260505415, 6680851); + map.insert(850300913, 623494092); + map.insert(833523294, 1244301689); + map.insert(799968056, 2004956933); + map.insert(1560232727, -916209979); + map.insert(-413558331, 1188929311); + map.insert(1908142967, -1808626591); + map.insert(715121622, -1994522136); + map.insert(1272425901, 1223823795); + map.insert(1222093044, 1240601414); + map.insert(1238870663, 1257379033); + map.insert(1520385604, -884634490); + map.insert(1794851262, 760097100); + map.insert(-489843050, -1088900628); + map.insert(134620654, 914695612); + map.insert(1727279361, -1543613601); + map.insert(-1531062819, -1812350413); + map.insert(-1581395676, -1795572794); + map.insert(-1310112650, 537586820); + map.insert(-63549978, 1940616802); + map.insert(637239835, 1950919896); + map.insert(1270941912, -1593146607); + map.insert(-1476669278, -104846425); + map.insert(1296660531, 37344055); + map.insert(1321274769, -1970535311); + map.insert(1674374796, -1910862068); + map.insert(1044369715, 51802137); + map.insert(1148667748, -1876550146); + map.insert(-1123556075, -875897953); + map.insert(-1173888932, -116700523); + map.insert(1061147334, 1157945219); + map.insert(1057978788, -248004880); + map.insert(538304911, 1437940812); + map.insert(-155211019, 1615892223); + map.insert(-1204172777, 662082465); + map.insert(-1415059053, 672724995); + map.insert(1727061684, 691571478); + map.insert(2077964311, -2115127911); + map.insert(-1599526777, 1757161528); + map.insert(1569718189, -581782413); + map.insert(-769708850, -1069212639); + map.insert(1012914743, -1801562034); + map.insert(-1630754290, -1506294940); + map.insert(-798482481, -210971633); + map.insert(1776884912, 1187537462); + map.insert(1913726824, 470138850); + map.insert(1378769140, 1638751609); + map.insert(-554277026, 385901056); + map.insert(-792547263, 912247923); + map.insert(47275219, 515642340); + map.insert(625794314, 845717332); + map.insert(932164427, 1250450319); + map.insert(948942046, -564513464); + map.insert(-148163169, -408513885); + map.insert(-164940788, 2059137836); + map.insert(156880079, 220871484); + map.insert(140102460, -295661983); + map.insert(2082244918, 1398601871); + map.insert(173657698, -1800007622); + map.insert(-131385550, 2053189737); + map.insert(-1393657855, 170888934); + map.insert(-286337438, -289031989); + map.insert(-370225533, 1344285533); + map.insert(-387003152, 86808445); + map.insert(-353447914, 269494260); + map.insert(-269559819, -898870119); + map.insert(1869993547, 2086817125); + map.insert(-1059857426, 1575281566); + map.insert(1043457811, 1919693123); + map.insert(793258837, -1939164602); + map.insert(726393310, -1237842925); + map.insert(-939952324, 926505363); + map.insert(39083218, -1737183401); + map.insert(1605747123, -978171135); + map.insert(999934475, -1605124253); + map.insert(1692725416, -99843703); + map.insert(40078001, 1075562113); + map.insert(165178998, -638714302); + map.insert(1316954978, -8248787); + map.insert(2135569592, -197924652); + map.insert(427562107, -773064923); + map.insert(-863415037, -435850030); + map.insert(-444185186, -1277484559); + map.insert(1467965949, -2115411093); + map.insert(754552538, 936452968); + map.insert(-513366507, -1178895547); + map.insert(847322071, -905892488); + map.insert(-1479002813, 2096962869); + map.insert(-1445447575, -659329626); + map.insert(-1395114718, -1828437537); + map.insert(-1428669956, -1824897694); + map.insert(-1411892337, 1370620670); + map.insert(-1462225194, -2064934662); + map.insert(419451940, 649758639); + map.insert(96086978, 1826479905); + map.insert(474921613, 1094959825); + map.insert(1457226786, 1516798828); + map.insert(1571053395, 1496854684); + map.insert(550273598, 1269791961); + map.insert(981853136, -38704817); + map.insert(2056325840, 617028448); + map.insert(1236918575, -1534873118); + map.insert(535849816, -480111181); + map.insert(1093841990, -10792498); + map.insert(783660389, -947719149); + map.insert(942378620, 1304511750); + map.insert(-1379062523, 1478195406); + map.insert(1077064371, -162769713); + map.insert(-1496505856, 1935354277); + map.insert(917879443, -1275642174); + map.insert(-28810868, 1238768572); + map.insert(276942069, -1847423486); + map.insert(1049579377, -1018476507); + map.insert(62110480, -1751674977); + map.insert(-1015096185, -759322097); + map.insert(-42215247, -304344646); + map.insert(1815475006, 433136267); + map.insert(-503435967, -1674197999); + map.insert(228543096, 1616170558); + map.insert(1984322081, -1406016738); + map.insert(-104228676, -328987441); + map.insert(-171339152, -1061662636); + map.insert(-53895819, -205129248); + map.insert(-154561533, -1370787542); + map.insert(-1335725443, 1816368607); + map.insert(-1386058300, -1595897508); + map.insert(-70673438, -1867755128); + map.insert(-121006295, 933428714); + map.insert(-1544115670, -1557227429); + map.insert(13510587, 419544133); + map.insert(97398682, 1675052919); + map.insert(-534949843, -234170969); + map.insert(-2078991444, 1150784263); + map.insert(1501593646, 484704172); + map.insert(-2028658587, -185351871); + map.insert(63843444, -1064586185); + map.insert(-527160284, 1981896529); + map.insert(-1988320981, -975766218); + map.insert(-323411402, -547717357); + map.insert(114176301, -1731459239); + map.insert(1348903202, -991785632); + map.insert(-633530960, -1226039221); + map.insert(-586728430, 1245658364); + map.insert(-767279638, -1835901954); + map.insert(-88850592, 872670820); + map.insert(1120232956, 698571423); + map.insert(-1528822541, 1356344465); + map.insert(1515476160, -850074650); + map.insert(996196254, 610482952); + map.insert(-1218449454, -1604162756); + map.insert(-622613463, -1022276760); + map.insert(-1408881309, -1216364815); + map.insert(368415360, -1956312930); + map.insert(-618411782, -693075425); + map.insert(-168121422, 1023463766); + map.insert(1545497909, -1174169377); + map.insert(548653731, -2078371787); + map.insert(-103878248, 703199986); + map.insert(1164783037, 482780573); + map.insert(-965441646, -123075667); + map.insert(1349922056, -579527112); + map.insert(-467385684, 840402477); + map.insert(-2084709799, 1903829007); + map.insert(1769557047, 1018916367); + map.insert(1390411059, 651470142); + map.insert(1627547621, -1628751678); + map.insert(-1799490276, -1515031434); + map.insert(-285638864, 1109228954); + map.insert(396292942, 430401293); + map.insert(-607005246, -1450058230); + map.insert(1819593638, -723474560); + map.insert(1516131873, -2036325523); + map.insert(656825598, -1984484433); + map.insert(480843337, 533293606); + map.insert(317322897, 1371001947); + map.insert(-327878852, 46996718); + map.insert(-308948240, 1474397698); + map.insert(-1584263064, -55786330); + map.insert(-1525811188, 421520484); + map.insert(1627288199, -312328034); + map.insert(-458054562, 1912978374); + map.insert(1516745668, -1230287719); + map.insert(1877375771, -1602374225); + map.insert(-2103877240, 2059266845); + map.insert(-2036766764, 521911872); + map.insert(-2070322002, 343042661); + map.insert(-2019989145, -1368719946); + map.insert(-2053544383, 767108599); + map.insert(-1705702885, 2090694567); + map.insert(906493988, -526145235); + map.insert(-833117452, 1365733797); + map.insert(-2110480457, 1074862246); + map.insert(1916975462, 1187374991); + map.insert(-224125069, 1826107924); + map.insert(-520048118, -777864242); + map.insert(1214737838, 539975485); + map.insert(914491752, 591149617); + map.insert(-1035051305, -1295373411); + map.insert(-309146858, -1989021920); + map.insert(536145838, -1377409745); + map.insert(-1090440898, 1937741205); + map.insert(-1073663279, 590629922); + map.insert(-1474984951, -584695776); + map.insert(-1692474990, -231334097); + map + }) +} + +pub fn get_tag_id_by_name(value: &str) -> i32 { + // This should not fail since it's applied to bindata contents + let utf16 = U16CString::from_str(value).unwrap(); + let tag = ue_gas_fnv_hash(utf16.as_slice()) as i32; + get_tag_ugly_map().get(&tag).copied().unwrap_or(tag) +} \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/utils/world_util.rs b/wicked-waifus-game-server/src/logic/utils/world_util.rs index c634f2f..f92d135 100644 --- a/wicked-waifus-game-server/src/logic/utils/world_util.rs +++ b/wicked-waifus-game-server/src/logic/utils/world_util.rs @@ -1,58 +1,80 @@ -use wicked_waifus_protocol::{DFsm, EEntityType, EntityAddNotify, EntityConfigType, EntityPb, - EntityRemoveInfo, EntityRemoveNotify, EntityState, FightRoleInfo, - FightRoleInfos, LivingStatus, SceneInformation, SceneMode, - ScenePlayerInformation, SceneTimeInfo}; -use wicked_waifus_data::{base_property_data, LevelEntityConfigData}; +use wicked_waifus_protocol::{ + EEntityType, ERemoveEntityType, EntityAddNotify, EntityConfigType, EntityPb, EntityRemoveInfo, + EntityRemoveNotify, EntityState, FightRoleInfo, FightRoleInfos, LivingStatus, SceneInformation, + SceneMode, ScenePlayerInformation, SceneTimeInfo, +}; +use wicked_waifus_data::pb_components::ComponentsData; +use wicked_waifus_data::{ + blueprint_config_data, template_config_data, EntityLogic, EntityType, LevelEntityConfigData, +}; + +use crate::logic::components::{Autonomous, Fsm, Interact, MonsterAi, StateTag, Tag}; +use crate::logic::ecs::entity::EntityBuilder; +use crate::logic::ecs::world::World; +use crate::logic::math::Transform; +use crate::logic::player::Player; +use crate::logic::utils::{entity_serializer, tag_utils}; +use crate::logic::utils::growth_utils::get_monster_props_by_level; use crate::logic::{ components::{ - Attribute, EntityConfig, Equip, FightBuff, Movement, OwnerPlayer, PlayerEntityMarker, + Attribute, EntityConfig, Equip, FightBuff, Movement, OwnerPlayer, PlayerOwnedEntityMarker, Position, RoleSkin, Visibility, VisionSkill, }, ecs::component::ComponentContainer, }; -use crate::logic::components::{Autonomous, Fsm, MonsterAi, StateTag, Tag}; -use crate::logic::ecs::entity::Entity; -use crate::logic::ecs::world::{World, WorldEntity}; -use crate::logic::math::Transform; -use crate::logic::player::Player; -use crate::logic::utils::entity_serializer; use crate::query_with; #[macro_export] macro_rules! create_player_entity_pb { - ($role_list:expr, $cur_map_id:expr, $world:expr, $player_id:expr, $position:expr, $explore_tools:expr) => {{ + ($role_list:expr, $cur_map_id:expr, $player:expr, $player_id:expr, $position:expr, $explore_tools:expr) => {{ + let mut world_ref = $player.world.borrow_mut(); + let world = world_ref.get_mut_world_entity(); + + let current_formation = $player.formation_list.get(&$player.cur_formation_id).unwrap(); + let cur_role_id = current_formation.cur_role; + let mut pbs = Vec::new(); - let mut general_buffs = FightBuff::default(); - general_buffs.add_generic_permanent_buffs(); - for role in $role_list { - // Once per character buffs are implemented, add a mut on role_buffs - let role_buffs = general_buffs.clone(); + let entity = world.create_entity( + role.role_id, + EEntityType::Player.into(), + $cur_map_id, + ); + // Once per character buffs are implemented, add a mut on role_buffs + let fight_buff_infos = world.generate_role_permanent_buffs(entity.entity_id as i64); + let buf_manager = FightBuff { + fight_buff_infos, + list_buff_effect_cd: vec![], + }; - let role_id: i32 = role.role_id; - let base_property = base_property_data::iter() - .find(|d| d.id == role_id) - .expect("macro create_role_entity_pb: Base property data not found"); - - let entity = $world - .create_entity(role_id, EEntityType::Player.into(), $cur_map_id) - .with(ComponentContainer::PlayerEntityMarker(PlayerEntityMarker)) + let entity = world.create_builder(entity) + .with(ComponentContainer::PlayerOwnedEntityMarker(PlayerOwnedEntityMarker { + entity_type: EEntityType::Player, + })) .with(ComponentContainer::EntityConfig(EntityConfig { - config_id: role_id, + camp: 0, + config_id: role.role_id, config_type: EntityConfigType::Character, entity_type: EEntityType::Player.into(), - entity_state: EntityState::Default + entity_state: EntityState::Default, })) .with(ComponentContainer::OwnerPlayer(OwnerPlayer($player_id))) .with(ComponentContainer::Position(Position($position))) - .with(ComponentContainer::Visibility(Visibility( - role_id == role_id, - ))) - .with(ComponentContainer::Attribute(Attribute::from_data( - base_property, - ))) + .with(ComponentContainer::Visibility(Visibility{ + is_visible: role.role_id == cur_role_id, + is_actor_visible: true, + })) + // TODO: Check if role has hardness or rage_mode + // TODO: Support AddProp from Equipment(Echo, weapon, buffs??), weapon base state goes to base_prop too. + .with(ComponentContainer::Attribute( + Attribute::from_data( + &role.get_base_properties(), + None, + None, + ) + )) .with(ComponentContainer::Movement(Movement::default())) .with(ComponentContainer::Equip(Equip { weapon_id: role.equip_weapon, @@ -64,7 +86,7 @@ macro_rules! create_player_entity_pb { .with(ComponentContainer::RoleSkin(RoleSkin { skin_id: role.skin_id, })) - .with(ComponentContainer::FightBuff(role_buffs)) + .with(ComponentContainer::FightBuff(buf_manager)) .build(); let mut pb = EntityPb { @@ -72,7 +94,7 @@ macro_rules! create_player_entity_pb { ..Default::default() }; - $world + world .get_entity_components(entity.entity_id) .into_iter() .for_each(|comp| comp.set_pb_data(&mut pb)); @@ -98,21 +120,29 @@ pub fn add_player_entities(player: &Player) { .map(|role_id| player.role_list.get(&role_id).unwrap()) .collect::>(); let cur_role_id = current_formation.cur_role; - let mut general_buffs = FightBuff::default(); - general_buffs.add_generic_permanent_buffs(); if world.active_entity_empty() { for role in role_vec { + let entity = world.create_entity( + role.role_id, + EEntityType::Player.into(), + player.basic_info.cur_map_id, + ); // Once per character buffs are implemented, add a mut on role_buffs - let role_buffs = general_buffs.clone(); + let fight_buff_infos = world.generate_role_permanent_buffs(entity.entity_id as i64); + let buf_manager = FightBuff { + fight_buff_infos, + list_buff_effect_cd: vec![], + }; let entity = world - .create_entity( - role.role_id, - EEntityType::Player.into(), - player.basic_info.cur_map_id, - ) - .with(ComponentContainer::PlayerEntityMarker(PlayerEntityMarker)) + .create_builder(entity) + .with(ComponentContainer::PlayerOwnedEntityMarker( + PlayerOwnedEntityMarker { + entity_type: EEntityType::Player, + }, + )) .with(ComponentContainer::EntityConfig(EntityConfig { + camp: 0, config_id: role.role_id, config_type: EntityConfigType::Character, entity_type: EEntityType::Player.into(), @@ -124,15 +154,17 @@ pub fn add_player_entities(player: &Player) { .with(ComponentContainer::Position(Position( player.location.position.clone(), ))) - .with(ComponentContainer::Visibility(Visibility( - role.role_id == cur_role_id, - ))) + .with(ComponentContainer::Visibility(Visibility { + is_visible: role.role_id == cur_role_id, + is_actor_visible: true, + })) + // TODO: from role + // TODO: Check if role has hardness or rage_mode + // TODO: Support AddProp from Equipment(Echo, weapon, buffs??), weapon base state goes to base_prop too. .with(ComponentContainer::Attribute(Attribute::from_data( - base_property_data::iter() - .find(|d| d.id == role.role_id) - .unwrap_or_else(|| { - base_property_data::iter().find(|d| d.id == 1102).unwrap() - }), + &role.get_base_properties(), + None, + None, ))) .with(ComponentContainer::Movement(Movement::default())) .with(ComponentContainer::Equip(Equip { @@ -145,7 +177,7 @@ pub fn add_player_entities(player: &Player) { .with(ComponentContainer::RoleSkin(RoleSkin { skin_id: role.skin_id, })) - .with(ComponentContainer::FightBuff(role_buffs)) + .with(ComponentContainer::FightBuff(buf_manager)) .build(); tracing::debug!( @@ -184,32 +216,32 @@ fn build_player_info_list(world: &World) -> Vec { .map(|sp| { let (cur_role_id, transform, _equip) = query_with!( world.get_world_entity(), - PlayerEntityMarker, + PlayerOwnedEntityMarker, OwnerPlayer, Visibility, EntityConfig, Position, Equip ) - .into_iter() - .find_map(|(_, _, owner, visibility, conf, pos, equip)| { - (sp.player_id == owner.0 && visibility.0).then_some(( - conf.config_id, - pos.0.clone(), - equip.weapon_id, - )) - }) - .unwrap_or_default(); + .into_iter() + .find_map(|(_, _, owner, visibility, conf, pos, equip)| { + (sp.player_id == owner.0 && visibility.is_visible).then_some(( + conf.config_id, + pos.0.clone(), + equip.weapon_id, + )) + }) + .unwrap_or_default(); let active_characters = query_with!( world.get_world_entity(), - PlayerEntityMarker, + PlayerOwnedEntityMarker, OwnerPlayer, EntityConfig, RoleSkin ) - .into_iter() - .filter(|(_, _, owner, _, _)| owner.0 == sp.player_id); + .into_iter() + .filter(|(_, _, owner, _, _)| owner.0 == sp.player_id); ScenePlayerInformation { cur_role: cur_role_id, @@ -230,7 +262,7 @@ fn build_player_info_list(world: &World) -> Vec { entity_id: id.into(), role_id: conf.config_id, on_stage_without_control: false, - role_skin_id: role_skin.skin_id, + // role_skin_id: role_skin.skin_id, }) .collect(), ..Default::default() @@ -242,91 +274,19 @@ fn build_player_info_list(world: &World) -> Vec { .collect() } -pub fn build_monster_entity(world: &mut WorldEntity, config_id: i32, map_id: i32, transform: Transform) -> Entity { - // TODO: Check for more components, AI and so - world.create_entity(config_id, EEntityType::Monster.into(), map_id) - .with(ComponentContainer::EntityConfig(EntityConfig { - config_id, - config_type: EntityConfigType::Level, - entity_type: EEntityType::Monster.into(), - entity_state: EntityState::Born, - })) - .with(ComponentContainer::Position(Position(transform))) - .with(ComponentContainer::Visibility(Visibility(true))) - .with(ComponentContainer::Attribute(Attribute::from_data( - base_property_data::iter() - .find(|d| d.id == 600000100) // TODO: Implement monster stats - .unwrap(), - ))) - .with(ComponentContainer::MonsterAi(MonsterAi { - weapon_id: 0, - hatred_group_id: 0, - ai_team_init_id: 100, - combat_message_id: 0, - })) - .with(ComponentContainer::Fsm(Fsm { - fsms: vec![ - DFsm { - fsm_id: 10007, - current_state: 10013, - flag: 0, - k_ts: 0, - }, - DFsm { - fsm_id: 10007, - current_state: 10015, - flag: 0, - k_ts: 0, - }, - DFsm { - fsm_id: 10007, - current_state: 10012, - flag: 0, - k_ts: 0, - }, - ], - hash_code: 0, - common_hash_code: 0, - black_board: vec![], - fsm_custom_blackboard_datas: None, - })) - .with(ComponentContainer::Movement(Movement::default())) - .build() -} +pub fn remove_entity(player: &Player, entity_id: i64, remove_type: ERemoveEntityType) { + let mut world_ref = player.world.borrow_mut(); + let world = world_ref.get_mut_world_entity(); -pub fn build_teleport_entity(world: &mut WorldEntity, - player_id: i32, - config_id: i32, - map_id: i32, - tp_unlocked: bool, - transform: Transform) -> Entity { - // TODO: Make this better - let teleport_state_tag = match tp_unlocked { - true => -3775711, - false => 1152559349 - }; - // TODO: Check for more components, InteractComponent & NearbyTrackingComponentPb - world.create_entity(config_id, EEntityType::SceneItem.into(), map_id) - .with(ComponentContainer::EntityConfig(EntityConfig { - config_id, - config_type: EntityConfigType::Level, - entity_type: EEntityType::SceneItem.into(), - entity_state: EntityState::Default, - })) - .with(ComponentContainer::Position(Position(transform))) - .with(ComponentContainer::Visibility(Visibility(true))) - .with(ComponentContainer::StateTag(StateTag { - state_tag_id: teleport_state_tag, - })) - .with(ComponentContainer::Autonomous(Autonomous { - autonomous_id: player_id, - })) - .with(ComponentContainer::Tag(Tag { - gameplay_tags: vec![], - entity_common_tags: vec![teleport_state_tag], - init_gameplay_tag: false, - })) - .build() + if world.remove_entity(entity_id as i32) { + player.notify(EntityRemoveNotify { + remove_infos: vec![EntityRemoveInfo { + entity_id, + r#type: remove_type.into(), + }], + is_remove: true, + }); + } } pub fn remove_entities(player: &Player, entities: &[&LevelEntityConfigData]) { @@ -345,13 +305,16 @@ pub fn remove_entities(player: &Player, entities: &[&LevelEntityConfigData]) { } for entity_id in removed_entities { player.notify(EntityRemoveNotify { - remove_infos: vec![EntityRemoveInfo { entity_id, r#type: 0 }], + remove_infos: vec![EntityRemoveInfo { + entity_id, + r#type: 0, + }], is_remove: true, }); } } -pub fn add_entities(player: &Player, entities: &[&LevelEntityConfigData]) { +pub fn add_entities(player: &Player, entities: &[&LevelEntityConfigData], external_awake: bool) { let mut added_entities = Vec::with_capacity(entities.len()); // Enclose to drop borrow mut ASAP { @@ -359,26 +322,113 @@ pub fn add_entities(player: &Player, entities: &[&LevelEntityConfigData]) { let world = world_ref.get_mut_world_entity(); for entity in entities { - // TODO: review other types - if entity.blueprint_type.contains("Monster") { - added_entities.push(build_monster_entity( - world, - entity.entity_id as i32, // TODO: Should be i64 - entity.map_id, - Transform::from(&entity.transform[..]), - )); - } else if entity.blueprint_type.starts_with("Teleport") { - added_entities.push(build_teleport_entity( - world, - player.basic_info.id, - entity.entity_id as i32, // TODO: Should be i64 - entity.map_id, - true, // TODO: Make this persistent within player - Transform::from(&entity.transform[..]), - )); - } else { - //tracing::debug!("Unhandled entity to be added of type: {}", entity.blueprint_type); + // Skip hidden entities + if entity.is_hidden { + tracing::debug!("Hidden entity with config id: {}", entity.entity_id); + continue; } + if entity.in_sleep && !external_awake { + tracing::debug!( + "Sleep entity with config id not spawned: {}", + entity.entity_id + ); + continue; + } + + let blueprint_config = blueprint_config_data::get(&entity.blueprint_type); + let template_config = template_config_data::get(&entity.blueprint_type); + if blueprint_config.is_none() || template_config.is_none() { + continue; + } + + let entity_logic: EntityLogic = blueprint_config.unwrap().entity_logic; + let (config_type, entity_type, mut entity_state) = match entity_logic { + EntityLogic::Item => ( + EntityConfigType::Level, + EEntityType::SceneItem, + EntityState::Default, + ), + EntityLogic::Animal => ( + EntityConfigType::Level, + EEntityType::Animal, + EntityState::Default, + ), + EntityLogic::Monster => ( + EntityConfigType::Level, + EEntityType::Monster, + EntityState::Born, + ), + EntityLogic::Vehicle => ( + EntityConfigType::Level, + EEntityType::Vehicle, + EntityState::Default, + ), + EntityLogic::Npc => ( + EntityConfigType::Level, + EEntityType::Npc, + EntityState::Default, + ), + EntityLogic::Vision => ( + EntityConfigType::Level, + EEntityType::Vision, + EntityState::Default, + ), + EntityLogic::ClientOnly => ( + EntityConfigType::Level, + EEntityType::ClientOnly, + EntityState::Default, + ), + EntityLogic::ServerOnly => { + tracing::debug!("Unhandled entity to be added of logic: {:?} with blueprint_type {} and id: {}", entity_logic, entity.blueprint_type, entity.entity_id); + continue; + } + EntityLogic::Custom => ( + EntityConfigType::Level, + EEntityType::Custom, + EntityState::Default, + ), + }; + + if entity.in_sleep { + entity_state = EntityState::Sleep; + } + + let config_id = entity.entity_id as i32; // TODO: i64???? + let map_id = entity.map_id; + let components: ComponentsData = entity + .components_data + .merge_with_template(&template_config.unwrap().components_data); + let tmp_entity = world.create_entity(config_id, config_type.into(), map_id); + let mut builder = world.create_builder(tmp_entity); + builder + .with(ComponentContainer::EntityConfig(EntityConfig { + camp: components + .base_info_component + .as_ref() + .and_then(|b| b.camp) + .unwrap_or(0), + config_id, + config_type, + entity_type, + entity_state, + })) + .with(ComponentContainer::Position(Position(Transform::from( + &entity.transform[..], + )))) + .with(ComponentContainer::Visibility(Visibility { + is_visible: true, + is_actor_visible: true, + })) + // Some entities may not actually have movement, but it's okay since we won't + // receive move package push for them + .with(ComponentContainer::Movement(Movement::default())); + + build_autonomous_component(&mut builder, player.basic_info.id, entity_logic); + build_interact_component(&mut builder, &components); + build_tags_components(&mut builder, &components, player, blueprint_config.unwrap().entity_type, config_id as i64); + build_attribute_component(&mut builder, &components, player.location.instance_id); + build_ai_components(&mut builder, &components); + added_entities.push(builder.build()); } } @@ -391,7 +441,8 @@ pub fn add_entities(player: &Player, entities: &[&LevelEntityConfigData]) { ..Default::default() }; - world.get_entity_components(entity.entity_id) + world + .get_entity_components(entity.entity_id) .into_iter() .for_each(|comp| comp.set_pb_data(&mut pb)); @@ -400,4 +451,124 @@ pub fn add_entities(player: &Player, entities: &[&LevelEntityConfigData]) { remove_tag_ids: true, }); } -} \ No newline at end of file +} + +#[inline(always)] +fn build_autonomous_component(builder: &mut EntityBuilder, id: i32, logic: EntityLogic) { + // TODO: Review if other types have autonomous + match logic { + EntityLogic::Item => { + builder.with(ComponentContainer::Autonomous(Autonomous { + autonomous_id: id, + })); + } + EntityLogic::Animal => {} + EntityLogic::Monster => {} + EntityLogic::Vehicle => {} + EntityLogic::Npc => {} + EntityLogic::Vision => {} + EntityLogic::ClientOnly => {} + EntityLogic::ServerOnly => {} + EntityLogic::Custom => {} + }; +} + +#[inline(always)] +fn build_interact_component(builder: &mut EntityBuilder, components: &ComponentsData) { + if components.interact_component.is_some() { + builder.with(ComponentContainer::Interact(Interact {})); + } +} + +#[inline(always)] +fn build_tags_components( + builder: &mut EntityBuilder, + components: &ComponentsData, + player: &Player, + entity_type: EntityType, + config_id: i64, +) { + if let Some(entity_state_component) = &components.entity_state_component { + let state = match entity_type { + EntityType::Teleporter | EntityType::TemporaryTeleporter => { + let result = player.teleports.teleports_data.iter() + .find(|teleporter| teleporter.entity_config_id == config_id); + match result.is_some() { + true => tag_utils::get_tag_id_by_name("关卡.Common.状态.激活"), + false => tag_utils::get_tag_id_by_name("关卡.Common.状态.常态"), + } + } + _ => { + // TODO: how to get states??? + let unlocked = false; + match unlocked { + true => tag_utils::get_tag_id_by_name("关卡.Common.状态.激活"), + false => tag_utils::get_tag_id_by_name("关卡.Common.状态.常态"), + } + } + }; + builder + .with(ComponentContainer::StateTag(StateTag { + state_tag_id: state, + })) + .with(ComponentContainer::Tag(Tag { + // TODO: + gameplay_tags: vec![], + entity_common_tags: vec![state], + // TODO: + init_gameplay_tag: false, + })); + } +} + +#[inline(always)] +fn build_attribute_component( + builder: &mut EntityBuilder, + components: &ComponentsData, + instance_id: i32, +) { + if let Some(attribute_component) = &components.attribute_component { + if attribute_component.disabled.unwrap_or_default() { + return; + } + if let Some(property_id) = attribute_component.property_id { + let inst_data = wicked_waifus_data::instance_dungeon_data::iter() + .find(|d| d.id == instance_id) + .unwrap(); + + let mut level = inst_data.entity_level; + if level == 0 { + // TODO: + // - iterate area_data + // - find player.basic_info.area_id + // - get player world level + // - get area.world_monster_level_max + level = 90; + } + builder.with(ComponentContainer::Attribute(Attribute::from_data( + &get_monster_props_by_level(property_id, level), + attribute_component.hardness_mode_id, + attribute_component.rage_mode_id, + ))); + } + } +} + +#[inline(always)] +fn build_ai_components(builder: &mut EntityBuilder, components: &ComponentsData) { + if let Some(ai_component) = &components.ai_component { + builder.with(ComponentContainer::MonsterAi(MonsterAi { + weapon_id: ai_component + .weapon_id + .as_deref() + .and_then(|id| id.parse().ok()) + .unwrap_or(0), + hatred_group_id: 0, // TODO: + ai_team_init_id: 100, // TODO: + combat_message_id: 0, // TODO: + })); + if let Some(ai_id) = ai_component.ai_id { + builder.with(ComponentContainer::Fsm(Fsm::from_ai_id(ai_id))); + } + } +} diff --git a/wicked-waifus-game-server/src/main.rs b/wicked-waifus-game-server/src/main.rs index d2c225f..3e20ee4 100644 --- a/wicked-waifus-game-server/src/main.rs +++ b/wicked-waifus-game-server/src/main.rs @@ -1,10 +1,10 @@ use std::sync::{Arc, LazyLock}; use anyhow::Result; -use wicked_waifus_commons::config_util; + use config::ServiceConfig; use session::SessionManager; - +use wicked_waifus_data::gacha_view_info_data; mod config; mod gateway_connection; mod logic; @@ -14,26 +14,46 @@ mod session; #[tokio::main] async fn main() -> Result<()> { - static CONFIG: LazyLock = - LazyLock::new(|| config_util::load_or_create("gameserver.toml")); static SESSION_MGR: LazyLock = LazyLock::new(SessionManager::default); + let service_config: &ServiceConfig = config::get_config(); ::wicked_waifus_commons::splash::print_splash(); ::wicked_waifus_commons::logging::init(::tracing::Level::DEBUG); - wicked_waifus_data::load_all_json_data("data/assets/game-data/BinData")?; - if CONFIG.game_server_config.load_textmaps { - wicked_waifus_data::text_map_data::load_textmaps("data/assets/game-data/Textmap")?; - } - logic::utils::quadrant_util::initialize_quadrant_system(CONFIG.game_server_config.quadrant_size); - let database = Arc::new(wicked_waifus_database::connect_to(&CONFIG.database).await?); + wicked_waifus_asset_updater::update_from_releases( + &service_config.asset_config.asset_url, + &service_config.game_server_config.resources_path, + service_config.asset_config.buffer_size, + )?; + let bin_data_path = format!( + "{}/BinData", + service_config.game_server_config.resources_path + ); + let text_map_path = format!( + "{}/Textmap", + service_config.game_server_config.resources_path + ); + + wicked_waifus_data::load_all_json_data(bin_data_path.as_str())?; + if service_config.game_server_config.load_textmaps { + for view_info in gacha_view_info_data::iter() { + wicked_waifus_data::text_map_data::register_filter(view_info.summary_title.clone()); + wicked_waifus_data::text_map_data::register_filter(view_info.summary_describe.clone()); + } + wicked_waifus_data::text_map_data::load_textmaps(text_map_path.as_str())?; + } + logic::utils::quadrant_util::initialize_quadrant_system( + service_config.game_server_config.quadrant_size, + ); + + let database = Arc::new(wicked_waifus_database::connect_to(&service_config.database).await?); wicked_waifus_database::run_migrations(database.as_ref()).await?; logic::thread_mgr::start_logic_threads(1); player_save_task::start(database.clone()); - gateway_connection::init(CONFIG.service_id, &CONFIG.gateway_end_point); - service_message_handler::run(&CONFIG.service_end_point, &SESSION_MGR, database).await?; + gateway_connection::init(service_config.service_id, &service_config.gateway_end_point); + service_message_handler::run(&service_config.service_end_point, &SESSION_MGR, database).await?; Ok(()) } diff --git a/wicked-waifus-gateway-server/Cargo.toml b/wicked-waifus-gateway-server/Cargo.toml index 33a121e..51bb976 100644 --- a/wicked-waifus-gateway-server/Cargo.toml +++ b/wicked-waifus-gateway-server/Cargo.toml @@ -3,6 +3,9 @@ name = "wicked-waifus-gateway-server" edition = "2021" version.workspace = true +[features] +debug-msg = [] + [dependencies] # Framework tokio.workspace = true diff --git a/wicked-waifus-gateway-server/src/handler/client_request_handler.rs b/wicked-waifus-gateway-server/src/handler/client_request_handler.rs index d288783..ef7792e 100644 --- a/wicked-waifus-gateway-server/src/handler/client_request_handler.rs +++ b/wicked-waifus-gateway-server/src/handler/client_request_handler.rs @@ -1,10 +1,7 @@ use wicked_waifus_commons::time_util; use wicked_waifus_database::{models, query_as}; use wicked_waifus_network::ServiceMessage; -use wicked_waifus_protocol::{ - message::Message, CreateCharacterRequest, EnterGameRequest, ErrorCode, HeartbeatRequest, - HeartbeatResponse, LoginRequest, LoginResponse, ProtoKeyRequest, ProtoKeyResponse, Protobuf, -}; +use wicked_waifus_protocol::{message::Message, CreateCharacterRequest, EnterGameRequest, ErrorCode, HeartbeatRequest, HeartbeatResponse, LoginRequest, LoginResponse, ProtoKeyRequest, ProtoKeyResponse, Protobuf, ReconnectRequest, ReconnectResponse}; use wicked_waifus_protocol_internal::{CreatePlayerDataRequest, StartPlayerSessionRequest, MessageID}; use crate::session::Session; @@ -39,6 +36,7 @@ macro_rules! requests { requests! { ProtoKey; Login; + Reconnect; Heartbeat; } @@ -138,6 +136,7 @@ async fn on_login_request( return; }; + // TODO: Add reconnect token session.player_id = Some(player_id); response.error_code = ErrorCode::Success.into(); response.timestamp = time_util::unix_timestamp_ms() as i64; @@ -149,6 +148,25 @@ async fn on_login_request( ); } +async fn on_reconnect_request( + session: &mut Session, + request: ReconnectRequest, + response: &mut ReconnectResponse, +) { + match session.player_id { + None => response.error_code = ErrorCode::ErrReconnectGwGetGatePlayerFailed.into(), + Some(player_id) => { + // TODO: check reconnect token / trace id and last seqno and verify it + if player_id == request.player_id { + response.error_code = ErrorCode::Success.into(); + response.timestamp = time_util::unix_timestamp_ms() as i64; + response.is_permitted_silent_login = false; + response.last_recv_seq_no = request.last_svr_seq_no; + } + } + } +} + async fn on_heartbeat_request( session: &mut Session, _: HeartbeatRequest, diff --git a/wicked-waifus-gateway-server/src/session/mod.rs b/wicked-waifus-gateway-server/src/session/mod.rs index ee9490f..f90f9ad 100644 --- a/wicked-waifus-gateway-server/src/session/mod.rs +++ b/wicked-waifus-gateway-server/src/session/mod.rs @@ -87,6 +87,8 @@ impl Session { )?); } + #[cfg(feature = "debug-msg")] + Self::debug_message(&message); client_message_handler::push_message(self.conv_id, message).await; } @@ -110,6 +112,8 @@ impl Session { } pub async fn send_message(&mut self, mut message: Message) -> Result<(), SessionError> { + #[cfg(feature = "debug-msg")] + Self::debug_message(&message); if let Some(session_key) = self.session_key.as_ref() { let payload = message.remove_payload(); message.set_payload(self.protokey_helper.encrypt( @@ -165,6 +169,16 @@ impl Session { .ok() }) } + + #[cfg(feature = "debug-msg")] + fn debug_message(message: &Message) { + if let Some(data) = message.get_payload() { + let id = message.get_message_id(); + let (name, value) = wicked_waifus_protocol::proto_dumper::get_debug_info(id, data) + .unwrap_or_else(|err| ("Error", err.to_string())); + tracing::warn!("DEBUG GATEWAY RX MESSAGE {name}({id}) with:\n{value}"); + } + } } impl fmt::Display for Session { diff --git a/wicked-waifus-protocol-internal/proto/data.proto b/wicked-waifus-protocol-internal/proto/data.proto index 6f6ed69..18f057c 100644 --- a/wicked-waifus-protocol-internal/proto/data.proto +++ b/wicked-waifus-protocol-internal/proto/data.proto @@ -30,6 +30,16 @@ message RoleSkillNodeData { int32 skill_id = 3; } +message RoleStats { + int32 hp = 1; // Current HP + int32 energy = 2; // Ultimate energy + int32 special_energy_1 = 3; // Forte + int32 special_energy_2 = 4; // Forte + int32 special_energy_3 = 5; // Forte + int32 special_energy_4 = 6; // Forte + int32 element_energy = 7; // Concerto +} + message RoleData { int32 role_id = 1; string name = 2; @@ -47,6 +57,9 @@ message RoleData { int32 resonant_chain_group_index = 14; int32 equip_weapon = 15; int32 skin_id = 16; + RoleStats stats = 17; + int32 favor_level = 18; + int32 favor_exp = 19; } message RoleFormationData { @@ -97,8 +110,76 @@ message PlayerChatData { map rooms = 1; } -message PlayerGuides { - repeated int32 finished_guides = 1; +message PlayerGuidesData { + repeated int32 started_guides = 1; + repeated int32 finished_guides = 2; +} + +message PlayerAdviceData { + bool is_show = 1; +} + +message PlayerAdventureTaskStatusData { + int32 id = 1; + int32 state = 2; + int32 progress = 3; +} + +message PlayerAdventureGlobalStatusData { + repeated PlayerAdventureTaskStatusData status = 1; + int32 now_chapter = 2; + int32 received_chapter = 3; +} + +message PlayerAdventureStatusData { + repeated PlayerAdventureGlobalStatusData status = 1; +} + +message PlayerInventoryData { + map items = 1; +} + +message PlayerTeleportData { + int32 id = 1; + int32 map_id = 2; + int64 entity_config_id = 3; +} + +message PlayerTeleportsData { + repeated PlayerTeleportData teleport_data = 1; +} + +message PlayerTutorialData { + int32 id = 1; + uint32 create_time = 2; + bool get_award = 3; +} + +message PlayerTutorialsData { + repeated PlayerTutorialData tutorials = 1; +} + +message PlayerMapTraceData { + repeated int32 traces = 1; +} + +message PlayerMonthCardData { + int32 days = 1; + int32 last_received_day = 2; +} + +enum PlayerMcElementType { + Glacio = 0; + Fusion = 1; + Electro = 2; + Aero = 3; + Spectro = 4; + Havoc = 5; +} + +message PlayerMcElementData { + repeated PlayerMcElementType unlocked_elements = 1; + PlayerMcElementType current_element = 2; } message PlayerSaveData { @@ -108,5 +189,13 @@ message PlayerSaveData { PlayerFuncData func_data = 4; PlayerExploreToolsData explore_tools_data = 5; PlayerChatData chat_data = 6; - PlayerGuides guides = 7; + PlayerGuidesData guides = 7; + PlayerAdviceData advise = 8; + PlayerAdventureStatusData adventure_status = 9; + PlayerInventoryData inventory = 10; + PlayerTeleportsData teleports = 11; + PlayerTutorialsData tutorials = 12; + PlayerMapTraceData map_trace = 13; + PlayerMonthCardData month_card = 14; + PlayerMcElementData mc_element = 15; }