From 7e8de3bb6338b2962f5fd11b6a157e9360f3b710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?= Date: Fri, 1 Nov 2024 20:03:41 +0100 Subject: [PATCH] Add support for 1.21.2 (#395) * feat: add support for 1.21.2 * test: remove refernces to junit 4 * chore: upgrade bukkit api version to 1.16.1 * chore: dump up version to 1.21.3 * fix: idea warnings --- .github/workflows/buildtools.sh | 1 + .../orebfuscator/util/MinecraftVersion.java | 1 + .../orebfuscator/util/BlockPosTest.java | 4 +- .../imprex/orebfuscator/OrebfuscatorNms.java | 2 +- .../orebfuscator-nms-v1_21_R2/pom.xml | 81 ++++++++ .../orebfuscator/nms/v1_21_R2/NmsManager.java | 176 ++++++++++++++++++ .../nms/v1_21_R2/ReadOnlyChunkWrapper.java | 18 ++ .../nms/v1_21_R2/RegionFileCache.java | 44 +++++ orebfuscator-nms/pom.xml | 1 + orebfuscator-plugin/pom.xml | 21 ++- .../net/imprex/orebfuscator/UpdateSystem.java | 3 +- ...rappedClientboundLevelChunkPacketData.java | 7 +- pom.xml | 12 +- 13 files changed, 354 insertions(+), 17 deletions(-) create mode 100644 orebfuscator-nms/orebfuscator-nms-v1_21_R2/pom.xml create mode 100644 orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java create mode 100644 orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/ReadOnlyChunkWrapper.java create mode 100644 orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java diff --git a/.github/workflows/buildtools.sh b/.github/workflows/buildtools.sh index 258e9868..8a51ff5e 100644 --- a/.github/workflows/buildtools.sh +++ b/.github/workflows/buildtools.sh @@ -38,3 +38,4 @@ checkVersion "1.20.2" "17" checkVersion "1.20.4" "17" checkVersion "1.20.6" "21" checkVersion "1.21.1" "21" +checkVersion "1.21.3" "21" diff --git a/orebfuscator-common/src/main/java/net/imprex/orebfuscator/util/MinecraftVersion.java b/orebfuscator-common/src/main/java/net/imprex/orebfuscator/util/MinecraftVersion.java index 1d7cc37c..26627c73 100644 --- a/orebfuscator-common/src/main/java/net/imprex/orebfuscator/util/MinecraftVersion.java +++ b/orebfuscator-common/src/main/java/net/imprex/orebfuscator/util/MinecraftVersion.java @@ -15,6 +15,7 @@ private static final class NmsMapping { private static final List MAPPINGS = new ArrayList<>(); static { + MAPPINGS.add(new NmsMapping("1.21.2", "v1_21_R2")); MAPPINGS.add(new NmsMapping("1.21", "v1_21_R1")); MAPPINGS.add(new NmsMapping("1.20.5", "v1_20_R4")); } diff --git a/orebfuscator-common/src/test/java/net/imprex/orebfuscator/util/BlockPosTest.java b/orebfuscator-common/src/test/java/net/imprex/orebfuscator/util/BlockPosTest.java index fdc01b15..7a79e4a0 100644 --- a/orebfuscator-common/src/test/java/net/imprex/orebfuscator/util/BlockPosTest.java +++ b/orebfuscator-common/src/test/java/net/imprex/orebfuscator/util/BlockPosTest.java @@ -1,8 +1,8 @@ package net.imprex.orebfuscator.util; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class BlockPosTest { diff --git a/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorNms.java b/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorNms.java index 2e91161c..dc011f8c 100644 --- a/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorNms.java +++ b/orebfuscator-nms/orebfuscator-nms-api/src/main/java/net/imprex/orebfuscator/OrebfuscatorNms.java @@ -26,7 +26,7 @@ public static void initialize(Config config) { } String nmsVersion = MinecraftVersion.nmsVersion(); - if (ServerVersion.isMojangMapped()) { + if (ServerVersion.isMojangMapped() && !ServerVersion.isPaper()) { nmsVersion += "_mojang"; } diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/pom.xml b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/pom.xml new file mode 100644 index 00000000..6dc06fa9 --- /dev/null +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/pom.xml @@ -0,0 +1,81 @@ + + 4.0.0 + + + net.imprex + orebfuscator-nms + ${revision} + + + orebfuscator-nms-v1_21_R2 + jar + + + + net.imprex + orebfuscator-nms-api + ${revision} + provided + + + org.spigotmc + spigot + 1.21.3-R0.1-SNAPSHOT + remapped-mojang + provided + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + true + mojang-mapped + + + net.imprex.orebfuscator.nms.v1_21_R2 + net.imprex.orebfuscator.nms.v1_21_R2_mojang + + + + + + net.md-5 + specialsource-maven-plugin + ${plugin.specialsource.version} + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.21.3-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.21.3-R0.1-SNAPSHOT:jar:remapped-mojang + true + remapped-obf + + + + package + + remap + + remap-spigot + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + org.spigotmc:minecraft-server:1.21.3-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.21.3-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + + + \ No newline at end of file diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java new file mode 100644 index 00000000..1e805079 --- /dev/null +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/NmsManager.java @@ -0,0 +1,176 @@ +package net.imprex.orebfuscator.nms.v1_21_R2; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_21_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R2.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import com.google.common.collect.ImmutableList; + +import it.unimi.dsi.fastutil.shorts.Short2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import net.imprex.orebfuscator.config.Config; +import net.imprex.orebfuscator.nms.AbstractNmsManager; +import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import net.imprex.orebfuscator.util.BlockProperties; +import net.imprex.orebfuscator.util.BlockStateProperties; +import net.imprex.orebfuscator.util.NamespacedKey; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; + +public class NmsManager extends AbstractNmsManager { + + private static final int BLOCK_ID_AIR = Block.getId(Blocks.AIR.defaultBlockState()); + + static int getBlockState(LevelChunk chunk, int x, int y, int z) { + LevelChunkSection[] sections = chunk.getSections(); + + int sectionIndex = chunk.getSectionIndex(y); + if (sectionIndex >= 0 && sectionIndex < sections.length) { + LevelChunkSection section = sections[sectionIndex]; + if (section != null && !section.hasOnlyAir()) { + return Block.getId(section.getBlockState(x & 0xF, y & 0xF, z & 0xF)); + } + } + + return BLOCK_ID_AIR; + } + + private static ServerLevel level(World world) { + return ((CraftWorld) world).getHandle(); + } + + private static ServerPlayer player(Player player) { + return ((CraftPlayer) player).getHandle(); + } + + public NmsManager(Config config) { + super(Block.BLOCK_STATE_REGISTRY.size(), new RegionFileCache(config.cache())); + + for (Map.Entry, Block> entry : BuiltInRegistries.BLOCK.entrySet()) { + NamespacedKey namespacedKey = NamespacedKey.fromString(entry.getKey().location().toString()); + Block block = entry.getValue(); + + ImmutableList possibleBlockStates = block.getStateDefinition().getPossibleStates(); + BlockProperties.Builder builder = BlockProperties.builder(namespacedKey); + + for (BlockState blockState : possibleBlockStates) { + Material material = CraftBlockData.fromData(blockState).getMaterial(); + + BlockStateProperties properties = BlockStateProperties.builder(Block.getId(blockState)) + .withIsAir(blockState.isAir()) + // check if material is occluding and use blockData check for rare edge cases like barrier, spawner, slime_block, ... + .withIsOccluding(material.isOccluding() && blockState.canOcclude()) + .withIsBlockEntity(blockState.hasBlockEntity()) + .withIsDefaultState(Objects.equals(block.defaultBlockState(), blockState)) + .build(); + + builder.withBlockState(properties); + } + + this.registerBlockProperties(builder.build()); + } + } + + @Override + public ReadOnlyChunk getReadOnlyChunk(World world, int chunkX, int chunkZ) { + ServerChunkCache serverChunkCache = level(world).getChunkSource(); + LevelChunk chunk = serverChunkCache.getChunk(chunkX, chunkZ, true); + return new ReadOnlyChunkWrapper(chunk); + } + + @Override + public int getBlockState(World world, int x, int y, int z) { + ServerChunkCache serverChunkCache = level(world).getChunkSource(); + if (!serverChunkCache.isChunkLoaded(x >> 4, z >> 4)) { + return BLOCK_ID_AIR; + } + + LevelChunk chunk = serverChunkCache.getChunk(x >> 4, z >> 4, true); + if (chunk == null) { + return BLOCK_ID_AIR; + } + + return getBlockState(chunk, x, y, z); + } + + @Override + public void sendBlockUpdates(World world, Iterable iterable) { + ServerChunkCache serverChunkCache = level(world).getChunkSource(); + BlockPos.MutableBlockPos position = new BlockPos.MutableBlockPos(); + + for (net.imprex.orebfuscator.util.BlockPos pos : iterable) { + position.set(pos.x, pos.y, pos.z); + serverChunkCache.blockChanged(position); + } + } + + @Override + public void sendBlockUpdates(Player player, Iterable iterable) { + ServerPlayer serverPlayer = player(player); + ServerLevel level = serverPlayer.serverLevel(); + ServerChunkCache serverChunkCache = level.getChunkSource(); + + BlockPos.MutableBlockPos position = new BlockPos.MutableBlockPos(); + Map> sectionPackets = new HashMap<>(); + List> blockEntityPackets = new ArrayList<>(); + + for (net.imprex.orebfuscator.util.BlockPos pos : iterable) { + if (!serverChunkCache.isChunkLoaded(pos.x >> 4, pos.z >> 4)) { + continue; + } + + position.set(pos.x, pos.y, pos.z); + BlockState blockState = level.getBlockState(position); + + sectionPackets.computeIfAbsent(SectionPos.of(position), key -> new Short2ObjectLinkedOpenHashMap<>()) + .put(SectionPos.sectionRelativePos(position), blockState); + + if (blockState.hasBlockEntity()) { + BlockEntity blockEntity = level.getBlockEntity(position); + if (blockEntity != null) { + blockEntityPackets.add(blockEntity.getUpdatePacket()); + } + } + } + + for (Map.Entry> entry : sectionPackets.entrySet()) { + Short2ObjectMap blockStates = entry.getValue(); + if (blockStates.size() == 1) { + Short2ObjectMap.Entry blockEntry = blockStates.short2ObjectEntrySet().iterator().next(); + BlockPos blockPosition = entry.getKey().relativeToBlockPos(blockEntry.getShortKey()); + serverPlayer.connection.send(new ClientboundBlockUpdatePacket(blockPosition, blockEntry.getValue())); + } else { + serverPlayer.connection.send(new ClientboundSectionBlocksUpdatePacket(entry.getKey(), + blockStates.keySet(), blockStates.values().toArray(BlockState[]::new))); + } + } + + for (Packet packet : blockEntityPackets) { + serverPlayer.connection.send(packet); + } + } +} diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/ReadOnlyChunkWrapper.java new file mode 100644 index 00000000..d424fc75 --- /dev/null +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/ReadOnlyChunkWrapper.java @@ -0,0 +1,18 @@ +package net.imprex.orebfuscator.nms.v1_21_R2; + +import net.imprex.orebfuscator.nms.ReadOnlyChunk; +import net.minecraft.world.level.chunk.LevelChunk; + +public class ReadOnlyChunkWrapper implements ReadOnlyChunk { + + private final LevelChunk chunk; + + ReadOnlyChunkWrapper(LevelChunk chunk) { + this.chunk = chunk; + } + + @Override + public int getBlockState(int x, int y, int z) { + return NmsManager.getBlockState(chunk, x, y, z); + } +} diff --git a/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java new file mode 100644 index 00000000..964e5031 --- /dev/null +++ b/orebfuscator-nms/orebfuscator-nms-v1_21_R2/src/main/java/net/imprex/orebfuscator/nms/v1_21_R2/RegionFileCache.java @@ -0,0 +1,44 @@ +package net.imprex.orebfuscator.nms.v1_21_R2; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.file.Path; + +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_21_R2.CraftServer; + +import net.imprex.orebfuscator.config.CacheConfig; +import net.imprex.orebfuscator.nms.AbstractRegionFileCache; +import net.imprex.orebfuscator.util.ChunkPosition; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.storage.RegionFile; +import net.minecraft.world.level.chunk.storage.RegionFileVersion; + +public class RegionFileCache extends AbstractRegionFileCache { + + RegionFileCache(CacheConfig cacheConfig) { + super(cacheConfig); + } + + @Override + protected RegionFile createRegionFile(Path path) throws IOException { + boolean isSyncChunkWrites = ((CraftServer) Bukkit.getServer()).getServer().forceSynchronousWrites(); + return new RegionFile(null, path, path.getParent(), RegionFileVersion.VERSION_NONE, isSyncChunkWrites); + } + + @Override + protected void closeRegionFile(RegionFile t) throws IOException { + t.close(); + } + + @Override + protected DataInputStream createInputStream(RegionFile t, ChunkPosition key) throws IOException { + return t.getChunkDataInputStream(new ChunkPos(key.x, key.z)); + } + + @Override + protected DataOutputStream createOutputStream(RegionFile t, ChunkPosition key) throws IOException { + return t.getChunkDataOutputStream(new ChunkPos(key.x, key.z)); + } +} \ No newline at end of file diff --git a/orebfuscator-nms/pom.xml b/orebfuscator-nms/pom.xml index 9cc79fc5..16f8c1bb 100644 --- a/orebfuscator-nms/pom.xml +++ b/orebfuscator-nms/pom.xml @@ -28,5 +28,6 @@ orebfuscator-nms-v1_20_R3 orebfuscator-nms-v1_20_R4 orebfuscator-nms-v1_21_R1 + orebfuscator-nms-v1_21_R2 \ No newline at end of file diff --git a/orebfuscator-plugin/pom.xml b/orebfuscator-plugin/pom.xml index c5c13098..4c196500 100644 --- a/orebfuscator-plugin/pom.xml +++ b/orebfuscator-plugin/pom.xml @@ -60,14 +60,6 @@ - - - org.junit.jupiter - junit-jupiter-engine - ${dependency.junit.version} - test - - io.netty @@ -289,5 +281,18 @@ ${revision} compile + + net.imprex + orebfuscator-nms-v1_21_R2 + ${revision} + mojang-mapped + compile + + + net.imprex + orebfuscator-nms-v1_21_R2 + ${revision} + compile + \ No newline at end of file diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/UpdateSystem.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/UpdateSystem.java index c039bf9f..3b6ef3f0 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/UpdateSystem.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/UpdateSystem.java @@ -22,6 +22,7 @@ import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.ComponentBuilder; import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.hover.content.Text; public class UpdateSystem { @@ -128,7 +129,7 @@ public void checkForUpdates(Player player) { BaseComponent[] components = new ComponentBuilder("[§bOrebfuscator§f]§7 A new release is available ") .append("§f§l[CLICK HERE]") .event(new ClickEvent(ClickEvent.Action.OPEN_URL, this.getHtmlUrl())) - .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("§7Click here to see the latest release").create())).create(); + .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(new ComponentBuilder("§7Click here to see the latest release").create()))).create(); OrebfuscatorCompatibility.runForPlayer(player, () -> { player.spigot().sendMessage(components); }); diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/chunk/WrappedClientboundLevelChunkPacketData.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/chunk/WrappedClientboundLevelChunkPacketData.java index ac22c74d..d634e58b 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/chunk/WrappedClientboundLevelChunkPacketData.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/chunk/WrappedClientboundLevelChunkPacketData.java @@ -10,7 +10,6 @@ import com.comphenix.protocol.utility.MinecraftReflection; import net.imprex.orebfuscator.util.BlockPos; -import net.imprex.orebfuscator.util.ServerVersion; public class WrappedClientboundLevelChunkPacketData { @@ -18,9 +17,9 @@ public class WrappedClientboundLevelChunkPacketData { private static final FieldAccessor BUFFER = Accessors.getFieldAccessor(CLIENTBOUND_LEVEL_CHUNK_PACKET_DATA, byte[].class, true); private static final FieldAccessor BLOCK_ENTITIES = Accessors.getFieldAccessor(CLIENTBOUND_LEVEL_CHUNK_PACKET_DATA, List.class, true); - private static final Class BLOCK_ENTITY_INFO = MinecraftReflection.getMinecraftClass(ServerVersion.isMojangMapped() - ? "network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo" - : "network.protocol.game.ClientboundLevelChunkPacketData$a"); + private static final Class BLOCK_ENTITY_INFO = MinecraftReflection.getMinecraftClass( + "network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo", + "network.protocol.game.ClientboundLevelChunkPacketData$a"); private static final FieldAccessor[] INT_FIELDS = Accessors.getFieldAccessorArray(BLOCK_ENTITY_INFO, int.class, true); private static final FieldAccessor PACKED_XZ = INT_FIELDS[0]; private static final FieldAccessor Y = INT_FIELDS[1]; diff --git a/pom.xml b/pom.xml index d03609a9..e5b04c55 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 5.0.0-b0 - 1.13-R0.1-SNAPSHOT + 1.16.1-R0.1-SNAPSHOT 1.20.1-R0.1-SNAPSHOT 1.20.1-R0.1-SNAPSHOT 3.1.0 @@ -161,4 +161,14 @@ + + + + + org.junit.jupiter + junit-jupiter-engine + ${dependency.junit.version} + test + +