mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-28 03:19:14 +00:00
动态渲染器
This commit is contained in:
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()) {
|
||||
// 自定义块到原版块,只需要判断旧块是否和客户端一直
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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() {}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user