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

优化方块实体切换

This commit is contained in:
XiaoMoMi
2025-11-04 22:13:43 +08:00
parent 7389318731
commit bb305343d3
11 changed files with 211 additions and 28 deletions

View File

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

View File

@@ -10,6 +10,8 @@ public interface BlockEntityElement {
void hide(Player player);
default void transform(Player player) {}
default void deactivate() {}
default void activate() {}

View File

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

View File

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