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

动态渲染器

This commit is contained in:
XiaoMoMi
2025-09-14 00:38:31 +08:00
parent 7d567dca54
commit 1ca16091bb
17 changed files with 183 additions and 156 deletions

View File

@@ -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());
}

View File

@@ -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);
}

View File

@@ -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<Object> 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<Object> 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();
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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()) {
// 自定义块到原版块,只需要判断旧块是否和客户端一直

View File

@@ -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);
}
}

View File

@@ -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<Player> 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<Object> players = FastNMS.INSTANCE.method$ChunkHolder$getPlayers(chunkHolder);
if (players.isEmpty()) return Collections.emptyList();
List<Player> tracked = new ArrayList<>(players.size());
for (Object player : players) {
tracked.add(BukkitAdaptors.adapt(FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(player)));
}
return tracked;
}
}

View File

@@ -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<? extends BlockEntity> type;
protected CEWorld world;
protected boolean valid;
@Nullable
protected DynamicBlockEntityRenderer blockEntityRenderer;
protected BlockEntity(BlockEntityType<? extends BlockEntity> type, BlockPos pos, ImmutableBlockState blockState) {
this.pos = pos;
@@ -78,7 +80,11 @@ public abstract class BlockEntity {
}
public BlockEntityType<? extends BlockEntity> 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) {

View File

@@ -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();
}
}
}

View File

@@ -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);
}

View File

@@ -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() {}

View File

@@ -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<CEChunk> 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);
}

View File

@@ -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<Player> getTrackedBy(ChunkPos pos);
}

View File

@@ -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<BlockPos, BlockEntity> blockEntities;
public final Map<BlockPos, ConstantBlockEntityRenderer> blockEntityRenderers;
public final Map<BlockPos, BlockEntity> blockEntities; // 从区域线程上访问,安全
public final Map<BlockPos, ReplaceableTickingBlockEntity> tickingBlockEntitiesByPos; // 从区域线程上访问,安全
public final Map<BlockPos, ConstantBlockEntityRenderer> constantBlockEntityRenderers; // 会从区域线程上读写netty线程上读取
public final Map<BlockPos, DynamicBlockEntityRenderer> dynamicBlockEntityRenderers; // 会从区域线程上读写netty线程上读取
private final ReentrantReadWriteLock renderLock = new ReentrantReadWriteLock();
private volatile boolean dirty;
private volatile boolean loaded;
protected final Map<BlockPos, ReplaceableTickingBlockEntity> 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<BlockPos> 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<? extends BlockEntityElement>[] 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<Player> 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 <T extends BlockEntity> 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<BlockPos> blockEntityRenderers() {
public List<BlockPos> constantBlockEntityRenderers() {
try {
this.renderLock.readLock().lock();
return new ArrayList<>(this.blockEntityRenderers.keySet());
return new ArrayList<>(this.constantBlockEntityRenderers.keySet());
} finally {
this.renderLock.readLock().unlock();
}

View File

@@ -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);
}