diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8ccb294 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# Generated by Cargo +target/ +**/target/ + +# These are backup files generated by rustfmt +**/*.rs.bk + +# OS and Editor metadata +.DS_Store +.vscode/ +.idea/ +*.swp +*.swo + +# Compiled Wasm artifacts (if copied outside target/) +*.wasm + +# Logs +*.log diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 8f4b661..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,570 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "anyhow" -version = "1.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" - -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - -[[package]] -name = "bitflags" -version = "2.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "custom-command" -version = "0.1.0" -dependencies = [ - "pumpkin-plugin-api", - "tracing", -] - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "event-listener" -version = "0.1.0" -dependencies = [ - "pumpkin-plugin-api", - "tracing", -] - -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" -dependencies = [ - "foldhash", -] - -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin", - "stable_deref_trait", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hello-world" -version = "0.1.0" -dependencies = [ - "pumpkin-plugin-api", - "tracing", -] - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "indexmap" -version = "2.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" -dependencies = [ - "equivalent", - "hashbrown", - "serde", - "serde_core", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" - -[[package]] -name = "memchr" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "postcard" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "serde", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.119", -] - -[[package]] -name = "proc-macro2" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pumpkin-plugin-api" -version = "0.1.0-dev+26.2-26.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09559c59b3c594994856d81a4101b6b10be3843542b191bb1d0a4fff19058888" -dependencies = [ - "postcard", - "serde_json", - "tracing", - "tracing-serde-structured", - "wit-bindgen", -] - -[[package]] -name = "quote" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" - -[[package]] -name = "serde" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.5", -] - -[[package]] -name = "serde_json" -version = "1.0.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "spin" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spleef" -version = "0.1.0" -dependencies = [ - "pumpkin-plugin-api", - "tracing", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "sumo" -version = "0.1.0" -dependencies = [ - "pumpkin-plugin-api", - "tracing", -] - -[[package]] -name = "syn" -version = "2.0.119" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "3.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "2.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.5", -] - -[[package]] -name = "tnt-run" -version = "0.1.0" -dependencies = [ - "pumpkin-plugin-api", - "tracing", -] - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-serde-structured" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0832510e9838a4ff7e45e278602ab0533686f9507bc6189e024e488602f29820" -dependencies = [ - "hash32", - "heapless", - "serde", - "tracing-core", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "wasm-encoder" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e974fe6821a8cf64575d51ea2194e2c8f77e7b66e9afe7419ce8a97f9ee0d251" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a11585adb92fe9b55ad1d760e8d8fb5d87e0d2e303cb8eed57f078d54293a2" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a61719f93a87b16d325921e251800c4833f8fab50fa21c7de73aed50086313" -dependencies = [ - "bitflags", - "hashbrown", - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e473fd0095479f9689ac7d2a52c427cc96bb2b973ace50238dfcc1ab1cd52d93" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87445680dfe6d6b5369e884bd63c03a3335268e855365b2fc3f7bcdce96a630e" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f2fe494de0d898216caf0fd0ae76af75753fcb3ff4f465b46131537cf24cf8" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn 2.0.119", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59283a01aec94f60f92ada22ffe182a5cea8acfce43be3be688de8d52df55312" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.119", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "481b5c47b2ecce0389b5e08a05557d6a190c9cd761773b8880a8017ee04dc7ef" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4daaa3cd97ae49ecd0a99dc009d453f93e0f083dd3be38c0f24a83a93e37ac" -dependencies = [ - "anyhow", - "hashbrown", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-ident", - "wasmparser", -] - -[[package]] -name = "zmij" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 3c2646c..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[workspace] -resolver = "2" -members = [ - "basics/*", - "minigames/*", -] diff --git a/basics/01-hello-world/Cargo.lock b/basics/01-hello-world/Cargo.lock deleted file mode 100644 index 0ace098..0000000 --- a/basics/01-hello-world/Cargo.lock +++ /dev/null @@ -1,530 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "anyhow" -version = "1.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" - -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - -[[package]] -name = "bitflags" -version = "2.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" -dependencies = [ - "foldhash", -] - -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin", - "stable_deref_trait", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hello-world" -version = "0.1.0" -dependencies = [ - "pumpkin-plugin-api", - "tracing", -] - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "indexmap" -version = "2.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" -dependencies = [ - "equivalent", - "hashbrown", - "serde", - "serde_core", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" - -[[package]] -name = "memchr" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "postcard" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "serde", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.119", -] - -[[package]] -name = "proc-macro2" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pumpkin-plugin-api" -version = "0.1.0-dev+26.2-26.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09559c59b3c594994856d81a4101b6b10be3843542b191bb1d0a4fff19058888" -dependencies = [ - "postcard", - "serde_json", - "tracing", - "tracing-serde-structured", - "wit-bindgen", -] - -[[package]] -name = "quote" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" - -[[package]] -name = "serde" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.5", -] - -[[package]] -name = "serde_json" -version = "1.0.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "spin" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "syn" -version = "2.0.119" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "3.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "2.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.5", -] - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-serde-structured" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0832510e9838a4ff7e45e278602ab0533686f9507bc6189e024e488602f29820" -dependencies = [ - "hash32", - "heapless", - "serde", - "tracing-core", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "wasm-encoder" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e974fe6821a8cf64575d51ea2194e2c8f77e7b66e9afe7419ce8a97f9ee0d251" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a11585adb92fe9b55ad1d760e8d8fb5d87e0d2e303cb8eed57f078d54293a2" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a61719f93a87b16d325921e251800c4833f8fab50fa21c7de73aed50086313" -dependencies = [ - "bitflags", - "hashbrown", - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e473fd0095479f9689ac7d2a52c427cc96bb2b973ace50238dfcc1ab1cd52d93" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87445680dfe6d6b5369e884bd63c03a3335268e855365b2fc3f7bcdce96a630e" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f2fe494de0d898216caf0fd0ae76af75753fcb3ff4f465b46131537cf24cf8" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn 2.0.119", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59283a01aec94f60f92ada22ffe182a5cea8acfce43be3be688de8d52df55312" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.119", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "481b5c47b2ecce0389b5e08a05557d6a190c9cd761773b8880a8017ee04dc7ef" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4daaa3cd97ae49ecd0a99dc009d453f93e0f083dd3be38c0f24a83a93e37ac" -dependencies = [ - "anyhow", - "hashbrown", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-ident", - "wasmparser", -] - -[[package]] -name = "zmij" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/basics/01-hello-world/Cargo.toml b/basics/01-hello-world/Cargo.toml deleted file mode 100644 index 9579420..0000000 --- a/basics/01-hello-world/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "hello-world" -version = "0.1.0" -edition = "2024" -authors = ["Pumpkin Developer"] -description = "A minimal hello-world plugin example for the Pumpkin Minecraft server" -license = "MIT OR Apache-2.0" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -pumpkin-plugin-api = "0.1.0-dev" -tracing = "0.1" diff --git a/basics/01-hello-world/src/lib.rs b/basics/01-hello-world/src/lib.rs deleted file mode 100644 index 3c6e6f0..0000000 --- a/basics/01-hello-world/src/lib.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! # 01 - Hello World Plugin Example for Pumpkin -//! -//! This is the simplest possible Pumpkin plugin. It demonstrates: -//! - Defining a plugin struct and implementing the [`Plugin`] trait. -//! - Setting up metadata (name, version, authors, permissions). -//! - Handling the [`on_load`] and [`on_unload`] lifecycle callbacks. -//! - Logging using the `tracing` crate, which connects to Pumpkin's server log system. -//! - Registering the plugin with the [`register_plugin!`] macro. - -use pumpkin_plugin_api::{ - Context, Plugin, PluginMetadata, permissions, register_plugin, -}; - -/// The main plugin state struct. -pub struct HelloWorldPlugin; - -impl Plugin for HelloWorldPlugin { - /// Constructs a new instance of the plugin. - /// - /// Called once by the runtime before [`on_load`](Plugin::on_load). - fn new() -> Self { - HelloWorldPlugin - } - - /// Provides metadata describing this plugin to the Pumpkin server. - fn metadata(&self) -> PluginMetadata { - PluginMetadata { - name: "hello-world".into(), - version: env!("CARGO_PKG_VERSION").into(), - authors: vec!["Pumpkin Developer".into()], - description: "A minimal Hello World plugin for Pumpkin Minecraft server.".into(), - dependencies: vec![], - permissions: vec![permissions::FS_READ_DATA.into()], - } - } - - /// Invoked when the server loads and enables the plugin. - fn on_load(&self, context: Context) -> Result<(), String> { - tracing::info!("Hello, world from Pumpkin plugin!"); - tracing::info!("Plugin private data directory: {}", context.get_data_folder()); - Ok(()) - } - - /// Invoked when the server unloads or stops the plugin. - fn on_unload(&self, _context: Context) -> Result<(), String> { - tracing::info!("Goodbye from Hello World plugin!"); - Ok(()) - } -} - -// Register HelloWorldPlugin as the entrypoint for the WebAssembly component. -register_plugin!(HelloWorldPlugin); diff --git a/basics/02-custom-command/Cargo.lock b/basics/02-custom-command/Cargo.lock deleted file mode 100644 index 79d9b42..0000000 --- a/basics/02-custom-command/Cargo.lock +++ /dev/null @@ -1,530 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "anyhow" -version = "1.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" - -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - -[[package]] -name = "bitflags" -version = "2.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "custom-command" -version = "0.1.0" -dependencies = [ - "pumpkin-plugin-api", - "tracing", -] - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" -dependencies = [ - "foldhash", -] - -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin", - "stable_deref_trait", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "indexmap" -version = "2.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" -dependencies = [ - "equivalent", - "hashbrown", - "serde", - "serde_core", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" - -[[package]] -name = "memchr" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "postcard" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "serde", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.119", -] - -[[package]] -name = "proc-macro2" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pumpkin-plugin-api" -version = "0.1.0-dev+26.2-26.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09559c59b3c594994856d81a4101b6b10be3843542b191bb1d0a4fff19058888" -dependencies = [ - "postcard", - "serde_json", - "tracing", - "tracing-serde-structured", - "wit-bindgen", -] - -[[package]] -name = "quote" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" - -[[package]] -name = "serde" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.5", -] - -[[package]] -name = "serde_json" -version = "1.0.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "spin" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "syn" -version = "2.0.119" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "3.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "2.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.5", -] - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-serde-structured" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0832510e9838a4ff7e45e278602ab0533686f9507bc6189e024e488602f29820" -dependencies = [ - "hash32", - "heapless", - "serde", - "tracing-core", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "wasm-encoder" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e974fe6821a8cf64575d51ea2194e2c8f77e7b66e9afe7419ce8a97f9ee0d251" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a11585adb92fe9b55ad1d760e8d8fb5d87e0d2e303cb8eed57f078d54293a2" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a61719f93a87b16d325921e251800c4833f8fab50fa21c7de73aed50086313" -dependencies = [ - "bitflags", - "hashbrown", - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e473fd0095479f9689ac7d2a52c427cc96bb2b973ace50238dfcc1ab1cd52d93" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87445680dfe6d6b5369e884bd63c03a3335268e855365b2fc3f7bcdce96a630e" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f2fe494de0d898216caf0fd0ae76af75753fcb3ff4f465b46131537cf24cf8" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn 2.0.119", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59283a01aec94f60f92ada22ffe182a5cea8acfce43be3be688de8d52df55312" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.119", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "481b5c47b2ecce0389b5e08a05557d6a190c9cd761773b8880a8017ee04dc7ef" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4daaa3cd97ae49ecd0a99dc009d453f93e0f083dd3be38c0f24a83a93e37ac" -dependencies = [ - "anyhow", - "hashbrown", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-ident", - "wasmparser", -] - -[[package]] -name = "zmij" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/basics/02-custom-command/Cargo.toml b/basics/02-custom-command/Cargo.toml deleted file mode 100644 index 826bb7b..0000000 --- a/basics/02-custom-command/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "custom-command" -version = "0.1.0" -edition = "2024" -authors = ["Pumpkin Developer"] -description = "A custom command plugin example for the Pumpkin Minecraft server" -license = "MIT OR Apache-2.0" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -pumpkin-plugin-api = "0.1.0-dev" -tracing = "0.1" diff --git a/basics/02-custom-command/src/lib.rs b/basics/02-custom-command/src/lib.rs deleted file mode 100644 index 70d32ad..0000000 --- a/basics/02-custom-command/src/lib.rs +++ /dev/null @@ -1,138 +0,0 @@ -//! # 02 - Custom Command Plugin Example for Pumpkin -//! -//! Demonstrates: -//! - Building and registering custom Minecraft commands using the Pumpkin Plugin API. -//! - Setting up subcommands with [`CommandNode::literal`]. -//! - Defining typed arguments with [`CommandNode::argument`] and [`ArgumentType`]. -//! - Implementing [`CommandHandler`] to handle command execution. -//! - Extracting consumed arguments from [`ConsumedArgs`]. -//! - Sending feedback messages back to the [`CommandSender`]. -//! - Accessing server methods from [`Server`]. - -use pumpkin_plugin_api::{ - command::{ - Arg, ArgumentType, Command, CommandError, CommandNode, CommandSender, ConsumedArgs, - StringType, - }, - commands::CommandHandler, - Context, Plugin, PluginMetadata, register_plugin, Server, - text::TextComponent, -}; - -/// Handler for the root `/greet` command. -struct GreetRootHandler; - -impl CommandHandler for GreetRootHandler { - fn handle( - &self, - sender: CommandSender, - _server: Server, - _args: ConsumedArgs, - ) -> Result { - let sender_name = sender.get_name(); - let message = format!("Hello, {sender_name}! Welcome to Pumpkin!"); - sender.send_message(TextComponent::text(&message)); - Ok(0) - } -} - -/// Handler for `/greet broadcast `. -struct GreetBroadcastHandler; - -impl CommandHandler for GreetBroadcastHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - args: ConsumedArgs, - ) -> Result { - let message = match args.get_value("message") { - Arg::Simple(s) | Arg::Msg(s) => s, - _ => "Hello everyone!".to_string(), - }; - - let sender_name = sender.get_name(); - let broadcast_text = format!("[Broadcast by {sender_name}] {message}"); - server.broadcast(&broadcast_text); - - sender.send_message(TextComponent::text("Broadcast sent to all online players!")); - Ok(0) - } -} - -/// Handler for `/greet stats`. -struct GreetStatsHandler; - -impl CommandHandler for GreetStatsHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let tps = server.get_tps(); - let mspt = server.get_mspt(); - let player_count = server.get_player_count(); - let max_players = server.get_max_players(); - - let stats_info = format!( - "Server Stats:\n - TPS: {:.2}\n - MSPT: {:.2}ms\n - Players: {}/{}", - tps, mspt, player_count, max_players - ); - - sender.send_message(TextComponent::text(&stats_info)); - Ok(0) - } -} - -/// Main plugin struct for custom command example. -pub struct CustomCommandPlugin; - -impl Plugin for CustomCommandPlugin { - fn new() -> Self { - CustomCommandPlugin - } - - fn metadata(&self) -> PluginMetadata { - PluginMetadata { - name: "custom-command".into(), - version: env!("CARGO_PKG_VERSION").into(), - authors: vec!["Pumpkin Developer".into()], - description: "A custom command example for the Pumpkin Minecraft server.".into(), - dependencies: vec![], - permissions: vec![], - } - } - - fn on_load(&self, context: Context) -> Result<(), String> { - let names = ["greet".to_string(), "greeting".to_string()]; - - // Build command tree: - // /greet - // /greet broadcast - // /greet stats - let command = Command::new(&names, "A friendly greeting and server stats command") - .then( - CommandNode::literal("broadcast").then( - CommandNode::argument("message", &ArgumentType::String(StringType::Greedy)) - .execute(GreetBroadcastHandler), - ), - ) - .then( - CommandNode::literal("stats").execute(GreetStatsHandler), - ) - .execute(GreetRootHandler); - - context.register_command(command, "pumpkin.command.greet"); - tracing::info!("Registered /greet command with aliases and subcommands!"); - - Ok(()) - } - - fn on_unload(&self, _context: Context) -> Result<(), String> { - tracing::info!("Unloaded custom command plugin!"); - Ok(()) - } -} - -register_plugin!(CustomCommandPlugin); diff --git a/basics/03-event-listener/Cargo.lock b/basics/03-event-listener/Cargo.lock deleted file mode 100644 index 468d343..0000000 --- a/basics/03-event-listener/Cargo.lock +++ /dev/null @@ -1,530 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "anyhow" -version = "1.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" - -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - -[[package]] -name = "bitflags" -version = "2.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "event-listener" -version = "0.1.0" -dependencies = [ - "pumpkin-plugin-api", - "tracing", -] - -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" -dependencies = [ - "foldhash", -] - -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin", - "stable_deref_trait", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "indexmap" -version = "2.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" -dependencies = [ - "equivalent", - "hashbrown", - "serde", - "serde_core", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" - -[[package]] -name = "memchr" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "postcard" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "serde", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.119", -] - -[[package]] -name = "proc-macro2" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pumpkin-plugin-api" -version = "0.1.0-dev+26.2-26.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09559c59b3c594994856d81a4101b6b10be3843542b191bb1d0a4fff19058888" -dependencies = [ - "postcard", - "serde_json", - "tracing", - "tracing-serde-structured", - "wit-bindgen", -] - -[[package]] -name = "quote" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" - -[[package]] -name = "serde" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.5", -] - -[[package]] -name = "serde_json" -version = "1.0.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "spin" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "syn" -version = "2.0.119" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "3.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "2.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.5", -] - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-serde-structured" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0832510e9838a4ff7e45e278602ab0533686f9507bc6189e024e488602f29820" -dependencies = [ - "hash32", - "heapless", - "serde", - "tracing-core", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "wasm-encoder" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e974fe6821a8cf64575d51ea2194e2c8f77e7b66e9afe7419ce8a97f9ee0d251" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a11585adb92fe9b55ad1d760e8d8fb5d87e0d2e303cb8eed57f078d54293a2" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a61719f93a87b16d325921e251800c4833f8fab50fa21c7de73aed50086313" -dependencies = [ - "bitflags", - "hashbrown", - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e473fd0095479f9689ac7d2a52c427cc96bb2b973ace50238dfcc1ab1cd52d93" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87445680dfe6d6b5369e884bd63c03a3335268e855365b2fc3f7bcdce96a630e" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f2fe494de0d898216caf0fd0ae76af75753fcb3ff4f465b46131537cf24cf8" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn 2.0.119", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59283a01aec94f60f92ada22ffe182a5cea8acfce43be3be688de8d52df55312" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.119", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "481b5c47b2ecce0389b5e08a05557d6a190c9cd761773b8880a8017ee04dc7ef" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.258.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4daaa3cd97ae49ecd0a99dc009d453f93e0f083dd3be38c0f24a83a93e37ac" -dependencies = [ - "anyhow", - "hashbrown", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-ident", - "wasmparser", -] - -[[package]] -name = "zmij" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/basics/03-event-listener/Cargo.toml b/basics/03-event-listener/Cargo.toml deleted file mode 100644 index 44d25ed..0000000 --- a/basics/03-event-listener/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "event-listener" -version = "0.1.0" -edition = "2024" -authors = ["Pumpkin Developer"] -description = "An event listener plugin example for the Pumpkin Minecraft server" -license = "MIT OR Apache-2.0" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -pumpkin-plugin-api = "0.1.0-dev" -tracing = "0.1" diff --git a/basics/03-event-listener/src/lib.rs b/basics/03-event-listener/src/lib.rs deleted file mode 100644 index 7534b9e..0000000 --- a/basics/03-event-listener/src/lib.rs +++ /dev/null @@ -1,140 +0,0 @@ -//! # 03 - Event Listener Plugin Example for Pumpkin -//! -//! Demonstrates: -//! - Subscribing to Pumpkin server events using [`EventHandler`]. -//! - Registering listeners with [`Context::register_event_handler`]. -//! - Setting [`EventPriority`] and configuring blocking vs non-blocking handlers. -//! - Handling player join and leave lifecycle events ([`PlayerJoinEvent`], [`PlayerLeaveEvent`]). -//! - Interacting with players (custom messages, titles, action bar). -//! - Handling block events ([`BlockBreakEvent`]) and cancelling events (`cancelled = true`) to protect blocks. - -use pumpkin_plugin_api::{ - events::{ - EventHandler, EventPriority, - block::BlockBreakEvent, - player::{PlayerJoinEvent, PlayerLeaveEvent}, - }, - events_wit::{BlockBreakEventData, PlayerJoinEventData, PlayerLeaveEventData}, - Context, Plugin, PluginMetadata, register_plugin, Server, - text::TextComponent, -}; - -/// Listens for players joining the server. -struct JoinListener; - -impl EventHandler for JoinListener { - fn handle(&self, _server: Server, event: PlayerJoinEventData) -> PlayerJoinEventData { - let name = event.player.get_name(); - tracing::info!("Player joined the game: {name}"); - - // Send a private chat message to the player - event.player.send_system_message( - TextComponent::text(&format!("Welcome to the server, {name}!")), - false, - ); - - // Show a welcoming title screen to the player - event - .player - .show_title(TextComponent::text("Welcome to Pumpkin!")); - event - .player - .show_subtitle(TextComponent::text("Have fun building and exploring!")); - - event - } -} - -/// Listens for players leaving the server. -struct LeaveListener; - -impl EventHandler for LeaveListener { - fn handle(&self, _server: Server, event: PlayerLeaveEventData) -> PlayerLeaveEventData { - let name = event.player.get_name(); - tracing::info!("Player left the game: {name}"); - event - } -} - -/// Listens for block breaking events and demonstrates event cancellation. -struct BlockBreakListener; - -impl EventHandler for BlockBreakListener { - fn handle(&self, _server: Server, mut event: BlockBreakEventData) -> BlockBreakEventData { - let block_name = &event.block; - let pos = &event.block_pos; - - tracing::info!( - "Block broken: {block_name} at X:{} Y:{} Z:{}", - pos.x, pos.y, pos.z - ); - - // Example: Protect bedrock and barrier blocks from being broken - if block_name.contains("bedrock") || block_name.contains("barrier") { - tracing::warn!("Cancelled breaking protected block '{block_name}' at ({}, {}, {})", pos.x, pos.y, pos.z); - event.cancelled = true; - - if let Some(player) = &event.player { - player.send_system_message( - TextComponent::text("You cannot break this protected block!"), - true, // overlay = true displays in the action bar - ); - } - } - - event - } -} - -/// Main plugin struct for the event listener example. -pub struct EventListenerPlugin; - -impl Plugin for EventListenerPlugin { - fn new() -> Self { - EventListenerPlugin - } - - fn metadata(&self) -> PluginMetadata { - PluginMetadata { - name: "event-listener".into(), - version: env!("CARGO_PKG_VERSION").into(), - authors: vec!["Pumpkin Developer".into()], - description: "An event listener example for the Pumpkin Minecraft server.".into(), - dependencies: vec![], - permissions: vec![], - } - } - - fn on_load(&self, context: Context) -> Result<(), String> { - // Register PlayerJoinEvent (non-blocking notification) - context.register_event_handler( - JoinListener, - EventPriority::Normal, - false, - )?; - - // Register PlayerLeaveEvent (non-blocking notification) - context.register_event_handler( - LeaveListener, - EventPriority::Normal, - false, - )?; - - // Register BlockBreakEvent (blocking = true allows event.cancelled to take effect) - context.register_event_handler( - BlockBreakListener, - EventPriority::High, - true, - )?; - - tracing::info!("Registered player join, player leave, and block break event handlers!"); - Ok(()) - } - - fn on_unload(&self, _context: Context) -> Result<(), String> { - tracing::info!("Unloaded event listener plugin!"); - Ok(()) - } -} - -register_plugin!(EventListenerPlugin); diff --git a/minigames/spleef/Cargo.toml b/minigames/spleef/Cargo.toml deleted file mode 100644 index 9571637..0000000 --- a/minigames/spleef/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "spleef" -version = "0.1.0" -edition = "2024" -authors = ["Pumpkin Developer"] -description = "A complete Spleef minigame for the Pumpkin Minecraft server" -license = "MIT OR Apache-2.0" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -pumpkin-plugin-api = "0.1.0-dev" -tracing = "0.1" diff --git a/minigames/spleef/src/lib.rs b/minigames/spleef/src/lib.rs deleted file mode 100644 index 17ab02f..0000000 --- a/minigames/spleef/src/lib.rs +++ /dev/null @@ -1,412 +0,0 @@ -//! # Spleef Minigame for Pumpkin -//! -//! A complete, runnable Spleef minigame showcasing: -//! - State management (`Waiting`, `Active`, `Ended`). -//! - Commands: `/spleef join`, `/spleef leave`, `/spleef start`, `/spleef status`, `/spleef reset`. -//! - [`BlockBreakEvent`]: -//! - Allows breaking snow blocks inside the active arena. -//! - Protects blocks outside the arena boundary or before the game starts. -//! - [`PlayerMoveEvent`]: -//! - Detects players falling below the snow platform into the elimination zone. -//! - Automatic win condition check (last player standing). -//! - Arena regeneration (`/spleef reset`). - -use std::{ - collections::HashSet, - sync::{Arc, Mutex}, -}; - -use pumpkin_plugin_api::{ - command::{Command, CommandError, CommandNode, CommandSender, ConsumedArgs}, - commands::CommandHandler, - common::{BlockPos, Position}, - events::{ - EventHandler, EventPriority, - block::BlockBreakEvent, - player::PlayerMoveEvent, - }, - events_wit::{BlockBreakEventData, PlayerMoveEventData}, - world::BlockFlags, - Context, Plugin, PluginMetadata, register_plugin, Server, - text::TextComponent, -}; - -/// Spleef arena boundaries and platform heights. -#[derive(Clone, Debug)] -pub struct SpleefConfig { - pub min_x: i32, - pub max_x: i32, - pub min_z: i32, - pub max_z: i32, - pub floor_y: i32, - pub elimination_y: f64, - pub spawn_pos: Position, - pub lobby_pos: Position, -} - -impl Default for SpleefConfig { - fn default() -> Self { - Self { - min_x: -12, - max_x: 12, - min_z: -12, - max_z: 12, - floor_y: 100, - elimination_y: 92.0, - spawn_pos: (0.5, 101.0, 0.5), - lobby_pos: (0.5, 115.0, 0.5), - } - } -} - -impl SpleefConfig { - pub fn is_inside_floor(&self, x: i32, y: i32, z: i32) -> bool { - y == self.floor_y && x >= self.min_x && x <= self.max_x && z >= self.min_z && z <= self.max_z - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum GameState { - Waiting, - Active, - Ended, -} - -pub struct SpleefSession { - pub state: GameState, - pub config: SpleefConfig, - pub queued_players: HashSet, - pub alive_players: HashSet, -} - -impl SpleefSession { - pub fn new(config: SpleefConfig) -> Self { - Self { - state: GameState::Waiting, - config, - queued_players: HashSet::new(), - alive_players: HashSet::new(), - } - } -} - -static SESSION: Mutex>>> = Mutex::new(None); - -fn get_session() -> Arc> { - SESSION - .lock() - .unwrap_or_else(|e| e.into_inner()) - .clone() - .expect("SpleefSession must be initialized in on_load") -} - -// ----------------------------------------------------------------------------- -// Commands: /spleef -// ----------------------------------------------------------------------------- - -struct SpleefRootHandler; -impl CommandHandler for SpleefRootHandler { - fn handle( - &self, - sender: CommandSender, - _server: Server, - _args: ConsumedArgs, - ) -> Result { - let help_text = "Spleef Commands:\n\ - /spleef join - Join the game queue\n\ - /spleef leave - Leave the queue or game\n\ - /spleef start - Force start the game\n\ - /spleef status - View game status\n\ - /spleef reset - Regenerate snow arena floor"; - sender.send_message(TextComponent::text(help_text)); - Ok(0) - } -} - -struct SpleefJoinHandler; -impl CommandHandler for SpleefJoinHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let player_name = sender.get_name(); - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - match session.state { - GameState::Active => { - sender.send_message(TextComponent::text("Game is already in progress! Please wait.")); - } - GameState::Waiting | GameState::Ended => { - if session.queued_players.insert(player_name.clone()) { - let count = session.queued_players.len(); - server.broadcast(&format!("{player_name} joined Spleef! ({count} players queued)")); - sender.send_message(TextComponent::text("You joined the queue! Use /spleef start when ready.")); - } else { - sender.send_message(TextComponent::text("You are already in the queue!")); - } - } - } - Ok(0) - } -} - -struct SpleefLeaveHandler; -impl CommandHandler for SpleefLeaveHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let player_name = sender.get_name(); - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - if session.queued_players.remove(&player_name) || session.alive_players.remove(&player_name) { - server.broadcast(&format!("{player_name} left Spleef.")); - sender.send_message(TextComponent::text("You left Spleef.")); - } else { - sender.send_message(TextComponent::text("You are not currently in a Spleef game.")); - } - Ok(0) - } -} - -struct SpleefStartHandler; -impl CommandHandler for SpleefStartHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - if session.state == GameState::Active { - sender.send_message(TextComponent::text("Game is already running!")); - return Ok(0); - } - - if session.queued_players.is_empty() { - session.queued_players.insert(sender.get_name()); - } - - session.alive_players = session.queued_players.clone(); - session.state = GameState::Active; - - let count = session.alive_players.len(); - server.broadcast(&format!("Spleef has STARTED with {count} players! Spleef your opponents!")); - - let spawn = session.config.spawn_pos; - for player_name in &session.alive_players { - if let Some(player) = server.get_player_by_name(player_name) { - let world = player.get_world(); - player.teleport(spawn, Some(0.0), Some(0.0), world); - player.show_title(TextComponent::text("SPLEEF!")); - player.show_subtitle(TextComponent::text("Break blocks beneath your rivals!")); - } - } - - Ok(0) - } -} - -struct SpleefStatusHandler; -impl CommandHandler for SpleefStatusHandler { - fn handle( - &self, - sender: CommandSender, - _server: Server, - _args: ConsumedArgs, - ) -> Result { - let session_arc = get_session(); - let session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - let status_msg = match session.state { - GameState::Waiting => format!("Spleef: WAITING ({} queued)", session.queued_players.len()), - GameState::Active => format!( - "Spleef: ACTIVE ({} alive: {:?})", - session.alive_players.len(), - session.alive_players - ), - GameState::Ended => "Spleef: ENDED (Use /spleef reset or /spleef start)".to_string(), - }; - - sender.send_message(TextComponent::text(&status_msg)); - Ok(0) - } -} - -struct SpleefResetHandler; -impl CommandHandler for SpleefResetHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - session.state = GameState::Waiting; - session.alive_players.clear(); - - let worlds = server.get_all_worlds(); - if let Some(world) = worlds.first() { - let flags = BlockFlags::NOTIFY_LISTENERS | BlockFlags::NOTIFY_NEIGHBORS; - for x in session.config.min_x..=session.config.max_x { - for z in session.config.min_z..=session.config.max_z { - let pos = BlockPos { x, y: session.config.floor_y, z }; - world.set_block_by_name(pos, "minecraft:snow_block", flags); - } - } - } - - server.broadcast("Spleef arena has been regenerated and reset!"); - sender.send_message(TextComponent::text("Spleef reset complete!")); - Ok(0) - } -} - -// ----------------------------------------------------------------------------- -// Event Listeners: BlockBreakEvent & PlayerMoveEvent -// ----------------------------------------------------------------------------- - -struct SpleefBreakListener; - -impl EventHandler for SpleefBreakListener { - fn handle(&self, _server: Server, mut event: BlockBreakEventData) -> BlockBreakEventData { - let session_arc = get_session(); - let session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - let pos = &event.block_pos; - - // If the block broken is on the Spleef floor: - if session.config.is_inside_floor(pos.x, pos.y, pos.z) { - // Only allow breaking during Active state by alive players - if session.state == GameState::Active { - if let Some(player) = &event.player { - if session.alive_players.contains(&player.get_name()) { - event.should_drop = false; // Don't drop cluttering snowballs - event.cancelled = false; - return event; - } - } - } - // Disallow breaking floor before start or by spectators - event.cancelled = true; - } - - event - } -} - -struct SpleefMoveListener; - -impl EventHandler for SpleefMoveListener { - fn handle(&self, server: Server, event: PlayerMoveEventData) -> PlayerMoveEventData { - let player_name = event.player.get_name(); - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - if session.state != GameState::Active || !session.alive_players.contains(&player_name) { - return event; - } - - let to = &event.to_position; - - // Elimination Check: player fell below elimination threshold - if to.1 < session.config.elimination_y { - session.alive_players.remove(&player_name); - server.broadcast(&format!("{player_name} was SPLEEFED and eliminated!")); - - let lobby = session.config.lobby_pos; - let world = event.player.get_world(); - event.player.teleport(lobby, Some(0.0), Some(0.0), world); - event.player.show_title(TextComponent::text("SPLEEFED!")); - - if session.alive_players.len() == 1 { - let winner_name = session.alive_players.iter().next().cloned().unwrap(); - server.broadcast(&format!("VICTORY! {winner_name} is the last player standing and WINS Spleef!")); - if let Some(winner) = server.get_player_by_name(&winner_name) { - winner.show_title(TextComponent::text("VICTORY!")); - winner.show_subtitle(TextComponent::text("You won Spleef!")); - } - session.state = GameState::Ended; - } else if session.alive_players.is_empty() { - server.broadcast("Game Over! No players remaining."); - session.state = GameState::Ended; - } - } - - event - } -} - -// ----------------------------------------------------------------------------- -// Plugin Lifecycle -// ----------------------------------------------------------------------------- - -pub struct SpleefPlugin; - -impl Plugin for SpleefPlugin { - fn new() -> Self { - SpleefPlugin - } - - fn metadata(&self) -> PluginMetadata { - PluginMetadata { - name: "spleef".into(), - version: env!("CARGO_PKG_VERSION").into(), - authors: vec!["Pumpkin Developer".into()], - description: "A complete Spleef minigame for Pumpkin Minecraft server.".into(), - dependencies: vec![], - permissions: vec![], - } - } - - fn on_load(&self, context: Context) -> Result<(), String> { - let config = SpleefConfig::default(); - let session = Arc::new(Mutex::new(SpleefSession::new(config))); - *SESSION.lock().unwrap_or_else(|e| e.into_inner()) = Some(session); - - let names = ["spleef".to_string(), "sp".to_string()]; - let command = Command::new(&names, "Spleef minigame management command") - .then(CommandNode::literal("join").execute(SpleefJoinHandler)) - .then(CommandNode::literal("leave").execute(SpleefLeaveHandler)) - .then(CommandNode::literal("start").execute(SpleefStartHandler)) - .then(CommandNode::literal("status").execute(SpleefStatusHandler)) - .then(CommandNode::literal("reset").execute(SpleefResetHandler)) - .execute(SpleefRootHandler); - - context.register_command(command, "pumpkin.command.spleef"); - - // Register BlockBreakEvent (blocking = true to allow/cancel break) - context.register_event_handler( - SpleefBreakListener, - EventPriority::High, - true, - )?; - - // Register PlayerMoveEvent for void detection - context.register_event_handler( - SpleefMoveListener, - EventPriority::Normal, - false, - )?; - - tracing::info!("Spleef minigame plugin successfully loaded!"); - Ok(()) - } - - fn on_unload(&self, _context: Context) -> Result<(), String> { - tracing::info!("Spleef plugin unloaded."); - Ok(()) - } -} - -register_plugin!(SpleefPlugin); diff --git a/minigames/sumo/Cargo.toml b/minigames/sumo/Cargo.toml deleted file mode 100644 index 8c75c1f..0000000 --- a/minigames/sumo/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "sumo" -version = "0.1.0" -edition = "2024" -authors = ["Pumpkin Developer"] -description = "A complete Sumo minigame for the Pumpkin Minecraft server" -license = "MIT OR Apache-2.0" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -pumpkin-plugin-api = "0.1.0-dev" -tracing = "0.1" diff --git a/minigames/sumo/src/lib.rs b/minigames/sumo/src/lib.rs deleted file mode 100644 index f0dbff7..0000000 --- a/minigames/sumo/src/lib.rs +++ /dev/null @@ -1,408 +0,0 @@ -//! # Sumo Minigame for Pumpkin -//! -//! A complete, runnable Sumo PvP minigame showcasing: -//! - State management (`Waiting`, `Active`, `Ended`). -//! - Commands: `/sumo join`, `/sumo leave`, `/sumo start`, `/sumo status`, `/sumo reset`. -//! - Arena protection: cancels all block breaking on the Sumo ring via [`BlockBreakEvent`]. -//! - Ring-out elimination: monitors [`PlayerMoveEvent`] to detect when a player is knocked off. -//! - Automatic win condition check (last player remaining on the platform). -//! - Platform regeneration (`/sumo reset`). - -use std::{ - collections::HashSet, - sync::{Arc, Mutex}, -}; - -use pumpkin_plugin_api::{ - command::{Command, CommandError, CommandNode, CommandSender, ConsumedArgs}, - commands::CommandHandler, - common::{BlockPos, Position}, - events::{ - EventHandler, EventPriority, - block::BlockBreakEvent, - player::PlayerMoveEvent, - }, - events_wit::{BlockBreakEventData, PlayerMoveEventData}, - world::BlockFlags, - Context, Plugin, PluginMetadata, register_plugin, Server, - text::TextComponent, -}; - -/// Sumo ring boundaries and platform coordinates. -#[derive(Clone, Debug)] -pub struct SumoConfig { - pub min_x: i32, - pub max_x: i32, - pub min_z: i32, - pub max_z: i32, - pub platform_y: i32, - pub elimination_y: f64, - pub spawn_pos_1: Position, - pub spawn_pos_2: Position, - pub lobby_pos: Position, -} - -impl Default for SumoConfig { - fn default() -> Self { - Self { - min_x: -6, - max_x: 6, - min_z: -6, - max_z: 6, - platform_y: 100, - elimination_y: 95.0, - spawn_pos_1: (-3.5, 101.0, 0.5), - spawn_pos_2: (3.5, 101.0, 0.5), - lobby_pos: (0.5, 115.0, 0.5), - } - } -} - -impl SumoConfig { - pub fn is_inside_platform(&self, x: i32, y: i32, z: i32) -> bool { - y == self.platform_y && x >= self.min_x && x <= self.max_x && z >= self.min_z && z <= self.max_z - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum GameState { - Waiting, - Active, - Ended, -} - -pub struct SumoSession { - pub state: GameState, - pub config: SumoConfig, - pub queued_players: HashSet, - pub alive_players: HashSet, -} - -impl SumoSession { - pub fn new(config: SumoConfig) -> Self { - Self { - state: GameState::Waiting, - config, - queued_players: HashSet::new(), - alive_players: HashSet::new(), - } - } -} - -static SESSION: Mutex>>> = Mutex::new(None); - -fn get_session() -> Arc> { - SESSION - .lock() - .unwrap_or_else(|e| e.into_inner()) - .clone() - .expect("SumoSession must be initialized in on_load") -} - -// ----------------------------------------------------------------------------- -// Commands: /sumo -// ----------------------------------------------------------------------------- - -struct SumoRootHandler; -impl CommandHandler for SumoRootHandler { - fn handle( - &self, - sender: CommandSender, - _server: Server, - _args: ConsumedArgs, - ) -> Result { - let help_text = "Sumo Commands:\n\ - /sumo join - Join the Sumo queue\n\ - /sumo leave - Leave the queue or game\n\ - /sumo start - Force start the duel\n\ - /sumo status - View game status\n\ - /sumo reset - Regenerate arena ring"; - sender.send_message(TextComponent::text(help_text)); - Ok(0) - } -} - -struct SumoJoinHandler; -impl CommandHandler for SumoJoinHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let player_name = sender.get_name(); - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - match session.state { - GameState::Active => { - sender.send_message(TextComponent::text("A Sumo round is currently active! Please wait.")); - } - GameState::Waiting | GameState::Ended => { - if session.queued_players.insert(player_name.clone()) { - let count = session.queued_players.len(); - server.broadcast(&format!("{player_name} joined Sumo! ({count} fighters queued)")); - sender.send_message(TextComponent::text("You joined the queue! Use /sumo start when ready.")); - } else { - sender.send_message(TextComponent::text("You are already in the queue!")); - } - } - } - Ok(0) - } -} - -struct SumoLeaveHandler; -impl CommandHandler for SumoLeaveHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let player_name = sender.get_name(); - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - if session.queued_players.remove(&player_name) || session.alive_players.remove(&player_name) { - server.broadcast(&format!("{player_name} left Sumo.")); - sender.send_message(TextComponent::text("You left Sumo.")); - } else { - sender.send_message(TextComponent::text("You are not currently in a Sumo game.")); - } - Ok(0) - } -} - -struct SumoStartHandler; -impl CommandHandler for SumoStartHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - if session.state == GameState::Active { - sender.send_message(TextComponent::text("Sumo match is already running!")); - return Ok(0); - } - - if session.queued_players.is_empty() { - session.queued_players.insert(sender.get_name()); - } - - session.alive_players = session.queued_players.clone(); - session.state = GameState::Active; - - let count = session.alive_players.len(); - server.broadcast(&format!("Sumo duel has STARTED with {count} fighters! Knock your opponents off the ring!")); - - // Alternate spawn positions for players facing each other - let spawns = [session.config.spawn_pos_1, session.config.spawn_pos_2]; - for (idx, player_name) in session.alive_players.iter().enumerate() { - if let Some(player) = server.get_player_by_name(player_name) { - let world = player.get_world(); - let spawn = spawns[idx % spawns.len()]; - player.teleport(spawn, Some(0.0), Some(0.0), world); - player.show_title(TextComponent::text("SUMO!")); - player.show_subtitle(TextComponent::text("Knock the other players off the ring!")); - } - } - - Ok(0) - } -} - -struct SumoStatusHandler; -impl CommandHandler for SumoStatusHandler { - fn handle( - &self, - sender: CommandSender, - _server: Server, - _args: ConsumedArgs, - ) -> Result { - let session_arc = get_session(); - let session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - let status_msg = match session.state { - GameState::Waiting => format!("Sumo: WAITING ({} fighters queued)", session.queued_players.len()), - GameState::Active => format!( - "Sumo: ACTIVE ({} fighters on ring: {:?})", - session.alive_players.len(), - session.alive_players - ), - GameState::Ended => "Sumo: ENDED (Use /sumo reset or /sumo start)".to_string(), - }; - - sender.send_message(TextComponent::text(&status_msg)); - Ok(0) - } -} - -struct SumoResetHandler; -impl CommandHandler for SumoResetHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - session.state = GameState::Waiting; - session.alive_players.clear(); - - let worlds = server.get_all_worlds(); - if let Some(world) = worlds.first() { - let flags = BlockFlags::NOTIFY_LISTENERS | BlockFlags::NOTIFY_NEIGHBORS; - for x in session.config.min_x..=session.config.max_x { - for z in session.config.min_z..=session.config.max_z { - let pos = BlockPos { x, y: session.config.platform_y, z }; - world.set_block_by_name(pos, "minecraft:smooth_stone", flags); - } - } - } - - server.broadcast("Sumo ring has been regenerated and reset!"); - sender.send_message(TextComponent::text("Sumo reset complete!")); - Ok(0) - } -} - -// ----------------------------------------------------------------------------- -// Event Listeners: BlockBreakEvent & PlayerMoveEvent -// ----------------------------------------------------------------------------- - -struct SumoBreakListener; - -impl EventHandler for SumoBreakListener { - fn handle(&self, _server: Server, mut event: BlockBreakEventData) -> BlockBreakEventData { - let session_arc = get_session(); - let session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - let pos = &event.block_pos; - - // The Sumo arena platform is strictly unbreakable - if session.config.is_inside_platform(pos.x, pos.y, pos.z) { - event.cancelled = true; - if let Some(player) = &event.player { - player.send_system_message( - TextComponent::text("You cannot break the Sumo ring!"), - true, - ); - } - } - - event - } -} - -struct SumoMoveListener; - -impl EventHandler for SumoMoveListener { - fn handle(&self, server: Server, event: PlayerMoveEventData) -> PlayerMoveEventData { - let player_name = event.player.get_name(); - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - if session.state != GameState::Active || !session.alive_players.contains(&player_name) { - return event; - } - - let to = &event.to_position; - - // Ring-out check: knocked off the platform below elimination Y - if to.1 < session.config.elimination_y { - session.alive_players.remove(&player_name); - server.broadcast(&format!("{player_name} was KNOCKED OFF the ring and eliminated!")); - - let lobby = session.config.lobby_pos; - let world = event.player.get_world(); - event.player.teleport(lobby, Some(0.0), Some(0.0), world); - event.player.show_title(TextComponent::text("RING OUT!")); - - if session.alive_players.len() == 1 { - let winner_name = session.alive_players.iter().next().cloned().unwrap(); - server.broadcast(&format!("VICTORY! {winner_name} pushed everyone off and WINS Sumo!")); - if let Some(winner) = server.get_player_by_name(&winner_name) { - winner.show_title(TextComponent::text("VICTORY!")); - winner.show_subtitle(TextComponent::text("You won the Sumo match!")); - } - session.state = GameState::Ended; - } else if session.alive_players.is_empty() { - server.broadcast("Game Over! All fighters fell."); - session.state = GameState::Ended; - } - } - - event - } -} - -// ----------------------------------------------------------------------------- -// Plugin Lifecycle -// ----------------------------------------------------------------------------- - -pub struct SumoPlugin; - -impl Plugin for SumoPlugin { - fn new() -> Self { - SumoPlugin - } - - fn metadata(&self) -> PluginMetadata { - PluginMetadata { - name: "sumo".into(), - version: env!("CARGO_PKG_VERSION").into(), - authors: vec!["Pumpkin Developer".into()], - description: "A complete Sumo PvP minigame for Pumpkin Minecraft server.".into(), - dependencies: vec![], - permissions: vec![], - } - } - - fn on_load(&self, context: Context) -> Result<(), String> { - let config = SumoConfig::default(); - let session = Arc::new(Mutex::new(SumoSession::new(config))); - *SESSION.lock().unwrap_or_else(|e| e.into_inner()) = Some(session); - - let names = ["sumo".to_string(), "sm".to_string()]; - let command = Command::new(&names, "Sumo minigame management command") - .then(CommandNode::literal("join").execute(SumoJoinHandler)) - .then(CommandNode::literal("leave").execute(SumoLeaveHandler)) - .then(CommandNode::literal("start").execute(SumoStartHandler)) - .then(CommandNode::literal("status").execute(SumoStatusHandler)) - .then(CommandNode::literal("reset").execute(SumoResetHandler)) - .execute(SumoRootHandler); - - context.register_command(command, "pumpkin.command.sumo"); - - // Protect the ring platform from being broken - context.register_event_handler( - SumoBreakListener, - EventPriority::High, - true, - )?; - - // Monitor ring-out falls - context.register_event_handler( - SumoMoveListener, - EventPriority::Normal, - false, - )?; - - tracing::info!("Sumo minigame plugin successfully loaded!"); - Ok(()) - } - - fn on_unload(&self, _context: Context) -> Result<(), String> { - tracing::info!("Sumo plugin unloaded."); - Ok(()) - } -} - -register_plugin!(SumoPlugin); diff --git a/minigames/tnt-run/Cargo.toml b/minigames/tnt-run/Cargo.toml deleted file mode 100644 index 4037ca4..0000000 --- a/minigames/tnt-run/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "tnt-run" -version = "0.1.0" -edition = "2024" -authors = ["Pumpkin Developer"] -description = "A complete TNT Run minigame for the Pumpkin Minecraft server" -license = "MIT OR Apache-2.0" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -pumpkin-plugin-api = "0.1.0-dev" -tracing = "0.1" diff --git a/minigames/tnt-run/src/lib.rs b/minigames/tnt-run/src/lib.rs deleted file mode 100644 index cca38ff..0000000 --- a/minigames/tnt-run/src/lib.rs +++ /dev/null @@ -1,422 +0,0 @@ -//! # TNT Run Minigame for Pumpkin -//! -//! A complete, runnable TNT Run minigame showcasing: -//! - State management (`Waiting`, `Active`, `Ended`). -//! - Commands: `/tntrun join`, `/tntrun leave`, `/tntrun start`, `/tntrun status`, `/tntrun reset`. -//! - Movement tracking with [`PlayerMoveEvent`]: -//! - Decaying blocks under players' feet with a delay. -//! - Detecting when a player falls below the arena elimination Y level. -//! - Automatic win condition check (last player standing). -//! - Clean floor regeneration when resetting. - -use std::{ - collections::HashSet, - sync::{Arc, Mutex}, -}; - -use pumpkin_plugin_api::{ - command::{Command, CommandError, CommandNode, CommandSender, ConsumedArgs}, - commands::CommandHandler, - common::{BlockPos, Position}, - events::{EventHandler, EventPriority, player::PlayerMoveEvent}, - events_wit::PlayerMoveEventData, - scheduler::SchedulerExt, - world::BlockFlags, - Context, Plugin, PluginMetadata, register_plugin, Server, - text::TextComponent, -}; - -/// Arena spatial configuration. -#[derive(Clone, Debug)] -pub struct ArenaConfig { - pub min_x: i32, - pub max_x: i32, - pub min_z: i32, - pub max_z: i32, - /// Y coordinates of the running floors (top to bottom) - pub floor_y_levels: Vec, - /// Any player falling below this Y level is eliminated - pub elimination_y: f64, - /// Spawn position where players start the game - pub spawn_pos: Position, - /// Lobby position where spectators / eliminated players wait - pub lobby_pos: Position, -} - -impl Default for ArenaConfig { - fn default() -> Self { - Self { - min_x: -15, - max_x: 15, - min_z: -15, - max_z: 15, - floor_y_levels: vec![100, 85, 70], - elimination_y: 60.0, - spawn_pos: (0.5, 101.0, 0.5), - lobby_pos: (0.5, 115.0, 0.5), - } - } -} - -impl ArenaConfig { - pub fn is_inside_xz(&self, x: f64, z: f64) -> bool { - let ix = x.floor() as i32; - let iz = z.floor() as i32; - ix >= self.min_x && ix <= self.max_x && iz >= self.min_z && iz <= self.max_z - } -} - -/// Lifecycle state of the TNT Run game. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum GameState { - Waiting, - Active, - Ended, -} - -/// Shared game session state. -pub struct GameSession { - pub state: GameState, - pub config: ArenaConfig, - pub queued_players: HashSet, - pub alive_players: HashSet, - pub recently_decaying: HashSet<(i32, i32, i32)>, -} - -impl GameSession { - pub fn new(config: ArenaConfig) -> Self { - Self { - state: GameState::Waiting, - config, - queued_players: HashSet::new(), - alive_players: HashSet::new(), - recently_decaying: HashSet::new(), - } - } -} - -static SESSION: Mutex>>> = Mutex::new(None); - -fn get_session() -> Arc> { - SESSION - .lock() - .unwrap_or_else(|e| e.into_inner()) - .clone() - .expect("GameSession must be initialized in on_load") -} - -// ----------------------------------------------------------------------------- -// Commands: /tntrun -// ----------------------------------------------------------------------------- - -struct TntRunRootHandler; -impl CommandHandler for TntRunRootHandler { - fn handle( - &self, - sender: CommandSender, - _server: Server, - _args: ConsumedArgs, - ) -> Result { - let help_text = "TNT Run Commands:\n\ - /tntrun join - Join the game queue\n\ - /tntrun leave - Leave the queue or game\n\ - /tntrun start - Force start the game\n\ - /tntrun status - View game status\n\ - /tntrun reset - Regenerate arena floors"; - sender.send_message(TextComponent::text(help_text)); - Ok(0) - } -} - -struct TntRunJoinHandler; -impl CommandHandler for TntRunJoinHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let player_name = sender.get_name(); - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - match session.state { - GameState::Active => { - sender.send_message(TextComponent::text("Game is already in progress! Please wait.")); - } - GameState::Waiting | GameState::Ended => { - if session.queued_players.insert(player_name.clone()) { - let count = session.queued_players.len(); - server.broadcast(&format!("{player_name} joined TNT Run! ({count} players queued)")); - sender.send_message(TextComponent::text("You joined the queue! Use /tntrun start when ready.")); - } else { - sender.send_message(TextComponent::text("You are already in the queue!")); - } - } - } - Ok(0) - } -} - -struct TntRunLeaveHandler; -impl CommandHandler for TntRunLeaveHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let player_name = sender.get_name(); - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - if session.queued_players.remove(&player_name) || session.alive_players.remove(&player_name) { - server.broadcast(&format!("{player_name} left TNT Run.")); - sender.send_message(TextComponent::text("You left TNT Run.")); - } else { - sender.send_message(TextComponent::text("You are not currently in a TNT Run game.")); - } - Ok(0) - } -} - -struct TntRunStartHandler; -impl CommandHandler for TntRunStartHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - if session.state == GameState::Active { - sender.send_message(TextComponent::text("Game is already running!")); - return Ok(0); - } - - // If no one is queued, queue the sender if it's a player - if session.queued_players.is_empty() { - session.queued_players.insert(sender.get_name()); - } - - session.alive_players = session.queued_players.clone(); - session.state = GameState::Active; - session.recently_decaying.clear(); - - let count = session.alive_players.len(); - server.broadcast(&format!("TNT Run has STARTED with {count} players! Keep running!")); - - // Teleport all alive players to the spawn position - let spawn = session.config.spawn_pos; - for player_name in &session.alive_players { - if let Some(player) = server.get_player_by_name(player_name) { - let world = player.get_world(); - player.teleport(spawn, Some(0.0), Some(0.0), world); - player.show_title(TextComponent::text("TNT RUN!")); - player.show_subtitle(TextComponent::text("Don't stop moving!")); - } - } - - Ok(0) - } -} - -struct TntRunStatusHandler; -impl CommandHandler for TntRunStatusHandler { - fn handle( - &self, - sender: CommandSender, - _server: Server, - _args: ConsumedArgs, - ) -> Result { - let session_arc = get_session(); - let session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - let status_msg = match session.state { - GameState::Waiting => format!("TNT Run: WAITING ({} players queued)", session.queued_players.len()), - GameState::Active => format!( - "TNT Run: ACTIVE ({} alive: {:?})", - session.alive_players.len(), - session.alive_players - ), - GameState::Ended => "TNT Run: ENDED (Use /tntrun reset or /tntrun start)".to_string(), - }; - - sender.send_message(TextComponent::text(&status_msg)); - Ok(0) - } -} - -struct TntRunResetHandler; -impl CommandHandler for TntRunResetHandler { - fn handle( - &self, - sender: CommandSender, - server: Server, - _args: ConsumedArgs, - ) -> Result { - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - session.state = GameState::Waiting; - session.alive_players.clear(); - session.recently_decaying.clear(); - - // Regenerate floors using the first available world - let worlds = server.get_all_worlds(); - if let Some(world) = worlds.first() { - let flags = BlockFlags::NOTIFY_LISTENERS | BlockFlags::NOTIFY_NEIGHBORS; - for &y in &session.config.floor_y_levels { - for x in session.config.min_x..=session.config.max_x { - for z in session.config.min_z..=session.config.max_z { - let pos = BlockPos { x, y, z }; - world.set_block_by_name(pos, "minecraft:sand", flags); - let tnt_pos = BlockPos { x, y: y - 1, z }; - world.set_block_by_name(tnt_pos, "minecraft:tnt", flags); - } - } - } - } - - server.broadcast("TNT Run arena has been regenerated and reset!"); - sender.send_message(TextComponent::text("Arena reset complete!")); - Ok(0) - } -} - -// ----------------------------------------------------------------------------- -// Movement & Decay Event Listener -// ----------------------------------------------------------------------------- - -struct TntRunMoveListener; - -impl EventHandler for TntRunMoveListener { - fn handle(&self, server: Server, event: PlayerMoveEventData) -> PlayerMoveEventData { - let player_name = event.player.get_name(); - let session_arc = get_session(); - let mut session = session_arc.lock().unwrap_or_else(|e| e.into_inner()); - - // Only process movement if game is active and player is an alive participant - if session.state != GameState::Active || !session.alive_players.contains(&player_name) { - return event; - } - - let to = &event.to_position; - - // 1. Elimination Check: player fell below the elimination threshold - if to.1 < session.config.elimination_y { - session.alive_players.remove(&player_name); - server.broadcast(&format!("{player_name} fell into the void and was ELIMINATED!")); - - // Teleport eliminated player back to lobby - let lobby = session.config.lobby_pos; - let world = event.player.get_world(); - event.player.teleport(lobby, Some(0.0), Some(0.0), world); - event.player.show_title(TextComponent::text("ELIMINATED!")); - - // 2. Win Condition Check - if session.alive_players.len() == 1 { - let winner_name = session.alive_players.iter().next().cloned().unwrap(); - server.broadcast(&format!("VICTORY! {winner_name} is the last player standing and WINS TNT Run!")); - if let Some(winner) = server.get_player_by_name(&winner_name) { - winner.show_title(TextComponent::text("VICTORY!")); - winner.show_subtitle(TextComponent::text("You won TNT Run!")); - } - session.state = GameState::Ended; - } else if session.alive_players.is_empty() { - server.broadcast("Game Over! No players remaining."); - session.state = GameState::Ended; - } - - return event; - } - - // 3. Block Decay Mechanic: if inside arena XZ, decay the block under feet - if session.config.is_inside_xz(to.0, to.2) { - let bx = to.0.floor() as i32; - let by = (to.1 - 0.2).floor() as i32; - let bz = to.2.floor() as i32; - - // Only trigger decay if standing on one of the designated floor Y levels - if session.config.floor_y_levels.contains(&by) && session.recently_decaying.insert((bx, by, bz)) { - let world = event.player.get_world(); - let flags = BlockFlags::NOTIFY_LISTENERS | BlockFlags::NOTIFY_NEIGHBORS; - - // Turn sand and underlying TNT to air after delay - let session_clone = Arc::clone(&session_arc); - server.schedule_delayed_task(8, move |_| { - let pos = BlockPos { x: bx, y: by, z: bz }; - let tnt_pos = BlockPos { x: bx, y: by - 1, z: bz }; - world.set_block_by_name(pos, "minecraft:air", flags); - world.set_block_by_name(tnt_pos, "minecraft:air", flags); - - if let Ok(mut s) = session_clone.lock() { - s.recently_decaying.remove(&(bx, by, bz)); - } - }); - } - } - - event - } -} - -// ----------------------------------------------------------------------------- -// Plugin Lifecycle -// ----------------------------------------------------------------------------- - -pub struct TntRunPlugin; - -impl Plugin for TntRunPlugin { - fn new() -> Self { - TntRunPlugin - } - - fn metadata(&self) -> PluginMetadata { - PluginMetadata { - name: "tnt-run".into(), - version: env!("CARGO_PKG_VERSION").into(), - authors: vec!["Pumpkin Developer".into()], - description: "A complete TNT Run minigame for Pumpkin Minecraft server.".into(), - dependencies: vec![], - permissions: vec![], - } - } - - fn on_load(&self, context: Context) -> Result<(), String> { - let config = ArenaConfig::default(); - let session = Arc::new(Mutex::new(GameSession::new(config))); - *SESSION.lock().unwrap_or_else(|e| e.into_inner()) = Some(session); - - // Register /tntrun command tree - let names = ["tntrun".to_string(), "tr".to_string()]; - let command = Command::new(&names, "TNT Run minigame management command") - .then(CommandNode::literal("join").execute(TntRunJoinHandler)) - .then(CommandNode::literal("leave").execute(TntRunLeaveHandler)) - .then(CommandNode::literal("start").execute(TntRunStartHandler)) - .then(CommandNode::literal("status").execute(TntRunStatusHandler)) - .then(CommandNode::literal("reset").execute(TntRunResetHandler)) - .execute(TntRunRootHandler); - - context.register_command(command, "pumpkin.command.tntrun"); - - // Register PlayerMoveEvent listener - context.register_event_handler( - TntRunMoveListener, - EventPriority::Normal, - false, - )?; - - tracing::info!("TNT Run minigame plugin successfully loaded!"); - Ok(()) - } - - fn on_unload(&self, _context: Context) -> Result<(), String> { - tracing::info!("TNT Run plugin unloaded."); - Ok(()) - } -} - -register_plugin!(TntRunPlugin);