mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2026-01-06 15:52:03 +00:00
宝贝实体方块渲染雏形
This commit is contained in:
@@ -4,6 +4,7 @@ import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
|
||||
import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntityType;
|
||||
import net.momirealms.craftengine.core.block.entity.render.BlockEntityRendererConfig;
|
||||
import net.momirealms.craftengine.core.block.entity.tick.BlockEntityTicker;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
@@ -30,6 +31,8 @@ public final class ImmutableBlockState extends BlockStateHolder {
|
||||
private Integer hashCode;
|
||||
private BlockSettings settings;
|
||||
private BlockEntityType<? extends BlockEntity> blockEntityType;
|
||||
@Nullable
|
||||
private BlockEntityRendererConfig rendererConfig;
|
||||
|
||||
ImmutableBlockState(
|
||||
Holder<CustomBlock> owner,
|
||||
@@ -66,6 +69,11 @@ public final class ImmutableBlockState extends BlockStateHolder {
|
||||
return this == EmptyBlock.STATE;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BlockEntityRendererConfig entityRenderer() {
|
||||
return this.rendererConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -85,6 +93,10 @@ public final class ImmutableBlockState extends BlockStateHolder {
|
||||
return this.blockEntityType != null;
|
||||
}
|
||||
|
||||
public boolean hasBlockEntityRenderer() {
|
||||
return this.rendererConfig != null;
|
||||
}
|
||||
|
||||
public BlockStateWrapper customBlockState() {
|
||||
return this.customBlockState;
|
||||
}
|
||||
|
||||
@@ -5,5 +5,6 @@ import net.momirealms.craftengine.core.util.Key;
|
||||
public final class BlockEntityTypeKeys {
|
||||
private BlockEntityTypeKeys() {}
|
||||
|
||||
public static final Key UNSAFE_COMPOSITE = Key.of("craftengine:unsafe_composite");
|
||||
public static final Key SIMPLE_STORAGE = Key.of("craftengine:simple_storage");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package net.momirealms.craftengine.core.block.entity.render;
|
||||
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
|
||||
public abstract class BlockEntityRenderer {
|
||||
private final int entityId;
|
||||
|
||||
public BlockEntityRenderer(int entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public int entityId() {
|
||||
return this.entityId;
|
||||
}
|
||||
|
||||
public abstract void spawn();
|
||||
|
||||
public abstract void despawn();
|
||||
|
||||
public abstract void spawn(Player player);
|
||||
|
||||
public abstract void despawn(Player player);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package net.momirealms.craftengine.core.block.entity.render;
|
||||
|
||||
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
|
||||
public class BlockEntityRendererConfig {
|
||||
private final float yRot;
|
||||
private final float xRot;
|
||||
private final ItemDisplayContext displayContext;
|
||||
private final Item<?> item;
|
||||
private final float scale;
|
||||
|
||||
public BlockEntityRendererConfig(ItemDisplayContext displayContext,
|
||||
float yRot,
|
||||
float xRot,
|
||||
Item<?> item,
|
||||
float scale) {
|
||||
this.displayContext = displayContext;
|
||||
this.yRot = yRot;
|
||||
this.xRot = xRot;
|
||||
this.item = item;
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public ItemDisplayContext displayContext() {
|
||||
return displayContext;
|
||||
}
|
||||
|
||||
public Item<?> item() {
|
||||
return item;
|
||||
}
|
||||
|
||||
public float xRot() {
|
||||
return xRot;
|
||||
}
|
||||
|
||||
public float yRot() {
|
||||
return yRot;
|
||||
}
|
||||
|
||||
public float scale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private ItemDisplayContext displayContext = ItemDisplayContext.NONE;
|
||||
private Item<?> item;
|
||||
private float xRot;
|
||||
private float yRot;
|
||||
private float scale = 1f;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder displayContext(ItemDisplayContext displayContext) {
|
||||
this.displayContext = displayContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder item(Item<?> item) {
|
||||
this.item = item;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder xRot(float xRot) {
|
||||
this.xRot = xRot;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder yRot(float yRot) {
|
||||
this.yRot = yRot;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder scale(float scale) {
|
||||
this.scale = scale;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockEntityRendererConfig build() {
|
||||
return new BlockEntityRendererConfig(this.displayContext, this.yRot, this.xRot, this.item, this.scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.util.AdventureHelper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -4,6 +4,8 @@ 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.BlockEntityRenderer;
|
||||
import net.momirealms.craftengine.core.block.entity.render.BlockEntityRendererConfig;
|
||||
import net.momirealms.craftengine.core.block.entity.tick.TickingBlockEntity;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
@@ -110,6 +112,11 @@ public abstract class CEWorld {
|
||||
return getChunkAtIfLoaded(ChunkPos.asLong(x, z));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CEChunk getChunkAtIfLoaded(ChunkPos chunkPos) {
|
||||
return getChunkAtIfLoaded(chunkPos.longKey);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ImmutableBlockState getBlockStateAtIfLoaded(int x, int y, int z) {
|
||||
CEChunk chunk = getChunkAtIfLoaded(x >> 4, z >> 4);
|
||||
@@ -208,4 +215,6 @@ public abstract class CEWorld {
|
||||
this.tickingBlockEntities.removeAll(toRemove);
|
||||
this.isTickingBlockEntities = false;
|
||||
}
|
||||
|
||||
public abstract BlockEntityRenderer createBlockEntityRenderer(BlockEntityRendererConfig config, BlockPos pos);
|
||||
}
|
||||
|
||||
@@ -4,15 +4,20 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
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.BlockEntityRenderer;
|
||||
import net.momirealms.craftengine.core.block.entity.render.BlockEntityRendererConfig;
|
||||
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.world.*;
|
||||
import net.momirealms.craftengine.core.world.chunk.serialization.DefaultBlockEntityRendererSerializer;
|
||||
import net.momirealms.craftengine.core.world.chunk.serialization.DefaultBlockEntitySerializer;
|
||||
import net.momirealms.sparrow.nbt.ListTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public class CEChunk {
|
||||
public final CEWorld world;
|
||||
@@ -20,23 +25,25 @@ public class CEChunk {
|
||||
public final CESection[] sections;
|
||||
public final WorldHeight worldHeightAccessor;
|
||||
public final Map<BlockPos, BlockEntity> blockEntities;
|
||||
public final Map<BlockPos, BlockEntityRenderer> blockEntityRenderers;
|
||||
private final ReentrantReadWriteLock renderLock = new ReentrantReadWriteLock();
|
||||
private volatile boolean dirty;
|
||||
private volatile boolean loaded;
|
||||
protected final Map<BlockPos, ReplaceableTickingBlockEntity> tickingBlockEntitiesByPos = new HashMap<>();
|
||||
protected final Map<BlockPos, ReplaceableTickingBlockEntity> tickingBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
|
||||
public CEChunk(CEWorld world, ChunkPos chunkPos) {
|
||||
this.world = world;
|
||||
this.chunkPos = chunkPos;
|
||||
this.worldHeightAccessor = world.worldHeight();
|
||||
this.sections = new CESection[this.worldHeightAccessor.getSectionsCount()];
|
||||
this.blockEntities = new Object2ObjectOpenHashMap<>(16, 0.5f);
|
||||
this.blockEntities = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
this.blockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
this.fillEmptySection();
|
||||
}
|
||||
|
||||
public CEChunk(CEWorld world, ChunkPos chunkPos, CESection[] sections, ListTag blockEntitiesTag) {
|
||||
public CEChunk(CEWorld world, ChunkPos chunkPos, CESection[] sections, @Nullable ListTag blockEntitiesTag, @Nullable ListTag itemDisplayBlockRenders) {
|
||||
this.world = world;
|
||||
this.chunkPos = chunkPos;
|
||||
this.blockEntities = new Object2ObjectOpenHashMap<>(Math.max(blockEntitiesTag.size(), 16), 0.5f);
|
||||
this.worldHeightAccessor = world.worldHeight();
|
||||
int sectionCount = this.worldHeightAccessor.getSectionsCount();
|
||||
this.sections = new CESection[sectionCount];
|
||||
@@ -49,9 +56,75 @@ public class CEChunk {
|
||||
}
|
||||
}
|
||||
this.fillEmptySection();
|
||||
List<BlockEntity> blockEntities = DefaultBlockEntitySerializer.deserialize(this, blockEntitiesTag);
|
||||
for (BlockEntity blockEntity : blockEntities) {
|
||||
this.setBlockEntity(blockEntity);
|
||||
if (blockEntitiesTag != null) {
|
||||
this.blockEntities = new Object2ObjectOpenHashMap<>(Math.max(blockEntitiesTag.size(), 10), 0.5f);
|
||||
List<BlockEntity> blockEntities = DefaultBlockEntitySerializer.deserialize(this, blockEntitiesTag);
|
||||
for (BlockEntity blockEntity : blockEntities) {
|
||||
this.setBlockEntity(blockEntity);
|
||||
}
|
||||
} else {
|
||||
this.blockEntities = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
}
|
||||
if (itemDisplayBlockRenders != null) {
|
||||
this.blockEntityRenderers = new Object2ObjectOpenHashMap<>(Math.max(itemDisplayBlockRenders.size(), 10), 0.5f);
|
||||
List<BlockPos> blockEntityRendererPoses = DefaultBlockEntityRendererSerializer.deserialize(this.chunkPos, itemDisplayBlockRenders);
|
||||
for (BlockPos pos : blockEntityRendererPoses) {
|
||||
this.addBlockEntityRenderer(pos);
|
||||
}
|
||||
} else {
|
||||
this.blockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
public void spawnBlockEntities(Player player) {
|
||||
try {
|
||||
this.renderLock.readLock().lock();
|
||||
for (BlockEntityRenderer renderer : this.blockEntityRenderers.values()) {
|
||||
renderer.spawn(player);
|
||||
}
|
||||
} finally {
|
||||
this.renderLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void despawnBlockEntities(Player player) {
|
||||
try {
|
||||
this.renderLock.readLock().lock();
|
||||
for (BlockEntityRenderer renderer : this.blockEntityRenderers.values()) {
|
||||
renderer.despawn(player);
|
||||
}
|
||||
} finally {
|
||||
this.renderLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void addBlockEntityRenderer(BlockPos pos) {
|
||||
this.addBlockEntityRenderer(pos, this.getBlockState(pos));
|
||||
}
|
||||
|
||||
public void addBlockEntityRenderer(BlockPos pos, ImmutableBlockState state) {
|
||||
BlockEntityRendererConfig config = state.entityRenderer();
|
||||
if (config != null) {
|
||||
BlockEntityRenderer renderer = this.world.createBlockEntityRenderer(config, pos);
|
||||
renderer.spawn();
|
||||
try {
|
||||
this.renderLock.writeLock().lock();
|
||||
this.blockEntityRenderers.put(pos, renderer);
|
||||
} finally {
|
||||
this.renderLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeBlockEntityRenderer(BlockPos pos) {
|
||||
try {
|
||||
this.renderLock.writeLock().lock();
|
||||
BlockEntityRenderer removed = this.blockEntityRenderers.remove(pos);
|
||||
if (removed != null) {
|
||||
removed.despawn();
|
||||
}
|
||||
} finally {
|
||||
this.renderLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,8 +225,17 @@ public class CEChunk {
|
||||
return Objects.requireNonNull(blockState.behavior().getEntityBehavior()).createBlockEntity(pos, blockState);
|
||||
}
|
||||
|
||||
public Map<BlockPos, BlockEntity> blockEntities() {
|
||||
return Collections.unmodifiableMap(this.blockEntities);
|
||||
public Collection<BlockEntity> blockEntities() {
|
||||
return Collections.unmodifiableCollection(this.blockEntities.values());
|
||||
}
|
||||
|
||||
public List<BlockPos> blockEntityRenderers() {
|
||||
try {
|
||||
this.renderLock.readLock().lock();
|
||||
return new ArrayList<>(this.blockEntityRenderers.keySet());
|
||||
} finally {
|
||||
this.renderLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean dirty() {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package net.momirealms.craftengine.core.world.chunk.serialization;
|
||||
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.ChunkPos;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.ListTag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class DefaultBlockEntityRendererSerializer {
|
||||
|
||||
public static List<BlockPos> deserialize(ChunkPos chunkPos, ListTag blockEntitiesTag) {
|
||||
List<BlockPos> blockEntities = new ArrayList<>(blockEntitiesTag.size());
|
||||
for (int i = 0; i < blockEntitiesTag.size(); i++) {
|
||||
CompoundTag tag = blockEntitiesTag.getCompound(i);
|
||||
BlockPos blockPos = BlockEntity.readPosAndVerify(tag, chunkPos);
|
||||
blockEntities.add(blockPos);
|
||||
}
|
||||
return blockEntities;
|
||||
}
|
||||
|
||||
public static ListTag serialize(List<BlockPos> poses) {
|
||||
ListTag listTag = new ListTag();
|
||||
for (BlockPos pos : poses) {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putInt("x", pos.x());
|
||||
tag.putInt("y", pos.y());
|
||||
tag.putInt("z", pos.z());
|
||||
listTag.add(tag);
|
||||
}
|
||||
return listTag;
|
||||
}
|
||||
}
|
||||
@@ -12,15 +12,14 @@ import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.ListTag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class DefaultBlockEntitySerializer {
|
||||
|
||||
public static ListTag serialize(Map<BlockPos, BlockEntity> tiles) {
|
||||
public static ListTag serialize(Collection<BlockEntity> entities) {
|
||||
ListTag result = new ListTag();
|
||||
for (Map.Entry<BlockPos, BlockEntity> entry : tiles.entrySet()) {
|
||||
BlockEntity entity = entry.getValue();
|
||||
for (BlockEntity entity : entities) {
|
||||
if (entity.isValid()) {
|
||||
result.add(entity.saveAsTag());
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ import net.momirealms.sparrow.nbt.ListTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public final class DefaultChunkSerializer {
|
||||
|
||||
@Nullable
|
||||
@@ -28,7 +26,14 @@ public final class DefaultChunkSerializer {
|
||||
if (sections.isEmpty()) return null;
|
||||
CompoundTag chunkNbt = new CompoundTag();
|
||||
chunkNbt.put("sections", sections);
|
||||
chunkNbt.put("block_entities", DefaultBlockEntitySerializer.serialize(chunk.blockEntities()));
|
||||
ListTag blockEntities = DefaultBlockEntitySerializer.serialize(chunk.blockEntities());
|
||||
if (!blockEntities.isEmpty()) {
|
||||
chunkNbt.put("block_entities", blockEntities);
|
||||
}
|
||||
ListTag blockEntityRenders = DefaultBlockEntityRendererSerializer.serialize(chunk.blockEntityRenderers());
|
||||
if (!blockEntityRenders.isEmpty()) {
|
||||
chunkNbt.put("block_entity_renders", blockEntityRenders);
|
||||
}
|
||||
return chunkNbt;
|
||||
}
|
||||
|
||||
@@ -46,7 +51,8 @@ public final class DefaultChunkSerializer {
|
||||
}
|
||||
}
|
||||
}
|
||||
ListTag blockEntities = Optional.ofNullable(chunkNbt.getList("block_entities")).orElse(new ListTag());
|
||||
return new CEChunk(world, pos, sectionArray, blockEntities);
|
||||
ListTag blockEntities = chunkNbt.getList("block_entities");
|
||||
ListTag itemDisplayBlockRenders = chunkNbt.getList("block_entity_renderers");
|
||||
return new CEChunk(world, pos, sectionArray, blockEntities, itemDisplayBlockRenders);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.momirealms.craftengine.core.world.collision;
|
||||
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.MCUtils;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.EntityHitResult;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
|
||||
Reference in New Issue
Block a user