9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

优化调色盘判断

This commit is contained in:
XiaoMoMi
2025-10-12 22:28:03 +08:00
parent a19cd429aa
commit 0ffad0621f
14 changed files with 172 additions and 115 deletions

View File

@@ -25,8 +25,10 @@ import net.momirealms.craftengine.core.plugin.logger.Debugger;
import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.sound.SoundData;
import net.momirealms.craftengine.core.sound.SoundSet; import net.momirealms.craftengine.core.sound.SoundSet;
import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import net.momirealms.craftengine.core.util.ObjectHolder;
import net.momirealms.craftengine.core.util.Tristate;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
@@ -322,9 +324,6 @@ public final class BukkitBlockManager extends AbstractBlockManager {
// 注册服务端侧的真实方块 // 注册服务端侧的真实方块
private void registerServerSideCustomBlocks(int count) { private void registerServerSideCustomBlocks(int count) {
// 这个会影响全局调色盘 // 这个会影响全局调色盘
if (MiscUtils.ceilLog2(this.vanillaBlockStateCount + count) == MiscUtils.ceilLog2(this.vanillaBlockStateCount)) {
PalettedContainer.NEED_DOWNGRADE = false;
}
try { try {
unfreezeRegistry(); unfreezeRegistry();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {

View File

@@ -8,4 +8,6 @@ public class BukkitBlockEntityTypes extends BlockEntityTypes {
public static final BlockEntityType<SimpleStorageBlockEntity> SIMPLE_STORAGE = register(BlockEntityTypeKeys.SIMPLE_STORAGE, SimpleStorageBlockEntity::new); public static final BlockEntityType<SimpleStorageBlockEntity> SIMPLE_STORAGE = register(BlockEntityTypeKeys.SIMPLE_STORAGE, SimpleStorageBlockEntity::new);
public static final BlockEntityType<SimpleParticleBlockEntity> SIMPLE_PARTICLE = register(BlockEntityTypeKeys.SIMPLE_PARTICLE, SimpleParticleBlockEntity::new); public static final BlockEntityType<SimpleParticleBlockEntity> SIMPLE_PARTICLE = register(BlockEntityTypeKeys.SIMPLE_PARTICLE, SimpleParticleBlockEntity::new);
public static final BlockEntityType<WallTorchParticleBlockEntity> WALL_TORCH_PARTICLE = register(BlockEntityTypeKeys.WALL_TORCH_PARTICLE, WallTorchParticleBlockEntity::new); public static final BlockEntityType<WallTorchParticleBlockEntity> WALL_TORCH_PARTICLE = register(BlockEntityTypeKeys.WALL_TORCH_PARTICLE, WallTorchParticleBlockEntity::new);
private BukkitBlockEntityTypes() {}
} }

View File

@@ -9,6 +9,8 @@ public class BukkitBlockEntityElementConfigs extends BlockEntityElementConfigs {
register(TEXT_DISPLAY, TextDisplayBlockEntityElementConfig.FACTORY); register(TEXT_DISPLAY, TextDisplayBlockEntityElementConfig.FACTORY);
} }
private BukkitBlockEntityElementConfigs() {}
public static void init() { public static void init() {
} }
} }

View File

@@ -299,7 +299,12 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
} }
this.blockStateRemapper = newMappings; this.blockStateRemapper = newMappings;
this.modBlockStateRemapper = newMappingsMOD; this.modBlockStateRemapper = newMappingsMOD;
registerS2CGamePacketListener(new LevelChunkWithLightListener(newMappings, newMappingsMOD, newMappings.length, RegistryUtils.currentBiomeRegistrySize()), this.packetIds.clientboundLevelChunkWithLightPacket(), "ClientboundLevelChunkWithLightPacket"); registerS2CGamePacketListener(new LevelChunkWithLightListener(
newMappings,
newMappingsMOD,
newMappings.length,
RegistryUtils.currentBiomeRegistrySize()
), this.packetIds.clientboundLevelChunkWithLightPacket(), "ClientboundLevelChunkWithLightPacket");
registerS2CGamePacketListener(new SectionBlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundSectionBlocksUpdatePacket(), "ClientboundSectionBlocksUpdatePacket"); registerS2CGamePacketListener(new SectionBlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundSectionBlocksUpdatePacket(), "ClientboundSectionBlocksUpdatePacket");
registerS2CGamePacketListener(new BlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundBlockUpdatePacket(), "ClientboundBlockUpdatePacket"); registerS2CGamePacketListener(new BlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundBlockUpdatePacket(), "ClientboundBlockUpdatePacket");
registerS2CGamePacketListener( registerS2CGamePacketListener(
@@ -1922,12 +1927,14 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
private final int[] modBlockStateMapper; private final int[] modBlockStateMapper;
private final IntIdentityList biomeList; private final IntIdentityList biomeList;
private final IntIdentityList blockList; private final IntIdentityList blockList;
private final boolean needsDowngrade;
public LevelChunkWithLightListener(int[] blockStateMapper, int[] modBlockStateMapper, int blockRegistrySize, int biomeRegistrySize) { public LevelChunkWithLightListener(int[] blockStateMapper, int[] modBlockStateMapper, int blockRegistrySize, int biomeRegistrySize) {
this.blockStateMapper = blockStateMapper; this.blockStateMapper = blockStateMapper;
this.modBlockStateMapper = modBlockStateMapper; this.modBlockStateMapper = modBlockStateMapper;
this.biomeList = new IntIdentityList(biomeRegistrySize); this.biomeList = new IntIdentityList(biomeRegistrySize);
this.blockList = new IntIdentityList(blockRegistrySize); this.blockList = new IntIdentityList(blockRegistrySize);
this.needsDowngrade = MiscUtils.ceilLog2(BlockStateUtils.vanillaBlockStateCount()) != MiscUtils.ceilLog2(blockRegistrySize);
} }
@Override @Override
@@ -1936,8 +1943,10 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
FriendlyByteBuf buf = event.getBuffer(); FriendlyByteBuf buf = event.getBuffer();
int chunkX = buf.readInt(); int chunkX = buf.readInt();
int chunkZ = buf.readInt(); int chunkZ = buf.readInt();
ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
boolean named = !VersionHelper.isOrAbove1_20_2(); boolean named = !VersionHelper.isOrAbove1_20_2();
// ClientboundLevelChunkPacketData
// 读取区块数据
int heightmapsCount = 0; int heightmapsCount = 0;
Map<Integer, long[]> heightmapsMap = null; Map<Integer, long[]> heightmapsMap = null;
net.momirealms.sparrow.nbt.Tag heightmaps = null; net.momirealms.sparrow.nbt.Tag heightmaps = null;
@@ -1956,112 +1965,105 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
int chunkDataBufferSize = buf.readVarInt(); int chunkDataBufferSize = buf.readVarInt();
byte[] chunkDataBytes = new byte[chunkDataBufferSize]; byte[] chunkDataBytes = new byte[chunkDataBufferSize];
buf.readBytes(chunkDataBytes); buf.readBytes(chunkDataBytes);
int blockEntitiesDataCount = buf.readVarInt();
List<BlockEntityData> blockEntitiesData = new ArrayList<>();
for (int i = 0; i < blockEntitiesDataCount; i++) {
byte packedXZ = buf.readByte();
short y = buf.readShort();
int type = buf.readVarInt();
Tag tag = buf.readNbt(named);
BlockEntityData blockEntityData = new BlockEntityData(packedXZ, y, type, tag);
blockEntitiesData.add(blockEntityData);
}
// ClientboundLightUpdatePacketData
BitSet skyYMask = buf.readBitSet();
BitSet blockYMask = buf.readBitSet();
BitSet emptySkyYMask = buf.readBitSet();
BitSet emptyBlockYMask = buf.readBitSet();
List<byte[]> skyUpdates = buf.readByteArrayList(2048);
List<byte[]> blockUpdates = buf.readByteArrayList(2048);
// 客户端侧section数量很重要不能读取此时玩家所在的真实世界包具有滞后性
int count = player.clientSideSectionCount(); int count = player.clientSideSectionCount();
MCSection[] sections = new MCSection[count]; MCSection[] sections = new MCSection[count];
FriendlyByteBuf chunkDataByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(chunkDataBytes)); FriendlyByteBuf chunkDataByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(chunkDataBytes));
// 开始处理
if (user.clientModEnabled()) {
for (int i = 0; i < count; i++) {
MCSection mcSection = new MCSection(user.clientBlockList(), this.blockList, this.biomeList);
mcSection.readPacket(chunkDataByteBuf);
PalettedContainer<Integer> container = mcSection.blockStateContainer();
remapBiomes(user, mcSection.biomeContainer());
Palette<Integer> palette = container.data().palette();
if (palette.canRemap()) {
palette.remap(s -> this.modBlockStateMapper[s]);
} else {
for (int j = 0; j < 4096; j++) {
int state = container.get(j);
int newState = this.modBlockStateMapper[state];
if (newState != state) {
container.set(j, newState);
}
}
}
sections[i] = mcSection;
}
} else {
for (int i = 0; i < count; i++) {
MCSection mcSection = new MCSection(user.clientBlockList(), this.blockList, this.biomeList);
mcSection.readPacket(chunkDataByteBuf);
PalettedContainer<Integer> container = mcSection.blockStateContainer();
remapBiomes(user, mcSection.biomeContainer());
Palette<Integer> palette = container.data().palette();
if (palette.canRemap()) {
palette.remap(s -> this.blockStateMapper[s]);
} else {
for (int j = 0; j < 4096; j++) {
int state = container.get(j);
int newState = this.blockStateMapper[state];
if (newState != state) {
container.set(j, newState);
}
}
}
sections[i] = mcSection;
}
}
FriendlyByteBuf newChunkDataBuf = new FriendlyByteBuf(Unpooled.buffer(chunkDataBufferSize)); boolean hasChangedAnyBlock = false;
boolean hasGlobalPalette = false;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
sections[i].writePacket(newChunkDataBuf); MCSection mcSection = new MCSection(user.clientBlockList(), this.blockList, this.biomeList);
} mcSection.readPacket(chunkDataByteBuf);
chunkDataBytes = newChunkDataBuf.array(); PalettedContainer<Integer> container = mcSection.blockStateContainer();
remapBiomes(user, mcSection.biomeContainer());
// 开始修改 Palette<Integer> palette = container.data().palette();
event.setChanged(true); if (palette.canRemap()) {
buf.clear(); if (palette.remapAndCheck(s -> this.blockStateMapper[s])) {
buf.writeVarInt(event.packetID()); hasChangedAnyBlock = true;
buf.writeInt(chunkX); }
buf.writeInt(chunkZ); } else {
if (VersionHelper.isOrAbove1_21_5()) { hasGlobalPalette = true;
buf.writeVarInt(heightmapsCount); for (int j = 0; j < 4096; j++) {
for (Map.Entry<Integer, long[]> entry : heightmapsMap.entrySet()) { int state = container.get(j);
buf.writeVarInt(entry.getKey()); int newState = this.blockStateMapper[state];
buf.writeLongArray(entry.getValue()); if (newState != state) {
container.set(j, newState);
hasChangedAnyBlock = true;
}
}
} }
} else { sections[i] = mcSection;
buf.writeNbt(heightmaps, named); }
// 只有被修改了,才读后续内容,并改写
if (hasChangedAnyBlock || (this.needsDowngrade && hasGlobalPalette)) {
// 读取其他非必要信息
int blockEntitiesDataCount = buf.readVarInt();
List<BlockEntityData> blockEntitiesData = new ArrayList<>();
for (int i = 0; i < blockEntitiesDataCount; i++) {
byte packedXZ = buf.readByte();
short y = buf.readShort();
int type = buf.readVarInt();
Tag tag = buf.readNbt(named);
BlockEntityData blockEntityData = new BlockEntityData(packedXZ, y, type, tag);
blockEntitiesData.add(blockEntityData);
}
// 光照信息
BitSet skyYMask = buf.readBitSet();
BitSet blockYMask = buf.readBitSet();
BitSet emptySkyYMask = buf.readBitSet();
BitSet emptyBlockYMask = buf.readBitSet();
List<byte[]> skyUpdates = buf.readByteArrayList(2048);
List<byte[]> blockUpdates = buf.readByteArrayList(2048);
// 预分配容量
FriendlyByteBuf newChunkDataBuf = new FriendlyByteBuf(Unpooled.buffer(chunkDataBufferSize + 16));
for (int i = 0; i < count; i++) {
sections[i].writePacket(newChunkDataBuf);
}
chunkDataBytes = newChunkDataBuf.array();
// 开始修改
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeInt(chunkX);
buf.writeInt(chunkZ);
if (VersionHelper.isOrAbove1_21_5()) {
buf.writeVarInt(heightmapsCount);
for (Map.Entry<Integer, long[]> entry : heightmapsMap.entrySet()) {
buf.writeVarInt(entry.getKey());
buf.writeLongArray(entry.getValue());
}
} else {
buf.writeNbt(heightmaps, named);
}
buf.writeVarInt(chunkDataBytes.length);
buf.writeBytes(chunkDataBytes);
buf.writeVarInt(blockEntitiesDataCount);
for (BlockEntityData blockEntityData : blockEntitiesData) {
buf.writeByte(blockEntityData.packedXZ());
buf.writeShort(blockEntityData.y());
buf.writeVarInt(blockEntityData.type());
buf.writeNbt(blockEntityData.tag(), named);
}
buf.writeBitSet(skyYMask);
buf.writeBitSet(blockYMask);
buf.writeBitSet(emptySkyYMask);
buf.writeBitSet(emptyBlockYMask);
buf.writeByteArrayList(skyUpdates);
buf.writeByteArrayList(blockUpdates);
} else {
System.out.println("没变化啊");
} }
buf.writeVarInt(chunkDataBytes.length);
buf.writeBytes(chunkDataBytes);
buf.writeVarInt(blockEntitiesDataCount);
for (BlockEntityData blockEntityData : blockEntitiesData) {
buf.writeByte(blockEntityData.packedXZ());
buf.writeShort(blockEntityData.y());
buf.writeVarInt(blockEntityData.type());
buf.writeNbt(blockEntityData.tag(), named);
}
buf.writeBitSet(skyYMask);
buf.writeBitSet(blockYMask);
buf.writeBitSet(emptySkyYMask);
buf.writeBitSet(emptyBlockYMask);
buf.writeByteArrayList(skyUpdates);
buf.writeByteArrayList(blockUpdates);
ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
// 记录加载的区块 // 记录加载的区块
player.addTrackedChunk(chunkPos.longKey, new ChunkStatus()); player.addTrackedChunk(chunkPos.longKey, new ChunkStatus());
// 生成方块实体
CEWorld ceWorld = BukkitWorldManager.instance().getWorld(player.world().uuid()); CEWorld ceWorld = BukkitWorldManager.instance().getWorld(player.world().uuid());
CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(chunkPos.longKey); CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(chunkPos.longKey);
if (ceChunk != null) { if (ceChunk != null) {

View File

@@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.registry.WritableRegistry;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceKey; import net.momirealms.craftengine.core.util.ResourceKey;
public class BlockEntityTypes { public abstract class BlockEntityTypes {
public static <T extends BlockEntity> BlockEntityType<T> register(Key id, BlockEntity.Factory<T> factory) { public static <T extends BlockEntity> BlockEntityType<T> register(Key id, BlockEntity.Factory<T> factory) {
BlockEntityType<T> type = new BlockEntityType<>(id, factory); BlockEntityType<T> type = new BlockEntityType<>(id, factory);

View File

@@ -10,7 +10,7 @@ import net.momirealms.craftengine.core.util.ResourceKey;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
public class BlockEntityElementConfigs { public abstract class BlockEntityElementConfigs {
public static final Key ITEM_DISPLAY = Key.of("craftengine:item_display"); public static final Key ITEM_DISPLAY = Key.of("craftengine:item_display");
public static final Key TEXT_DISPLAY = Key.of("craftengine:text_display"); public static final Key TEXT_DISPLAY = Key.of("craftengine:text_display");

View File

@@ -35,15 +35,36 @@ public class Int2ObjectBiMap<K> implements IndexedIterable<K> {
public void remapValues(Function<K, K> function) { public void remapValues(Function<K, K> function) {
for (int i = 0; i < values.length; i++) { for (int i = 0; i < values.length; i++) {
if (values[i] == null) break; K prev = values[i];
values[i] = function.apply(values[i]); if (prev == null) break;
values[i] = function.apply(prev);
} }
for (int i = 0; i < idToValues.length; i++) { for (int i = 0; i < idToValues.length; i++) {
if (idToValues[i] == null) break; K prev = idToValues[i];
idToValues[i] = function.apply(idToValues[i]); if (prev == null) break;
idToValues[i] = function.apply(prev);
} }
} }
public boolean remapValuesAndCheck(Function<K, K> function) {
boolean changed = false;
for (int i = 0; i < values.length; i++) {
K prev = values[i];
if (prev == null) break;
K apply = function.apply(prev);
values[i] = apply;
if (apply != prev) {
changed = true;
}
}
for (int i = 0; i < idToValues.length; i++) {
K prev = idToValues[i];
if (prev == null) break;
idToValues[i] = function.apply(prev);
}
return changed;
}
public static <A> Int2ObjectBiMap<A> create(int expectedSize) { public static <A> Int2ObjectBiMap<A> create(int expectedSize) {
return new Int2ObjectBiMap<>((int) ((float) expectedSize / LOAD_FACTOR)); return new Int2ObjectBiMap<>((int) ((float) expectedSize / LOAD_FACTOR));
} }

View File

@@ -108,11 +108,27 @@ public class ArrayPalette<T> implements Palette<T> {
@Override @Override
public void remap(Function<T, T> function) { public void remap(Function<T, T> function) {
for (int i = 0; i < this.array.length; i++) { for (int i = 0; i < this.array.length; i++) {
if (this.array[i] == null) return; T prev = this.array[i];
this.array[i] = function.apply(this.array[i]); if (prev == null) return;
this.array[i] = function.apply(prev);
} }
} }
@Override
public boolean remapAndCheck(Function<T, T> function) {
boolean changed = false;
for (int i = 0; i < this.array.length; i++) {
T prev = this.array[i];
if (prev == null) return changed;
T newV = function.apply(prev);
this.array[i] = newV;
if (newV != prev) {
changed = true;
}
}
return changed;
}
@Override @Override
public boolean canRemap() { public boolean canRemap() {
return true; return true;

View File

@@ -106,6 +106,11 @@ public class BiMapPalette<T> implements Palette<T> {
this.map.remapValues(function); this.map.remapValues(function);
} }
@Override
public boolean remapAndCheck(Function<T, T> function) {
return this.map.remapValuesAndCheck(function);
}
@Override @Override
public boolean canRemap() { public boolean canRemap() {
return true; return true;

View File

@@ -63,6 +63,11 @@ public class IdListPalette<T> implements Palette<T> {
return false; return false;
} }
@Override
public boolean remapAndCheck(Function<T, T> function) {
return false;
}
@Override @Override
public void readPacket(FriendlyByteBuf buf) { public void readPacket(FriendlyByteBuf buf) {
} }

View File

@@ -25,6 +25,8 @@ public interface Palette<T> {
void remap(Function<T, T> function); void remap(Function<T, T> function);
boolean remapAndCheck(Function<T, T> function);
boolean canRemap(); boolean canRemap();
interface Factory { interface Factory {

View File

@@ -23,7 +23,6 @@ import java.util.function.Predicate;
import java.util.stream.LongStream; import java.util.stream.LongStream;
public class PalettedContainer<T> implements PaletteResizeListener<T>, ReadableContainer<T> { public class PalettedContainer<T> implements PaletteResizeListener<T>, ReadableContainer<T> {
public static boolean NEED_DOWNGRADE = true;
private static final BiConsumer<FriendlyByteBuf, long[]> RAW_DATA_WRITER = VersionHelper.isOrAbove1_21_5() ? private static final BiConsumer<FriendlyByteBuf, long[]> RAW_DATA_WRITER = VersionHelper.isOrAbove1_21_5() ?
(FriendlyByteBuf::writeFixedSizeLongArray) : (FriendlyByteBuf::writeLongArray); (FriendlyByteBuf::writeFixedSizeLongArray) : (FriendlyByteBuf::writeLongArray);
private static final BiConsumer<FriendlyByteBuf, long[]> RAW_DATA_READER = VersionHelper.isOrAbove1_21_5() ? private static final BiConsumer<FriendlyByteBuf, long[]> RAW_DATA_READER = VersionHelper.isOrAbove1_21_5() ?
@@ -75,10 +74,7 @@ public class PalettedContainer<T> implements PaletteResizeListener<T>, ReadableC
return false; return false;
} }
public PalettedContainer<T> downgradeTo(IndexedIterable<T> idList) { public PalettedContainer<T> getClientCompatiblePalettedContainer(IndexedIterable<T> idList) {
if (!NEED_DOWNGRADE) {
return this;
}
Palette<T> palette = this.data.palette; Palette<T> palette = this.data.palette;
if (!(palette instanceof IdListPalette<T> idListPalette)) { if (!(palette instanceof IdListPalette<T> idListPalette)) {
return this; return this;

View File

@@ -73,6 +73,13 @@ public class SingularPalette<T> implements Palette<T> {
this.entry = function.apply(this.entry); this.entry = function.apply(this.entry);
} }
@Override
public boolean remapAndCheck(Function<T, T> function) {
T previous = this.entry;
this.entry = function.apply(previous);
return previous == this.entry;
}
@Override @Override
public boolean canRemap() { public boolean canRemap() {
return true; return true;

View File

@@ -26,7 +26,7 @@ public class MCSection {
public void writePacket(FriendlyByteBuf buf) { public void writePacket(FriendlyByteBuf buf) {
buf.writeShort(this.nonEmptyBlockCount); buf.writeShort(this.nonEmptyBlockCount);
this.serverBlockStateContainer.downgradeTo(this.clientBlockStateList).writePacket(buf); this.serverBlockStateContainer.getClientCompatiblePalettedContainer(this.clientBlockStateList).writePacket(buf);
this.biomeContainer.writePacket(buf); this.biomeContainer.writePacket(buf);
} }