diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/MappingsConfigReader.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/MappingsConfigReader.java index eaf07c382..f1cde1759 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/mappings/MappingsConfigReader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/MappingsConfigReader.java @@ -23,15 +23,16 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.item.mappings; +package org.geysermc.geyser.registry.mappings; import com.fasterxml.jackson.databind.JsonNode; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.item.custom.CustomItemData; -import org.geysermc.geyser.item.mappings.versions.MappingsReader; -import org.geysermc.geyser.item.mappings.versions.MappingsReader_v1; +import org.geysermc.geyser.registry.mappings.versions.MappingsReader; +import org.geysermc.geyser.registry.mappings.versions.MappingsReader_v1; import java.io.IOException; import java.nio.file.Files; @@ -56,43 +57,86 @@ public class MappingsConfigReader { } } - public void loadMappingsFromJson(BiConsumer consumer) { - Path customMappingsDirectory = this.customMappingsDirectory; - if (!Files.exists(customMappingsDirectory)) { + public boolean ensureMappingsDirectory(Path mappingsDirectory) { + if (!Files.exists(mappingsDirectory)) { try { - Files.createDirectories(customMappingsDirectory); + Files.createDirectories(mappingsDirectory); + return true; } catch (IOException e) { - GeyserImpl.getInstance().getLogger().error("Failed to create custom mappings directory", e); - return; + GeyserImpl.getInstance().getLogger().error("Failed to create mappings directory", e); + return false; } } + return true; + } + + public void loadItemMappingsFromJson(BiConsumer consumer) { + if (!ensureMappingsDirectory(this.customMappingsDirectory)) { + return; + } Path[] mappingsFiles = this.getCustomMappingsFiles(); for (Path mappingsFile : mappingsFiles) { - this.readMappingsFromJson(mappingsFile, consumer); + this.readItemMappingsFromJson(mappingsFile, consumer); } } - public void readMappingsFromJson(Path file, BiConsumer consumer) { + public void loadBlockMappingsFromJson(BiConsumer consumer) { + if (!ensureMappingsDirectory(this.customMappingsDirectory)) { + return; + } + + Path[] mappingsFiles = this.getCustomMappingsFiles(); + for (Path mappingsFile : mappingsFiles) { + this.readBlockMappingsFromJson(mappingsFile, consumer); + } + } + + public JsonNode getMappingsRoot(Path file) { JsonNode mappingsRoot; try { mappingsRoot = GeyserImpl.JSON_MAPPER.readTree(file.toFile()); } catch (IOException e) { GeyserImpl.getInstance().getLogger().error("Failed to read custom mapping file: " + file, e); - return; + return null; } if (!mappingsRoot.has("format_version")) { GeyserImpl.getInstance().getLogger().error("Mappings file " + file + " is missing the format version field!"); - return; + return null; } - int formatVersion = mappingsRoot.get("format_version").asInt(); + return mappingsRoot; + } + + public int getFormatVersion(JsonNode mappingsRoot, Path file) { + int formatVersion = mappingsRoot.get("format_version").asInt(); if (!this.mappingReaders.containsKey(formatVersion)) { GeyserImpl.getInstance().getLogger().error("Mappings file " + file + " has an unknown format version: " + formatVersion); + return -1; + } + return formatVersion; + } + + public void readItemMappingsFromJson(Path file, BiConsumer consumer) { + JsonNode mappingsRoot = getMappingsRoot(file); + + int formatVersion = getFormatVersion(mappingsRoot, file); + if (formatVersion < 0) { return; } - this.mappingReaders.get(formatVersion).readMappings(file, mappingsRoot, consumer); + this.mappingReaders.get(formatVersion).readItemMappings(file, mappingsRoot, consumer); + } + + public void readBlockMappingsFromJson(Path file, BiConsumer consumer) { + JsonNode mappingsRoot = getMappingsRoot(file); + + int formatVersion = getFormatVersion(mappingsRoot, file); + if (formatVersion < 0) { + return; + } + + this.mappingReaders.get(formatVersion).readBlockMappings(file, mappingsRoot, consumer); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader.java index ef553f488..2d7d33228 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader.java @@ -23,9 +23,11 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.item.mappings.versions; +package org.geysermc.geyser.registry.mappings.versions; import com.fasterxml.jackson.databind.JsonNode; + +import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomRenderOffsets; import org.geysermc.geyser.item.exception.InvalidCustomMappingsFileException; @@ -34,9 +36,11 @@ import java.nio.file.Path; import java.util.function.BiConsumer; public abstract class MappingsReader { - public abstract void readMappings(Path file, JsonNode mappingsRoot, BiConsumer consumer); + public abstract void readItemMappings(Path file, JsonNode mappingsRoot, BiConsumer consumer); + public abstract void readBlockMappings(Path file, JsonNode mappingsRoot, BiConsumer consumer); public abstract CustomItemData readItemMappingEntry(JsonNode node) throws InvalidCustomMappingsFileException; + public abstract CustomBlockData readBlockMappingEntry(JsonNode node) throws InvalidCustomMappingsFileException; protected CustomRenderOffsets fromJsonNode(JsonNode node) { if (node == null || !node.isObject()) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java index 217ff844e..6f46c7f56 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java @@ -23,10 +23,11 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.item.mappings.versions; +package org.geysermc.geyser.registry.mappings.versions; import com.fasterxml.jackson.databind.JsonNode; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.item.exception.InvalidCustomMappingsFileException; @@ -36,11 +37,16 @@ import java.util.function.BiConsumer; public class MappingsReader_v1 extends MappingsReader { @Override - public void readMappings(Path file, JsonNode mappingsRoot, BiConsumer consumer) { - this.readItemMappings(file, mappingsRoot, consumer); + public void readItemMappings(Path file, JsonNode mappingsRoot, BiConsumer consumer) { + this.readItemMappingsV1(file, mappingsRoot, consumer); } - public void readItemMappings(Path file, JsonNode mappingsRoot, BiConsumer consumer) { + @Override + public void readBlockMappings(Path file, JsonNode mappingsRoot, BiConsumer consumer) { + this.readBlockMappingsV1(file, mappingsRoot, consumer); + } + + public void readItemMappingsV1(Path file, JsonNode mappingsRoot, BiConsumer consumer) { JsonNode itemsNode = mappingsRoot.get("items"); if (itemsNode != null && itemsNode.isObject()) { @@ -51,7 +57,26 @@ public class MappingsReader_v1 extends MappingsReader { CustomItemData customItemData = this.readItemMappingEntry(data); consumer.accept(entry.getKey(), customItemData); } catch (InvalidCustomMappingsFileException e) { - GeyserImpl.getInstance().getLogger().error("Error in custom mapping file: " + file.toString(), e); + GeyserImpl.getInstance().getLogger().error("Error in registering items for custom mapping file: " + file.toString(), e); + } + }); + } + }); + } + } + + public void readBlockMappingsV1(Path file, JsonNode mappingsRoot, BiConsumer consumer) { + JsonNode blocksNode = mappingsRoot.get("blocks"); + + if (blocksNode != null && blocksNode.isObject()) { + blocksNode.fields().forEachRemaining(entry -> { + if (entry.getValue().isObject()) { + entry.getValue().forEach(data -> { + try { + CustomBlockData customBlockData = this.readBlockMappingEntry(data); + consumer.accept(entry.getKey(), customBlockData); + } catch (InvalidCustomMappingsFileException e) { + GeyserImpl.getInstance().getLogger().error("Error in registering blocks for custom mapping file: " + file.toString(), e); } }); } @@ -120,4 +145,18 @@ public class MappingsReader_v1 extends MappingsReader { return customItemData.build(); } + + @Override + public CustomBlockData readBlockMappingEntry(JsonNode node) throws InvalidCustomMappingsFileException { + if (node == null || !node.isObject()) { + throw new InvalidCustomMappingsFileException("Invalid block mappings entry"); + } + + String name = node.get("name").asText(); + if (name == null || name.isEmpty()) { + throw new InvalidCustomMappingsFileException("A block entry has no name"); + } + + return null; + } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index ed9f08f36..bfb34bca4 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -25,6 +25,40 @@ package org.geysermc.geyser.registry.populator; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.GeyserBootstrap; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.block.custom.CustomBlockData; +import org.geysermc.geyser.api.item.custom.CustomItemData; +import org.geysermc.geyser.api.item.custom.CustomItemOptions; +import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; +import org.geysermc.geyser.event.type.GeyserDefineCustomItemsEventImpl; +import org.geysermc.geyser.inventory.item.StoredItemMappings; +import org.geysermc.geyser.item.GeyserCustomMappingData; +import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.mappings.MappingsConfigReader; +import org.geysermc.geyser.registry.type.BlockMappings; +import org.geysermc.geyser.registry.type.GeyserMappingItem; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.registry.type.NonVanillaItemRegistration; +import org.geysermc.geyser.registry.type.PaletteItem; +import org.geysermc.geyser.util.ItemUtils; +import org.geysermc.geyser.util.collection.FixedInt2IntMap; + import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.Multimap; @@ -37,37 +71,23 @@ import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; -import com.nukkitx.protocol.bedrock.v560.Bedrock_v560; -import it.unimi.dsi.fastutil.ints.*; -import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; -import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; +import com.nukkitx.protocol.bedrock.v560.Bedrock_v560; + import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; -import it.unimi.dsi.fastutil.objects.*; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.GeyserBootstrap; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.block.custom.CustomBlockData; -import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCustomItemsEvent; -import org.geysermc.geyser.api.item.custom.CustomItemData; -import org.geysermc.geyser.api.item.custom.CustomItemOptions; -import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData; -import org.geysermc.geyser.event.type.GeyserDefineCustomItemsEventImpl; -import org.geysermc.geyser.inventory.item.StoredItemMappings; -import org.geysermc.geyser.item.GeyserCustomMappingData; -import org.geysermc.geyser.item.mappings.MappingsConfigReader; -import org.geysermc.geyser.registry.BlockRegistries; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.*; -import org.geysermc.geyser.util.ItemUtils; -import org.geysermc.geyser.util.collection.FixedInt2IntMap; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.*; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntMaps; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectIntPair; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; /** * Populates the item registries. @@ -105,7 +125,7 @@ public class ItemRegistryPopulator { MappingsConfigReader mappingsConfigReader = new MappingsConfigReader(); if (customItemsAllowed) { // Load custom items from mappings files - mappingsConfigReader.loadMappingsFromJson((key, item) -> { + mappingsConfigReader.loadItemMappingsFromJson((key, item) -> { if (CustomItemRegistryPopulator.initialCheck(key, item, items)) { customItems.get(key).add(item); }