diff --git a/build.gradle.kts b/build.gradle.kts index eac6daf..5d0b1a9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,6 +9,7 @@ minecraft_fp { modid = "chunkapi" name = "ChunkAPI" rootPkg = "$group.chunk" + version = "0.7.0" } api { diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/mixins/common/thermos/S26PacketMapChunkBulkMixin.java b/src/main/java/com/falsepattern/chunk/internal/mixin/mixins/common/thermos/S26PacketMapChunkBulkMixin.java new file mode 100644 index 0000000..dea4bb3 --- /dev/null +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/mixins/common/thermos/S26PacketMapChunkBulkMixin.java @@ -0,0 +1,153 @@ +/* + * ChunkAPI + * + * Copyright (C) 2023-2025 FalsePattern, The MEGA Team, LegacyModdingMC contributors + * All Rights Reserved + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, only version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.falsepattern.chunk.internal.mixin.mixins.common.thermos; + +import com.falsepattern.chunk.internal.mixin.helpers.LockHelper; +import lombok.val; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.play.server.S21PacketChunkData; +import net.minecraft.network.play.server.S26PacketMapChunkBulk; + +import java.io.IOException; +import java.util.concurrent.Semaphore; +import java.util.zip.DataFormatException; +import java.util.zip.Inflater; + +@Mixin(S26PacketMapChunkBulk.class) +public abstract class S26PacketMapChunkBulkMixin { + @Shadow(aliases = "field_149268_i", + remap = false) + private byte[] inflaterBuffer; + @Shadow(aliases = "field_149263_e", + remap = false) + private byte[] deflatedData; + @Shadow(aliases = "field_149266_a", + remap = false) + private int[] xPositions; + @Shadow(aliases = "field_149264_b", + remap = false) + private int[] zPositions; + @Shadow(aliases = "field_149265_c", + remap = false) + private int[] subChunkMasks; + @Shadow(aliases = "field_149262_d", + remap = false) + private int[] subChunkMSBMasks; + @Shadow(aliases = "field_149261_g", + remap = false) + private int deflatedSize; + @Shadow(aliases = "field_149267_h", + remap = false) + private boolean skylight; + @Shadow(aliases = "field_149260_f", + remap = false) + private byte[][] datas; + + @Shadow(remap = false) + protected abstract void compress(); + + /** + * @author FalsePattern + * @reason Replace functionality + */ + @Overwrite + public void readPacketData(PacketBuffer data) throws IOException { + short chunkCount = data.readShort(); + val sizes = new int[chunkCount]; + for (int i = 0; i < chunkCount; i++) { + sizes[i] = data.readInt(); + } + deflatedSize = data.readInt(); + skylight = data.readBoolean(); + xPositions = new int[chunkCount]; + zPositions = new int[chunkCount]; + subChunkMasks = new int[chunkCount]; + subChunkMSBMasks = new int[chunkCount]; + datas = new byte[chunkCount][]; + + while (!LockHelper.bufferLockS26PacketMapChunkBulk.tryLock()) { + Thread.yield(); + } + byte[] buf; + try { + if (inflaterBuffer.length < deflatedSize) { + inflaterBuffer = new byte[deflatedSize]; + } + + data.readBytes(inflaterBuffer, 0, deflatedSize); + buf = new byte[S21PacketChunkData.func_149275_c() * chunkCount]; + Inflater inflater = new Inflater(); + inflater.setInput(inflaterBuffer, 0, deflatedSize); + + try { + inflater.inflate(buf); + } catch (DataFormatException dataformatexception) { + throw new IOException("Bad compressed data format"); + } finally { + inflater.end(); + } + } finally { + LockHelper.bufferLockS26PacketMapChunkBulk.unlock(); + } + + int pos = 0; + + for (int i = 0; i < chunkCount; ++i) { + val size = sizes[i]; + xPositions[i] = data.readInt(); + zPositions[i] = data.readInt(); + subChunkMasks[i] = data.readUnsignedShort(); + + datas[i] = new byte[size]; + System.arraycopy(buf, pos, datas[i], 0, size); + pos += size; + } + } + + /** + * @author FalsePattern + * @reason Replace functionality + */ + @Overwrite + public void writePacketData(PacketBuffer data) { + compress(); + + data.writeShort(xPositions.length); + for (byte[] bytes : datas) { + data.writeInt(bytes.length); + } + data.writeInt(deflatedSize); + data.writeBoolean(skylight); + data.writeBytes(deflatedData, 0, deflatedSize); + + for (int i = 0; i < xPositions.length; ++i) { + data.writeInt(xPositions[i]); + data.writeInt(zPositions[i]); + data.writeShort((short) (subChunkMasks[i] & 65535)); + } + } +} diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/Mixin.java b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/Mixin.java index 2e5f6c8..65ac433 100644 --- a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/Mixin.java +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/Mixin.java @@ -44,14 +44,24 @@ import static com.falsepattern.chunk.internal.mixin.plugin.fplib.MixinHelper.req @RequiredArgsConstructor public enum Mixin implements IMixins { // @formatter:off - Core(Phase.EARLY, + VanillaCore(Phase.EARLY, + () -> !hasThermos(), common("vanilla.PlayerInstanceMixin", "vanilla.S21PacketChunkDataMixin", "vanilla.S22PacketMultiBlockChangeMixin", "vanilla.S23PacketBlockChangeMixin", "vanilla.S26PacketMapChunkBulkMixin"), client("vanilla.NetHandlerPlayClientMixin")), - + + ThermosCore(Phase.EARLY, + () -> hasThermos(), + common("vanilla.PlayerInstanceMixin", + "vanilla.S21PacketChunkDataMixin", + "vanilla.S22PacketMultiBlockChangeMixin", + "vanilla.S23PacketBlockChangeMixin", + "thermos.S26PacketMapChunkBulkMixin"), + client("vanilla.NetHandlerPlayClientMixin")), + //from: https://github.com/BallOfEnergy1/ChunkAPI/commit/4f5c0e60e04b6892d206f5f5d93cb20ba6b45608 Core_NoSpool(Phase.EARLY, avoid(Spool), @@ -110,4 +120,16 @@ public enum Mixin implements IMixins { return MixinHelper.server(mixins); } //endregion + + static boolean hasThermos() + { + try + { + Class.forName("thermos.Thermos"); + return true; + } + catch(ClassNotFoundException ignored) { + return false; + } + } }