diff --git a/.gitignore b/.gitignore index ea8c4bf..b60de5b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -/target +**/target diff --git a/Cargo.lock b/Cargo.lock index 11c1195..44daea7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,20 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "addr2line" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" +dependencies = [ + "gimli 0.23.0", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "adler32" version = "1.2.0" @@ -40,12 +55,36 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "backtrace" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88fb5a785d6b44fd9d6700935608639af1b8356de1e55d5f7c2740f4faa15d82" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide 0.4.4", + "object 0.23.0", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bindgen" version = "0.56.0" @@ -161,7 +200,7 @@ checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c" dependencies = [ "glob", "libc", - "libloading", + "libloading 0.7.0", ] [[package]] @@ -186,6 +225,16 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" +[[package]] +name = "core_plugin" +version = "0.1.0" +dependencies = [ + "image", + "lazy_static", + "plugin_api", + "wasm_plugin_guest", +] + [[package]] name = "coreaudio-rs" version = "0.10.0" @@ -230,6 +279,71 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "cranelift-bforest" +version = "0.68.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9221545c0507dc08a62b2d8b5ffe8e17ac580b0a74d1813b496b8d70b070fbd0" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.68.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9936ea608b6cd176f107037f6adbb4deac933466fc7231154f96598b2d3ab1" +dependencies = [ + "byteorder", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", + "gimli 0.22.0", + "log", + "regalloc", + "smallvec", + "target-lexicon", + "thiserror", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.68.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef2b2768568306540f4c8db3acce9105534d34c4a1e440529c1e702d7f8c8d7" +dependencies = [ + "cranelift-codegen-shared", + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.68.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6759012d6d19c4caec95793f052613e9d4113e925e7f14154defbac0f1d4c938" + +[[package]] +name = "cranelift-entity" +version = "0.68.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86badbce14e15f52a45b666b38abe47b204969dd7f8fb7488cb55dd46b361fa6" +dependencies = [ + "serde", +] + +[[package]] +name = "cranelift-frontend" +version = "0.68.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b608bb7656c554d0a4cf8f50c7a10b857e80306f6ff829ad6d468a7e2323c8d8" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + [[package]] name = "crc32fast" version = "1.2.1" @@ -239,14 +353,69 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "lazy_static", +] + [[package]] name = "darling" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.10.2", + "darling_macro 0.10.2", +] + +[[package]] +name = "darling" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c" +dependencies = [ + "darling_core 0.12.4", + "darling_macro 0.12.4", ] [[package]] @@ -259,7 +428,21 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.9.3", + "syn", +] + +[[package]] +name = "darling_core" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", "syn", ] @@ -269,7 +452,18 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ - "darling_core", + "darling_core 0.10.2", + "quote", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a" +dependencies = [ + "darling_core 0.12.4", "quote", "syn", ] @@ -295,18 +489,54 @@ dependencies = [ "syn", ] +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "enumset" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbd795df6708a599abf1ee10eacc72efd052b7a5f70fdf0715e4d5151a6db9c3" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19c52f9ec503c8a68dc04daf71a04b07e690c32ab1a8b68e33897f255269d47" +dependencies = [ + "darling 0.12.4", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + [[package]] name = "fishgame" version = "0.1.0" dependencies = [ "base64", "bitfield", + "core_plugin", "macroquad", "macroquad-particles", "macroquad-platformer", "macroquad-tiled", "nakama-rs", "nanoserde", + "plugin_api", + "wasm_plugin_host", ] [[package]] @@ -321,7 +551,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3203e88e086474e56b0785255804a0c23542f76253584d3f43152cd2bb95d0b7" dependencies = [ - "hashbrown", + "hashbrown 0.8.2", "ttf-parser", ] @@ -372,6 +602,34 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "gimli" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" + [[package]] name = "glam" version = "0.14.0" @@ -394,6 +652,21 @@ dependencies = [ "autocfg", ] +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + [[package]] name = "hound" version = "3.4.0" @@ -402,9 +675,9 @@ checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549" [[package]] name = "httparse" -version = "1.3.6" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc35c995b9d93ec174cf9a27d425c7892722101e14993cd227fdb51d70cf9589" +checksum = "4a1ce40d6fc9764887c2fdc7305c3dcc429ba11ff981c1509416afd5697e4437" [[package]] name = "ident_case" @@ -449,6 +722,17 @@ dependencies = [ "png", ] +[[package]] +name = "indexmap" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" +dependencies = [ + "autocfg", + "hashbrown 0.9.1", + "serde", +] + [[package]] name = "instant" version = "0.1.9" @@ -467,6 +751,12 @@ dependencies = [ "libc", ] +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + [[package]] name = "jni" version = "0.18.0" @@ -489,9 +779,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +checksum = "972f5ae5d1cb9c6ae417789196c803205313edde988685da5e3aae0827b9e7fd" dependencies = [ "libc", ] @@ -527,6 +817,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "leb128" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" + [[package]] name = "lewton" version = "0.10.2" @@ -540,9 +836,19 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.93" +version = "0.2.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" + +[[package]] +name = "libloading" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if 1.0.0", + "winapi 0.3.9", +] [[package]] name = "libloading" @@ -556,9 +862,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" dependencies = [ "scopeguard", ] @@ -583,9 +889,9 @@ dependencies = [ [[package]] name = "macroquad" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e9a227ffaf48bcb3022d0e1941fd0f4da4b49f0d05fd53ea252b2f024dca82" +checksum = "2d4b6dab140824bd6958aae0020011b30de49d82615ec60d2f3622d4dc1777ae" dependencies = [ "bumpalo", "fontdue", @@ -640,15 +946,33 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" + +[[package]] +name = "memmap2" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397d1a6d6d0563c0f5462bbdae662cf6c784edf5e828e40c7257f85d82bf56dd" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d" +dependencies = [ + "autocfg", +] [[package]] name = "miniquad" -version = "0.3.0-alpha.29" +version = "0.3.0-alpha.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c118b3ca8ee14b60dbadd67c20b84946a6c92db4761e60eb1c545e27863c24" +checksum = "544f4f479ba6084845f4908abbeb40abb5fe01b171928dca2901852231f3f838" dependencies = [ "sapp-android", "sapp-darwin", @@ -668,6 +992,16 @@ dependencies = [ "adler32", ] +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + [[package]] name = "mio" version = "0.6.23" @@ -711,6 +1045,12 @@ dependencies = [ "ws2_32-sys", ] +[[package]] +name = "more-asserts" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" + [[package]] name = "nakama-rs" version = "0.1.1" @@ -769,7 +1109,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" dependencies = [ - "darling", + "darling 0.10.2", "proc-macro-crate", "proc-macro2", "quote", @@ -867,6 +1207,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "num_enum" version = "0.5.1" @@ -889,6 +1239,22 @@ dependencies = [ "syn", ] +[[package]] +name = "object" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" +dependencies = [ + "crc32fast", + "indexmap", +] + +[[package]] +name = "object" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" + [[package]] name = "oboe" version = "0.4.1" @@ -929,9 +1295,9 @@ checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" [[package]] name = "openssl" -version = "0.10.33" +version = "0.10.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577" +checksum = "6d7830286ad6a3973c0f1d9b73738f69c76b739301d0229c4b96501695cbe4c8" dependencies = [ "bitflags", "cfg-if 1.0.0", @@ -943,9 +1309,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.61" +version = "0.9.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f" +checksum = "fa52160d45fa2e7608d504b7c3a3355afed615e6d8b627a74458634ba21b69bd" dependencies = [ "autocfg", "cc", @@ -997,12 +1363,25 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "pin-project-lite" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" + [[package]] name = "pkg-config" version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +[[package]] +name = "plugin_api" +version = "0.1.0" +dependencies = [ + "serde", +] + [[package]] name = "png" version = "0.16.8" @@ -1012,9 +1391,15 @@ dependencies = [ "bitflags", "crc32fast", "deflate", - "miniz_oxide", + "miniz_oxide 0.3.7", ] +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + [[package]] name = "proc-macro-crate" version = "0.1.5" @@ -1025,21 +1410,45 @@ dependencies = [ ] [[package]] -name = "proc-macro2" -version = "1.0.26" +name = "proc-macro-error" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ - "unicode-xid", + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", ] [[package]] -name = "quad-net" -version = "0.1.1" +name = "proc-macro-error-attr" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b697fe4057cb8a40c8822fa0ad8ecc999be6acb70a2b36cbcf1fba51e42f190" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "nanoserde", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quad-net" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b697fe4057cb8a40c8822fa0ad8ecc999be6acb70a2b36cbcf1fba51e42f190" +dependencies = [ + "nanoserde", "qws", "sapp-jsutils", "ureq", @@ -1073,7 +1482,7 @@ dependencies = [ "mio", "mio-extras", "openssl", - "rand", + "rand 0.4.6", "sha1", "slab", "url 1.7.2", @@ -1092,6 +1501,28 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.2", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.2", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -1107,6 +1538,49 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +[[package]] +name = "rand_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core 0.6.2", +] + +[[package]] +name = "rayon" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -1118,27 +1592,59 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" +checksum = "85dd92e586f7355c633911e11f77f3d12f04b1b1bd76a198bd34ae3af8341ef2" dependencies = [ "bitflags", ] +[[package]] +name = "regalloc" +version = "0.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5" +dependencies = [ + "log", + "rustc-hash", + "smallvec", +] + [[package]] name = "regex" -version = "1.4.5" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" +checksum = "1efb2352a0f4d4b128f734b5c44c79ff80117351138733f12f982fe3e2b13343" dependencies = [ "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.23" +version = "0.6.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" +checksum = "00efb87459ba4f6fb2169d20f68565555688e1250ee6825cdf6254f8b48fafb2" + +[[package]] +name = "region" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi 0.3.9", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi 0.3.9", +] [[package]] name = "ring" @@ -1166,6 +1672,12 @@ dependencies = [ "lewton", ] +[[package]] +name = "rustc-demangle" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -1174,9 +1686,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustls" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "064fd21ff87c6e87ed4506e68beb42459caa4a0e2eb144932e6776768556980b" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ "base64", "log", @@ -1185,6 +1697,12 @@ dependencies = [ "webpki", ] +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + [[package]] name = "same-file" version = "1.0.6" @@ -1247,9 +1765,9 @@ dependencies = [ [[package]] name = "sapp-wasm" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6632d855712381429686c971a984067cb214900640e8fb045c461d2aa35378e4" +checksum = "46dc18c2e8b9b9d1a50a8d83944d1e7c309581c99186b52d0530420d108ce37c" [[package]] name = "sapp-windows" @@ -1281,6 +1799,40 @@ name = "serde" version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +dependencies = [ + "itoa", + "ryu", + "serde", +] [[package]] name = "sha1" @@ -1296,9 +1848,9 @@ checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] name = "slab" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" [[package]] name = "smallvec" @@ -1312,6 +1864,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "stdweb" version = "0.1.3" @@ -1324,17 +1882,43 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" -version = "1.0.69" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb" +checksum = "ad184cc9470f9117b2ac6817bfe297307418819ba40552f9b3846f05c33d5373" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] +[[package]] +name = "target-lexicon" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422045212ea98508ae3d28025bc5aaa2bd4a9cdaecd442a08da2ee620ee9ea95" + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "rand 0.8.3", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.9", +] + [[package]] name = "thiserror" version = "1.0.24" @@ -1379,6 +1963,38 @@ dependencies = [ "serde", ] +[[package]] +name = "tracing" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +dependencies = [ + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" +dependencies = [ + "lazy_static", +] + [[package]] name = "ttf-parser" version = "0.8.3" @@ -1405,9 +2021,9 @@ dependencies = [ [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "untrusted" @@ -1417,9 +2033,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "ureq" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fbeb1aabb07378cf0e084971a74f24241273304653184f54cdce113c0d7df1b" +checksum = "2475a6781e9bc546e7b64f4013d2f4032c8c6a40fcffd7c6f4ee734a890972ab" dependencies = [ "base64", "chunked_transfer", @@ -1456,9 +2072,9 @@ dependencies = [ [[package]] name = "vcpkg" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" +checksum = "cbdbff6266a24120518560b5dc983096efb98462e51d0d68169895b237be3e5d" [[package]] name = "version_check" @@ -1477,6 +2093,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + [[package]] name = "wasm-bindgen" version = "0.2.73" @@ -1531,6 +2153,239 @@ version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" +[[package]] +name = "wasm_plugin_guest" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85398177caedea857f8a881cafa0256101b261a65d03872e577fdb7bff16f89c" +dependencies = [ + "bitfield", + "serde", + "serde_json", + "wasm_plugin_guest_derive", +] + +[[package]] +name = "wasm_plugin_guest_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8029abbe46726b92fcfb290819097e8ae205030d8b09cdada5be037476ad879a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "wasm_plugin_host" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e8c64adb96d595ada056e5229e653594dbaab81ce3f9b932cf0caade26bef" +dependencies = [ + "bitfield", + "serde", + "serde_json", + "wasmer", +] + +[[package]] +name = "wasmer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a70cfae554988d904d64ca17ab0e7cd652ee5c8a0807094819c1ea93eb9d6866" +dependencies = [ + "cfg-if 0.1.10", + "indexmap", + "more-asserts", + "target-lexicon", + "thiserror", + "wasmer-compiler", + "wasmer-compiler-cranelift", + "wasmer-derive", + "wasmer-engine", + "wasmer-engine-jit", + "wasmer-engine-native", + "wasmer-types", + "wasmer-vm", + "wat", + "winapi 0.3.9", +] + +[[package]] +name = "wasmer-compiler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b7732a9cab472bd921d5a0c422f45b3d03f62fa2c40a89e0770cef6d47e383e" +dependencies = [ + "enumset", + "serde", + "serde_bytes", + "smallvec", + "target-lexicon", + "thiserror", + "wasmer-types", + "wasmer-vm", + "wasmparser", +] + +[[package]] +name = "wasmer-compiler-cranelift" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48cb9395f094e1d81534f4c5e330ed4cdb424e8df870d29ad585620284f5fddb" +dependencies = [ + "cranelift-codegen", + "cranelift-frontend", + "gimli 0.22.0", + "more-asserts", + "rayon", + "serde", + "smallvec", + "tracing", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", +] + +[[package]] +name = "wasmer-derive" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b86dcd2c3efdb8390728a2b56f762db07789aaa5aa872a9dc776ba3a7912ed" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "wasmer-engine" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efe4667d6bd888f26ae8062a63a9379fa697415b4b4e380f33832e8418fd71b5" +dependencies = [ + "backtrace", + "bincode", + "lazy_static", + "memmap2", + "more-asserts", + "rustc-demangle", + "serde", + "serde_bytes", + "target-lexicon", + "thiserror", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", +] + +[[package]] +name = "wasmer-engine-jit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26770be802888011b4a3072f2a282fc2faa68aa48c71b3db6252a3937a85f3da" +dependencies = [ + "bincode", + "cfg-if 0.1.10", + "region", + "serde", + "serde_bytes", + "wasmer-compiler", + "wasmer-engine", + "wasmer-types", + "wasmer-vm", + "winapi 0.3.9", +] + +[[package]] +name = "wasmer-engine-native" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb4083a6c69f2cd4b000b82a80717f37c6cc2e536aee3a8ffe9af3edc276a8b" +dependencies = [ + "bincode", + "cfg-if 0.1.10", + "leb128", + "libloading 0.6.7", + "serde", + "tempfile", + "tracing", + "wasmer-compiler", + "wasmer-engine", + "wasmer-object", + "wasmer-types", + "wasmer-vm", + "which", +] + +[[package]] +name = "wasmer-object" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf8e0c12b82ff81ebecd30d7e118be5fec871d6de885a90eeb105df0a769a7b" +dependencies = [ + "object 0.22.0", + "thiserror", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-types" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f4ac28c2951cd792c18332f03da523ed06b170f5cf6bb5b1bdd7e36c2a8218" +dependencies = [ + "cranelift-entity", + "serde", + "thiserror", +] + +[[package]] +name = "wasmer-vm" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7635ba0b6d2fd325f588d69a950ad9fa04dddbf6ad08b6b2a183146319bf6ae" +dependencies = [ + "backtrace", + "cc", + "cfg-if 0.1.10", + "indexmap", + "libc", + "memoffset", + "more-asserts", + "region", + "serde", + "thiserror", + "wasmer-types", + "winapi 0.3.9", +] + +[[package]] +name = "wasmparser" +version = "0.65.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc2fe6350834b4e528ba0901e7aa405d78b89dc1fa3145359eb4de0e323fcf" + +[[package]] +name = "wast" +version = "35.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" +dependencies = [ + "leb128", +] + +[[package]] +name = "wat" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec280a739b69173e0ffd12c1658507996836ba4e992ed9bc1e5385a0bd72a02" +dependencies = [ + "wast", +] + [[package]] name = "web-sys" version = "0.3.50" @@ -1560,6 +2415,16 @@ dependencies = [ "webpki", ] +[[package]] +name = "which" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55551e42cbdf2ce2bedd2203d0cc08dba002c27510f86dab6d0ce304cba3dfe" +dependencies = [ + "either", + "libc", +] + [[package]] name = "winapi" version = "0.2.8" diff --git a/Cargo.toml b/Cargo.toml index 84795cf..dd6384d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,10 @@ macroquad-particles = {version = "0.1", features = ["nanoserde"] } bitfield = "0.13" nakama-rs = "0.1" base64 = "0.13" +plugin_api = { path = "./plugin_api" } +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +wasm_plugin_host = { version = "0.1.6", default-features = false, features = ["serialize_json"] } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +core_plugin = { path = "./core_plugin", features = ["inline"] } diff --git a/core_plugin/Cargo.lock b/core_plugin/Cargo.lock new file mode 100644 index 0000000..cfc5198 --- /dev/null +++ b/core_plugin/Cargo.lock @@ -0,0 +1,269 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "bytemuck" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "core_plugin" +version = "0.1.0" +dependencies = [ + "image", + "lazy_static", + "plugin_api", + "wasm_plugin_guest", +] + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +dependencies = [ + "adler32", + "byteorder", +] + +[[package]] +name = "image" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-iter", + "num-rational", + "num-traits", + "png", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "miniz_oxide" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +dependencies = [ + "adler32", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "plugin_api" +version = "0.1.0" +dependencies = [ + "serde", +] + +[[package]] +name = "png" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +dependencies = [ + "bitflags", + "crc32fast", + "deflate", + "miniz_oxide", +] + +[[package]] +name = "proc-macro2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "serde" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad184cc9470f9117b2ac6817bfe297307418819ba40552f9b3846f05c33d5373" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "wasm_plugin_guest" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85398177caedea857f8a881cafa0256101b261a65d03872e577fdb7bff16f89c" +dependencies = [ + "bitfield", + "serde", + "serde_json", + "wasm_plugin_guest_derive", +] + +[[package]] +name = "wasm_plugin_guest_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8029abbe46726b92fcfb290819097e8ae205030d8b09cdada5be037476ad879a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/core_plugin/Cargo.toml b/core_plugin/Cargo.toml new file mode 100644 index 0000000..489d1ee --- /dev/null +++ b/core_plugin/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "core_plugin" +version = "0.1.0" +authors = ["Alec Deason "] +edition = "2018" + +[lib] + crate-type = ["rlib", "cdylib"] + +[features] +inline = [] + +[dependencies] +plugin_api = { path = "../plugin_api" } +image = { version = "0.23", default-features = false, features = ["png"] } +lazy_static = "1.4.0" +wasm_plugin_guest = { version = "0.1.5", default-features = false, features = ["serialize_json"] } diff --git a/core_plugin/README.md b/core_plugin/README.md new file mode 100644 index 0000000..0c6da65 --- /dev/null +++ b/core_plugin/README.md @@ -0,0 +1,7 @@ +This plugin provides the default weapons used by Fish Game. + +To build: +``` +cargo build --target wasm32-unknown-unknown --release +cp target/wasm32-unknown-unknown/debug/core_plugin.wasm ../plugins/ +``` diff --git a/core_plugin/src/lib.rs b/core_plugin/src/lib.rs new file mode 100644 index 0000000..0e1c974 --- /dev/null +++ b/core_plugin/src/lib.rs @@ -0,0 +1,381 @@ +use std::{collections::HashMap, io::Cursor, sync::Mutex}; + +use plugin_api::{ + import_game_api, AnimatedSpriteDescription, AnimationDescription, GameApi, ImageDescription, + ItemDescription, ItemInstanceId, ItemType, PluginDescription, PluginId, Rect, SoundDescription, +}; + +lazy_static::lazy_static! { + static ref ITEMS:Mutex> = Default::default(); +} + +const GUN: ItemType = ItemType::new(9868317461196439167); +const SWORD: ItemType = ItemType::new(11238048715746880612); + +pub const GUN_THROWBACK: f32 = 700.0; + +pub enum ItemState { + Gun(GunState), + Sword(SwordState), +} + +#[cfg(not(feature = "inline"))] +use wasm_game_api::*; + +#[cfg(not(feature = "inline"))] +mod wasm_game_api { + use super::*; + import_game_api!(); + + pub struct GuestGameApi; + impl GameApi for GuestGameApi { + fn spawn_bullet(&self) { + spawn_bullet(); + } + + fn hit_rect(&self, rect: [f32; 4]) -> u32 { + hit_rect(rect) + } + + fn set_sprite_fx(&self, s: bool) { + set_sprite_fx(s); + } + + fn get_speed(&self) -> [f32; 2] { + get_speed() + } + + fn set_speed(&self, speed: [f32; 2]) { + set_speed(speed); + } + + fn facing_dir(&self) -> f32 { + facing_dir() + } + + fn position(&self) -> [f32; 2] { + position() + } + + fn set_sprite_animation(&self, animation: u32) { + set_sprite_animation(animation); + } + + fn set_fx_sprite_animation(&self, animation: u32) { + set_fx_sprite_animation(animation); + } + + fn set_sprite_frame(&self, frame: u32) { + set_sprite_frame(frame); + } + + fn set_fx_sprite_frame(&self, frame: u32) { + set_fx_sprite_frame(frame); + } + + fn disarm(&self) { + disarm(); + } + + fn play_sound_once(&self, sound: String) { + play_sound_once(sound); + } + + fn nakama_shoot(&self) { + nakama_shoot(); + } + + fn debug_print(&self, message: String) { + debug_print(message); + } + } +} +#[cfg_attr(not(feature = "inline"), wasm_plugin_guest::export_function)] +pub fn plugin_description() -> PluginDescription { + let sword_image = image::load( + Cursor::new(include_bytes!("../../assets/Whale/Sword(65x93).png")), + image::ImageFormat::Png, + ) + .unwrap() + .to_rgba8(); + let sword_width = sword_image.width() as u16; + let sword_height = sword_image.height() as u16; + let sword_bytes = sword_image.into_vec(); + + let gun_image = image::load( + Cursor::new(include_bytes!("../../assets/Whale/Gun(92x32).png")), + image::ImageFormat::Png, + ) + .unwrap() + .to_rgba8(); + let gun_width = gun_image.width() as u16; + let gun_height = gun_image.height() as u16; + let gun_bytes = gun_image.into_vec(); + + PluginDescription { + plugin_id: PluginId::new(11229058760733382699), + display_name: "basic weapons".to_string(), + sounds: vec![ + SoundDescription { + name: "sword".to_string(), + bytes: include_bytes!("../../assets/sounds/sword.wav").to_vec(), + }, + SoundDescription { + name: "shoot".to_string(), + bytes: include_bytes!("../../assets/sounds/shoot.ogg").to_vec(), + }, + ], + items: vec![ + ItemDescription { + item_type: SWORD, + display_name: "Sword".to_string(), + image: ImageDescription { + bytes: sword_bytes, + width: sword_width as u16, + height: sword_height as u16, + }, + mount_pos_right: [10.0, -35.0], + mount_pos_left: [-50.0, -35.0], + pickup_src: Rect { + x: 200.0, + y: 98.0, + w: 55.0, + h: 83.0, + }, + pickup_dst: [32.0, 32.0], + sprite: AnimatedSpriteDescription { + tile_width: 65, + tile_height: 93, + animations: vec![ + AnimationDescription { + name: "idle".to_string(), + row: 0, + frames: 1, + fps: 1, + }, + AnimationDescription { + name: "shoot".to_string(), + row: 1, + frames: 4, + fps: 15, + }, + ], + playing: true, + }, + fx_sprite: None, + }, + ItemDescription { + item_type: GUN, + display_name: "Gun".to_string(), + image: ImageDescription { + bytes: gun_bytes, + width: gun_width as u16, + height: gun_height as u16, + }, + mount_pos_right: [0.0, 16.0], + mount_pos_left: [-60.0, 16.0], + pickup_src: Rect { + x: 0.0, + y: 0.0, + w: 64.0, + h: 32.0, + }, + pickup_dst: [32.0, 16.0], + sprite: AnimatedSpriteDescription { + tile_width: 92, + tile_height: 32, + animations: vec![ + AnimationDescription { + name: "idle".to_string(), + row: 0, + frames: 1, + fps: 1, + }, + AnimationDescription { + name: "shoot".to_string(), + row: 1, + frames: 3, + fps: 15, + }, + ], + playing: true, + }, + fx_sprite: Some(AnimatedSpriteDescription { + tile_width: 76, + tile_height: 66, + animations: vec![AnimationDescription { + name: "shoot".to_string(), + row: 2, + frames: 3, + fps: 15, + }], + playing: true, + }), + }, + ], + } +} + +#[cfg_attr(not(feature = "inline"), wasm_plugin_guest::export_function)] +pub fn new_instance(item_type: ItemType, item_id: ItemInstanceId) { + let state = match item_type { + GUN => ItemState::Gun(GunState::default()), + SWORD => ItemState::Sword(SwordState::default()), + _ => panic!(), + }; + + ITEMS.lock().unwrap().insert(item_id, state); +} + +#[cfg_attr(not(feature = "inline"), wasm_plugin_guest::export_function)] +pub fn destroy_instance(item_id: ItemInstanceId) { + ITEMS.lock().unwrap().remove(&item_id); +} + +#[cfg_attr(not(feature = "inline"), wasm_plugin_guest::export_function)] +pub fn uses_remaining(item_id: ItemInstanceId) -> Option<(u32, u32)> { + if let Some(ItemState::Gun(state)) = ITEMS.lock().unwrap().get(&item_id) { + Some((state.ammo, 3)) + } else { + None + } +} + +#[cfg(not(feature = "inline"))] +#[wasm_plugin_guest::export_function] +pub fn update_shoot(item_id: ItemInstanceId, current_time: f64) -> bool { + inner_update_shoot(item_id, current_time, &GuestGameApi) +} + +#[cfg(feature = "inline")] +pub fn update_shoot(item_id: ItemInstanceId, current_time: f64, game_api: &dyn GameApi) -> bool { + inner_update_shoot(item_id, current_time, game_api) +} + +fn inner_update_shoot(item_id: ItemInstanceId, current_time: f64, game_api: &dyn GameApi) -> bool { + if let Some(item) = ITEMS.lock().unwrap().get_mut(&item_id) { + match item { + ItemState::Gun(state) => { + if let Some(time) = state.recovery_time { + if time <= current_time { + game_api.set_sprite_animation(0); + game_api.set_sprite_fx(false); + state.recovery_time.take(); + if state.ammo == 0 { + game_api.disarm(); + } + true + } else { + false + } + } else { + state.ammo -= 1; + game_api.play_sound_once("shoot".to_string()); + game_api.spawn_bullet(); + game_api.nakama_shoot(); + game_api.set_sprite_fx(true); + let mut speed = game_api.get_speed(); + speed[0] -= GUN_THROWBACK * game_api.facing_dir(); + game_api.set_speed(speed); + game_api.set_sprite_animation(1); + state.recovery_time = Some(current_time + 0.08 * 3.0); + false + } + } + ItemState::Sword(state) => { + if let Some(time) = state.recovery_time { + if time <= current_time { + game_api.set_sprite_animation(0); + state.recovery_time.take(); + true + } else { + game_api.nakama_shoot(); + game_api.play_sound_once("sword".to_string()); + let pos = game_api.position(); + let sword_hit_box = if game_api.facing_dir() > 0.0 { + [pos[0] + 35., pos[1] - 5., 40., 60.] + } else { + [pos[0] - 50., pos[1] - 5., 40., 60.] + }; + game_api.hit_rect(sword_hit_box); + false + } + } else { + game_api.set_sprite_animation(1); + state.recovery_time = Some(current_time + 0.08 * 3.0); + false + } + } + } + } else { + true + } +} + +#[cfg(not(feature = "inline"))] +#[wasm_plugin_guest::export_function] +pub fn update_remote_shoot(item_id: ItemInstanceId, current_time: f64) -> bool { + inner_update_remote_shoot(item_id, current_time, &GuestGameApi) +} + +#[cfg(feature = "inline")] +pub fn update_remote_shoot( + item_id: ItemInstanceId, + current_time: f64, + game_api: &dyn GameApi, +) -> bool { + inner_update_remote_shoot(item_id, current_time, game_api) +} + +fn inner_update_remote_shoot( + item_id: ItemInstanceId, + current_time: f64, + game_api: &dyn GameApi, +) -> bool { + if let Some(item) = ITEMS.lock().unwrap().get_mut(&item_id) { + match item { + ItemState::Gun(_) => { + game_api.spawn_bullet(); + game_api.play_sound_once("shoot".to_string()); + true + } + ItemState::Sword(state) => { + if let Some(time) = state.recovery_time { + if time <= current_time { + game_api.set_sprite_animation(0); + state.recovery_time.take(); + true + } else { + false + } + } else { + game_api.play_sound_once("sword".to_string()); + game_api.set_sprite_animation(1); + state.recovery_time = Some(current_time + 0.08 * 3.0); + false + } + } + } + } else { + true + } +} + +pub struct GunState { + recovery_time: Option, + ammo: u32, +} + +impl Default for GunState { + fn default() -> Self { + Self { + recovery_time: None, + ammo: 3, + } + } +} + +#[derive(Default)] +pub struct SwordState { + recovery_time: Option, +} diff --git a/plugin_api/Cargo.lock b/plugin_api/Cargo.lock new file mode 100644 index 0000000..2cc8003 --- /dev/null +++ b/plugin_api/Cargo.lock @@ -0,0 +1,63 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "plugin_api" +version = "0.1.0" +dependencies = [ + "serde", +] + +[[package]] +name = "proc-macro2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/plugin_api/Cargo.toml b/plugin_api/Cargo.toml new file mode 100644 index 0000000..1d05182 --- /dev/null +++ b/plugin_api/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "plugin_api" +version = "0.1.0" +authors = ["Alec Deason "] +edition = "2018" + +[dependencies] +serde = { version = "1", features = ["derive"] } diff --git a/plugin_api/src/lib.rs b/plugin_api/src/lib.rs new file mode 100644 index 0000000..fad05e4 --- /dev/null +++ b/plugin_api/src/lib.rs @@ -0,0 +1,153 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct ItemType { + id: u64 +} + +impl ItemType { + pub const fn new(id: u64) -> Self { + Self { id } + } +} + +impl From for u64 { + fn from(item_type: ItemType) -> u64 { + item_type.id + } +} + +impl From for ItemType { + fn from(item_type: u64) -> ItemType{ + ItemType { id: item_type } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct ItemInstanceId { + pub id: u64 +} + +impl ItemInstanceId { + pub const fn new(id: u64) -> Self { + Self { id } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct PluginId { + id: u64 +} + +impl PluginId { + pub const fn new(id: u64) -> Self { + Self { id } + } +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct PluginDescription { + pub plugin_id: PluginId, + pub display_name: String, + pub items: Vec, + pub sounds: Vec, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct ItemDescription { + pub item_type: ItemType, + pub display_name: String, + pub image: ImageDescription, + pub mount_pos_right: [f32; 2], + pub mount_pos_left: [f32; 2], + pub pickup_src: Rect, + pub pickup_dst: [f32; 2], + pub sprite: AnimatedSpriteDescription, + pub fx_sprite: Option, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct Rect { + pub x: f32, + pub y: f32, + pub w: f32, + pub h: f32 +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct SoundDescription { + pub name: String, + pub bytes: Vec, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct ImageDescription { + pub bytes: Vec, + pub width: u16, + pub height: u16, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct AnimatedSpriteDescription { + pub tile_width: u32, + pub tile_height: u32, + pub animations: Vec, + pub playing: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AnimationDescription { + pub name: String, + pub row: u32, + pub frames: u32, + pub fps: u32, +} + +pub trait PluginApi { + fn new_instance(&mut self, item_type: ItemType, item_id: ItemInstanceId); + fn destroy_instance(&mut self, item_id: ItemInstanceId); + fn uses_remaining(&mut self, item_id: ItemInstanceId) -> Option<(u32, u32)>; + fn update_shoot(&mut self, item_id: ItemInstanceId, time: f64) -> bool; + fn update_remote_shoot(&mut self, item_id: ItemInstanceId, time: f64) -> bool; +} + +pub trait GameApi { + fn spawn_bullet(&self); + fn hit_rect(&self, rect: [f32; 4]) -> u32; + fn set_sprite_fx(&self, s: bool); + fn get_speed(&self) -> [f32; 2]; + fn set_speed(&self, speed: [f32; 2]); + fn facing_dir(&self) -> f32; + fn position(&self) -> [f32; 2]; + fn set_sprite_animation(&self, animation: u32); + fn set_fx_sprite_animation(&self, animation: u32); + fn set_sprite_frame(&self, frame: u32); + fn set_fx_sprite_frame(&self, frame: u32); + fn disarm(&self); + fn play_sound_once(&self, sound: String); + fn nakama_shoot(&self); + fn debug_print(&self, message: String); +} + +#[macro_export] +macro_rules! import_game_api { + () => { + wasm_plugin_guest::import_functions! { + fn spawn_bullet(); + fn hit_rect(rect: [f32; 4]) -> u32; + fn set_sprite_fx(s: bool); + fn get_speed() -> [f32; 2]; + fn set_speed(speed: [f32; 2]); + fn facing_dir() -> f32; + fn position() -> [f32; 2]; + fn set_sprite_animation(animation: u32); + fn set_fx_sprite_animation(animation: u32); + fn set_sprite_frame(frame: u32); + fn set_fx_sprite_frame(frame: u32); + fn disarm(); + fn play_sound_once(sound: String); + fn nakama_shoot(); + fn debug_print(message: String); + } + }; +} diff --git a/src/gui.rs b/src/gui.rs index a20eaf7..1a021a6 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -5,18 +5,18 @@ use macroquad::{ }; mod authentication; +mod credits; mod lobby; mod main_menu; mod style; mod waitscreen; -mod credits; pub use authentication::authentication; +pub use credits::credits; pub use lobby::matchmaking_lobby; pub use main_menu::main_menu; pub use style::GuiResources; pub use waitscreen::waitscreen; -pub use credits::credits; const WINDOW_WIDTH: f32 = 700.0; const WINDOW_HEIGHT: f32 = 300.0; diff --git a/src/main.rs b/src/main.rs index 85f652e..65920be 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,18 +14,20 @@ use macroquad::{ }; use nanoserde::DeJson; -use particles::EmittersCache; use macroquad_platformer::World as CollisionWorld; +use particles::EmittersCache; mod credentials { include!(concat!(env!("OUT_DIR"), "/nakama_credentials.rs")); } -mod nodes; - mod gui; +mod nodes; +mod plugin; use gui::Scene; +use nodes::{ItemIdSource, ItemImplementationRegistry}; +use plugin::PluginRegistry; pub mod consts { pub const GRAVITY: f32 = 900.0; @@ -268,6 +270,12 @@ async fn network_game(nakama: Handle, game_type: GameType, networ let w = resources.tiled_map.raw_tiled_map.tilewidth * resources.tiled_map.raw_tiled_map.width; let h = resources.tiled_map.raw_tiled_map.tileheight * resources.tiled_map.raw_tiled_map.height; + let mut item_registry = ItemImplementationRegistry::default(); + let plugin_registry = PluginRegistry::load("plugins/", &mut item_registry).await; + storage::store(item_registry); + storage::store(plugin_registry); + storage::store(ItemIdSource::default()); + let level_background = scene::add_node(LevelBackground::new()); for object in &resources.tiled_map.layers["decorations"].objects { diff --git a/src/nodes.rs b/src/nodes.rs index f4ad5d2..a694937 100644 --- a/src/nodes.rs +++ b/src/nodes.rs @@ -3,6 +3,7 @@ mod camera; mod decoration; mod fxses; mod global_events; +mod item; mod level_background; mod nakama; mod pickup; @@ -14,8 +15,9 @@ pub use camera::Camera; pub use decoration::Decoration; pub use fxses::Fxses; pub use global_events::GlobalEvents; +pub use item::{ItemIdSource, ItemImplementationRegistry}; pub use level_background::LevelBackground; pub use nakama::{Nakama, NakamaRealtimeGame}; pub use pickup::Pickup; -pub use player::Player; +pub use player::{Fish, Player}; pub use remote_player::RemotePlayer; diff --git a/src/nodes/global_events.rs b/src/nodes/global_events.rs index 20f8c12..485aecc 100644 --- a/src/nodes/global_events.rs +++ b/src/nodes/global_events.rs @@ -7,7 +7,7 @@ use macroquad::{ }; use crate::{ - nodes::{pickup::ItemType, NakamaRealtimeGame, Pickup, Player, RemotePlayer}, + nodes::{item::ItemImplementationRegistry, NakamaRealtimeGame, Pickup, Player, RemotePlayer}, Resources, }; @@ -45,6 +45,13 @@ impl scene::Node for GlobalEvents { if get_time() - node.last_spawn_time >= Self::SPAWN_INTERVAL as _ && node.spawned_items.len() < 3 { + let item_registry = storage::get::(); + let item_types = item_registry.item_types(); + if item_types.is_empty() { + // Probably no plugins are loaded. Nothing to do. + return; + } + let resources = storage::get::(); let tilewidth = resources.tiled_map.raw_tiled_map.tilewidth as f32; @@ -75,11 +82,8 @@ impl scene::Node for GlobalEvents { node.last_spawn_time = get_time(); - let item_type = if rand::gen_range(0, 2) == 0 { - ItemType::Gun - } else { - ItemType::Sword - }; + let idx = rand::gen_range(0, item_types.len()); + let item_type = item_types[idx]; let item_id = node.uid; node.spawned_items .push((item_id, scene::add_node(Pickup::new(pos, item_type)))); diff --git a/src/nodes/item.rs b/src/nodes/item.rs new file mode 100644 index 0000000..02e3b2d --- /dev/null +++ b/src/nodes/item.rs @@ -0,0 +1,122 @@ +use std::collections::HashMap; + +use macroquad::{ + experimental::{animation::AnimatedSprite, collections::storage, scene::Handle}, + prelude::*, +}; + +use crate::{ + nodes::{Player, RemotePlayer}, + plugin::{animated_sprite_from_desc, image_from_desc, Plugin, PluginRegistry}, +}; +use plugin_api::{ItemDescription, ItemInstanceId, ItemType, PluginApi, PluginId}; + +pub(crate) struct ItemImplementation { + display_name: String, + item_type: ItemType, + pub texture: Texture2D, + pub mount_pos_right: Vec2, + pub mount_pos_left: Vec2, + pub pickup_src: Rect, + pub pickup_dst: Vec2, + pub sprite: AnimatedSprite, + pub fx_sprite: Option, + implementing_plugin: PluginId, +} + +impl ItemImplementation { + pub(crate) fn from_description(description: ItemDescription, plugin: PluginId) -> Self { + let texture = Texture2D::from_image(&image_from_desc(description.image)); + let pickup_src = description.pickup_src; + Self { + display_name: description.display_name, + item_type: description.item_type, + texture, + mount_pos_right: vec2( + description.mount_pos_right[0], + description.mount_pos_right[1], + ), + mount_pos_left: vec2(description.mount_pos_left[0], description.mount_pos_left[1]), + pickup_src: Rect::new(pickup_src.x, pickup_src.y, pickup_src.w, pickup_src.h), + pickup_dst: vec2(description.pickup_dst[0], description.pickup_dst[1]), + sprite: animated_sprite_from_desc(description.sprite), + fx_sprite: description.fx_sprite.map(|d| animated_sprite_from_desc(d)), + implementing_plugin: plugin, + } + } +} + +impl ItemImplementation { + fn with_plugin(&self, mut f: impl FnMut(&mut Plugin) -> R) -> R { + let mut plugin_registry = storage::get_mut::(); + let plugin = plugin_registry + .get_plugin(self.implementing_plugin) + .unwrap(); + f(plugin) + } + + pub(crate) fn construct(&self, item_id: ItemInstanceId) { + self.with_plugin(|p| { + p.new_instance(self.item_type, item_id); + }) + } + + pub(crate) fn destroy(&self, item_id: ItemInstanceId) { + self.with_plugin(|p| { + p.destroy_instance(item_id); + }) + } + + pub(crate) fn uses_remaining(&self, item_id: ItemInstanceId) -> Option<(u32, u32)> { + self.with_plugin(|p| p.uses_remaining(item_id)) + } + + pub(crate) fn update_shoot(&self, item_id: ItemInstanceId, player: Handle) -> bool { + self.with_plugin(|p| p.with_current_player(player, |p| p.update_shoot(item_id, get_time()))) + } + + pub(crate) fn update_remote_shoot( + &self, + item_id: ItemInstanceId, + player: Handle, + ) -> bool { + self.with_plugin(|p| { + p.with_current_remote_player(player, |p| p.update_remote_shoot(item_id, get_time())) + }) + } +} + +#[derive(Default)] +pub struct ItemImplementationRegistry(HashMap); + +impl ItemImplementationRegistry { + pub(crate) fn add(&mut self, description: ItemDescription, implementing_plugin: PluginId) { + self.0.insert( + description.item_type, + ItemImplementation::from_description(description, implementing_plugin), + ); + } + + pub(crate) fn get_implementation(&self, item_type: ItemType) -> Option<&ItemImplementation> { + self.0.get(&item_type) + } + + pub(crate) fn item_types(&self) -> Vec { + self.0.keys().copied().collect() + } +} + +pub struct ItemIdSource(u64); +impl Default for ItemIdSource { + fn default() -> Self { + Self(1) + } +} + +impl ItemIdSource { + pub fn next_id(&mut self) -> ItemInstanceId { + let new_id = self.0; + self.0 += 1; + ItemInstanceId::new(new_id) + } +} diff --git a/src/nodes/nakama/nakama_realtime_game.rs b/src/nodes/nakama/nakama_realtime_game.rs index e46d13b..9142606 100644 --- a/src/nodes/nakama/nakama_realtime_game.rs +++ b/src/nodes/nakama/nakama_realtime_game.rs @@ -14,18 +14,19 @@ use nakama_rs::api_client::Event; use crate::{ consts, - nodes::{pickup::ItemType, Nakama, Pickup, Player, RemotePlayer}, + nodes::{Nakama, Pickup, Player, RemotePlayer}, GameType, Resources, }; +use plugin_api::ItemType; struct NetworkCache { - sent_position: [u8; 4], + sent_position: [u8; 11], last_send_time: f64, } impl NetworkCache { fn flush(&mut self) { - self.sent_position = [0; 4]; + self.sent_position = [0; 11]; self.last_send_time = 0.0; } } @@ -38,34 +39,34 @@ bitfield::bitfield! { y, set_y: 19, 10; facing, set_facing: 20; shooting, set_shooting: 21; - weapon, set_weapon: 30, 22; - dead, set_dead: 31; + u64, weapon, set_weapon: 85, 22; + dead, set_dead: 86; } #[test] fn test_bitfield() { - let mut bits = PlayerStateBits([0; 4]); + let mut bits = PlayerStateBits([0; 11]); bits.set_x(345); bits.set_y(567); bits.set_facing(true); bits.set_shooting(false); - bits.set_weapon(66); + bits.set_weapon(11527428624421318257); assert_eq!(bits.x(), 345); assert_eq!(bits.y(), 567); assert_eq!(bits.facing(), true); assert_eq!(bits.shooting(), false); - assert_eq!(bits.weapon(), 66); + assert_eq!(bits.weapon(), 11527428624421318257); assert_eq!(bits.dead(), false); - assert_eq!(std::mem::size_of_val(&bits), 4); + assert_eq!(std::mem::size_of_val(&bits), 11); } mod message { use nanoserde::{DeBin, SerBin}; #[derive(Debug, Clone, SerBin, DeBin, PartialEq)] - pub struct State(pub [u8; 4]); + pub struct State(pub [u8; 11]); impl State { pub const OPCODE: i32 = 1; } @@ -84,7 +85,7 @@ mod message { pub id: u32, pub x: u16, pub y: u16, - pub item_type: u8, + pub item_type: u64, } impl SpawnItem { pub const OPCODE: i32 = 4; @@ -142,7 +143,7 @@ impl NakamaRealtimeGame { NakamaRealtimeGame { game_type, network_cache: NetworkCache { - sent_position: [0; 4], + sent_position: [0; 11], last_send_time: 0.0, }, remote_players: BTreeMap::new(), @@ -176,7 +177,7 @@ impl NakamaRealtimeGame { id: id as _, x: pos.x as _, y: pos.y as _, - item_type: item_type as _, + item_type: item_type.into(), }, ); } @@ -315,18 +316,13 @@ impl Node for NakamaRealtimeGame { node.network_cache.last_send_time = get_time(); - let mut state = PlayerStateBits([0; 4]); + let mut state = PlayerStateBits([0; 11]); state.set_x(player.pos().x as u32); state.set_y(player.pos().y as u32); state.set_facing(player.facing()); state.set_shooting(shooting); - let weapon = match player.weapon() { - None => 0, - Some(ItemType::Gun) => 1, - Some(ItemType::Sword) => 2, - }; - state.set_weapon(weapon); + state.set_weapon(player.weapon().map_or(0, |weapon| weapon.into())); state.set_dead(player.is_dead()); if node.network_cache.sent_position != state.0 { @@ -403,14 +399,10 @@ impl Node for NakamaRealtimeGame { resources.disarm_fxses.spawn(pos + vec2(16., 33.)); other.disarm(); } - if other.weapon().map_or(0, |weapon| weapon as u32) + if other.weapon().map_or(0, |weapon| weapon.into()) != state.weapon() { - match state.weapon() { - 1 => other.pick_weapon(ItemType::Gun), - 2 => other.pick_weapon(ItemType::Sword), - _ => unreachable!(), - } + other.pick_weapon(state.weapon().into()); } if state.shooting() { let handle = other.handle(); @@ -440,14 +432,7 @@ impl Node for NakamaRealtimeGame { } = DeBin::deserialize_bin(&data).unwrap(); let pos = vec2(x as f32, y as f32); - let new_node = scene::add_node(Pickup::new( - pos, - match item_type { - x if x == ItemType::Sword as u8 => ItemType::Sword, - x if x == ItemType::Gun as u8 => ItemType::Gun, - _ => unreachable!(), - }, - )); + let new_node = scene::add_node(Pickup::new(pos, item_type.into())); if let Some(pickup) = node.pickups.insert(id as _, new_node) { if let Some(node) = scene::try_get_node(pickup) { node.delete(); diff --git a/src/nodes/pickup.rs b/src/nodes/pickup.rs index 155b470..322dda9 100644 --- a/src/nodes/pickup.rs +++ b/src/nodes/pickup.rs @@ -7,14 +7,8 @@ use macroquad::{ prelude::*, }; -use crate::Resources; - -#[derive(Debug, Clone, Copy, PartialEq)] -#[repr(u8)] -pub enum ItemType { - Gun = 1, - Sword = 2, -} +use crate::{nodes::item::ItemImplementationRegistry, Resources}; +use plugin_api::ItemType; pub struct Pickup { pub pos: Vec2, @@ -80,29 +74,22 @@ impl scene::Node for Pickup { ), ); - match node.item_type { - ItemType::Gun => draw_texture_ex( - resources.gun, - node.pos.x, - node.pos.y + 8., - WHITE, - DrawTextureParams { - source: Some(Rect::new(0.0, 0.0, 64., 32.)), - dest_size: Some(vec2(32., 16.)), - ..Default::default() - }, - ), - ItemType::Sword => draw_texture_ex( - resources.sword, - node.pos.x + 4., - node.pos.y - 4., - WHITE, - DrawTextureParams { - source: Some(Rect::new(195.0 + 5., 93.0 + 5., 65. - 10., 93. - 10.)), - dest_size: Some(vec2(32., 32.)), - ..Default::default() - }, - ), - } + let item_registry = storage::get::(); + let item_impl = item_registry + .get_implementation(node.item_type) + .expect(&format!("Invalid ItemType: {:?}", node.item_type)); + + //TODO: position sprite + draw_texture_ex( + item_impl.texture, + node.pos.x, + node.pos.y + 8., + WHITE, + DrawTextureParams { + source: Some(item_impl.pickup_src), + dest_size: Some(item_impl.pickup_dst), + ..Default::default() + }, + ); } } diff --git a/src/nodes/player.rs b/src/nodes/player.rs index 94fa76b..8a5d16d 100644 --- a/src/nodes/player.rs +++ b/src/nodes/player.rs @@ -15,10 +15,15 @@ use macroquad_platformer::Actor; use crate::{ consts, - nodes::{pickup::ItemType, Nakama, NakamaRealtimeGame, Pickup}, + nodes::{ + item::{ItemIdSource, ItemImplementationRegistry}, + Nakama, NakamaRealtimeGame, Pickup, + }, Resources, }; +use plugin_api::{ItemInstanceId, ItemType}; + #[derive(Default, Debug, Clone)] pub struct Input { jump: bool, @@ -27,24 +32,65 @@ pub struct Input { right: bool, } -pub enum Weapon { - Gun { bullets: i32 }, - Sword, +pub struct Weapon { + pub item_type: ItemType, + pub item_id: ItemInstanceId, + texture: Texture2D, + mount_pos_right: Vec2, + mount_pos_left: Vec2, + pub sprite: AnimatedSprite, + pub fx_sprite: Option, + pub fx: bool, +} + +impl Drop for Weapon { + fn drop(&mut self) { + let item_registry = storage::get::(); + let item_impl = item_registry + .get_implementation(self.item_type) + .expect(&format!("Invalid ItemType: {:?}", self.item_type)); + item_impl.destroy(self.item_id); + } +} + +impl Weapon { + fn new(item_type: ItemType) -> Self { + let mut item_id_source = storage::get_mut::(); + let item_registry = storage::get::(); + let item_impl = item_registry + .get_implementation(item_type) + .expect(&format!("Invalid ItemType: {:?}", item_type)); + let instance_id = item_id_source.next_id(); + item_impl.construct(instance_id); + Self { + item_type, + item_id: instance_id, + texture: item_impl.texture, + mount_pos_right: item_impl.mount_pos_right, + mount_pos_left: item_impl.mount_pos_left, + sprite: item_impl.sprite.clone(), + fx_sprite: item_impl.fx_sprite.clone(), + fx: false, + } + } + + fn uses_remaining(&self) -> Option<(u32, u32)> { + let item_registry = storage::get::(); + let implementation = item_registry.get_implementation(self.item_type).unwrap(); + implementation.uses_remaining(self.item_id) + } } pub struct Fish { fish_sprite: AnimatedSprite, - gun_sprite: AnimatedSprite, - pub sword_sprite: AnimatedSprite, - gun_fx_sprite: AnimatedSprite, - gun_fx: bool, pub collider: Actor, - pos: Vec2, - speed: Vec2, + pub pos: Vec2, + pub speed: Vec2, on_ground: bool, dead: bool, - facing: bool, + pub facing: bool, pub weapon: Option, + discarded_weapon: Option, input: Input, } @@ -83,62 +129,9 @@ impl Fish { ], true, ); - let gun_sprite = AnimatedSprite::new( - 92, - 32, - &[ - Animation { - name: "idle".to_string(), - row: 0, - frames: 1, - fps: 1, - }, - Animation { - name: "shoot".to_string(), - row: 1, - frames: 3, - fps: 15, - }, - ], - false, - ); - let sword_sprite = AnimatedSprite::new( - 65, - 93, - &[ - Animation { - name: "idle".to_string(), - row: 0, - frames: 1, - fps: 1, - }, - Animation { - name: "shoot".to_string(), - row: 1, - frames: 4, - fps: 15, - }, - ], - false, - ); - let gun_fx_sprite = AnimatedSprite::new( - 92, - 32, - &[Animation { - name: "shoot".to_string(), - row: 2, - frames: 3, - fps: 15, - }], - false, - ); Fish { fish_sprite, - gun_fx_sprite, - gun_fx: false, - gun_sprite, - sword_sprite, collider: resources.collision_world.add_actor(spawner_pos, 30, 54), on_ground: false, dead: false, @@ -146,6 +139,7 @@ impl Fish { speed: vec2(0., 0.), facing: true, weapon: None, + discarded_weapon: None, input: Default::default(), } } @@ -171,19 +165,17 @@ impl Fish { } pub fn disarm(&mut self) { - self.weapon = None; + // This juggle is necessary because the plugins need to clean up + // their internal state when a weapon is discarded but they aren't + // currently callable recursively so the actual weapon cleanup must + // be defered until there's no call to the plugin happening. + self.discarded_weapon = self.weapon.take(); } pub fn pick_weapon(&mut self, item_type: ItemType) { + self.weapon = Some(Weapon::new(item_type)); let resources = storage::get_mut::(); play_sound_once(resources.pickup_sound); - - match item_type { - ItemType::Gun => { - self.weapon = Some(Weapon::Gun { bullets: 3 }); - } - ItemType::Sword => self.weapon = Some(Weapon::Sword), - } } pub fn facing_dir(&self) -> f32 { @@ -225,62 +217,45 @@ impl Fish { }, ); - if self.dead == false && matches!(self.weapon, Some(Weapon::Gun { .. })) { - let gun_mount_pos = if self.facing { - vec2(0., 16.) - } else { - vec2(-60., 16.) - }; - self.gun_sprite.update(); - draw_texture_ex( - resources.gun, - self.pos.x + gun_mount_pos.x, - self.pos.y + gun_mount_pos.y, - color::WHITE, - DrawTextureParams { - source: Some(self.gun_sprite.frame().source_rect), - dest_size: Some(self.gun_sprite.frame().dest_size), - flip_x: !self.facing, - ..Default::default() - }, - ); - - if self.gun_fx { - self.gun_fx_sprite.update(); + if self.dead == false { + if let Some(weapon) = &mut self.weapon { + let mount_pos = if self.facing { + weapon.mount_pos_right + } else { + weapon.mount_pos_left + }; + weapon.sprite.update(); draw_texture_ex( - resources.gun, - self.pos.x + gun_mount_pos.x, - self.pos.y + gun_mount_pos.y, + weapon.texture, + self.pos.x + mount_pos.x, + self.pos.y + mount_pos.y, color::WHITE, DrawTextureParams { - source: Some(self.gun_fx_sprite.frame().source_rect), - dest_size: Some(self.gun_fx_sprite.frame().dest_size), + source: Some(weapon.sprite.frame().source_rect), + dest_size: Some(weapon.sprite.frame().dest_size), flip_x: !self.facing, ..Default::default() }, ); - } - } - if self.dead == false && matches!(self.weapon, Some(Weapon::Sword)) { - let sword_mount_pos = if self.facing { - vec2(10., -35.) - } else { - vec2(-50., -35.) - }; - self.sword_sprite.update(); - draw_texture_ex( - resources.sword, - self.pos.x + sword_mount_pos.x, - self.pos.y + sword_mount_pos.y, - color::WHITE, - DrawTextureParams { - source: Some(self.sword_sprite.frame().source_rect), - dest_size: Some(self.sword_sprite.frame().dest_size), - flip_x: !self.facing, - ..Default::default() - }, - ); + if weapon.fx { + if let Some(sprite) = &mut weapon.fx_sprite { + sprite.update(); + draw_texture_ex( + weapon.texture, + self.pos.x + mount_pos.x, + self.pos.y + mount_pos.y, + color::WHITE, + DrawTextureParams { + source: Some(sprite.frame().source_rect), + dest_size: Some(sprite.frame().dest_size), + flip_x: !self.facing, + ..Default::default() + }, + ); + } + } + } } } } @@ -295,15 +270,14 @@ pub struct Player { state_machine: StateMachine>, leaderboard_written: bool, nakama: Handle, - nakama_realtime: Handle, + pub nakama_realtime: Handle, } impl Player { const ST_NORMAL: usize = 0; const ST_DEATH: usize = 1; const ST_SHOOT: usize = 2; - const ST_SWORD_SHOOT: usize = 3; - const ST_AFTERMATCH: usize = 4; + const ST_AFTERMATCH: usize = 3; pub fn new( deathmatch: bool, @@ -331,12 +305,6 @@ impl Player { .update(Self::update_shoot) .coroutine(Self::shoot_coroutine), ); - state_machine.add_state( - Self::ST_SWORD_SHOOT, - State::new() - .update(Self::update_sword_shoot) - .coroutine(Self::sword_shoot_coroutine), - ); state_machine.add_state( Self::ST_AFTERMATCH, State::new().update(Self::update_aftermatch), @@ -364,9 +332,7 @@ impl Player { } pub fn pick_weapon(&mut self, item_type: ItemType) { - if self.state_machine.state() != Self::ST_SHOOT - && self.state_machine.state() != Self::ST_SWORD_SHOOT - { + if self.state_machine.state() != Self::ST_SHOOT { self.fish.pick_weapon(item_type); } } @@ -381,11 +347,7 @@ impl Player { } pub fn weapon(&self) -> Option { - match self.fish.weapon { - None => None, - Some(Weapon::Gun { .. }) => Some(ItemType::Gun), - Some(Weapon::Sword) => Some(ItemType::Sword), - } + self.fish.weapon.as_ref().map(|weapon| weapon.item_type) } fn death_coroutine(node: &mut RefMut) -> Coroutine { @@ -454,124 +416,36 @@ impl Player { start_coroutine(coroutine) } + fn update_shoot(node: &mut RefMut, _dt: f32) {} + fn shoot_coroutine(node: &mut RefMut) -> Coroutine { let handle = node.handle(); let coroutine = async move { - { - let resources = storage::get_mut::(); - play_sound_once(resources.shoot_sound); - - let mut node = &mut *scene::get_node(handle); - - node.fish.gun_fx = true; - let mut nakama = scene::get_node(node.nakama_realtime); - nakama.shoot(); - - let mut bullets = scene::find_node_by_type::().unwrap(); - bullets.spawn_bullet(node.fish.pos, node.fish.facing); - node.fish.speed.x = -consts::GUN_THROWBACK * node.fish.facing_dir(); - } - { - let node = &mut *scene::get_node(handle); - node.fish.gun_sprite.set_animation(1); - } - for i in 0u32..3 { - { - let node = &mut *scene::get_node(handle); - node.fish.gun_sprite.set_frame(i); - node.fish.gun_fx_sprite.set_frame(i); + loop { + let mut item = None; + if let Some(weapon) = &scene::get_node(handle).fish.weapon { + item = Some((weapon.item_type, weapon.item_id)); } - - wait_seconds(0.08).await; - } - { - let mut node = scene::get_node(handle); - node.fish.gun_sprite.set_animation(0); - } - - let mut node = &mut *scene::get_node(handle); - - node.fish.gun_fx = false; - - if let Weapon::Gun { bullets } = node.fish.weapon.as_mut().unwrap() { - *bullets -= 1; - - if *bullets <= 0 { - let mut resources = storage::get_mut::(); - resources.disarm_fxses.spawn(node.fish.pos + vec2(16., 33.)); - node.fish.weapon = None; - } - } - - // node.weapon_animation.play(0, 0..5).await; - // node.weapon_animation.play(0, 5..).await; - node.state_machine.set_state(Self::ST_NORMAL); - }; - - start_coroutine(coroutine) - } - - fn update_shoot(node: &mut RefMut, _dt: f32) { - node.fish.speed.x *= 0.9; - } - - fn sword_shoot_coroutine(node: &mut RefMut) -> Coroutine { - let handle = node.handle(); - let coroutine = async move { - { - let resources = storage::get_mut::(); - play_sound_once(resources.sword_sound); - - let node = &mut *scene::get_node(handle); - node.fish.sword_sprite.set_animation(1); - - let mut nakama = scene::get_node(node.nakama_realtime); - nakama.shoot(); - } - - { - let node = &mut *scene::get_node(handle); - let others = scene::find_nodes_by_type::(); - let sword_hit_box = if node.fish.facing { - Rect::new(node.pos().x + 35., node.pos().y - 5., 40., 60.) - } else { - Rect::new(node.pos().x - 50., node.pos().y - 5., 40., 60.) - }; - - for player in others { - if Rect::new(player.pos().x, player.pos().y, 20., 64.).overlaps(&sword_hit_box) - { - let mut net = scene::get_node(node.nakama_realtime); - net.kill(&player.id, !node.fish.facing); + if let Some((item_type, item_id)) = item { + let item_registry = storage::get::(); + let implementation = item_registry.get_implementation(item_type).unwrap(); + let done = implementation.update_shoot(item_id, handle); + if done { + let node = &mut *scene::get_node(handle); + node.state_machine.set_state(Self::ST_NORMAL); + break; } - } - } - - for i in 0u32..3 { - { + } else { let node = &mut *scene::get_node(handle); - node.fish.sword_sprite.set_frame(i); + node.state_machine.set_state(Self::ST_NORMAL); + break; } - - wait_seconds(0.08).await; + wait_seconds(0.005).await; } - - { - let mut node = scene::get_node(handle); - node.fish.sword_sprite.set_animation(0); - } - - let node = &mut *scene::get_node(handle); - node.state_machine.set_state(Self::ST_NORMAL); }; - start_coroutine(coroutine) } - fn update_sword_shoot(node: &mut RefMut, _dt: f32) { - node.fish.speed.x *= 0.9; - } - fn update_aftermatch(node: &mut RefMut, _dt: f32) { let resources = storage::get::(); let nakama = &mut scene::get_node(node.nakama).api_client; @@ -637,10 +511,8 @@ impl Player { } if fish.input.fire { - match fish.weapon { - Some(Weapon::Gun { .. }) => node.state_machine.set_state(Self::ST_SHOOT), - Some(Weapon::Sword) => node.state_machine.set_state(Self::ST_SWORD_SHOOT), - None => {} + if fish.weapon.is_some() { + node.state_machine.set_state(Self::ST_SHOOT); } } } @@ -649,17 +521,19 @@ impl Player { if self.is_dead() { return; } - if let Some(Weapon::Gun { bullets }) = self.fish.weapon { - let full_color = Color::new(0.8, 0.9, 1.0, 1.0); - let empty_color = Color::new(0.8, 0.9, 1.0, 0.8); - for i in 0..3 { - let x = self.fish.pos.x + 15.0 * i as f32; - - if i >= bullets { - draw_circle_lines(x, self.fish.pos.y - 4.0, 4.0, 2., empty_color); - } else { - draw_circle(x, self.fish.pos.y - 4.0, 4.0, full_color); - }; + if let Some(weapon) = &self.fish.weapon { + if let Some((remaining, max_uses)) = weapon.uses_remaining() { + let full_color = Color::new(0.8, 0.9, 1.0, 1.0); + let empty_color = Color::new(0.8, 0.9, 1.0, 0.8); + for i in 0..max_uses { + let x = self.fish.pos.x + 15.0 * i as f32; + + if i >= remaining { + draw_circle_lines(x, self.fish.pos.y - 4.0, 4.0, 2., empty_color); + } else { + draw_circle(x, self.fish.pos.y - 4.0, 4.0, full_color); + }; + } } } } @@ -685,6 +559,10 @@ impl scene::Node for Player { } fn update(mut node: RefMut) { + // finalize any disarmament that happened in the previous frame + // here where it's safe to call the plugin's item destructor. + node.fish.discarded_weapon.take(); + let game_started = scene::find_node_by_type::() .unwrap() .game_started(); diff --git a/src/nodes/remote_player.rs b/src/nodes/remote_player.rs index c9ca3d1..2c14de1 100644 --- a/src/nodes/remote_player.rs +++ b/src/nodes/remote_player.rs @@ -8,17 +8,15 @@ use macroquad::{ }; use crate::{ - nodes::{ - pickup::ItemType, - player::{Fish, Weapon}, - }, + nodes::{item::ItemImplementationRegistry, player::Fish}, Resources, }; +use plugin_api::ItemType; pub struct RemotePlayer { pub username: String, pub id: String, - fish: Fish, + pub fish: Fish, pub dead: bool, pub ready: bool, @@ -50,11 +48,7 @@ impl RemotePlayer { } pub fn weapon(&self) -> Option { - match self.fish.weapon { - None => None, - Some(Weapon::Gun { .. }) => Some(ItemType::Gun), - Some(Weapon::Sword) => Some(ItemType::Sword), - } + self.fish.weapon.as_ref().map(|weapon| weapon.item_type) } pub fn set_pos(&mut self, pos: Vec2) { @@ -76,41 +70,26 @@ impl RemotePlayer { } pub fn shoot(&mut self, handle: Handle) { - match self.fish.weapon { - Some(Weapon::Gun { .. }) => { - let mut bullets = scene::find_node_by_type::().unwrap(); - bullets.spawn_bullet(self.pos(), self.fish.facing()); - } - Some(Weapon::Sword) => { - let swing = async move { - { - if let Some(mut node) = scene::try_get_node(handle) { - node.fish.sword_sprite.set_animation(1); - } - } - - for i in 0u32..3 { - { - if let Some(mut node) = scene::try_get_node(handle) { - node.fish.sword_sprite.set_frame(i); - } - } - - wait_seconds(0.08).await; - } - - { - if let Some(mut node) = scene::try_get_node(handle) { - node.fish.sword_sprite.set_animation(0); - } + let coroutine = async move { + loop { + let mut item = None; + if let Some(weapon) = &scene::get_node(handle).fish.weapon { + item = Some((weapon.item_type, weapon.item_id)); + } + if let Some((item_type, item_id)) = item { + let item_registry = storage::get::(); + let implementation = item_registry.get_implementation(item_type).unwrap(); + let done = implementation.update_remote_shoot(item_id, handle); + if done { + break; } - }; - start_coroutine(swing); + } else { + break; + } + wait_seconds(0.005).await; } - None => { - println!("well"); - } - } + }; + start_coroutine(coroutine); } } impl scene::Node for RemotePlayer { diff --git a/src/plugin.rs b/src/plugin.rs new file mode 100644 index 0000000..790f857 --- /dev/null +++ b/src/plugin.rs @@ -0,0 +1,522 @@ +use macroquad::{ + audio::{load_sound_from_bytes, play_sound_once, Sound}, + experimental::{ + animation::{AnimatedSprite, Animation}, + scene::{self, Handle, RefMut}, + }, + prelude::*, + texture::Image, +}; +use std::{ + collections::HashMap, + path::Path, + sync::{Arc, Mutex}, +}; + +use crate::nodes::{Fish, ItemImplementationRegistry, Player, RemotePlayer}; +use plugin_api::{ + AnimatedSpriteDescription, AnimationDescription, GameApi, ImageDescription, ItemInstanceId, + ItemType, PluginApi, PluginDescription, PluginId, +}; + +pub fn image_from_desc(desc: ImageDescription) -> Image { + Image { + bytes: desc.bytes, + width: desc.width, + height: desc.height, + } +} +pub fn animation_from_desc(desc: AnimationDescription) -> Animation { + Animation { + name: desc.name, + row: desc.row, + frames: desc.frames, + fps: desc.fps, + } +} + +pub fn animated_sprite_from_desc(desc: AnimatedSpriteDescription) -> AnimatedSprite { + let animations: Vec = desc + .animations + .into_iter() + .map(|a| animation_from_desc(a)) + .collect(); + AnimatedSprite::new(desc.tile_width, desc.tile_height, &animations, desc.playing) +} + +#[derive(Default, Clone)] +pub struct HostGameApi { + current_player: Arc>>>, + current_remote_player: Arc>>>, + sounds: Arc>>, +} +unsafe impl Send for HostGameApi {} +unsafe impl Sync for HostGameApi {} + +enum LocalOrRemotePlayer { + Local(RefMut), + Remote(RefMut), +} +struct FishMut { + node: LocalOrRemotePlayer, +} +impl std::ops::Deref for FishMut { + type Target = Fish; + + fn deref(&self) -> &Self::Target { + match &self.node { + LocalOrRemotePlayer::Local(player) => &player.fish, + LocalOrRemotePlayer::Remote(player) => &player.fish, + } + } +} +impl std::ops::DerefMut for FishMut { + fn deref_mut(&mut self) -> &mut Self::Target { + match &mut self.node { + LocalOrRemotePlayer::Local(player) => &mut player.fish, + LocalOrRemotePlayer::Remote(player) => &mut player.fish, + } + } +} + +impl HostGameApi { + fn current_player(&self) -> Option> { + self.current_player.lock().unwrap().map(|p| p.clone()) + } + + fn current_remote_player(&self) -> Option> { + self.current_remote_player + .lock() + .unwrap() + .map(|p| p.clone()) + } + + fn current_fish(&self) -> FishMut { + if let Some(handle) = self.current_player() { + let node = scene::get_node(handle); + FishMut { + node: LocalOrRemotePlayer::Local(node), + } + } else { + let node = scene::get_node(self.current_remote_player().unwrap()); + FishMut { + node: LocalOrRemotePlayer::Remote(node), + } + } + } +} + +impl GameApi for HostGameApi { + fn spawn_bullet(&self) { + let mut bullets = scene::find_node_by_type::().unwrap(); + let fish = self.current_fish(); + bullets.spawn_bullet(fish.pos, fish.facing); + } + + fn hit_rect(&self, rect: [f32; 4]) -> u32 { + if let Some(handle) = self.current_player() { + let hit_box = Rect::new(rect[0], rect[1], rect[2], rect[3]); + let node = &mut *scene::get_node(handle); + let others = scene::find_nodes_by_type::(); + let mut hit_count = 0; + for player in others { + if Rect::new(player.pos().x, player.pos().y, 20., 64.).overlaps(&hit_box) { + hit_count += 1; + let mut net = scene::get_node(node.nakama_realtime); + net.kill(&player.id, !node.fish.facing); + } + } + hit_count + } else { + 0 + } + } + + fn set_sprite_fx(&self, s: bool) { + let mut fish = self.current_fish(); + if let Some(weapon) = &mut fish.weapon { + weapon.fx = s; + } + } + + fn get_speed(&self) -> [f32; 2] { + let fish = self.current_fish(); + [fish.speed.x, fish.speed.y] + } + + fn set_speed(&self, speed: [f32; 2]) { + let mut fish = self.current_fish(); + fish.speed.x = speed[0]; + fish.speed.y = speed[1]; + } + + fn set_sprite_animation(&self, animation: u32) { + let mut fish = self.current_fish(); + if let Some(weapon) = &mut fish.weapon { + weapon.sprite.set_animation(animation as usize); + } + } + + fn set_fx_sprite_animation(&self, animation: u32) { + let mut fish = self.current_fish(); + if let Some(weapon) = &mut fish.weapon { + if let Some(sprite) = &mut weapon.fx_sprite { + sprite.set_animation(animation as usize); + } + } + } + + fn set_sprite_frame(&self, frame: u32) { + let mut fish = self.current_fish(); + if let Some(weapon) = &mut fish.weapon { + weapon.sprite.set_frame(frame); + } + } + + fn set_fx_sprite_frame(&self, frame: u32) { + let mut fish = self.current_fish(); + if let Some(weapon) = &mut fish.weapon { + if let Some(sprite) = &mut weapon.fx_sprite { + sprite.set_frame(frame); + } + } + } + + fn facing_dir(&self) -> f32 { + let fish = self.current_fish(); + fish.facing_dir() + } + + fn position(&self) -> [f32; 2] { + let fish = self.current_fish(); + let pos = fish.pos(); + [pos.x, pos.y] + } + + fn nakama_shoot(&self) { + if let Some(handle) = self.current_player() { + let node = &mut *scene::get_node(handle); + let mut nakama = scene::get_node(node.nakama_realtime); + nakama.shoot(); + } + } + + fn disarm(&self) { + let mut fish = self.current_fish(); + fish.disarm(); + } + + fn play_sound_once(&self, name: String) { + if let Some(sound) = self.sounds.lock().unwrap().get(&name) { + play_sound_once(*sound); + } + } + + fn debug_print(&self, message: String) { + println!("{}", message); + } +} + +#[cfg(not(target_arch = "wasm32"))] +pub use native_host::*; +#[cfg(target_arch = "wasm32")] +pub use wasm_host::*; + +#[cfg(not(target_arch = "wasm32"))] +mod native_host { + use super::*; + + use wasm_plugin_host::WasmPlugin; + + pub struct PluginRegistry(HashMap); + + pub struct Plugin { + pub wasm_plugin: WasmPlugin, + pub game_api: HostGameApi, + } + + impl PluginRegistry { + pub async fn load( + path: impl AsRef, + item_registry: &mut ItemImplementationRegistry, + ) -> Self { + let mut plugins = HashMap::new(); + for entry in path + .as_ref() + .read_dir() + .expect("Unable to read plugins directory") + { + if let Ok(entry) = entry { + if entry.path().to_str().unwrap().contains(".wasm") { + let game_api = HostGameApi::default(); + let mut builder = + wasm_plugin_host::WasmPluginBuilder::from_file(entry.path()) + .expect(&format!("Failed to load plugin {:?}", entry.path())); + // TODO: This should probably be a macro or something to reduce boilerplate + builder = builder.import_function_with_context( + "spawn_bullet", + game_api.clone(), + |ctx: &HostGameApi| { + ctx.spawn_bullet(); + }, + ); + builder = builder.import_function_with_context( + "hit_rect", + game_api.clone(), + |ctx: &HostGameApi, rect: [f32; 4]| ctx.hit_rect(rect), + ); + builder = builder.import_function_with_context( + "set_sprite_fx", + game_api.clone(), + |ctx: &HostGameApi, s: bool| { + ctx.set_sprite_fx(s); + }, + ); + builder = builder.import_function_with_context( + "get_speed", + game_api.clone(), + |ctx: &HostGameApi| ctx.get_speed(), + ); + builder = builder.import_function_with_context( + "set_speed", + game_api.clone(), + |ctx: &HostGameApi, s: [f32; 2]| { + ctx.set_speed(s); + }, + ); + builder = builder.import_function_with_context( + "set_sprite_animation", + game_api.clone(), + |ctx: &HostGameApi, animation: u32| { + ctx.set_sprite_animation(animation); + }, + ); + builder = builder.import_function_with_context( + "set_fx_sprite_animation", + game_api.clone(), + |ctx: &HostGameApi, animation: u32| { + ctx.set_fx_sprite_animation(animation); + }, + ); + builder = builder.import_function_with_context( + "set_sprite_frame", + game_api.clone(), + |ctx: &HostGameApi, frame: u32| { + ctx.set_sprite_frame(frame); + }, + ); + builder = builder.import_function_with_context( + "set_fx_sprite_frame", + game_api.clone(), + |ctx: &HostGameApi, frame: u32| { + ctx.set_fx_sprite_frame(frame); + }, + ); + builder = builder.import_function_with_context( + "facing_dir", + game_api.clone(), + |ctx: &HostGameApi| ctx.facing_dir(), + ); + builder = builder.import_function_with_context( + "position", + game_api.clone(), + |ctx: &HostGameApi| ctx.position(), + ); + builder = builder.import_function_with_context( + "disarm", + game_api.clone(), + |ctx: &HostGameApi| ctx.disarm(), + ); + builder = builder.import_function_with_context( + "play_sound_once", + game_api.clone(), + |ctx: &HostGameApi, sound: String| { + ctx.play_sound_once(sound); + }, + ); + builder = builder.import_function_with_context( + "nakama_shoot", + game_api.clone(), + |ctx: &HostGameApi| ctx.nakama_shoot(), + ); + builder = builder.import_function_with_context( + "debug_print", + game_api.clone(), + |ctx: &HostGameApi, message: String| ctx.debug_print(message), + ); + let mut plugin = builder.finish().unwrap(); + let description: PluginDescription = + plugin.call_function("plugin_description").expect(&format!( + "Failed to call 'plugin_description' on plugin {:?}", + entry.path() + )); + + for item in description.items { + item_registry.add(item, description.plugin_id); + } + + { + let mut sounds = game_api.sounds.lock().unwrap(); + for sound in description.sounds { + sounds.insert( + sound.name, + load_sound_from_bytes(&sound.bytes).await.unwrap(), + ); + } + } + + plugins.insert( + description.plugin_id, + Plugin { + wasm_plugin: plugin, + game_api, + }, + ); + } + } + } + + PluginRegistry(plugins) + } + + pub(crate) fn get_plugin(&mut self, plugin_id: PluginId) -> Option<&mut Plugin> { + self.0.get_mut(&plugin_id) + } + } + + impl Plugin { + pub fn with_current_player( + &mut self, + player: Handle, + mut f: impl FnMut(&mut Plugin) -> R, + ) -> R { + self.game_api.current_player.lock().unwrap().replace(player); + let result = f(self); + self.game_api.current_player.lock().unwrap().take(); + result + } + + pub fn with_current_remote_player( + &mut self, + player: Handle, + mut f: impl FnMut(&mut Plugin) -> R, + ) -> R { + self.game_api + .current_remote_player + .lock() + .unwrap() + .replace(player); + let result = f(self); + self.game_api.current_remote_player.lock().unwrap().take(); + result + } + } + + impl PluginApi for Plugin { + fn new_instance(&mut self, item_type: ItemType, item_id: ItemInstanceId) { + self.wasm_plugin + .call_function_with_argument("new_instance", &(item_type, item_id)) + .unwrap() + } + + fn destroy_instance(&mut self, item_id: ItemInstanceId) { + self.wasm_plugin + .call_function_with_argument("destroy_instance", &item_id) + .unwrap() + } + + fn uses_remaining(&mut self, item_id: ItemInstanceId) -> Option<(u32, u32)> { + self.wasm_plugin + .call_function_with_argument("uses_remaining", &item_id) + .unwrap() + } + + fn update_shoot(&mut self, item_id: ItemInstanceId, time: f64) -> bool { + self.wasm_plugin + .call_function_with_argument("update_shoot", &(item_id, time)) + .unwrap() + } + + fn update_remote_shoot(&mut self, item_id: ItemInstanceId, time: f64) -> bool { + self.wasm_plugin + .call_function_with_argument("update_remote_shoot", &(item_id, time)) + .unwrap() + } + } +} + +#[cfg(target_arch = "wasm32")] +mod wasm_host { + use super::*; + use core_plugin::{ + destroy_instance, new_instance, plugin_description, update_remote_shoot, update_shoot, + uses_remaining, + }; + + pub struct Plugin { + pub game_api: HostGameApi, + } + + impl Plugin { + pub fn with_current_player( + &mut self, + player: Handle, + mut f: impl FnMut(&mut Plugin) -> R, + ) -> R { + self.game_api.current_player.lock().unwrap().replace(player); + let result = f(self); + self.game_api.current_player.lock().unwrap().take(); + result + } + + pub fn with_current_remote_player( + &mut self, + player: Handle, + mut f: impl FnMut(&mut Plugin) -> R, + ) -> R { + self.game_api + .current_remote_player + .lock() + .unwrap() + .replace(player); + let result = f(self); + self.game_api.current_remote_player.lock().unwrap().take(); + result + } + } + + impl PluginApi for Plugin { + fn new_instance(&mut self, item_type: ItemType, item_id: ItemInstanceId) { + new_instance(item_type, item_id); + } + + fn destroy_instance(&mut self, item_id: ItemInstanceId) { + destroy_instance(item_id); + } + + fn uses_remaining(&mut self, item_id: ItemInstanceId) -> Option<(u32, u32)> { + uses_remaining(item_id) + } + + fn update_shoot(&mut self, item_id: ItemInstanceId, time: f64) -> bool { + update_shoot(item_id, time, &self.game_api) + } + + fn update_remote_shoot(&mut self, item_id: ItemInstanceId, time: f64) -> bool { + update_remote_shoot(item_id, time, &self.game_api) + } + } + + pub struct PluginRegistry; + impl PluginRegistry { + pub async fn load( + _path: impl AsRef, + _item_registry: &mut ItemImplementationRegistry, + ) -> Self { + PluginRegistry + } + pub(crate) fn get_plugin(&mut self, plugin_id: PluginId) -> Option<&mut Plugin> { + None + } + } +}