mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-09-27 06:42:42 +02:00
Add mechanism for retrieving BlockEntity data (#524)
* Add mechanism for retrieving BlockEntity data This commit adds a mechanism for retrieving block entity data. Block entity data is required to support for example text on signs, banner patterns, or mods such as Domum Ornamentum. * Fix the coordinate-packing for block entity-loading This commit fixes the incorrect shifting of bits when packing the chunk-local coordinates of a block entity into a 64-bit long for lookups. * Change mapping type of BlockEntity lookups This commit changes the type stored for BlockEntity mappings from a class of the type associated with the ID to a method reference to its constructor. * Tidy BlockEntity mappings This commit introduces a small functional interface to make the type less ungodly. Also silences the warning about referencing subclasses in the superclass, it is fine in this case, we're just storing a reference to the constructor. * Add missing license headers The license headers were missing. Oops.
This commit is contained in:
parent
2689cd10e0
commit
a847e247e5
@ -56,6 +56,7 @@
|
|||||||
import de.bluecolored.bluemap.core.world.Chunk;
|
import de.bluecolored.bluemap.core.world.Chunk;
|
||||||
import de.bluecolored.bluemap.core.world.World;
|
import de.bluecolored.bluemap.core.world.World;
|
||||||
import de.bluecolored.bluemap.core.world.block.Block;
|
import de.bluecolored.bluemap.core.world.block.Block;
|
||||||
|
import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@ -528,6 +529,11 @@ private Text formatBlock(Block<?> block) {
|
|||||||
lines.put("block-light", block.getBlockLightLevel());
|
lines.put("block-light", block.getBlockLightLevel());
|
||||||
lines.put("sun-light", block.getSunLightLevel());
|
lines.put("sun-light", block.getSunLightLevel());
|
||||||
|
|
||||||
|
BlockEntity blockEntity = block.getBlockEntity();
|
||||||
|
if (blockEntity != null) {
|
||||||
|
lines.put("block-entity", blockEntity);
|
||||||
|
}
|
||||||
|
|
||||||
Object[] textElements = lines.entrySet().stream()
|
Object[] textElements = lines.entrySet().stream()
|
||||||
.flatMap(e -> Stream.of(TextColor.GRAY, e.getKey(), ": ", TextColor.WHITE, e.getValue(), "\n"))
|
.flatMap(e -> Stream.of(TextColor.GRAY, e.getKey(), ": ", TextColor.WHITE, e.getValue(), "\n"))
|
||||||
.toArray(Object[]::new);
|
.toArray(Object[]::new);
|
||||||
|
@ -24,6 +24,9 @@
|
|||||||
*/
|
*/
|
||||||
package de.bluecolored.bluemap.core.world;
|
package de.bluecolored.bluemap.core.world;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public interface Chunk {
|
public interface Chunk {
|
||||||
|
|
||||||
Chunk EMPTY_CHUNK = new Chunk() {};
|
Chunk EMPTY_CHUNK = new Chunk() {};
|
||||||
@ -72,4 +75,5 @@ default boolean hasOceanFloorHeights() {
|
|||||||
|
|
||||||
default int getOceanFloorY(int x, int z) { return 0; }
|
default int getOceanFloorY(int x, int z) { return 0; }
|
||||||
|
|
||||||
|
default @Nullable BlockEntity getBlockEntity(int x, int y, int z) { return null; };
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
import de.bluecolored.bluemap.core.world.Chunk;
|
import de.bluecolored.bluemap.core.world.Chunk;
|
||||||
import de.bluecolored.bluemap.core.world.LightData;
|
import de.bluecolored.bluemap.core.world.LightData;
|
||||||
import de.bluecolored.bluemap.core.world.World;
|
import de.bluecolored.bluemap.core.world.World;
|
||||||
|
import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class Block<T extends Block<T>> {
|
public class Block<T extends Block<T>> {
|
||||||
|
|
||||||
@ -147,6 +149,10 @@ public int getBlockLightLevel() {
|
|||||||
return getLightData().getBlockLight();
|
return getLightData().getBlockLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable BlockEntity getBlockEntity() {
|
||||||
|
return getChunk().getBlockEntity(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (world != null) {
|
if (world != null) {
|
||||||
@ -174,5 +180,4 @@ public String toString() {
|
|||||||
protected T self() {
|
protected T self() {
|
||||||
return (T) this;
|
return (T) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.core.world.block.entity;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class BannerBlockEntity extends BlockEntity {
|
||||||
|
private final List<Pattern> patterns = new ArrayList<>();
|
||||||
|
|
||||||
|
protected BannerBlockEntity(Map<String, Object> data) {
|
||||||
|
super(data);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Map<String, Object>> patterns = (List<Map<String, Object>>) data.getOrDefault("Patterns", List.of());
|
||||||
|
|
||||||
|
for (Map<String, Object> compound : patterns) {
|
||||||
|
this.patterns.add(new Pattern(compound));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Pattern> getPatterns() {
|
||||||
|
return patterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "BannerBlockEntity{" +
|
||||||
|
"patterns=" + patterns +
|
||||||
|
"} " + super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Pattern {
|
||||||
|
private final String code;
|
||||||
|
private final Color color;
|
||||||
|
|
||||||
|
private Pattern(Map<String, Object> data) {
|
||||||
|
this.code = (String) data.get("Pattern");
|
||||||
|
this.color = Color.values()[(int) data.get("Color")];
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Pattern{" +
|
||||||
|
"code='" + code + '\'' +
|
||||||
|
", color=" + color +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Color {
|
||||||
|
WHITE, ORANGE, MAGENTA, LIGHT_BLUE, YELLOW, LIME, PINK, GRAY, LIGHT_GRAY, CYAN, PURPLE, BLUE, BROWN, GREEN,
|
||||||
|
RED, BLACK
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.core.world.block.entity;
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import de.bluecolored.bluemap.core.logger.Logger;
|
||||||
|
import de.bluecolored.bluenbt.BlueNBT;
|
||||||
|
import de.bluecolored.bluenbt.NBTDeserializer;
|
||||||
|
import de.bluecolored.bluenbt.NBTReader;
|
||||||
|
import de.bluecolored.bluenbt.TypeDeserializer;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
@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
|
||||||
|
);
|
||||||
|
|
||||||
|
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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BlockEntityDeserializer implements TypeDeserializer<BlockEntity> {
|
||||||
|
@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));
|
||||||
|
|
||||||
|
String id = (String) data.get("id");
|
||||||
|
if (id == null || id.isBlank()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockEntityInitializer instance = ID_MAPPING.getOrDefault(id, BlockEntity::new);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return instance.create(data);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger.global.logError("Failed to instantiate BlockEntity instance!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.core.world.block.entity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class SignBlockEntity extends BlockEntity {
|
||||||
|
private final TextData frontText;
|
||||||
|
private final TextData backText;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected SignBlockEntity(Map<String, Object> data) {
|
||||||
|
super(data);
|
||||||
|
|
||||||
|
// Versions before 1.20 used a different format
|
||||||
|
if (data.containsKey("front_text")) {
|
||||||
|
this.frontText = new TextData((Map<String, Object>) data.getOrDefault("front_text", Map.of()));
|
||||||
|
this.backText = new TextData((Map<String, Object>) data.getOrDefault("back_text", Map.of()));
|
||||||
|
} else {
|
||||||
|
this.frontText = new TextData(
|
||||||
|
(byte) data.getOrDefault("GlowingText", (byte) 0) == 1,
|
||||||
|
(String) data.getOrDefault("Color", ""),
|
||||||
|
List.of(
|
||||||
|
(String) data.getOrDefault("Text1", ""),
|
||||||
|
(String) data.getOrDefault("Text2", ""),
|
||||||
|
(String) data.getOrDefault("Text3", ""),
|
||||||
|
(String) data.getOrDefault("Text4", "")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.backText = new TextData(false, "", List.of());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextData getFrontText() {
|
||||||
|
return frontText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextData getBackText() {
|
||||||
|
return backText;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SignBlockEntity{" +
|
||||||
|
"frontText=" + frontText +
|
||||||
|
", backText=" + backText +
|
||||||
|
"} " + super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TextData {
|
||||||
|
private final boolean hasGlowingText;
|
||||||
|
private final String color;
|
||||||
|
private final List<String> messages;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private TextData(Map<String, Object> data) {
|
||||||
|
this.hasGlowingText = (byte) data.getOrDefault("has_glowing_text", (byte) 0) == 1;
|
||||||
|
this.color = (String) data.getOrDefault("color", "");
|
||||||
|
this.messages = (List<String>) data.getOrDefault("messages", List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextData(boolean hasGlowingText, String color, List<String> messages) {
|
||||||
|
this.hasGlowingText = hasGlowingText;
|
||||||
|
this.color = color;
|
||||||
|
this.messages = messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHasGlowingText() {
|
||||||
|
return hasGlowingText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getMessages() {
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TextData{" +
|
||||||
|
"hasGlowingText=" + hasGlowingText +
|
||||||
|
", color='" + color + '\'' +
|
||||||
|
", messages=" + messages +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.core.world.block.entity;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class SkullBlockEntity extends BlockEntity {
|
||||||
|
private final @Nullable String noteBlockSound;
|
||||||
|
private final @Nullable String extraType;
|
||||||
|
private final @Nullable SkullOwner skullOwner;
|
||||||
|
|
||||||
|
protected SkullBlockEntity(Map<String, Object> data) {
|
||||||
|
super(data);
|
||||||
|
|
||||||
|
this.noteBlockSound = (String) data.get("note_block_sound");
|
||||||
|
this.extraType = (String) data.get("ExtraType");
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> ownerData = (Map<String, Object>) data.get("SkullOwner");
|
||||||
|
this.skullOwner = ownerData != null ? new SkullOwner(ownerData) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getNoteBlockSound() {
|
||||||
|
return noteBlockSound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getExtraType() {
|
||||||
|
return extraType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkullOwner getSkullOwner() {
|
||||||
|
return skullOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SkullBlockEntity{" +
|
||||||
|
"noteBlockSound='" + noteBlockSound + '\'' +
|
||||||
|
", extraType='" + extraType + '\'' +
|
||||||
|
", skullOwner=" + skullOwner +
|
||||||
|
"} " + super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SkullOwner {
|
||||||
|
private final @Nullable UUID id;
|
||||||
|
private final @Nullable String name;
|
||||||
|
private final List<Texture> textures = new ArrayList<>();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private SkullOwner(Map<String, Object> data) {
|
||||||
|
int[] uuidInts = (int[]) data.get("Id");
|
||||||
|
this.id = new UUID((long) uuidInts[0] << 32 | uuidInts[1], (long) uuidInts[2] << 32 | uuidInts[3]);
|
||||||
|
this.name = (String) data.get("Name");
|
||||||
|
|
||||||
|
Map<String, Object> properties = (Map<String, Object>) data.getOrDefault("Properties", Map.of());
|
||||||
|
List<Map<String, Object>> textures = (List<Map<String, Object>>) properties.getOrDefault("textures", List.of());
|
||||||
|
|
||||||
|
for (Map<String, Object> compound : textures) {
|
||||||
|
this.textures.add(new Texture(compound));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Texture> getTextures() {
|
||||||
|
return textures;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SkullOwner{" +
|
||||||
|
"id=" + id +
|
||||||
|
", name='" + name + '\'' +
|
||||||
|
", textures=" + textures +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Texture {
|
||||||
|
private final @Nullable String signature;
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
private Texture(Map<String, Object> data) {
|
||||||
|
this.signature = (String) data.get("signature");
|
||||||
|
this.value = (String) data.getOrDefault("value", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSignature() {
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Texture{" +
|
||||||
|
"signature='" + signature + '\'' +
|
||||||
|
", value='" + value + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,7 @@
|
|||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import de.bluecolored.bluemap.core.util.Key;
|
import de.bluecolored.bluemap.core.util.Key;
|
||||||
import de.bluecolored.bluemap.core.world.BlockState;
|
import de.bluecolored.bluemap.core.world.BlockState;
|
||||||
|
import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
|
||||||
import de.bluecolored.bluemap.core.world.mca.data.BlockStateDeserializer;
|
import de.bluecolored.bluemap.core.world.mca.data.BlockStateDeserializer;
|
||||||
import de.bluecolored.bluemap.core.world.mca.data.KeyDeserializer;
|
import de.bluecolored.bluemap.core.world.mca.data.KeyDeserializer;
|
||||||
import de.bluecolored.bluenbt.BlueNBT;
|
import de.bluecolored.bluenbt.BlueNBT;
|
||||||
@ -37,6 +38,7 @@ public class MCAUtil {
|
|||||||
static {
|
static {
|
||||||
BLUENBT.register(TypeToken.get(BlockState.class), new BlockStateDeserializer());
|
BLUENBT.register(TypeToken.get(BlockState.class), new BlockStateDeserializer());
|
||||||
BLUENBT.register(TypeToken.get(Key.class), new KeyDeserializer());
|
BLUENBT.register(TypeToken.get(Key.class), new KeyDeserializer());
|
||||||
|
BLUENBT.register(TypeToken.get(BlockEntity.class), new BlockEntity.BlockEntityDeserializer());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,12 +30,17 @@
|
|||||||
import de.bluecolored.bluemap.core.world.BlockState;
|
import de.bluecolored.bluemap.core.world.BlockState;
|
||||||
import de.bluecolored.bluemap.core.world.DimensionType;
|
import de.bluecolored.bluemap.core.world.DimensionType;
|
||||||
import de.bluecolored.bluemap.core.world.LightData;
|
import de.bluecolored.bluemap.core.world.LightData;
|
||||||
|
import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
|
||||||
import de.bluecolored.bluemap.core.world.mca.MCAUtil;
|
import de.bluecolored.bluemap.core.world.mca.MCAUtil;
|
||||||
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
|
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
|
||||||
import de.bluecolored.bluenbt.NBTName;
|
import de.bluecolored.bluenbt.NBTName;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class Chunk_1_13 extends MCAChunk {
|
public class Chunk_1_13 extends MCAChunk {
|
||||||
|
|
||||||
private static final Key STATUS_EMPTY = new Key("minecraft", "empty");
|
private static final Key STATUS_EMPTY = new Key("minecraft", "empty");
|
||||||
@ -58,6 +63,7 @@ public class Chunk_1_13 extends MCAChunk {
|
|||||||
private final int sectionMin, sectionMax;
|
private final int sectionMin, sectionMax;
|
||||||
|
|
||||||
final int[] biomes;
|
final int[] biomes;
|
||||||
|
private final Map<Long, BlockEntity> blockEntities;
|
||||||
|
|
||||||
public Chunk_1_13(MCAWorld world, Data data) {
|
public Chunk_1_13(MCAWorld world, Data data) {
|
||||||
super(world, data);
|
super(world, data);
|
||||||
@ -113,6 +119,10 @@ public Chunk_1_13(MCAWorld world, Data data) {
|
|||||||
this.sectionMin = 0;
|
this.sectionMin = 0;
|
||||||
this.sectionMax = 0;
|
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
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -195,6 +205,11 @@ public int getOceanFloorY(int x, int z) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockEntity getBlockEntity(int x, int y, int z) {
|
||||||
|
return blockEntities.get((long) y << 8 | (x & 0xF) << 4 | z & 0xF);
|
||||||
|
}
|
||||||
|
|
||||||
private @Nullable Section getSection(int y) {
|
private @Nullable Section getSection(int y) {
|
||||||
y -= sectionMin;
|
y -= sectionMin;
|
||||||
if (y < 0 || y >= this.sections.length) return null;
|
if (y < 0 || y >= this.sections.length) return null;
|
||||||
@ -273,6 +288,7 @@ public static class Level {
|
|||||||
private HeightmapsData heightmaps = new HeightmapsData();
|
private HeightmapsData heightmaps = new HeightmapsData();
|
||||||
private SectionData @Nullable [] sections = null;
|
private SectionData @Nullable [] sections = null;
|
||||||
private int[] biomes = EMPTY_INT_ARRAY;
|
private int[] biomes = EMPTY_INT_ARRAY;
|
||||||
|
@NBTName("TileEntities") private List<BlockEntity> blockEntities = List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
import de.bluecolored.bluemap.core.world.BlockState;
|
import de.bluecolored.bluemap.core.world.BlockState;
|
||||||
import de.bluecolored.bluemap.core.world.DimensionType;
|
import de.bluecolored.bluemap.core.world.DimensionType;
|
||||||
import de.bluecolored.bluemap.core.world.LightData;
|
import de.bluecolored.bluemap.core.world.LightData;
|
||||||
|
import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
|
||||||
import de.bluecolored.bluemap.core.world.mca.MCAUtil;
|
import de.bluecolored.bluemap.core.world.mca.MCAUtil;
|
||||||
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
|
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
|
||||||
import de.bluecolored.bluemap.core.world.mca.PackedIntArrayAccess;
|
import de.bluecolored.bluemap.core.world.mca.PackedIntArrayAccess;
|
||||||
@ -37,6 +38,10 @@
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class Chunk_1_16 extends MCAChunk {
|
public class Chunk_1_16 extends MCAChunk {
|
||||||
|
|
||||||
private static final Key STATUS_EMPTY = new Key("minecraft", "empty");
|
private static final Key STATUS_EMPTY = new Key("minecraft", "empty");
|
||||||
@ -57,6 +62,7 @@ public class Chunk_1_16 extends MCAChunk {
|
|||||||
private final int sectionMin, sectionMax;
|
private final int sectionMin, sectionMax;
|
||||||
|
|
||||||
private final int[] biomes;
|
private final int[] biomes;
|
||||||
|
private final Map<Long, BlockEntity> blockEntities;
|
||||||
|
|
||||||
public Chunk_1_16(MCAWorld world, Data data) {
|
public Chunk_1_16(MCAWorld world, Data data) {
|
||||||
super(world, data);
|
super(world, data);
|
||||||
@ -112,6 +118,10 @@ public Chunk_1_16(MCAWorld world, Data data) {
|
|||||||
this.sectionMin = 0;
|
this.sectionMin = 0;
|
||||||
this.sectionMax = 0;
|
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
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -191,6 +201,11 @@ public int getOceanFloorY(int x, int z) {
|
|||||||
return oceanFloorHeights.get((z & 0xF) << 4 | x & 0xF);
|
return oceanFloorHeights.get((z & 0xF) << 4 | x & 0xF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockEntity getBlockEntity(int x, int y, int z) {
|
||||||
|
return blockEntities.get((long) y << 8 | (x & 0xF) << 4 | z & 0xF);
|
||||||
|
}
|
||||||
|
|
||||||
private @Nullable Section getSection(int y) {
|
private @Nullable Section getSection(int y) {
|
||||||
y -= sectionMin;
|
y -= sectionMin;
|
||||||
if (y < 0 || y >= this.sections.length) return null;
|
if (y < 0 || y >= this.sections.length) return null;
|
||||||
@ -261,6 +276,7 @@ public static class Level {
|
|||||||
private HeightmapsData heightmaps = new HeightmapsData();
|
private HeightmapsData heightmaps = new HeightmapsData();
|
||||||
private SectionData @Nullable [] sections = null;
|
private SectionData @Nullable [] sections = null;
|
||||||
private int[] biomes = EMPTY_INT_ARRAY;
|
private int[] biomes = EMPTY_INT_ARRAY;
|
||||||
|
@NBTName("TileEntities") private List<BlockEntity> blockEntities = List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
import de.bluecolored.bluemap.core.world.BlockState;
|
import de.bluecolored.bluemap.core.world.BlockState;
|
||||||
import de.bluecolored.bluemap.core.world.DimensionType;
|
import de.bluecolored.bluemap.core.world.DimensionType;
|
||||||
import de.bluecolored.bluemap.core.world.LightData;
|
import de.bluecolored.bluemap.core.world.LightData;
|
||||||
|
import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
|
||||||
import de.bluecolored.bluemap.core.world.mca.MCAUtil;
|
import de.bluecolored.bluemap.core.world.mca.MCAUtil;
|
||||||
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
|
import de.bluecolored.bluemap.core.world.mca.MCAWorld;
|
||||||
import de.bluecolored.bluemap.core.world.mca.PackedIntArrayAccess;
|
import de.bluecolored.bluemap.core.world.mca.PackedIntArrayAccess;
|
||||||
@ -37,6 +38,10 @@
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class Chunk_1_18 extends MCAChunk {
|
public class Chunk_1_18 extends MCAChunk {
|
||||||
|
|
||||||
private static final Key STATUS_EMPTY = new Key("minecraft", "empty");
|
private static final Key STATUS_EMPTY = new Key("minecraft", "empty");
|
||||||
@ -57,6 +62,8 @@ public class Chunk_1_18 extends MCAChunk {
|
|||||||
private final Section[] sections;
|
private final Section[] sections;
|
||||||
private final int sectionMin, sectionMax;
|
private final int sectionMin, sectionMax;
|
||||||
|
|
||||||
|
private final Map<Long, BlockEntity> blockEntities;
|
||||||
|
|
||||||
public Chunk_1_18(MCAWorld world, Data data) {
|
public Chunk_1_18(MCAWorld world, Data data) {
|
||||||
super(world, data);
|
super(world, data);
|
||||||
|
|
||||||
@ -108,6 +115,10 @@ public Chunk_1_18(MCAWorld world, Data data) {
|
|||||||
this.sectionMin = 0;
|
this.sectionMin = 0;
|
||||||
this.sectionMax = 0;
|
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
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -182,6 +193,11 @@ public int getOceanFloorY(int x, int z) {
|
|||||||
return oceanFloorHeights.get((z & 0xF) << 4 | x & 0xF) + worldMinY;
|
return oceanFloorHeights.get((z & 0xF) << 4 | x & 0xF) + worldMinY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockEntity getBlockEntity(int x, int y, int z) {
|
||||||
|
return blockEntities.get((long) y << 8 | (x & 0xF) << 4 | z & 0xF);
|
||||||
|
}
|
||||||
|
|
||||||
private @Nullable Section getSection(int y) {
|
private @Nullable Section getSection(int y) {
|
||||||
y -= sectionMin;
|
y -= sectionMin;
|
||||||
if (y < 0 || y >= this.sections.length) return null;
|
if (y < 0 || y >= this.sections.length) return null;
|
||||||
@ -263,6 +279,7 @@ public static class Data extends MCAChunk.Data {
|
|||||||
private long inhabitedTime = 0;
|
private long inhabitedTime = 0;
|
||||||
private HeightmapsData heightmaps = new HeightmapsData();
|
private HeightmapsData heightmaps = new HeightmapsData();
|
||||||
private SectionData @Nullable [] sections = null;
|
private SectionData @Nullable [] sections = null;
|
||||||
|
@NBTName("block_entities") private List<BlockEntity> blockEntities = List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
Loading…
Reference in New Issue
Block a user