diff --git a/src/main/java/org/geysermc/rainbow/Rainbow.java b/src/main/java/org/geysermc/rainbow/Rainbow.java index 3ceb730..f0f4eba 100644 --- a/src/main/java/org/geysermc/rainbow/Rainbow.java +++ b/src/main/java/org/geysermc/rainbow/Rainbow.java @@ -34,4 +34,8 @@ public class Rainbow implements ClientModInitializer { public static ResourceLocation getModdedLocation(String path) { return ResourceLocation.fromNamespaceAndPath(MOD_ID, path); } + + public static String fileSafeResourceLocation(ResourceLocation location) { + return location.toString().replace(':', '.').replace('/', '_'); + } } diff --git a/src/main/java/org/geysermc/rainbow/mapping/BedrockItemMapper.java b/src/main/java/org/geysermc/rainbow/mapping/BedrockItemMapper.java index d37c43a..307b3b2 100644 --- a/src/main/java/org/geysermc/rainbow/mapping/BedrockItemMapper.java +++ b/src/main/java/org/geysermc/rainbow/mapping/BedrockItemMapper.java @@ -42,6 +42,7 @@ import org.geysermc.rainbow.mapping.attachable.AttachableMapper; import org.geysermc.rainbow.mapping.geometry.BedrockGeometryContext; import org.geysermc.rainbow.mapping.geometry.GeometryMapper; import org.geysermc.rainbow.mapping.geometry.GeometryRenderer; +import org.geysermc.rainbow.mapping.geyser.GeyserBaseDefinition; import org.geysermc.rainbow.mapping.geyser.GeyserMappings; import org.geysermc.rainbow.mapping.geyser.GeyserSingleDefinition; import org.geysermc.rainbow.mapping.geyser.predicate.GeyserConditionPredicate; @@ -78,14 +79,17 @@ public class BedrockItemMapper { } mapItem(model, displayName, protectionValue, stack.getComponentsPatch(), reporter, - mapping -> mappings.map(stack.getItemHolder(), mapping), packPath, itemConsumer, additionalTextureConsumer); + packPath, mapping -> mappings.map(stack.getItemHolder(), new GeyserSingleDefinition(mapping, Optional.of(model))), + itemConsumer, additionalTextureConsumer); } public static void mapItem(ResourceLocation modelLocation, String displayName, int protectionValue, DataComponentPatch componentPatch, ProblemReporter reporter, - Consumer mappingConsumer, Path packPath, BedrockItemConsumer itemConsumer, Consumer additionalTextureConsumer) { + Path packPath, Consumer mappingConsumer, BedrockItemConsumer itemConsumer, + Consumer additionalTextureConsumer) { ItemModel model = Minecraft.getInstance().getModelManager().getItemModel(modelLocation); - MappingContext context = new MappingContext(List.of(), modelLocation, displayName, protectionValue, componentPatch, - reporter.forChild(() -> "client item definition " + modelLocation + " "), mappingConsumer, itemConsumer, packPath, additionalTextureConsumer); + MappingContext context = new MappingContext(List.of(), displayName, protectionValue, componentPatch, + reporter.forChild(() -> "client item definition " + modelLocation + " "), + packPath, mappingConsumer, itemConsumer, additionalTextureConsumer); mapItem(model, context); } @@ -153,8 +157,8 @@ public class BedrockItemMapper { mapItem(onFalse, context.with(new GeyserConditionPredicate(predicateProperty, false), "condition on false ")); } + @SuppressWarnings("unchecked") private static void mapSelectModel(SelectItemModel model, MappingContext context) { - //noinspection unchecked SelectItemModelProperty property = ((SelectItemModelAccessor) model).getProperty(); Function dataConstructor = switch (property) { case Charge ignored -> chargeType -> new GeyserMatchPredicate.ChargeType((CrossbowItem.ChargeType) chargeType); @@ -165,7 +169,6 @@ public class BedrockItemMapper { default -> null; }; - //noinspection unchecked Object2ObjectMap cases = ((SelectItemModelCasesAccessor) model).rainbow$getCases(); if (dataConstructor == null) { @@ -186,24 +189,24 @@ public class BedrockItemMapper { mapItem(cases.defaultReturnValue(), context.child("select fallback case ")); } - private record MappingContext(List predicateStack, ResourceLocation model, String displayName, int protectionValue, DataComponentPatch componentPatch, ProblemReporter reporter, - Consumer mappingConsumer, BedrockItemConsumer itemConsumer, Path packPath, + private record MappingContext(List predicateStack, String displayName, int protectionValue, DataComponentPatch componentPatch, ProblemReporter reporter, + Path packPath, Consumer mappingConsumer, BedrockItemConsumer itemConsumer, Consumer additionalTextureConsumer) { public MappingContext with(GeyserPredicate predicate, String childName) { - return new MappingContext(Stream.concat(predicateStack.stream(), Stream.of(predicate)).toList(), model, displayName, protectionValue, componentPatch, - reporter.forChild(() -> childName), mappingConsumer, itemConsumer, packPath, additionalTextureConsumer); + return new MappingContext(Stream.concat(predicateStack.stream(), Stream.of(predicate)).toList(), displayName, protectionValue, componentPatch, + reporter.forChild(() -> childName), packPath, mappingConsumer, itemConsumer, additionalTextureConsumer); } public MappingContext child(String childName) { - return new MappingContext(predicateStack, model, displayName, protectionValue, componentPatch, reporter.forChild(() -> childName), - mappingConsumer, itemConsumer, packPath, additionalTextureConsumer); + return new MappingContext(predicateStack, displayName, protectionValue, componentPatch, reporter.forChild(() -> childName), + packPath, mappingConsumer, itemConsumer, additionalTextureConsumer); } public void create(ResourceLocation bedrockIdentifier, ResourceLocation texture, boolean displayHandheld, Optional customModel) { - GeyserSingleDefinition definition = new GeyserSingleDefinition(Optional.of(model), bedrockIdentifier, Optional.of(displayName), predicateStack, - new GeyserSingleDefinition.BedrockOptions(Optional.empty(), true, displayHandheld, protectionValue), componentPatch); + GeyserBaseDefinition definition = new GeyserBaseDefinition(bedrockIdentifier, Optional.of(displayName), predicateStack, + new GeyserBaseDefinition.BedrockOptions(Optional.empty(), true, displayHandheld, protectionValue), componentPatch); try { mappingConsumer.accept(definition); } catch (Exception exception) { @@ -221,7 +224,7 @@ public class BedrockItemMapper { boolean exportTexture = true; if (customModel.isPresent()) { ItemStack fakeItem = new ItemStack(Items.FLINT); - fakeItem.set(DataComponents.ITEM_MODEL, model); + //fakeItem.set(DataComponents.ITEM_MODEL, model); TODO texture = texture.withPath(path -> path + "_icon"); GeometryRenderer.render(fakeItem, packPath.resolve(BedrockTextures.TEXTURES_FOLDER + texture.getPath() + ".png")); diff --git a/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserBaseDefinition.java b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserBaseDefinition.java new file mode 100644 index 0000000..b74cbe8 --- /dev/null +++ b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserBaseDefinition.java @@ -0,0 +1,78 @@ +package org.geysermc.rainbow.mapping.geyser; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.component.DataComponents; +import net.minecraft.resources.ResourceLocation; +import org.geysermc.rainbow.Rainbow; +import org.geysermc.rainbow.mapping.geyser.predicate.GeyserPredicate; + +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +// TODO other keys, etc. +// TODO sometimes still includes components key when patch before filtering is not empty but after is +// TODO display name can be a component +public record GeyserBaseDefinition(ResourceLocation bedrockIdentifier, Optional displayName, + List predicates, BedrockOptions bedrockOptions, DataComponentPatch components) { + private static final List> SUPPORTED_COMPONENTS = List.of(DataComponents.CONSUMABLE, DataComponents.EQUIPPABLE, DataComponents.FOOD, + DataComponents.MAX_DAMAGE, DataComponents.MAX_STACK_SIZE, DataComponents.USE_COOLDOWN, DataComponents.ENCHANTABLE, DataComponents.ENCHANTMENT_GLINT_OVERRIDE); + + private static final Codec FILTERED_COMPONENT_MAP_CODEC = DataComponentPatch.CODEC.xmap(Function.identity(), patch -> { + DataComponentPatch.Builder filtered = DataComponentPatch.builder(); + patch.entrySet().stream() + .filter(entry -> entry.getValue().isEmpty() || SUPPORTED_COMPONENTS.contains(entry.getKey())) + .forEach(entry -> { + if (entry.getValue().isPresent()) { + filtered.set((DataComponentType) entry.getKey(), entry.getValue().orElseThrow()); + } else { + filtered.remove(entry.getKey()); + } + }); + return filtered.build(); + }); + + public static final MapCodec MAP_CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + ResourceLocation.CODEC.fieldOf("bedrock_identifier").forGetter(GeyserBaseDefinition::bedrockIdentifier), + Codec.STRING.optionalFieldOf("display_name").forGetter(GeyserBaseDefinition::displayName), + GeyserPredicate.LIST_CODEC.optionalFieldOf("predicate", List.of()).forGetter(GeyserBaseDefinition::predicates), + BedrockOptions.CODEC.optionalFieldOf("bedrock_options", BedrockOptions.DEFAULT).forGetter(GeyserBaseDefinition::bedrockOptions), + FILTERED_COMPONENT_MAP_CODEC.optionalFieldOf("components", DataComponentPatch.EMPTY).forGetter(GeyserBaseDefinition::components) + ).apply(instance, GeyserBaseDefinition::new) + ); + + public boolean conflictsWith(GeyserBaseDefinition other) { + if (predicates.size() == other.predicates.size()) { + boolean predicatesAreEqual = true; + for (GeyserPredicate predicate : predicates) { + if (!other.predicates.contains(predicate)) { + predicatesAreEqual = false; + break; + } + } + return predicatesAreEqual; + } + return false; + } + + public String textureName() { + return bedrockOptions.icon.orElse(Rainbow.fileSafeResourceLocation(bedrockIdentifier)); + } + + public record BedrockOptions(Optional icon, boolean allowOffhand, boolean displayHandheld, int protectionValue) { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group( + Codec.STRING.optionalFieldOf("icon").forGetter(BedrockOptions::icon), + Codec.BOOL.optionalFieldOf("allow_offhand", true).forGetter(BedrockOptions::allowOffhand), + Codec.BOOL.optionalFieldOf("display_handheld", false).forGetter(BedrockOptions::displayHandheld), + Codec.INT.optionalFieldOf("protection_value", 0).forGetter(BedrockOptions::protectionValue) + ).apply(instance, BedrockOptions::new) + ); + public static final BedrockOptions DEFAULT = new BedrockOptions(Optional.empty(), true, false, 0); + } +} diff --git a/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserGroupDefinition.java b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserGroupDefinition.java index 427d94b..3199f47 100644 --- a/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserGroupDefinition.java +++ b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserGroupDefinition.java @@ -21,16 +21,16 @@ public record GeyserGroupDefinition(Optional model, List model) { + return this.model.isPresent() && model.isPresent() && this.model.get().equals(model.get()); } - public boolean conflictsWith(Optional parentModel, GeyserSingleDefinition other) { + public boolean conflictsWith(Optional parentModel, GeyserItemDefinition other) { Optional thisModel = model.or(() -> parentModel); for (GeyserMapping definition : definitions) { if (definition instanceof GeyserGroupDefinition group && group.conflictsWith(thisModel, other)) { return true; - } else if (definition instanceof GeyserSingleDefinition single && single.conflictsWith(thisModel, other)) { + } else if (definition instanceof GeyserItemDefinition item && item.conflictsWith(thisModel, other)) { return true; } } diff --git a/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserItemDefinition.java b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserItemDefinition.java new file mode 100644 index 0000000..ee7ef16 --- /dev/null +++ b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserItemDefinition.java @@ -0,0 +1,12 @@ +package org.geysermc.rainbow.mapping.geyser; + +import net.minecraft.resources.ResourceLocation; + +import java.util.Optional; + +public interface GeyserItemDefinition extends GeyserMapping { + + GeyserBaseDefinition base(); + + boolean conflictsWith(Optional parentModel, GeyserItemDefinition other); +} diff --git a/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserLegacyDefinition.java b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserLegacyDefinition.java new file mode 100644 index 0000000..bff6ba8 --- /dev/null +++ b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserLegacyDefinition.java @@ -0,0 +1,31 @@ +package org.geysermc.rainbow.mapping.geyser; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.resources.ResourceLocation; + +import java.util.Optional; + +public record GeyserLegacyDefinition(GeyserBaseDefinition base, int customModelData) implements GeyserItemDefinition { + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + GeyserBaseDefinition.MAP_CODEC.forGetter(GeyserLegacyDefinition::base), + Codec.INT.fieldOf("custom_model_data").forGetter(GeyserLegacyDefinition::customModelData) + ).apply(instance, GeyserLegacyDefinition::new) + ); + + @Override + public boolean conflictsWith(Optional parentModel, GeyserItemDefinition other) { + if (other instanceof GeyserLegacyDefinition otherLegacy) { + return customModelData == otherLegacy.customModelData && base.conflictsWith(otherLegacy.base); + } + return false; + } + + @Override + public Type type() { + return Type.LEGACY; + } +} diff --git a/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserMapping.java b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserMapping.java index 56f606d..14c8ffc 100644 --- a/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserMapping.java +++ b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserMapping.java @@ -21,6 +21,7 @@ public interface GeyserMapping { enum Type implements StringRepresentable { SINGLE("definition", GeyserSingleDefinition.CODEC), + LEGACY("legacy", GeyserLegacyDefinition.CODEC), GROUP("group", GeyserGroupDefinition.CODEC); public static final Codec CODEC = StringRepresentable.fromEnum(Type::values); diff --git a/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserMappings.java b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserMappings.java index 064a3e9..96fb307 100644 --- a/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserMappings.java +++ b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserMappings.java @@ -36,8 +36,8 @@ public class GeyserMappings { } } - public void map(Holder item, GeyserSingleDefinition mapping) { - ResourceLocation model = mapping.model().orElseThrow(); + public void map(Holder item, GeyserItemDefinition mapping) { + Optional model = mapping instanceof GeyserSingleDefinition single ? Optional.of(single.model().orElseThrow()) : Optional.empty(); Optional modelGroup = Optional.empty(); Collection existingMappings = new ArrayList<>(mappings.get(item)); @@ -48,19 +48,22 @@ public class GeyserMappings { } modelGroup = Optional.of(existingGroup); break; - } else if (existing instanceof GeyserSingleDefinition single) { - if (single.conflictsWith(Optional.empty(), mapping)) { - throw new IllegalArgumentException("Mapping conflicts with existing single mapping"); - } else if (model.equals(single.model().orElseThrow())) { - mappings.remove(item, single); - modelGroup = Optional.of(new GeyserGroupDefinition(Optional.of(model), List.of(single.withoutModel()))); + } else if (existing instanceof GeyserItemDefinition itemDefinition) { + if (itemDefinition.conflictsWith(Optional.empty(), mapping)) { + throw new IllegalArgumentException("Mapping conflicts with existing item mapping"); + } else if (model.isPresent() && itemDefinition instanceof GeyserSingleDefinition single && model.get().equals(single.model().orElseThrow())) { + mappings.remove(item, itemDefinition); + modelGroup = Optional.of(new GeyserGroupDefinition(model, List.of(single.withoutModel()))); } } } if (modelGroup.isPresent()) { mappings.remove(item, modelGroup.get()); - mappings.put(item, modelGroup.get().with(mapping.withoutModel())); + + // We're only putting mappings in groups when they're single definitions - legacy mappings always go ungrouped + assert mapping instanceof GeyserSingleDefinition; + mappings.put(item, modelGroup.get().with(((GeyserSingleDefinition) mapping).withoutModel())); } else { mappings.put(item, mapping); } diff --git a/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserSingleDefinition.java b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserSingleDefinition.java index ae2da37..85f02ce 100644 --- a/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserSingleDefinition.java +++ b/src/main/java/org/geysermc/rainbow/mapping/geyser/GeyserSingleDefinition.java @@ -1,96 +1,35 @@ package org.geysermc.rainbow.mapping.geyser; -import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.core.component.DataComponentPatch; -import net.minecraft.core.component.DataComponentType; -import net.minecraft.core.component.DataComponents; import net.minecraft.resources.ResourceLocation; -import org.geysermc.rainbow.mapping.geyser.predicate.GeyserPredicate; -import java.util.List; import java.util.Optional; -import java.util.function.Function; - -// TODO other keys, etc. -// TODO sometimes still includes components key when patch before filtering is not empty but after is -// TODO display name can be a component -public record GeyserSingleDefinition(Optional model, ResourceLocation bedrockIdentifier, Optional displayName, - List predicates, BedrockOptions bedrockOptions, DataComponentPatch components) implements GeyserMapping { - private static final List> SUPPORTED_COMPONENTS = List.of(DataComponents.CONSUMABLE, DataComponents.EQUIPPABLE, DataComponents.FOOD, - DataComponents.MAX_DAMAGE, DataComponents.MAX_STACK_SIZE, DataComponents.USE_COOLDOWN, DataComponents.ENCHANTABLE, DataComponents.ENCHANTMENT_GLINT_OVERRIDE); - - private static final Codec FILTERED_COMPONENT_MAP_CODEC = DataComponentPatch.CODEC.xmap(Function.identity(), patch -> { - DataComponentPatch.Builder filtered = DataComponentPatch.builder(); - patch.entrySet().stream() - .filter(entry -> entry.getValue().isEmpty() || SUPPORTED_COMPONENTS.contains(entry.getKey())) - .forEach(entry -> { - if (entry.getValue().isPresent()) { - filtered.set((DataComponentType) entry.getKey(), entry.getValue().orElseThrow()); - } else { - filtered.remove(entry.getKey()); - } - }); - return filtered.build(); - }); +public record GeyserSingleDefinition(GeyserBaseDefinition base, Optional model) implements GeyserItemDefinition { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( - ResourceLocation.CODEC.optionalFieldOf("model").forGetter(GeyserSingleDefinition::model), - ResourceLocation.CODEC.fieldOf("bedrock_identifier").forGetter(GeyserSingleDefinition::bedrockIdentifier), - Codec.STRING.optionalFieldOf("display_name").forGetter(GeyserSingleDefinition::displayName), - GeyserPredicate.LIST_CODEC.optionalFieldOf("predicate", List.of()).forGetter(GeyserSingleDefinition::predicates), - BedrockOptions.CODEC.optionalFieldOf("bedrock_options", BedrockOptions.DEFAULT).forGetter(GeyserSingleDefinition::bedrockOptions), - FILTERED_COMPONENT_MAP_CODEC.optionalFieldOf("components", DataComponentPatch.EMPTY).forGetter(GeyserSingleDefinition::components) + GeyserBaseDefinition.MAP_CODEC.forGetter(GeyserSingleDefinition::base), + ResourceLocation.CODEC.optionalFieldOf("model").forGetter(GeyserSingleDefinition::model) ).apply(instance, GeyserSingleDefinition::new) ); - public String textureName() { - return bedrockOptions.icon.orElse(iconFromResourceLocation(bedrockIdentifier)); - } - - public boolean conflictsWith(Optional parentModel, GeyserSingleDefinition other) { - ResourceLocation thisModel = model.or(() -> parentModel).orElseThrow(); - ResourceLocation otherModel = other.model.or(() -> parentModel).orElseThrow(); - if (!thisModel.equals(otherModel)) { - return false; - } else if (predicates.size() == other.predicates.size()) { - boolean predicatesAreEqual = true; - for (GeyserPredicate predicate : predicates) { - if (!other.predicates.contains(predicate)) { - predicatesAreEqual = false; - break; - } - } - return predicatesAreEqual; + @Override + public boolean conflictsWith(Optional parentModel, GeyserItemDefinition other) { + if (other instanceof GeyserSingleDefinition otherSingle) { + ResourceLocation thisModel = model.or(() -> parentModel).orElseThrow(); + ResourceLocation otherModel = otherSingle.model.or(() -> parentModel).orElseThrow(); + return thisModel.equals(otherModel) && base.conflictsWith(other.base()); } return false; } public GeyserSingleDefinition withoutModel() { - return new GeyserSingleDefinition(Optional.empty(), bedrockIdentifier, displayName, predicates, bedrockOptions, components); + return new GeyserSingleDefinition(base, Optional.empty()); } @Override public Type type() { return Type.SINGLE; } - - public record BedrockOptions(Optional icon, boolean allowOffhand, boolean displayHandheld, int protectionValue) { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> - instance.group( - Codec.STRING.optionalFieldOf("icon").forGetter(BedrockOptions::icon), - Codec.BOOL.optionalFieldOf("allow_offhand", true).forGetter(BedrockOptions::allowOffhand), - Codec.BOOL.optionalFieldOf("display_handheld", false).forGetter(BedrockOptions::displayHandheld), - Codec.INT.optionalFieldOf("protection_value", 0).forGetter(BedrockOptions::protectionValue) - ).apply(instance, BedrockOptions::new) - ); - public static final BedrockOptions DEFAULT = new BedrockOptions(Optional.empty(), true, false, 0); - } - - // TODO this method is used in other places too now, maybe move it - public static String iconFromResourceLocation(ResourceLocation location) { - return location.toString().replace(':', '.').replace('/', '_'); - } } diff --git a/src/main/java/org/geysermc/rainbow/pack/BedrockItem.java b/src/main/java/org/geysermc/rainbow/pack/BedrockItem.java index 9a0e141..f2403cc 100644 --- a/src/main/java/org/geysermc/rainbow/pack/BedrockItem.java +++ b/src/main/java/org/geysermc/rainbow/pack/BedrockItem.java @@ -1,7 +1,7 @@ package org.geysermc.rainbow.pack; import net.minecraft.resources.ResourceLocation; -import org.geysermc.rainbow.mapping.geyser.GeyserSingleDefinition; +import org.geysermc.rainbow.Rainbow; import org.geysermc.rainbow.pack.animation.BedrockAnimation; import org.geysermc.rainbow.pack.attachable.BedrockAttachable; import org.geysermc.rainbow.pack.geometry.BedrockGeometry; @@ -21,7 +21,7 @@ public record BedrockItem(ResourceLocation identifier, String textureName, Resou geometry.get().save(geometryDirectory); } if (animation.isPresent()) { - animation.get().save(animationDirectory, GeyserSingleDefinition.iconFromResourceLocation(identifier)); + animation.get().save(animationDirectory, Rainbow.fileSafeResourceLocation(identifier)); } } } diff --git a/src/main/java/org/geysermc/rainbow/pack/attachable/BedrockAttachable.java b/src/main/java/org/geysermc/rainbow/pack/attachable/BedrockAttachable.java index 3dddea4..a6e8b25 100644 --- a/src/main/java/org/geysermc/rainbow/pack/attachable/BedrockAttachable.java +++ b/src/main/java/org/geysermc/rainbow/pack/attachable/BedrockAttachable.java @@ -11,7 +11,7 @@ import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.EquipmentSlot; import org.geysermc.rainbow.CodecUtil; import org.geysermc.rainbow.PackConstants; -import org.geysermc.rainbow.mapping.geyser.GeyserSingleDefinition; +import org.geysermc.rainbow.Rainbow; import org.geysermc.rainbow.pack.BedrockTextures; import org.geysermc.rainbow.pack.BedrockVersion; import org.geysermc.rainbow.pack.geometry.BedrockGeometry; @@ -37,7 +37,7 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf public void save(Path attachablesDirectory) throws IOException { // Get a safe attachable path by using Geyser's way of getting icons - CodecUtil.trySaveJson(CODEC, this, attachablesDirectory.resolve(GeyserSingleDefinition.iconFromResourceLocation(info.identifier) + ".json")); + CodecUtil.trySaveJson(CODEC, this, attachablesDirectory.resolve(Rainbow.fileSafeResourceLocation(info.identifier) + ".json")); } public static Builder builder(ResourceLocation identifier) {