Fix compatibility with current Pumpkin nightlies
This commit is contained in:
parent
f7ef6e3378
commit
43ba5b50ae
25
.github/workflows/rust.yml
vendored
25
.github/workflows/rust.yml
vendored
@ -20,10 +20,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
java-version: "25"
|
java-version: "25"
|
||||||
distribution: "temurin"
|
distribution: "temurin"
|
||||||
- name: Install Protoc
|
|
||||||
uses: arduino/setup-protoc@v3
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v5
|
uses: gradle/actions/setup-gradle@v5
|
||||||
- name: Build JAR with Gradle
|
- name: Build JAR with Gradle
|
||||||
@ -82,10 +78,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: patchbukkit-jar
|
name: patchbukkit-jar
|
||||||
path: java/patchbukkit/build/libs/
|
path: java/patchbukkit/build/libs/
|
||||||
- name: Install Protoc
|
- name: Sync Pumpkin dependencies
|
||||||
uses: arduino/setup-protoc@v3
|
run: cargo update -p pumpkin -p pumpkin-api-macros -p pumpkin-data -p pumpkin-protocol -p pumpkin-util
|
||||||
with:
|
working-directory: rust
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Clippy (debug)
|
- name: Clippy (debug)
|
||||||
run: cargo clippy --all-targets --all-features
|
run: cargo clippy --all-targets --all-features
|
||||||
working-directory: rust
|
working-directory: rust
|
||||||
@ -108,10 +103,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: patchbukkit-jar
|
name: patchbukkit-jar
|
||||||
path: java/patchbukkit/build/libs/
|
path: java/patchbukkit/build/libs/
|
||||||
- name: Install Protoc
|
- name: Sync Pumpkin dependencies
|
||||||
uses: arduino/setup-protoc@v3
|
run: cargo update -p pumpkin -p pumpkin-api-macros -p pumpkin-data -p pumpkin-protocol -p pumpkin-util
|
||||||
with:
|
working-directory: rust
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Clippy (release)
|
- name: Clippy (release)
|
||||||
run: cargo clippy --release --all-targets --all-features
|
run: cargo clippy --release --all-targets --all-features
|
||||||
working-directory: rust
|
working-directory: rust
|
||||||
@ -142,10 +136,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: patchbukkit-jar
|
name: patchbukkit-jar
|
||||||
path: java/patchbukkit/build/libs/
|
path: java/patchbukkit/build/libs/
|
||||||
- name: Install Protoc
|
- name: Sync Pumpkin dependencies
|
||||||
uses: arduino/setup-protoc@v3
|
run: cargo update -p pumpkin -p pumpkin-api-macros -p pumpkin-data -p pumpkin-protocol -p pumpkin-util
|
||||||
with:
|
working-directory: rust
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build Release
|
- name: Build Release
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@ -18,6 +18,7 @@ If you wish to contribute to PatchBukkit, follow the following steps:
|
|||||||
> Your PumpkinMC server must be built with the same nightly toolchain as PatchBukkit.
|
> Your PumpkinMC server must be built with the same nightly toolchain as PatchBukkit.
|
||||||
|
|
||||||
1. Run `./build.sh`
|
1. Run `./build.sh`
|
||||||
2. Copy the `target/debug/patchbukkit` binary to the `plugins` directory in your PumpkinMC server.
|
2. Copy the generated native library from `rust/target/debug/` (or `rust/target/release/`) to your PumpkinMC `plugins/` directory.
|
||||||
|
3. Start Pumpkin once to create the `patchbukkit/` directory in your server root, then place your `.jar` plugins in `patchbukkit/patchbukkit-plugins/`.
|
||||||
|
|
||||||
There is also an [architecture guide](https://github.com/Pumpkin-MC/PatchBukkit/blob/master/ARCHITECTURE.md) available.
|
There is also an [architecture guide](https://github.com/Pumpkin-MC/PatchBukkit/blob/master/ARCHITECTURE.md) available.
|
||||||
|
|||||||
1
build.sh
1
build.sh
@ -2,4 +2,5 @@ cd java
|
|||||||
./gradlew jar
|
./gradlew jar
|
||||||
cd ..
|
cd ..
|
||||||
cd rust
|
cd rust
|
||||||
|
cargo update -p pumpkin -p pumpkin-api-macros -p pumpkin-data -p pumpkin-protocol -p pumpkin-util
|
||||||
cargo build
|
cargo build
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=120000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@ -45,7 +45,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("io.papermc.paper:paper-api:1.21.11-R0.1-SNAPSHOT")
|
implementation("io.papermc.paper:paper-api:1.21.11-R0.1-SNAPSHOT")
|
||||||
implementation("net.sf.jopt-simple:jopt-simple:6.0-alpha-3")
|
implementation("net.sf.jopt-simple:jopt-simple:6.0-alpha-3")
|
||||||
implementation("io.github.astonbitecode:j4rs:0.24.0")
|
implementation("io.github.astonbitecode:j4rs:0.24.0")
|
||||||
implementation("org.apache.maven:maven-resolver-provider:3.9.6")
|
implementation("org.apache.maven:maven-resolver-provider:3.9.6")
|
||||||
@ -69,3 +69,20 @@ tasks.withType<JavaCompile> {
|
|||||||
"-Xlint:-deprecation"
|
"-Xlint:-deprecation"
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.named<Jar>("jar") {
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
dependsOn(configurations.runtimeClasspath)
|
||||||
|
|
||||||
|
from({
|
||||||
|
configurations.runtimeClasspath.get()
|
||||||
|
.filter { it.name.endsWith(".jar") }
|
||||||
|
.map { zipTree(it) }
|
||||||
|
})
|
||||||
|
|
||||||
|
exclude(
|
||||||
|
"META-INF/*.SF",
|
||||||
|
"META-INF/*.DSA",
|
||||||
|
"META-INF/*.RSA"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
1977
rust/Cargo.lock
generated
1977
rust/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,8 @@
|
|||||||
name = "patchbukkit"
|
name = "patchbukkit"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
authors = ["PumpkinMC Contributors"]
|
||||||
|
description = "Compatibility layer for running Bukkit, Spigot, and Paper plugins on Pumpkin"
|
||||||
|
|
||||||
build = "build/main.rs"
|
build = "build/main.rs"
|
||||||
|
|
||||||
@ -41,6 +43,7 @@ j4rs = { version = "0.24", artifact = "cdylib", lib = true }
|
|||||||
env_logger = "0.11.8"
|
env_logger = "0.11.8"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
prost-build = "0.14"
|
prost-build = "0.14"
|
||||||
|
protoc-bin-vendored = "3"
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
use crate::{java::setup_java, protobufs::setup_protobufs};
|
use crate::{java::setup_java, protobufs::setup_protobufs, pumpkin::setup_pumpkin_build_info};
|
||||||
use std::{error::Error, path::PathBuf};
|
use std::{error::Error, path::PathBuf};
|
||||||
|
|
||||||
pub mod java;
|
pub mod java;
|
||||||
pub mod protobufs;
|
pub mod protobufs;
|
||||||
|
pub mod pumpkin;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
println!("cargo::rerun-if-changed=rust/src/build.rs");
|
println!("cargo::rerun-if-changed=rust/src/build.rs");
|
||||||
@ -11,6 +12,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
let base = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
|
let base = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||||
|
|
||||||
|
setup_pumpkin_build_info(&base);
|
||||||
setup_protobufs(base.clone());
|
setup_protobufs(base.clone());
|
||||||
setup_java(base);
|
setup_java(base);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -164,6 +164,13 @@ fn to_snake_case(s: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_protobufs(base: PathBuf) {
|
pub fn setup_protobufs(base: PathBuf) {
|
||||||
|
let protoc = protoc_bin_vendored::protoc_bin_path()
|
||||||
|
.expect("Failed to locate vendored protoc binary for PatchBukkit");
|
||||||
|
// Avoid requiring a host-wide protoc installation for local and CI builds.
|
||||||
|
unsafe {
|
||||||
|
std::env::set_var("PROTOC", protoc);
|
||||||
|
}
|
||||||
|
|
||||||
let proto_path = base.parent().unwrap().join("proto");
|
let proto_path = base.parent().unwrap().join("proto");
|
||||||
let paths: Vec<_> = glob(&format!("{}/**/*.proto", proto_path.display()))
|
let paths: Vec<_> = glob(&format!("{}/**/*.proto", proto_path.display()))
|
||||||
.expect("Failed to read glob pattern")
|
.expect("Failed to read glob pattern")
|
||||||
|
|||||||
64
rust/build/pumpkin.rs
Normal file
64
rust/build/pumpkin.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use std::{fs, path::Path};
|
||||||
|
|
||||||
|
fn extract_git_revision(source: &str) -> Option<String> {
|
||||||
|
source.rsplit('#').next().and_then(|revision| {
|
||||||
|
let trimmed = revision.trim();
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(trimmed.to_string())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_pumpkin_build_info(base: &Path) {
|
||||||
|
let lock_path = base.join("Cargo.lock");
|
||||||
|
let lock_contents =
|
||||||
|
fs::read_to_string(&lock_path).expect("Failed to read Cargo.lock for Pumpkin build info");
|
||||||
|
|
||||||
|
let mut in_pumpkin_package = false;
|
||||||
|
let mut pumpkin_version: Option<String> = None;
|
||||||
|
let mut pumpkin_revision: Option<String> = None;
|
||||||
|
|
||||||
|
for line in lock_contents.lines() {
|
||||||
|
let trimmed = line.trim();
|
||||||
|
|
||||||
|
if trimmed == "[[package]]" {
|
||||||
|
if in_pumpkin_package {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
in_pumpkin_package = false;
|
||||||
|
pumpkin_version = None;
|
||||||
|
pumpkin_revision = None;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if trimmed == r#"name = "pumpkin""# {
|
||||||
|
in_pumpkin_package = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !in_pumpkin_package {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(version) = trimmed.strip_prefix(r#"version = ""#) {
|
||||||
|
pumpkin_version = Some(version.trim_end_matches('"').to_string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(source) = trimmed.strip_prefix(r#"source = ""#) {
|
||||||
|
let source = source.trim_end_matches('"');
|
||||||
|
pumpkin_revision = extract_git_revision(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let pumpkin_version = pumpkin_version.unwrap_or_else(|| "unknown".to_string());
|
||||||
|
let pumpkin_revision = pumpkin_revision.unwrap_or_else(|| "unknown".to_string());
|
||||||
|
let pumpkin_revision_short = pumpkin_revision.chars().take(7).collect::<String>();
|
||||||
|
|
||||||
|
println!("cargo::rustc-env=PATCHBUKKIT_PUMPKIN_VERSION={pumpkin_version}");
|
||||||
|
println!("cargo::rustc-env=PATCHBUKKIT_PUMPKIN_REVISION={pumpkin_revision}");
|
||||||
|
println!("cargo::rustc-env=PATCHBUKKIT_PUMPKIN_REVISION_SHORT={pumpkin_revision_short}");
|
||||||
|
println!("cargo::rerun-if-changed={}", lock_path.display());
|
||||||
|
}
|
||||||
@ -53,13 +53,13 @@ impl ArgumentConsumer for AnyCommandNode {
|
|||||||
let first_word_opt = args.pop();
|
let first_word_opt = args.pop();
|
||||||
|
|
||||||
let mut msg = match first_word_opt {
|
let mut msg = match first_word_opt {
|
||||||
Some(word) => word.to_string(),
|
Some(word) => word.value.to_string(),
|
||||||
None => return Box::pin(async { None }),
|
None => return Box::pin(async { None }),
|
||||||
};
|
};
|
||||||
|
|
||||||
while let Some(word) = args.pop() {
|
while let Some(word) = args.pop() {
|
||||||
msg.push(' ');
|
msg.push(' ');
|
||||||
msg.push_str(word);
|
msg.push_str(word.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Box::pin(async move { Some(Arg::Msg(msg)) })
|
Box::pin(async move { Some(Arg::Msg(msg)) })
|
||||||
|
|||||||
@ -11,8 +11,12 @@ pub struct PatchBukkitDirectories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_directories(server: &Context) -> Result<PatchBukkitDirectories, String> {
|
pub fn setup_directories(server: &Context) -> Result<PatchBukkitDirectories, String> {
|
||||||
let base = std::path::absolute(server.get_data_folder())
|
let data_folder = std::path::absolute(server.get_data_folder())
|
||||||
.map_err(|_| "Failed to get absolute directory from relative")?;
|
.map_err(|_| "Failed to get absolute directory from relative")?;
|
||||||
|
let server_root = data_folder
|
||||||
|
.parent()
|
||||||
|
.ok_or("Failed to determine server root from PatchBukkit data folder")?;
|
||||||
|
let base = server_root.join("patchbukkit");
|
||||||
|
|
||||||
let plugins = base.join("patchbukkit-plugins");
|
let plugins = base.join("patchbukkit-plugins");
|
||||||
let plugin_updates = plugins.join("update");
|
let plugin_updates = plugins.join("update");
|
||||||
|
|||||||
@ -16,6 +16,8 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PATCHBUKKIT_PERMISSION_NAMESPACE: &str = "patchbukkit";
|
||||||
|
|
||||||
pub struct CommandManager {
|
pub struct CommandManager {
|
||||||
command_map: Option<Instance>,
|
command_map: Option<Instance>,
|
||||||
}
|
}
|
||||||
@ -185,22 +187,35 @@ impl CommandManager {
|
|||||||
cmd_data.description.clone().unwrap_or_default(),
|
cmd_data.description.clone().unwrap_or_default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let permission = format!("patchbukkit:{cmd_name}");
|
let permission = build_permission_node(&plugin.name, &cmd_name);
|
||||||
|
|
||||||
if let Err(e) = context
|
let registry = {
|
||||||
.register_permission(Permission::new(
|
let permission_manager = context.permission_manager.read().await;
|
||||||
&permission,
|
permission_manager.registry.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = registry.write().await.register_permission(Permission::new(
|
||||||
&permission,
|
&permission,
|
||||||
|
&format!(
|
||||||
|
"Allows running the Bukkit command `{cmd_name}` from `{}`",
|
||||||
|
plugin.name
|
||||||
|
),
|
||||||
PermissionDefault::Allow,
|
PermissionDefault::Allow,
|
||||||
))
|
)) {
|
||||||
.await
|
if e.contains("already registered") {
|
||||||
{
|
tracing::debug!(
|
||||||
|
"Permission already registered for command {}: {}",
|
||||||
|
cmd_name,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
} else {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
"Failed to register permission for command {}: {:?}",
|
"Failed to register permission for command {}: {:?}",
|
||||||
cmd_name,
|
cmd_name,
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
context.register_command(node, permission).await;
|
context.register_command(node, permission).await;
|
||||||
|
|
||||||
@ -302,3 +317,49 @@ impl CommandManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_permission_node(plugin_name: &str, cmd_name: &str) -> String {
|
||||||
|
let plugin_segment = sanitize_permission_segment(plugin_name);
|
||||||
|
let command_segment = sanitize_permission_segment(cmd_name);
|
||||||
|
format!("{PATCHBUKKIT_PERMISSION_NAMESPACE}:command.{plugin_segment}.{command_segment}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sanitize_permission_segment(value: &str) -> String {
|
||||||
|
let sanitized: String = value
|
||||||
|
.chars()
|
||||||
|
.map(|ch| {
|
||||||
|
if ch.is_ascii_alphanumeric() || matches!(ch, '.' | '_' | '-') {
|
||||||
|
ch.to_ascii_lowercase()
|
||||||
|
} else {
|
||||||
|
'_'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if sanitized.is_empty() {
|
||||||
|
"unknown".to_string()
|
||||||
|
} else {
|
||||||
|
sanitized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::build_permission_node;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn permission_node_is_namespaced_and_stable() {
|
||||||
|
assert_eq!(
|
||||||
|
build_permission_node("SimpleSpawn", "spawn"),
|
||||||
|
"patchbukkit:command.simplespawn.spawn"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn permission_node_sanitizes_unfriendly_characters() {
|
||||||
|
assert_eq!(
|
||||||
|
build_permission_node("Fancy Plugin", "Spawn-All"),
|
||||||
|
"patchbukkit:command.fancy_plugin.spawn-all"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -5,134 +5,15 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use j4rs::{JvmBuilder, MavenArtifact, MavenArtifactRepo, MavenSettings};
|
|
||||||
use rust_embed::Embed;
|
use rust_embed::Embed;
|
||||||
|
|
||||||
#[derive(Embed)]
|
#[derive(Embed)]
|
||||||
#[folder = "resources/"]
|
#[folder = "resources/"]
|
||||||
pub struct Resources;
|
pub struct Resources;
|
||||||
|
|
||||||
pub const DEPENDENCIES: &[(&str, &str, &str)] = &[
|
|
||||||
("com.google.guava", "guava", "33.3.1-jre"),
|
|
||||||
(
|
|
||||||
"net.md-5",
|
|
||||||
"bungeecord-chat",
|
|
||||||
"1.21-R0.2-deprecated+build.21",
|
|
||||||
),
|
|
||||||
("net.kyori", "adventure-text-logger-slf4j", "4.25.0"),
|
|
||||||
("net.kyori", "adventure-text-minimessage", "4.25.0"),
|
|
||||||
("net.kyori", "adventure-text-serializer-legacy", "4.25.0"),
|
|
||||||
("net.kyori", "adventure-text-serializer-plain", "4.25.0"),
|
|
||||||
("net.kyori", "adventure-text-serializer-json", "4.25.0"),
|
|
||||||
("net.kyori", "adventure-api", "4.25.0"),
|
|
||||||
("net.kyori", "adventure-key", "4.25.0"),
|
|
||||||
("net.kyori", "adventure-text-serializer-commons", "4.25.0"),
|
|
||||||
("net.kyori", "adventure-text-serializer-gson", "4.25.0"),
|
|
||||||
("com.google.code.gson", "gson", "2.11.0"),
|
|
||||||
("org.yaml", "snakeyaml", "2.2"),
|
|
||||||
("org.joml", "joml", "1.10.8"),
|
|
||||||
("it.unimi.dsi", "fastutil", "8.5.15"),
|
|
||||||
("org.apache.logging.log4j", "log4j-api", "2.24.1"),
|
|
||||||
(
|
|
||||||
"org.apache.maven.resolver",
|
|
||||||
"maven-resolver-connector-basic",
|
|
||||||
"1.9.18",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"org.apache.maven.resolver",
|
|
||||||
"maven-resolver-transport-http",
|
|
||||||
"1.9.18",
|
|
||||||
),
|
|
||||||
("org.apache.maven", "maven-resolver-provider", "3.9.6"),
|
|
||||||
("org.apache.maven.resolver", "maven-resolver-impl", "1.9.18"),
|
|
||||||
("org.slf4j", "jcl-over-slf4j", "1.7.36"),
|
|
||||||
(
|
|
||||||
"org.apache.maven.resolver",
|
|
||||||
"maven-resolver-named-locks",
|
|
||||||
"1.9.18",
|
|
||||||
),
|
|
||||||
("org.slf4j", "slf4j-api", "2.0.16"),
|
|
||||||
("com.mojang", "brigadier", "1.3.10"),
|
|
||||||
("org.jspecify", "jspecify", "1.0.0"),
|
|
||||||
("com.google.guava", "failureaccess", "1.0.2"),
|
|
||||||
(
|
|
||||||
"com.google.guava",
|
|
||||||
"listenablefuture",
|
|
||||||
"9999.0-empty-to-avoid-conflict-with-guava",
|
|
||||||
),
|
|
||||||
("com.google.code.findbugs", "jsr305", "3.0.2"),
|
|
||||||
("org.checkerframework", "checker-qual", "3.43.0"),
|
|
||||||
("com.google.errorprone", "error_prone_annotations", "2.28.0"),
|
|
||||||
("com.google.j2objc", "j2objc-annotations", "3.0.0"),
|
|
||||||
("org.apache.maven", "maven-model-builder", "3.9.6"),
|
|
||||||
("org.apache.maven", "maven-model", "3.9.6"),
|
|
||||||
("org.apache.maven", "maven-repository-metadata", "3.9.6"),
|
|
||||||
("org.apache.maven.resolver", "maven-resolver-spi", "1.9.18"),
|
|
||||||
("org.apache.maven.resolver", "maven-resolver-util", "1.9.18"),
|
|
||||||
("org.apache.maven.resolver", "maven-resolver-api", "1.9.18"),
|
|
||||||
("org.apache.maven", "maven-artifact", "3.9.6"),
|
|
||||||
("org.codehaus.plexus", "plexus-utils", "3.5.1"),
|
|
||||||
("javax.inject", "javax.inject", "1"),
|
|
||||||
("org.apache.httpcomponents", "httpclient", "4.5.14"),
|
|
||||||
("org.apache.httpcomponents", "httpcore", "4.4.16"),
|
|
||||||
("commons-codec", "commons-codec", "1.16.0"),
|
|
||||||
("net.kyori", "examination-string", "1.3.0"),
|
|
||||||
("net.kyori", "examination-api", "1.3.0"),
|
|
||||||
("org.codehaus.plexus", "plexus-interpolation", "1.26"),
|
|
||||||
("org.apache.maven", "maven-builder-support", "3.9.6"),
|
|
||||||
("org.eclipse.sisu", "org.eclipse.sisu.inject", "0.9.0.M2"),
|
|
||||||
("org.apache.commons", "commons-lang3", "3.12.0"),
|
|
||||||
("net.kyori", "option", "1.1.0"),
|
|
||||||
// These are deps of patchbukkit itself
|
|
||||||
("io.papermc.paper", "paper-api", "1.21.11-R0.1-SNAPSHOT"),
|
|
||||||
("com.google.protobuf", "protobuf-java", "4.33.5"),
|
|
||||||
("org.slf4j", "slf4j-jdk14", "2.0.16"),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub fn setup_j4rs(j4rs_folder: &Path) -> Result<()> {
|
pub fn setup_j4rs(j4rs_folder: &Path) -> Result<()> {
|
||||||
sync_embedded_resources(j4rs_folder)?;
|
sync_embedded_resources(j4rs_folder)?;
|
||||||
cleanup_stale_files(j4rs_folder);
|
cleanup_stale_files(j4rs_folder);
|
||||||
resolve_maven_dependencies(j4rs_folder)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_maven_dependencies(j4rs_folder: &Path) -> Result<()> {
|
|
||||||
let jassets = j4rs_folder.join("jassets");
|
|
||||||
|
|
||||||
// Check if all expected jars already exist
|
|
||||||
let all_present = DEPENDENCIES
|
|
||||||
.iter()
|
|
||||||
.all(|&(_, artifact, version)| jassets.join(format!("{artifact}-{version}.jar")).exists());
|
|
||||||
|
|
||||||
if all_present {
|
|
||||||
tracing::debug!("All Maven dependencies already present, skipping JVM init");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
tracing::info!("Some Maven dependencies missing, starting JVM to resolve...");
|
|
||||||
|
|
||||||
let jvm = JvmBuilder::new()
|
|
||||||
.with_maven_settings(MavenSettings::new(vec![MavenArtifactRepo::from(
|
|
||||||
"papermc::https://repo.papermc.io/repository/maven-public/",
|
|
||||||
)]))
|
|
||||||
.skip_setting_native_lib()
|
|
||||||
.with_base_path(j4rs_folder)
|
|
||||||
.build()
|
|
||||||
.map_err(|err| anyhow::anyhow!("JVM failed to init: {err:?}"))?;
|
|
||||||
|
|
||||||
for &(group, artifact, version) in DEPENDENCIES {
|
|
||||||
let jar_path = jassets.join(format!("{artifact}-{version}.jar"));
|
|
||||||
if !jar_path.exists() {
|
|
||||||
tracing::info!("Downloading Maven dependency: {group}:{artifact}:{version}");
|
|
||||||
jvm.deploy_artifact(&MavenArtifact::from(format!(
|
|
||||||
"{group}:{artifact}:{version}"
|
|
||||||
)))
|
|
||||||
.map_err(|err| {
|
|
||||||
anyhow::anyhow!("Failed to deploy {group}:{artifact}:{version}: {err:?}")
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -142,32 +23,20 @@ fn cleanup_stale_files(j4rs_folder: &Path) {
|
|||||||
.map(|p| PathBuf::from(p.to_string()))
|
.map(|p| PathBuf::from(p.to_string()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let maven_jars: HashSet<String> = DEPENDENCIES
|
|
||||||
.iter()
|
|
||||||
.map(|d| format!("{}-{}.jar", d.1, d.2))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
for entry in walkdir::WalkDir::new(j4rs_folder)
|
for entry in walkdir::WalkDir::new(j4rs_folder)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|e| e.ok())
|
.filter_map(|e| e.ok())
|
||||||
.filter(|e| e.file_type().is_file())
|
.filter(|e| e.file_type().is_file())
|
||||||
{
|
{
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
if let Ok(rel_path) = path.strip_prefix(j4rs_folder) {
|
if let Ok(rel_path) = path.strip_prefix(j4rs_folder)
|
||||||
// Skip Maven-managed jars — handled by cleanup_stale_maven_jars
|
&& !embedded_paths.contains(rel_path)
|
||||||
if let Some(file_name) = path.file_name().and_then(|f| f.to_str())
|
|
||||||
&& maven_jars.contains(file_name)
|
|
||||||
{
|
{
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !embedded_paths.contains(rel_path) {
|
|
||||||
tracing::warn!("Removing stale embedded file: {}", rel_path.display());
|
tracing::warn!("Removing stale embedded file: {}", rel_path.display());
|
||||||
let _ = fs::remove_file(path);
|
let _ = fs::remove_file(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sync_embedded_resources(j4rs_folder: &Path) -> Result<()> {
|
pub fn sync_embedded_resources(j4rs_folder: &Path) -> Result<()> {
|
||||||
for resource_path_str in Resources::iter() {
|
for resource_path_str in Resources::iter() {
|
||||||
|
|||||||
@ -30,9 +30,17 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PATCHBUKKIT_PUMPKIN_VERSION: &str = env!("PATCHBUKKIT_PUMPKIN_VERSION");
|
||||||
|
const PATCHBUKKIT_PUMPKIN_REVISION: &str = env!("PATCHBUKKIT_PUMPKIN_REVISION");
|
||||||
|
const PATCHBUKKIT_PUMPKIN_REVISION_SHORT: &str = env!("PATCHBUKKIT_PUMPKIN_REVISION_SHORT");
|
||||||
|
|
||||||
async fn on_load_inner(plugin: &PatchBukkitPlugin, server: Arc<Context>) -> Result<(), String> {
|
async fn on_load_inner(plugin: &PatchBukkitPlugin, server: Arc<Context>) -> Result<(), String> {
|
||||||
server.init_log();
|
server.init_log();
|
||||||
tracing::info!("Starting PatchBukkit");
|
tracing::info!("Starting PatchBukkit");
|
||||||
|
tracing::info!(
|
||||||
|
"Built against Pumpkin {PATCHBUKKIT_PUMPKIN_VERSION} ({PATCHBUKKIT_PUMPKIN_REVISION_SHORT})"
|
||||||
|
);
|
||||||
|
tracing::debug!("Full Pumpkin dependency revision: {PATCHBUKKIT_PUMPKIN_REVISION}");
|
||||||
|
|
||||||
// Setup directories
|
// Setup directories
|
||||||
let dirs = setup_directories(&server)?;
|
let dirs = setup_directories(&server)?;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user