diff --git a/src/main/java/org/geysermc/packgenerator/pack/attachable/BedrockAttachable.java b/src/main/java/org/geysermc/packgenerator/pack/attachable/BedrockAttachable.java index a548035..a394a05 100644 --- a/src/main/java/org/geysermc/packgenerator/pack/attachable/BedrockAttachable.java +++ b/src/main/java/org/geysermc/packgenerator/pack/attachable/BedrockAttachable.java @@ -1,8 +1,12 @@ package org.geysermc.packgenerator.pack.attachable; +import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.ExtraCodecs; import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.EquipmentSlot; import org.geysermc.packgenerator.CodecUtil; @@ -10,6 +14,7 @@ import org.geysermc.packgenerator.PackConstants; import org.geysermc.packgenerator.mapping.geyser.GeyserSingleDefinition; import org.geysermc.packgenerator.pack.BedrockTextures; import org.geysermc.packgenerator.pack.BedrockVersion; +import org.geysermc.packgenerator.pack.geometry.BedrockGeometry; import org.jetbrains.annotations.NotNull; import java.io.IOException; @@ -19,6 +24,8 @@ import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo info) { public static final Codec CODEC = RecordCodecBuilder.create(instance -> @@ -46,8 +53,8 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf default -> ""; }; return builder(identifier) - .withMaterial(DisplaySlot.DEFAULT, "armor") - .withMaterial(DisplaySlot.ENCHANTED, "armor_enchanted") + .withMaterial(DisplaySlot.DEFAULT, VanillaMaterials.ARMOR) + .withMaterial(DisplaySlot.ENCHANTED, VanillaMaterials.ARMOR_ENCHANTED) .withTexture(DisplaySlot.DEFAULT, texture) .withTexture(DisplaySlot.ENCHANTED, VanillaTextures.ENCHANTED_ACTOR_GLINT) .withGeometry(DisplaySlot.DEFAULT, VanillaGeometries.fromEquipmentSlot(slot)) @@ -56,13 +63,25 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf .build(); } + public static BedrockAttachable geometry(ResourceLocation identifier, BedrockGeometry.GeometryDefinition geometry, String texture) { + // TODO animations to make it look right + return builder(identifier) + .withMaterial(DisplaySlot.DEFAULT, VanillaMaterials.ENTITY) + .withMaterial(DisplaySlot.ENCHANTED, VanillaMaterials.ENTITY_ALPHATEST_GLINT) + .withTexture(DisplaySlot.DEFAULT, texture) + .withTexture(DisplaySlot.ENCHANTED, VanillaTextures.ENCHANTED_ITEM_GLINT) + .withGeometry(DisplaySlot.DEFAULT, geometry.info().identifier()) + .withRenderController(VanillaRenderControllers.ITEM_DEFAULT) + .build(); + } + public static class Builder { private final ResourceLocation identifier; private final EnumMap materials = new EnumMap<>(DisplaySlot.class); private final EnumMap textures = new EnumMap<>(DisplaySlot.class); private final EnumMap geometries = new EnumMap<>(DisplaySlot.class); private final Map animations = new HashMap<>(); - private final Map scripts = new HashMap<>(); + private final Map> scripts = new HashMap<>(); private final List renderControllers = new ArrayList<>(); public Builder(ResourceLocation identifier) { @@ -89,11 +108,19 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf return this; } - public Builder withScript(String key, String script) { - scripts.put(key, script); + public Builder withScript(String key, Script script) { + scripts.merge(key, List.of(script), (scripts, newScript) -> Stream.concat(scripts.stream(), newScript.stream()).toList()); return this; } + public Builder withScript(String key, String script, String condition) { + return withScript(key, new Script(script, Optional.of(condition))); + } + + public Builder withScript(String key, String script) { + return withScript(key, new Script(script, Optional.empty())); + } + public Builder withRenderController(String controller) { renderControllers.add(controller); return this; @@ -101,7 +128,8 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf public BedrockAttachable build() { return new BedrockAttachable(PackConstants.ENGINE_VERSION, - new AttachableInfo(identifier, verifyDefault(materials), verifyDefault(textures), verifyDefault(geometries), Map.copyOf(animations), Map.copyOf(scripts), List.copyOf(renderControllers))); + new AttachableInfo(identifier, verifyDefault(materials), verifyDefault(textures), verifyDefault(geometries), Map.copyOf(animations), + new Scripts(Map.copyOf(scripts)), List.copyOf(renderControllers))); } private static DisplayMap verifyDefault(EnumMap map) { @@ -113,7 +141,7 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf } public record AttachableInfo(ResourceLocation identifier, DisplayMap materials, DisplayMap textures, - DisplayMap geometry, Map animations, Map scripts, + DisplayMap geometry, Map animations, Scripts scripts, List renderControllers) { private static final Codec> STRING_MAP_CODEC = Codec.unboundedMap(Codec.STRING, Codec.STRING); public static final Codec CODEC = RecordCodecBuilder.create(instance -> @@ -123,7 +151,7 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf DisplayMap.CODEC.fieldOf("textures").forGetter(AttachableInfo::textures), DisplayMap.CODEC.fieldOf("geometry").forGetter(AttachableInfo::geometry), STRING_MAP_CODEC.optionalFieldOf("animations", Map.of()).forGetter(AttachableInfo::animations), - STRING_MAP_CODEC.optionalFieldOf("scripts", Map.of()).forGetter(AttachableInfo::scripts), + Scripts.CODEC.optionalFieldOf("scripts", Scripts.EMPTY).forGetter(AttachableInfo::scripts), Codec.STRING.listOf().optionalFieldOf("render_controllers", List.of()).forGetter(AttachableInfo::renderControllers) ).apply(instance, AttachableInfo::new) ); @@ -151,4 +179,40 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf return name; } } + + public record Scripts(Map> scripts) { + public static final Codec CODEC = Codec.unboundedMap(Codec.STRING, ExtraCodecs.compactListCodec(Script.CODEC)).xmap(Scripts::new, Scripts::scripts); + public static final Scripts EMPTY = new Scripts(Map.of()); + } + + public record Script(String script, Optional condition) { + private static final Codec