mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-15 23:25:32 +01:00
Implement a Registry for BlockEntities
This commit is contained in:
parent
02d9fc1405
commit
b1c75aa44a
@ -25,113 +25,58 @@
|
||||
package de.bluecolored.bluemap.core.world.block.entity;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import de.bluecolored.bluemap.core.util.Key;
|
||||
import de.bluecolored.bluenbt.BlueNBT;
|
||||
import de.bluecolored.bluenbt.NBTDeserializer;
|
||||
import de.bluecolored.bluenbt.NBTReader;
|
||||
import de.bluecolored.bluenbt.TypeDeserializer;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
@NBTDeserializer(BlockEntity.BlockEntityDeserializer.class)
|
||||
public class BlockEntity {
|
||||
private static final BlueNBT BLUENBT = new BlueNBT();
|
||||
|
||||
@FunctionalInterface
|
||||
private interface BlockEntityInitializer {
|
||||
BlockEntity create(Map<String, Object> data);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StaticInitializerReferencesSubClass")
|
||||
private static final Map<String, BlockEntityInitializer> ID_MAPPING = Map.of(
|
||||
"minecraft:sign", SignBlockEntity::new,
|
||||
"minecraft:skull", SkullBlockEntity::new,
|
||||
"minecraft:banner", BannerBlockEntity::new
|
||||
);
|
||||
public abstract class BlockEntity {
|
||||
|
||||
protected final String id;
|
||||
protected final int x, y, z;
|
||||
protected final boolean keepPacked;
|
||||
|
||||
protected BlockEntity(Map<String, Object> data) {
|
||||
this.id = (String) data.get("id");
|
||||
this.x = (int) data.get("x");
|
||||
this.y = (int) data.get("y");
|
||||
this.z = (int) data.get("z");
|
||||
this.keepPacked = (byte) data.getOrDefault("keepPacked", (byte) 0) == 1;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public int getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public boolean isKeepPacked() {
|
||||
return keepPacked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BlockEntity that = (BlockEntity) o;
|
||||
return x == that.x && y == that.y && z == that.z && keepPacked == that.keepPacked && Objects.equals(id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, x, y, z, keepPacked);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BlockEntity{" +
|
||||
"id='" + id + '\'' +
|
||||
", x=" + x +
|
||||
", y=" + y +
|
||||
", z=" + z +
|
||||
", keepPacked=" + keepPacked +
|
||||
'}';
|
||||
protected BlockEntity(Map<String, Object> raw) {
|
||||
this.id = (String) raw.get("id");
|
||||
this.x = (int) raw.getOrDefault("x", 0);
|
||||
this.y = (int) raw.getOrDefault("y", 0);
|
||||
this.z = (int) raw.getOrDefault("z", 0);
|
||||
this.keepPacked = (byte) raw.getOrDefault("keepPacked", (byte) 0) == 1;
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public static class BlockEntityDeserializer implements TypeDeserializer<BlockEntity> {
|
||||
|
||||
private final BlueNBT blueNBT;
|
||||
|
||||
@Override
|
||||
public BlockEntity read(NBTReader reader) throws IOException {
|
||||
@SuppressWarnings("unchecked") Map<String, Object> data =
|
||||
(Map<String, Object>) BLUENBT.read(reader, TypeToken.getParameterized(Map.class, String.class, Object.class));
|
||||
@SuppressWarnings("unchecked")
|
||||
public @Nullable BlockEntity read(NBTReader reader) throws IOException {
|
||||
Map<String, Object> raw = (Map<String, Object>) blueNBT.read(reader, TypeToken.getParameterized(Map.class, String.class, Object.class));
|
||||
|
||||
String id = (String) data.get("id");
|
||||
if (id == null || id.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
String id = (String) raw.get("id");
|
||||
if (id == null) return null;
|
||||
|
||||
BlockEntityInitializer instance = ID_MAPPING.getOrDefault(id, BlockEntity::new);
|
||||
Key typeKey = Key.parse(id, Key.MINECRAFT_NAMESPACE);
|
||||
BlockEntityType type = BlockEntityType.REGISTRY.get(typeKey);
|
||||
if (type == null) return null;
|
||||
|
||||
try {
|
||||
return instance.create(data);
|
||||
} catch (Exception e) {
|
||||
Logger.global.logError("Failed to instantiate BlockEntity instance!", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
return type.load(raw);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
package de.bluecolored.bluemap.core.world.block.entity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface BlockEntityLoader {
|
||||
|
||||
BlockEntity load(Map<String, Object> raw);
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package de.bluecolored.bluemap.core.world.block.entity;
|
||||
|
||||
import de.bluecolored.bluemap.core.util.Key;
|
||||
import de.bluecolored.bluemap.core.util.Keyed;
|
||||
import de.bluecolored.bluemap.core.util.Registry;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface BlockEntityType extends Keyed, BlockEntityLoader {
|
||||
|
||||
BlockEntityType SIGN = new Impl(Key.minecraft("sign"), SignBlockEntity::new);
|
||||
BlockEntityType SKULL = new Impl(Key.minecraft("skull"), SkullBlockEntity::new);
|
||||
BlockEntityType BANNER = new Impl(Key.minecraft("banner"), BannerBlockEntity::new);
|
||||
|
||||
Registry<BlockEntityType> REGISTRY = new Registry<>(
|
||||
SIGN,
|
||||
SKULL,
|
||||
BANNER
|
||||
);
|
||||
|
||||
@RequiredArgsConstructor
|
||||
class Impl implements BlockEntityType {
|
||||
|
||||
@Getter
|
||||
private final Key key;
|
||||
private final BlockEntityLoader loader;
|
||||
|
||||
@Override
|
||||
public BlockEntity load(Map<String, Object> raw) {
|
||||
return loader.load(raw);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -41,7 +41,7 @@ public class MCAUtil {
|
||||
public static BlueNBT addCommonNbtAdapters(BlueNBT nbt) {
|
||||
nbt.register(TypeToken.get(BlockState.class), new BlockStateDeserializer());
|
||||
nbt.register(TypeToken.get(Key.class), new KeyDeserializer());
|
||||
nbt.register(TypeToken.get(BlockEntity.class), new BlockEntity.BlockEntityDeserializer());
|
||||
nbt.register(TypeToken.get(BlockEntity.class), new BlockEntity.BlockEntityDeserializer(nbt));
|
||||
return nbt;
|
||||
}
|
||||
|
||||
|
@ -26,10 +26,10 @@
|
||||
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import de.bluecolored.bluemap.core.util.Key;
|
||||
import de.bluecolored.bluemap.core.world.biome.Biome;
|
||||
import de.bluecolored.bluemap.core.world.BlockState;
|
||||
import de.bluecolored.bluemap.core.world.DimensionType;
|
||||
import de.bluecolored.bluemap.core.world.LightData;
|
||||
import de.bluecolored.bluemap.core.world.biome.Biome;
|
||||
import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
|
||||
import de.bluecolored.bluemap.core.world.mca.MCAUtil;
|
||||
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
|
||||
@ -37,9 +37,8 @@
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Chunk_1_13 extends MCAChunk {
|
||||
|
||||
@ -120,9 +119,15 @@ public Chunk_1_13(MCAWorld world, Data data) {
|
||||
this.sectionMax = 0;
|
||||
}
|
||||
|
||||
this.blockEntities = level.blockEntities.stream().collect(Collectors.toMap(
|
||||
it -> (long) it.getY() << 8 | (it.getX() & 0xF) << 4 | it.getZ() & 0xF, it -> it
|
||||
));
|
||||
// load block-entities
|
||||
this.blockEntities = new HashMap<>();
|
||||
for (int i = 0; i < level.blockEntities.length; i++) {
|
||||
BlockEntity be = level.blockEntities[i];
|
||||
if (be == null) continue;
|
||||
|
||||
long hash = (long) be.getY() << 8 | (be.getX() & 0xF) << 4 | be.getZ() & 0xF;
|
||||
blockEntities.put(hash, be);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -290,7 +295,7 @@ public static class Level {
|
||||
private HeightmapsData heightmaps = new HeightmapsData();
|
||||
private SectionData @Nullable [] sections = null;
|
||||
private int[] biomes = EMPTY_INT_ARRAY;
|
||||
@NBTName("TileEntities") private List<BlockEntity> blockEntities = List.of();
|
||||
@NBTName("TileEntities") private @Nullable BlockEntity [] blockEntities = EMPTY_BLOCK_ENTITIES_ARRAY;
|
||||
}
|
||||
|
||||
@Getter
|
||||
|
@ -26,10 +26,10 @@
|
||||
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import de.bluecolored.bluemap.core.util.Key;
|
||||
import de.bluecolored.bluemap.core.world.biome.Biome;
|
||||
import de.bluecolored.bluemap.core.world.BlockState;
|
||||
import de.bluecolored.bluemap.core.world.DimensionType;
|
||||
import de.bluecolored.bluemap.core.world.LightData;
|
||||
import de.bluecolored.bluemap.core.world.biome.Biome;
|
||||
import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
|
||||
import de.bluecolored.bluemap.core.world.mca.MCAUtil;
|
||||
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
|
||||
@ -38,9 +38,8 @@
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Chunk_1_16 extends MCAChunk {
|
||||
|
||||
@ -119,9 +118,15 @@ public Chunk_1_16(MCAWorld world, Data data) {
|
||||
this.sectionMax = 0;
|
||||
}
|
||||
|
||||
this.blockEntities = level.blockEntities.stream().collect(Collectors.toMap(
|
||||
it -> (long) it.getY() << 8 | (it.getX() & 0xF) << 4 | it.getZ() & 0xF, it -> it
|
||||
));
|
||||
// load block-entities
|
||||
this.blockEntities = new HashMap<>();
|
||||
for (int i = 0; i < level.blockEntities.length; i++) {
|
||||
BlockEntity be = level.blockEntities[i];
|
||||
if (be == null) continue;
|
||||
|
||||
long hash = (long) be.getY() << 8 | (be.getX() & 0xF) << 4 | be.getZ() & 0xF;
|
||||
blockEntities.put(hash, be);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -277,7 +282,7 @@ public static class Level {
|
||||
private HeightmapsData heightmaps = new HeightmapsData();
|
||||
private SectionData @Nullable [] sections = null;
|
||||
private int[] biomes = EMPTY_INT_ARRAY;
|
||||
@NBTName("TileEntities") private List<BlockEntity> blockEntities = List.of();
|
||||
@NBTName("TileEntities") private @Nullable BlockEntity [] blockEntities = EMPTY_BLOCK_ENTITIES_ARRAY;
|
||||
}
|
||||
|
||||
@Getter
|
||||
|
@ -26,10 +26,10 @@
|
||||
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import de.bluecolored.bluemap.core.util.Key;
|
||||
import de.bluecolored.bluemap.core.world.biome.Biome;
|
||||
import de.bluecolored.bluemap.core.world.BlockState;
|
||||
import de.bluecolored.bluemap.core.world.DimensionType;
|
||||
import de.bluecolored.bluemap.core.world.LightData;
|
||||
import de.bluecolored.bluemap.core.world.biome.Biome;
|
||||
import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
|
||||
import de.bluecolored.bluemap.core.world.mca.MCAUtil;
|
||||
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
|
||||
@ -38,9 +38,8 @@
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Chunk_1_18 extends MCAChunk {
|
||||
|
||||
@ -116,9 +115,15 @@ public Chunk_1_18(MCAWorld world, Data data) {
|
||||
this.sectionMax = 0;
|
||||
}
|
||||
|
||||
this.blockEntities = data.blockEntities.stream().collect(Collectors.toMap(
|
||||
it -> (long) it.getY() << 8 | (it.getX() & 0xF) << 4 | it.getZ() & 0xF, it -> it
|
||||
));
|
||||
// load block-entities
|
||||
this.blockEntities = new HashMap<>();
|
||||
for (int i = 0; i < data.blockEntities.length; i++) {
|
||||
BlockEntity be = data.blockEntities[i];
|
||||
if (be == null) continue;
|
||||
|
||||
long hash = (long) be.getY() << 8 | (be.getX() & 0xF) << 4 | be.getZ() & 0xF;
|
||||
blockEntities.put(hash, be);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -285,7 +290,7 @@ public static class Data extends MCAChunk.Data {
|
||||
private long inhabitedTime = 0;
|
||||
private HeightmapsData heightmaps = new HeightmapsData();
|
||||
private SectionData @Nullable [] sections = null;
|
||||
@NBTName("block_entities") private List<BlockEntity> blockEntities = List.of();
|
||||
@NBTName("block_entities") private @Nullable BlockEntity [] blockEntities = EMPTY_BLOCK_ENTITIES_ARRAY;
|
||||
}
|
||||
|
||||
@Getter
|
||||
|
@ -27,6 +27,7 @@
|
||||
import de.bluecolored.bluemap.core.util.Key;
|
||||
import de.bluecolored.bluemap.core.world.BlockState;
|
||||
import de.bluecolored.bluemap.core.world.Chunk;
|
||||
import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
|
||||
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
@ -44,6 +45,7 @@ public abstract class MCAChunk implements Chunk {
|
||||
protected static final long[] EMPTY_LONG_ARRAY = new long[0];
|
||||
protected static final Key[] EMPTY_KEY_ARRAY = new Key[0];
|
||||
protected static final BlockState[] EMPTY_BLOCKSTATE_ARRAY = new BlockState[0];
|
||||
protected static final BlockEntity[] EMPTY_BLOCK_ENTITIES_ARRAY = new BlockEntity[0];
|
||||
|
||||
private final MCAWorld world;
|
||||
private final int dataVersion;
|
||||
|
Loading…
Reference in New Issue
Block a user