enforce clippy lints and rustfmt

This commit is contained in:
Alexander Medvedev 2026-02-03 21:00:51 +01:00
parent 9f92bf25e9
commit e8d53a458e
22 changed files with 620 additions and 243 deletions

View File

@ -28,6 +28,12 @@ jobs:
run: ./gradlew jar
working-directory: java
- name: Check Formatting
run: cargo fmt --all -- --check
working-directory: rust
- name: Lint with Clippy
run: cargo clippy -- -D warnings
working-directory: rust
- name: Build rust
run: cargo build --verbose
working-directory: rust

View File

@ -7,7 +7,7 @@
plugins {
// Apply the foojay-resolver plugin to allow automatic download of JDKs
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
}
rootProject.name = "patchbukkit"

336
rust/Cargo.lock generated
View File

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "addr2line"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
dependencies = [
"gimli",
]
[[package]]
name = "adler2"
version = "2.0.1"
@ -54,7 +63,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16e4850548ff4a25a77ce3bda7241874e17fb702ea551f0cc62a2dbe052f1272"
dependencies = [
"anstyle",
"unicode-width",
"unicode-width 0.2.2",
]
[[package]]
@ -149,12 +158,45 @@ dependencies = [
"tokio",
]
[[package]]
name = "atomic"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340"
dependencies = [
"bytemuck",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "backtrace"
version = "0.3.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-link",
]
[[package]]
name = "backtrace-ext"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50"
dependencies = [
"backtrace",
]
[[package]]
name = "base16ct"
version = "0.2.0"
@ -209,6 +251,12 @@ version = "3.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
[[package]]
name = "bytemuck"
version = "1.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
[[package]]
name = "bytes"
version = "1.11.0"
@ -224,6 +272,15 @@ dependencies = [
"libbz2-rs-sys",
]
[[package]]
name = "castaway"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
dependencies = [
"rustversion",
]
[[package]]
name = "cc"
version = "1.2.55"
@ -314,6 +371,20 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "compact_str"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32"
dependencies = [
"castaway",
"cfg-if",
"itoa",
"rustversion",
"ryu",
"static_assertions",
]
[[package]]
name = "compression-codecs"
version = "0.4.36"
@ -552,6 +623,41 @@ dependencies = [
"cmov",
]
[[package]]
name = "darling"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "dashmap"
version = "6.1.0"
@ -823,6 +929,18 @@ dependencies = [
"subtle",
]
[[package]]
name = "figment"
version = "0.10.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3"
dependencies = [
"atomic",
"serde",
"uncased",
"version_check",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
@ -840,6 +958,12 @@ dependencies = [
"zlib-rs",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
version = "0.1.5"
@ -956,6 +1080,28 @@ dependencies = [
"slab",
]
[[package]]
name = "garde"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a74b56a4039a46e8c91cc9d84e8a7df4e1f8b24239ca57d1304b3263cb599b9"
dependencies = [
"compact_str",
"garde_derive",
"smallvec 1.15.1",
]
[[package]]
name = "garde_derive"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7224c08ec489e2840af29ed882b47f7f6ac8f4ce15c275d9fc0d6d1b94578ae6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "generic-array"
version = "0.14.7"
@ -1006,6 +1152,12 @@ dependencies = [
"wasip3",
]
[[package]]
name = "gimli"
version = "0.32.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
[[package]]
name = "glob"
version = "0.3.3"
@ -1209,6 +1361,12 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "1.1.0"
@ -1251,6 +1409,12 @@ dependencies = [
"generic-array",
]
[[package]]
name = "is_ci"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
@ -1518,6 +1682,36 @@ version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "miette"
version = "7.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7"
dependencies = [
"backtrace",
"backtrace-ext",
"cfg-if",
"miette-derive",
"owo-colors",
"supports-color",
"supports-hyperlinks",
"supports-unicode",
"terminal_size",
"textwrap",
"unicode-width 0.1.14",
]
[[package]]
name = "miette-derive"
version = "7.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "miniz_oxide"
version = "0.8.9"
@ -1630,6 +1824,15 @@ dependencies = [
"libc",
]
[[package]]
name = "object"
version = "0.37.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.21.3"
@ -1648,6 +1851,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "owo-colors"
version = "4.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
[[package]]
name = "p384"
version = "0.13.1"
@ -2370,6 +2579,12 @@ dependencies = [
"walkdir",
]
[[package]]
name = "rustc-demangle"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
[[package]]
name = "rustc-hash"
version = "2.1.1"
@ -2447,7 +2662,7 @@ dependencies = [
"nix",
"radix_trie",
"unicode-segmentation",
"unicode-width",
"unicode-width 0.2.2",
"utf8parse",
"windows-sys 0.60.2",
]
@ -2461,6 +2676,12 @@ dependencies = [
"twox-hash 2.1.2",
]
[[package]]
name = "ryu"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
[[package]]
name = "same-file"
version = "1.0.6"
@ -2472,9 +2693,9 @@ dependencies = [
[[package]]
name = "saphyr-parser-bw"
version = "0.0.605"
version = "0.0.607"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e1aee7486406df3541b5a657204a11be97175a467d77bc98e6d94a66289fb80"
checksum = "2f9bae8d059bf1ca32753cf3cdafbf5d391502de2fc2ca54510811fe9c100d90"
dependencies = [
"arraydeque",
"smallvec 2.0.0-alpha.12",
@ -2519,14 +2740,18 @@ dependencies = [
[[package]]
name = "serde-saphyr"
version = "0.0.16"
version = "0.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4db5a4a562bcc0017c34cd0efbabf447be783f00576a2a516947f884e6a7ed57"
checksum = "bc14a55107113a16346915d7e3d78acc539a923458385db89670e22cac106d7a"
dependencies = [
"ahash",
"annotate-snippets",
"base64",
"encoding_rs_io",
"figment",
"garde",
"getrandom 0.3.4",
"miette",
"nohash-hasher",
"num-traits",
"regex",
@ -2534,6 +2759,7 @@ dependencies = [
"serde",
"serde_json",
"smallvec 2.0.0-alpha.12",
"validator",
"zmij",
]
@ -2789,12 +3015,39 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "supports-color"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6"
dependencies = [
"is_ci",
]
[[package]]
name = "supports-hyperlinks"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91"
[[package]]
name = "supports-unicode"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2"
[[package]]
name = "syn"
version = "2.0.114"
@ -2832,6 +3085,26 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "terminal_size"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0"
dependencies = [
"rustix",
"windows-sys 0.60.2",
]
[[package]]
name = "textwrap"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
dependencies = [
"unicode-linebreak",
"unicode-width 0.2.2",
]
[[package]]
name = "thiserror"
version = "2.0.18"
@ -3019,18 +3292,39 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
[[package]]
name = "uncased"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697"
dependencies = [
"version_check",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "unicode-linebreak"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "unicode-width"
version = "0.2.2"
@ -3124,6 +3418,36 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "validator"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43fb22e1a008ece370ce08a3e9e4447a910e92621bb49b85d6e48a45397e7cfa"
dependencies = [
"idna",
"once_cell",
"regex",
"serde",
"serde_derive",
"serde_json",
"url",
"validator_derive",
]
[[package]]
name = "validator_derive"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7df16e474ef958526d1205f6dda359fdfab79d9aa6d54bafcb92dcd07673dca"
dependencies = [
"darling",
"once_cell",
"proc-macro-error2",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "version_check"
version = "0.9.5"

View File

@ -27,7 +27,7 @@ uuid = "1.20.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde-saphyr = "0.0.16"
serde-saphyr = "0.0.17"
rand = { git = "https://github.com/rust-random/rand"}
@ -38,3 +38,16 @@ log = "0.4"
[profile.release]
lto = true
[lints.clippy]
# Groups
all = { level = "deny", priority = -1 }
# nursery = { level = "deny", priority = -1 }
# pedantic = { level = "deny", priority = -1 }
# cargo = { level = "deny", priority = -1 }
multiple_crate_versions = "allow"
unnecessary_fallible_conversions = "allow"
not_unsafe_ptr_arg_deref = "allow" # Not sure about this one

View File

@ -1,8 +1,9 @@
use std::{collections::HashSet, error::Error, fs, path::PathBuf};
use std::{collections::HashSet, fs, path::PathBuf};
use j4rs::{JvmBuilder, LocalJarArtifact, MavenArtifact, MavenArtifactRepo, MavenSettings};
fn main() -> Result<(), Box<dyn Error>> {
#[expect(clippy::too_many_lines)]
fn main() {
println!("cargo::rerun-if-changed=rust/src/build.rs");
println!("cargo::rerun-if-changed=java/build/libs/");
env_logger::init();
@ -93,7 +94,7 @@ fn main() -> Result<(), Box<dyn Error>> {
.skip_setting_native_lib()
.with_base_path(resources)
.build()
.map_err(|err| format!("jvm failed to init: {:?}", err))
.map_err(|err| format!("jvm failed to init: {err:?}"))
.unwrap();
let expected: HashSet<String> = dependencies
@ -130,7 +131,7 @@ fn main() -> Result<(), Box<dyn Error>> {
}
}
let mut java_path = base.clone();
let mut java_path = base;
java_path.pop();
let java_path = java_path.join("java");
@ -140,12 +141,11 @@ fn main() -> Result<(), Box<dyn Error>> {
.join("libs")
.join("patchbukkit.jar");
println!("patchbukkit_jar: {:?}", patchbukkit_jar);
if !&patchbukkit_jar.exists() {
panic!(
"Failed to find patchbukkit.jar, build the java library first by running `gradle build` in the java directory!"
);
}
println!("patchbukkit_jar: {}", patchbukkit_jar.display());
assert!(
!!&patchbukkit_jar.exists(),
"Failed to find patchbukkit.jar, build the java library first by running `gradle build` in the java directory!"
);
jvm.deploy_artifact(&LocalJarArtifact::new(&patchbukkit_jar.to_string_lossy()))
.unwrap();
@ -153,18 +153,16 @@ fn main() -> Result<(), Box<dyn Error>> {
let cdylib = std::env::var("CARGO_CDYLIB_FILE_J4RS").unwrap();
let cdylib = PathBuf::from(cdylib);
let mut cdylib_to = deps.clone();
let mut cdylib_to = deps;
fs::create_dir_all(&cdylib_to).unwrap();
let original_name = cdylib.file_name().unwrap().to_string_lossy();
let stem = original_name.split('-').next().unwrap(); // before the first '-'
let ext = cdylib.extension().unwrap().to_string_lossy();
cdylib_to.push(format!("{}.{}", stem, ext));
cdylib_to.push(format!("{stem}.{ext}"));
fs::copy(&cdylib, &cdylib_to)
.map_err(|err| format!("Failed to copy j4rs native lib: {:?}", err))
.map_err(|err| format!("Failed to copy j4rs native lib: {err:?}"))
.unwrap();
Ok(())
}

View File

@ -104,20 +104,17 @@ impl ArgumentConsumer for AnyCommandNode {
.await
.unwrap();
let suggestion = rx.await.unwrap();
suggestion
rx.await.unwrap()
})
}
}
impl Into<SimpleCommandSender> for &CommandSender {
fn into(self) -> SimpleCommandSender {
match self {
impl From<&CommandSender> for SimpleCommandSender {
fn from(val: &CommandSender) -> Self {
match val {
CommandSender::Rcon(_mutex) => todo!(),
CommandSender::Console => SimpleCommandSender::Console,
CommandSender::Player(player) => {
SimpleCommandSender::Player(player.gameprofile.id.to_string())
}
CommandSender::Console => Self::Console,
CommandSender::Player(player) => Self::Player(player.gameprofile.id.to_string()),
CommandSender::CommandBlock(_block_entity, _world) => todo!(),
}
}
@ -139,7 +136,7 @@ impl CommandExecutor for JavaCommandExecutor {
let (tx, _rx) = oneshot::channel();
self.command_tx
.send(JvmCommand::TriggerCommand {
full_command: full_command,
full_command,
respond_to: tx,
command_sender: sender.into(),
})

View File

@ -4,7 +4,7 @@ use std::collections::HashMap;
pub const PAPER_PLUGIN_CONFIG: &str = "paper-plugin.yml";
/// Represents the load order for a dependency
#[derive(Debug, Deserialize, Default, Clone, PartialEq)]
#[derive(Debug, Deserialize, Default, Clone, PartialEq, Eq)]
#[serde(rename_all = "UPPERCASE")]
pub enum LoadOrder {
/// Load the dependency before this plugin
@ -36,7 +36,7 @@ pub struct PaperDependency {
pub join_classpath: bool,
}
fn default_true() -> bool {
const fn default_true() -> bool {
true
}
@ -64,6 +64,7 @@ pub struct PaperDependencies {
impl PaperDependencies {
/// Get all bootstrap dependencies
#[must_use]
pub fn get_bootstrap_deps(&self) -> Vec<(&String, &PaperDependency)> {
self.bootstrap
.as_ref()
@ -72,6 +73,7 @@ impl PaperDependencies {
}
/// Get all server dependencies
#[must_use]
pub fn get_server_deps(&self) -> Vec<(&String, &PaperDependency)> {
self.server
.as_ref()
@ -80,6 +82,7 @@ impl PaperDependencies {
}
/// Get all required bootstrap dependencies
#[must_use]
pub fn get_required_bootstrap_deps(&self) -> Vec<&String> {
self.bootstrap
.as_ref()
@ -93,6 +96,7 @@ impl PaperDependencies {
}
/// Get all required server dependencies
#[must_use]
pub fn get_required_server_deps(&self) -> Vec<&String> {
self.server
.as_ref()
@ -106,19 +110,19 @@ impl PaperDependencies {
}
/// Check if a plugin is a bootstrap dependency
#[must_use]
pub fn has_bootstrap_dep(&self, name: &str) -> bool {
self.bootstrap
.as_ref()
.map(|deps| deps.contains_key(name))
.unwrap_or(false)
.is_some_and(|deps| deps.contains_key(name))
}
/// Check if a plugin is a server dependency
#[must_use]
pub fn has_server_dep(&self, name: &str) -> bool {
self.server
.as_ref()
.map(|deps| deps.contains_key(name))
.unwrap_or(false)
.is_some_and(|deps| deps.contains_key(name))
}
}
@ -132,7 +136,7 @@ pub struct PaperPluginYml {
/// The current version of the plugin
pub version: String,
/// The main class of your plugin (extends JavaPlugin)
/// The main class of your plugin (extends `JavaPlugin`)
pub main: String,
// Optional metadata fields
@ -163,11 +167,11 @@ pub struct PaperPluginYml {
pub api_version: Option<String>,
// Paper-specific fields
/// The bootstrapper class that implements PluginBootstrap
/// The bootstrapper class that implements `PluginBootstrap`
#[serde(default)]
pub bootstrapper: Option<String>,
/// The loader class that implements PluginLoader
/// The loader class that implements `PluginLoader`
#[serde(default)]
pub loader: Option<String>,
@ -184,11 +188,12 @@ pub struct PaperPluginYml {
impl PaperPluginYml {
/// Parse a paper-plugin.yml from a YAML string
pub fn from_str(yaml: &str) -> Result<Self, serde_saphyr::Error> {
pub fn parse(yaml: &str) -> Result<Self, serde_saphyr::Error> {
serde_saphyr::from_str(yaml)
}
/// Get all authors (combines author and authors fields)
#[must_use]
pub fn get_all_authors(&self) -> Vec<String> {
let mut result = Vec::new();
if let Some(ref author) = self.author {
@ -201,44 +206,47 @@ impl PaperPluginYml {
}
/// Check if this plugin has a bootstrapper
pub fn has_bootstrapper(&self) -> bool {
#[must_use]
pub const fn has_bootstrapper(&self) -> bool {
self.bootstrapper.is_some()
}
/// Check if this plugin has a custom loader
pub fn has_loader(&self) -> bool {
#[must_use]
pub const fn has_loader(&self) -> bool {
self.loader.is_some()
}
/// Get dependencies (returns default if none specified)
#[must_use]
pub fn get_dependencies(&self) -> PaperDependencies {
self.dependencies.clone().unwrap_or_default()
}
/// Check if a plugin is required (in either bootstrap or server)
#[must_use]
pub fn requires_plugin(&self, name: &str) -> bool {
if let Some(ref deps) = self.dependencies {
// Check bootstrap dependencies
if let Some(ref bootstrap) = deps.bootstrap {
if let Some(dep) = bootstrap.get(name) {
if dep.required {
return true;
}
}
if let Some(ref bootstrap) = deps.bootstrap
&& let Some(dep) = bootstrap.get(name)
&& dep.required
{
return true;
}
// Check server dependencies
if let Some(ref server) = deps.server {
if let Some(dep) = server.get(name) {
if dep.required {
return true;
}
}
if let Some(ref server) = deps.server
&& let Some(dep) = server.get(name)
&& dep.required
{
return true;
}
}
false
}
/// Get all plugins that should load BEFORE this plugin
#[must_use]
pub fn get_load_before_deps(&self) -> Vec<String> {
let mut result = Vec::new();
if let Some(ref deps) = self.dependencies {
@ -261,6 +269,7 @@ impl PaperPluginYml {
}
/// Get all plugins that should load AFTER this plugin
#[must_use]
pub fn get_load_after_deps(&self) -> Vec<String> {
let mut result = Vec::new();
if let Some(ref deps) = self.dependencies {

View File

@ -5,7 +5,7 @@ use serde::Deserialize;
pub const SPIGOT_PLUGIN_CONFIG: &str = "plugin.yml";
/// Represents when a plugin should be loaded
#[derive(Debug, Deserialize, Default, Clone, PartialEq)]
#[derive(Debug, Deserialize, Default, Clone, PartialEq, Eq)]
#[serde(rename_all = "UPPERCASE")]
pub enum LoadOrder {
#[serde(alias = "startup", alias = "Startup")]
@ -16,9 +16,11 @@ pub enum LoadOrder {
}
/// Represents the default permission value
#[derive(Debug, Deserialize, Clone, PartialEq)]
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
#[derive(Default)]
pub enum DefaultPermission {
#[default]
Op,
#[serde(alias = "notop")]
NotOp,
@ -26,12 +28,6 @@ pub enum DefaultPermission {
False,
}
impl Default for DefaultPermission {
fn default() -> Self {
DefaultPermission::Op
}
}
/// Represents a permission node definition
#[derive(Debug, Deserialize, Clone)]
pub struct Permission {
@ -69,10 +65,11 @@ pub enum StringOrList {
impl StringOrList {
/// Convert to a Vec<String> regardless of the variant
#[must_use]
pub fn to_vec(&self) -> Vec<String> {
match self {
StringOrList::Single(s) => vec![s.clone()],
StringOrList::Multiple(v) => v.clone(),
Self::Single(s) => vec![s.clone()],
Self::Multiple(v) => v.clone(),
}
}
}
@ -85,7 +82,7 @@ pub struct SpigotPluginYml {
pub name: String,
/// The current version of the plugin
pub version: String,
/// The main class of your plugin (extends JavaPlugin)
/// The main class of your plugin (extends `JavaPlugin`)
pub main: String,
// Optional metadata fields
@ -161,11 +158,12 @@ pub struct SpigotPluginYml {
impl SpigotPluginYml {
/// Parse a plugin.yml from a YAML string
pub fn from_str(yaml: &str) -> Result<Self, serde_saphyr::Error> {
pub fn parse(yaml: &str) -> Result<Self, serde_saphyr::Error> {
serde_saphyr::from_str(yaml)
}
/// Get all authors (combines author and authors fields)
#[must_use]
pub fn get_all_authors(&self) -> Vec<String> {
let mut result = Vec::new();
if let Some(ref author) = self.author {
@ -178,6 +176,7 @@ impl SpigotPluginYml {
}
/// Check if this plugin depends on another plugin
#[must_use]
pub fn depends_on(&self, plugin_name: &str) -> bool {
if let Some(ref deps) = self.depend {
return deps.iter().any(|d| d == plugin_name);
@ -186,6 +185,7 @@ impl SpigotPluginYml {
}
/// Check if this plugin soft-depends on another plugin
#[must_use]
pub fn soft_depends_on(&self, plugin_name: &str) -> bool {
if let Some(ref deps) = self.softdepend {
return deps.iter().any(|d| d == plugin_name);

View File

@ -20,10 +20,10 @@ pub fn setup_directories(server: &Context) -> Result<PatchBukkitDirectories, Str
let jassets = j4rs.join("jassets");
fs::create_dir_all(&jassets)
.map_err(|err| format!("Failed to create jassets folder: {:?}", err))?;
.map_err(|err| format!("Failed to create jassets folder: {err:?}"))?;
fs::create_dir_all(&plugins)
.map_err(|err| format!("Failed to create patchbukkit-plugins folder: {:?}", err))?;
.map_err(|err| format!("Failed to create patchbukkit-plugins folder: {err:?}"))?;
Ok(PatchBukkitDirectories {
base,

View File

@ -19,13 +19,13 @@ pub enum PatchBukkitEvent {
}
pub trait IntoEventData {
fn into_patch_bukkit_event(&self, server: Arc<Server>) -> PatchBukkitEvent;
fn get_patch_bukkit_event(&self, server: Arc<Server>) -> PatchBukkitEvent;
}
impl IntoEventData for pumpkin::plugin::player::player_join::PlayerJoinEvent {
fn into_patch_bukkit_event(&self, server: Arc<Server>) -> PatchBukkitEvent {
fn get_patch_bukkit_event(&self, server: Arc<Server>) -> PatchBukkitEvent {
PatchBukkitEvent::PlayerJoinEvent {
server: server,
server,
player: self.player.clone(),
join_message: self.join_message.clone().get_text(),
}
@ -39,7 +39,8 @@ pub struct PatchBukkitEventHandler<E: IntoEventData> {
}
impl<E: IntoEventData> PatchBukkitEventHandler<E> {
pub fn new(plugin_name: String, command_tx: mpsc::Sender<JvmCommand>) -> Self {
#[must_use]
pub const fn new(plugin_name: String, command_tx: mpsc::Sender<JvmCommand>) -> Self {
Self {
plugin_name,
command_tx,
@ -64,13 +65,13 @@ where
let (tx, rx) = oneshot::channel();
if let Err(e) = command_tx
.send(JvmCommand::FireEvent {
patchbukkit_event: event.into_patch_bukkit_event(server.clone()),
patchbukkit_event: event.get_patch_bukkit_event(server.clone()),
respond_to: tx,
plugin: self.plugin_name.clone(),
})
.await
{
log::error!("Failed to send event to JVM worker: {}", e);
log::error!("Failed to send event to JVM worker: {e}");
return;
}

View File

@ -10,17 +10,17 @@ use zip::ZipArchive;
use crate::config::{paper::PAPER_PLUGIN_CONFIG, spigot::SPIGOT_PLUGIN_CONFIG};
pub fn discover_jar_files(plugin_folder: &PathBuf) -> impl Iterator<Item = PathBuf> {
pub fn discover_jar_files(plugin_folder: &Path) -> impl Iterator<Item = PathBuf> {
let pattern = format!("{}/**/*.jar", plugin_folder.display());
glob(&pattern)
.expect("Invalid glob pattern")
.filter_map(|entry| {
entry
.map_err(|e| log::error!("Glob error: {:?}", e))
.map_err(|e| log::error!("Glob error: {e:?}"))
.ok()?
.canonicalize()
.map_err(|e| log::error!("Canonicalize error: {:?}", e))
.map_err(|e| log::error!("Canonicalize error: {e:?}"))
.ok()
})
}

View File

@ -22,7 +22,7 @@ pub enum JvmCommand {
j4rs_path: PathBuf,
respond_to: oneshot::Sender<Result<()>>,
context: Arc<Context>,
command_tx: mpsc::Sender<JvmCommand>,
command_tx: mpsc::Sender<Self>,
},
LoadPlugin {
plugin_path: PathBuf,
@ -31,7 +31,7 @@ pub enum JvmCommand {
InstantiateAllPlugins {
respond_to: oneshot::Sender<Result<()>>,
server: Arc<Context>,
command_tx: mpsc::Sender<JvmCommand>,
command_tx: mpsc::Sender<Self>,
},
EnableAllPlugins {
respond_to: oneshot::Sender<Result<()>>,
@ -66,8 +66,9 @@ pub struct Rotation {
}
impl Rotation {
pub fn new(yaw: f32, pitch: f32) -> Self {
Rotation { yaw, pitch }
#[must_use]
pub const fn new(yaw: f32, pitch: f32) -> Self {
Self { yaw, pitch }
}
}
@ -80,8 +81,9 @@ pub struct Location {
}
impl Location {
pub fn new(world: Uuid, x: f64, y: f64, z: f64, rotation: Option<Rotation>) -> Self {
Location {
#[must_use]
pub const fn new(world: Uuid, x: f64, y: f64, z: f64, rotation: Option<Rotation>) -> Self {
Self {
world,
x,
y,

View File

@ -23,6 +23,7 @@ pub struct JvmWorker {
}
impl JvmWorker {
#[must_use]
pub fn new(command_rx: mpsc::Receiver<JvmCommand>) -> Self {
Self {
command_rx,
@ -61,13 +62,13 @@ impl JvmWorker {
} => {
let _ = match read_configs_from_jar(&plugin_path) {
Ok(configs) => match configs {
(Some(paper_plugin_config), spigot @ _) => {
(Some(paper_plugin_config), spigot) => {
match self.plugin_manager.load_paper_plugin(
&plugin_path,
&paper_plugin_config,
&spigot,
) {
Ok(_) => {
Ok(()) => {
respond_to.send(LoadPluginResult::SuccessfullyLoadedPaper)
}
Err(err) => respond_to
@ -79,7 +80,7 @@ impl JvmWorker {
.plugin_manager
.load_spigot_plugin(&plugin_path, &spigot)
{
Ok(_) => {
Ok(()) => {
respond_to.send(LoadPluginResult::SuccessfullyLoadedSpigot)
}
Err(err) => respond_to
@ -151,7 +152,7 @@ impl JvmWorker {
{
Ok(c) => c,
Err(e) => {
log::error!("Failed to fire event: {}", e);
log::error!("Failed to fire event: {e}");
false
}
};
@ -201,7 +202,7 @@ impl JvmWorker {
}
fn initialize_jvm(&mut self, j4rs_path: &PathBuf) -> anyhow::Result<()> {
log::info!("Initializing JVM with path: {:?}", j4rs_path);
log::info!("Initializing JVM with path: {j4rs_path:?}");
let jvm = JvmBuilder::new().with_base_path(j4rs_path).build()?;

View File

@ -51,10 +51,10 @@ pub extern "C" fn rust_set_abilities(
server_abilities.invulnerable = (*abilities).invulnerable;
server_abilities.walk_speed = (*abilities).walk_speed;
}
})
});
});
let player = player.clone();
let player = player;
ctx.runtime.spawn(async move {
player.send_abilities_update().await;
});

View File

@ -31,16 +31,12 @@ pub extern "C" fn rust_register_event(
};
log::info!(
"Plugin '{}' registering listener for '{}' (priority={:?}, blocking={})",
plugin_name,
event_type,
priority,
blocking
"Plugin '{plugin_name}' registering listener for '{event_type}' (priority={priority:?}, blocking={blocking})"
);
let command_tx = ctx.command_tx.clone();
let context = ctx.plugin_context.clone();
let event_type_owned = event_type.clone();
let event_type_owned = event_type;
tokio::task::block_in_place(|| {
ctx.runtime.block_on(async {
@ -62,8 +58,7 @@ pub extern "C" fn rust_register_event(
}
_ => {
log::warn!(
"Unsupported Bukkit event type '{}' from plugin '{}'",
event_type_owned, plugin_name
"Unsupported Bukkit event type '{event_type_owned}' from plugin '{plugin_name}'"
);
}
}
@ -83,47 +78,38 @@ pub extern "C" fn rust_call_event(
return false;
};
log::debug!(
"Java calling event '{}' with data: {}",
event_type,
event_data_json
);
log::debug!("Java calling event '{event_type}' with data: {event_data_json}");
let event_data: serde_json::Value = match serde_json::from_str(&event_data_json) {
Ok(v) => v,
Err(e) => {
log::error!("Failed to parse event data JSON: {}", e);
log::error!("Failed to parse event data JSON: {e}");
return false;
}
};
let context = ctx.plugin_context.clone();
let handled = tokio::task::block_in_place(|| {
tokio::task::block_in_place(|| {
ctx.runtime.block_on(async {
match event_type.as_str() {
"org.bukkit.event.player.PlayerJoinEvent" => {
let player_uuid_str = event_data["playerUuid"].as_str().unwrap_or("");
let join_message_str = event_data["joinMessage"].as_str().unwrap_or("");
if let Ok(uuid) = uuid::Uuid::parse_str(player_uuid_str) {
if let Some(player) = context.server.get_player_by_uuid(uuid) {
let pumpkin_event = PlayerJoinEvent::new(
player,
TextComponent::from_legacy_string(join_message_str),
);
context.server.plugin_manager.fire(pumpkin_event).await;
return true;
}
}
false
}
_ => {
log::warn!("Unknown event type for Pumpkin: {}", event_type);
false
if event_type.as_str() == "org.bukkit.event.player.PlayerJoinEvent" {
let player_uuid_str = event_data["playerUuid"].as_str().unwrap_or("");
let join_message_str = event_data["joinMessage"].as_str().unwrap_or("");
if let Ok(uuid) = uuid::Uuid::parse_str(player_uuid_str)
&& let Some(player) = context.server.get_player_by_uuid(uuid)
{
let pumpkin_event = PlayerJoinEvent::new(
player,
TextComponent::from_legacy_string(join_message_str),
);
context.server.plugin_manager.fire(pumpkin_event).await;
return true;
}
false
} else {
log::warn!("Unknown event type for Pumpkin: {event_type}");
false
}
})
});
handled
})
}

View File

@ -12,11 +12,12 @@ struct Registry {
}
impl Registry {
pub fn new(entries: Vec<Value>, tags: HashMap<String, Vec<String>>) -> Self {
Registry { entries, tags }
pub const fn new(entries: Vec<Value>, tags: HashMap<String, Vec<String>>) -> Self {
Self { entries, tags }
}
}
#[must_use]
pub extern "C" fn rust_get_registry_data(registry_name: *const c_char) -> *const c_char {
let name = get_string(registry_name);
@ -44,7 +45,7 @@ pub extern "C" fn rust_get_registry_data(registry_name: *const c_char) -> *const
let json_str = match serde_json::to_string(&registry) {
Ok(json_str) => json_str,
Err(err) => {
log::error!("Failed to serialize registry: {}", err);
log::error!("Failed to serialize registry: {err}");
return std::ptr::null();
}
};
@ -52,8 +53,8 @@ pub extern "C" fn rust_get_registry_data(registry_name: *const c_char) -> *const
match CString::new(json_str) {
Ok(cstring) => cstring.into_raw(),
Err(err) => {
log::error!("Failed to convert registry string to CString: {}", err);
return std::ptr::null_mut();
log::error!("Failed to convert registry string to CString: {err}");
std::ptr::null_mut()
}
}
}

View File

@ -1,5 +1,6 @@
use std::ffi::{CStr, c_char};
#[must_use]
pub fn get_string(str_ptr: *const c_char) -> String {
unsafe { CStr::from_ptr(str_ptr).to_string_lossy().into_owned() }
}

View File

@ -20,8 +20,15 @@ pub struct CommandManager {
command_map: Option<Instance>,
}
impl Default for CommandManager {
fn default() -> Self {
Self::new()
}
}
impl CommandManager {
pub fn new() -> Self {
#[must_use]
pub const fn new() -> Self {
Self { command_map: None }
}
@ -66,7 +73,7 @@ impl CommandManager {
let command_map = match self.command_map {
Some(ref command_map) => command_map,
None => match self.init(jvm) {
Ok(_) => self.command_map.as_ref().unwrap(),
Ok(()) => self.command_map.as_ref().unwrap(),
Err(_) => return Ok(None),
},
};
@ -145,7 +152,7 @@ impl CommandManager {
let command_map = match self.command_map {
Some(ref command_map) => command_map,
None => match self.init(jvm) {
Ok(_) => self.command_map.as_ref().unwrap(),
Ok(()) => self.command_map.as_ref().unwrap(),
Err(err) => return Err(err),
},
};
@ -164,7 +171,7 @@ impl CommandManager {
log::info!("Registering Bukkit command: {}", &cmd_name);
{
let cmd_lock = j_plugin_cmd.lock().unwrap();
let j_plugin_cmd_owned = jvm.clone_instance(&*cmd_lock)?;
let j_plugin_cmd_owned = jvm.clone_instance(&cmd_lock)?;
jvm.invoke(
command_map,
"register",
@ -189,7 +196,7 @@ impl CommandManager {
// } else {
// format!("patchbukkit:{}", cmd_name) // TODO
// };
let permission = format!("patchbukkit:{}", cmd_name);
let permission = format!("patchbukkit:{cmd_name}");
context
.register_permission(Permission::new(
@ -214,7 +221,7 @@ impl CommandManager {
let command_map = match self.command_map {
Some(ref command_map) => command_map,
None => match self.init(jvm) {
Ok(_) => self.command_map.as_ref().unwrap(),
Ok(()) => self.command_map.as_ref().unwrap(),
Err(err) => return Err(err),
},
};

View File

@ -8,8 +8,15 @@ use crate::events::handler::PatchBukkitEvent;
pub struct EventManager {}
impl Default for EventManager {
fn default() -> Self {
Self::new()
}
}
impl EventManager {
pub fn new() -> Self {
#[must_use]
pub const fn new() -> Self {
Self {}
}
@ -29,7 +36,7 @@ impl EventManager {
player,
join_message,
} => {
EventManager::register_player(jvm, &patch_server, &player, &server)?;
Self::register_player(jvm, &patch_server, &player, &server)?;
jvm.invoke_static(
"org.patchbukkit.events.PatchBukkitEventFactory",
"createPlayerJoinEvent",
@ -57,16 +64,17 @@ impl EventManager {
&[InvocationArg::from(jvm.clone_instance(&j_event)?)],
)?)?;
let cancelled = match is_cancellable {
true => match jvm.invoke(
let cancelled = if is_cancellable {
match jvm.invoke(
&jvm.clone_instance(&j_event)?,
"isCancelled",
InvocationArg::empty(),
) {
Ok(instance) => jvm.to_rust::<bool>(instance).unwrap_or(false),
Err(_) => false,
},
false => false,
}
} else {
false
};
Ok(cancelled)
@ -84,7 +92,7 @@ impl EventManager {
"fromString",
&[InvocationArg::try_from(player.gameprofile.id.to_string())?],
)
.map_err(|e| format!("Failed to create Java UUID: {}", e))
.map_err(|e| format!("Failed to create Java UUID: {e}"))
.unwrap();
let j_player = jvm.create_instance(
@ -105,10 +113,10 @@ impl EventManager {
.into_primitive()
.unwrap()],
)?;
};
}
jvm.invoke(
&patch_server,
patch_server,
"registerPlayer",
&[InvocationArg::from(j_player)],
)?;

View File

@ -31,6 +31,7 @@ pub enum PluginState {
Errored,
}
#[expect(clippy::large_enum_variant)]
#[derive(Debug)]
pub enum PluginType {
Paper(PaperPluginData),
@ -85,7 +86,14 @@ pub struct PluginManager {
pub plugins: HashMap<String, Plugin>,
}
impl Default for PluginManager {
fn default() -> Self {
Self::new()
}
}
impl PluginManager {
#[must_use]
pub fn new() -> Self {
Self {
plugins: HashMap::new(),
@ -110,13 +118,21 @@ impl PluginManager {
paper_plugin_config: &str,
spigot_plugin_config: &Option<String>,
) -> Result<()> {
let parsed_paper_plugin = PaperPluginYml::from_str(paper_plugin_config)?;
let parsed_paper_plugin = PaperPluginYml::parse(paper_plugin_config)?;
let parsed_spigot_plugin = match spigot_plugin_config {
Some(config) => Some(SpigotPluginYml::from_str(config)?),
Some(config) => Some(SpigotPluginYml::parse(config)?),
None => None,
};
let (spigot_depends, spigot_soft_depends, spigot_load_before, spigot_load_after, spigot_provides, spigot_libraries, spigot_skip_libraries) = match &parsed_spigot_plugin {
let (
spigot_depends,
spigot_soft_depends,
spigot_load_before,
spigot_load_after,
spigot_provides,
spigot_libraries,
spigot_skip_libraries,
) = match &parsed_spigot_plugin {
Some(config) => (
normalize_names(config.depend.clone()),
normalize_names(config.softdepend.clone()),
@ -126,7 +142,15 @@ impl PluginManager {
config.libraries.clone().unwrap_or_default(),
config.paper_skip_libraries.unwrap_or(false),
),
None => (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new(), false),
None => (
Vec::new(),
Vec::new(),
Vec::new(),
Vec::new(),
Vec::new(),
Vec::new(),
false,
),
};
let mut paper_depends = Vec::new();
@ -181,10 +205,11 @@ impl PluginManager {
let classpath_deps = paper_classpath;
let commands = match &parsed_spigot_plugin {
Some(config) => config.commands.clone().unwrap_or_default(),
None => HashMap::new(),
};
let commands = parsed_spigot_plugin
.as_ref()
.map_or_else(HashMap::new, |config| {
config.commands.clone().unwrap_or_default()
});
let libraries = if spigot_skip_libraries {
Vec::new()
@ -231,7 +256,7 @@ impl PluginManager {
jar_path: P,
spigot_plugin_config: &str,
) -> Result<()> {
let parsed_spigot_plugin = SpigotPluginYml::from_str(spigot_plugin_config)?;
let parsed_spigot_plugin = SpigotPluginYml::parse(spigot_plugin_config)?;
let depends = normalize_names(parsed_spigot_plugin.depend.clone());
let soft_depends = normalize_names(parsed_spigot_plugin.softdepend.clone());
@ -247,7 +272,7 @@ impl PluginManager {
let version = parsed_spigot_plugin.version.clone();
let main_class = parsed_spigot_plugin.main.clone();
let spigot_config = parsed_spigot_plugin.clone();
let commands = parsed_spigot_plugin.commands.clone().unwrap_or_default();
let commands = parsed_spigot_plugin.commands.unwrap_or_default();
let plugin = Plugin {
name,
@ -275,18 +300,18 @@ impl PluginManager {
}
pub fn enable_all_plugins(&mut self, jvm: &Jvm) -> Result<()> {
// IMPORANT: enable trough PluginManager not manually
// IMPORTANT: enable trough PluginManager not manually
let plugin_manager = jvm.invoke_static(
"org.bukkit.Bukkit",
"getPluginManager",
InvocationArg::empty(),
)?;
for (_plugin_name, plugin) in &mut self.plugins {
for plugin in self.plugins.values_mut() {
if plugin.instance.is_none() {
continue;
}
let plugin_instance = plugin.instance.as_ref().unwrap();
let plugin_instance = jvm.clone_instance(&plugin_instance).unwrap();
let plugin_instance = jvm.clone_instance(plugin_instance).unwrap();
let result = jvm.invoke(
&plugin_manager,
@ -318,12 +343,12 @@ impl PluginManager {
"getPluginManager",
InvocationArg::empty(),
)?;
for (_plugin_name, plugin) in &mut self.plugins {
for plugin in self.plugins.values_mut() {
if plugin.instance.is_none() {
continue;
}
let plugin_instance = plugin.instance.as_ref().unwrap();
let plugin_instance = jvm.clone_instance(&plugin_instance).unwrap();
let plugin_instance = jvm.clone_instance(plugin_instance).unwrap();
let result = jvm.invoke(
&plugin_manager,
@ -362,7 +387,7 @@ impl PluginManager {
let (classpath, libraries) = match self.plugins.get(&plugin_key) {
Some(plugin) => (
self.classpath_string_for(plugin),
self.library_string_for(plugin),
Self::library_string_for(plugin),
),
None => continue,
};
@ -386,16 +411,16 @@ impl PluginManager {
for (cmd_name, cmd_data) in &plugin.commands {
match command_manager
.register_command(
&jvm,
jvm,
server,
&plugin,
plugin,
cmd_name.clone(),
cmd_data,
command_tx.clone(),
)
.await
{
Ok(_) => (),
Ok(()) => (),
Err(e) => {
log::error!(
"Failed to register command {} for plugin {}: {:?}",
@ -438,7 +463,9 @@ impl PluginManager {
if provide.is_empty() {
continue;
}
provides_map.entry(provide.clone()).or_insert_with(|| key.clone());
provides_map
.entry(provide.clone())
.or_insert_with(|| key.clone());
}
}
@ -470,8 +497,7 @@ impl PluginManager {
}
let mut edges: HashMap<String, HashSet<String>> = HashMap::new();
let mut indegree: HashMap<String, usize> =
active.iter().map(|k| (k.clone(), 0)).collect();
let mut indegree: HashMap<String, usize> = active.iter().map(|k| (k.clone(), 0)).collect();
for (key, plugin) in &self.plugins {
if !active.contains(key) {
@ -479,15 +505,12 @@ impl PluginManager {
}
let mut before = Vec::new();
for dep in plugin
.depends
.iter()
.chain(plugin.soft_depends.iter())
{
if let Some(resolved) = self.resolve_dependency_name(dep, &provides_map) {
if resolved != *key && active.contains(&resolved) {
before.push(resolved);
}
for dep in plugin.depends.iter().chain(plugin.soft_depends.iter()) {
if let Some(resolved) = self.resolve_dependency_name(dep, &provides_map)
&& resolved != *key
&& active.contains(&resolved)
{
before.push(resolved);
}
}
@ -496,18 +519,20 @@ impl PluginManager {
}
for target in &plugin.load_before {
if let Some(resolved) = self.resolve_dependency_name(target, &provides_map) {
if resolved != *key && active.contains(&resolved) {
add_edge(&mut edges, &mut indegree, key, &resolved);
}
if let Some(resolved) = self.resolve_dependency_name(target, &provides_map)
&& resolved != *key
&& active.contains(&resolved)
{
add_edge(&mut edges, &mut indegree, key, &resolved);
}
}
for target in &plugin.load_after {
if let Some(resolved) = self.resolve_dependency_name(target, &provides_map) {
if resolved != *key && active.contains(&resolved) {
add_edge(&mut edges, &mut indegree, &resolved, key);
}
if let Some(resolved) = self.resolve_dependency_name(target, &provides_map)
&& resolved != *key
&& active.contains(&resolved)
{
add_edge(&mut edges, &mut indegree, &resolved, key);
}
}
}
@ -541,10 +566,8 @@ impl PluginManager {
}
if order.len() != active.len() {
let mut remaining: Vec<String> = active
.into_iter()
.filter(|k| !order.contains(k))
.collect();
let mut remaining: Vec<String> =
active.into_iter().filter(|k| !order.contains(k)).collect();
remaining.sort();
log::warn!(
"Detected plugin dependency cycle(s). Loading remaining plugins in name order: {}",
@ -567,23 +590,25 @@ impl PluginManager {
if provide.is_empty() {
continue;
}
provides_map.entry(provide.clone()).or_insert_with(|| key.clone());
provides_map
.entry(provide.clone())
.or_insert_with(|| key.clone());
}
}
let mut paths = Vec::new();
for dep in &plugin.classpath_deps {
if let Some(resolved) = self.resolve_dependency_name(dep, &provides_map) {
if let Some(dep_plugin) = self.plugins.get(&resolved) {
paths.push(dep_plugin.path.to_string_lossy().to_string());
}
if let Some(resolved) = self.resolve_dependency_name(dep, &provides_map)
&& let Some(dep_plugin) = self.plugins.get(&resolved)
{
paths.push(dep_plugin.path.to_string_lossy().to_string());
}
}
paths.join(";")
}
fn library_string_for(&self, plugin: &Plugin) -> String {
fn library_string_for(plugin: &Plugin) -> String {
if plugin.libraries.is_empty() {
return String::new();
}
@ -640,9 +665,9 @@ fn add_edge(
return;
}
let entry = edges.entry(from.to_string()).or_default();
if entry.insert(to.to_string()) {
if let Some(count) = indegree.get_mut(to) {
*count += 1;
}
if entry.insert(to.to_string())
&& let Some(count) = indegree.get_mut(to)
{
*count += 1;
}
}

View File

@ -18,17 +18,17 @@ pub fn cleanup_stale_files(j4rs_folder: &PathBuf) {
for entry in walkdir::WalkDir::new(j4rs_folder)
.into_iter()
.filter_map(|e| e.ok())
.filter_map(std::result::Result::ok)
.filter(|e| e.file_type().is_file())
{
let path = entry.path();
if let Ok(rel_path) = path.strip_prefix(j4rs_folder) {
if !allowed.contains(rel_path) {
log::warn!("Removing stale j4rs file: {}", rel_path.display());
if let Err(e) = fs::remove_file(path) {
log::error!("Failed to remove stale file {}: {}", path.display(), e);
}
if let Ok(rel_path) = path.strip_prefix(j4rs_folder)
&& !allowed.contains(rel_path)
{
log::warn!("Removing stale j4rs file: {}", rel_path.display());
if let Err(e) = fs::remove_file(path) {
log::error!("Failed to remove stale file {}: {}", path.display(), e);
}
}
}
@ -39,11 +39,11 @@ pub fn sync_embedded_resources(j4rs_folder: &Path) -> Result<(), String> {
let resource_path = j4rs_folder.join(resource_path_str.to_string());
let resource = Resources::get(&resource_path_str).unwrap();
if !resource_path.exists() {
if resource_path.exists() {
update_resource_if_changed(&resource_path, &resource.data)?;
} else {
log::info!("Extracting new resource: {}", resource_path.display());
write_resource(&resource_path, &resource.data)?;
} else {
update_resource_if_changed(&resource_path, &resource.data)?;
}
}
Ok(())
@ -62,9 +62,7 @@ fn write_resource(path: &Path, data: &[u8]) -> Result<(), String> {
fn update_resource_if_changed(path: &Path, new_data: &[u8]) -> Result<(), String> {
// Quick check: If file sizes differ, it's definitely changed, TODO: use Hash ?
let metadata = fs::metadata(path).ok();
let size_matches = metadata
.map(|m| m.len() == new_data.len() as u64)
.unwrap_or(false);
let size_matches = metadata.is_some_and(|m| m.len() == new_data.len() as u64);
if !size_matches || fs::read(path).map_err(|e| e.to_string())? != new_data {
log::debug!("Updating changed resource: {}", path.display());

View File

@ -1,3 +1,5 @@
#![allow(clippy::async_yields_async)]
use std::sync::Arc;
use pumpkin::plugin::Context;
@ -24,7 +26,7 @@ use crate::java::jvm::{
worker::JvmWorker,
};
async fn on_load_inner(plugin: &mut PatchBukkitPlugin, server: Arc<Context>) -> Result<(), String> {
async fn on_load_inner(plugin: &PatchBukkitPlugin, server: Arc<Context>) -> Result<(), String> {
server.init_log();
log::info!("Starting PatchBukkit");
@ -53,37 +55,37 @@ async fn on_load_inner(plugin: &mut PatchBukkitPlugin, server: Arc<Context>) ->
match rx.await {
Ok(result) => match result {
LoadPluginResult::SuccessfullyLoadedSpigot => {
log::info!("Loaded Spigot plugin from JAR `{}`", jar_path.display())
log::info!("Loaded Spigot plugin from JAR `{}`", jar_path.display());
}
LoadPluginResult::SuccessfullyLoadedPaper => {
log::info!("Loaded Paper plugin from JAR `{}`", jar_path.display())
log::info!("Loaded Paper plugin from JAR `{}`", jar_path.display());
}
LoadPluginResult::FailedToLoadSpigotPlugin(error) => {
log::error!(
"Failed to load Spigot plugin from JAR `{}` with error: {}",
jar_path.display(),
error
)
);
}
LoadPluginResult::FailedToLoadPaperPlugin(error) => {
log::error!(
"Failed to load Paper plugin from JAR `{}` with error: {}",
jar_path.display(),
error
)
);
}
LoadPluginResult::FailedToReadConfigurationFile(error) => {
log::error!(
"Failed to read configuration file from JAR `{}`: {}",
jar_path.display(),
error
)
);
}
LoadPluginResult::NoConfigurationFile => {
log::warn!(
"No configuration file found for plugin from JAR `{}`",
jar_path.display()
)
);
}
},
Err(e) => log::error!(
@ -110,10 +112,10 @@ async fn on_load_inner(plugin: &mut PatchBukkitPlugin, server: Arc<Context>) ->
command_tx: plugin.command_tx.clone(),
})
.await
.map_err(|e| format!("Failed to send command to initialize J4RS: {}", e))?;
.map_err(|e| format!("Failed to send command to initialize J4RS: {e}"))?;
rx.await
.map_err(|e| format!("Unable to receive response from J4RS initialization: {}", e))?
.map_err(|e| format!("Failed to initialize all plugins: {}", e))?;
.map_err(|e| format!("Unable to receive response from J4RS initialization: {e}"))?
.map_err(|e| format!("Failed to initialize all plugins: {e}"))?;
}
{
@ -126,10 +128,10 @@ async fn on_load_inner(plugin: &mut PatchBukkitPlugin, server: Arc<Context>) ->
command_tx: plugin.command_tx.clone(),
})
.await
.map_err(|e| format!("Failed to send command to instantiate plugins: {}", e))?;
.map_err(|e| format!("Failed to send command to instantiate plugins: {e}"))?;
rx.await
.map_err(|e| format!("Unable to receive response from instantiate plugins: {}", e))?
.map_err(|e| format!("Failed to instantiate all plugins: {}", e))?;
.map_err(|e| format!("Unable to receive response from instantiate plugins: {e}"))?
.map_err(|e| format!("Failed to instantiate all plugins: {e}"))?;
}
{
@ -138,29 +140,26 @@ async fn on_load_inner(plugin: &mut PatchBukkitPlugin, server: Arc<Context>) ->
.command_tx
.send(JvmCommand::EnableAllPlugins { respond_to: tx })
.await
.map_err(|e| format!("Failed to send command to enable all plugins: {}", e))?;
.map_err(|e| format!("Failed to send command to enable all plugins: {e}"))?;
rx.await
.map_err(|e| format!("Unable to receive response from enable all plugins: {}", e))?
.map_err(|e| format!("Failed to enable all plugins: {}", e))?;
.map_err(|e| format!("Unable to receive response from enable all plugins: {e}"))?
.map_err(|e| format!("Failed to enable all plugins: {e}"))?;
};
Ok(())
}
async fn on_unload_inner(
plugin: &mut PatchBukkitPlugin,
_server: Arc<Context>,
) -> Result<(), String> {
async fn on_unload_inner(plugin: &PatchBukkitPlugin, _server: Arc<Context>) -> Result<(), String> {
{
let (tx, rx) = oneshot::channel();
plugin
.command_tx
.send(JvmCommand::DisableAllPlugins { respond_to: tx })
.await
.map_err(|e| format!("Failed to send command to disable all plugins: {}", e))?;
.map_err(|e| format!("Failed to send command to disable all plugins: {e}"))?;
rx.await
.map_err(|e| format!("Unable to receive response from disable all plugins: {}", e))?
.map_err(|e| format!("Failed to disable all plugins: {}", e))?;
.map_err(|e| format!("Unable to receive response from disable all plugins: {e}"))?
.map_err(|e| format!("Failed to disable all plugins: {e}"))?;
}
{
@ -169,10 +168,10 @@ async fn on_unload_inner(
.command_tx
.send(JvmCommand::Shutdown { respond_to: tx })
.await
.map_err(|e| format!("Failed to send command to shutdown: {}", e))?;
.map_err(|e| format!("Failed to send command to shutdown: {e}"))?;
rx.await
.map_err(|e| format!("Unable to receive response from shutdown: {}", e))?
.map_err(|e| format!("Failed to shutdown: {}", e))?;
.map_err(|e| format!("Unable to receive response from shutdown: {e}"))?
.map_err(|e| format!("Failed to shutdown: {e}"))?;
}
Ok(())
@ -194,6 +193,7 @@ pub struct PatchBukkitPlugin {
}
impl PatchBukkitPlugin {
#[must_use]
pub fn new() -> Self {
let (tx, rx) = mpsc::channel(100);
@ -208,7 +208,7 @@ impl PatchBukkitPlugin {
jvm_thread_task(rx);
})
.unwrap();
PatchBukkitPlugin { command_tx: tx }
Self { command_tx: tx }
}
}