From 4361146bf526f7a1efe9c394ec880923e77106c3 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 13 Jan 2025 11:27:55 +0100
Subject: [PATCH 01/15] Rework block-entity deserialization and add first draft
for entities
---
.../src/main/kotlin/bluemap.base.gradle.kts | 2 +-
.../common/plugin/commands/Commands.java | 2 +-
.../bluemap/core/world/BlockEntity.java | 15 +++
.../bluecolored/bluemap/core/world/Chunk.java | 1 -
.../bluemap/core/world/Entity.java | 25 ++++
.../bluecolored/bluemap/core/world/World.java | 3 +
.../core/world/block/entity/BlockEntity.java | 78 ------------
.../world/block/entity/SignBlockEntity.java | 113 -----------------
.../world/block/entity/SkullBlockEntity.java | 115 ------------------
.../bluemap/core/world/mca/MCAUtil.java | 24 +++-
.../bluemap/core/world/mca/MCAWorld.java | 2 +-
.../blockentity}/BannerBlockEntity.java | 69 ++++-------
.../blockentity}/BlockEntityType.java | 26 ++--
.../blockentity/MCABlockEntity.java} | 21 +++-
.../mca/blockentity/SignBlockEntity.java | 76 ++++++++++++
.../mca/blockentity/SkullBlockEntity.java | 72 +++++++++++
.../core/world/mca/chunk/Chunk_1_13.java | 2 +-
.../core/world/mca/chunk/Chunk_1_16.java | 2 +-
.../core/world/mca/chunk/Chunk_1_18.java | 2 +-
.../core/world/mca/chunk/MCAChunk.java | 2 +-
.../mca/data/BlockEntityTypeResolver.java | 47 +++++++
.../world/mca/data/EntityTypeResolver.java | 47 +++++++
.../LenientBlockEntityArrayDeserializer.java | 2 +-
.../mca/data/SignBlockEntityTypeResolver.java | 36 ++++++
.../core/world/mca/data/UUIDDeserializer.java | 54 ++++++++
.../world/mca/data/Vector2fDeserializer.java | 57 +++++++++
.../world/mca/data/Vector3dDeserializer.java | 59 +++++++++
.../core/world/mca/entity/EntityType.java | 25 ++++
.../core/world/mca/entity/MCAEntity.java | 28 +++++
.../core/world/mca/region/RegionType.java | 2 -
gradle/libs.versions.toml | 2 +-
31 files changed, 624 insertions(+), 387 deletions(-)
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/BlockEntity.java
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/Entity.java
delete mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntity.java
delete mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/block/entity/SignBlockEntity.java
delete mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/block/entity/SkullBlockEntity.java
rename core/src/main/java/de/bluecolored/bluemap/core/world/{block/entity => mca/blockentity}/BannerBlockEntity.java (52%)
rename core/src/main/java/de/bluecolored/bluemap/core/world/{block/entity => mca/blockentity}/BlockEntityType.java (82%)
rename core/src/main/java/de/bluecolored/bluemap/core/world/{block/entity/BlockEntityLoader.java => mca/blockentity/MCABlockEntity.java} (72%)
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/blockentity/SignBlockEntity.java
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/blockentity/SkullBlockEntity.java
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/BlockEntityTypeResolver.java
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/EntityTypeResolver.java
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/SignBlockEntityTypeResolver.java
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/UUIDDeserializer.java
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2fDeserializer.java
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector3dDeserializer.java
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/EntityType.java
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/MCAEntity.java
diff --git a/buildSrc/src/main/kotlin/bluemap.base.gradle.kts b/buildSrc/src/main/kotlin/bluemap.base.gradle.kts
index 078ba7bd0..9aeab70c3 100644
--- a/buildSrc/src/main/kotlin/bluemap.base.gradle.kts
+++ b/buildSrc/src/main/kotlin/bluemap.base.gradle.kts
@@ -10,7 +10,7 @@ version = gitVersion()
repositories {
maven ("https://repo.bluecolored.de/releases") {
- content { includeGroupByRegex ("de\\.bluecolored\\..*") }
+ content { includeGroupByRegex ("de\\.bluecolored.*") }
}
maven ("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") {
content { includeGroup ("org.spigotmc") }
diff --git a/common/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java b/common/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java
index dde0796c2..3f762519d 100644
--- a/common/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java
+++ b/common/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java
@@ -59,7 +59,7 @@
import de.bluecolored.bluemap.core.world.ChunkConsumer;
import de.bluecolored.bluemap.core.world.World;
import de.bluecolored.bluemap.core.world.block.Block;
-import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
+import de.bluecolored.bluemap.core.world.BlockEntity;
import java.io.IOException;
import java.nio.file.Path;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/BlockEntity.java b/core/src/main/java/de/bluecolored/bluemap/core/world/BlockEntity.java
new file mode 100644
index 000000000..cb6ca9282
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/BlockEntity.java
@@ -0,0 +1,15 @@
+package de.bluecolored.bluemap.core.world;
+
+import de.bluecolored.bluemap.core.util.Key;
+
+public interface BlockEntity {
+
+ Key getId();
+
+ int getX();
+ int getY();
+ int getZ();
+
+ boolean isKeepPacked();
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/Chunk.java b/core/src/main/java/de/bluecolored/bluemap/core/world/Chunk.java
index 0228becf1..4dcdda671 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/Chunk.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/Chunk.java
@@ -25,7 +25,6 @@
package de.bluecolored.bluemap.core.world;
import de.bluecolored.bluemap.core.world.biome.Biome;
-import de.bluecolored.bluemap.core.world.block.entity.BlockEntity;
import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/Entity.java b/core/src/main/java/de/bluecolored/bluemap/core/world/Entity.java
new file mode 100644
index 000000000..949cf9b88
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/Entity.java
@@ -0,0 +1,25 @@
+package de.bluecolored.bluemap.core.world;
+
+import com.flowpowered.math.vector.Vector2f;
+import com.flowpowered.math.vector.Vector3d;
+import de.bluecolored.bluemap.core.util.Key;
+
+import java.util.UUID;
+
+public interface Entity {
+
+ Key getId();
+
+ UUID getUuid();
+
+ String getCustomName();
+
+ boolean isCustomNameVisible();
+
+ Vector3d getPos();
+
+ Vector3d getMotion();
+
+ Vector2f getRotation();
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/World.java b/core/src/main/java/de/bluecolored/bluemap/core/world/World.java
index bd495ef16..a46973698 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/World.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/World.java
@@ -33,6 +33,7 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -107,6 +108,8 @@ default void preloadRegionChunks(int x, int z) {
*/
void invalidateChunkCache(int x, int z);
+ void iterateEntities(int minX, int minZ, int maxX, int maxZ, Consumer entityConsumer);
+
/**
* Generates a unique world-id based on a world-folder and a dimension
*/
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntity.java b/core/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntity.java
deleted file mode 100644
index 5b42e134b..000000000
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntity.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * This file is part of BlueMap, licensed under the MIT License (MIT).
- *
- * Copyright (c) Blue (Lukas Rieger)
- * 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 de.bluecolored.bluemap.core.util.Key;
-import de.bluecolored.bluenbt.*;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-import lombok.ToString;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.IOException;
-import java.util.Map;
-
-@Getter
-@EqualsAndHashCode
-@ToString
-@NBTDeserializer(BlockEntity.BlockEntityDeserializer.class)
-public abstract class BlockEntity {
-
- protected final String id;
- protected final int x, y, z;
- protected final boolean keepPacked;
-
- protected BlockEntity(Map 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 {
-
- private final BlueNBT blueNBT;
-
- @Override
- @SuppressWarnings("unchecked")
- public @Nullable BlockEntity read(NBTReader reader) throws IOException {
- Map raw = (Map) blueNBT.read(reader, TypeToken.of(Map.class, String.class, Object.class));
-
- String id = (String) raw.get("id");
- if (id == null) return null;
-
- Key typeKey = Key.parse(id, Key.MINECRAFT_NAMESPACE);
- BlockEntityType type = BlockEntityType.REGISTRY.get(typeKey);
- if (type == null) return null;
-
- return type.load(raw);
- }
-
- }
-
-}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/block/entity/SignBlockEntity.java b/core/src/main/java/de/bluecolored/bluemap/core/world/block/entity/SignBlockEntity.java
deleted file mode 100644
index 4327987e1..000000000
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/block/entity/SignBlockEntity.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * This file is part of BlueMap, licensed under the MIT License (MIT).
- *
- * Copyright (c) Blue (Lukas Rieger)
- * 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 data) {
- super(data);
-
- // Versions before 1.20 used a different format
- if (data.containsKey("front_text")) {
- this.frontText = new TextData((Map) data.getOrDefault("front_text", Map.of()));
- this.backText = new TextData((Map) 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 messages;
-
- @SuppressWarnings("unchecked")
- private TextData(Map data) {
- this.hasGlowingText = (byte) data.getOrDefault("has_glowing_text", (byte) 0) == 1;
- this.color = (String) data.getOrDefault("color", "");
- this.messages = (List) data.getOrDefault("messages", List.of());
- }
-
- public TextData(boolean hasGlowingText, String color, List messages) {
- this.hasGlowingText = hasGlowingText;
- this.color = color;
- this.messages = messages;
- }
-
- public boolean isHasGlowingText() {
- return hasGlowingText;
- }
-
- public String getColor() {
- return color;
- }
-
- public List getMessages() {
- return messages;
- }
-
- @Override
- public String toString() {
- return "TextData{" +
- "hasGlowingText=" + hasGlowingText +
- ", color='" + color + '\'' +
- ", messages=" + messages +
- '}';
- }
- }
-}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/block/entity/SkullBlockEntity.java b/core/src/main/java/de/bluecolored/bluemap/core/world/block/entity/SkullBlockEntity.java
deleted file mode 100644
index daafb0a7b..000000000
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/block/entity/SkullBlockEntity.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * This file is part of BlueMap, licensed under the MIT License (MIT).
- *
- * Copyright (c) Blue (Lukas Rieger)
- * 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 lombok.Getter;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-@Getter
-public class SkullBlockEntity extends BlockEntity {
- private final @Nullable String noteBlockSound;
- private final @Nullable String extraType;
- private final @Nullable SkullOwner skullOwner;
-
- protected SkullBlockEntity(Map data) {
- super(data);
-
- this.noteBlockSound = (String) data.get("note_block_sound");
- this.extraType = (String) data.get("ExtraType");
-
- @SuppressWarnings("unchecked")
- Map ownerData = (Map) data.get("SkullOwner");
- this.skullOwner = ownerData != null ? new SkullOwner(ownerData) : null;
- }
-
- @Override
- public String toString() {
- return "SkullBlockEntity{" +
- "noteBlockSound='" + noteBlockSound + '\'' +
- ", extraType='" + extraType + '\'' +
- ", skullOwner=" + skullOwner +
- "} " + super.toString();
- }
-
- @Getter
- public static class SkullOwner {
- private final @Nullable UUID id;
- private final @Nullable String name;
- private final List textures = new ArrayList<>();
-
- @SuppressWarnings("unchecked")
- private SkullOwner(Map data) {
- int @Nullable [] uuidInts = (int[]) data.get("Id");
-
- if (uuidInts == null || uuidInts.length != 4) {
- this.id = null;
- } else {
- this.id = new UUID((long) uuidInts[0] << 32 | uuidInts[1], (long) uuidInts[2] << 32 | uuidInts[3]);
- }
-
- this.name = (String) data.get("Name");
-
- Map properties = (Map) data.getOrDefault("Properties", Map.of());
- List
* @param block The block information that should be rendered.
* @param variant The block-state variant that should be rendered.
- * @param blockModel The model(-view) where the block should be rendered to.
+ * @param tileModel The model(-view) where the block should be rendered to.
* @param blockColor The color that should be set to the color that represents the rendered block.
*/
- void render(BlockNeighborhood block, Variant variant, TileModelView blockModel, Color blockColor);
+ void render(BlockNeighborhood block, Variant variant, TileModelView tileModel, Color blockColor);
}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/block/BlockStateModelRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/block/BlockStateModelRenderer.java
index 19037ee0a..2d4a2580c 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/block/BlockStateModelRenderer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/block/BlockStateModelRenderer.java
@@ -30,7 +30,6 @@
import de.bluecolored.bluemap.core.map.hires.RenderSettings;
import de.bluecolored.bluemap.core.map.hires.TileModelView;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variant;
import de.bluecolored.bluemap.core.util.math.Color;
import de.bluecolored.bluemap.core.world.BlockState;
@@ -57,30 +56,30 @@ public void render(BlockNeighborhood block, TileModelView blockModel, Color bloc
}
private final Color waterloggedColor = new Color();
- public void render(BlockNeighborhood block, BlockState blockState, TileModelView blockModel, Color blockColor) {
+ public void render(BlockNeighborhood block, BlockState blockState, TileModelView tileModel, Color blockColor) {
blockColor.set(0, 0, 0, 0, true);
//shortcut for air
if (blockState.isAir()) return;
- int modelStart = blockModel.getStart();
+ int modelStart = tileModel.getStart();
// render block
- renderModel(block, blockState, blockModel.initialize(), blockColor);
+ renderModel(block, blockState, tileModel.initialize(), blockColor);
// add water if block is waterlogged
if (blockState.isWaterlogged() || block.getProperties().isAlwaysWaterlogged()) {
waterloggedColor.set(0f, 0f, 0f, 0f, true);
- renderModel(block, WATERLOGGED_BLOCKSTATE, blockModel.initialize(), waterloggedColor);
+ renderModel(block, WATERLOGGED_BLOCKSTATE, tileModel.initialize(), waterloggedColor);
blockColor.set(waterloggedColor.overlay(blockColor.premultiplied()));
}
- blockModel.initialize(modelStart);
+ tileModel.initialize(modelStart);
}
private final Color variantColor = new Color();
- private void renderModel(BlockNeighborhood block, BlockState blockState, TileModelView blockModel, Color blockColor) {
- int modelStart = blockModel.getStart();
+ private void renderModel(BlockNeighborhood block, BlockState blockState, TileModelView tileModel, Color blockColor) {
+ int modelStart = tileModel.getStart();
var stateResource = resourcePack.getBlockState(blockState);
if (stateResource == null) return;
@@ -91,19 +90,14 @@ private void renderModel(BlockNeighborhood block, BlockState blockState, TileMod
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < variants.size(); i++) {
- Variant variant = variants.get(i);
-
- BlockModel modelResource = variant.getModel().getResource(resourcePack::getBlockModel);
- if (modelResource == null) continue;
-
variantColor.set(0f, 0f, 0f, 0f, true);
- blockRenderers.get(modelResource.getRenderer())
- .render(block, variant, blockModel.initialize(), variantColor);
+ Variant variant = variants.get(i);
+ blockRenderers.get(variant.getRenderer())
+ .render(block, variant, tileModel.initialize(), variantColor);
if (variantColor.a > blockColorOpacity)
blockColorOpacity = variantColor.a;
-
blockColor.add(variantColor.premultiplied());
}
@@ -112,7 +106,7 @@ private void renderModel(BlockNeighborhood block, BlockState blockState, TileMod
blockColor.a = blockColorOpacity;
}
- blockModel.initialize(modelStart);
+ tileModel.initialize(modelStart);
}
private final static BlockState WATERLOGGED_BLOCKSTATE = new BlockState("minecraft:water");
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/block/LiquidModelRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/block/LiquidModelRenderer.java
index c2a75e620..d44adf63f 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/block/LiquidModelRenderer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/block/LiquidModelRenderer.java
@@ -33,8 +33,8 @@
import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory;
import de.bluecolored.bluemap.core.resources.ResourcePath;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.TextureVariable;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Model;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.TextureVariable;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variant;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture;
import de.bluecolored.bluemap.core.util.Direction;
@@ -69,7 +69,7 @@ public class LiquidModelRenderer implements BlockRenderer {
private BlockNeighborhood block;
private BlockState blockState;
private boolean isWaterlogged, isWaterLike;
- private BlockModel modelResource;
+ private Model modelResource;
private TileModelView blockModel;
private Color blockColor;
@@ -98,10 +98,12 @@ public void render(BlockNeighborhood block, Variant variant, TileModelView block
this.blockState = block.getBlockState();
this.isWaterlogged = blockState.isWaterlogged() || block.getProperties().isAlwaysWaterlogged();
this.isWaterLike = blockState.isWater() || isWaterlogged;
- this.modelResource = variant.getModel().getResource();
+ this.modelResource = variant.getModel().getResource(resourcePack::getModel);
this.blockModel = blockModel;
this.blockColor = color;
+ if (this.modelResource == null) return;
+
build();
}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/block/ResourceModelRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/block/ResourceModelRenderer.java
index 1983efdfc..3abc93c55 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/block/ResourceModelRenderer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/block/ResourceModelRenderer.java
@@ -35,10 +35,10 @@
import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory;
import de.bluecolored.bluemap.core.resources.ResourcePath;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.Element;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.Face;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variant;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Element;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Face;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Model;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture;
import de.bluecolored.bluemap.core.util.Direction;
import de.bluecolored.bluemap.core.util.math.Color;
@@ -70,7 +70,7 @@ public class ResourceModelRenderer implements BlockRenderer {
private BlockNeighborhood block;
private Variant variant;
- private BlockModel modelResource;
+ private Model modelResource;
private TileModelView blockModel;
private Color blockColor;
private float blockColorOpacity;
@@ -85,14 +85,15 @@ public ResourceModelRenderer(ResourcePack resourcePack, TextureGallery textureGa
for (int i = 0; i < rawUvs.length; i++) rawUvs[i] = new VectorM2f(0, 0);
}
- private final MatrixM4f modelTransform = new MatrixM4f();
public void render(BlockNeighborhood block, Variant variant, TileModelView blockModel, Color color) {
this.block = block;
this.blockModel = blockModel;
this.blockColor = color;
this.blockColorOpacity = 0f;
this.variant = variant;
- this.modelResource = variant.getModel().getResource();
+ this.modelResource = variant.getModel().getResource(resourcePack::getModel);
+
+ if (this.modelResource == null) return;
this.tintColor.set(0, 0, 0, -1, true);
@@ -113,14 +114,9 @@ public void render(BlockNeighborhood block, Variant variant, TileModelView block
blockModel.initialize(modelStart);
- // apply model-rotation
- if (variant.isRotated()) {
- blockModel.transform(modelTransform.identity()
- .translate(-0.5f, -0.5f, -0.5f)
- .multiplyTo(variant.getRotationMatrix())
- .translate(0.5f, 0.5f, 0.5f)
- );
- }
+ // apply model-transform
+ if (variant.isTransformed())
+ blockModel.transform(variant.getTransformMatrix());
//random offset
if (block.getProperties().isRandomOffset()){
@@ -258,7 +254,7 @@ private void createElementFace(Element element, Direction faceDir, VectorM3f c0,
// UV-Lock counter-rotation
float uvRotation = 0f;
- if (variant.isUvlock() && variant.isRotated()) {
+ if (variant.isUvlock() && variant.isTransformed()) {
float xRotSin = TrigMath.sin(variant.getX() * TrigMath.DEG_TO_RAD);
float xRotCos = TrigMath.cos(variant.getX() * TrigMath.DEG_TO_RAD);
@@ -300,8 +296,8 @@ private void createElementFace(Element element, Direction faceDir, VectorM3f c0,
tileModel.setColor(face1, tintColor.r, tintColor.g, tintColor.b);
tileModel.setColor(face2, tintColor.r, tintColor.g, tintColor.b);
} else {
- tileModel.setColor(face1, 1, 1, 1);
- tileModel.setColor(face2, 1, 1, 1);
+ tileModel.setColor(face1, 1f, 1f, 1f);
+ tileModel.setColor(face2, 1f, 1f, 1f);
}
// ####### blocklight
@@ -375,8 +371,8 @@ private ExtendedBlock getRotationRelativeBlock(int dx, int dy, int dz){
}
private void makeRotationRelative(VectorM3f direction){
- if (variant.isRotated())
- direction.transform(variant.getRotationMatrix());
+ if (variant.isTransformed())
+ direction.rotateAndScale(variant.getTransformMatrix());
}
private float testAo(VectorM3f vertex, Direction dir){
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityModelRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityModelRenderer.java
new file mode 100644
index 000000000..73efa4e16
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityModelRenderer.java
@@ -0,0 +1,43 @@
+package de.bluecolored.bluemap.core.map.hires.entity;
+
+import com.github.benmanes.caffeine.cache.Caffeine;
+import com.github.benmanes.caffeine.cache.LoadingCache;
+import de.bluecolored.bluemap.core.map.TextureGallery;
+import de.bluecolored.bluemap.core.map.hires.RenderSettings;
+import de.bluecolored.bluemap.core.map.hires.TileModelView;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.entitystate.EntityState;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.entitystate.Part;
+import de.bluecolored.bluemap.core.world.Entity;
+import de.bluecolored.bluemap.core.world.block.BlockNeighborhood;
+
+public class EntityModelRenderer {
+
+ private final ResourcePack resourcePack;
+ private final LoadingCache entityRenderers;
+
+ public EntityModelRenderer(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
+ this.resourcePack = resourcePack;
+ this.entityRenderers = Caffeine.newBuilder()
+ .build(type -> type.create(resourcePack, textureGallery, renderSettings));
+ }
+
+ public void render(Entity entity, BlockNeighborhood block, TileModelView tileModel) {
+ int modelStart = tileModel.getStart();
+
+ EntityState stateResource = resourcePack.getEntityState(entity.getId());
+ if (stateResource == null) return;
+
+ Part[] parts = stateResource.getParts();
+
+ //noinspection ForLoopReplaceableByForEach
+ for (int i = 0; i < parts.length; i++) {
+ Part part = parts[i];
+ entityRenderers.get(part.getRenderer())
+ .render(entity, block, part, tileModel.initialize());
+ }
+
+ tileModel.initialize(modelStart);
+ }
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRenderer.java
new file mode 100644
index 000000000..931defd14
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRenderer.java
@@ -0,0 +1,54 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.map.hires.entity;
+
+import de.bluecolored.bluemap.core.map.hires.TileModelView;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variant;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.entitystate.Part;
+import de.bluecolored.bluemap.core.util.math.Color;
+import de.bluecolored.bluemap.core.world.Entity;
+import de.bluecolored.bluemap.core.world.block.BlockAccess;
+import de.bluecolored.bluemap.core.world.block.BlockNeighborhood;
+
+public interface EntityRenderer {
+
+ /**
+ * Renders the given entities part into the given model, and sets the given blockColor to the
+ * color that represents the rendered block.
+ *
+ * Implementation Note:
+ * This method is guaranteed to be called only on one thread per BlockRenderer instance, so you can use this
+ * for optimizations.
+ * Keep in mind this method will be called once for every block that is being rendered, so be very careful
+ * about performance and instance-creations.
+ *
+ * @param entity The entity information that should be rendered.
+ * @param block the block-position the entity lives at.
+ * @param part The entity part that should be rendered.
+ * @param tileModel The model(-view) where the block should be rendered to.
+ */
+ void render(Entity entity, BlockNeighborhood block, Part part, TileModelView tileModel);
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRendererFactory.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRendererFactory.java
new file mode 100644
index 000000000..cc1a1c76e
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRendererFactory.java
@@ -0,0 +1,35 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.map.hires.entity;
+
+import de.bluecolored.bluemap.core.map.TextureGallery;
+import de.bluecolored.bluemap.core.map.hires.RenderSettings;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
+
+public interface EntityRendererFactory {
+
+ EntityRenderer create(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings);
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRendererType.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRendererType.java
new file mode 100644
index 000000000..07309ae69
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRendererType.java
@@ -0,0 +1,77 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.map.hires.entity;
+
+import de.bluecolored.bluemap.core.map.TextureGallery;
+import de.bluecolored.bluemap.core.map.hires.RenderSettings;
+import de.bluecolored.bluemap.core.map.hires.block.LiquidModelRenderer;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
+import de.bluecolored.bluemap.core.util.Key;
+import de.bluecolored.bluemap.core.util.Keyed;
+import de.bluecolored.bluemap.core.util.Registry;
+import de.bluecolored.bluemap.core.world.BlockState;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+public interface EntityRendererType extends Keyed, EntityRendererFactory {
+
+ EntityRendererType DEFAULT = new Impl(Key.bluemap("default"), ResourceModelRenderer::new);
+ EntityRendererType MISSING = new Impl(Key.bluemap("missing"), MissingModelRenderer::new);
+
+ Registry REGISTRY = new Registry<>(
+ DEFAULT,
+ MISSING
+ );
+
+ /**
+ * If the loaded resourcepack does not have any resources for this entity, this method will be called.
+ * If this method returns true, this renderer will be used to render the entity instead.
+ *
+ *
+ * This can (and should only then) be used to provide a way of rendering entities that are completely dynamically
+ * created by a mod, and there is no way to provide static entity resources that point at the correct renderer.
+ *
+ *
+ * @param entityType The entity-type {@link Key} that was not found in the loaded resources.
+ * @return true if this renderer-type can render the provided entity-type {@link Key} despite missing resources.
+ */
+ default boolean isFallbackFor(Key entityType) {
+ return false;
+ }
+
+ @RequiredArgsConstructor
+ class Impl implements EntityRendererType {
+
+ @Getter private final Key key;
+ private final EntityRendererFactory rendererFactory;
+
+ @Override
+ public EntityRenderer create(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
+ return rendererFactory.create(resourcePack, textureGallery, renderSettings);
+ }
+
+ }
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/MissingModelRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/MissingModelRenderer.java
new file mode 100644
index 000000000..c7b64ff5c
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/MissingModelRenderer.java
@@ -0,0 +1,64 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.map.hires.entity;
+
+import com.github.benmanes.caffeine.cache.Caffeine;
+import com.github.benmanes.caffeine.cache.LoadingCache;
+import de.bluecolored.bluemap.core.logger.Logger;
+import de.bluecolored.bluemap.core.map.TextureGallery;
+import de.bluecolored.bluemap.core.map.hires.RenderSettings;
+import de.bluecolored.bluemap.core.map.hires.TileModelView;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.entitystate.Part;
+import de.bluecolored.bluemap.core.util.Key;
+import de.bluecolored.bluemap.core.world.Entity;
+import de.bluecolored.bluemap.core.world.block.BlockNeighborhood;
+
+public class MissingModelRenderer implements EntityRenderer {
+
+ private static final LoadingCache ENTITY_RENDERER_TYPES = Caffeine.newBuilder()
+ .maximumSize(1000)
+ .build(entityType -> {
+ for (EntityRendererType type : EntityRendererType.REGISTRY.values())
+ if (type.isFallbackFor(entityType)) return type;
+
+ Logger.global.logDebug("No renderer found for entity type: " + entityType);
+ return EntityRendererType.DEFAULT;
+ });
+
+ private final LoadingCache entityRenderers;
+
+ public MissingModelRenderer(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
+ this.entityRenderers = Caffeine.newBuilder()
+ .build(type -> type.create(resourcePack, textureGallery, renderSettings));
+ }
+
+ @Override
+ public void render(Entity entity, BlockNeighborhood block, Part part, TileModelView tileModel) {
+ entityRenderers.get(ENTITY_RENDERER_TYPES.get(entity.getId()))
+ .render(entity, block, part, tileModel);
+ }
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/ResourceModelRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/ResourceModelRenderer.java
new file mode 100644
index 000000000..225954cff
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/ResourceModelRenderer.java
@@ -0,0 +1,255 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.map.hires.entity;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.flowpowered.math.vector.Vector3i;
+import com.flowpowered.math.vector.Vector4f;
+import de.bluecolored.bluemap.core.map.TextureGallery;
+import de.bluecolored.bluemap.core.map.hires.RenderSettings;
+import de.bluecolored.bluemap.core.map.hires.TileModel;
+import de.bluecolored.bluemap.core.map.hires.TileModelView;
+import de.bluecolored.bluemap.core.resources.ResourcePath;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.entitystate.Part;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Element;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Face;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Model;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture;
+import de.bluecolored.bluemap.core.util.Direction;
+import de.bluecolored.bluemap.core.util.math.MatrixM4f;
+import de.bluecolored.bluemap.core.util.math.VectorM2f;
+import de.bluecolored.bluemap.core.util.math.VectorM3f;
+import de.bluecolored.bluemap.core.world.Entity;
+import de.bluecolored.bluemap.core.world.LightData;
+import de.bluecolored.bluemap.core.world.block.BlockNeighborhood;
+
+/**
+ * This model builder creates a BlockStateModel using the information from parsed resource-pack json files.
+ */
+@SuppressWarnings("DuplicatedCode")
+public class ResourceModelRenderer implements EntityRenderer {
+ private static final float SCALE = 1f / 16f;
+
+ private final ResourcePack resourcePack;
+ private final TextureGallery textureGallery;
+ private final RenderSettings renderSettings;
+
+ private final VectorM3f[] corners = new VectorM3f[8];
+ private final VectorM2f[] rawUvs = new VectorM2f[4];
+ private final VectorM2f[] uvs = new VectorM2f[4];
+
+ private Part part;
+ private Model modelResource;
+ private TileModelView tileModel;
+ private int sunLight, blockLight;
+
+ @SuppressWarnings("unused")
+ public ResourceModelRenderer(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
+ this.resourcePack = resourcePack;
+ this.textureGallery = textureGallery;
+ this.renderSettings = renderSettings;
+
+ for (int i = 0; i < corners.length; i++) corners[i] = new VectorM3f(0, 0, 0);
+ for (int i = 0; i < rawUvs.length; i++) rawUvs[i] = new VectorM2f(0, 0);
+ }
+
+ @Override
+ public void render(Entity entity, BlockNeighborhood block, Part part, TileModelView tileModel) {
+ this.part = part;
+ this.tileModel = tileModel;
+ this.modelResource = part.getModel().getResource(resourcePack::getModel);
+
+ // light calculation
+ LightData blockLightData = block.getLightData();
+ this.sunLight = blockLightData.getSkyLight();
+ this.blockLight = blockLightData.getBlockLight();
+
+ // filter out entities that are in a "cave" that should not be rendered
+ if (
+ block.isRemoveIfCave() &&
+ (renderSettings.isCaveDetectionUsesBlockLight() ? Math.max(blockLight, sunLight) : sunLight) == 0
+ ) return;
+
+ // render model
+ int modelStart = this.tileModel.getStart();
+
+ Element[] elements = modelResource.getElements();
+ if (elements != null) {
+ for (Element element : elements) {
+ buildModelElementResource(element, this.tileModel.initialize());
+ }
+ }
+
+ this.tileModel.initialize(modelStart);
+
+ // apply model-transform
+ if (part.isTransformed())
+ this.tileModel.transform(part.getTransformMatrix());
+
+ }
+
+ private final MatrixM4f modelElementTransform = new MatrixM4f();
+ private void buildModelElementResource(Element element, TileModelView blockModel) {
+
+ //create faces
+ Vector3f from = element.getFrom();
+ Vector3f to = element.getTo();
+
+ float
+ minX = Math.min(from.getX(), to.getX()),
+ minY = Math.min(from.getY(), to.getY()),
+ minZ = Math.min(from.getZ(), to.getZ()),
+ maxX = Math.max(from.getX(), to.getX()),
+ maxY = Math.max(from.getY(), to.getY()),
+ maxZ = Math.max(from.getZ(), to.getZ());
+
+ VectorM3f[] c = corners;
+ c[0].x = minX; c[0].y = minY; c[0].z = minZ;
+ c[1].x = minX; c[1].y = minY; c[1].z = maxZ;
+ c[2].x = maxX; c[2].y = minY; c[2].z = minZ;
+ c[3].x = maxX; c[3].y = minY; c[3].z = maxZ;
+ c[4].x = minX; c[4].y = maxY; c[4].z = minZ;
+ c[5].x = minX; c[5].y = maxY; c[5].z = maxZ;
+ c[6].x = maxX; c[6].y = maxY; c[6].z = minZ;
+ c[7].x = maxX; c[7].y = maxY; c[7].z = maxZ;
+
+ int modelStart = blockModel.getStart();
+ createElementFace(element, Direction.DOWN, c[0], c[2], c[3], c[1]);
+ createElementFace(element, Direction.UP, c[5], c[7], c[6], c[4]);
+ createElementFace(element, Direction.NORTH, c[2], c[0], c[4], c[6]);
+ createElementFace(element, Direction.SOUTH, c[1], c[3], c[7], c[5]);
+ createElementFace(element, Direction.WEST, c[0], c[1], c[5], c[4]);
+ createElementFace(element, Direction.EAST, c[3], c[2], c[6], c[7]);
+ blockModel.initialize(modelStart);
+
+ //rotate and scale down
+ blockModel.transform(modelElementTransform
+ .copy(element.getRotation().getMatrix())
+ .scale(SCALE, SCALE, SCALE)
+ );
+ }
+
+ private final VectorM3f faceRotationVector = new VectorM3f(0, 0, 0);
+ private void createElementFace(Element element, Direction faceDir, VectorM3f c0, VectorM3f c1, VectorM3f c2, VectorM3f c3) {
+ Face face = element.getFaces().get(faceDir);
+ if (face == null) return;
+
+ Vector3i faceDirVector = faceDir.toVector();
+
+ // calculate faceRotationVector
+ faceRotationVector.set(
+ faceDirVector.getX(),
+ faceDirVector.getY(),
+ faceDirVector.getZ()
+ );
+ faceRotationVector.rotateAndScale(element.getRotation().getMatrix());
+ makeRotationRelative(faceRotationVector);
+
+ // face culling
+ if (renderSettings.isRenderTopOnly() && faceRotationVector.y < 0.01) return;
+
+ // initialize the faces
+ tileModel.initialize();
+ tileModel.add(2);
+
+ TileModel tileModel = this.tileModel.getTileModel();
+ int face1 = this.tileModel.getStart();
+ int face2 = face1 + 1;
+
+ // ####### positions
+ tileModel.setPositions(face1,
+ c0.x, c0.y, c0.z,
+ c1.x, c1.y, c1.z,
+ c2.x, c2.y, c2.z
+ );
+ tileModel.setPositions(face2,
+ c0.x, c0.y, c0.z,
+ c2.x, c2.y, c2.z,
+ c3.x, c3.y, c3.z
+ );
+
+ // ####### texture
+ ResourcePath texturePath = face.getTexture().getTexturePath(modelResource.getTextures()::get);
+ int textureId = textureGallery.get(texturePath);
+ tileModel.setMaterialIndex(face1, textureId);
+ tileModel.setMaterialIndex(face2, textureId);
+
+ // ####### UV
+ Vector4f uvRaw = face.getUv();
+ float
+ uvx = uvRaw.getX() / 16f,
+ uvy = uvRaw.getY() / 16f,
+ uvz = uvRaw.getZ() / 16f,
+ uvw = uvRaw.getW() / 16f;
+
+ rawUvs[0].set(uvx, uvw);
+ rawUvs[1].set(uvz, uvw);
+ rawUvs[2].set(uvz, uvy);
+ rawUvs[3].set(uvx, uvy);
+
+ // face-rotation
+ int rotationSteps = Math.floorDiv(face.getRotation(), 90) % 4;
+ if (rotationSteps < 0) rotationSteps += 4;
+ for (int i = 0; i < 4; i++)
+ uvs[i] = rawUvs[(rotationSteps + i) % 4];
+
+ tileModel.setUvs(face1,
+ uvs[0].x, uvs[0].y,
+ uvs[1].x, uvs[1].y,
+ uvs[2].x, uvs[2].y
+ );
+
+ tileModel.setUvs(face2,
+ uvs[0].x, uvs[0].y,
+ uvs[2].x, uvs[2].y,
+ uvs[3].x, uvs[3].y
+ );
+
+ // ####### color
+ tileModel.setColor(face1, 1f, 1f, 1f);
+ tileModel.setColor(face2, 1f, 1f, 1f);
+
+ // ####### blocklight
+ int emissiveBlockLight = Math.max(blockLight, element.getLightEmission());
+ tileModel.setBlocklight(face1, emissiveBlockLight);
+ tileModel.setBlocklight(face2, emissiveBlockLight);
+
+ // ####### sunlight
+ tileModel.setSunlight(face1, sunLight);
+ tileModel.setSunlight(face2, sunLight);
+
+ // ######## AO
+ tileModel.setAOs(face1, 1f, 1f, 1f);
+ tileModel.setAOs(face2, 1f, 1f, 1f);
+
+ }
+
+ private void makeRotationRelative(VectorM3f direction){
+ if (part.isTransformed())
+ direction.rotateAndScale(part.getTransformMatrix());
+ }
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/resources/adapter/ResourcesGson.java b/core/src/main/java/de/bluecolored/bluemap/core/resources/adapter/ResourcesGson.java
index 65dc09452..a62596bfd 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/resources/adapter/ResourcesGson.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/resources/adapter/ResourcesGson.java
@@ -30,7 +30,8 @@
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import de.bluecolored.bluemap.core.map.hires.block.BlockRendererType;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.Face;
+import de.bluecolored.bluemap.core.map.hires.entity.EntityRendererType;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Face;
import de.bluecolored.bluemap.core.util.Direction;
import de.bluecolored.bluemap.core.util.Key;
import de.bluecolored.bluemap.core.util.math.Axis;
@@ -70,6 +71,11 @@ public static GsonBuilder addAdapter(GsonBuilder builder) {
BlockRendererType.REGISTRY,
Key.BLUEMAP_NAMESPACE,
BlockRendererType.DEFAULT
+ ))
+ .registerTypeAdapter(EntityRendererType.class, new RegistryAdapter<>(
+ EntityRendererType.REGISTRY,
+ Key.BLUEMAP_NAMESPACE,
+ EntityRendererType.DEFAULT
));
}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java
index 700f0c9c8..e3481161a 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java
@@ -33,11 +33,13 @@
import de.bluecolored.bluemap.core.resources.ResourcePath;
import de.bluecolored.bluemap.core.resources.adapter.ResourcesGson;
import de.bluecolored.bluemap.core.resources.pack.Pack;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.TextureVariable;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.BlockState;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.entitystate.EntityState;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Model;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.TextureVariable;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.AnimationMeta;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture;
+import de.bluecolored.bluemap.core.util.Key;
import de.bluecolored.bluemap.core.util.Tristate;
import de.bluecolored.bluemap.core.world.BlockProperties;
import org.jetbrains.annotations.Nullable;
@@ -59,11 +61,14 @@
public class ResourcePack extends Pack {
public static final ResourcePath MISSING_BLOCK_STATE = new ResourcePath<>("bluemap", "missing");
- public static final ResourcePath MISSING_BLOCK_MODEL = new ResourcePath<>("bluemap", "block/missing");
+ public static final ResourcePath MISSING_ENTITY_STATE = new ResourcePath<>("bluemap", "missing");
+ public static final ResourcePath MISSING_BLOCK_MODEL = new ResourcePath<>("bluemap", "block/missing");
+ public static final ResourcePath MISSING_ENTITY_MODEL = new ResourcePath<>("bluemap", "entity/missing");
public static final ResourcePath MISSING_TEXTURE = new ResourcePath<>("bluemap", "block/missing");
private final Map, BlockState> blockStates;
- private final Map, BlockModel> blockModels;
+ private final Map, EntityState> entityStates;
+ private final Map, Model> models;
private final Map, Texture> textures;
private final Map, BufferedImage> colormaps;
@@ -73,19 +78,19 @@ public class ResourcePack extends Pack {
private final Map, ResourcePackExtension> resourcePackExtensions;
private final Map> blockStatePaths;
+ private final Map> entityStatePaths;
private final Map> texturePaths;
private final LoadingCache blockPropertiesCache;
public ResourcePack(int packVersion) {
super(packVersion);
- this.blockStatePaths = new HashMap<>();
this.blockStates = new HashMap<>();
- this.blockModels = new HashMap<>();
- this.texturePaths = new HashMap<>();
+ this.entityStates = new HashMap<>();
+ this.models = new HashMap<>();
this.textures = new HashMap<>();
- this.colormaps = new HashMap<>();
+ this.colormaps = new HashMap<>();
this.colorCalculatorFactory = new BlockColorCalculatorFactory();
this.blockPropertiesConfig = new BlockPropertiesConfig();
@@ -93,6 +98,9 @@ public ResourcePack(int packVersion) {
for (ResourcePackExtensionType> extensionType : ResourcePackExtensionType.REGISTRY.values())
resourcePackExtensions.put(extensionType, extensionType.create());
+ this.blockStatePaths = new HashMap<>();
+ this.entityStatePaths = new HashMap<>();
+ this.texturePaths = new HashMap<>();
this.blockPropertiesCache = Caffeine.newBuilder()
.executor(BlueMap.THREAD_POOL)
.maximumSize(10000)
@@ -145,7 +153,22 @@ private void loadResources(Path root) throws IOException {
}, blockStates));
}, BlueMap.THREAD_POOL),
- // load blockmodels
+ // load entitystates
+ CompletableFuture.runAsync(() -> {
+ list(root.resolve("assets"))
+ .map(path -> path.resolve("entitystates"))
+ .filter(Files::isDirectory)
+ .flatMap(ResourcePack::walk)
+ .filter(path -> path.getFileName().toString().endsWith(".json"))
+ .filter(Files::isRegularFile)
+ .forEach(file -> loadResource(root, file, 1, 3, key -> {
+ try (BufferedReader reader = Files.newBufferedReader(file)) {
+ return ResourcesGson.INSTANCE.fromJson(reader, EntityState.class);
+ }
+ }, entityStates));
+ }, BlueMap.THREAD_POOL),
+
+ // load models
CompletableFuture.runAsync(() -> {
list(root.resolve("assets"))
.map(path -> path.resolve("models"))
@@ -156,9 +179,9 @@ private void loadResources(Path root) throws IOException {
.filter(Files::isRegularFile)
.forEach(file -> loadResource(root, file, 1, 3, key -> {
try (BufferedReader reader = Files.newBufferedReader(file)) {
- return ResourcesGson.INSTANCE.fromJson(reader, BlockModel.class);
+ return ResourcesGson.INSTANCE.fromJson(reader, Model.class);
}
- }, blockModels));
+ }, models));
}, BlueMap.THREAD_POOL),
// load colormaps
@@ -223,7 +246,7 @@ private void loadTextures(Path root) throws IOException {
// collect all used textures
Set> usedTextures = new HashSet<>();
usedTextures.add(MISSING_TEXTURE);
- for (BlockModel model : blockModels.values()) {
+ for (Model model : models.values()) {
for (TextureVariable textureVariable : model.getTextures().values()) {
if (textureVariable.isReference()) continue;
usedTextures.add(textureVariable.getTexturePath());
@@ -276,24 +299,25 @@ private void bake() throws IOException, InterruptedException {
// fill path maps
blockStates.keySet().forEach(path -> blockStatePaths.put(path.getFormatted(), path));
+ entityStates.keySet().forEach(path -> entityStatePaths.put(path, path));
textures.keySet().forEach(path -> texturePaths.put(path.getFormatted(), path));
// optimize references
- for (BlockModel model : blockModels.values()) {
+ for (Model model : models.values()) {
model.optimize(this);
}
if (Thread.interrupted()) throw new InterruptedException();
// apply model parents
- for (BlockModel model : blockModels.values()) {
+ for (Model model : models.values()) {
model.applyParent(this);
}
if (Thread.interrupted()) throw new InterruptedException();
// calculate model properties
- for (BlockModel model : blockModels.values()) {
+ for (Model model : models.values()) {
model.calculateProperties(this);
}
@@ -322,9 +346,19 @@ private void bake() throws IOException, InterruptedException {
return blockState != null ? blockState : MISSING_BLOCK_STATE.getResource(blockStates::get);
}
- public @Nullable BlockModel getBlockModel(ResourcePath path) {
- BlockModel blockModel = blockModels.get(path);
- return blockModel != null ? blockModel : MISSING_BLOCK_MODEL.getResource(blockModels::get);
+ public @Nullable EntityState getEntityState(Key entityId) {
+ ResourcePath path = entityStatePaths.get(entityId);
+ return path != null ? path.getResource(this::getEntityState) : MISSING_ENTITY_STATE.getResource(this::getEntityState);
+ }
+
+ public @Nullable EntityState getEntityState(ResourcePath path) {
+ EntityState entityState = entityStates.get(path);
+ return entityState != null ? entityState : MISSING_ENTITY_STATE.getResource(entityStates::get);
+ }
+
+ public @Nullable Model getModel(ResourcePath path) {
+ Model model = models.get(path);
+ return model != null ? model : MISSING_BLOCK_MODEL.getResource(models::get);
}
public @Nullable ResourcePath getTexturePath(String formatted) {
@@ -355,7 +389,7 @@ private BlockProperties loadBlockProperties(de.bluecolored.bluemap.core.world.Bl
BlockState resource = getBlockState(state);
if (resource != null) {
resource.forEach(state,0, 0, 0, variant -> {
- BlockModel model = variant.getModel().getResource(this::getBlockModel);
+ Model model = variant.getModel().getResource(this::getModel);
if (model != null) {
if (props.isOccluding() == Tristate.UNDEFINED) props.occluding(model.isOccluding());
if (props.isCulling() == Tristate.UNDEFINED) props.culling(model.isCulling());
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variant.java b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variant.java
index aefb0bf88..12a91d385 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variant.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variant.java
@@ -28,59 +28,39 @@
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
+import de.bluecolored.bluemap.core.map.hires.block.BlockRendererType;
import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory;
import de.bluecolored.bluemap.core.resources.ResourcePath;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Model;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
import de.bluecolored.bluemap.core.util.math.MatrixM3f;
+import de.bluecolored.bluemap.core.util.math.MatrixM4f;
+import lombok.Getter;
import java.io.IOException;
@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"})
@JsonAdapter(Variant.Adapter.class)
+@Getter
public class Variant {
- private ResourcePath model = ResourcePack.MISSING_BLOCK_MODEL;
+ private BlockRendererType renderer = BlockRendererType.DEFAULT;
+ private ResourcePath model = ResourcePack.MISSING_BLOCK_MODEL;
private float x = 0, y = 0;
private boolean uvlock = false;
private double weight = 1;
- private transient boolean rotated;
- private transient MatrixM3f rotationMatrix;
+ private transient boolean transformed;
+ private transient MatrixM4f transformMatrix;
private Variant(){}
private void init() {
- this.rotated = x != 0 || y != 0;
- this.rotationMatrix = new MatrixM3f().rotate(-x, -y, 0);
- }
-
- public ResourcePath getModel() {
- return model;
- }
-
- public float getX() {
- return x;
- }
-
- public float getY() {
- return y;
- }
-
- public boolean isUvlock() {
- return uvlock;
- }
-
- public double getWeight() {
- return weight;
- }
-
- public boolean isRotated() {
- return rotated;
- }
-
- public MatrixM3f getRotationMatrix() {
- return rotationMatrix;
+ this.transformed = x != 0 || y != 0;
+ this.transformMatrix = new MatrixM4f()
+ .translate(-0.5f, -0.5f, -0.5f)
+ .rotate(-x, -y, 0)
+ .translate(0.5f, 0.5f, 0.5f);
}
static class Adapter extends AbstractTypeAdapterFactory {
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/EntityState.java b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/EntityState.java
new file mode 100644
index 000000000..e1cc37f0b
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/EntityState.java
@@ -0,0 +1,43 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.resources.pack.resourcepack.entitystate;
+
+import de.bluecolored.bluemap.core.resources.ResourcePath;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Multipart;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variant;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variants;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Model;
+import lombok.Getter;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.Consumer;
+
+@SuppressWarnings("FieldMayBeFinal")
+@Getter
+public class EntityState {
+
+ private Part[] parts;
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/Part.java b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/Part.java
new file mode 100644
index 000000000..0ff7bd35a
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/Part.java
@@ -0,0 +1,55 @@
+package de.bluecolored.bluemap.core.resources.pack.resourcepack.entitystate;
+
+import com.flowpowered.math.vector.Vector3f;
+import com.google.gson.Gson;
+import com.google.gson.annotations.JsonAdapter;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import de.bluecolored.bluemap.core.map.hires.entity.EntityRendererType;
+import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory;
+import de.bluecolored.bluemap.core.resources.ResourcePath;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
+import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Model;
+import de.bluecolored.bluemap.core.util.math.MatrixM4f;
+import lombok.Getter;
+
+import java.io.IOException;
+
+@SuppressWarnings("FieldMayBeFinal")
+@JsonAdapter(Part.Adapter.class)
+@Getter
+public class Part {
+
+ private EntityRendererType renderer = EntityRendererType.DEFAULT;
+ private ResourcePath model = ResourcePack.MISSING_ENTITY_MODEL;
+ private Vector3f position = Vector3f.ZERO;
+ private Vector3f rotation = Vector3f.ZERO;
+
+ private transient boolean transformed;
+ private transient MatrixM4f transformMatrix;
+
+ private Part(){}
+
+ private void init() {
+ this.transformed = !position.equals(Vector3f.ZERO) || !rotation.equals(Vector3f.ZERO);
+ this.transformMatrix = new MatrixM4f()
+ .rotate(rotation.getX(), rotation.getY(), rotation.getZ())
+ .translate(position.getX(), position.getY(), position.getZ());
+ }
+
+ static class Adapter extends AbstractTypeAdapterFactory {
+
+ public Adapter() {
+ super(Part.class);
+ }
+
+ @Override
+ public Part read(JsonReader in, Gson gson) throws IOException {
+ Part part = gson.getDelegateAdapter(this, TypeToken.get(Part.class)).read(in);
+ part.init();
+ return part;
+ }
+
+ }
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Element.java b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/Element.java
similarity index 68%
rename from core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Element.java
rename to core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/Element.java
index 38ce530bd..4e39b9511 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Element.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/Element.java
@@ -22,7 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel;
+package de.bluecolored.bluemap.core.resources.pack.resourcepack.model;
import com.flowpowered.math.vector.Vector3f;
import com.flowpowered.math.vector.Vector4f;
@@ -33,12 +33,14 @@
import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
import de.bluecolored.bluemap.core.util.Direction;
+import lombok.Getter;
import java.io.IOException;
import java.util.EnumMap;
@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"})
@JsonAdapter(Element.Adapter.class)
+@Getter
public class Element {
private static final Vector3f FULL_BLOCK_MIN = Vector3f.ZERO;
private static final Vector3f FULL_BLOCK_MAX = new Vector3f(16, 16, 16);
@@ -67,79 +69,31 @@ private void init() {
}
private Vector4f calculateDefaultUV(Direction face) {
- switch (face){
-
- case DOWN :
- case UP :
- return new Vector4f(
- from.getX(), from.getZ(),
- to.getX(), to.getZ()
- );
-
- case NORTH :
- case SOUTH :
- return new Vector4f(
- from.getX(), from.getY(),
- to.getX(), to.getY()
- );
-
- case WEST :
- case EAST :
- return new Vector4f(
- from.getZ(), from.getY(),
- to.getZ(), to.getY()
- );
-
- default :
- return new Vector4f(
- 0, 0,
- 16, 16
- );
-
- }
+ return switch (face) {
+ case DOWN, UP -> new Vector4f(
+ from.getX(), from.getZ(),
+ to.getX(), to.getZ()
+ );
+ case NORTH, SOUTH -> new Vector4f(
+ from.getX(), from.getY(),
+ to.getX(), to.getY()
+ );
+ case WEST, EAST -> new Vector4f(
+ from.getZ(), from.getY(),
+ to.getZ(), to.getY()
+ );
+ };
}
private Direction calculateDefaultCullface(Direction face) {
- switch (face) {
- case DOWN:
- return from.getY() == 0f ? Direction.DOWN : null;
- case UP:
- return to.getY() == 1f ? Direction.UP : null;
- case NORTH:
- return from.getZ() == 0f ? Direction.NORTH : null;
- case SOUTH:
- return to.getZ() == 1f ? Direction.SOUTH : null;
- case EAST:
- return to.getX() == 1f ? Direction.EAST : null;
- case WEST:
- return from.getX() == 0f ? Direction.WEST : null;
- default:
- return null;
- }
- }
-
- public Vector3f getFrom() {
- return from;
- }
-
- public Vector3f getTo() {
- return to;
- }
-
- public Rotation getRotation() {
- return rotation;
- }
-
- public boolean isShade() {
- return shade;
- }
-
- public int getLightEmission() {
- return lightEmission;
- }
-
- public EnumMap getFaces() {
- return faces;
+ return switch (face) {
+ case DOWN -> from.getY() == 0f ? Direction.DOWN : null;
+ case UP -> to.getY() == 1f ? Direction.UP : null;
+ case NORTH -> from.getZ() == 0f ? Direction.NORTH : null;
+ case SOUTH -> to.getZ() == 1f ? Direction.SOUTH : null;
+ case EAST -> to.getX() == 1f ? Direction.EAST : null;
+ case WEST -> from.getX() == 0f ? Direction.WEST : null;
+ };
}
public Element copy() {
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Face.java b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/Face.java
similarity index 88%
rename from core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Face.java
rename to core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/Face.java
index 2b9c42a30..16505a3fc 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Face.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/Face.java
@@ -22,15 +22,17 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel;
+package de.bluecolored.bluemap.core.resources.pack.resourcepack.model;
import com.flowpowered.math.vector.Vector4f;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
import de.bluecolored.bluemap.core.util.Direction;
+import lombok.Getter;
import java.util.function.Function;
@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"})
+@Getter
public class Face {
private static final TextureVariable DEFAULT_TEXTURE = new TextureVariable(ResourcePack.MISSING_TEXTURE);
@@ -57,26 +59,6 @@ void init(Direction direction, Function defaultUvCalculator
if (uv == null) uv = defaultUvCalculator.apply(direction);
}
- public Vector4f getUv() {
- return uv;
- }
-
- public TextureVariable getTexture() {
- return texture;
- }
-
- public Direction getCullface() {
- return cullface;
- }
-
- public int getRotation() {
- return rotation;
- }
-
- public int getTintindex() {
- return tintindex;
- }
-
public Face copy() {
return new Face(this);
}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/BlockModel.java b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/Model.java
similarity index 81%
rename from core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/BlockModel.java
rename to core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/Model.java
index 25c5f4487..18852aa9b 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/BlockModel.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/Model.java
@@ -22,62 +22,31 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel;
+package de.bluecolored.bluemap.core.resources.pack.resourcepack.model;
-import de.bluecolored.bluemap.core.map.hires.block.BlockRendererType;
import de.bluecolored.bluemap.core.resources.ResourcePath;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture;
import de.bluecolored.bluemap.core.util.Direction;
+import lombok.Getter;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"})
-public class BlockModel {
+@Getter
+public class Model {
- private BlockRendererType renderer = BlockRendererType.DEFAULT;
-
- private ResourcePath parent;
+ private @Nullable ResourcePath parent;
private Map textures = new HashMap<>();
- private Element[] elements;
+ private Element @Nullable [] elements;
private boolean ambientocclusion = true;
private transient boolean culling = false;
private transient boolean occluding = false;
- private BlockModel(){}
-
- public BlockRendererType getRenderer() {
- return renderer;
- }
-
- @Nullable
- public ResourcePath getParent() {
- return parent;
- }
-
- public Map getTextures() {
- return textures;
- }
-
- @Nullable
- public Element[] getElements() {
- return elements;
- }
-
- public boolean isAmbientocclusion() {
- return ambientocclusion;
- }
-
- public boolean isCulling() {
- return culling;
- }
-
- public boolean isOccluding() {
- return occluding;
- }
+ private Model(){}
public synchronized void optimize(ResourcePack resourcePack) {
for (var variable : this.textures.values()) {
@@ -95,10 +64,10 @@ public synchronized void applyParent(ResourcePack resourcePack) {
if (this.parent == null) return;
// set parent to null early to avoid trying to resolve reference-loops
- ResourcePath parentPath = this.parent;
+ ResourcePath parentPath = this.parent;
this.parent = null;
- BlockModel parent = parentPath.getResource(resourcePack::getBlockModel);
+ Model parent = parentPath.getResource(resourcePack::getModel);
if (parent != null) {
parent.applyParent(resourcePack);
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Rotation.java b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/Rotation.java
similarity index 90%
rename from core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Rotation.java
rename to core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/Rotation.java
index 47f0af128..7209cee27 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Rotation.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/Rotation.java
@@ -22,7 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel;
+package de.bluecolored.bluemap.core.resources.pack.resourcepack.model;
import com.flowpowered.math.TrigMath;
import com.flowpowered.math.vector.Vector3f;
@@ -34,19 +34,19 @@
import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory;
import de.bluecolored.bluemap.core.util.math.Axis;
import de.bluecolored.bluemap.core.util.math.MatrixM4f;
+import lombok.Getter;
import java.io.IOException;
@SuppressWarnings("FieldMayBeFinal")
@JsonAdapter(Rotation.Adapter.class)
+@Getter
public class Rotation {
private static final Vector3f DEFAULT_ORIGIN = new Vector3f(8, 8, 8);
private static final double FIT_TO_BLOCK_SCALE_MULTIPLIER = 2 - Math.sqrt(2);
public static final Rotation ZERO = new Rotation();
- static {
- ZERO.init();
- }
+ static { ZERO.init(); }
private Vector3f origin = DEFAULT_ORIGIN;
private Axis axis = Axis.Y;
@@ -83,26 +83,6 @@ private void init() {
}
}
- public Vector3f getOrigin() {
- return origin;
- }
-
- public Axis getAxis() {
- return axis;
- }
-
- public double getAngle() {
- return angle;
- }
-
- public boolean isRescale() {
- return rescale;
- }
-
- public MatrixM4f getMatrix() {
- return matrix;
- }
-
static class Adapter extends AbstractTypeAdapterFactory {
public Adapter() {
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/TextureVariable.java
similarity index 91%
rename from core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java
rename to core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/TextureVariable.java
index 8d2e397ed..dbdaa392d 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/model/TextureVariable.java
@@ -22,7 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel;
+package de.bluecolored.bluemap.core.resources.pack.resourcepack.model;
import com.google.gson.TypeAdapter;
import com.google.gson.annotations.JsonAdapter;
@@ -31,6 +31,8 @@
import de.bluecolored.bluemap.core.resources.ResourcePath;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture;
+import lombok.Getter;
+import lombok.Setter;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
@@ -40,7 +42,10 @@
@JsonAdapter(TextureVariable.Adapter.class)
public class TextureVariable {
- private String referenceName;
+ @Getter @Setter
+ private @Nullable String referenceName;
+
+ @Getter @Setter
private ResourcePath texturePath;
private transient volatile boolean isReference, isResolving;
@@ -66,20 +71,6 @@ public TextureVariable(ResourcePath texturePath) {
this.isResolving = false;
}
- @Nullable
- public String getReferenceName() {
- return referenceName;
- }
-
- public void setReferenceName(String referenceName) {
- this.referenceName = referenceName;
- }
-
- @Nullable
- public ResourcePath getTexturePath() {
- return texturePath;
- }
-
@Nullable
public ResourcePath getTexturePath(Function supplier) {
if (this.isReference) return resolveTexturePath(supplier);
@@ -105,10 +96,6 @@ private ResourcePath resolveTexturePath(Function texturePath) {
- this.texturePath = texturePath;
- }
-
public boolean isReference() {
return isReference;
}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/block/ExtendedBlock.java b/core/src/main/java/de/bluecolored/bluemap/core/world/block/ExtendedBlock.java
index 4aed05a11..eb08c495b 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/block/ExtendedBlock.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/block/ExtendedBlock.java
@@ -75,6 +75,9 @@ public ExtendedBlock copy() {
}
protected void copyFrom(ExtendedBlock extendedBlock) {
+ this.x = extendedBlock.x;
+ this.y = extendedBlock.y;
+ this.z = extendedBlock.z;
this.blockAccess = extendedBlock.blockAccess;
this.resourcePack = extendedBlock.resourcePack;
this.renderSettings = extendedBlock.renderSettings;
diff --git a/core/src/main/resourceExtensions/assets/bluemap/blockstates/missing.json b/core/src/main/resourceExtensions/assets/bluemap/blockstates/missing.json
index 55827a939..803c28520 100644
--- a/core/src/main/resourceExtensions/assets/bluemap/blockstates/missing.json
+++ b/core/src/main/resourceExtensions/assets/bluemap/blockstates/missing.json
@@ -1,5 +1,8 @@
{
"variants": {
- "": { "model": "bluemap:block/missing" }
+ "": {
+ "renderer": "bluemap:missing",
+ "model": "bluemap:block/missing"
+ }
}
}
\ No newline at end of file
diff --git a/core/src/main/resourceExtensions/assets/bluemap/entitystates/missing.json b/core/src/main/resourceExtensions/assets/bluemap/entitystates/missing.json
new file mode 100644
index 000000000..5f44fc120
--- /dev/null
+++ b/core/src/main/resourceExtensions/assets/bluemap/entitystates/missing.json
@@ -0,0 +1,8 @@
+{
+ "parts": [
+ {
+ "renderer": "bluemap:missing",
+ "model": "bluemap:entity/missing"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/core/src/main/resourceExtensions/assets/bluemap/models/block/missing.json b/core/src/main/resourceExtensions/assets/bluemap/models/block/missing.json
index e185348a5..206494b39 100644
--- a/core/src/main/resourceExtensions/assets/bluemap/models/block/missing.json
+++ b/core/src/main/resourceExtensions/assets/bluemap/models/block/missing.json
@@ -1,5 +1,4 @@
{
- "renderer": "bluemap:missing",
"parent": "block/cube_all",
"textures": {
"all": "bluemap:block/missing"
diff --git a/core/src/main/resourceExtensions/assets/bluemap/models/entity/missing.json b/core/src/main/resourceExtensions/assets/bluemap/models/entity/missing.json
new file mode 100644
index 000000000..9e26dfeeb
--- /dev/null
+++ b/core/src/main/resourceExtensions/assets/bluemap/models/entity/missing.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/core/src/main/resourceExtensions/assets/minecraft/blockstates/lava.json b/core/src/main/resourceExtensions/assets/minecraft/blockstates/lava.json
index 0ca283840..aba57984a 100644
--- a/core/src/main/resourceExtensions/assets/minecraft/blockstates/lava.json
+++ b/core/src/main/resourceExtensions/assets/minecraft/blockstates/lava.json
@@ -1,5 +1,8 @@
{
"variants": {
- "": { "model": "block/lava" }
+ "": {
+ "renderer": "bluemap:liquid",
+ "model": "block/lava"
+ }
}
}
diff --git a/core/src/main/resourceExtensions/assets/minecraft/blockstates/water.json b/core/src/main/resourceExtensions/assets/minecraft/blockstates/water.json
index 358729bf5..7a766ffd4 100644
--- a/core/src/main/resourceExtensions/assets/minecraft/blockstates/water.json
+++ b/core/src/main/resourceExtensions/assets/minecraft/blockstates/water.json
@@ -1,5 +1,8 @@
{
"variants": {
- "": { "model": "block/water" }
+ "": {
+ "renderer": "bluemap:liquid",
+ "model": "block/water"
+ }
}
}
diff --git a/core/src/main/resourceExtensions/assets/minecraft/models/block/lava.json b/core/src/main/resourceExtensions/assets/minecraft/models/block/lava.json
index 51c0b0d9e..db482171d 100644
--- a/core/src/main/resourceExtensions/assets/minecraft/models/block/lava.json
+++ b/core/src/main/resourceExtensions/assets/minecraft/models/block/lava.json
@@ -1,5 +1,4 @@
{
- "renderer": "bluemap:liquid",
"textures": {
"particle": "block/lava_still",
"still": "block/lava_still",
diff --git a/core/src/main/resourceExtensions/assets/minecraft/models/block/water.json b/core/src/main/resourceExtensions/assets/minecraft/models/block/water.json
index 47316ea37..8f24d8dd0 100644
--- a/core/src/main/resourceExtensions/assets/minecraft/models/block/water.json
+++ b/core/src/main/resourceExtensions/assets/minecraft/models/block/water.json
@@ -1,5 +1,4 @@
{
- "renderer": "bluemap:liquid",
"textures": {
"particle": "block/water_still",
"still": "block/water_still",
From 05e12c5a749d00fa3060ce203cee22810686a8c4 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Sun, 19 Jan 2025 22:05:17 +0100
Subject: [PATCH 08/15] Extract region/chunk-loading/caching from mcaworld into
generic ChunkGrid class
---
.../bluemap/core/world/mca/ChunkGrid.java | 165 ++++++++++++++++++
.../bluemap/core/world/mca/ChunkLoader.java | 2 +
.../bluemap/core/world/mca/MCAWorld.java | 122 ++-----------
.../core/world/mca/chunk/MCAChunkLoader.java | 5 +
4 files changed, 183 insertions(+), 111 deletions(-)
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkGrid.java
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkGrid.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkGrid.java
new file mode 100644
index 000000000..0be1e8a09
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkGrid.java
@@ -0,0 +1,165 @@
+package de.bluecolored.bluemap.core.world.mca;
+
+import com.flowpowered.math.vector.Vector2i;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import com.github.benmanes.caffeine.cache.LoadingCache;
+import de.bluecolored.bluemap.core.BlueMap;
+import de.bluecolored.bluemap.core.logger.Logger;
+import de.bluecolored.bluemap.core.util.Vector2iCache;
+import de.bluecolored.bluemap.core.util.WatchService;
+import de.bluecolored.bluemap.core.world.ChunkConsumer;
+import de.bluecolored.bluemap.core.world.Region;
+import de.bluecolored.bluemap.core.world.mca.region.RegionType;
+import lombok.RequiredArgsConstructor;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+@RequiredArgsConstructor
+public class ChunkGrid {
+ private static final Vector2iCache VECTOR_2_I_CACHE = new Vector2iCache();
+
+ private final ChunkLoader chunkLoader;
+ private final Path regionFolder;
+
+ private final LoadingCache> regionCache = Caffeine.newBuilder()
+ .executor(BlueMap.THREAD_POOL)
+ .softValues()
+ .maximumSize(32)
+ .expireAfterWrite(10, TimeUnit.MINUTES)
+ .expireAfterAccess(1, TimeUnit.MINUTES)
+ .build(this::loadRegion);
+ private final LoadingCache chunkCache = Caffeine.newBuilder()
+ .executor(BlueMap.THREAD_POOL)
+ .softValues()
+ .maximumSize(10240) // 10 regions worth of chunks
+ .expireAfterWrite(10, TimeUnit.MINUTES)
+ .expireAfterAccess(1, TimeUnit.MINUTES)
+ .build(this::loadChunk);
+
+ public T getChunk(int x, int z) {
+ return getChunk(VECTOR_2_I_CACHE.get(x, z));
+ }
+
+ private T getChunk(Vector2i pos) {
+ return chunkCache.get(pos);
+ }
+
+ public Region getRegion(int x, int z) {
+ return getRegion(VECTOR_2_I_CACHE.get(x, z));
+ }
+
+ private Region getRegion(Vector2i pos) {
+ return regionCache.get(pos);
+ }
+
+ public void iterateChunks(int minX, int minZ, int maxX, int maxZ, ChunkConsumer chunkConsumer) {
+
+ }
+
+ public void preloadRegionChunks(int x, int z, Predicate chunkFilter) {
+ try {
+ getRegion(x, z).iterateAllChunks(new ChunkConsumer<>() {
+ @Override
+ public boolean filter(int chunkX, int chunkZ, int lastModified) {
+ Vector2i chunkPos = VECTOR_2_I_CACHE.get(chunkX, chunkZ);
+ return chunkFilter.test(chunkPos);
+ }
+
+ @Override
+ public void accept(int chunkX, int chunkZ, T chunk) {
+ Vector2i chunkPos = VECTOR_2_I_CACHE.get(chunkX, chunkZ);
+ chunkCache.put(chunkPos, chunk);
+ }
+ });
+ } catch (IOException ex) {
+ Logger.global.logDebug("Unexpected exception trying to load preload region (x:" + x + ", z:" + z + "): " + ex);
+ }
+ }
+
+ public Collection listRegions() {
+ if (!Files.exists(regionFolder)) return Collections.emptyList();
+ try (Stream stream = Files.list(regionFolder)) {
+ return stream
+ .map(file -> {
+ try {
+ if (Files.size(file) <= 0) return null;
+ return RegionType.regionForFileName(file.getFileName().toString());
+ } catch (IOException ex) {
+ Logger.global.logError("Failed to read region-file: " + file, ex);
+ return null;
+ }
+ })
+ .filter(Objects::nonNull)
+ .toList();
+ } catch (IOException ex) {
+ Logger.global.logError("Failed to list regions for folder: '" + regionFolder + "'", ex);
+ return List.of();
+ }
+ }
+
+ public WatchService createRegionWatchService() throws IOException {
+ return new MCAWorldRegionWatchService(this.regionFolder);
+ }
+
+ public void invalidateChunkCache() {
+ regionCache.invalidateAll();
+ chunkCache.invalidateAll();
+ }
+
+ public void invalidateChunkCache(int x, int z) {
+ regionCache.invalidate(VECTOR_2_I_CACHE.get(x >> 5, z >> 5));
+ chunkCache.invalidate(VECTOR_2_I_CACHE.get(x, z));
+ }
+
+ private Region loadRegion(Vector2i regionPos) {
+ return loadRegion(regionPos.getX(), regionPos.getY());
+ }
+
+ private Region loadRegion(int x, int z) {
+ return RegionType.loadRegion(chunkLoader, regionFolder, x, z);
+ }
+
+ private T loadChunk(Vector2i chunkPos) {
+ return loadChunk(chunkPos.getX(), chunkPos.getY());
+ }
+
+ private T loadChunk(int x, int z) {
+ final int tries = 3;
+ final int tryInterval = 1000;
+
+ Exception loadException = null;
+ for (int i = 0; i < tries; i++) {
+ try {
+ return getRegion(x >> 5, z >> 5)
+ .loadChunk(x, z);
+ } catch (IOException | RuntimeException e) {
+ if (loadException != null && loadException != e)
+ e.addSuppressed(loadException);
+
+ loadException = e;
+
+ if (i + 1 < tries) {
+ try {
+ Thread.sleep(tryInterval);
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ break;
+ }
+ }
+ }
+ }
+
+ Logger.global.logDebug("Unexpected exception trying to load chunk (x:" + x + ", z:" + z + "): " + loadException);
+ return chunkLoader.erroredChunk();
+ }
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkLoader.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkLoader.java
index 17e4b1055..19d36b765 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkLoader.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkLoader.java
@@ -34,4 +34,6 @@ public interface ChunkLoader {
T emptyChunk();
+ T erroredChunk();
+
}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java
index 09f0a71f4..608fb50ee 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java
@@ -66,8 +66,6 @@ public class MCAWorld implements World {
private static final Grid CHUNK_GRID = new Grid(16);
private static final Grid REGION_GRID = new Grid(32).multiply(CHUNK_GRID);
- private static final Vector2iCache VECTOR_2_I_CACHE = new Vector2iCache();
-
private final String id;
private final Path worldFolder;
private final Key dimension;
@@ -77,23 +75,8 @@ public class MCAWorld implements World {
private final DimensionType dimensionType;
private final Vector3i spawnPoint;
private final Path dimensionFolder;
- private final Path regionFolder;
- private final MCAChunkLoader chunkLoader = new MCAChunkLoader(this);
- private final LoadingCache> regionCache = Caffeine.newBuilder()
- .executor(BlueMap.THREAD_POOL)
- .softValues()
- .maximumSize(32)
- .expireAfterWrite(10, TimeUnit.MINUTES)
- .expireAfterAccess(1, TimeUnit.MINUTES)
- .build(this::loadRegion);
- private final LoadingCache chunkCache = Caffeine.newBuilder()
- .executor(BlueMap.THREAD_POOL)
- .softValues()
- .maximumSize(10240) // 10 regions worth of chunks
- .expireAfterWrite(10, TimeUnit.MINUTES)
- .expireAfterAccess(1, TimeUnit.MINUTES)
- .build(this::loadChunk);
+ private final ChunkGrid blockChunkGrid;
private MCAWorld(Path worldFolder, Key dimension, DataPack dataPack, LevelData levelData) {
this.id = World.id(worldFolder, dimension);
@@ -121,7 +104,9 @@ private MCAWorld(Path worldFolder, Key dimension, DataPack dataPack, LevelData l
levelData.getData().getSpawnZ()
);
this.dimensionFolder = resolveDimensionFolder(worldFolder, dimension);
- this.regionFolder = dimensionFolder.resolve("region");
+
+ this.blockChunkGrid = new ChunkGrid<>(new MCAChunkLoader(this), dimensionFolder.resolve("region"));
+
}
@Override
@@ -146,80 +131,37 @@ public Chunk getChunkAtBlock(int x, int z) {
@Override
public Chunk getChunk(int x, int z) {
- return getChunk(VECTOR_2_I_CACHE.get(x, z));
- }
-
- private Chunk getChunk(Vector2i pos) {
- return chunkCache.get(pos);
+ return blockChunkGrid.getChunk(x, z);
}
@Override
public Region getRegion(int x, int z) {
- return getRegion(VECTOR_2_I_CACHE.get(x, z));
- }
-
- private Region getRegion(Vector2i pos) {
- return regionCache.get(pos);
+ return blockChunkGrid.getRegion(x, z);
}
@Override
public Collection listRegions() {
- if (!Files.exists(regionFolder)) return Collections.emptyList();
- try (Stream stream = Files.list(regionFolder)) {
- return stream
- .map(file -> {
- try {
- if (Files.size(file) <= 0) return null;
- return RegionType.regionForFileName(file.getFileName().toString());
- } catch (IOException ex) {
- Logger.global.logError("Failed to read region-file: " + file, ex);
- return null;
- }
- })
- .filter(Objects::nonNull)
- .toList();
- } catch (IOException ex) {
- Logger.global.logError("Failed to list regions for world: '" + getId() + "'", ex);
- return List.of();
- }
+ return blockChunkGrid.listRegions();
}
@Override
public WatchService createRegionWatchService() throws IOException {
- return new MCAWorldRegionWatchService(this.regionFolder);
+ return blockChunkGrid.createRegionWatchService();
}
@Override
public void preloadRegionChunks(int x, int z, Predicate chunkFilter) {
- try {
- getRegion(x, z).iterateAllChunks(new ChunkConsumer<>() {
- @Override
- public boolean filter(int chunkX, int chunkZ, int lastModified) {
- Vector2i chunkPos = VECTOR_2_I_CACHE.get(chunkX, chunkZ);
- return chunkFilter.test(chunkPos);
- }
-
- @Override
- public void accept(int chunkX, int chunkZ, Chunk chunk) {
- Vector2i chunkPos = VECTOR_2_I_CACHE.get(chunkX, chunkZ);
- chunkCache.put(chunkPos, chunk);
- }
- });
- } catch (IOException ex) {
- Logger.global.logDebug("Unexpected exception trying to load preload region (x:" + x + ", z:" + z + "): " + ex);
- }
+ blockChunkGrid.preloadRegionChunks(x, z, chunkFilter);
}
@Override
public void invalidateChunkCache() {
- regionCache.invalidateAll();
- chunkCache.invalidateAll();
+ blockChunkGrid.invalidateChunkCache();
}
@Override
public void invalidateChunkCache(int x, int z) {
- regionCache.invalidate(VECTOR_2_I_CACHE.get(x >> 5, z >> 5));
- chunkCache.invalidate(VECTOR_2_I_CACHE.get(x, z));
+ blockChunkGrid.invalidateChunkCache(x, z);
}
@Override
@@ -227,48 +169,6 @@ public void iterateEntities(int minX, int minZ, int maxX, int maxZ, Consumer loadRegion(Vector2i regionPos) {
- return loadRegion(regionPos.getX(), regionPos.getY());
- }
-
- private Region loadRegion(int x, int z) {
- return RegionType.loadRegion(chunkLoader, getRegionFolder(), x, z);
- }
-
- private Chunk loadChunk(Vector2i chunkPos) {
- return loadChunk(chunkPos.getX(), chunkPos.getY());
- }
-
- private Chunk loadChunk(int x, int z) {
- final int tries = 3;
- final int tryInterval = 1000;
-
- Exception loadException = null;
- for (int i = 0; i < tries; i++) {
- try {
- return getRegion(x >> 5, z >> 5)
- .loadChunk(x, z);
- } catch (IOException | RuntimeException e) {
- if (loadException != null && loadException != e)
- e.addSuppressed(loadException);
-
- loadException = e;
-
- if (i + 1 < tries) {
- try {
- Thread.sleep(tryInterval);
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- break;
- }
- }
- }
- }
-
- Logger.global.logDebug("Unexpected exception trying to load chunk (x:" + x + ", z:" + z + "): " + loadException);
- return Chunk.ERRORED_CHUNK;
- }
-
public static MCAWorld load(Path worldFolder, Key dimension, DataPack dataPack) throws IOException, InterruptedException {
// load level.dat
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/MCAChunkLoader.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/MCAChunkLoader.java
index bb49d7a9a..44a41dce4 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/MCAChunkLoader.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/MCAChunkLoader.java
@@ -86,6 +86,11 @@ public Chunk emptyChunk() {
return Chunk.EMPTY_CHUNK;
}
+ @Override
+ public Chunk erroredChunk() {
+ return Chunk.ERRORED_CHUNK;
+ }
+
private @Nullable ChunkVersionLoader> findBestLoaderForVersion(int version) {
for (ChunkVersionLoader> loader : CHUNK_VERSION_LOADERS) {
if (loader.mightSupport(version)) return loader;
From d1a36e5816e1016cd01553e982f7621e05e6cfa0 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Sun, 19 Jan 2025 22:36:50 +0100
Subject: [PATCH 09/15] ChunkGrid improvements
---
.../bluemap/core/world/mca/ChunkGrid.java | 22 +++++++++++++------
.../bluemap/core/world/mca/MCAWorld.java | 7 ++----
2 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkGrid.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkGrid.java
index 0be1e8a09..60a7a2624 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkGrid.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkGrid.java
@@ -5,6 +5,7 @@
import com.github.benmanes.caffeine.cache.LoadingCache;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.logger.Logger;
+import de.bluecolored.bluemap.core.util.Grid;
import de.bluecolored.bluemap.core.util.Vector2iCache;
import de.bluecolored.bluemap.core.util.WatchService;
import de.bluecolored.bluemap.core.world.ChunkConsumer;
@@ -25,6 +26,9 @@
@RequiredArgsConstructor
public class ChunkGrid {
+ private static final Grid CHUNK_GRID = new Grid(16);
+ private static final Grid REGION_GRID = new Grid(32).multiply(CHUNK_GRID);
+
private static final Vector2iCache VECTOR_2_I_CACHE = new Vector2iCache();
private final ChunkLoader chunkLoader;
@@ -45,6 +49,14 @@ public class ChunkGrid {
.expireAfterAccess(1, TimeUnit.MINUTES)
.build(this::loadChunk);
+ public Grid getChunkGrid() {
+ return CHUNK_GRID;
+ }
+
+ public Grid getRegionGrid() {
+ return REGION_GRID;
+ }
+
public T getChunk(int x, int z) {
return getChunk(VECTOR_2_I_CACHE.get(x, z));
}
@@ -61,10 +73,6 @@ private Region getRegion(Vector2i pos) {
return regionCache.get(pos);
}
- public void iterateChunks(int minX, int minZ, int maxX, int maxZ, ChunkConsumer chunkConsumer) {
-
- }
-
public void preloadRegionChunks(int x, int z, Predicate chunkFilter) {
try {
getRegion(x, z).iterateAllChunks(new ChunkConsumer<>() {
@@ -81,7 +89,7 @@ public void accept(int chunkX, int chunkZ, T chunk) {
}
});
} catch (IOException ex) {
- Logger.global.logDebug("Unexpected exception trying to load preload region (x:" + x + ", z:" + z + "): " + ex);
+ Logger.global.logDebug("Unexpected exception trying to load preload region ('%s' -> x:%d, z:%d): %s".formatted(regionFolder, x, z, ex));
}
}
@@ -101,7 +109,7 @@ public Collection listRegions() {
.filter(Objects::nonNull)
.toList();
} catch (IOException ex) {
- Logger.global.logError("Failed to list regions for folder: '" + regionFolder + "'", ex);
+ Logger.global.logError("Failed to list regions from: '%s'".formatted(regionFolder), ex);
return List.of();
}
}
@@ -158,7 +166,7 @@ private T loadChunk(int x, int z) {
}
}
- Logger.global.logDebug("Unexpected exception trying to load chunk (x:" + x + ", z:" + z + "): " + loadException);
+ Logger.global.logDebug("Unexpected exception trying to load chunk ('%s' -> x:%d, z:%d): %s".formatted(regionFolder, x, z, loadException));
return chunkLoader.erroredChunk();
}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java
index 608fb50ee..29fc9919b 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java
@@ -63,9 +63,6 @@
@ToString
public class MCAWorld implements World {
- private static final Grid CHUNK_GRID = new Grid(16);
- private static final Grid REGION_GRID = new Grid(32).multiply(CHUNK_GRID);
-
private final String id;
private final Path worldFolder;
private final Key dimension;
@@ -116,12 +113,12 @@ public String getName() {
@Override
public Grid getChunkGrid() {
- return CHUNK_GRID;
+ return blockChunkGrid.getChunkGrid();
}
@Override
public Grid getRegionGrid() {
- return REGION_GRID;
+ return blockChunkGrid.getRegionGrid();
}
@Override
From 19d3c321dc47ddf649745bbc22625ece3e6d50dd Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 20 Jan 2025 15:27:34 +0100
Subject: [PATCH 10/15] Add entity ChunkGrid
---
.../core/map/hires/HiresModelRenderer.java | 7 ++-
.../map/hires/entity/EntityModelRenderer.java | 8 ++-
.../core/map/hires/entity/EntityRenderer.java | 5 +-
.../bluemap/core/world/mca/MCAUtil.java | 4 ++
.../bluemap/core/world/mca/MCAWorld.java | 27 +++++----
.../world/mca/data/Vector2fDeserializer.java | 8 +--
.../world/mca/data/Vector2iDeserializer.java | 56 +++++++++++++++++++
.../mca/entity/chunk/MCAEntityChunk.java | 25 +++++++++
.../entity/chunk/MCAEntityChunkLoader.java | 33 +++++++++++
implementations/fabric/build.gradle.kts | 5 +-
implementations/forge/build.gradle.kts | 5 +-
implementations/neoforge/build.gradle.kts | 5 +-
implementations/paper/build.gradle.kts | 3 -
implementations/spigot/build.gradle.kts | 3 -
implementations/sponge/build.gradle.kts | 3 -
15 files changed, 158 insertions(+), 39 deletions(-)
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2iDeserializer.java
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunk.java
create mode 100644 core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunkLoader.java
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelRenderer.java
index e082df072..a25a76e99 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelRenderer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelRenderer.java
@@ -125,7 +125,12 @@ public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel
world.iterateEntities(min.getX(), min.getZ(), max.getX(), max.getZ(), entity -> {
Vector3d pos = entity.getPos();
block.set(pos.getFloorX(), pos.getFloorY(), pos.getFloorZ());
- entityRenderer.render(entity, block, tileModelView);
+ entityRenderer.render(entity, block, tileModelView.initialize());
+ tileModelView.translate(
+ (float) pos.getX() - modelAnchor.getX(),
+ (float) pos.getY() - modelAnchor.getY(),
+ (float) pos.getZ() - modelAnchor.getZ()
+ );
});
}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityModelRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityModelRenderer.java
index 73efa4e16..344a91005 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityModelRenderer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityModelRenderer.java
@@ -23,12 +23,13 @@ public EntityModelRenderer(ResourcePack resourcePack, TextureGallery textureGall
}
public void render(Entity entity, BlockNeighborhood block, TileModelView tileModel) {
- int modelStart = tileModel.getStart();
-
EntityState stateResource = resourcePack.getEntityState(entity.getId());
if (stateResource == null) return;
Part[] parts = stateResource.getParts();
+ if (parts.length == 0) return;
+
+ int modelStart = tileModel.getStart();
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < parts.length; i++) {
@@ -38,6 +39,9 @@ public void render(Entity entity, BlockNeighborhood block, TileModelView tileMod
}
tileModel.initialize(modelStart);
+
+ // apply entity rotation
+ tileModel.rotate(entity.getRotation().getY(), entity.getRotation().getX(), 0f);
}
}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRenderer.java
index 931defd14..c42f9c222 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRenderer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRenderer.java
@@ -35,11 +35,10 @@
public interface EntityRenderer {
/**
- * Renders the given entities part into the given model, and sets the given blockColor to the
- * color that represents the rendered block.
+ * Renders the given entities part into the given model.
*
* Implementation Note:
- * This method is guaranteed to be called only on one thread per BlockRenderer instance, so you can use this
+ * This method is guaranteed to be called only on one thread per EntityRenderer instance, so you can use this
* for optimizations.
* Keep in mind this method will be called once for every block that is being rendered, so be very careful
* about performance and instance-creations.
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAUtil.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAUtil.java
index 4a680ea0e..42c00bfa9 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAUtil.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAUtil.java
@@ -24,6 +24,8 @@
*/
package de.bluecolored.bluemap.core.world.mca;
+import com.flowpowered.math.vector.Vector2f;
+import com.flowpowered.math.vector.Vector2i;
import com.flowpowered.math.vector.Vector3d;
import de.bluecolored.bluemap.core.util.Key;
import de.bluecolored.bluemap.core.world.BlockState;
@@ -51,6 +53,8 @@ public static BlueNBT addCommonNbtSettings(BlueNBT nbt) {
nbt.register(TypeToken.of(Key.class), new KeyDeserializer());
nbt.register(TypeToken.of(UUID.class), new UUIDDeserializer());
nbt.register(TypeToken.of(Vector3d.class), new Vector3dDeserializer());
+ nbt.register(TypeToken.of(Vector2i.class), new Vector2iDeserializer());
+ nbt.register(TypeToken.of(Vector2f.class), new Vector2fDeserializer());
nbt.register(TypeToken.of(BlockEntity.class), new BlockEntityTypeResolver());
nbt.register(TypeToken.of(SignBlockEntity.class), new SignBlockEntityTypeResolver());
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java
index 29fc9919b..d423adc81 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java
@@ -26,21 +26,18 @@
import com.flowpowered.math.vector.Vector2i;
import com.flowpowered.math.vector.Vector3i;
-import com.github.benmanes.caffeine.cache.Caffeine;
-import com.github.benmanes.caffeine.cache.LoadingCache;
-import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.resources.pack.datapack.DataPack;
import de.bluecolored.bluemap.core.storage.compression.Compression;
import de.bluecolored.bluemap.core.util.Grid;
import de.bluecolored.bluemap.core.util.Key;
-import de.bluecolored.bluemap.core.util.Vector2iCache;
import de.bluecolored.bluemap.core.util.WatchService;
import de.bluecolored.bluemap.core.world.*;
import de.bluecolored.bluemap.core.world.mca.chunk.MCAChunkLoader;
import de.bluecolored.bluemap.core.world.mca.data.DimensionTypeDeserializer;
import de.bluecolored.bluemap.core.world.mca.data.LevelData;
-import de.bluecolored.bluemap.core.world.mca.region.RegionType;
+import de.bluecolored.bluemap.core.world.mca.entity.chunk.MCAEntityChunk;
+import de.bluecolored.bluemap.core.world.mca.entity.chunk.MCAEntityChunkLoader;
import de.bluecolored.bluenbt.BlueNBT;
import de.bluecolored.bluenbt.TypeToken;
import lombok.Getter;
@@ -51,13 +48,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Predicate;
-import java.util.stream.Stream;
@Getter
@ToString
@@ -74,6 +66,7 @@ public class MCAWorld implements World {
private final Path dimensionFolder;
private final ChunkGrid blockChunkGrid;
+ private final ChunkGrid entityChunkGrid;
private MCAWorld(Path worldFolder, Key dimension, DataPack dataPack, LevelData levelData) {
this.id = World.id(worldFolder, dimension);
@@ -103,6 +96,7 @@ private MCAWorld(Path worldFolder, Key dimension, DataPack dataPack, LevelData l
this.dimensionFolder = resolveDimensionFolder(worldFolder, dimension);
this.blockChunkGrid = new ChunkGrid<>(new MCAChunkLoader(this), dimensionFolder.resolve("region"));
+ this.entityChunkGrid = new ChunkGrid<>(new MCAEntityChunkLoader(), dimensionFolder.resolve("entities"));
}
@@ -163,7 +157,18 @@ public void invalidateChunkCache(int x, int z) {
@Override
public void iterateEntities(int minX, int minZ, int maxX, int maxZ, Consumer entityConsumer) {
- //TODO
+ int minChunkX = minX >> 4, minChunkZ = minZ >> 4;
+ int maxChunkX = maxX >> 4, maxChunkZ = maxZ >> 4;
+
+ for (int x = minChunkX; x <= maxChunkX; x++) {
+ for (int z = minChunkZ; z <= maxChunkZ; z++) {
+ Entity[] entities = entityChunkGrid.getChunk(x, z).getEntities();
+ //noinspection ForLoopReplaceableByForEach
+ for (int i = 0; i < entities.length; i++) {
+ entityConsumer.accept(entities[i]);
+ }
+ }
+ }
}
public static MCAWorld load(Path worldFolder, Key dimension, DataPack dataPack) throws IOException, InterruptedException {
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2fDeserializer.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2fDeserializer.java
index 36375bef3..235493a87 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2fDeserializer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2fDeserializer.java
@@ -28,8 +28,8 @@ yield new Vector2f(
case LIST -> {
reader.beginList();
Vector2f value = new Vector2f(
- reader.nextDouble(),
- reader.nextDouble()
+ reader.nextFloat(),
+ reader.nextFloat()
);
reader.endList();
yield value;
@@ -40,8 +40,8 @@ yield new Vector2f(
reader.beginCompound();
while (reader.peek() != TagType.END) {
switch (reader.name()) {
- case "x", "yaw": x = reader.nextDouble(); break;
- case "y", "pitch": y = reader.nextDouble(); break;
+ case "x", "yaw": x = reader.nextFloat(); break;
+ case "y", "z", "pitch": y = reader.nextFloat(); break;
default: reader.skip();
}
}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2iDeserializer.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2iDeserializer.java
new file mode 100644
index 000000000..7cb0b1133
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2iDeserializer.java
@@ -0,0 +1,56 @@
+package de.bluecolored.bluemap.core.world.mca.data;
+
+import com.flowpowered.math.vector.Vector2i;
+import de.bluecolored.bluenbt.NBTReader;
+import de.bluecolored.bluenbt.TagType;
+import de.bluecolored.bluenbt.TypeDeserializer;
+
+import java.io.IOException;
+
+public class Vector2iDeserializer implements TypeDeserializer {
+
+ @Override
+ public Vector2i read(NBTReader reader) throws IOException {
+ TagType tag = reader.peek();
+
+ return switch (tag) {
+
+ case INT_ARRAY, LONG_ARRAY, BYTE_ARRAY -> {
+ long[] values = reader.nextArrayAsLongArray();
+ if (values.length != 2) throw new IllegalStateException("Unexpected array length: " + values.length);
+ yield new Vector2i(
+ values[0],
+ values[1]
+ );
+ }
+
+ case LIST -> {
+ reader.beginList();
+ Vector2i value = new Vector2i(
+ reader.nextDouble(),
+ reader.nextDouble()
+ );
+ reader.endList();
+ yield value;
+ }
+
+ case COMPOUND -> {
+ double x = 0, y = 0;
+ reader.beginCompound();
+ while (reader.peek() != TagType.END) {
+ switch (reader.name()) {
+ case "x": x = reader.nextDouble(); break;
+ case "y", "z": y = reader.nextDouble(); break;
+ default: reader.skip();
+ }
+ }
+ reader.endCompound();
+ yield new Vector2i(x, y);
+ }
+
+ case null, default -> throw new IllegalStateException("Unexpected tag-type: " + tag);
+
+ };
+ }
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunk.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunk.java
new file mode 100644
index 000000000..b299a8158
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunk.java
@@ -0,0 +1,25 @@
+package de.bluecolored.bluemap.core.world.mca.entity.chunk;
+
+import com.flowpowered.math.vector.Vector2i;
+import de.bluecolored.bluemap.core.world.Entity;
+import de.bluecolored.bluenbt.NBTName;
+import lombok.Getter;
+
+@Getter
+public class MCAEntityChunk {
+
+ private static final Entity[] EMPTY_ENTITIES = new Entity[0];
+
+ public static final MCAEntityChunk EMPTY_CHUNK = new MCAEntityChunk();
+ public static final MCAEntityChunk ERRORED_CHUNK = new MCAEntityChunk();
+
+ @NBTName("Entities")
+ public Entity[] entities = EMPTY_ENTITIES;
+
+ @NBTName("DataVersion")
+ public int dataVersion = -1;
+
+ @NBTName("Position")
+ public Vector2i position = Vector2i.ZERO;
+
+}
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunkLoader.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunkLoader.java
new file mode 100644
index 000000000..8377cd2c9
--- /dev/null
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunkLoader.java
@@ -0,0 +1,33 @@
+package de.bluecolored.bluemap.core.world.mca.entity.chunk;
+
+import de.bluecolored.bluemap.core.storage.compression.Compression;
+import de.bluecolored.bluemap.core.world.mca.ChunkLoader;
+import de.bluecolored.bluemap.core.world.mca.MCAUtil;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class MCAEntityChunkLoader implements ChunkLoader {
+
+ @Override
+ public MCAEntityChunk load(byte[] data, int offset, int length, Compression compression) throws IOException {
+ try (
+ InputStream in = new ByteArrayInputStream(data, offset, length);
+ InputStream decompressedIn = compression.decompress(in)
+ ) {
+ return MCAUtil.BLUENBT.read(decompressedIn, MCAEntityChunk.class);
+ }
+ }
+
+ @Override
+ public MCAEntityChunk emptyChunk() {
+ return MCAEntityChunk.EMPTY_CHUNK;
+ }
+
+ @Override
+ public MCAEntityChunk erroredChunk() {
+ return MCAEntityChunk.ERRORED_CHUNK;
+ }
+
+}
diff --git a/implementations/fabric/build.gradle.kts b/implementations/fabric/build.gradle.kts
index d7e833d1c..f3a6d6ed9 100644
--- a/implementations/fabric/build.gradle.kts
+++ b/implementations/fabric/build.gradle.kts
@@ -34,6 +34,7 @@ dependencies {
// jarInJar
include ( libs.flow.math )
+ include ( libs.bluenbt )
}
@@ -43,14 +44,12 @@ tasks.shadowJar {
// exclude jarInJar
dependencies {
exclude( dependency ( libs.flow.math.get() ) )
+ exclude( dependency ( libs.bluenbt.get() ) )
}
// airlift
relocate ("io.airlift", "de.bluecolored.shadow.airlift")
- // bluenbt
- relocate ("de.bluecolored.bluenbt", "de.bluecolored.shadow.bluenbt")
-
// caffeine
relocate ("com.github.benmanes.caffeine", "de.bluecolored.shadow.caffeine")
relocate ("org.checkerframework", "de.bluecolored.shadow.checkerframework")
diff --git a/implementations/forge/build.gradle.kts b/implementations/forge/build.gradle.kts
index 2aa25706e..cfe7bb2db 100644
--- a/implementations/forge/build.gradle.kts
+++ b/implementations/forge/build.gradle.kts
@@ -26,6 +26,7 @@ dependencies {
minecraft ( "net.minecraftforge", "forge", "$minecraftVersion-$forgeVersion" )
jarJar ( libs.flow.math.get().group, libs.flow.math.get().name , "[${libs.flow.math.get().version},)" )
+ jarJar ( libs.bluenbt.get().group, libs.bluenbt.get().name , "[${libs.bluenbt.get().version},)" )
}
@@ -40,14 +41,12 @@ tasks.shadowJar {
// exclude jarInJar
dependencies {
exclude( dependency ( libs.flow.math.get() ) )
+ exclude( dependency ( libs.bluenbt.get() ) )
}
// airlift
relocate ("io.airlift", "de.bluecolored.shadow.airlift")
- // bluenbt
- relocate ("de.bluecolored.bluenbt", "de.bluecolored.shadow.bluenbt")
-
// caffeine
relocate ("com.github.benmanes.caffeine", "de.bluecolored.shadow.caffeine")
relocate ("org.checkerframework", "de.bluecolored.shadow.checkerframework")
diff --git a/implementations/neoforge/build.gradle.kts b/implementations/neoforge/build.gradle.kts
index 8960713bb..3cba674ed 100644
--- a/implementations/neoforge/build.gradle.kts
+++ b/implementations/neoforge/build.gradle.kts
@@ -27,6 +27,7 @@ dependencies {
}
jarJar ( libs.flow.math.get().group, libs.flow.math.get().name , "[${libs.flow.math.get().version},)" )
+ jarJar ( libs.bluenbt.get().group, libs.bluenbt.get().name , "[${libs.bluenbt.get().version},)" )
}
tasks.shadowJar {
@@ -35,14 +36,12 @@ tasks.shadowJar {
// exclude jarInJar
dependencies {
exclude( dependency ( libs.flow.math.get() ) )
+ exclude( dependency ( libs.bluenbt.get() ) )
}
// airlift
relocate ("io.airlift", "de.bluecolored.shadow.airlift")
- // bluenbt
- relocate ("de.bluecolored.bluenbt", "de.bluecolored.shadow.bluenbt")
-
// caffeine
relocate ("com.github.benmanes.caffeine", "de.bluecolored.shadow.caffeine")
relocate ("org.checkerframework", "de.bluecolored.shadow.checkerframework")
diff --git a/implementations/paper/build.gradle.kts b/implementations/paper/build.gradle.kts
index 433ee8fc7..4f6b03c78 100644
--- a/implementations/paper/build.gradle.kts
+++ b/implementations/paper/build.gradle.kts
@@ -32,9 +32,6 @@ tasks.shadowJar {
// airlift
relocate ("io.airlift", "de.bluecolored.shadow.airlift")
- // bluenbt
- relocate ("de.bluecolored.bluenbt", "de.bluecolored.shadow.bluenbt")
-
// brigadier
relocate ("com.mojang.brigadier", "de.bluecolored.shadow.brigadier")
diff --git a/implementations/spigot/build.gradle.kts b/implementations/spigot/build.gradle.kts
index 028bb127a..828f1d4bb 100644
--- a/implementations/spigot/build.gradle.kts
+++ b/implementations/spigot/build.gradle.kts
@@ -28,9 +28,6 @@ tasks.shadowJar {
// brigadier
relocate ("com.mojang.brigadier", "de.bluecolored.shadow.brigadier")
- // bluenbt
- relocate ("de.bluecolored.bluenbt", "de.bluecolored.shadow.bluenbt")
-
// caffeine
relocate ("com.github.benmanes.caffeine", "de.bluecolored.shadow.caffeine")
relocate ("org.checkerframework", "de.bluecolored.shadow.checkerframework")
diff --git a/implementations/sponge/build.gradle.kts b/implementations/sponge/build.gradle.kts
index 641364bd7..dc54cdc47 100644
--- a/implementations/sponge/build.gradle.kts
+++ b/implementations/sponge/build.gradle.kts
@@ -48,9 +48,6 @@ tasks.shadowJar {
// brigadier
relocate ("com.mojang.brigadier", "de.bluecolored.shadow.brigadier")
- // bluenbt
- relocate ("de.bluecolored.bluenbt", "de.bluecolored.shadow.bluenbt")
-
// caffeine
relocate ("com.github.benmanes.caffeine", "de.bluecolored.shadow.caffeine")
relocate ("org.checkerframework", "de.bluecolored.shadow.checkerframework")
From 2367f4fecac1bfcf0e9c47c49120901264b683d4 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 20 Jan 2025 15:41:22 +0100
Subject: [PATCH 11/15] Improvements on world handling the entity chunk-grid
---
.../bluemap/core/world/mca/MCAWorld.java | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java
index d423adc81..3c5f318c5 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java
@@ -25,6 +25,7 @@
package de.bluecolored.bluemap.core.world.mca;
import com.flowpowered.math.vector.Vector2i;
+import com.flowpowered.math.vector.Vector3d;
import com.flowpowered.math.vector.Vector3i;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.resources.pack.datapack.DataPack;
@@ -143,16 +144,19 @@ public WatchService createRegionWatchService() throws IOException {
@Override
public void preloadRegionChunks(int x, int z, Predicate chunkFilter) {
blockChunkGrid.preloadRegionChunks(x, z, chunkFilter);
+ entityChunkGrid.preloadRegionChunks(x, z, chunkFilter);
}
@Override
public void invalidateChunkCache() {
blockChunkGrid.invalidateChunkCache();
+ entityChunkGrid.invalidateChunkCache();
}
@Override
public void invalidateChunkCache(int x, int z) {
blockChunkGrid.invalidateChunkCache(x, z);
+ entityChunkGrid.invalidateChunkCache(x, z);
}
@Override
@@ -165,7 +169,17 @@ public void iterateEntities(int minX, int minZ, int maxX, int maxZ, Consumer= minX && pX <= maxX &&
+ pZ >= minZ && pZ <= maxZ
+ ) {
+ entityConsumer.accept(entities[i]);
+ }
}
}
}
From 205f697434df9b695222d27e582e6a1e10099fa4 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 20 Jan 2025 15:42:34 +0100
Subject: [PATCH 12/15] Apply spotless fixes
---
.../map/hires/entity/EntityModelRenderer.java | 24 +++++++++++++++++++
.../pack/resourcepack/entitystate/Part.java | 24 +++++++++++++++++++
.../bluemap/core/world/BlockEntity.java | 24 +++++++++++++++++++
.../bluemap/core/world/Entity.java | 24 +++++++++++++++++++
.../bluemap/core/world/block/BlockAccess.java | 24 +++++++++++++++++++
.../bluemap/core/world/mca/ChunkGrid.java | 24 +++++++++++++++++++
.../mca/data/BlockEntityTypeResolver.java | 24 +++++++++++++++++++
.../world/mca/data/EntityTypeResolver.java | 24 +++++++++++++++++++
.../mca/data/SignBlockEntityTypeResolver.java | 24 +++++++++++++++++++
.../world/mca/data/Vector2fDeserializer.java | 24 +++++++++++++++++++
.../world/mca/data/Vector2iDeserializer.java | 24 +++++++++++++++++++
.../world/mca/data/Vector3dDeserializer.java | 24 +++++++++++++++++++
.../core/world/mca/entity/EntityType.java | 24 +++++++++++++++++++
.../core/world/mca/entity/MCAEntity.java | 24 +++++++++++++++++++
.../mca/entity/chunk/MCAEntityChunk.java | 24 +++++++++++++++++++
.../entity/chunk/MCAEntityChunkLoader.java | 24 +++++++++++++++++++
16 files changed, 384 insertions(+)
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityModelRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityModelRenderer.java
index 344a91005..ebcb9f80b 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityModelRenderer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityModelRenderer.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.map.hires.entity;
import com.github.benmanes.caffeine.cache.Caffeine;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/Part.java b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/Part.java
index 0ff7bd35a..4d4bb519a 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/Part.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/Part.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.resources.pack.resourcepack.entitystate;
import com.flowpowered.math.vector.Vector3f;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/BlockEntity.java b/core/src/main/java/de/bluecolored/bluemap/core/world/BlockEntity.java
index cb6ca9282..c81c18613 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/BlockEntity.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/BlockEntity.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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;
import de.bluecolored.bluemap.core.util.Key;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/Entity.java b/core/src/main/java/de/bluecolored/bluemap/core/world/Entity.java
index 949cf9b88..328d1c134 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/Entity.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/Entity.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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;
import com.flowpowered.math.vector.Vector2f;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/block/BlockAccess.java b/core/src/main/java/de/bluecolored/bluemap/core/world/block/BlockAccess.java
index 64969496d..c1217880b 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/block/BlockAccess.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/block/BlockAccess.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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;
import de.bluecolored.bluemap.core.world.BlockEntity;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkGrid.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkGrid.java
index 60a7a2624..2ea00bc96 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkGrid.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/ChunkGrid.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.mca;
import com.flowpowered.math.vector.Vector2i;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/BlockEntityTypeResolver.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/BlockEntityTypeResolver.java
index 685a6eb4e..2dd4786fa 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/BlockEntityTypeResolver.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/BlockEntityTypeResolver.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.mca.data;
import de.bluecolored.bluemap.core.logger.Logger;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/EntityTypeResolver.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/EntityTypeResolver.java
index fd9f32b26..c0fc492d8 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/EntityTypeResolver.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/EntityTypeResolver.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.mca.data;
import de.bluecolored.bluemap.core.logger.Logger;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/SignBlockEntityTypeResolver.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/SignBlockEntityTypeResolver.java
index b7fafbc23..22dd54839 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/SignBlockEntityTypeResolver.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/SignBlockEntityTypeResolver.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.mca.data;
import de.bluecolored.bluemap.core.world.mca.blockentity.SignBlockEntity;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2fDeserializer.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2fDeserializer.java
index 235493a87..d220f41ff 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2fDeserializer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2fDeserializer.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.mca.data;
import com.flowpowered.math.vector.Vector2f;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2iDeserializer.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2iDeserializer.java
index 7cb0b1133..c6790f49f 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2iDeserializer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector2iDeserializer.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.mca.data;
import com.flowpowered.math.vector.Vector2i;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector3dDeserializer.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector3dDeserializer.java
index 0d5bd883e..7eb32ee52 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector3dDeserializer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/data/Vector3dDeserializer.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.mca.data;
import com.flowpowered.math.vector.Vector3d;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/EntityType.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/EntityType.java
index 759ace4ae..9b871c26e 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/EntityType.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/EntityType.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.mca.entity;
import de.bluecolored.bluemap.core.util.Key;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/MCAEntity.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/MCAEntity.java
index d479fd2a1..26a6b52ca 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/MCAEntity.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/MCAEntity.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.mca.entity;
import com.flowpowered.math.vector.Vector2f;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunk.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunk.java
index b299a8158..46652ae4d 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunk.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunk.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.mca.entity.chunk;
import com.flowpowered.math.vector.Vector2i;
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunkLoader.java b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunkLoader.java
index 8377cd2c9..5ee1dde93 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunkLoader.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/world/mca/entity/chunk/MCAEntityChunkLoader.java
@@ -1,3 +1,27 @@
+/*
+ * This file is part of BlueMap, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) Blue (Lukas Rieger)
+ * 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.mca.entity.chunk;
import de.bluecolored.bluemap.core.storage.compression.Compression;
From 56346f9c79b49dde5cce467d777077a920800902 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 20 Jan 2025 19:55:36 +0100
Subject: [PATCH 13/15] Add cows
---
.../resourcepack/entitystate/EntityState.java | 8 --
.../assets/minecraft/entitystates/cow.json | 5 +
.../minecraft/models/entity/cow/cow.json | 135 ++++++++++++++++++
3 files changed, 140 insertions(+), 8 deletions(-)
create mode 100644 core/src/main/resourceExtensions/assets/minecraft/entitystates/cow.json
create mode 100644 core/src/main/resourceExtensions/assets/minecraft/models/entity/cow/cow.json
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/EntityState.java b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/EntityState.java
index e1cc37f0b..ac39df8b5 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/EntityState.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/entitystate/EntityState.java
@@ -24,15 +24,7 @@
*/
package de.bluecolored.bluemap.core.resources.pack.resourcepack.entitystate;
-import de.bluecolored.bluemap.core.resources.ResourcePath;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Multipart;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variant;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variants;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Model;
import lombok.Getter;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.function.Consumer;
@SuppressWarnings("FieldMayBeFinal")
@Getter
diff --git a/core/src/main/resourceExtensions/assets/minecraft/entitystates/cow.json b/core/src/main/resourceExtensions/assets/minecraft/entitystates/cow.json
new file mode 100644
index 000000000..3a1d4c92f
--- /dev/null
+++ b/core/src/main/resourceExtensions/assets/minecraft/entitystates/cow.json
@@ -0,0 +1,5 @@
+{
+ "parts": [
+ { "model": "minecraft:entity/cow/cow" }
+ ]
+}
\ No newline at end of file
diff --git a/core/src/main/resourceExtensions/assets/minecraft/models/entity/cow/cow.json b/core/src/main/resourceExtensions/assets/minecraft/models/entity/cow/cow.json
new file mode 100644
index 000000000..c64b83c7a
--- /dev/null
+++ b/core/src/main/resourceExtensions/assets/minecraft/models/entity/cow/cow.json
@@ -0,0 +1,135 @@
+{
+ "credit": "Made with Blockbench",
+ "texture_size": [64, 32],
+ "textures": {
+ "particle": "entity/cow/cow",
+ "body": "entity/cow/cow"
+ },
+ "elements": [
+ {
+ "name": "head",
+ "from": [-4, 16, -14],
+ "to": [4, 24, -8],
+ "rotation": {"angle": 0, "axis": "x", "origin": [2, 22, -14]},
+ "faces": {
+ "north": {"uv": [1.5, 3, 3.5, 7], "texture": "#body"},
+ "east": {"uv": [0, 3, 1.5, 7], "texture": "#body"},
+ "south": {"uv": [5, 3, 7, 7], "texture": "#body"},
+ "west": {"uv": [3.5, 3, 5, 7], "texture": "#body"},
+ "up": {"uv": [1.5, 0, 3.5, 3], "texture": "#body"},
+ "down": {"uv": [3.5, 0, 5.5, 3], "texture": "#body"}
+ }
+ },
+ {
+ "name": "body",
+ "from": [-6, 12, -8],
+ "to": [6, 22, 10],
+ "rotation": {"angle": 0, "axis": "y", "origin": [-6, 12, -8]},
+ "faces": {
+ "north": {"uv": [7, 2, 10, 7], "texture": "#body"},
+ "east": {"uv": [4.5, 7, 7, 16], "rotation": 90, "texture": "#body"},
+ "south": {"uv": [10, 2, 13, 7], "texture": "#body"},
+ "west": {"uv": [10, 7, 12.5, 16], "rotation": 270, "texture": "#body"},
+ "up": {"uv": [12.5, 7, 15.5, 16], "texture": "#body"},
+ "down": {"uv": [7, 7, 10, 16], "rotation": 180, "texture": "#body"}
+ }
+ },
+ {
+ "name": "horn_right",
+ "from": [4, 22, -12],
+ "to": [5, 25, -11],
+ "rotation": {"angle": 0, "axis": "y", "origin": [6, 22, -13]},
+ "faces": {
+ "north": {"uv": [6.25, 0.5, 6.5, 2], "texture": "#body"},
+ "east": {"uv": [6, 0.5, 6.25, 2], "texture": "#body"},
+ "south": {"uv": [5.75, 0.5, 6, 2], "texture": "#body"},
+ "west": {"uv": [5.5, 0.5, 5.75, 2], "texture": "#body"},
+ "up": {"uv": [5.75, 0, 6, 0.5], "texture": "#body"},
+ "down": {"uv": [6, 0, 6.25, 0.5], "texture": "#body"}
+ }
+ },
+ {
+ "name": "horn_left",
+ "from": [-5, 22, -12],
+ "to": [-4, 25, -11],
+ "rotation": {"angle": 0, "axis": "x", "origin": [-6, 22, -13]},
+ "faces": {
+ "north": {"uv": [6.5, 0.5, 6.25, 2], "texture": "#body"},
+ "east": {"uv": [5.75, 0.5, 5.5, 2], "texture": "#body"},
+ "south": {"uv": [6, 0.5, 5.75, 2], "texture": "#body"},
+ "west": {"uv": [6.25, 0.5, 6, 2], "texture": "#body"},
+ "up": {"uv": [6, 0, 5.75, 0.5], "texture": "#body"},
+ "down": {"uv": [6.25, 0, 6, 0.5], "texture": "#body"}
+ }
+ },
+ {
+ "name": "leg_front_right",
+ "from": [2, 0, -8],
+ "to": [6, 12, -4],
+ "rotation": {"angle": 0, "axis": "y", "origin": [4, 0, -6]},
+ "faces": {
+ "north": {"uv": [1, 10, 2, 16], "texture": "#body"},
+ "east": {"uv": [0, 10, 1, 16], "texture": "#body"},
+ "south": {"uv": [3, 10, 4, 16], "texture": "#body"},
+ "west": {"uv": [2, 10, 3, 16], "texture": "#body"},
+ "up": {"uv": [1, 8, 2, 10], "texture": "#body"},
+ "down": {"uv": [2, 8, 3, 10], "texture": "#body"}
+ }
+ },
+ {
+ "name": "leg_front_left",
+ "from": [-6, 0, -8],
+ "to": [-2, 12, -4],
+ "rotation": {"angle": 0, "axis": "y", "origin": [-4, 0, -6]},
+ "faces": {
+ "north": {"uv": [1, 10, 2, 16], "texture": "#body"},
+ "east": {"uv": [0, 10, 1, 16], "texture": "#body"},
+ "south": {"uv": [3, 10, 4, 16], "texture": "#body"},
+ "west": {"uv": [2, 10, 3, 16], "texture": "#body"},
+ "up": {"uv": [1, 8, 2, 10], "texture": "#body"},
+ "down": {"uv": [2, 8, 3, 10], "texture": "#body"}
+ }
+ },
+ {
+ "name": "leg_back_left",
+ "from": [-6, 0, 5],
+ "to": [-2, 12, 9],
+ "rotation": {"angle": 0, "axis": "y", "origin": [-4, 0, 7]},
+ "faces": {
+ "north": {"uv": [1, 10, 2, 16], "texture": "#body"},
+ "east": {"uv": [0, 10, 1, 16], "texture": "#body"},
+ "south": {"uv": [3, 10, 4, 16], "texture": "#body"},
+ "west": {"uv": [2, 10, 3, 16], "texture": "#body"},
+ "up": {"uv": [1, 8, 2, 10], "texture": "#body"},
+ "down": {"uv": [2, 8, 3, 10], "texture": "#body"}
+ }
+ },
+ {
+ "name": "leg_back_right",
+ "from": [2, 0, 5],
+ "to": [6, 12, 9],
+ "rotation": {"angle": 0, "axis": "y", "origin": [4, 0, 7]},
+ "faces": {
+ "north": {"uv": [1, 10, 2, 16], "texture": "#body"},
+ "east": {"uv": [0, 10, 1, 16], "texture": "#body"},
+ "south": {"uv": [3, 10, 4, 16], "texture": "#body"},
+ "west": {"uv": [2, 10, 3, 16], "texture": "#body"},
+ "up": {"uv": [1, 8, 2, 10], "texture": "#body"},
+ "down": {"uv": [2, 8, 3, 10], "texture": "#body"}
+ }
+ },
+ {
+ "name": "udder",
+ "from": [-2, 11, 4],
+ "to": [2, 12, 10],
+ "rotation": {"angle": 0, "axis": "y", "origin": [0, 11, 5]},
+ "faces": {
+ "north": {"uv": [13.25, 0, 14.25, 0.5], "texture": "#body"},
+ "east": {"uv": [14.25, 0.5, 14.5, 3.5], "rotation": 90, "texture": "#body"},
+ "south": {"uv": [14.25, 0, 15.25, 0.5], "texture": "#body"},
+ "west": {"uv": [13, 0.5, 13.25, 3.5], "rotation": 90, "texture": "#body"},
+ "down": {"uv": [13.25, 0.5, 14.25, 3.5], "texture": "#body"}
+ }
+ }
+ ]
+}
\ No newline at end of file
From bce0ba09b864ffe878b712d02cf297dc3de345e0 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Wed, 22 Jan 2025 14:02:21 +0100
Subject: [PATCH 14/15] Add abillity to tint and split off default-renderer
method for rendering a Model instead of Part
---
.../core/map/hires/entity/EntityRenderer.java | 3 -
.../hires/entity/ResourceModelRenderer.java | 65 ++++++++++---------
2 files changed, 33 insertions(+), 35 deletions(-)
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRenderer.java
index c42f9c222..b3adac7ea 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRenderer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/EntityRenderer.java
@@ -25,11 +25,8 @@
package de.bluecolored.bluemap.core.map.hires.entity;
import de.bluecolored.bluemap.core.map.hires.TileModelView;
-import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variant;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.entitystate.Part;
-import de.bluecolored.bluemap.core.util.math.Color;
import de.bluecolored.bluemap.core.world.Entity;
-import de.bluecolored.bluemap.core.world.block.BlockAccess;
import de.bluecolored.bluemap.core.world.block.BlockNeighborhood;
public interface EntityRenderer {
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/ResourceModelRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/ResourceModelRenderer.java
index 225954cff..97a71e5f6 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/ResourceModelRenderer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/ResourceModelRenderer.java
@@ -25,7 +25,6 @@
package de.bluecolored.bluemap.core.map.hires.entity;
import com.flowpowered.math.vector.Vector3f;
-import com.flowpowered.math.vector.Vector3i;
import com.flowpowered.math.vector.Vector4f;
import de.bluecolored.bluemap.core.map.TextureGallery;
import de.bluecolored.bluemap.core.map.hires.RenderSettings;
@@ -39,6 +38,7 @@
import de.bluecolored.bluemap.core.resources.pack.resourcepack.model.Model;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture;
import de.bluecolored.bluemap.core.util.Direction;
+import de.bluecolored.bluemap.core.util.math.Color;
import de.bluecolored.bluemap.core.util.math.MatrixM4f;
import de.bluecolored.bluemap.core.util.math.VectorM2f;
import de.bluecolored.bluemap.core.util.math.VectorM3f;
@@ -53,18 +53,19 @@
public class ResourceModelRenderer implements EntityRenderer {
private static final float SCALE = 1f / 16f;
- private final ResourcePack resourcePack;
- private final TextureGallery textureGallery;
- private final RenderSettings renderSettings;
+ final ResourcePack resourcePack;
+ final TextureGallery textureGallery;
+ final RenderSettings renderSettings;
private final VectorM3f[] corners = new VectorM3f[8];
private final VectorM2f[] rawUvs = new VectorM2f[4];
private final VectorM2f[] uvs = new VectorM2f[4];
+ private final Color tintColor = new Color();
- private Part part;
private Model modelResource;
private TileModelView tileModel;
private int sunLight, blockLight;
+ private TintColorProvider tintProvider;
@SuppressWarnings("unused")
public ResourceModelRenderer(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
@@ -78,9 +79,23 @@ public ResourceModelRenderer(ResourcePack resourcePack, TextureGallery textureGa
@Override
public void render(Entity entity, BlockNeighborhood block, Part part, TileModelView tileModel) {
- this.part = part;
+ render(
+ entity,
+ block,
+ part.getModel().getResource(resourcePack::getModel),
+ (index, color) -> color.set(1f, 1f, 1f, 1f, true),
+ tileModel
+ );
+
+ // apply transform
+ if (part.isTransformed())
+ tileModel.transform(part.getTransformMatrix());
+ }
+
+ void render(Entity entity, BlockNeighborhood block, Model model, TintColorProvider tintProvider, TileModelView tileModel) {
+ this.modelResource = model;
this.tileModel = tileModel;
- this.modelResource = part.getModel().getResource(resourcePack::getModel);
+ this.tintProvider = tintProvider;
// light calculation
LightData blockLightData = block.getLightData();
@@ -105,10 +120,6 @@ public void render(Entity entity, BlockNeighborhood block, Part part, TileModelV
this.tileModel.initialize(modelStart);
- // apply model-transform
- if (part.isTransformed())
- this.tileModel.transform(part.getTransformMatrix());
-
}
private final MatrixM4f modelElementTransform = new MatrixM4f();
@@ -152,25 +163,10 @@ private void buildModelElementResource(Element element, TileModelView blockModel
);
}
- private final VectorM3f faceRotationVector = new VectorM3f(0, 0, 0);
private void createElementFace(Element element, Direction faceDir, VectorM3f c0, VectorM3f c1, VectorM3f c2, VectorM3f c3) {
Face face = element.getFaces().get(faceDir);
if (face == null) return;
- Vector3i faceDirVector = faceDir.toVector();
-
- // calculate faceRotationVector
- faceRotationVector.set(
- faceDirVector.getX(),
- faceDirVector.getY(),
- faceDirVector.getZ()
- );
- faceRotationVector.rotateAndScale(element.getRotation().getMatrix());
- makeRotationRelative(faceRotationVector);
-
- // face culling
- if (renderSettings.isRenderTopOnly() && faceRotationVector.y < 0.01) return;
-
// initialize the faces
tileModel.initialize();
tileModel.add(2);
@@ -228,9 +224,15 @@ private void createElementFace(Element element, Direction faceDir, VectorM3f c0,
uvs[3].x, uvs[3].y
);
- // ####### color
- tileModel.setColor(face1, 1f, 1f, 1f);
- tileModel.setColor(face2, 1f, 1f, 1f);
+ // ####### face-tint
+ if (face.getTintindex() >= 0) {
+ tintProvider.setTintColor(face.getTintindex(), tintColor);
+ tileModel.setColor(face1, tintColor.r, tintColor.g, tintColor.b);
+ tileModel.setColor(face2, tintColor.r, tintColor.g, tintColor.b);
+ } else {
+ tileModel.setColor(face1, 1f, 1f, 1f);
+ tileModel.setColor(face2, 1f, 1f, 1f);
+ }
// ####### blocklight
int emissiveBlockLight = Math.max(blockLight, element.getLightEmission());
@@ -247,9 +249,8 @@ private void createElementFace(Element element, Direction faceDir, VectorM3f c0,
}
- private void makeRotationRelative(VectorM3f direction){
- if (part.isTransformed())
- direction.rotateAndScale(part.getTransformMatrix());
+ interface TintColorProvider {
+ void setTintColor(int tintIndex, Color target);
}
}
From 60d40e1bfd5fdf9f74dd47f36b0646d877dc1386 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Wed, 22 Jan 2025 14:31:42 +0100
Subject: [PATCH 15/15] Add static NO_TINT TintColorProvider function
---
.../bluemap/core/map/hires/entity/ResourceModelRenderer.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/ResourceModelRenderer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/ResourceModelRenderer.java
index 97a71e5f6..238a7203f 100644
--- a/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/ResourceModelRenderer.java
+++ b/core/src/main/java/de/bluecolored/bluemap/core/map/hires/entity/ResourceModelRenderer.java
@@ -83,7 +83,7 @@ public void render(Entity entity, BlockNeighborhood block, Part part, TileModelV
entity,
block,
part.getModel().getResource(resourcePack::getModel),
- (index, color) -> color.set(1f, 1f, 1f, 1f, true),
+ TintColorProvider.NO_TINT,
tileModel
);
@@ -250,6 +250,7 @@ private void createElementFace(Element element, Direction faceDir, VectorM3f c0,
}
interface TintColorProvider {
+ TintColorProvider NO_TINT = (index, color) -> color.set(1f, 1f, 1f, 1f, true);
void setTintColor(int tintIndex, Color target);
}