Full Multiversion (untested)
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful

Dieser Commit ist enthalten in:
Lixfel 2023-09-12 17:32:07 +02:00
Ursprung 8cfed96b39
Commit a0367320c3
9 geänderte Dateien mit 133 neuen und 78 gelöschten Zeilen

Datei anzeigen

@ -6,8 +6,12 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
@ -17,7 +21,6 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
public class AxiomPaper extends JavaPlugin implements Listener {
@ -43,11 +46,26 @@ public class AxiomPaper extends JavaPlugin implements Listener {
return worldGetHandle.invoke(world);
}
private static final Reflection.Method<Level, LevelChunk> getChunk = Reflection.getTypedMethod(Level.class, LevelChunk.class, int.class, int.class);
public static LevelChunk getChunk(Level level, int cx, int cz) {
return getChunk.invoke(level, cx, cz);
}
private static final Reflection.Method<BlockPos, BlockPos> of = Reflection.getTypedMethod(BlockPos.class, BlockPos.class, long.class);
public static BlockPos convert(long packed) {
return of.invoke(null, packed);
}
private static final Reflection.Field<ServerPlayer, ServerGamePacketListenerImpl> serverPlayerConnection = Reflection.getField(ServerPlayer.class, ServerGamePacketListenerImpl.class);
public static ServerGamePacketListenerImpl getConnection(ServerPlayer player) {
return serverPlayerConnection.get(player);
}
private static final Reflection.Method<ServerLevel, ServerChunkCache> getChunkSource = Reflection.getTypedMethod(ServerLevel.class, ServerChunkCache.class);
public static ServerChunkCache getChunkSource(ServerLevel level) {
return getChunkSource.invoke(level);
}
@Override
public void onEnable() {
instance = this;
@ -55,7 +73,7 @@ public class AxiomPaper extends JavaPlugin implements Listener {
try {
Bukkit.getPluginManager().registerEvents(new PaperFailMoveListener(), this);
} catch (NoClassDefFoundError e) {
getLogger().log(Level.WARNING, "Axiom players may move too quickly according to the server. Use a current Paper version or increase the 'moved-too-quickly-multiplier' in spigot.yml.");
getLogger().log(java.util.logging.Level.WARNING, "Axiom players may move too quickly according to the server. Use a current Paper version or increase the 'moved-too-quickly-multiplier' in spigot.yml.");
}
for(OutChannel channel : OutChannel.values()) {
@ -65,13 +83,13 @@ public class AxiomPaper extends JavaPlugin implements Listener {
registerInChannel("hello", new HelloPacketListener(new AxiomPlayerManager()));
registerInChannel("set_gamemode", new SetGamemodePacketListener());
registerInChannel("set_fly_speed", new SetFlySpeedPacketListener());
registerInChannel("set_block", new SetBlockPacketListener()); //TODO multiversion
registerInChannel("set_block", new SetBlockPacketListener());
registerInChannel("set_hotbar_slot", new SetHotbarSlotPacketListener());
registerInChannel("switch_active_hotbar", new SwitchActiveHotbarPacketListener());
registerInChannel("teleport", new TeleportPacketListener());
registerInChannel("set_editor_views", new SetEditorViewsPacketListener());
registerInChannel("request_block_entity", new RequestBlockEntityPacketListener());
registerInChannel("handle_big_payload", new SetBlockBufferPacketListener()); //TODO multiversion
registerInChannel("handle_big_payload", new SetBlockBufferPacketListener());
}
private void registerInChannel(String channel, AxiomPacketListener handler) {

Datei anzeigen

@ -74,12 +74,16 @@ public class Reflection {
R invoke(T target, Object... arguments);
}
public static <T> Method<T, Object> getMethod(Class<T> clazz, Class<?>... params) {
return getTypedMethod(clazz, null, null, 0, params);
public static <T> Method<T, Void> getMethod(Class<T> clazz, Class<?>... params) {
return getTypedMethod(clazz, null, Void.TYPE, 0, params);
}
public static <T> Method<T, Object> getMethod(Class<T> clazz, String methodName, Class<?>... params) {
return getTypedMethod(clazz, methodName, null, 0, params);
public static <T> Method<T, Void> getMethod(Class<T> clazz, int index, Class<?>... params) {
return getTypedMethod(clazz, null, Void.TYPE, index, params);
}
public static <T> Method<T, Void> getMethod(Class<T> clazz, String methodName, Class<?>... params) {
return getTypedMethod(clazz, methodName, Void.TYPE, 0, params);
}
public static <T, R> Method<T, R> getTypedMethod(Class<T> clazz, Class<R> returnType, Class<?>... params) {

Datei anzeigen

@ -25,7 +25,7 @@ public record CompressedBlockEntity(int originalSize, byte compressionDict, byte
}
}
private static final Reflection.Method<NbtIo, Object> write = Reflection.getMethod(NbtIo.class, CompoundTag.class, DataOutput.class);
private static final Reflection.Method<NbtIo, Void> write = Reflection.getMethod(NbtIo.class, CompoundTag.class, DataOutput.class);
public static CompressedBlockEntity compress(CompoundTag tag, ByteArrayOutputStream baos) {
baos.reset();
DataOutputStream dos = new DataOutputStream(baos);

Datei anzeigen

@ -46,7 +46,7 @@ public class NoVersionTranslator implements VersionTranslator {
}
private static final PalettedContainer.Strategy SECTION_STATES = Reflection.getField(PalettedContainer.Strategy.class, PalettedContainer.Strategy.class).get(null);
private static final Reflection.Method<PalettedContainer, Object> read = Reflection.getMethod(PalettedContainer.class, FriendlyByteBuf.class);
private static final Reflection.Method<PalettedContainer, Void> read = Reflection.getMethod(PalettedContainer.class, FriendlyByteBuf.class);
@Override
public void readPalettedContainer(Player player, ByteBuf buf, PositionConsumer<BlockState> consumer) {
//EMPTY_STATE is completely ignored

Datei anzeigen

@ -7,10 +7,14 @@ import net.minecraft.core.SectionPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.levelgen.Heightmap;
@ -18,13 +22,14 @@ import net.minecraft.world.level.lighting.LightEngine;
import net.minecraft.world.level.lighting.LightEventListener;
import org.bukkit.World;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class ChunkSectionModifier {
//TODO multiversioning
private static final List<Heightmap.Types> types = List.of(Heightmap.Types.WORLD_SURFACE, Heightmap.Types.OCEAN_FLOOR, Heightmap.Types.MOTION_BLOCKING, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES);
//TODO end multiversioning
private static final Reflection.Method<Heightmap.Types, String> getSerializationKey = Reflection.getTypedMethod(Heightmap.Types.class, String.class);
private static final List<Heightmap.Types> types = Arrays.stream(Heightmap.Types.values()).filter(type -> List.of("WORLD_SURFACE", "OCEAN_FLOOR", "MOTION_BLOCKING", "MOTION_BLOCKING_NO_LEAVES").contains(getSerializationKey.invoke(type))).toList();
private final int cx;
private final int cy;
@ -37,30 +42,35 @@ public class ChunkSectionModifier {
private final Heightmap[] heightmaps;
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<LevelChunkSection, Boolean> hasOnlyAir = Reflection.getTypedMethod(LevelChunkSection.class, boolean.class, 1);
private static final Reflection.Field<ChunkAccess, Map> chunkHeightmaps = Reflection.getField(ChunkAccess.class, Map.class);
public ChunkSectionModifier(World world, int cx, int cy, int cz) {
this.cx = cx;
this.cy = cy;
this.cz = cz;
ServerLevel level = AxiomPaper.convert(world);
//TODO multiversioning
chunkSource = level.getChunkSource();
lightEngine = chunkSource.getLightEngine();
chunk = level.getChunk(cx, cz);
chunkSource = AxiomPaper.getChunkSource(level);
lightEngine = getLightEngine.invoke(chunkSource);
chunk = AxiomPaper.getChunk(level, cx, cz);
section = chunk.getSection(cy - world.getMinHeight() >> 4);
hadOnlyAir = section.hasOnlyAir();
section = getSection.invoke(chunk, cy - world.getMinHeight() >> 4);
hadOnlyAir = hasOnlyAir.invoke(section);
heightmaps = types.stream().map(chunk.heightmaps::get).toArray(Heightmap[]::new);
//TODO end multiversioning
heightmaps = types.stream().map(chunkHeightmaps.get(chunk)::get).toArray(Heightmap[]::new);
}
private static final Reflection.Method<LevelChunkSection, BlockState> setBlockState = Reflection.getTypedMethod(LevelChunkSection.class, BlockState.class, int.class, int.class, int.class, BlockState.class, boolean.class);
private static final Reflection.Method<Heightmap, Boolean> update = Reflection.getTypedMethod(Heightmap.class, boolean.class, int.class, int.class, int.class, BlockState.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<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);
public void setState(int sx, int sy, int sz, BlockState state) {
//TODO multiversioning
if (hadOnlyAir && state.isAir())
return;
BlockState old = section.setBlockState(sx, sy, sz, state, false);
BlockState old = setBlockState.invoke(section, sx, sy, sz, state, false);
if (state == old)
return;
@ -68,68 +78,70 @@ public class ChunkSectionModifier {
BlockPos pos = new BlockPos(cx * 16 + sx, by, cz * 16 + sz);
for (Heightmap heightmap : heightmaps)
heightmap.update(sx, by, sz, state);
update.invoke(heightmap, sx, by, sz, state);
if (state.hasBlockEntity()) {
if (getBlock.invoke(state) instanceof EntityBlock) {
setBlockEntity(state, pos);
} else if (old.hasBlockEntity()) {
chunk.removeBlockEntity(pos);
} else if (getBlock.invoke(old) instanceof EntityBlock) {
removeBlockEntity.invoke(chunk, pos);
}
chunkSource.blockChanged(pos);
blockChanged.invoke(chunkSource, pos);
if (LightEngine.hasDifferentLightProperties(chunk, pos, old, state)) {
lightEngine.checkBlock(pos);
if (hasDifferentLightProperties.invoke(null, chunk, pos, old, state)) {
checkBlock.invoke(lightEngine, pos);
}
//TODO end multiversioning
}
private static final Reflection.Method<BlockGetter, BlockEntity> getBlockEntity = Reflection.getTypedMethod(BlockGetter.class, BlockEntity.class, BlockPos.class);
private static final Reflection.Method<BlockEntity, Void> load = Reflection.getMethod(BlockEntity.class, CompoundTag.class);
public void setBlockEntity(int sx, int sy, int sz, CompoundTag tag) {
//TODO multiversioning
BlockEntity blockEntity = chunk.getBlockEntity(new BlockPos(cx * 16 + sx, cy * 16 + sy, cz * 16 + sz), LevelChunk.EntityCreationType.CHECK);
BlockEntity blockEntity = getBlockEntity.invoke(chunk, new BlockPos(cx * 16 + sx, cy * 16 + sy, cz * 16 + sz));
if(blockEntity != null)
blockEntity.load(tag);
//TODO end multiversioning
load.invoke(blockEntity, tag);
}
private static final Reflection.Method<LevelChunk, Object> updateBlockEntityTicker = Reflection.getMethod(LevelChunk.class, BlockEntity.class);
private static final Reflection.Method<BlockEntity, BlockEntityType> getType = Reflection.getTypedMethod(BlockEntity.class, BlockEntityType.class);
private static final Reflection.Method<BlockEntityType, Boolean> isValid = Reflection.getTypedMethod(BlockEntityType.class, boolean.class, BlockState.class);
private static final Reflection.Method<BlockEntity, Void> blockEntitySetBlockState = Reflection.getMethod(BlockEntity.class, BlockState.class);
private static final Reflection.Method<LevelChunk, Void> updateBlockEntityTicker = Reflection.getMethod(LevelChunk.class, 2, BlockEntity.class);
private static final Reflection.Method<EntityBlock, BlockEntity> newBlockEntity = Reflection.getTypedMethod(EntityBlock.class, BlockEntity.class, BlockPos.class, BlockState.class);
private static final Reflection.Method<LevelChunk, Void> addAndRegisterBlockEntity = Reflection.getMethod(LevelChunk.class, BlockEntity.class);
private void setBlockEntity(BlockState state, BlockPos pos) {
//TODO multiversioning
BlockEntity blockEntity = chunk.getBlockEntity(pos, LevelChunk.EntityCreationType.CHECK);
BlockEntity blockEntity = getBlockEntity.invoke(chunk, pos, LevelChunk.EntityCreationType.CHECK);
if (blockEntity != null) {
if (blockEntity.getType().isValid(state)) {
if (isValid.invoke(getType.invoke(blockEntity), state)) {
// Block entity is here and the type is correct
blockEntity.setBlockState(state);
blockEntitySetBlockState.invoke(blockEntity, state);
updateBlockEntityTicker.invoke(chunk, blockEntity);
} else {
// Block entity type isn't correct, we need to recreate it
chunk.removeBlockEntity(pos);
removeBlockEntity.invoke(chunk, pos);
blockEntity = null;
}
}
if (blockEntity == null) {
// There isn't a block entity here, create it!
Block block = state.getBlock();
blockEntity = ((EntityBlock) block).newBlockEntity(pos, state);
EntityBlock block = (EntityBlock)getBlock.invoke(state);
blockEntity = newBlockEntity.invoke(block, pos, state);
if (blockEntity != null) {
chunk.addAndRegisterBlockEntity(blockEntity);
addAndRegisterBlockEntity.invoke(chunk, blockEntity);
}
}
//TODO end multiversioning
}
private static final Reflection.Method<SectionPos, SectionPos> of = Reflection.getTypedMethod(SectionPos.class, SectionPos.class, int.class, int.class, int.class);
private static final Reflection.Method<LightEventListener, Void> updateSectionStatus = Reflection.getMethod(LightEventListener.class, SectionPos.class, boolean.class);
private static final Reflection.Method<ChunkAccess, Void> setUnsaved = Reflection.getMethod(ChunkAccess.class, boolean.class);
public void finish() {
//TODO multiversioning
boolean hasOnlyAir = section.hasOnlyAir();
if (hadOnlyAir != hasOnlyAir) {
lightEngine.updateSectionStatus(SectionPos.of(cx, cy, cz), hasOnlyAir);
boolean onlyAir = hasOnlyAir.invoke(section);
if (hadOnlyAir != onlyAir) {
updateSectionStatus.invoke(lightEngine, of.invoke(null, cx, cy, cz), onlyAir);
}
chunk.setUnsaved(true);
//TODO end multiversioning
setUnsaved.invoke(chunk, true);
}
}

Datei anzeigen

@ -9,7 +9,6 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import net.kyori.adventure.text.Component;
import net.minecraft.network.Connection;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@ -23,7 +22,6 @@ import java.util.UUID;
public class HelloPacketListener implements AxiomPacketListener, Listener {
private static final Reflection.Field<ServerPlayer, ServerGamePacketListenerImpl> serverPlayerConnection = Reflection.getField(ServerPlayer.class, ServerGamePacketListenerImpl.class);
private static final Reflection.Field<ServerGamePacketListenerImpl, Connection> packetListenerConnection = Reflection.getField(ServerGamePacketListenerImpl.class, Connection.class);
private static final Reflection.Field<Connection, Channel> channel = Reflection.getField(Connection.class, Channel.class);
@ -54,7 +52,7 @@ public class HelloPacketListener implements AxiomPacketListener, Listener {
// Welcome to multiversioning!
channel.get(
packetListenerConnection.get(
serverPlayerConnection.get(
AxiomPaper.getConnection(
AxiomPaper.convert(player)
)
)

Datei anzeigen

@ -2,6 +2,7 @@ package com.moulberry.axiom.packet;
import com.moulberry.axiom.AxiomConstants;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.Reflection;
import com.moulberry.axiom.buffer.BiomeBuffer;
import com.moulberry.axiom.buffer.CompressedBlockEntity;
import com.moulberry.axiom.buffer.MojBuf;
@ -10,17 +11,18 @@ import com.moulberry.axiom.integration.RegionProtection;
import com.moulberry.axiom.integration.VersionTranslator;
import io.netty.buffer.ByteBuf;
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.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R1.CraftChunk;
import org.bukkit.entity.Player;
import java.util.*;
@ -78,6 +80,10 @@ 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) {
Set<Chunk> changedChunks = new HashSet<>();
biomeBuffer.forEachEntry((x, y, z, biome) -> {
@ -86,17 +92,16 @@ public class SetBlockBufferPacketListener implements AxiomPacketListener {
});
ServerLevel level = AxiomPaper.convert(world);
//TODO multiversioning
ChunkMap chunkMap = level.getChunkSource().chunkMap;
HashMap<ServerPlayer, List<LevelChunk>> map = new HashMap<>();
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());
for (ServerPlayer serverPlayer2 : chunkMap.getPlayers(chunkPos, false)) {
map.computeIfAbsent(serverPlayer2, serverPlayer -> new ArrayList<>()).add((LevelChunk) ((CraftChunk)chunk).getHandle(ChunkStatus.BIOMES));
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);
}
}
map.forEach((serverPlayer, list) -> serverPlayer.connection.send(ClientboundChunksBiomesPacket.forChunks(list)));
//TODO end multiversioning
playerChunks.forEach((serverPlayer, list) -> send.invoke(AxiomPaper.getConnection(serverPlayer), forChunks.invoke(null, list)));
}
}

Datei anzeigen

@ -1,23 +1,38 @@
package com.moulberry.axiom.packet;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.Reflection;
import com.moulberry.axiom.buffer.MojBuf;
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
import com.moulberry.axiom.integration.RegionProtection;
import com.moulberry.axiom.integration.VersionTranslator;
import io.netty.buffer.ByteBuf;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class SetBlockPacketListener implements AxiomPacketListener {
private static final Reflection.Method<Level, Boolean> setBlock = Reflection.getTypedMethod(Level.class, boolean.class, BlockPos.class, BlockState.class, int.class);
private static final Reflection.Method<Vec3i, Integer> getX = Reflection.getTypedMethod(Vec3i.class, int.class, 0);
private static final Reflection.Method<Vec3i, Integer> getY = Reflection.getTypedMethod(Vec3i.class, int.class, 1);
private static final Reflection.Method<Vec3i, Integer> getZ = Reflection.getTypedMethod(Vec3i.class, int.class, 2);
private static final Reflection.Method<ServerGamePacketListenerImpl, Void> ackBlockChangesUpTo = Reflection.getMethod(ServerGamePacketListenerImpl.class, int.class);
@Override
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
World world = player.getWorld();
// Check if player is allowed to modify this world
AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(player, player.getWorld());
AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(player, world);
Bukkit.getPluginManager().callEvent(modifyWorldEvent);
if (modifyWorldEvent.isCancelled()) return;
@ -28,21 +43,24 @@ public class SetBlockPacketListener implements AxiomPacketListener {
int sequenceId = buf.readInt();
ServerPlayer serverPlayer = AxiomPaper.convert(player);
int x = getX.invoke(pos);
int y = getY.invoke(pos);
int z = getZ.invoke(pos);
// Update blocks
//TODO multiversioning
if (updateNeighbors) {
AxiomPaper.convert(player.getWorld()).setBlock(pos, state, 3);
} else {
ChunkSectionModifier section = new ChunkSectionModifier(player.getWorld(), pos.getX() >> 4, pos.getY() >> 4, pos.getZ() >> 4);
section.setState(pos.getX() & 0xF, pos.getY() & 0xF, pos.getZ() & 0xF, state);
section.finish();
if(RegionProtection.getProtection.apply(player, world).canBuildInSection(x >> 4, y >> 4, z >> 4)) {
if (updateNeighbors) {
setBlock.invoke(AxiomPaper.convert(player.getWorld()), pos, state, 3);
} else {
ChunkSectionModifier section = new ChunkSectionModifier(player.getWorld(), x >> 4, y >> 4, z >> 4);
section.setState(x & 0xF, y & 0xF, z & 0xF, state);
section.finish();
}
}
if (sequenceId >= 0) {
serverPlayer.connection.ackBlockChangesUpTo(sequenceId);
ackBlockChangesUpTo.invoke(AxiomPaper.getConnection(serverPlayer), sequenceId);
}
//TODO end multiversioning
}
}

Datei anzeigen

@ -25,7 +25,7 @@ public class ItemStackDataType implements PersistentDataType<PersistentDataConta
}
private static final Class<PersistentDataContainer> CraftPersistentDataContainer = Reflection.getClass("org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer");
private static final Reflection.Method<PersistentDataContainer, Object> putAll = Reflection.getMethod(CraftPersistentDataContainer, "putAll", CompoundTag.class);
private static final Reflection.Method<PersistentDataContainer, Void> putAll = Reflection.getMethod(CraftPersistentDataContainer, "putAll", CompoundTag.class);
private static final Reflection.Method<PersistentDataContainer, CompoundTag> toTagCompound = Reflection.getTypedMethod(CraftPersistentDataContainer, "toTagCompound", CompoundTag.class);
private static final Reflection.Method<net.minecraft.world.item.ItemStack, CompoundTag> save = Reflection.getTypedMethod(net.minecraft.world.item.ItemStack.class, CompoundTag.class, CompoundTag.class);