9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2026-01-04 15:41:38 +00:00

添加方块实体

This commit is contained in:
XiaoMoMi
2025-04-29 22:13:33 +08:00
parent 65c5cece93
commit 3a3083a12a
11 changed files with 84 additions and 20 deletions

View File

@@ -169,7 +169,6 @@ public class BukkitBlockManager extends AbstractBlockManager {
this.tempVanillaBlockStateModels.clear();
}
@Nullable
public Object getMinecraftBlockHolder(int stateId) {
return stateId2BlockHolder.get(stateId);

View File

@@ -388,7 +388,7 @@ public class BukkitInjector {
// }
// }
public static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEWorld ceWorld, CEChunk chunk, SectionPos pos) {
public synchronized static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEWorld ceWorld, CEChunk chunk, SectionPos pos) {
try {
Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection);
if (!clazz$InjectedPalettedContainer.isInstance(container)) {

View File

@@ -0,0 +1,17 @@
package net.momirealms.craftengine.core.block;
import net.momirealms.sparrow.nbt.CompoundTag;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Experimental
public class BlockEntityState {
private final CompoundTag nbt;
public BlockEntityState(CompoundTag nbt) {
this.nbt = nbt.deepClone();
}
public CompoundTag nbt() {
return nbt;
}
}

View File

@@ -5,7 +5,6 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce
import net.momirealms.craftengine.core.util.Key;
import java.util.Map;
import java.util.Objects;
public class BannerSpecialModel implements SpecialModel {
public static final Factory FACTORY = new Factory();

View File

@@ -4,10 +4,8 @@ import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import software.amazon.awssdk.services.s3.endpoints.internal.Value;
import java.util.Map;
import java.util.Objects;
public class ChestSpecialModel implements SpecialModel {
public static final Factory FACTORY = new Factory();

View File

@@ -8,7 +8,6 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
public class ShulkerBoxSpecialModel implements SpecialModel {
public static final Factory FACTORY = new Factory();

View File

@@ -5,7 +5,6 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce
import net.momirealms.craftengine.core.util.Key;
import java.util.Map;
import java.util.Objects;
public class SignSpecialModel implements SpecialModel {
public static final Factory FACTORY = new Factory();

View File

@@ -1,13 +1,14 @@
package net.momirealms.craftengine.core.world.chunk;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.momirealms.craftengine.core.block.BlockEntityState;
import net.momirealms.craftengine.core.block.EmptyBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.world.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class CEChunk {
private boolean loaded;
@@ -15,7 +16,7 @@ public class CEChunk {
private final ChunkPos chunkPos;
private final CESection[] sections;
private final WorldHeight worldHeightAccessor;
private final List<Vec3d> entities;
private final Map<Integer, BlockEntityState> blockEntities;
private boolean dirty;
public CEChunk(CEWorld world, ChunkPos chunkPos) {
@@ -23,14 +24,14 @@ public class CEChunk {
this.chunkPos = chunkPos;
this.worldHeightAccessor = world.worldHeight();
this.sections = new CESection[this.worldHeightAccessor.getSectionsCount()];
this.entities = new ArrayList<>();
this.blockEntities = new Int2ObjectOpenHashMap<>(16, 0.5f);
this.fillEmptySection();
}
public CEChunk(CEWorld world, ChunkPos chunkPos, CESection[] sections, List<Vec3d> entities) {
public CEChunk(CEWorld world, ChunkPos chunkPos, CESection[] sections, Map<Integer, BlockEntityState> blockEntities) {
this.world = world;
this.chunkPos = chunkPos;
this.entities = entities;
this.blockEntities = blockEntities;
this.worldHeightAccessor = world.worldHeight();
int sectionCount = this.worldHeightAccessor.getSectionsCount();
this.sections = new CESection[sectionCount];
@@ -45,6 +46,10 @@ public class CEChunk {
this.fillEmptySection();
}
public Map<Integer, BlockEntityState> blockEntities() {
return blockEntities;
}
public boolean dirty() {
return dirty;
}
@@ -54,7 +59,7 @@ public class CEChunk {
}
public boolean isEmpty() {
if (!this.entities.isEmpty()) return false;
if (!this.blockEntities.isEmpty()) return false;
for (CESection section : this.sections) {
if (section != null && !section.statesContainer().isEmpty()) {
return false;

View File

@@ -0,0 +1,48 @@
package net.momirealms.craftengine.core.world.chunk.serialization;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.momirealms.craftengine.core.block.BlockEntityState;
import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.ListTag;
import org.jetbrains.annotations.ApiStatus;
import java.util.Map;
public final class DefaultBlockEntitySerializer {
@ApiStatus.Experimental
public static ListTag serialize(Map<Integer, BlockEntityState> tiles) {
ListTag result = new ListTag();
Map<CompoundTag, int[]> nbtToPosMap = new Object2ObjectOpenHashMap<>(Math.max(tiles.size(), 10), 0.75f);
for (Map.Entry<Integer, BlockEntityState> entry : tiles.entrySet()) {
int pos = entry.getKey();
CompoundTag tag = entry.getValue().nbt();
int[] previous = nbtToPosMap.computeIfAbsent(tag, k -> new int[] {pos});
int[] newPoses = new int[previous.length + 1];
System.arraycopy(previous, 0, newPoses, 0, previous.length);
newPoses[previous.length] = pos;
nbtToPosMap.put(tag, newPoses);
}
for (Map.Entry<CompoundTag, int[]> entry : nbtToPosMap.entrySet()) {
CompoundTag blockEntityTag = new CompoundTag();
blockEntityTag.put("data", entry.getKey());
blockEntityTag.putIntArray("pos", entry.getValue());
result.add(blockEntityTag);
}
return result;
}
@ApiStatus.Experimental
public static Map<Integer, BlockEntityState> deserialize(ListTag tag) {
Map<Integer, BlockEntityState> result = new Object2ObjectOpenHashMap<>(Math.max(tag.size(), 16), 0.5f);
for (int i = 0; i < tag.size(); i++) {
CompoundTag blockEntityTag = tag.getCompound(i);
CompoundTag data = blockEntityTag.getCompound("data");
int[] pos = blockEntityTag.getIntArray("pos");
for (int j = 0; j < pos.length; j++) {
result.put(j, new BlockEntityState(data));
}
}
return result;
}
}

View File

@@ -9,9 +9,9 @@ import net.momirealms.sparrow.nbt.ListTag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Optional;
public class DefaultChunkSerializer {
public final class DefaultChunkSerializer {
@Nullable
public static CompoundTag serialize(@NotNull CEChunk chunk) {
@@ -28,7 +28,7 @@ public class DefaultChunkSerializer {
if (sections.isEmpty()) return null;
CompoundTag chunkNbt = new CompoundTag();
chunkNbt.put("sections", sections);
chunkNbt.put("entities", new ListTag());
chunkNbt.put("block_entities", DefaultBlockEntitySerializer.serialize(chunk.blockEntities()));
return chunkNbt;
}
@@ -46,7 +46,7 @@ public class DefaultChunkSerializer {
}
}
}
ListTag entities = chunkNbt.getList("entities");
return new CEChunk(world, pos, sectionArray, List.of());
ListTag blockEntities = Optional.ofNullable(chunkNbt.getList("block_entities")).orElse(new ListTag());
return new CEChunk(world, pos, sectionArray, DefaultBlockEntitySerializer.deserialize(blockEntities));
}
}

View File

@@ -24,7 +24,7 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.LongStream;
public class DefaultSectionSerializer {
public final class DefaultSectionSerializer {
@Nullable
public static CompoundTag serialize(@NotNull CESection section) {