diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/components/DataComponentReader.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/DataComponentReader.java index 4113093d5..1baab1548 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/mappings/components/DataComponentReader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/DataComponentReader.java @@ -46,4 +46,10 @@ public abstract class DataComponentReader { // TODO primitives?? return type.getDataComponentFactory().create(type, readDataComponent(node)); } + + protected static void requireObject(JsonNode node) throws InvalidCustomMappingsFileException { + if (!node.isObject()) { + throw new InvalidCustomMappingsFileException("Expected an object"); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/components/DataComponentReaders.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/DataComponentReaders.java index 560b4480b..5ec00708f 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/mappings/components/DataComponentReaders.java +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/DataComponentReaders.java @@ -30,7 +30,12 @@ import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.item.exception.InvalidCustomMappingsFileException; import org.geysermc.geyser.registry.mappings.components.readers.ConsumableReader; +import org.geysermc.geyser.registry.mappings.components.readers.EquippableReader; +import org.geysermc.geyser.registry.mappings.components.readers.FoodReader; +import org.geysermc.geyser.registry.mappings.components.readers.IntComponentReader; +import org.geysermc.geyser.registry.mappings.components.readers.UseCooldownReader; import org.geysermc.geyser.util.MinecraftKey; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import java.util.HashMap; @@ -49,5 +54,10 @@ public class DataComponentReaders { static { READERS.put(MinecraftKey.key("consumable"), new ConsumableReader()); + READERS.put(MinecraftKey.key("equippable"), new EquippableReader()); + READERS.put(MinecraftKey.key("food"), new FoodReader()); + READERS.put(MinecraftKey.key("max_damage"), new IntComponentReader(DataComponentType.MAX_DAMAGE, 0)); + READERS.put(MinecraftKey.key("max_stack_size"), new IntComponentReader(DataComponentType.MAX_STACK_SIZE, 0, 99)); + READERS.put(MinecraftKey.key("use_cooldown"), new UseCooldownReader()); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/ConsumableReader.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/ConsumableReader.java index 8a3ff9a6c..2b2ce1440 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/ConsumableReader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/ConsumableReader.java @@ -43,10 +43,7 @@ public class ConsumableReader extends DataComponentReader { @Override protected Consumable readDataComponent(@NonNull JsonNode node) throws InvalidCustomMappingsFileException { - if (!node.isObject()) { - throw new InvalidCustomMappingsFileException("Expected consumable component to be an object"); - } - + requireObject(node); float consumeSeconds = 1.6F; if (node.has("consume_seconds")) { consumeSeconds = (float) node.get("consume_seconds").asDouble(); @@ -57,6 +54,6 @@ public class ConsumableReader extends DataComponentReader { animation = Consumable.ItemUseAnimation.valueOf(node.get("animation").asText().toUpperCase()); // TODO maybe not rely on the enum } - return new Consumable(consumeSeconds, animation, BuiltinSound.ENTITY_GENERIC_EAT, false, List.of()); // TODO + return new Consumable(consumeSeconds, animation, BuiltinSound.ENTITY_GENERIC_EAT, false, List.of()); // TODO are sound and particles supported on bedrock? } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/EquippableReader.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/EquippableReader.java new file mode 100644 index 000000000..8c5e1d6c3 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/EquippableReader.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.registry.mappings.components.readers; + +import com.fasterxml.jackson.databind.JsonNode; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.exception.InvalidCustomMappingsFileException; +import org.geysermc.geyser.registry.mappings.components.DataComponentReader; +import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.Equippable; +import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound; + +public class EquippableReader extends DataComponentReader { + + public EquippableReader() { + super(DataComponentType.EQUIPPABLE); + } + + @Override + protected Equippable readDataComponent(@NonNull JsonNode node) throws InvalidCustomMappingsFileException { + requireObject(node); + + JsonNode slot = node.get("slot"); + if (slot == null || !slot.isTextual()) { + throw new InvalidCustomMappingsFileException("Expected slot to be helmet, chestplate, leggings or boots"); + } + + return new Equippable(EquipmentSlot.valueOf(slot.asText().toUpperCase()), BuiltinSound.ITEM_ARMOR_EQUIP_GENERIC, + null, null, null, false, false, false); // Other properties are unused + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/FoodReader.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/FoodReader.java new file mode 100644 index 000000000..011c0210e --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/FoodReader.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.registry.mappings.components.readers; + +import com.fasterxml.jackson.databind.JsonNode; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.exception.InvalidCustomMappingsFileException; +import org.geysermc.geyser.registry.mappings.components.DataComponentReader; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.FoodProperties; + +public class FoodReader extends DataComponentReader { + + public FoodReader() { + super(DataComponentType.FOOD); + } + + @Override + protected FoodProperties readDataComponent(@NonNull JsonNode node) throws InvalidCustomMappingsFileException { + requireObject(node); + + JsonNode canAlwaysEat = node.get("can_always_eat"); + return new FoodProperties(0, 0, canAlwaysEat != null && canAlwaysEat.asBoolean()); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/IntComponentReader.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/IntComponentReader.java new file mode 100644 index 000000000..1d54e3314 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/IntComponentReader.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.registry.mappings.components.readers; + +import com.fasterxml.jackson.databind.JsonNode; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.exception.InvalidCustomMappingsFileException; +import org.geysermc.geyser.registry.mappings.components.DataComponentReader; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; + +public class IntComponentReader extends DataComponentReader { + private final int minimum; + private final int maximum; + + public IntComponentReader(DataComponentType type, int minimum, int maximum) { + super(type); + this.minimum = minimum; + this.maximum = maximum; + } + + public IntComponentReader(DataComponentType type, int minimum) { + this(type, minimum, Integer.MAX_VALUE); + } + + @Override + protected Integer readDataComponent(@NonNull JsonNode node) throws InvalidCustomMappingsFileException { + if (!node.isIntegralNumber()) { + throw new InvalidCustomMappingsFileException("Expected an integer number"); + } + int value = node.asInt(); + if (value < minimum || value > maximum) { + throw new InvalidCustomMappingsFileException("Expected integer to be in the range of [" + minimum + ", " + maximum + "]"); + } + return value; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/UseCooldownReader.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/UseCooldownReader.java new file mode 100644 index 000000000..583bddfc0 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/components/readers/UseCooldownReader.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.registry.mappings.components.readers; + +import com.fasterxml.jackson.databind.JsonNode; +import net.kyori.adventure.key.Key; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.item.exception.InvalidCustomMappingsFileException; +import org.geysermc.geyser.registry.mappings.components.DataComponentReader; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.UseCooldown; + +public class UseCooldownReader extends DataComponentReader { + + public UseCooldownReader() { + super(DataComponentType.USE_COOLDOWN); + } + + @Override + protected UseCooldown readDataComponent(@NonNull JsonNode node) throws InvalidCustomMappingsFileException { + requireObject(node); + + JsonNode seconds = node.get("seconds"); + JsonNode cooldown_group = node.get("cooldown_group"); + + if (seconds == null || !seconds.isNumber()) { + throw new InvalidCustomMappingsFileException("Expected seconds to be a number"); + } + + if (cooldown_group == null || !cooldown_group.isTextual()) { + throw new InvalidCustomMappingsFileException("Expected cooldown group to be a resource location"); + } + + return new UseCooldown((float) seconds.asDouble(), Key.key(cooldown_group.asText())); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator_v2.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator_v2.java index c5f690f2a..a6c0dbc32 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator_v2.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator_v2.java @@ -69,7 +69,6 @@ public class CustomItemRegistryPopulator_v2 { // Load custom items from mappings files mappingsConfigReader.loadItemMappingsFromJson((id, item) -> { if (initialCheck(item, items)) { - System.out.println("read item " + id + " item " + item); customItems.get(id).add(item); } });