diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e26e25d0..e1348729 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,13 +23,14 @@ jobs: key: ${{ runner.os }}-maven-${{ secrets.CACHE_VERSION }}-${{ hashFiles('./.github/workflows/buildtools.sh') }} restore-keys: | ${{ runner.os }}-maven-${{ secrets.CACHE_VERSION }}- - - name: Set up JDK 8/17 + - name: Set up JDK 8/17/21 uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: | 8 17 + 21 - name: Run BuildTools run: | bash ./.github/workflows/buildtools.sh diff --git a/.github/workflows/buildtools.sh b/.github/workflows/buildtools.sh index 41ea07d7..bbfad0c2 100644 --- a/.github/workflows/buildtools.sh +++ b/.github/workflows/buildtools.sh @@ -44,3 +44,4 @@ checkVersion "1.19.4" "17" checkVersion "1.20.1" "17" checkVersion "1.20.2" "17" checkVersion "1.20.4" "17" +checkVersion "1.20.5" "21" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1354f151..56dd1350 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,13 +23,14 @@ jobs: key: ${{ runner.os }}-maven-${{ secrets.CACHE_VERSION }}-${{ hashFiles('./.github/workflows/buildtools.sh') }} restore-keys: | ${{ runner.os }}-maven-${{ secrets.CACHE_VERSION }}- - - name: Set up JDK 8/17 + - name: Set up JDK 8/17/21 uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: | 8 17 + 21 - name: Run BuildTools run: | bash ./.github/workflows/buildtools.sh diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/pom.xml b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/pom.xml new file mode 100644 index 00000000..d5bb3333 --- /dev/null +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/pom.xml @@ -0,0 +1,81 @@ + + 4.0.0 + + + net.imprex + orebfuscator-nms + ${revision} + + + orebfuscator-nms-v1_20_R4 + jar + + + + net.imprex + orebfuscator-nms-api + ${revision} + provided + + + org.spigotmc + spigot + 1.20.5-R0.1-SNAPSHOT + remapped-mojang + provided + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + true + mojang-mapped + + + net.imprex.orebfuscator.nms.v1_20_R4 + net.imprex.orebfuscator.nms.v1_20_R4_mojang + + + + + + net.md-5 + specialsource-maven-plugin + ${plugin.specialsource.version} + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.20.5-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.20.5-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.20.5-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.20.5-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + + + \ No newline at end of file diff --git a/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java new file mode 100644 index 00000000..f37d98f8 --- /dev/null +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/NmsManager.java @@ -0,0 +1,176 @@ +package net.imprex.orebfuscator.nms.v1_20_R4; + +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_20_R4.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R4.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R4.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_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/ReadOnlyChunkWrapper.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/ReadOnlyChunkWrapper.java new file mode 100644 index 00000000..d09fbff6 --- /dev/null +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/ReadOnlyChunkWrapper.java @@ -0,0 +1,18 @@ +package net.imprex.orebfuscator.nms.v1_20_R4; + +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_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/RegionFileCache.java b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/RegionFileCache.java new file mode 100644 index 00000000..81d74cde --- /dev/null +++ b/orebfuscator-nms/orebfuscator-nms-v1_20_R4/src/main/java/net/imprex/orebfuscator/nms/v1_20_R4/RegionFileCache.java @@ -0,0 +1,44 @@ +package net.imprex.orebfuscator.nms.v1_20_R4; + +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_20_R4.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_DEFLATE, 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 5eaebebf..23fe8399 100644 --- a/orebfuscator-nms/pom.xml +++ b/orebfuscator-nms/pom.xml @@ -34,5 +34,6 @@ orebfuscator-nms-v1_20_R1 orebfuscator-nms-v1_20_R2 orebfuscator-nms-v1_20_R3 + orebfuscator-nms-v1_20_R4 \ No newline at end of file diff --git a/orebfuscator-plugin/pom.xml b/orebfuscator-plugin/pom.xml index 96ed2fb0..ed7b4fe1 100644 --- a/orebfuscator-plugin/pom.xml +++ b/orebfuscator-plugin/pom.xml @@ -295,5 +295,18 @@ ${revision} compile + + net.imprex + orebfuscator-nms-v1_20_R4 + ${revision} + mojang-mapped + compile + + + net.imprex + orebfuscator-nms-v1_20_R4 + ${revision} + compile + \ No newline at end of file diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java index 5ff78d23..2ba8b68a 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/Orebfuscator.java @@ -1,5 +1,7 @@ package net.imprex.orebfuscator; +import java.util.logging.Level; + import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; @@ -17,6 +19,7 @@ import net.imprex.orebfuscator.player.OrebfuscatorPlayerMap; import net.imprex.orebfuscator.proximity.ProximityDirectorThread; import net.imprex.orebfuscator.proximity.ProximityPacketListener; +import net.imprex.orebfuscator.util.ConsoleUtil; import net.imprex.orebfuscator.util.HeightAccessor; import net.imprex.orebfuscator.util.OFCLogger; @@ -42,6 +45,12 @@ public void onLoad() { @Override public void onEnable() { try { + ConsoleUtil.printBox(Level.SEVERE, + "WARNING", + "REMOVAL OF SUPPORT FOR JAVA VERSIONS BEFORE 17 AND MINECRAFT VERSIONS BEFORE 1.16", + "", + "https://github.com/Imprex-Development/orebfuscator/discussions/367"); + // Check if protocolLib is enabled Plugin protocolLib = getServer().getPluginManager().getPlugin("ProtocolLib"); if (protocolLib == null || !protocolLib.isEnabled()) { diff --git a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/ConsoleUtil.java b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/ConsoleUtil.java index 14736a68..209c99b1 100644 --- a/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/ConsoleUtil.java +++ b/orebfuscator-plugin/src/main/java/net/imprex/orebfuscator/util/ConsoleUtil.java @@ -8,7 +8,7 @@ public final class ConsoleUtil { private static final int BOX_PADDING = 3; - private static final int BOX_MAX_WIDTH = 48; + private static final int BOX_PREFERRED_WIDTH = 48; private ConsoleUtil() { } @@ -28,12 +28,12 @@ public static Iterable createBox(String...lines) { for (String line : lines) { line = line.trim(); - while (line.length() > BOX_MAX_WIDTH) { + while (line.length() > BOX_PREFERRED_WIDTH) { int splitLength = 0; for (int i = 0; i < line.length(); i++) { if (Character.isWhitespace(line.charAt(i))) { - if (i <= BOX_MAX_WIDTH) { + if (i <= BOX_PREFERRED_WIDTH) { splitLength = i; } else { break; @@ -41,6 +41,11 @@ public static Iterable createBox(String...lines) { } } + // can't split line no whitespace character found + if (splitLength == 0) { + break; + } + // split line at latest word that fit length wrappedLines.add(line.substring(0, splitLength)); line = line.substring(splitLength, line.length()).trim(); diff --git a/pom.xml b/pom.xml index 761a9165..c41acc1b 100644 --- a/pom.xml +++ b/pom.xml @@ -23,16 +23,16 @@ 1.20.1-R0.1-SNAPSHOT 1.20.1-R0.1-SNAPSHOT 3.0.2 - 5.10.0 - 4.1.68.Final + 5.10.2 + 4.1.90.Final 5.0.0 1.10.5 - 3.11.0 - 3.5.0 - 3.1.2 - 1.5.0 - 1.2.5 + 3.13.0 + 3.5.2 + 3.2.5 + 1.6.0 + 2.0.2 UTF-8