mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-19 15:09:15 +00:00
优化方块实体切换
This commit is contained in:
@@ -44,6 +44,11 @@ public class BetterModelBlockEntityElementConfig implements BlockEntityElementCo
|
||||
return new BetterModelBlockEntityElement(world, pos, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<BetterModelBlockEntityElement> elementClass() {
|
||||
return BetterModelBlockEntityElement.class;
|
||||
}
|
||||
|
||||
public static class Factory implements BlockEntityElementConfigFactory {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -44,6 +44,11 @@ public class ModelEngineBlockEntityElementConfig implements BlockEntityElementCo
|
||||
return new ModelEngineBlockEntityElement(world, pos, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ModelEngineBlockEntityElement> elementClass() {
|
||||
return ModelEngineBlockEntityElement.class;
|
||||
}
|
||||
|
||||
public static class Factory implements BlockEntityElementConfigFactory {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -13,13 +13,16 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ItemDisplayBlockEntityElement implements BlockEntityElement {
|
||||
private final ItemDisplayBlockEntityElementConfig config;
|
||||
private final Object cachedSpawnPacket;
|
||||
private final Object cachedDespawnPacket;
|
||||
private final int entityId;
|
||||
public final ItemDisplayBlockEntityElementConfig config;
|
||||
public final Object cachedSpawnPacket;
|
||||
public final Object cachedDespawnPacket;
|
||||
public final int entityId;
|
||||
|
||||
public ItemDisplayBlockEntityElement(ItemDisplayBlockEntityElementConfig config, BlockPos pos) {
|
||||
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
|
||||
this(config, pos, CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet());
|
||||
}
|
||||
|
||||
public ItemDisplayBlockEntityElement(ItemDisplayBlockEntityElementConfig config, BlockPos pos, int entityId) {
|
||||
Vector3f position = config.position();
|
||||
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityId, UUID.randomUUID(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z,
|
||||
@@ -39,4 +42,9 @@ public class ItemDisplayBlockEntityElement implements BlockEntityElement {
|
||||
public void show(Player player) {
|
||||
player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(Player player) {
|
||||
player.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player)), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,19 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo
|
||||
return new ItemDisplayBlockEntityElement(this, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDisplayBlockEntityElement create(World world, BlockPos pos, ItemDisplayBlockEntityElement previous) {
|
||||
if (previous.config.yRot != this.yRot || !previous.config.position.equals(this.position)) {
|
||||
return null;
|
||||
}
|
||||
return new ItemDisplayBlockEntityElement(this, pos, previous.entityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ItemDisplayBlockEntityElement> elementClass() {
|
||||
return ItemDisplayBlockEntityElement.class;
|
||||
}
|
||||
|
||||
public Item<?> item(Player player) {
|
||||
return this.item.apply(player);
|
||||
}
|
||||
|
||||
@@ -13,13 +13,16 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class TextDisplayBlockEntityElement implements BlockEntityElement {
|
||||
private final TextDisplayBlockEntityElementConfig config;
|
||||
private final Object cachedSpawnPacket;
|
||||
private final Object cachedDespawnPacket;
|
||||
private final int entityId;
|
||||
public final TextDisplayBlockEntityElementConfig config;
|
||||
public final Object cachedSpawnPacket;
|
||||
public final Object cachedDespawnPacket;
|
||||
public final int entityId;
|
||||
|
||||
public TextDisplayBlockEntityElement(TextDisplayBlockEntityElementConfig config, BlockPos pos) {
|
||||
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
|
||||
this(config, pos, CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet());
|
||||
}
|
||||
|
||||
public TextDisplayBlockEntityElement(TextDisplayBlockEntityElementConfig config, BlockPos pos, int entityId) {
|
||||
Vector3f position = config.position();
|
||||
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityId, UUID.randomUUID(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z,
|
||||
@@ -39,4 +42,13 @@ public class TextDisplayBlockEntityElement implements BlockEntityElement {
|
||||
public void show(Player player) {
|
||||
player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(Player player) {
|
||||
player.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player)), false);
|
||||
}
|
||||
|
||||
public int entityId() {
|
||||
return entityId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,19 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo
|
||||
return new TextDisplayBlockEntityElement(this, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextDisplayBlockEntityElement create(World world, BlockPos pos, TextDisplayBlockEntityElement previous) {
|
||||
if (previous.config.yRot != this.yRot || !previous.config.position.equals(this.position)) {
|
||||
return null;
|
||||
}
|
||||
return new TextDisplayBlockEntityElement(this, pos, previous.entityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<TextDisplayBlockEntityElement> elementClass() {
|
||||
return TextDisplayBlockEntityElement.class;
|
||||
}
|
||||
|
||||
public Component text(Player player) {
|
||||
return AdventureHelper.miniMessage().deserialize(this.text, PlayerOptionalContext.of(player).tagResolvers());
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import net.momirealms.craftengine.core.block.DelegatingBlockState;
|
||||
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.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.util.ReflectionUtils;
|
||||
@@ -226,7 +228,10 @@ public final class WorldStorageInjector {
|
||||
// 处理 自定义块到自定义块或原版块到自定义块
|
||||
CEChunk chunk = holder.ceChunk();
|
||||
chunk.setDirty(true);
|
||||
|
||||
ConstantBlockEntityRenderer previousRenderer = null;
|
||||
// 如果两个方块没有相同的主人 且 旧方块有方块实体
|
||||
|
||||
if (!previousImmutableBlockState.isEmpty()) {
|
||||
if (previousImmutableBlockState.owner() != newImmutableBlockState.owner() && previousImmutableBlockState.hasBlockEntity()) {
|
||||
BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z);
|
||||
@@ -242,9 +247,11 @@ 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.removeConstantBlockEntityRenderer(pos);
|
||||
// 如果新状态没有entity renderer,那么直接移除,否则暂存
|
||||
previousRenderer = chunk.removeConstantBlockEntityRenderer(pos, !newImmutableBlockState.hasConstantBlockEntityRenderer());
|
||||
}
|
||||
}
|
||||
|
||||
if (newImmutableBlockState.hasBlockEntity()) {
|
||||
BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z);
|
||||
BlockEntity blockEntity = chunk.getBlockEntity(pos, false);
|
||||
@@ -264,10 +271,13 @@ public final class WorldStorageInjector {
|
||||
chunk.createDynamicBlockEntityRenderer(blockEntity);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理新老entity renderer更替
|
||||
if (newImmutableBlockState.hasConstantBlockEntityRenderer()) {
|
||||
BlockPos pos = new BlockPos(chunk.chunkPos.x * 16 + x, section.sectionY * 16 + y, chunk.chunkPos.z * 16 + z);
|
||||
chunk.addConstantBlockEntityRenderer(pos, newImmutableBlockState);
|
||||
chunk.addConstantBlockEntityRenderer(pos, newImmutableBlockState, previousRenderer);
|
||||
}
|
||||
|
||||
// 如果新方块的光照属性和客户端认为的不同
|
||||
if (Config.enableLightSystem()) {
|
||||
if (previousImmutableBlockState.isEmpty()) {
|
||||
|
||||
@@ -4,6 +4,8 @@ import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityEl
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public class ConstantBlockEntityRenderer {
|
||||
private final BlockEntityElement[] elements;
|
||||
@@ -14,25 +16,37 @@ public class ConstantBlockEntityRenderer {
|
||||
|
||||
public void show(Player player) {
|
||||
for (BlockEntityElement element : this.elements) {
|
||||
element.show(player);
|
||||
if (element != null) {
|
||||
element.show(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void hide(Player player) {
|
||||
for (BlockEntityElement element : this.elements) {
|
||||
element.hide(player);
|
||||
if (element != null) {
|
||||
element.hide(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void deactivate() {
|
||||
for (BlockEntityElement element : this.elements) {
|
||||
element.deactivate();
|
||||
if (element != null) {
|
||||
element.deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
for (BlockEntityElement element : this.elements) {
|
||||
element.activate();
|
||||
if (element != null) {
|
||||
element.activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BlockEntityElement[] elements() {
|
||||
return this.elements;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ public interface BlockEntityElement {
|
||||
|
||||
void hide(Player player);
|
||||
|
||||
default void transform(Player player) {}
|
||||
|
||||
default void deactivate() {}
|
||||
|
||||
default void activate() {}
|
||||
|
||||
@@ -3,7 +3,16 @@ package net.momirealms.craftengine.core.block.entity.render.element;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public interface BlockEntityElementConfig<E extends BlockEntityElement> {
|
||||
|
||||
E create(World world, BlockPos pos);
|
||||
|
||||
default E create(World world, BlockPos pos, E previous) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<E> elementClass();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityEl
|
||||
import net.momirealms.craftengine.core.block.entity.tick.*;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.plugin.logger.Debugger;
|
||||
import net.momirealms.craftengine.core.util.BlockEntityTickersList;
|
||||
import net.momirealms.craftengine.core.world.*;
|
||||
import net.momirealms.craftengine.core.world.chunk.serialization.DefaultBlockEntityRendererSerializer;
|
||||
import net.momirealms.craftengine.core.world.chunk.serialization.DefaultBlockEntitySerializer;
|
||||
@@ -115,40 +116,131 @@ public class CEChunk {
|
||||
}
|
||||
}
|
||||
|
||||
public void addConstantBlockEntityRenderer(BlockPos pos) {
|
||||
this.addConstantBlockEntityRenderer(pos, this.getBlockState(pos));
|
||||
public ConstantBlockEntityRenderer addConstantBlockEntityRenderer(BlockPos pos) {
|
||||
return this.addConstantBlockEntityRenderer(pos, this.getBlockState(pos), null);
|
||||
}
|
||||
|
||||
public void addConstantBlockEntityRenderer(BlockPos pos, ImmutableBlockState state) {
|
||||
public ConstantBlockEntityRenderer addConstantBlockEntityRenderer(BlockPos pos, ImmutableBlockState state) {
|
||||
return this.addConstantBlockEntityRenderer(pos, state, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public ConstantBlockEntityRenderer addConstantBlockEntityRenderer(BlockPos pos, ImmutableBlockState state, @Nullable ConstantBlockEntityRenderer previous) {
|
||||
BlockEntityElementConfig<? extends BlockEntityElement>[] renderers = state.constantRenderers();
|
||||
if (renderers != null && renderers.length > 0) {
|
||||
BlockEntityElement[] elements = new BlockEntityElement[renderers.length];
|
||||
World wrappedWorld = this.world.world();
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
elements[i] = renderers[i].create(wrappedWorld, pos);
|
||||
}
|
||||
ConstantBlockEntityRenderer renderer = new ConstantBlockEntityRenderer(elements);
|
||||
for (Player player : getTrackedBy()) {
|
||||
renderer.show(player);
|
||||
World wrappedWorld = this.world.world();
|
||||
List<Player> trackedBy = getTrackedBy();
|
||||
boolean hasTrackedBy = trackedBy != null && !trackedBy.isEmpty();
|
||||
// 处理旧到新的转换
|
||||
if (previous != null) {
|
||||
// 由于entity-render的体量基本都很小,所以考虑一个特殊情况,即前后都是1个renderer,对此情况进行简化和优化
|
||||
BlockEntityElement[] previousElements = previous.elements().clone();
|
||||
if (previousElements.length == 1 && renderers.length == 1) {
|
||||
BlockEntityElement previousElement = previousElements[0];
|
||||
BlockEntityElementConfig<? extends BlockEntityElement> config = renderers[0];
|
||||
outer: {
|
||||
if (config.elementClass().isInstance(previousElement)) {
|
||||
BlockEntityElement element = ((BlockEntityElementConfig) config).create(wrappedWorld, pos, previousElement);
|
||||
if (element != null) {
|
||||
elements[0] = element;
|
||||
if (hasTrackedBy) {
|
||||
for (Player player : trackedBy) {
|
||||
element.transform(player);
|
||||
}
|
||||
}
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
BlockEntityElement element = config.create(wrappedWorld, pos);
|
||||
elements[0] = element;
|
||||
if (hasTrackedBy) {
|
||||
for (Player player : trackedBy) {
|
||||
previousElement.hide(player);
|
||||
element.show(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
outer: for (int i = 0; i < elements.length; i++) {
|
||||
BlockEntityElementConfig<? extends BlockEntityElement> config = renderers[i];
|
||||
{
|
||||
for (int j = 0; j < previousElements.length; j++) {
|
||||
BlockEntityElement previousElement = previousElements[j];
|
||||
if (previousElement != null && config.elementClass().isInstance(previousElement)) {
|
||||
BlockEntityElement newElement = ((BlockEntityElementConfig) config).create(wrappedWorld, pos, previousElement);
|
||||
if (newElement != null) {
|
||||
previousElements[i] = null;
|
||||
elements[i] = newElement;
|
||||
if (hasTrackedBy) {
|
||||
for (Player player : trackedBy) {
|
||||
newElement.transform(player);
|
||||
}
|
||||
}
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
BlockEntityElement newElement = config.create(wrappedWorld, pos);
|
||||
elements[i] = newElement;
|
||||
if (hasTrackedBy) {
|
||||
for (Player player : trackedBy) {
|
||||
newElement.show(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasTrackedBy) {
|
||||
for (int i = 0; i < previousElements.length; i++) {
|
||||
BlockEntityElement previousElement = previousElements[i];
|
||||
if (previousElement != null) {
|
||||
for (Player player : trackedBy) {
|
||||
previousElement.hide(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
elements[i] = renderers[i].create(wrappedWorld, pos);
|
||||
}
|
||||
if (hasTrackedBy) {
|
||||
for (Player player : trackedBy) {
|
||||
renderer.show(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
this.renderLock.writeLock().lock();
|
||||
this.constantBlockEntityRenderers.put(pos, renderer);
|
||||
return renderer;
|
||||
} finally {
|
||||
this.renderLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removeConstantBlockEntityRenderer(BlockPos pos) {
|
||||
@Nullable
|
||||
public ConstantBlockEntityRenderer removeConstantBlockEntityRenderer(BlockPos pos) {
|
||||
return this.removeConstantBlockEntityRenderer(pos, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ConstantBlockEntityRenderer removeConstantBlockEntityRenderer(BlockPos pos, boolean hide) {
|
||||
try {
|
||||
this.renderLock.writeLock().lock();
|
||||
ConstantBlockEntityRenderer removed = this.constantBlockEntityRenderers.remove(pos);
|
||||
if (removed != null) {
|
||||
for (Player player : getTrackedBy()) {
|
||||
removed.hide(player);
|
||||
if (hide) {
|
||||
for (Player player : getTrackedBy()) {
|
||||
removed.hide(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
} finally {
|
||||
this.renderLock.writeLock().unlock();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user