diff --git a/.gitignore b/.gitignore index 621429a..e0e1035 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ out/ plugin/bin/ api/bin/ +# VSCode +.vscode/ + # Compiled class file *.class diff --git a/build.gradle.kts b/build.gradle.kts index bb7727c..c13fa8d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,10 +1,10 @@ plugins { `java-library` - id("io.papermc.paperweight.userdev") version "1.5.11" - id("xyz.jpenilla.run-paper") version "2.2.2" // Adds runServer and runMojangMappedServer tasks for testing + alias(libs.plugins.paperweight.userdev) + alias(libs.plugins.run.paper) // Adds runServer and runMojangMappedServer tasks for testing // Shades and relocates dependencies into our plugin jar. See https://imperceptiblethoughts.com/shadow/introduction/ - id("com.github.johnrengelman.shadow") version "8.1.1" + alias(libs.plugins.shadow) } group = "com.moulberry.axiom" @@ -23,26 +23,30 @@ repositories { maven("https://jitpack.io") maven("https://repo.papermc.io/repository/maven-public/") maven("https://maven.enginehub.org/repo/") + maven("https://maven.playpro.com") } dependencies { - paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT") - implementation("xyz.jpenilla:reflection-remapper:0.1.0-SNAPSHOT") - implementation("org.incendo:cloud-paper:2.0.0-beta.2") + paperweight.paperDevBundle(libs.versions.paper) + implementation(libs.reflection.remapper) + implementation(libs.cloud.paper) // Zstd Compression Library - implementation("com.github.luben:zstd-jni:1.5.5-4") + implementation(libs.zstd.jni) // ViaVersion support - compileOnly("com.viaversion:viaversion-api:4.10.1-SNAPSHOT") + compileOnly(libs.viaversion.api) // WorldGuard support - compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.1.0-SNAPSHOT") + compileOnly(libs.worldguard.bukkit) // PlotSquared support - implementation(platform("com.intellectualsites.bom:bom-newest:1.37")) - compileOnly("com.intellectualsites.plotsquared:plotsquared-core") - compileOnly("com.intellectualsites.plotsquared:plotsquared-bukkit") { isTransitive = false } + implementation(platform(libs.bom.newest)) + compileOnly(libs.plotsquared.core) + compileOnly(libs.plotsquared.bukkit) { isTransitive = false } + + // CoreProtect support + compileOnly(libs.coreprotect) } tasks { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..98d24c8 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,32 @@ +[versions] +# Dependencies +bom-newest = "1.37" +cloud-paper = "2.0.0-20240516.054251-69" +coreprotect = "22.4" +paper = "1.20.4-R0.1-SNAPSHOT" +plotsquared = "7.3.9-20240513.192211-13" +reflection-remapper = "0.1.2-20240315.033304-2" +viaversion-api = "4.10.1-20240505.124211-22" +worldguard-bukkit = "7.1.0-20240503.180049-12" +zstd-jni = "1.5.5-4" + +# Plugins +paperweight-userdev = "1.5.11" +run-paper = "2.2.2" +shadow = "8.1.1" + +[libraries] +bom-newest = { group = "com.intellectualsites.bom", name = "bom-newest", version.ref = "bom-newest" } +cloud-paper = { group = "org.incendo", name = "cloud-paper", version.ref = "cloud-paper" } +coreprotect = { group = "net.coreprotect", name = "coreprotect", version.ref = "coreprotect" } +plotsquared-bukkit = { group = "com.intellectualsites.plotsquared", name = "plotsquared-bukkit", version.ref = "plotsquared" } +plotsquared-core = { group = "com.intellectualsites.plotsquared", name = "plotsquared-core", version.ref = "plotsquared" } +reflection-remapper = { group = "xyz.jpenilla", name = "reflection-remapper", version.ref = "reflection-remapper" } +viaversion-api = { group = "com.viaversion", name = "viaversion-api", version.ref = "viaversion-api" } +worldguard-bukkit = { group = "com.sk89q.worldguard", name = "worldguard-bukkit", version.ref = "worldguard-bukkit" } +zstd-jni = { group = "com.github.luben", name = "zstd-jni", version = "1.5.5-4" } + +[plugins] +paperweight-userdev = { id = "io.papermc.paperweight.userdev", version.ref = "paperweight-userdev" } +run-paper = { id = "xyz.jpenilla.run-paper", version.ref = "run-paper" } +shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" } diff --git a/src/main/java/com/moulberry/axiom/AxiomPaper.java b/src/main/java/com/moulberry/axiom/AxiomPaper.java index e0fe969..300d79d 100644 --- a/src/main/java/com/moulberry/axiom/AxiomPaper.java +++ b/src/main/java/com/moulberry/axiom/AxiomPaper.java @@ -6,6 +6,7 @@ import com.moulberry.axiom.buffer.CompressedBlockEntity; import com.moulberry.axiom.commands.AxiomDebugCommand; import com.moulberry.axiom.event.AxiomCreateWorldPropertiesEvent; import com.moulberry.axiom.event.AxiomModifyWorldEvent; +import com.moulberry.axiom.integration.coreprotect.CoreProtectIntegration; import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import com.moulberry.axiom.packet.*; import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry; @@ -38,7 +39,7 @@ import org.bukkit.plugin.messaging.Messenger; import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.bukkit.CloudBukkitCapabilities; import org.incendo.cloud.execution.ExecutionCoordinator; -import org.incendo.cloud.paper.PaperCommandManager; +import org.incendo.cloud.paper.LegacyPaperCommandManager; import org.jetbrains.annotations.Nullable; import java.io.FileReader; @@ -285,16 +286,22 @@ public class AxiomPaper extends JavaPlugin implements Listener { WorldExtension.tick(MinecraftServer.getServer(), sendMarkers, maxChunkRelightsPerTick, maxChunkSendsPerTick); }, 1, 1); - PaperCommandManager manager = PaperCommandManager.createNative( - this, - ExecutionCoordinator.simpleCoordinator() - ); - - if (manager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) { - manager.registerBrigadier(); + try { + LegacyPaperCommandManager manager = LegacyPaperCommandManager.createNative( + this, + ExecutionCoordinator.simpleCoordinator() + ); + if (manager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) { + manager.registerBrigadier(); + } + AxiomDebugCommand.register(this, manager); + } catch (Exception e) { + e.printStackTrace(); } - AxiomDebugCommand.register(this, manager); + if (CoreProtectIntegration.isEnabled()) { + this.getLogger().info("CoreProtect integration enabled"); + } } public boolean logLargeBlockBufferChanges() { diff --git a/src/main/java/com/moulberry/axiom/integration/coreprotect/CoreProtectIntegration.java b/src/main/java/com/moulberry/axiom/integration/coreprotect/CoreProtectIntegration.java new file mode 100644 index 0000000..3bba2e7 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/integration/coreprotect/CoreProtectIntegration.java @@ -0,0 +1,60 @@ +package com.moulberry.axiom.integration.coreprotect; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.craftbukkit.CraftWorld; + +public class CoreProtectIntegration { + public static boolean isEnabled() { + return CoreProtectIntegrationImpl.isEnabled(); + } + + public static boolean logPlacement(String name, BlockState blockState, CraftWorld world, BlockPos pos) { + if (!CoreProtectIntegrationImpl.isEnabled()) { + return false; + } + + return CoreProtectIntegrationImpl.logPlacement(name, blockState, world, pos); + } + + public static boolean logPlacement(String name, BlockState blockState, CraftWorld world, int x, int y, int z) { + if (!CoreProtectIntegrationImpl.isEnabled()) { + return false; + } + + return CoreProtectIntegrationImpl.logPlacement(name, blockState, world, x, y, z); + } + + public static boolean logPlacement(String name, Level level, CraftWorld world, BlockPos pos) { + if (!CoreProtectIntegrationImpl.isEnabled()) { + return false; + } + + return CoreProtectIntegrationImpl.logPlacement(name, level, world, pos); + } + + public static boolean logRemoval(String name, BlockState blockState, CraftWorld world, BlockPos pos) { + if (!CoreProtectIntegrationImpl.isEnabled()) { + return false; + } + + return CoreProtectIntegrationImpl.logRemoval(name, blockState, world, pos); + } + + public static boolean logRemoval(String name, BlockState blockState, CraftWorld world, int x, int y, int z) { + if (!CoreProtectIntegrationImpl.isEnabled()) { + return false; + } + + return CoreProtectIntegrationImpl.logRemoval(name, blockState, world, x, y, z); + } + + public static boolean logRemoval(String name, Level level, CraftWorld world, BlockPos pos) { + if (!CoreProtectIntegrationImpl.isEnabled()) { + return false; + } + + return CoreProtectIntegrationImpl.logRemoval(name, level, world, pos); + } +} \ No newline at end of file diff --git a/src/main/java/com/moulberry/axiom/integration/coreprotect/CoreProtectIntegrationImpl.java b/src/main/java/com/moulberry/axiom/integration/coreprotect/CoreProtectIntegrationImpl.java new file mode 100644 index 0000000..571d90b --- /dev/null +++ b/src/main/java/com/moulberry/axiom/integration/coreprotect/CoreProtectIntegrationImpl.java @@ -0,0 +1,99 @@ +package com.moulberry.axiom.integration.coreprotect; + +import com.moulberry.axiom.AxiomPaper; +import net.coreprotect.CoreProtect; +import net.coreprotect.CoreProtectAPI; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +public class CoreProtectIntegrationImpl { + private static final CoreProtectAPI COREPROTECT_API; + private static final boolean COREPROTECT_ENABLED; + private static final Constructor CRAFT_BLOCK_STATE_CONSTRUCTOR; + + static { + COREPROTECT_API = getCoreProtect(); + Constructor constructor = null; + + if (COREPROTECT_API != null) { + try { + constructor = CraftBlockState.class.getDeclaredConstructor(World.class, BlockPos.class, BlockState.class); + constructor.setAccessible(true); + } catch (NoSuchMethodException | SecurityException e) { + AxiomPaper.PLUGIN.getLogger().warning("Failed to get CraftBlockState constructor for CoreProtect: " + e); + } + } + + CRAFT_BLOCK_STATE_CONSTRUCTOR = constructor; + COREPROTECT_ENABLED = COREPROTECT_API != null && CRAFT_BLOCK_STATE_CONSTRUCTOR != null; + } + + private static CoreProtectAPI getCoreProtect() { + Plugin plugin = Bukkit.getPluginManager().getPlugin("CoreProtect"); + + if (plugin == null || !(plugin instanceof CoreProtect)) { + return null; + } + + CoreProtectAPI coreProtect = ((CoreProtect) plugin).getAPI(); + if (coreProtect.isEnabled() == false) { + return null; + } + + if (coreProtect.APIVersion() < 10) { + return null; + } + + return coreProtect; + } + + private static CraftBlockState createCraftBlockState(World world, BlockPos pos, BlockState blockState) { + try { + return (CraftBlockState) CRAFT_BLOCK_STATE_CONSTRUCTOR.newInstance(world, pos, blockState); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + AxiomPaper.PLUGIN.getLogger().warning("Failed to create CraftBlockState for CoreProtect: " + e); + return null; + } + } + + static boolean isEnabled() { + return COREPROTECT_ENABLED; + } + + static boolean logPlacement(String name, BlockState blockState, CraftWorld world, BlockPos pos) { + if (blockState.isAir()) { + return false; + } + + return COREPROTECT_API.logPlacement(name, createCraftBlockState(world, pos, blockState)); + } + + static boolean logPlacement(String name, BlockState blockState, CraftWorld world, int x, int y, int z) { + return logPlacement(name, blockState, world, new BlockPos(x, y, z)); + } + + static boolean logPlacement(String name, Level level, CraftWorld world, BlockPos pos) { + return logPlacement(name, level.getBlockState(pos), world, pos); + } + + static boolean logRemoval(String name, BlockState blockState, CraftWorld world, BlockPos pos) { + return COREPROTECT_API.logRemoval(name, createCraftBlockState(world, pos, blockState)); + } + + static boolean logRemoval(String name, BlockState blockState, CraftWorld world, int x, int y, int z) { + return logRemoval(name, blockState, world, new BlockPos(x, y, z)); + } + + static boolean logRemoval(String name, Level level, CraftWorld world, BlockPos pos) { + return logRemoval(name, level.getBlockState(pos), world, pos); + } +} \ No newline at end of file diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java index 74cad82..24ef72b 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java @@ -8,6 +8,7 @@ import com.moulberry.axiom.buffer.BlockBuffer; import com.moulberry.axiom.buffer.CompressedBlockEntity; import com.moulberry.axiom.integration.Integration; import com.moulberry.axiom.integration.SectionPermissionChecker; +import com.moulberry.axiom.integration.coreprotect.CoreProtectIntegration; import com.moulberry.axiom.viaversion.UnknownVersionHelper; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; @@ -220,6 +221,9 @@ public class SetBlockBufferPacketListener { BlockState old = section.setBlockState(x, y, z, blockState, true); if (blockState != old) { + CoreProtectIntegration.logRemoval(player.getBukkitEntity().getName(), old, world.getWorld(), bx, by, bz); + CoreProtectIntegration.logPlacement(player.getBukkitEntity().getName(), blockState, world.getWorld(), bx, by, bz); + sectionChanged = true; blockPos.set(bx, by, bz); diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index 91c3856..12c478b 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -3,6 +3,7 @@ package com.moulberry.axiom.packet; import com.google.common.collect.Maps; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.integration.Integration; +import com.moulberry.axiom.integration.coreprotect.CoreProtectIntegration; import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import io.netty.buffer.Unpooled; import net.kyori.adventure.text.Component; @@ -158,8 +159,11 @@ public class SetBlockPacketListener implements PluginMessageListener { continue; } + CoreProtectIntegration.logRemoval(bukkitPlayer.getName(), player.level(), world, blockPos); + // Place block player.level().setBlock(blockPos, blockState, 3); + CoreProtectIntegration.logPlacement(bukkitPlayer.getName(), blockState, world, blockPos); } } else { int count = 0; @@ -221,6 +225,9 @@ public class SetBlockPacketListener implements PluginMessageListener { BlockState old = section.setBlockState(x, y, z, blockState, true); if (blockState != old) { + CoreProtectIntegration.logRemoval(bukkitPlayer.getName(), old, world, blockPos); + CoreProtectIntegration.logPlacement(bukkitPlayer.getName(), blockState, world, blockPos); + Block block = blockState.getBlock(); motionBlocking.update(x, by, z, blockState); motionBlockingNoLeaves.update(x, by, z, blockState); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 2531c61..8e00fc0 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -5,6 +5,7 @@ description: $description authors: - Moulberry api-version: "$apiVersion" +softdepend: ["CoreProtect"] permissions: axiom.*: description: Allows use of all default Axiom features