geforkt von Mirrors/AxiomPaperPlugin
Support Axiom b0.7
Dieser Commit ist enthalten in:
Ursprung
10240f435c
Commit
76b00ce0ad
@ -15,6 +15,7 @@ import io.papermc.paper.network.ChannelInitializeListenerHolder;
|
|||||||
import io.papermc.paper.network.ConnectionEvent;
|
import io.papermc.paper.network.ConnectionEvent;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import net.kyori.adventure.key.Key;
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.network.Connection;
|
import net.minecraft.network.Connection;
|
||||||
import net.minecraft.network.ConnectionProtocol;
|
import net.minecraft.network.ConnectionProtocol;
|
||||||
@ -46,6 +47,13 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class AxiomPaper extends JavaPlugin implements Listener {
|
public class AxiomPaper extends JavaPlugin implements Listener {
|
||||||
|
|
||||||
|
public static final long MIN_POSITION_LONG = BlockPos.asLong(-33554432, -2048, -33554432);
|
||||||
|
static {
|
||||||
|
if (MIN_POSITION_LONG != 0b1000000000000000000000000010000000000000000000000000100000000000L) {
|
||||||
|
throw new Error("BlockPos representation changed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
Bukkit.getPluginManager().registerEvents(this, this);
|
Bukkit.getPluginManager().registerEvents(this, this);
|
||||||
|
88
src/main/java/com/moulberry/axiom/buffer/BiomeBuffer.java
Normale Datei
88
src/main/java/com/moulberry/axiom/buffer/BiomeBuffer.java
Normale Datei
@ -0,0 +1,88 @@
|
|||||||
|
package com.moulberry.axiom.buffer;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ByteMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
|
||||||
|
public class BiomeBuffer {
|
||||||
|
|
||||||
|
private final Position2ByteMap map;
|
||||||
|
private final ResourceKey<Biome>[] palette;
|
||||||
|
private final Object2ByteMap<ResourceKey<Biome>> paletteReverse;
|
||||||
|
private int paletteSize = 0;
|
||||||
|
|
||||||
|
public BiomeBuffer() {
|
||||||
|
this.map = new Position2ByteMap();
|
||||||
|
this.palette = new ResourceKey[255];
|
||||||
|
this.paletteReverse = new Object2ByteOpenHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private BiomeBuffer(Position2ByteMap map, ResourceKey<Biome>[] palette, Object2ByteMap<ResourceKey<Biome>> paletteReverse) {
|
||||||
|
this.map = map;
|
||||||
|
this.palette = palette;
|
||||||
|
this.paletteReverse = paletteReverse;
|
||||||
|
this.paletteSize = this.paletteReverse.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(FriendlyByteBuf friendlyByteBuf) {
|
||||||
|
friendlyByteBuf.writeByte(this.paletteSize);
|
||||||
|
for (int i = 0; i < this.paletteSize; i++) {
|
||||||
|
friendlyByteBuf.writeResourceKey(this.palette[i]);
|
||||||
|
}
|
||||||
|
this.map.save(friendlyByteBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BiomeBuffer load(FriendlyByteBuf friendlyByteBuf) {
|
||||||
|
int paletteSize = friendlyByteBuf.readByte();
|
||||||
|
ResourceKey<Biome>[] palette = new ResourceKey[255];
|
||||||
|
Object2ByteMap<ResourceKey<Biome>> paletteReverse = new Object2ByteOpenHashMap<>();
|
||||||
|
for (int i = 0; i < paletteSize; i++) {
|
||||||
|
ResourceKey<Biome> key = friendlyByteBuf.readResourceKey(Registries.BIOME);
|
||||||
|
palette[i] = key;
|
||||||
|
paletteReverse.put(key, (byte)(i+1));
|
||||||
|
}
|
||||||
|
Position2ByteMap map = Position2ByteMap.load(friendlyByteBuf);
|
||||||
|
return new BiomeBuffer(map, palette, paletteReverse);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
this.map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forEachEntry(PositionConsumer<ResourceKey<Biome>> consumer) {
|
||||||
|
this.map.forEachEntry((x, y, z, v) -> {
|
||||||
|
if (v != 0) consumer.accept(x, y, z, this.palette[(v & 0xFF) - 1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceKey<Biome> get(int quartX, int quartY, int quartZ) {
|
||||||
|
int index = this.map.get(quartX, quartY, quartZ) & 0xFF;
|
||||||
|
if (index == 0) return null;
|
||||||
|
return this.palette[index - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getPaletteIndex(ResourceKey<Biome> biome) {
|
||||||
|
int index = this.paletteReverse.getOrDefault(biome, (byte) 0) & 0xFF;
|
||||||
|
if (index != 0) return index;
|
||||||
|
|
||||||
|
index = this.paletteSize;
|
||||||
|
if (index >= this.palette.length) {
|
||||||
|
throw new UnsupportedOperationException("Too many biomes! :(");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.palette[index] = biome;
|
||||||
|
this.paletteReverse.put(biome, (byte)(index + 1));
|
||||||
|
|
||||||
|
this.paletteSize += 1;
|
||||||
|
return index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(int quartX, int quartY, int quartZ, ResourceKey<Biome> biome) {
|
||||||
|
this.map.put(quartX, quartY, quartZ, (byte) this.getPaletteIndex(biome));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,13 +1,15 @@
|
|||||||
package com.moulberry.axiom.buffer;
|
package com.moulberry.axiom.buffer;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.AxiomPaper;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.*;
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
|
|
||||||
public class BlockBuffer {
|
public class BlockBuffer {
|
||||||
|
|
||||||
@ -16,7 +18,7 @@ public class BlockBuffer {
|
|||||||
private final Long2ObjectMap<PalettedContainer<BlockState>> values;
|
private final Long2ObjectMap<PalettedContainer<BlockState>> values;
|
||||||
|
|
||||||
private PalettedContainer<BlockState> last = null;
|
private PalettedContainer<BlockState> last = null;
|
||||||
private long lastId = Long.MAX_VALUE;
|
private long lastId = AxiomPaper.MIN_POSITION_LONG;
|
||||||
private int count;
|
private int count;
|
||||||
|
|
||||||
public BlockBuffer() {
|
public BlockBuffer() {
|
||||||
@ -31,9 +33,32 @@ public class BlockBuffer {
|
|||||||
return this.count;
|
return this.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void save(FriendlyByteBuf friendlyByteBuf) {
|
||||||
|
for (Long2ObjectMap.Entry<PalettedContainer<BlockState>> entry : this.entrySet()) {
|
||||||
|
friendlyByteBuf.writeLong(entry.getLongKey());
|
||||||
|
entry.getValue().write(friendlyByteBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
friendlyByteBuf.writeLong(AxiomPaper.MIN_POSITION_LONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockBuffer load(FriendlyByteBuf friendlyByteBuf) {
|
||||||
|
BlockBuffer buffer = new BlockBuffer();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
long index = friendlyByteBuf.readLong();
|
||||||
|
if (index == AxiomPaper.MIN_POSITION_LONG) break;
|
||||||
|
|
||||||
|
PalettedContainer<BlockState> palettedContainer = buffer.getOrCreateSection(index);
|
||||||
|
palettedContainer.read(friendlyByteBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
this.last = null;
|
this.last = null;
|
||||||
this.lastId = Long.MAX_VALUE;
|
this.lastId = AxiomPaper.MIN_POSITION_LONG;
|
||||||
this.values.clear();
|
this.values.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
179
src/main/java/com/moulberry/axiom/buffer/Position2ByteMap.java
Normale Datei
179
src/main/java/com/moulberry/axiom/buffer/Position2ByteMap.java
Normale Datei
@ -0,0 +1,179 @@
|
|||||||
|
package com.moulberry.axiom.buffer;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.AxiomPaper;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.function.LongFunction;
|
||||||
|
|
||||||
|
public class Position2ByteMap {
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface EntryConsumer {
|
||||||
|
void consume(int x, int y, int z, byte v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final byte defaultValue;
|
||||||
|
private final LongFunction<byte[]> defaultFunction;
|
||||||
|
private final Long2ObjectMap<byte[]> map = new Long2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
private long lastChunkPos = AxiomPaper.MIN_POSITION_LONG;
|
||||||
|
private byte[] lastChunk = null;
|
||||||
|
|
||||||
|
public Position2ByteMap() {
|
||||||
|
this((byte) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Position2ByteMap(byte defaultValue) {
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
|
||||||
|
if (defaultValue == 0) {
|
||||||
|
this.defaultFunction = k -> new byte[16*16*16];
|
||||||
|
} else {
|
||||||
|
this.defaultFunction = k -> {
|
||||||
|
byte[] array = new byte[16*16*16];
|
||||||
|
Arrays.fill(array, defaultValue);
|
||||||
|
return array;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(FriendlyByteBuf friendlyByteBuf) {
|
||||||
|
friendlyByteBuf.writeByte(this.defaultValue);
|
||||||
|
for (Long2ObjectMap.Entry<byte[]> entry : this.map.long2ObjectEntrySet()) {
|
||||||
|
friendlyByteBuf.writeLong(entry.getLongKey());
|
||||||
|
friendlyByteBuf.writeBytes(entry.getValue());
|
||||||
|
}
|
||||||
|
friendlyByteBuf.writeLong(AxiomPaper.MIN_POSITION_LONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Position2ByteMap load(FriendlyByteBuf friendlyByteBuf) {
|
||||||
|
Position2ByteMap map = new Position2ByteMap(friendlyByteBuf.readByte());
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
long pos = friendlyByteBuf.readLong();
|
||||||
|
if (pos == AxiomPaper.MIN_POSITION_LONG) break;
|
||||||
|
|
||||||
|
byte[] bytes = new byte[16*16*16];
|
||||||
|
friendlyByteBuf.readBytes(bytes);
|
||||||
|
map.map.put(pos, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
this.map.clear();
|
||||||
|
this.lastChunkPos = AxiomPaper.MIN_POSITION_LONG;
|
||||||
|
this.lastChunk = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte get(int x, int y, int z) {
|
||||||
|
int xC = x >> 4;
|
||||||
|
int yC = y >> 4;
|
||||||
|
int zC = z >> 4;
|
||||||
|
|
||||||
|
byte[] array = this.getChunk(xC, yC, zC);
|
||||||
|
if (array == null) return this.defaultValue;
|
||||||
|
|
||||||
|
return array[(x&15) + (y&15)*16 + (z&15)*16*16];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(int x, int y, int z, byte v) {
|
||||||
|
int xC = x >> 4;
|
||||||
|
int yC = y >> 4;
|
||||||
|
int zC = z >> 4;
|
||||||
|
|
||||||
|
byte[] array = this.getOrCreateChunk(xC, yC, zC);
|
||||||
|
array[(x&15) + (y&15)*16 + (z&15)*16*16] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte add(int x, int y, int z, byte v) {
|
||||||
|
if (v == 0) return this.get(x, y, z);
|
||||||
|
|
||||||
|
int xC = x >> 4;
|
||||||
|
int yC = y >> 4;
|
||||||
|
int zC = z >> 4;
|
||||||
|
|
||||||
|
byte[] array = this.getOrCreateChunk(xC, yC, zC);
|
||||||
|
return array[(x&15) + (y&15)*16 + (z&15)*16*16] += v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public byte binaryAnd(int x, int y, int z, byte v) {
|
||||||
|
int xC = x >> 4;
|
||||||
|
int yC = y >> 4;
|
||||||
|
int zC = z >> 4;
|
||||||
|
|
||||||
|
byte[] array = this.getOrCreateChunk(xC, yC, zC);
|
||||||
|
return array[(x&15) + (y&15)*16 + (z&15)*16*16] &= v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean min(int x, int y, int z, byte v) {
|
||||||
|
int xC = x >> 4;
|
||||||
|
int yC = y >> 4;
|
||||||
|
int zC = z >> 4;
|
||||||
|
|
||||||
|
byte[] array = this.getOrCreateChunk(xC, yC, zC);
|
||||||
|
int index = (x&15) + (y&15)*16 + (z&15)*16*16;
|
||||||
|
|
||||||
|
if (v < array[index]) {
|
||||||
|
array[index] = v;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forEachEntry(EntryConsumer consumer) {
|
||||||
|
for (Long2ObjectMap.Entry<byte[]> entry : this.map.long2ObjectEntrySet()) {
|
||||||
|
int cx = BlockPos.getX(entry.getLongKey()) * 16;
|
||||||
|
int cy = BlockPos.getY(entry.getLongKey()) * 16;
|
||||||
|
int cz = BlockPos.getZ(entry.getLongKey()) * 16;
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
for (int z=0; z<16; z++) {
|
||||||
|
for (int y=0; y<16; y++) {
|
||||||
|
for (int x=0; x<16; x++) {
|
||||||
|
byte v = entry.getValue()[index++];
|
||||||
|
if (v != this.defaultValue) {
|
||||||
|
consumer.consume(cx + x, cy + y, cz + z, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getChunk(int xC, int yC, int zC) {
|
||||||
|
return this.getChunk(BlockPos.asLong(xC, yC, zC));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getChunk(long pos) {
|
||||||
|
if (this.lastChunkPos != pos) {
|
||||||
|
byte[] chunk = this.map.get(pos);
|
||||||
|
this.lastChunkPos = pos;
|
||||||
|
this.lastChunk = chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.lastChunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getOrCreateChunk(int xC, int yC, int zC) {
|
||||||
|
return this.getOrCreateChunk(BlockPos.asLong(xC, yC, zC));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getOrCreateChunk(long pos) {
|
||||||
|
if (this.lastChunk == null || this.lastChunkPos != pos) {
|
||||||
|
byte[] chunk = this.map.computeIfAbsent(pos, this.defaultFunction);
|
||||||
|
this.lastChunkPos = pos;
|
||||||
|
this.lastChunk = chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.lastChunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
src/main/java/com/moulberry/axiom/buffer/PositionConsumer.java
Normale Datei
8
src/main/java/com/moulberry/axiom/buffer/PositionConsumer.java
Normale Datei
@ -0,0 +1,8 @@
|
|||||||
|
package com.moulberry.axiom.buffer;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface PositionConsumer<T> {
|
||||||
|
|
||||||
|
void accept(int x, int y, int z, T t);
|
||||||
|
|
||||||
|
}
|
@ -13,7 +13,7 @@ import java.util.List;
|
|||||||
|
|
||||||
public class AxiomBigPayloadHandler extends ByteToMessageDecoder {
|
public class AxiomBigPayloadHandler extends ByteToMessageDecoder {
|
||||||
|
|
||||||
private static final ResourceLocation SET_BLOCK_BUFFER = new ResourceLocation("axiom", "set_block_buffer");
|
private static final ResourceLocation SET_BUFFER = new ResourceLocation("axiom", "set_buffer");
|
||||||
private final int payloadId;
|
private final int payloadId;
|
||||||
private final Connection connection;
|
private final Connection connection;
|
||||||
private final SetBlockBufferPacketListener listener;
|
private final SetBlockBufferPacketListener listener;
|
||||||
@ -35,7 +35,7 @@ public class AxiomBigPayloadHandler extends ByteToMessageDecoder {
|
|||||||
|
|
||||||
if (packetId == payloadId) {
|
if (packetId == payloadId) {
|
||||||
ResourceLocation identifier = buf.readResourceLocation();
|
ResourceLocation identifier = buf.readResourceLocation();
|
||||||
if (identifier.equals(SET_BLOCK_BUFFER)) {
|
if (identifier.equals(SET_BUFFER)) {
|
||||||
ServerPlayer player = connection.getPlayer();
|
ServerPlayer player = connection.getPlayer();
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
listener.onReceive(player, buf);
|
listener.onReceive(player, buf);
|
||||||
|
@ -1,21 +1,29 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
import com.moulberry.axiom.AxiomPaper;
|
import com.moulberry.axiom.AxiomPaper;
|
||||||
|
import com.moulberry.axiom.buffer.BiomeBuffer;
|
||||||
import com.moulberry.axiom.buffer.BlockBuffer;
|
import com.moulberry.axiom.buffer.BlockBuffer;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundChunksBiomesPacket;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
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;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
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.chunk.PalettedContainer;
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
@ -29,7 +37,7 @@ import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
|
|||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Map;
|
import java.util.*;
|
||||||
|
|
||||||
public class SetBlockBufferPacketListener {
|
public class SetBlockBufferPacketListener {
|
||||||
|
|
||||||
@ -52,19 +60,26 @@ public class SetBlockBufferPacketListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onReceive(ServerPlayer player, FriendlyByteBuf friendlyByteBuf) {
|
public void onReceive(ServerPlayer player, FriendlyByteBuf friendlyByteBuf) {
|
||||||
|
MinecraftServer server = player.getServer();
|
||||||
|
if (server == null) return;
|
||||||
|
|
||||||
ResourceKey<Level> worldKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
ResourceKey<Level> worldKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
||||||
BlockBuffer buffer = new BlockBuffer();
|
|
||||||
|
|
||||||
while (true) {
|
byte type = friendlyByteBuf.readByte();
|
||||||
long index = friendlyByteBuf.readLong();
|
if (type == 0) {
|
||||||
if (index == Long.MAX_VALUE) break;
|
BlockBuffer buffer = BlockBuffer.load(friendlyByteBuf);
|
||||||
|
applyBlockBuffer(server, buffer, worldKey);
|
||||||
PalettedContainer<BlockState> palettedContainer = buffer.getOrCreateSection(index);
|
} else if (type == 1) {
|
||||||
palettedContainer.read(friendlyByteBuf);
|
BiomeBuffer buffer = BiomeBuffer.load(friendlyByteBuf);
|
||||||
|
applyBiomeBuffer(server, buffer, worldKey);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Unknown buffer type: " + type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
player.getServer().execute(() -> {
|
private void applyBlockBuffer(MinecraftServer server, BlockBuffer buffer, ResourceKey<Level> worldKey) {
|
||||||
ServerLevel world = player.getServer().getLevel(worldKey);
|
server.execute(() -> {
|
||||||
|
ServerLevel world = server.getLevel(worldKey);
|
||||||
if (world == null) return;
|
if (world == null) return;
|
||||||
|
|
||||||
BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos();
|
BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos();
|
||||||
@ -182,4 +197,52 @@ public class SetBlockBufferPacketListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void applyBiomeBuffer(MinecraftServer server, BiomeBuffer biomeBuffer, ResourceKey<Level> worldKey) {
|
||||||
|
server.execute(() -> {
|
||||||
|
ServerLevel world = server.getLevel(worldKey);
|
||||||
|
if (world == null) return;
|
||||||
|
|
||||||
|
Set<LevelChunk> changedChunks = new HashSet<>();
|
||||||
|
|
||||||
|
int minSection = world.getMinSection();
|
||||||
|
int maxSection = world.getMaxSection();
|
||||||
|
|
||||||
|
Optional<Registry<Biome>> registryOptional = world.registryAccess().registry(Registries.BIOME);
|
||||||
|
if (registryOptional.isEmpty()) return;
|
||||||
|
|
||||||
|
Registry<Biome> registry = registryOptional.get();
|
||||||
|
|
||||||
|
biomeBuffer.forEachEntry((x, y, z, biome) -> {
|
||||||
|
int cy = y >> 2;
|
||||||
|
if (cy < minSection || cy >= maxSection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var chunk = (LevelChunk) world.getChunk(x >> 2, z >> 2, ChunkStatus.FULL, false);
|
||||||
|
if (chunk == null) return;
|
||||||
|
|
||||||
|
var section = chunk.getSection(cy - minSection);
|
||||||
|
PalettedContainer<Holder<Biome>> container = (PalettedContainer<Holder<Biome>>) section.getBiomes();
|
||||||
|
|
||||||
|
var holder = registry.getHolder(biome);
|
||||||
|
if (holder.isPresent()) {
|
||||||
|
container.set(x & 3, y & 3, z & 3, holder.get());
|
||||||
|
changedChunks.add(chunk);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var chunkMap = world.getChunkSource().chunkMap;
|
||||||
|
HashMap<ServerPlayer, List<LevelChunk>> map = new HashMap<>();
|
||||||
|
for (LevelChunk chunk : changedChunks) {
|
||||||
|
chunk.setUnsaved(true);
|
||||||
|
ChunkPos chunkPos = chunk.getPos();
|
||||||
|
for (ServerPlayer serverPlayer2 : chunkMap.getPlayers(chunkPos, false)) {
|
||||||
|
map.computeIfAbsent(serverPlayer2, serverPlayer -> new ArrayList<>()).add(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map.forEach((serverPlayer, list) -> serverPlayer.connection.send(ClientboundChunksBiomesPacket.forChunks(list)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren