Add 1.19.3 compatibility layer
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful

Dieser Commit ist enthalten in:
Lixfel 2023-09-14 12:19:20 +02:00
Ursprung 6f5617ded3
Commit 162bfc8fe2
8 geänderte Dateien mit 137 neuen und 36 gelöschten Zeilen

Datei anzeigen

@ -6,10 +6,11 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerChunkCache; import net.minecraft.network.protocol.Packet;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.*;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.server.network.ServerPlayerConnection;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -19,6 +20,7 @@ import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -66,6 +68,23 @@ public class AxiomPaper extends JavaPlugin implements Listener {
return getChunkSource.invoke(level); return getChunkSource.invoke(level);
} }
private static final Reflection.Method<ServerChunkCache, ThreadedLevelLightEngine> getLightEngine = Reflection.getTypedMethod(ServerChunkCache.class, ThreadedLevelLightEngine.class);
public static ThreadedLevelLightEngine getLightEngine(ServerChunkCache chunkSource) {
return getLightEngine.invoke(chunkSource);
}
private static final Reflection.Method<ServerPlayerConnection, Void> send = Reflection.getMethod(ServerPlayerConnection.class, Packet.class);
public static void sendPacket(ServerPlayer player, Packet<?> packet) {
send.invoke(AxiomPaper.getConnection(player), packet);
}
private static final Reflection.Field<ServerChunkCache, ChunkMap> chunkMap = Reflection.getField(ServerChunkCache.class, ChunkMap.class);
private static final Reflection.Method<ChunkMap, List> getPlayers = Reflection.getTypedMethod(ChunkMap.class, List.class, ChunkPos.class, boolean.class);
public static List<ServerPlayer> getPlayersSeeingChunk(ServerLevel level, ChunkPos pos) {
ChunkMap map = chunkMap.get(AxiomPaper.getChunkSource(level));
return (List<ServerPlayer>)getPlayers.invoke(map, pos, false);
}
@Override @Override
public void onEnable() { public void onEnable() {
instance = this; instance = this;

Datei anzeigen

@ -127,6 +127,12 @@ public class Reflection {
private static final String ORG_BUKKIT_CRAFTBUKKIT = Bukkit.getServer().getClass().getPackage().getName(); private static final String ORG_BUKKIT_CRAFTBUKKIT = Bukkit.getServer().getClass().getPackage().getName();
public static final int VERSION; // Format: 2 digit minor version, 2 digit CraftBukkit revision: eg. 2001 for v1_20_R1
static {
String[] version = ORG_BUKKIT_CRAFTBUKKIT.substring(ORG_BUKKIT_CRAFTBUKKIT.lastIndexOf('.')).split("_");
VERSION = Integer.parseInt(version[1]) * 100 + Integer.parseInt(version[2].substring(1));
}
public static <T> Class<T> getClass(String name) { public static <T> Class<T> getClass(String name) {
if(name.startsWith("org.bukkit.craftbukkit")) if(name.startsWith("org.bukkit.craftbukkit"))
name = ORG_BUKKIT_CRAFTBUKKIT + name.substring(22); name = ORG_BUKKIT_CRAFTBUKKIT + name.substring(22);

Datei anzeigen

@ -49,7 +49,7 @@ public class ViaVersionTranslator implements VersionTranslator {
@Override @Override
public void readPalettedContainer(Player player, ByteBuf buf, PositionConsumer<BlockState> consumer) { public void readPalettedContainer(Player player, ByteBuf buf, PositionConsumer<BlockState> consumer) {
//TODO GlobalPaletteBits depend on player version //TODO GlobalPaletteBits depend on player version (currently only 1.20.1, depending on Axiom version)
DataPalette container; DataPalette container;
try { try {
container = new PaletteType1_18(PaletteType.BLOCKS, 15).read(buf); container = new PaletteType1_18(PaletteType.BLOCKS, 15).read(buf);

Datei anzeigen

@ -2,12 +2,12 @@ package com.moulberry.axiom.packet;
import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.Reflection; import com.moulberry.axiom.Reflection;
import com.moulberry.axiom.version.VersionWrapper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos; import net.minecraft.core.SectionPos;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.EntityBlock;
@ -18,7 +18,6 @@ import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.lighting.LightEngine;
import net.minecraft.world.level.lighting.LightEventListener; import net.minecraft.world.level.lighting.LightEventListener;
import org.bukkit.World; import org.bukkit.World;
@ -42,7 +41,6 @@ public class ChunkSectionModifier {
private final Heightmap[] heightmaps; private final Heightmap[] heightmaps;
private final boolean hadOnlyAir; private final boolean hadOnlyAir;
private static final Reflection.Method<ServerChunkCache, ThreadedLevelLightEngine> getLightEngine = Reflection.getTypedMethod(ServerChunkCache.class, ThreadedLevelLightEngine.class);
private static final Reflection.Method<ChunkAccess, LevelChunkSection> getSection = Reflection.getTypedMethod(ChunkAccess.class, LevelChunkSection.class, int.class); private static final Reflection.Method<ChunkAccess, LevelChunkSection> getSection = Reflection.getTypedMethod(ChunkAccess.class, LevelChunkSection.class, int.class);
private static final Reflection.Method<LevelChunkSection, Boolean> hasOnlyAir = Reflection.getTypedMethod(LevelChunkSection.class, boolean.class, 1); private static final Reflection.Method<LevelChunkSection, Boolean> hasOnlyAir = Reflection.getTypedMethod(LevelChunkSection.class, boolean.class, 1);
private static final Reflection.Field<ChunkAccess, Map> chunkHeightmaps = Reflection.getField(ChunkAccess.class, Map.class); private static final Reflection.Field<ChunkAccess, Map> chunkHeightmaps = Reflection.getField(ChunkAccess.class, Map.class);
@ -53,7 +51,7 @@ public class ChunkSectionModifier {
ServerLevel level = AxiomPaper.convert(world); ServerLevel level = AxiomPaper.convert(world);
chunkSource = AxiomPaper.getChunkSource(level); chunkSource = AxiomPaper.getChunkSource(level);
lightEngine = getLightEngine.invoke(chunkSource); lightEngine = AxiomPaper.getLightEngine(chunkSource);
chunk = AxiomPaper.getChunk(level, cx, cz); chunk = AxiomPaper.getChunk(level, cx, cz);
section = getSection.invoke(chunk, cy - world.getMinHeight() / 16); section = getSection.invoke(chunk, cy - world.getMinHeight() / 16);
@ -67,7 +65,6 @@ public class ChunkSectionModifier {
private static final Reflection.Method<BlockState, Block> getBlock = Reflection.getTypedMethod(BlockState.class, Block.class); private static final Reflection.Method<BlockState, Block> getBlock = Reflection.getTypedMethod(BlockState.class, Block.class);
private static final Reflection.Method<ChunkAccess, Void> removeBlockEntity = Reflection.getMethod(ChunkAccess.class, BlockPos.class); private static final Reflection.Method<ChunkAccess, Void> removeBlockEntity = Reflection.getMethod(ChunkAccess.class, BlockPos.class);
private static final Reflection.Method<ServerChunkCache, Void> blockChanged = Reflection.getMethod(ServerChunkCache.class, BlockPos.class); private static final Reflection.Method<ServerChunkCache, Void> blockChanged = Reflection.getMethod(ServerChunkCache.class, BlockPos.class);
private static final Reflection.Method<LightEngine, Boolean> hasDifferentLightProperties = Reflection.getTypedMethod(LightEngine.class, boolean.class, BlockGetter.class, BlockPos.class, BlockState.class, BlockState.class);
private static final Reflection.Method<LightEventListener, Void> checkBlock = Reflection.getMethod(LightEventListener.class, BlockPos.class); private static final Reflection.Method<LightEventListener, Void> checkBlock = Reflection.getMethod(LightEventListener.class, BlockPos.class);
public void setState(int sx, int sy, int sz, BlockState state) { public void setState(int sx, int sy, int sz, BlockState state) {
BlockState old = setBlockState.invoke(section, sx, sy, sz, state, false); BlockState old = setBlockState.invoke(section, sx, sy, sz, state, false);
@ -88,7 +85,7 @@ public class ChunkSectionModifier {
blockChanged.invoke(chunkSource, pos); blockChanged.invoke(chunkSource, pos);
if (hasDifferentLightProperties.invoke(null, chunk, pos, old, state)) { if (VersionWrapper.impl.hasDifferentLightProperties(chunk, pos, old, state)) {
checkBlock.invoke(lightEngine, pos); checkBlock.invoke(lightEngine, pos);
} }
} }

Datei anzeigen

@ -2,30 +2,22 @@ package com.moulberry.axiom.packet;
import com.moulberry.axiom.AxiomConstants; import com.moulberry.axiom.AxiomConstants;
import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.Reflection;
import com.moulberry.axiom.buffer.BiomeBuffer; import com.moulberry.axiom.buffer.BiomeBuffer;
import com.moulberry.axiom.buffer.CompressedBlockEntity; import com.moulberry.axiom.buffer.CompressedBlockEntity;
import com.moulberry.axiom.buffer.MojBuf; import com.moulberry.axiom.buffer.MojBuf;
import com.moulberry.axiom.event.AxiomModifyWorldEvent; import com.moulberry.axiom.event.AxiomModifyWorldEvent;
import com.moulberry.axiom.integration.RegionProtection; import com.moulberry.axiom.integration.RegionProtection;
import com.moulberry.axiom.integration.VersionTranslator; import com.moulberry.axiom.integration.VersionTranslator;
import com.moulberry.axiom.version.VersionWrapper;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundChunksBiomesPacket;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerPlayerConnection;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.*; import java.util.HashSet;
import java.util.Set;
public class SetBlockBufferPacketListener implements AxiomPacketListener { public class SetBlockBufferPacketListener implements AxiomPacketListener {
@ -80,10 +72,6 @@ public class SetBlockBufferPacketListener implements AxiomPacketListener {
} }
} }
private static final Reflection.Field<ServerChunkCache, ChunkMap> chunkMap = Reflection.getField(ServerChunkCache.class, ChunkMap.class);
private static final Reflection.Method<ChunkMap, List> getPlayers = Reflection.getTypedMethod(ChunkMap.class, List.class, ChunkPos.class, boolean.class);
private static final Reflection.Method<ServerPlayerConnection, Void> send = Reflection.getMethod(ServerPlayerConnection.class, Packet.class);
private static final Reflection.Method<ClientboundChunksBiomesPacket, ClientboundChunksBiomesPacket> forChunks = Reflection.getTypedMethod(ClientboundChunksBiomesPacket.class, ClientboundChunksBiomesPacket.class, List.class);
private void applyBiomeBuffer(World world, BiomeBuffer biomeBuffer) { private void applyBiomeBuffer(World world, BiomeBuffer biomeBuffer) {
Set<Chunk> changedChunks = new HashSet<>(); Set<Chunk> changedChunks = new HashSet<>();
biomeBuffer.forEachEntry((x, y, z, biome) -> { biomeBuffer.forEachEntry((x, y, z, biome) -> {
@ -93,17 +81,7 @@ public class SetBlockBufferPacketListener implements AxiomPacketListener {
changedChunks.add(world.getChunkAt(cx, cz)); changedChunks.add(world.getChunkAt(cx, cz));
}); });
ServerLevel level = AxiomPaper.convert(world); VersionWrapper.impl.publishBiomeChange(AxiomPaper.convert(world), changedChunks);
ChunkMap map = chunkMap.get(AxiomPaper.getChunkSource(level));
HashMap<ServerPlayer, List<LevelChunk>> playerChunks = new HashMap<>();
for (Chunk chunk : changedChunks) {
ChunkPos chunkPos = new ChunkPos(chunk.getX(), chunk.getZ());
LevelChunk nativeChunk = AxiomPaper.getChunk(level, chunk.getX(), chunk.getZ());
for (ServerPlayer player : (List<ServerPlayer>)getPlayers.invoke(map, chunkPos, false)) {
playerChunks.computeIfAbsent(player, p -> new ArrayList<>()).add(nativeChunk);
}
}
playerChunks.forEach((serverPlayer, list) -> send.invoke(AxiomPaper.getConnection(serverPlayer), forChunks.invoke(null, list)));
} }
} }

Datei anzeigen

@ -0,0 +1,41 @@
package com.moulberry.axiom.version;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.Reflection;
import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.Chunk;
import java.util.Set;
public class Version19R2 implements VersionWrapper {
private static final Reflection.Method<BlockState, Integer> getLightBlock = Reflection.getTypedMethod(BlockState.class, int.class, BlockGetter.class, BlockPos.class);
private static final Reflection.Field<BlockState, Integer> lightEmission = Reflection.getField(BlockState.class, int.class);
private static final Reflection.Field<BlockState, Boolean> useShapeForLightOcclusion = Reflection.getField(BlockState.class, boolean.class);
@Override
public boolean hasDifferentLightProperties(BlockGetter chunk, BlockPos pos, BlockState old, BlockState state) {
return getLightBlock.invoke(old, chunk, pos) != getLightBlock.invoke(state, chunk, pos) || lightEmission.get(old) != lightEmission.get(state) || useShapeForLightOcclusion.get(old) || useShapeForLightOcclusion.get(state);
}
@Override
public void publishBiomeChange(ServerLevel level, Set<Chunk> chunks) {
ThreadedLevelLightEngine lightEngine = AxiomPaper.getLightEngine(AxiomPaper.getChunkSource(level));
for (Chunk chunk : chunks) {
ChunkPos chunkPos = new ChunkPos(chunk.getX(), chunk.getZ());
LevelChunk nativeChunk = AxiomPaper.getChunk(level, chunk.getX(), chunk.getZ());
ClientboundLevelChunkWithLightPacket packet = new ClientboundLevelChunkWithLightPacket(nativeChunk, lightEngine, null, null, true);
for (ServerPlayer player : AxiomPaper.getPlayersSeeingChunk(level, chunkPos)) {
AxiomPaper.sendPacket(player, packet);
}
}
}
}

Datei anzeigen

@ -0,0 +1,42 @@
package com.moulberry.axiom.version;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.Reflection;
import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.game.ClientboundChunksBiomesPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.lighting.LightEngine;
import org.bukkit.Chunk;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
public class Version20R1 implements VersionWrapper {
private static final Reflection.Method<LightEngine, Boolean> hasDifferentLightProperties = Reflection.getTypedMethod(LightEngine.class, boolean.class, BlockGetter.class, BlockPos.class, BlockState.class, BlockState.class);
@Override
public boolean hasDifferentLightProperties(BlockGetter chunk, BlockPos pos, BlockState old, BlockState state) {
return hasDifferentLightProperties.invoke(null, chunk, pos, old, state);
}
private static final Reflection.Method<ClientboundChunksBiomesPacket, ClientboundChunksBiomesPacket> forChunks = Reflection.getTypedMethod(ClientboundChunksBiomesPacket.class, ClientboundChunksBiomesPacket.class, List.class);
@Override
public void publishBiomeChange(ServerLevel level, Set<Chunk> chunks) {
HashMap<ServerPlayer, List<LevelChunk>> playerChunks = new HashMap<>();
for (Chunk chunk : chunks) {
ChunkPos chunkPos = new ChunkPos(chunk.getX(), chunk.getZ());
LevelChunk nativeChunk = AxiomPaper.getChunk(level, chunk.getX(), chunk.getZ());
for (ServerPlayer player : AxiomPaper.getPlayersSeeingChunk(level, chunkPos)) {
playerChunks.computeIfAbsent(player, p -> new ArrayList<>()).add(nativeChunk);
}
}
playerChunks.forEach((serverPlayer, list) -> AxiomPaper.sendPacket(serverPlayer, forChunks.invoke(null, list)));
}
}

Datei anzeigen

@ -0,0 +1,18 @@
package com.moulberry.axiom.version;
import com.moulberry.axiom.Reflection;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.Chunk;
import java.util.Set;
public interface VersionWrapper {
VersionWrapper impl = Reflection.VERSION > 1902 ? new Version20R1() : new Version19R2();
boolean hasDifferentLightProperties(BlockGetter chunk, BlockPos pos, BlockState old, BlockState state);
void publishBiomeChange(ServerLevel level, Set<Chunk> chunks);
}