From 5af4b5e20632bc2fde392b4106aaf2e08d142d15 Mon Sep 17 00:00:00 2001 From: Bulbmin Date: Mon, 25 May 2026 19:28:39 -0400 Subject: [PATCH 1/3] Add support for waxed varients for CopperRail simple admin hack --- .../plugins/SimpleAdminHacks/config.yml | 8 +++ .../hacks/basic/CopperRail.java | 59 ++++++++++++++++--- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/ansible/files/paper-config/plugins/SimpleAdminHacks/config.yml b/ansible/files/paper-config/plugins/SimpleAdminHacks/config.yml index ebd8563ffc..db9d3cbbc1 100644 --- a/ansible/files/paper-config/plugins/SimpleAdminHacks/config.yml +++ b/ansible/files/paper-config/plugins/SimpleAdminHacks/config.yml @@ -582,16 +582,24 @@ hacks: materials: COBBLESTONE: 8 COPPER_BLOCK: 29 + WAXED_COPPER_BLOCK: 29 EXPOSED_COPPER: 23 + WAXED_EXPOSED_COPPER: 23 WEATHERED_COPPER: 18 + WAXED_WEATHERED_COPPER: 18 OXIDIZED_COPPER: 14 + WAXED_OXIDIZED_COPPER: 14 skyBase: 10 skyMaterials: COBBLESTONE: 8 COPPER_BLOCK: 30 + WAXED_COPPER_BLOCK: 30 EXPOSED_COPPER: 24 + WAXED_EXPOSED_COPPER: 24 WEATHERED_COPPER: 19 + WAXED_WEATHERED_COPPER: 19 OXIDIZED_COPPER: 15 + WAXED_OXIDIZED_COPPER: 15 CopperRail: enabled: true deoxidise: true diff --git a/plugins/simpleadminhacks-paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java b/plugins/simpleadminhacks-paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java index bb0d1a912c..b7f9906dc3 100644 --- a/plugins/simpleadminhacks-paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java +++ b/plugins/simpleadminhacks-paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java @@ -47,6 +47,35 @@ public CopperRail(SimpleAdminHacks plugin, BasicHackConfig config) { super(plugin, config); } + + private net.minecraft.world.level.block.state.BlockState getWaxedVersion(net.minecraft.world.level.block.Block normalBlock) { + if (normalBlock == net.minecraft.world.level.block.Blocks.COPPER_BLOCK) return net.minecraft.world.level.block.Blocks.WAXED_COPPER_BLOCK.defaultBlockState(); + if (normalBlock == net.minecraft.world.level.block.Blocks.EXPOSED_COPPER) return net.minecraft.world.level.block.Blocks.WAXED_EXPOSED_COPPER.defaultBlockState(); + if (normalBlock == net.minecraft.world.level.block.Blocks.WEATHERED_COPPER) return net.minecraft.world.level.block.Blocks.WAXED_WEATHERED_COPPER.defaultBlockState(); + if (normalBlock == net.minecraft.world.level.block.Blocks.OXIDIZED_COPPER) return net.minecraft.world.level.block.Blocks.WAXED_OXIDIZED_COPPER.defaultBlockState(); + return null; + } + + private net.minecraft.world.level.block.Block getUnwaxedVersion(net.minecraft.world.level.block.Block waxedBlock) { + if (waxedBlock == net.minecraft.world.level.block.Blocks.WAXED_COPPER_BLOCK) return net.minecraft.world.level.block.Blocks.COPPER_BLOCK; + if (waxedBlock == net.minecraft.world.level.block.Blocks.WAXED_EXPOSED_COPPER) return net.minecraft.world.level.block.Blocks.EXPOSED_COPPER; + if (waxedBlock == net.minecraft.world.level.block.Blocks.WAXED_WEATHERED_COPPER) return net.minecraft.world.level.block.Blocks.WEATHERED_COPPER; + if (waxedBlock == net.minecraft.world.level.block.Blocks.WAXED_OXIDIZED_COPPER) return net.minecraft.world.level.block.Blocks.OXIDIZED_COPPER; + return null; + } + + private boolean canBeCopperOxidized(Block block) { + net.minecraft.world.level.block.Block nmsBlock = ((CraftBlock) block).getNMS().getBlock(); + + if (nmsBlock instanceof WeatheringCopper) { + return WeatheringCopper.getNext(nmsBlock).isPresent(); + } + + // waxed check + net.minecraft.world.level.block.Block unwaxedTwin = getUnwaxedVersion(nmsBlock); + return unwaxedTwin != null && WeatheringCopper.getNext(unwaxedTwin).isPresent(); + } + @EventHandler public void on(VehicleMoveEvent event) { if (this.damage <= 0 || !(event.getVehicle() instanceof Minecart minecart)) { @@ -84,13 +113,11 @@ public void on(VehicleMoveEvent event) { } Location location = new Location(minecart.getWorld(), x, from.getY(), z); Block topCopperBlock = location.getBlock().getRelative(BlockFace.DOWN); - Optional next = WeatheringCopper.getNext(((CraftBlock) topCopperBlock).getNMS().getBlock()); - if (next.isPresent()) { + if (canBeCopperOxidized(topCopperBlock)) { copperBlocks.add(topCopperBlock); } Block belowCopperBlock = topCopperBlock.getRelative(BlockFace.DOWN); - next = WeatheringCopper.getNext(((CraftBlock) belowCopperBlock).getNMS().getBlock()); - if (next.isPresent()) { + if (canBeCopperOxidized(belowCopperBlock)) { copperBlocks.add(belowCopperBlock); } } @@ -100,15 +127,33 @@ public void on(VehicleMoveEvent event) { CraftBlock craftBlock = (CraftBlock) copperBlock; BlockState state = craftBlock.getNMS(); ServerLevel level = ((CraftWorld) copperBlock.getWorld()).getHandle(); + + net.minecraft.world.level.block.Block nmsBlock = state.getBlock(); + boolean isWaxed = !(nmsBlock instanceof WeatheringCopper); + // We damage the copper directly instead of using random ticking, as random ticking is easy to cheese // by placing waxed copper next to the rail, entirely preventing the rest of the rail from oxidising. - WeatheringCopper copper = (WeatheringCopper) state.getBlock(); + net.minecraft.world.level.block.Block simulatedCopper = isWaxed + ? getUnwaxedVersion(nmsBlock) + : nmsBlock; + + if (simulatedCopper == null) continue; + WeatheringCopper copper = (WeatheringCopper) simulatedCopper; float chanceModifier = copper.getChanceModifier(); + if (this.damage * chanceModifier > ThreadLocalRandom.current().nextFloat()) { - copper.getNext(state).ifPresent((iblockdata2) -> { + BlockState targetState = isWaxed ? simulatedCopper.defaultBlockState() : state; + + copper.getNext(targetState).ifPresent((nextVanillaNmsState) -> { + BlockState finalBlockState = isWaxed + ? getWaxedVersion(nextVanillaNmsState.getBlock()) + : nextVanillaNmsState; + + if (finalBlockState == null) return; + try { formingBlock = true; - CraftEventFactory.handleBlockFormEvent(level, craftBlock.getPosition(), iblockdata2, 3); + CraftEventFactory.handleBlockFormEvent(level, craftBlock.getPosition(), finalBlockState, 3); } finally { formingBlock = false; } From 4a6898622797fcf70fd57a1703b7cd9a51eabc17 Mon Sep 17 00:00:00 2001 From: Bulbmin Date: Mon, 25 May 2026 22:06:16 -0400 Subject: [PATCH 2/3] implement new copperstage to replace mc functions --- .../hacks/basic/CopperRail.java | 159 +++++++++--------- 1 file changed, 79 insertions(+), 80 deletions(-) diff --git a/plugins/simpleadminhacks-paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java b/plugins/simpleadminhacks-paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java index b7f9906dc3..9dab824207 100644 --- a/plugins/simpleadminhacks-paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java +++ b/plugins/simpleadminhacks-paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java @@ -5,9 +5,7 @@ import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack; import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig; import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.block.WeatheringCopper; -import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.Bukkit; import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.Material; @@ -15,10 +13,6 @@ import org.bukkit.SoundCategory; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.block.CraftBlock; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.craftbukkit.event.CraftEventFactory; import org.bukkit.entity.Entity; import org.bukkit.entity.Minecart; import org.bukkit.entity.Player; @@ -30,7 +24,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.concurrent.ThreadLocalRandom; public class CopperRail extends BasicHack { @@ -47,33 +40,55 @@ public CopperRail(SimpleAdminHacks plugin, BasicHackConfig config) { super(plugin, config); } + private enum CopperStage { + UNAFFECTED(Material.COPPER_BLOCK, Material.WAXED_COPPER_BLOCK, 1.0f), + EXPOSED(Material.EXPOSED_COPPER, Material.WAXED_EXPOSED_COPPER, 1.0f), + WEATHERED(Material.WEATHERED_COPPER, Material.WAXED_WEATHERED_COPPER, 0.75f), + OXIDIZED(Material.OXIDIZED_COPPER, Material.WAXED_OXIDIZED_COPPER, 0.0f); - private net.minecraft.world.level.block.state.BlockState getWaxedVersion(net.minecraft.world.level.block.Block normalBlock) { - if (normalBlock == net.minecraft.world.level.block.Blocks.COPPER_BLOCK) return net.minecraft.world.level.block.Blocks.WAXED_COPPER_BLOCK.defaultBlockState(); - if (normalBlock == net.minecraft.world.level.block.Blocks.EXPOSED_COPPER) return net.minecraft.world.level.block.Blocks.WAXED_EXPOSED_COPPER.defaultBlockState(); - if (normalBlock == net.minecraft.world.level.block.Blocks.WEATHERED_COPPER) return net.minecraft.world.level.block.Blocks.WAXED_WEATHERED_COPPER.defaultBlockState(); - if (normalBlock == net.minecraft.world.level.block.Blocks.OXIDIZED_COPPER) return net.minecraft.world.level.block.Blocks.WAXED_OXIDIZED_COPPER.defaultBlockState(); - return null; + private final Material unwaxed; + private final Material waxed; + private final float chance; + + CopperStage(Material unwaxed, Material waxed, float chance) { + this.unwaxed = unwaxed; + this.waxed = waxed; + this.chance = chance; + } + + public static CopperStage from(Material mat) { + for (CopperStage stage : values()) { + if (stage.unwaxed == mat || stage.waxed == mat) return stage; + } + return null; + } } - private net.minecraft.world.level.block.Block getUnwaxedVersion(net.minecraft.world.level.block.Block waxedBlock) { - if (waxedBlock == net.minecraft.world.level.block.Blocks.WAXED_COPPER_BLOCK) return net.minecraft.world.level.block.Blocks.COPPER_BLOCK; - if (waxedBlock == net.minecraft.world.level.block.Blocks.WAXED_EXPOSED_COPPER) return net.minecraft.world.level.block.Blocks.EXPOSED_COPPER; - if (waxedBlock == net.minecraft.world.level.block.Blocks.WAXED_WEATHERED_COPPER) return net.minecraft.world.level.block.Blocks.WEATHERED_COPPER; - if (waxedBlock == net.minecraft.world.level.block.Blocks.WAXED_OXIDIZED_COPPER) return net.minecraft.world.level.block.Blocks.OXIDIZED_COPPER; - return null; + private boolean isWaxed(Material material) { + CopperStage stage = CopperStage.from(material); + return stage != null && stage.waxed == material; } - private boolean canBeCopperOxidized(Block block) { - net.minecraft.world.level.block.Block nmsBlock = ((CraftBlock) block).getNMS().getBlock(); - - if (nmsBlock instanceof WeatheringCopper) { - return WeatheringCopper.getNext(nmsBlock).isPresent(); + private Material getNextStage(Material material) { + CopperStage current = CopperStage.from(material); + if (current == null) return null; + + int nextIndex = current.ordinal() + 1; + if (nextIndex >= CopperStage.values().length) return null; + + CopperStage nextStage = CopperStage.values()[nextIndex]; + return isWaxed(material) ? nextStage.waxed : nextStage.unwaxed; } - - // waxed check - net.minecraft.world.level.block.Block unwaxedTwin = getUnwaxedVersion(nmsBlock); - return unwaxedTwin != null && WeatheringCopper.getNext(unwaxedTwin).isPresent(); + + private Material resetStage(Material material) { + CopperStage current = CopperStage.from(material); + if (current == null) return null; + + if (current == CopperStage.UNAFFECTED) { + return isWaxed(material) ? current.unwaxed : null; + } + + return isWaxed(material) ? CopperStage.UNAFFECTED.waxed : CopperStage.UNAFFECTED.unwaxed; } @EventHandler @@ -113,51 +128,41 @@ public void on(VehicleMoveEvent event) { } Location location = new Location(minecart.getWorld(), x, from.getY(), z); Block topCopperBlock = location.getBlock().getRelative(BlockFace.DOWN); - if (canBeCopperOxidized(topCopperBlock)) { + if (getNextStage(topCopperBlock.getType()) != null) { copperBlocks.add(topCopperBlock); } Block belowCopperBlock = topCopperBlock.getRelative(BlockFace.DOWN); - if (canBeCopperOxidized(belowCopperBlock)) { + if (getNextStage(belowCopperBlock.getType()) != null) { copperBlocks.add(belowCopperBlock); } } } for (Block copperBlock : copperBlocks) { - CraftBlock craftBlock = (CraftBlock) copperBlock; - BlockState state = craftBlock.getNMS(); - ServerLevel level = ((CraftWorld) copperBlock.getWorld()).getHandle(); - - net.minecraft.world.level.block.Block nmsBlock = state.getBlock(); - boolean isWaxed = !(nmsBlock instanceof WeatheringCopper); + Material currentMaterial = copperBlock.getType(); + Material nextMaterial = getNextStage(currentMaterial); - // We damage the copper directly instead of using random ticking, as random ticking is easy to cheese - // by placing waxed copper next to the rail, entirely preventing the rest of the rail from oxidising. - net.minecraft.world.level.block.Block simulatedCopper = isWaxed - ? getUnwaxedVersion(nmsBlock) - : nmsBlock; + if (nextMaterial == null) { + continue; + } - if (simulatedCopper == null) continue; - WeatheringCopper copper = (WeatheringCopper) simulatedCopper; - float chanceModifier = copper.getChanceModifier(); + CopperStage stage = CopperStage.from(currentMaterial); + float chanceModifier = (stage != null) ? stage.chance : 0.0f; if (this.damage * chanceModifier > ThreadLocalRandom.current().nextFloat()) { - BlockState targetState = isWaxed ? simulatedCopper.defaultBlockState() : state; - - copper.getNext(targetState).ifPresent((nextVanillaNmsState) -> { - BlockState finalBlockState = isWaxed - ? getWaxedVersion(nextVanillaNmsState.getBlock()) - : nextVanillaNmsState; - - if (finalBlockState == null) return; - - try { - formingBlock = true; - CraftEventFactory.handleBlockFormEvent(level, craftBlock.getPosition(), finalBlockState, 3); - } finally { - formingBlock = false; + org.bukkit.block.BlockState newState = copperBlock.getState(); + newState.setType(nextMaterial); + BlockFormEvent formEvent = new BlockFormEvent(copperBlock, newState); + + try { + formingBlock = true; + Bukkit.getPluginManager().callEvent(formEvent); + if (!formEvent.isCancelled()) { + newState.update(true); } - }); + } finally { + formingBlock = false; + } } } } @@ -178,29 +183,27 @@ public void on(PlayerInteractEvent event) { return; } - Block copperBlock = block.getRelative(BlockFace.DOWN); - Optional previous = WeatheringCopper.getPrevious(((CraftBlock) copperBlock).getNMS()); - boolean damaged = false; - CraftPlayer player = (CraftPlayer) event.getPlayer(); + Player player = event.getPlayer(); - while (previous.isPresent() && event.getItem().getType() != Material.AIR) { - copperBlock.setType(previous.get().getBukkitMaterial()); - damaged = true; + // First copper block directly underneath the rail + Block topCopperBlock = block.getRelative(BlockFace.DOWN); + Material previousTop = resetStage(topCopperBlock.getType()); + if (previousTop != null) { + topCopperBlock.setType(previousTop); + damaged = true; item.damage(1, player); - previous = WeatheringCopper.getPrevious(((CraftBlock) copperBlock).getNMS()); } - copperBlock = copperBlock.getRelative(BlockFace.DOWN); - previous = WeatheringCopper.getPrevious(((CraftBlock) copperBlock).getNMS()); + // Second copper block two spaces underneath the rail + Block belowCopperBlock = topCopperBlock.getRelative(BlockFace.DOWN); + Material previousBelow = resetStage(belowCopperBlock.getType()); - while (previous.isPresent() && event.getItem().getType() != Material.AIR) { - copperBlock.setType(previous.get().getBukkitMaterial()); + if (previousBelow != null && item.getType() != Material.AIR) { + belowCopperBlock.setType(previousBelow); damaged = true; - item.damage(1, player); - previous = WeatheringCopper.getPrevious(((CraftBlock) copperBlock).getNMS()); } if (!damaged) { @@ -213,8 +216,6 @@ public void on(PlayerInteractEvent event) { event.setCancelled(true); } - // It's not really fair for copper blocks that are below rails to naturally oxidise, - // as it is easy to cheese by placing a waxed copper block every 9 blocks @EventHandler public void on(BlockFormEvent event) { if (formingBlock) { @@ -222,9 +223,7 @@ public void on(BlockFormEvent event) { } Block block = event.getBlock(); - - Optional next = WeatheringCopper.getNext(((CraftBlock) block).getNMS().getBlock()); - if (next.isEmpty()) { + if (getNextStage(block.getType()) == null) { return; } @@ -239,4 +238,4 @@ public void on(BlockFormEvent event) { event.setCancelled(true); } -} +} \ No newline at end of file From 284db0c15bd4c4611e1de8edcf8be4d5015766f1 Mon Sep 17 00:00:00 2001 From: Bulbmin Date: Wed, 27 May 2026 21:58:30 -0400 Subject: [PATCH 3/3] fixed dura, probabilities --- .../hacks/basic/CopperRail.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/plugins/simpleadminhacks-paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java b/plugins/simpleadminhacks-paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java index 9dab824207..3a8dda302b 100644 --- a/plugins/simpleadminhacks-paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java +++ b/plugins/simpleadminhacks-paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java @@ -41,9 +41,9 @@ public CopperRail(SimpleAdminHacks plugin, BasicHackConfig config) { } private enum CopperStage { - UNAFFECTED(Material.COPPER_BLOCK, Material.WAXED_COPPER_BLOCK, 1.0f), + UNAFFECTED(Material.COPPER_BLOCK, Material.WAXED_COPPER_BLOCK, .75f), EXPOSED(Material.EXPOSED_COPPER, Material.WAXED_EXPOSED_COPPER, 1.0f), - WEATHERED(Material.WEATHERED_COPPER, Material.WAXED_WEATHERED_COPPER, 0.75f), + WEATHERED(Material.WEATHERED_COPPER, Material.WAXED_WEATHERED_COPPER, 1.0f), OXIDIZED(Material.OXIDIZED_COPPER, Material.WAXED_OXIDIZED_COPPER, 0.0f); private final Material unwaxed; @@ -80,15 +80,15 @@ private Material getNextStage(Material material) { return isWaxed(material) ? nextStage.waxed : nextStage.unwaxed; } - private Material resetStage(Material material) { + private Material getPreviousStage(Material material) { CopperStage current = CopperStage.from(material); if (current == null) return null; - if (current == CopperStage.UNAFFECTED) { - return isWaxed(material) ? current.unwaxed : null; - } + int prevIndex = current.ordinal() - 1; + if (prevIndex < 0) return null; - return isWaxed(material) ? CopperStage.UNAFFECTED.waxed : CopperStage.UNAFFECTED.unwaxed; + CopperStage prevStage = CopperStage.values()[prevIndex]; + return isWaxed(material) ? prevStage.waxed : prevStage.unwaxed; } @EventHandler @@ -188,22 +188,24 @@ public void on(PlayerInteractEvent event) { // First copper block directly underneath the rail Block topCopperBlock = block.getRelative(BlockFace.DOWN); - Material previousTop = resetStage(topCopperBlock.getType()); + Material previousTop = getPreviousStage(topCopperBlock.getType()); - if (previousTop != null) { + while (previousTop != null && item.getType() != Material.AIR) { topCopperBlock.setType(previousTop); damaged = true; item.damage(1, player); + previousTop = getPreviousStage(topCopperBlock.getType()); } // Second copper block two spaces underneath the rail Block belowCopperBlock = topCopperBlock.getRelative(BlockFace.DOWN); - Material previousBelow = resetStage(belowCopperBlock.getType()); + Material previousBelow = getPreviousStage(belowCopperBlock.getType()); - if (previousBelow != null && item.getType() != Material.AIR) { + while (previousBelow != null && item.getType() != Material.AIR) { belowCopperBlock.setType(previousBelow); damaged = true; item.damage(1, player); + previousBelow = getPreviousStage(belowCopperBlock.getType()); } if (!damaged) { @@ -216,6 +218,8 @@ public void on(PlayerInteractEvent event) { event.setCancelled(true); } + // It's not really fair for copper blocks that are below rails to naturally oxidise, + // as it is easy to cheese by placing a waxed copper block every 9 blocks @EventHandler public void on(BlockFormEvent event) { if (formingBlock) {