From 1ca16091bb30b77c93aa6621235bf37313354bca Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 14 Sep 2025 00:38:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A8=E6=80=81=E6=B8=B2=E6=9F=93=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BetterModelBlockEntityElement.java | 4 +- .../ModelEngineBlockEntityElement.java | 4 +- .../BukkitConstantBlockEntityRenderer.java | 84 ------------- .../ItemDisplayBlockEntityElement.java | 4 +- .../TextDisplayBlockEntityElement.java | 4 +- .../bukkit/plugin/BukkitCraftEngine.java | 3 - .../plugin/injector/WorldStorageInjector.java | 7 +- .../bukkit/world/BukkitCEWorld.java | 12 +- .../craftengine/bukkit/world/BukkitWorld.java | 20 +++ .../core/block/entity/BlockEntity.java | 17 +-- .../render/ConstantBlockEntityRenderer.java | 34 +++-- .../render/DynamicBlockEntityRenderer.java | 14 +++ .../render/element/BlockEntityElement.java | 4 +- .../craftengine/core/world/CEWorld.java | 6 +- .../craftengine/core/world/World.java | 4 + .../craftengine/core/world/chunk/CEChunk.java | 116 ++++++++++++++---- .../serialization/DefaultChunkSerializer.java | 2 +- 17 files changed, 183 insertions(+), 156 deletions(-) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/BukkitConstantBlockEntityRenderer.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/entity/render/DynamicBlockEntityRenderer.java diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelBlockEntityElement.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelBlockEntityElement.java index bf8e180ba..1c9a0e5d3 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelBlockEntityElement.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelBlockEntityElement.java @@ -32,14 +32,14 @@ public class BetterModelBlockEntityElement implements BlockEntityElement { } @Override - public void despawn(Player player) { + public void hide(Player player) { if (this.dummyTracker != null) { this.dummyTracker.remove((org.bukkit.entity.Player) player.platformPlayer()); } } @Override - public void spawn(Player player) { + public void show(Player player) { if (this.dummyTracker != null) { this.dummyTracker.spawn((org.bukkit.entity.Player) player.platformPlayer()); } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineBlockEntityElement.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineBlockEntityElement.java index 5e3660563..0b49726b7 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineBlockEntityElement.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineBlockEntityElement.java @@ -39,14 +39,14 @@ public class ModelEngineBlockEntityElement implements BlockEntityElement { } @Override - public void despawn(Player player) { + public void hide(Player player) { if (this.dummy != null) { this.dummy.setForceViewing((org.bukkit.entity.Player) player.platformPlayer(), true); } } @Override - public void spawn(Player player) { + public void show(Player player) { if (this.dummy != null) { this.dummy.setForceHidden((org.bukkit.entity.Player) player.platformPlayer(), true); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/BukkitConstantBlockEntityRenderer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/BukkitConstantBlockEntityRenderer.java deleted file mode 100644 index 9ca1bc4f1..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/BukkitConstantBlockEntityRenderer.java +++ /dev/null @@ -1,84 +0,0 @@ -package net.momirealms.craftengine.bukkit.block.entity.renderer; - -import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; -import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; -import net.momirealms.craftengine.core.block.entity.render.ConstantBlockEntityRenderer; -import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; -import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.world.ChunkPos; -import net.momirealms.craftengine.core.world.World; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.Objects; - -public class BukkitConstantBlockEntityRenderer extends ConstantBlockEntityRenderer { - private final BlockEntityElement[] elements; - private final World world; - private final ChunkPos chunkPos; - - public BukkitConstantBlockEntityRenderer(World world, ChunkPos pos, BlockEntityElement[] elements) { - this.world = world; - this.chunkPos = pos; - this.elements = elements; - } - - private Object getChunkHolder() { - Object serverLevel = this.world.serverWorld(); - Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel); - return FastNMS.INSTANCE.method$ServerChunkCache$getVisibleChunkIfPresent(chunkSource, this.chunkPos.longKey); - } - - @Override - public void despawn() { - List players = FastNMS.INSTANCE.method$ChunkHolder$getPlayers(this.getChunkHolder()); - if (players.isEmpty()) return; - for (Object player : players) { - org.bukkit.entity.Player bkPlayer = FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(player); - BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(bkPlayer); - if (serverPlayer == null) continue; - despawn(serverPlayer); - } - } - - @Override - public void spawn() { - List players = FastNMS.INSTANCE.method$ChunkHolder$getPlayers(this.getChunkHolder()); - if (players.isEmpty()) return; - for (Object player : players) { - org.bukkit.entity.Player bkPlayer = FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(player); - BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(bkPlayer); - if (serverPlayer == null) continue; - spawn(serverPlayer); - } - } - - @Override - public void spawn(Player player) { - for (BlockEntityElement element : this.elements) { - element.spawn(player); - } - } - - @Override - public void despawn(Player player) { - for (BlockEntityElement element : this.elements) { - element.despawn(player); - } - } - - @Override - public void deactivate() { - for (BlockEntityElement element : this.elements) { - element.deactivate(); - } - } - - @Override - public void activate() { - for (BlockEntityElement element : this.elements) { - element.activate(); - } - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/ItemDisplayBlockEntityElement.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/ItemDisplayBlockEntityElement.java index ae5b42482..074bc87c5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/ItemDisplayBlockEntityElement.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/ItemDisplayBlockEntityElement.java @@ -31,12 +31,12 @@ public class ItemDisplayBlockEntityElement implements BlockEntityElement { } @Override - public void despawn(Player player) { + public void hide(Player player) { player.sendPacket(this.cachedDespawnPacket, false); } @Override - public void spawn(Player player) { + public void show(Player player) { player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), true); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/TextDisplayBlockEntityElement.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/TextDisplayBlockEntityElement.java index d3a8e8485..45a1c6c9d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/TextDisplayBlockEntityElement.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/TextDisplayBlockEntityElement.java @@ -31,12 +31,12 @@ public class TextDisplayBlockEntityElement implements BlockEntityElement { } @Override - public void despawn(Player player) { + public void hide(Player player) { player.sendPacket(this.cachedDespawnPacket, false); } @Override - public void spawn(Player player) { + public void show(Player player) { player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), true); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index 3f98c3a30..6633b1fa3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -40,14 +40,11 @@ import net.momirealms.craftengine.core.plugin.gui.category.ItemBrowserManagerImp import net.momirealms.craftengine.core.plugin.locale.TranslationManagerImpl; import net.momirealms.craftengine.core.plugin.logger.JavaPluginLogger; import net.momirealms.craftengine.core.plugin.logger.PluginLogger; -import net.momirealms.craftengine.core.plugin.logger.filter.DisconnectLogFilter; -import net.momirealms.craftengine.core.plugin.logger.filter.LogFilter; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerAdapter; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.CharacterUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; -import org.apache.logging.log4j.LogManager; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.World; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java index e4d1bb197..6a79e1032 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java @@ -243,7 +243,7 @@ public final class WorldStorageInjector { } if (previousImmutableBlockState.hasConstantBlockEntityRenderer()) { BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z); - chunk.removeBlockEntityRenderer(pos); + chunk.removeConstantBlockEntityRenderer(pos); } } if (newImmutableBlockState.hasBlockEntity()) { @@ -262,11 +262,12 @@ public final class WorldStorageInjector { blockEntity.setBlockState(newImmutableBlockState); // 方块类型未变,仅更新状态,选择性更新ticker chunk.replaceOrCreateTickingBlockEntity(blockEntity); + chunk.createDynamicBlockEntityRenderer(blockEntity); } } if (newImmutableBlockState.hasConstantBlockEntityRenderer()) { BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z); - chunk.addBlockEntityRenderer(pos, newImmutableBlockState); + chunk.addConstantBlockEntityRenderer(pos, newImmutableBlockState); } // 如果新方块的光照属性和客户端认为的不同 if (Config.enableLightSystem()) { @@ -296,7 +297,7 @@ public final class WorldStorageInjector { } if (previous.hasConstantBlockEntityRenderer()) { BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z); - chunk.removeBlockEntityRenderer(pos); + chunk.removeConstantBlockEntityRenderer(pos); } if (Config.enableLightSystem()) { // 自定义块到原版块,只需要判断旧块是否和客户端一直 diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java index 6e21a56f5..012529a87 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java @@ -1,18 +1,17 @@ package net.momirealms.craftengine.bukkit.world; -import net.momirealms.craftengine.bukkit.block.entity.renderer.BukkitConstantBlockEntityRenderer; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.LightUtils; -import net.momirealms.craftengine.core.block.entity.render.ConstantBlockEntityRenderer; -import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; +import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.SectionPosUtils; import net.momirealms.craftengine.core.world.*; import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; -import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class BukkitCEWorld extends CEWorld { @@ -43,9 +42,4 @@ public class BukkitCEWorld extends CEWorld { super.lightSections.addAll(pendingLightSections); } } - - @Override - public ConstantBlockEntityRenderer createBlockEntityRenderer(BlockEntityElement[] elements, World world, BlockPos pos) { - return new BukkitConstantBlockEntityRenderer(world, new ChunkPos(pos), elements); - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index fc162525c..2624bc78d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -1,8 +1,10 @@ package net.momirealms.craftengine.bukkit.world; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.sound.SoundSource; @@ -21,6 +23,9 @@ import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.UUID; public class BukkitWorld implements World { @@ -129,4 +134,19 @@ public class BukkitWorld implements World { public CEWorld storageWorld() { return BukkitWorldManager.instance().getWorld(uuid()); } + + @Override + public List getTrackedBy(ChunkPos pos) { + Object serverLevel = serverWorld(); + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel); + Object chunkHolder = FastNMS.INSTANCE.method$ServerChunkCache$getVisibleChunkIfPresent(chunkSource, pos.longKey); + if (chunkHolder == null) return Collections.emptyList(); + List players = FastNMS.INSTANCE.method$ChunkHolder$getPlayers(chunkHolder); + if (players.isEmpty()) return Collections.emptyList(); + List tracked = new ArrayList<>(players.size()); + for (Object player : players) { + tracked.add(BukkitAdaptors.adapt(FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(player))); + } + return tracked; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntity.java b/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntity.java index 73f715209..fd582ffe5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntity.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/entity/BlockEntity.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.block.entity; import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.block.entity.render.ConstantBlockEntityRenderer; +import net.momirealms.craftengine.core.block.entity.render.DynamicBlockEntityRenderer; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.ChunkPos; @@ -15,6 +15,8 @@ public abstract class BlockEntity { protected BlockEntityType type; protected CEWorld world; protected boolean valid; + @Nullable + protected DynamicBlockEntityRenderer blockEntityRenderer; protected BlockEntity(BlockEntityType type, BlockPos pos, ImmutableBlockState blockState) { this.pos = pos; @@ -78,7 +80,11 @@ public abstract class BlockEntity { } public BlockEntityType type() { - return type; + return this.type; + } + + public @Nullable DynamicBlockEntityRenderer blockEntityRenderer() { + return blockEntityRenderer; } public static BlockPos readPosAndVerify(CompoundTag tag, ChunkPos chunkPos) { @@ -95,12 +101,7 @@ public abstract class BlockEntity { } public BlockPos pos() { - return pos; - } - - @Nullable - public ConstantBlockEntityRenderer[] getBlockEntityRenderers() { - return null; + return this.pos; } public boolean isValidBlockState(ImmutableBlockState blockState) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/entity/render/ConstantBlockEntityRenderer.java b/core/src/main/java/net/momirealms/craftengine/core/block/entity/render/ConstantBlockEntityRenderer.java index b6e45acf8..f28ab579f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/entity/render/ConstantBlockEntityRenderer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/entity/render/ConstantBlockEntityRenderer.java @@ -1,20 +1,38 @@ package net.momirealms.craftengine.core.block.entity.render; +import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; import net.momirealms.craftengine.core.entity.player.Player; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Experimental -public abstract class ConstantBlockEntityRenderer { +public class ConstantBlockEntityRenderer { + private final BlockEntityElement[] elements; - public abstract void spawn(); + public ConstantBlockEntityRenderer(BlockEntityElement[] elements) { + this.elements = elements; + } - public abstract void despawn(); + public void show(Player player) { + for (BlockEntityElement element : this.elements) { + element.show(player); + } + } - public abstract void spawn(Player player); + public void hide(Player player) { + for (BlockEntityElement element : this.elements) { + element.hide(player); + } + } - public abstract void despawn(Player player); + public void deactivate() { + for (BlockEntityElement element : this.elements) { + element.deactivate(); + } + } - public abstract void deactivate(); - - public abstract void activate(); + public void activate() { + for (BlockEntityElement element : this.elements) { + element.activate(); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/entity/render/DynamicBlockEntityRenderer.java b/core/src/main/java/net/momirealms/craftengine/core/block/entity/render/DynamicBlockEntityRenderer.java new file mode 100644 index 000000000..bd7fa3c88 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/entity/render/DynamicBlockEntityRenderer.java @@ -0,0 +1,14 @@ +package net.momirealms.craftengine.core.block.entity.render; + +import net.momirealms.craftengine.core.entity.player.Player; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Experimental +public interface DynamicBlockEntityRenderer { + + void show(Player player); + + void hide(Player player); + + void update(Player player); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/entity/render/element/BlockEntityElement.java b/core/src/main/java/net/momirealms/craftengine/core/block/entity/render/element/BlockEntityElement.java index d098200bd..eaf5d605c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/entity/render/element/BlockEntityElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/entity/render/element/BlockEntityElement.java @@ -6,9 +6,9 @@ import org.jetbrains.annotations.ApiStatus; @ApiStatus.Experimental public interface BlockEntityElement { - void spawn(Player player); + void show(Player player); - void despawn(Player player); + void hide(Player player); default void deactivate() {} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java index 21ec02ff0..38b3985ec 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java @@ -4,8 +4,6 @@ import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTabl import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.entity.BlockEntity; -import net.momirealms.craftengine.core.block.entity.render.ConstantBlockEntityRenderer; -import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; import net.momirealms.craftengine.core.block.entity.tick.TickingBlockEntity; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; @@ -21,7 +19,7 @@ import java.util.concurrent.ConcurrentHashMap; public abstract class CEWorld { public static final String REGION_DIRECTORY = "craftengine"; - protected final World world; + public final World world; protected final ConcurrentLong2ReferenceChainedHashTable loadedChunkMap; protected final WorldDataStorage worldDataStorage; protected final WorldHeight worldHeightAccessor; @@ -219,6 +217,4 @@ public abstract class CEWorld { } this.isTickingBlockEntities = false; } - - public abstract ConstantBlockEntityRenderer createBlockEntityRenderer(BlockEntityElement[] elements, World world, BlockPos pos); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/World.java b/core/src/main/java/net/momirealms/craftengine/core/world/World.java index 287429f5a..bc6181c8b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/World.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/World.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.sound.SoundData; @@ -12,6 +13,7 @@ import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; import java.nio.file.Path; +import java.util.List; import java.util.UUID; public interface World { @@ -59,4 +61,6 @@ public interface World { void spawnParticle(Position location, Key particle, int count, double xOffset, double yOffset, double zOffset, double speed, @Nullable ParticleData extraData, @NotNull Context context); long time(); + + List getTrackedBy(ChunkPos pos); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java index 55706f1b4..442ac8999 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.core.block.EmptyBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.entity.BlockEntity; import net.momirealms.craftengine.core.block.entity.render.ConstantBlockEntityRenderer; +import net.momirealms.craftengine.core.block.entity.render.DynamicBlockEntityRenderer; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig; import net.momirealms.craftengine.core.block.entity.tick.*; @@ -25,12 +26,13 @@ public class CEChunk { public final ChunkPos chunkPos; public final CESection[] sections; public final WorldHeight worldHeightAccessor; - public final Map blockEntities; - public final Map blockEntityRenderers; + public final Map blockEntities; // 从区域线程上访问,安全 + public final Map tickingBlockEntitiesByPos; // 从区域线程上访问,安全 + public final Map constantBlockEntityRenderers; // 会从区域线程上读写,netty线程上读取 + public final Map dynamicBlockEntityRenderers; // 会从区域线程上读写,netty线程上读取 private final ReentrantReadWriteLock renderLock = new ReentrantReadWriteLock(); private volatile boolean dirty; private volatile boolean loaded; - protected final Map tickingBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f); public CEChunk(CEWorld world, ChunkPos chunkPos) { this.world = world; @@ -38,7 +40,9 @@ public class CEChunk { this.worldHeightAccessor = world.worldHeight(); this.sections = new CESection[this.worldHeightAccessor.getSectionsCount()]; this.blockEntities = new Object2ObjectOpenHashMap<>(10, 0.5f); - this.blockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f); + this.constantBlockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f); + this.dynamicBlockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f); + this.tickingBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f); this.fillEmptySection(); } @@ -46,6 +50,8 @@ public class CEChunk { this.world = world; this.chunkPos = chunkPos; this.worldHeightAccessor = world.worldHeight(); + this.dynamicBlockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f); + this.tickingBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f); int sectionCount = this.worldHeightAccessor.getSectionsCount(); this.sections = new CESection[sectionCount]; if (sections != null) { @@ -67,21 +73,24 @@ public class CEChunk { this.blockEntities = new Object2ObjectOpenHashMap<>(10, 0.5f); } if (itemDisplayBlockRenders != null) { - this.blockEntityRenderers = new Object2ObjectOpenHashMap<>(Math.max(itemDisplayBlockRenders.size(), 10), 0.5f); + this.constantBlockEntityRenderers = new Object2ObjectOpenHashMap<>(Math.max(itemDisplayBlockRenders.size(), 10), 0.5f); List blockEntityRendererPoses = DefaultBlockEntityRendererSerializer.deserialize(this.chunkPos, itemDisplayBlockRenders); for (BlockPos pos : blockEntityRendererPoses) { - this.addBlockEntityRenderer(pos); + this.addConstantBlockEntityRenderer(pos); } } else { - this.blockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f); + this.constantBlockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f); } } public void spawnBlockEntities(Player player) { try { this.renderLock.readLock().lock(); - for (ConstantBlockEntityRenderer renderer : this.blockEntityRenderers.values()) { - renderer.spawn(player); + for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) { + renderer.show(player); + } + for (DynamicBlockEntityRenderer renderer : this.dynamicBlockEntityRenderers.values()) { + renderer.show(player); } } finally { this.renderLock.readLock().unlock(); @@ -91,19 +100,22 @@ public class CEChunk { public void despawnBlockEntities(Player player) { try { this.renderLock.readLock().lock(); - for (ConstantBlockEntityRenderer renderer : this.blockEntityRenderers.values()) { - renderer.despawn(player); + for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) { + renderer.hide(player); + } + for (DynamicBlockEntityRenderer renderer : this.dynamicBlockEntityRenderers.values()) { + renderer.hide(player); } } finally { this.renderLock.readLock().unlock(); } } - public void addBlockEntityRenderer(BlockPos pos) { - this.addBlockEntityRenderer(pos, this.getBlockState(pos)); + public void addConstantBlockEntityRenderer(BlockPos pos) { + this.addConstantBlockEntityRenderer(pos, this.getBlockState(pos)); } - public void addBlockEntityRenderer(BlockPos pos, ImmutableBlockState state) { + public void addConstantBlockEntityRenderer(BlockPos pos, ImmutableBlockState state) { BlockEntityElementConfig[] renderers = state.constantRenderers(); if (renderers != null && renderers.length > 0) { BlockEntityElement[] elements = new BlockEntityElement[renderers.length]; @@ -111,23 +123,41 @@ public class CEChunk { for (int i = 0; i < elements.length; i++) { elements[i] = renderers[i].create(wrappedWorld, pos); } - ConstantBlockEntityRenderer renderer = this.world.createBlockEntityRenderer(elements, wrappedWorld, pos); - renderer.spawn(); + ConstantBlockEntityRenderer renderer = new ConstantBlockEntityRenderer(elements); + for (Player player : getTrackedBy()) { + renderer.show(player); + } try { this.renderLock.writeLock().lock(); - this.blockEntityRenderers.put(pos, renderer); + this.constantBlockEntityRenderers.put(pos, renderer); } finally { this.renderLock.writeLock().unlock(); } } } - public void removeBlockEntityRenderer(BlockPos pos) { + public void removeConstantBlockEntityRenderer(BlockPos pos) { try { this.renderLock.writeLock().lock(); - ConstantBlockEntityRenderer removed = this.blockEntityRenderers.remove(pos); + ConstantBlockEntityRenderer removed = this.constantBlockEntityRenderers.remove(pos); if (removed != null) { - removed.despawn(); + for (Player player : getTrackedBy()) { + removed.hide(player); + } + } + } finally { + this.renderLock.writeLock().unlock(); + } + } + + private void removeDynamicBlockEntityRenderer(BlockPos pos) { + try { + this.renderLock.writeLock().lock(); + DynamicBlockEntityRenderer renderer = this.dynamicBlockEntityRenderers.remove(pos); + if (renderer != null) { + for (Player player : getTrackedBy()) { + renderer.hide(player); + } } } finally { this.renderLock.writeLock().unlock(); @@ -137,6 +167,7 @@ public class CEChunk { public void addBlockEntity(BlockEntity blockEntity) { this.setBlockEntity(blockEntity); this.replaceOrCreateTickingBlockEntity(blockEntity); + this.createDynamicBlockEntityRenderer(blockEntity); } public void removeBlockEntity(BlockPos blockPos) { @@ -145,21 +176,28 @@ public class CEChunk { removedBlockEntity.setValid(false); } this.removeBlockEntityTicker(blockPos); + this.removeDynamicBlockEntityRenderer(blockPos); } public void activateAllBlockEntities() { for (BlockEntity blockEntity : this.blockEntities.values()) { blockEntity.setValid(true); - replaceOrCreateTickingBlockEntity(blockEntity); + this.replaceOrCreateTickingBlockEntity(blockEntity); + this.createDynamicBlockEntityRenderer(blockEntity); } - for (ConstantBlockEntityRenderer renderer : this.blockEntityRenderers.values()) { + for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) { renderer.activate(); } } + public List getTrackedBy() { + return this.world.world.getTrackedBy(this.chunkPos); + } + public void deactivateAllBlockEntities() { this.blockEntities.values().forEach(e -> e.setValid(false)); - this.blockEntityRenderers.values().forEach(ConstantBlockEntityRenderer::deactivate); + this.constantBlockEntityRenderers.values().forEach(ConstantBlockEntityRenderer::deactivate); + this.dynamicBlockEntityRenderers.clear(); this.tickingBlockEntitiesByPos.values().forEach((ticker) -> ticker.setTicker(DummyTickingBlockEntity.INSTANCE)); this.tickingBlockEntitiesByPos.clear(); } @@ -184,6 +222,34 @@ public class CEChunk { } } + public void createDynamicBlockEntityRenderer(T blockEntity) { + DynamicBlockEntityRenderer renderer = blockEntity.blockEntityRenderer(); + if (renderer != null) { + DynamicBlockEntityRenderer previous; + try { + this.renderLock.writeLock().lock(); + previous = this.dynamicBlockEntityRenderers.put(blockEntity.pos(), renderer); + } finally { + this.renderLock.writeLock().unlock(); + } + if (previous != null) { + if (previous == renderer) { + return; + } + for (Player player : getTrackedBy()) { + previous.hide(player); + renderer.show(player); + } + } else { + for (Player player : getTrackedBy()) { + renderer.show(player); + } + } + } else { + this.removeDynamicBlockEntityRenderer(blockEntity.pos()); + } + } + private void removeBlockEntityTicker(BlockPos pos) { ReplaceableTickingBlockEntity blockEntity = this.tickingBlockEntitiesByPos.remove(pos); if (blockEntity != null) { @@ -239,10 +305,10 @@ public class CEChunk { return Collections.unmodifiableCollection(this.blockEntities.values()); } - public List blockEntityRenderers() { + public List constantBlockEntityRenderers() { try { this.renderLock.readLock().lock(); - return new ArrayList<>(this.blockEntityRenderers.keySet()); + return new ArrayList<>(this.constantBlockEntityRenderers.keySet()); } finally { this.renderLock.readLock().unlock(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultChunkSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultChunkSerializer.java index ff195c4d3..5c4395082 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultChunkSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultChunkSerializer.java @@ -30,7 +30,7 @@ public final class DefaultChunkSerializer { if (!blockEntities.isEmpty()) { chunkNbt.put("block_entities", blockEntities); } - ListTag blockEntityRenders = DefaultBlockEntityRendererSerializer.serialize(chunk.blockEntityRenderers()); + ListTag blockEntityRenders = DefaultBlockEntityRendererSerializer.serialize(chunk.constantBlockEntityRenderers()); if (!blockEntityRenders.isEmpty()) { chunkNbt.put("block_entity_renderers", blockEntityRenders); }