Remove old root basics and minigames folders, add .gitignore

This commit is contained in:
Alexander Medvedev 2026-09-05 12:47:51 +02:00
parent da3f482da4
commit 3c9305cf39
18 changed files with 19 additions and 3822 deletions

19
.gitignore vendored Normal file
View File

@ -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

570
Cargo.lock generated
View File

@ -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"

View File

@ -1,6 +0,0 @@
[workspace]
resolver = "2"
members = [
"basics/*",
"minigames/*",
]

View File

@ -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"

View File

@ -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"

View File

@ -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);

View File

@ -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"

View File

@ -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"

View File

@ -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<i32, CommandError> {
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 <message>`.
struct GreetBroadcastHandler;
impl CommandHandler for GreetBroadcastHandler {
fn handle(
&self,
sender: CommandSender,
server: Server,
args: ConsumedArgs,
) -> Result<i32, CommandError> {
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<i32, CommandError> {
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 <message>
// /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);

View File

@ -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"

View File

@ -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"

View File

@ -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<PlayerJoinEvent> 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<PlayerLeaveEvent> 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<BlockBreakEvent> 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);

View File

@ -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"

View File

@ -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<String>,
pub alive_players: HashSet<String>,
}
impl SpleefSession {
pub fn new(config: SpleefConfig) -> Self {
Self {
state: GameState::Waiting,
config,
queued_players: HashSet::new(),
alive_players: HashSet::new(),
}
}
}
static SESSION: Mutex<Option<Arc<Mutex<SpleefSession>>>> = Mutex::new(None);
fn get_session() -> Arc<Mutex<SpleefSession>> {
SESSION
.lock()
.unwrap_or_else(|e| e.into_inner())
.clone()
.expect("SpleefSession must be initialized in on_load")
}
// -----------------------------------------------------------------------------
// Commands: /spleef <subcommand>
// -----------------------------------------------------------------------------
struct SpleefRootHandler;
impl CommandHandler for SpleefRootHandler {
fn handle(
&self,
sender: CommandSender,
_server: Server,
_args: ConsumedArgs,
) -> Result<i32, CommandError> {
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<i32, CommandError> {
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<i32, CommandError> {
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<i32, CommandError> {
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<i32, CommandError> {
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<i32, CommandError> {
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<BlockBreakEvent> 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<PlayerMoveEvent> 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);

View File

@ -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"

View File

@ -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<String>,
pub alive_players: HashSet<String>,
}
impl SumoSession {
pub fn new(config: SumoConfig) -> Self {
Self {
state: GameState::Waiting,
config,
queued_players: HashSet::new(),
alive_players: HashSet::new(),
}
}
}
static SESSION: Mutex<Option<Arc<Mutex<SumoSession>>>> = Mutex::new(None);
fn get_session() -> Arc<Mutex<SumoSession>> {
SESSION
.lock()
.unwrap_or_else(|e| e.into_inner())
.clone()
.expect("SumoSession must be initialized in on_load")
}
// -----------------------------------------------------------------------------
// Commands: /sumo <subcommand>
// -----------------------------------------------------------------------------
struct SumoRootHandler;
impl CommandHandler for SumoRootHandler {
fn handle(
&self,
sender: CommandSender,
_server: Server,
_args: ConsumedArgs,
) -> Result<i32, CommandError> {
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<i32, CommandError> {
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<i32, CommandError> {
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<i32, CommandError> {
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<i32, CommandError> {
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<i32, CommandError> {
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<BlockBreakEvent> 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<PlayerMoveEvent> 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);

View File

@ -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"

View File

@ -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<i32>,
/// 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<String>,
pub alive_players: HashSet<String>,
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<Option<Arc<Mutex<GameSession>>>> = Mutex::new(None);
fn get_session() -> Arc<Mutex<GameSession>> {
SESSION
.lock()
.unwrap_or_else(|e| e.into_inner())
.clone()
.expect("GameSession must be initialized in on_load")
}
// -----------------------------------------------------------------------------
// Commands: /tntrun <subcommand>
// -----------------------------------------------------------------------------
struct TntRunRootHandler;
impl CommandHandler for TntRunRootHandler {
fn handle(
&self,
sender: CommandSender,
_server: Server,
_args: ConsumedArgs,
) -> Result<i32, CommandError> {
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<i32, CommandError> {
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<i32, CommandError> {
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<i32, CommandError> {
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<i32, CommandError> {
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<i32, CommandError> {
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<PlayerMoveEvent> 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);