mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-25 09:59:20 +00:00
方块实体2
This commit is contained in:
@@ -4,9 +4,11 @@ import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -31,6 +33,22 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public EntityBlockBehavior getEntityBehavior() {
|
||||
EntityBlockBehavior target = null;
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
if (behavior instanceof EntityBlockBehavior entityBehavior) {
|
||||
if (target == null) {
|
||||
target = entityBehavior;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Multiple entity block behaviors are not allowed");
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
|
||||
@@ -19,7 +19,6 @@ import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.BlockStateWrapper;
|
||||
import net.momirealms.craftengine.core.block.EmptyBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
@@ -36,6 +35,7 @@ import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Consumer;
|
||||
@@ -217,59 +217,84 @@ public final class WorldStorageInjector {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
private static void compareAndUpdateBlockState(int x, int y, int z, Object newState, Object previousState, InjectedHolder holder) {
|
||||
try {
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(newState);
|
||||
CESection section = holder.ceSection();
|
||||
// 如果是原版方块
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
// 那么应该清空自定义块
|
||||
ImmutableBlockState previous = section.setBlockState(x, y, z, EmptyBlock.STATE);
|
||||
// 处理 自定义块 -> 原版块
|
||||
if (!previous.isEmpty()) {
|
||||
CEChunk chunk = holder.ceChunk();
|
||||
chunk.setDirty(true);
|
||||
if (previous.hasBlockEntity()) {
|
||||
BlockPos pos = new BlockPos(
|
||||
chunk.chunkPos().x * 16 + x,
|
||||
section.sectionY() * 16 + y,
|
||||
chunk.chunkPos().z * 16 + z
|
||||
);
|
||||
BlockEntity blockEntity = chunk.getBlockEntity(pos);
|
||||
if (blockEntity != null) {
|
||||
blockEntity.preRemove();
|
||||
chunk.removeBlockEntity(pos);
|
||||
}
|
||||
}
|
||||
if (Config.enableLightSystem()) {
|
||||
// 自定义块到原版块,只需要判断旧块是否和客户端一直
|
||||
BlockStateWrapper wrapper = previous.vanillaBlockState();
|
||||
if (wrapper != null) {
|
||||
updateLight(holder, wrapper.literalObject(), previousState, x, y, z);
|
||||
}
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(newState);
|
||||
CESection section = holder.ceSection();
|
||||
// 如果是原版方块
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
// 那么应该清空自定义块
|
||||
ImmutableBlockState previous = section.setBlockState(x, y, z, EmptyBlock.STATE);
|
||||
// 处理 自定义块 -> 原版块
|
||||
if (!previous.isEmpty()) {
|
||||
CEChunk chunk = holder.ceChunk();
|
||||
chunk.setDirty(true);
|
||||
if (previous.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);
|
||||
if (blockEntity != null) {
|
||||
blockEntity.preRemove();
|
||||
chunk.removeBlockEntity(pos);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ImmutableBlockState immutableBlockState = optionalCustomState.get();
|
||||
ImmutableBlockState previousImmutableBlockState = section.setBlockState(x, y, z, immutableBlockState);
|
||||
if (previousImmutableBlockState == immutableBlockState) return;
|
||||
// 处理 自定义块到自定义块或原版块到自定义块
|
||||
holder.ceChunk().setDirty(true);
|
||||
// 不可能!绝对不可能!
|
||||
if (immutableBlockState.isEmpty()) return;
|
||||
// 如果新方块的光照属性和客户端认为的不同
|
||||
if (Config.enableLightSystem()) {
|
||||
if (previousImmutableBlockState.isEmpty()) {
|
||||
// 原版块到自定义块,只需要判断新块是否和客户端视觉一致
|
||||
updateLight(holder, immutableBlockState.vanillaBlockState().literalObject(), newState, x, y, z);
|
||||
} else {
|
||||
// 自定义块到自定义块
|
||||
updateLight$complex(holder, immutableBlockState.vanillaBlockState().literalObject(), newState, previousState, x, y, z);
|
||||
// 自定义块到原版块,只需要判断旧块是否和客户端一直
|
||||
BlockStateWrapper wrapper = previous.vanillaBlockState();
|
||||
if (wrapper != null) {
|
||||
updateLight(holder, wrapper.literalObject(), previousState, x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to intercept setBlockState", e);
|
||||
} else {
|
||||
ImmutableBlockState newImmutableBlockState = optionalCustomState.get();
|
||||
ImmutableBlockState previousImmutableBlockState = section.setBlockState(x, y, z, newImmutableBlockState);
|
||||
if (previousImmutableBlockState == newImmutableBlockState) return;
|
||||
// 处理 自定义块到自定义块或原版块到自定义块
|
||||
CEChunk chunk = holder.ceChunk();
|
||||
chunk.setDirty(true);
|
||||
// 如果两个方块没有相同的主人 且 旧方块有方块实体
|
||||
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);
|
||||
BlockEntity blockEntity = chunk.getBlockEntity(pos, false);
|
||||
if (blockEntity != null) {
|
||||
try {
|
||||
blockEntity.preRemove();
|
||||
} catch (Throwable t) {
|
||||
CraftEngine.instance().logger().warn("Error removing block entity " + blockEntity.getClass().getName(), t);
|
||||
}
|
||||
chunk.removeBlockEntity(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
if (blockEntity != null && !blockEntity.isValidBlockState(newImmutableBlockState)) {
|
||||
chunk.removeBlockEntity(pos);
|
||||
blockEntity = null;
|
||||
}
|
||||
if (blockEntity == null) {
|
||||
blockEntity = Objects.requireNonNull(newImmutableBlockState.behavior().getEntityBehavior()).createBlockEntity(pos, newImmutableBlockState);
|
||||
if (blockEntity != null) {
|
||||
chunk.addBlockEntity(blockEntity);
|
||||
}
|
||||
} else {
|
||||
blockEntity.setBlockState(newImmutableBlockState);
|
||||
// 方块类型未变,仅更新状态,选择性更新ticker
|
||||
chunk.replaceOrCreateTickingBlockEntity(blockEntity);
|
||||
}
|
||||
}
|
||||
// 如果新方块的光照属性和客户端认为的不同
|
||||
if (Config.enableLightSystem()) {
|
||||
if (previousImmutableBlockState.isEmpty()) {
|
||||
// 原版块到自定义块,只需要判断新块是否和客户端视觉一致
|
||||
updateLight(holder, newImmutableBlockState.vanillaBlockState().literalObject(), newState, x, y, z);
|
||||
} else {
|
||||
// 自定义块到自定义块
|
||||
updateLight$complex(holder, newImmutableBlockState.vanillaBlockState().literalObject(), newState, previousState, x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.momirealms.craftengine.bukkit.util;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import org.bukkit.World;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.block;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.parser.BlockNbtParser;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
@@ -80,12 +81,16 @@ public abstract class AbstractCustomBlock implements CustomBlock {
|
||||
state.setVanillaBlockState(BlockRegistryMirror.stateByRegistryId(vanillaStateRegistryId));
|
||||
state.setCustomBlockState(BlockRegistryMirror.stateByRegistryId(blockStateVariant.internalRegistryId()));
|
||||
}
|
||||
EntityBlockBehavior entityBlockBehavior = this.behavior.getEntityBehavior();
|
||||
// double check if there's any invalid state
|
||||
for (ImmutableBlockState state : this.variantProvider().states()) {
|
||||
state.setBehavior(this.behavior);
|
||||
if (state.settings() == null) {
|
||||
state.setSettings(settings);
|
||||
}
|
||||
if (entityBlockBehavior != null) {
|
||||
state.setBlockEntityType(entityBlockBehavior.blockEntityType());
|
||||
}
|
||||
}
|
||||
this.applyPlatformSettings();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.momirealms.craftengine.core.block;
|
||||
|
||||
import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
@@ -10,6 +11,7 @@ import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -24,6 +26,14 @@ public abstract class BlockBehavior {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public EntityBlockBehavior getEntityBehavior() {
|
||||
if (this instanceof EntityBlockBehavior behavior) {
|
||||
return behavior;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// BlockState state, Rotation rotation
|
||||
public Object rotate(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
return superMethod.call();
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package net.momirealms.craftengine.core.block;
|
||||
|
||||
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.tick.BlockEntityTicker;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
@@ -10,6 +12,7 @@ import net.momirealms.craftengine.core.loot.LootTable;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.registry.Holder;
|
||||
import net.momirealms.craftengine.core.world.CEWorld;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.NBT;
|
||||
@@ -147,4 +150,11 @@ public final class ImmutableBlockState extends BlockStateHolder {
|
||||
if (lootTable == null) return List.of();
|
||||
return lootTable.getRandomItems(builder.withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, this).build(), world, player);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> createBlockEntityTicker(CEWorld world, BlockEntityType<? extends BlockEntity> type) {
|
||||
EntityBlockBehavior blockBehavior = this.behavior.getEntityBehavior();
|
||||
if (blockBehavior == null) return null;
|
||||
return (BlockEntityTicker<T>) blockBehavior.createBlockEntityTicker(world, this, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package net.momirealms.craftengine.core.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntityType;
|
||||
import net.momirealms.craftengine.core.block.entity.tick.BlockEntityTicker;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.CEWorld;
|
||||
|
||||
public interface EntityBlockBehavior {
|
||||
|
||||
<T extends BlockEntity> BlockEntityType<T> blockEntityType();
|
||||
|
||||
BlockEntity createBlockEntity(BlockPos pos, ImmutableBlockState state);
|
||||
|
||||
default <T extends BlockEntity> BlockEntityTicker<T> createBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType<T> blockEntityType) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
|
||||
public abstract class BlockEntity {
|
||||
protected final BlockPos pos;
|
||||
protected final ImmutableBlockState blockState;
|
||||
protected ImmutableBlockState blockState;
|
||||
protected BlockEntityType<? extends BlockEntity> type;
|
||||
protected CEWorld world;
|
||||
protected boolean valid;
|
||||
@@ -22,11 +22,24 @@ public abstract class BlockEntity {
|
||||
|
||||
public final CompoundTag saveAsTag() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
this.saveId(tag);
|
||||
this.savePos(tag);
|
||||
this.saveCustomData(tag);
|
||||
return tag;
|
||||
}
|
||||
|
||||
private void saveId(CompoundTag tag) {
|
||||
tag.putString("id", this.type.id().asString());
|
||||
}
|
||||
|
||||
public void setBlockState(ImmutableBlockState blockState) {
|
||||
this.blockState = blockState;
|
||||
}
|
||||
|
||||
public ImmutableBlockState blockState() {
|
||||
return blockState;
|
||||
}
|
||||
|
||||
public CEWorld world() {
|
||||
return world;
|
||||
}
|
||||
@@ -52,7 +65,7 @@ public abstract class BlockEntity {
|
||||
protected void saveCustomData(CompoundTag tag) {
|
||||
}
|
||||
|
||||
protected void readCustomData(CompoundTag tag) {
|
||||
public void loadCustomData(CompoundTag tag) {
|
||||
}
|
||||
|
||||
public void preRemove() {
|
||||
@@ -84,7 +97,7 @@ public abstract class BlockEntity {
|
||||
}
|
||||
|
||||
public boolean isValidBlockState(ImmutableBlockState blockState) {
|
||||
return blockState.blockEntityType() == this.type;
|
||||
return this.type == blockState.blockEntityType();
|
||||
}
|
||||
|
||||
public interface Factory<T extends BlockEntity> {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package net.momirealms.craftengine.core.block.entity.tick;
|
||||
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
|
||||
public class DummyTickingBlockEntity implements TickingBlockEntity {
|
||||
public static final DummyTickingBlockEntity INSTANCE = new DummyTickingBlockEntity();
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos pos() {
|
||||
return BlockPos.ZERO;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public class ReplaceableTickingBlockEntity implements TickingBlockEntity {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget(TickingBlockEntity target) {
|
||||
public void setTicker(TickingBlockEntity target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.registry;
|
||||
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntityType;
|
||||
import net.momirealms.craftengine.core.block.properties.PropertyFactory;
|
||||
import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory;
|
||||
import net.momirealms.craftengine.core.item.ItemDataModifierFactory;
|
||||
@@ -85,6 +86,7 @@ public class BuiltInRegistries {
|
||||
public static final Registry<PostProcessor.Type<?>> RECIPE_POST_PROCESSOR_TYPE = createConstantBoundRegistry(Registries.RECIPE_POST_PROCESSOR_TYPE, 16);
|
||||
public static final Registry<ItemUpdaterType<?>> ITEM_UPDATER_TYPE = createConstantBoundRegistry(Registries.ITEM_UPDATER_TYPE, 16);
|
||||
public static final Registry<NetworkCodec<FriendlyByteBuf, ? extends ModPacket>> MOD_PACKET = createConstantBoundRegistry(Registries.MOD_PACKET, 16);
|
||||
public static final Registry<BlockEntityType<?>> BLOCK_ENTITY_TYPE = createConstantBoundRegistry(Registries.BLOCK_ENTITY_TYPE, 128);
|
||||
|
||||
private static <T> Registry<T> createConstantBoundRegistry(ResourceKey<? extends Registry<T>> key, int expectedSize) {
|
||||
return new ConstantBoundRegistry<>(key, expectedSize);
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.registry;
|
||||
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntityType;
|
||||
import net.momirealms.craftengine.core.block.properties.PropertyFactory;
|
||||
import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory;
|
||||
import net.momirealms.craftengine.core.item.ItemDataModifierFactory;
|
||||
@@ -87,4 +88,5 @@ public class Registries {
|
||||
public static final ResourceKey<Registry<PostProcessor.Type<?>>> RECIPE_POST_PROCESSOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_post_processor_type"));
|
||||
public static final ResourceKey<Registry<ItemUpdaterType<?>>> ITEM_UPDATER_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("item_updater_type"));
|
||||
public static final ResourceKey<Registry<NetworkCodec<FriendlyByteBuf, ? extends ModPacket>>> MOD_PACKET = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("mod_packet_type"));
|
||||
public static final ResourceKey<Registry<BlockEntityType<?>>> BLOCK_ENTITY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("block_entity_type"));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.MCUtils;
|
||||
|
||||
public class BlockPos extends Vec3i {
|
||||
public static final BlockPos ZERO = new BlockPos(0, 0, 0);
|
||||
|
||||
public BlockPos(int x, int y, int z) {
|
||||
super(x, y, z);
|
||||
|
||||
@@ -149,7 +149,7 @@ public abstract class CEWorld {
|
||||
if (chunk == null) {
|
||||
return null;
|
||||
}
|
||||
return chunk.getBlockEntity(blockPos);
|
||||
return chunk.getBlockEntity(blockPos, true);
|
||||
}
|
||||
|
||||
public WorldDataStorage worldDataStorage() {
|
||||
@@ -183,6 +183,14 @@ public abstract class CEWorld {
|
||||
|
||||
public abstract void updateLight();
|
||||
|
||||
public void addBlockEntityTicker(TickingBlockEntity ticker) {
|
||||
if (this.isTickingBlockEntities) {
|
||||
this.pendingTickingBlockEntities.add(ticker);
|
||||
} else {
|
||||
this.tickingBlockEntities.add(ticker);
|
||||
}
|
||||
}
|
||||
|
||||
protected void tickBlockEntities() {
|
||||
this.isTickingBlockEntities = true;
|
||||
if (!this.pendingTickingBlockEntities.isEmpty()) {
|
||||
@@ -191,7 +199,7 @@ public abstract class CEWorld {
|
||||
}
|
||||
ReferenceOpenHashSet<TickingBlockEntity> toRemove = new ReferenceOpenHashSet<>();
|
||||
for (TickingBlockEntity blockEntity : this.tickingBlockEntities) {
|
||||
if (!blockEntity.isValid()) {
|
||||
if (blockEntity.isValid()) {
|
||||
blockEntity.tick();
|
||||
} else {
|
||||
toRemove.add(blockEntity);
|
||||
|
||||
@@ -47,12 +47,12 @@ public class Vec3i implements Comparable<Vec3i> {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
return this == object || object instanceof Vec3i vec3i && this.x() == vec3i.x() && this.y() == vec3i.y() && this.z() == vec3i.z();
|
||||
return this == object || object instanceof Vec3i vec3i && this.x == vec3i.x && this.y == vec3i.y && this.z == vec3i.z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (this.y() + this.z() * 31) * 31 + this.x();
|
||||
return (this.y + this.z * 31) * 31 + this.x;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,7 @@ 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.tick.*;
|
||||
import net.momirealms.craftengine.core.plugin.logger.Debugger;
|
||||
import net.momirealms.craftengine.core.world.*;
|
||||
import net.momirealms.craftengine.core.world.chunk.serialization.DefaultBlockEntitySerializer;
|
||||
@@ -14,6 +15,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class CEChunk {
|
||||
public final CEWorld world;
|
||||
@@ -23,6 +26,7 @@ public class CEChunk {
|
||||
public final Map<BlockPos, BlockEntity> blockEntities;
|
||||
private volatile boolean dirty;
|
||||
private volatile boolean loaded;
|
||||
protected final Map<BlockPos, ReplaceableTickingBlockEntity> tickingBlockEntitiesByPos = new ConcurrentHashMap<>();
|
||||
|
||||
public CEChunk(CEWorld world, ChunkPos chunkPos) {
|
||||
this.world = world;
|
||||
@@ -57,6 +61,7 @@ public class CEChunk {
|
||||
|
||||
public void addBlockEntity(BlockEntity blockEntity) {
|
||||
this.setBlockEntity(blockEntity);
|
||||
this.replaceOrCreateTickingBlockEntity(blockEntity);
|
||||
}
|
||||
|
||||
public void removeBlockEntity(BlockPos blockPos) {
|
||||
@@ -66,6 +71,33 @@ public class CEChunk {
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends BlockEntity> void replaceOrCreateTickingBlockEntity(T blockEntity) {
|
||||
ImmutableBlockState blockState = blockEntity.blockState();
|
||||
BlockEntityTicker<T> ticker = blockState.createBlockEntityTicker(this.world, blockEntity.type());
|
||||
if (ticker != null) {
|
||||
this.tickingBlockEntitiesByPos.compute(blockEntity.pos(), ((pos, previousTicker) -> {
|
||||
TickingBlockEntity newTicker = new TickingBlockEntityImpl<>(this, blockEntity, ticker);
|
||||
if (previousTicker != null) {
|
||||
previousTicker.setTicker(newTicker);
|
||||
return previousTicker;
|
||||
} else {
|
||||
ReplaceableTickingBlockEntity replaceableTicker = new ReplaceableTickingBlockEntity(newTicker);
|
||||
this.world.addBlockEntityTicker(replaceableTicker);
|
||||
return replaceableTicker;
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
this.removeBlockEntityTicker(blockEntity.pos());
|
||||
}
|
||||
}
|
||||
|
||||
private void removeBlockEntityTicker(BlockPos pos) {
|
||||
ReplaceableTickingBlockEntity blockEntity = this.tickingBlockEntitiesByPos.remove(pos);
|
||||
if (blockEntity != null) {
|
||||
blockEntity.setTicker(DummyTickingBlockEntity.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBlockEntity(BlockEntity blockEntity) {
|
||||
BlockPos pos = blockEntity.pos();
|
||||
ImmutableBlockState blockState = this.getBlockState(pos);
|
||||
@@ -84,12 +116,14 @@ public class CEChunk {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BlockEntity getBlockEntity(BlockPos pos) {
|
||||
public BlockEntity getBlockEntity(BlockPos pos, boolean create) {
|
||||
BlockEntity blockEntity = this.blockEntities.get(pos);
|
||||
if (blockEntity == null) {
|
||||
blockEntity = createBlockEntity(pos);
|
||||
if (blockEntity != null) {
|
||||
this.addBlockEntity(blockEntity);
|
||||
if (create) {
|
||||
blockEntity = createBlockEntity(pos);
|
||||
if (blockEntity != null) {
|
||||
this.addBlockEntity(blockEntity);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!blockEntity.isValid()) {
|
||||
@@ -105,7 +139,7 @@ public class CEChunk {
|
||||
if (!blockState.hasBlockEntity()) {
|
||||
return null;
|
||||
}
|
||||
return blockState.blockEntityType().factory().create(pos, blockState);
|
||||
return Objects.requireNonNull(blockState.behavior().getEntityBehavior()).createBlockEntity(pos, blockState);
|
||||
}
|
||||
|
||||
public Map<BlockPos, BlockEntity> blockEntities() {
|
||||
|
||||
@@ -9,8 +9,8 @@ public class CESection {
|
||||
public static final int SECTION_HEIGHT = 16;
|
||||
public static final int SECTION_SIZE = SECTION_WIDTH * SECTION_WIDTH * SECTION_HEIGHT;
|
||||
|
||||
private final int sectionY;
|
||||
private final PalettedContainer<ImmutableBlockState> statesContainer;
|
||||
public final int sectionY;
|
||||
public final PalettedContainer<ImmutableBlockState> statesContainer;
|
||||
|
||||
public CESection(int sectionY, PalettedContainer<ImmutableBlockState> statesContainer) {
|
||||
this.sectionY = sectionY;
|
||||
|
||||
@@ -2,6 +2,10 @@ package net.momirealms.craftengine.core.world.chunk.serialization;
|
||||
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntityType;
|
||||
import net.momirealms.craftengine.core.plugin.logger.Debugger;
|
||||
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.chunk.CEChunk;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
@@ -28,8 +32,17 @@ public final class DefaultBlockEntitySerializer {
|
||||
List<BlockEntity> blockEntities = new ArrayList<>(tag.size());
|
||||
for (int i = 0; i < tag.size(); i++) {
|
||||
CompoundTag data = tag.getCompound(i);
|
||||
BlockPos pos = BlockEntity.readPosAndVerify(data, chunk.chunkPos());
|
||||
ImmutableBlockState blockState = chunk.getBlockState(pos);
|
||||
Key id = Key.of(data.getString("id"));
|
||||
BlockEntityType<?> type = BuiltInRegistries.BLOCK_ENTITY_TYPE.getValue(id);
|
||||
if (type == null) {
|
||||
Debugger.BLOCK_ENTITY.debug(() -> "Unknown block entity type: " + id);
|
||||
} else {
|
||||
BlockPos pos = BlockEntity.readPosAndVerify(data, chunk.chunkPos());
|
||||
ImmutableBlockState blockState = chunk.getBlockState(pos);
|
||||
BlockEntity blockEntity = type.factory().create(pos, blockState);
|
||||
blockEntity.loadCustomData(data);
|
||||
blockEntities.add(blockEntity);
|
||||
}
|
||||
}
|
||||
return blockEntities;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user