diff --git a/src/main/java/org/geysermc/packgenerator/mapping/BedrockItemConsumer.java b/src/main/java/org/geysermc/packgenerator/mapping/BedrockItemConsumer.java new file mode 100644 index 0000000..746b441 --- /dev/null +++ b/src/main/java/org/geysermc/packgenerator/mapping/BedrockItemConsumer.java @@ -0,0 +1,9 @@ +package org.geysermc.packgenerator.mapping; + +import org.geysermc.packgenerator.pack.BedrockItem; + +@FunctionalInterface +public interface BedrockItemConsumer { + + void accept(BedrockItem item); +} diff --git a/src/main/java/org/geysermc/packgenerator/mapping/geyser/GeyserItemMapper.java b/src/main/java/org/geysermc/packgenerator/mapping/BedrockItemMapper.java similarity index 78% rename from src/main/java/org/geysermc/packgenerator/mapping/geyser/GeyserItemMapper.java rename to src/main/java/org/geysermc/packgenerator/mapping/BedrockItemMapper.java index 62322de..9625cea 100644 --- a/src/main/java/org/geysermc/packgenerator/mapping/geyser/GeyserItemMapper.java +++ b/src/main/java/org/geysermc/packgenerator/mapping/BedrockItemMapper.java @@ -1,7 +1,8 @@ -package org.geysermc.packgenerator.mapping.geyser; +package org.geysermc.packgenerator.mapping; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.SimpleUnbakedGeometry; import net.minecraft.client.renderer.item.BlockModelWrapper; import net.minecraft.client.renderer.item.ConditionalItemModel; import net.minecraft.client.renderer.item.ItemModel; @@ -28,27 +29,32 @@ import net.minecraft.world.level.Level; import org.geysermc.packgenerator.accessor.BlockModelWrapperLocationAccessor; import org.geysermc.packgenerator.accessor.ResolvedModelAccessor; import org.geysermc.packgenerator.accessor.SelectItemModelCasesAccessor; +import org.geysermc.packgenerator.mapping.attachable.AttachableMapper; +import org.geysermc.packgenerator.mapping.geometry.GeometryMapper; +import org.geysermc.packgenerator.mapping.geyser.GeyserSingleDefinition; import org.geysermc.packgenerator.mapping.geyser.predicate.GeyserConditionPredicate; import org.geysermc.packgenerator.mapping.geyser.predicate.GeyserMatchPredicate; import org.geysermc.packgenerator.mapping.geyser.predicate.GeyserPredicate; import org.geysermc.packgenerator.mixin.ConditionalItemModelAccessor; import org.geysermc.packgenerator.mixin.SelectItemModelAccessor; +import org.geysermc.packgenerator.pack.BedrockItem; import java.util.List; import java.util.Optional; -import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Stream; -public class GeyserItemMapper { +public class BedrockItemMapper { private static final List HANDHELD_MODELS = Stream.of("item/handheld", "item/handheld_rod", "item/handheld_mace") .map(ResourceLocation::withDefaultNamespace) .toList(); public static void mapItem(ResourceLocation modelLocation, String displayName, int protectionValue, DataComponentPatch componentPatch, ProblemReporter reporter, - BiConsumer mappingTextureConsumer) { + 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 + " "), mappingTextureConsumer); + MappingContext context = new MappingContext(List.of(), modelLocation, displayName, protectionValue, componentPatch, + reporter.forChild(() -> "client item definition " + modelLocation + " "), mappingConsumer, itemConsumer, additionalTextureConsumer); mapItem(model, context); } @@ -73,10 +79,13 @@ public class GeyserItemMapper { ResourceLocation texture = itemModelLocation; Material layer0Texture = itemModel.getTopTextureSlots().getMaterial("layer0"); + Optional customGeometry = Optional.empty(); if (layer0Texture != null) { texture = layer0Texture.texture(); + } else { + customGeometry = Optional.of((SimpleUnbakedGeometry) itemModel.getTopGeometry()); } - context.create(bedrockIdentifier, texture, handheld); + context.create(bedrockIdentifier, texture, handheld, customGeometry); }, () -> context.reporter.report(() -> "missing block model " + itemModelLocation)); } case ConditionalItemModel conditional -> mapConditionalModel(conditional, context.child("condition " + conditional + " ")); @@ -131,20 +140,31 @@ public class GeyserItemMapper { } private record MappingContext(List predicateStack, ResourceLocation model, String displayName, int protectionValue, DataComponentPatch componentPatch, ProblemReporter reporter, - BiConsumer mappingTextureConsumer) { + 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), mappingTextureConsumer); + reporter.forChild(() -> childName), mappingConsumer, itemConsumer, additionalTextureConsumer); } public MappingContext child(String childName) { - return new MappingContext(predicateStack, model, displayName, protectionValue, componentPatch, reporter.forChild(() -> childName), mappingTextureConsumer); + return new MappingContext(predicateStack, model, displayName, protectionValue, componentPatch, reporter.forChild(() -> childName), mappingConsumer, itemConsumer, additionalTextureConsumer); } - public void create(ResourceLocation bedrockIdentifier, ResourceLocation texture, boolean displayHandheld) { - mappingTextureConsumer.accept(new GeyserSingleDefinition(Optional.of(model), bedrockIdentifier, Optional.of(displayName), predicateStack, - new GeyserSingleDefinition.BedrockOptions(Optional.empty(), true, displayHandheld, protectionValue), componentPatch), texture); + public void create(ResourceLocation bedrockIdentifier, ResourceLocation texture, boolean displayHandheld, + Optional customGeometry) { + GeyserSingleDefinition definition = new GeyserSingleDefinition(Optional.of(model), bedrockIdentifier, Optional.of(displayName), predicateStack, + new GeyserSingleDefinition.BedrockOptions(Optional.empty(), true, displayHandheld, protectionValue), componentPatch); + try { + mappingConsumer.accept(definition); + } catch (Exception exception) { + reporter.forChild(() -> "mapping with bedrock identifier " + bedrockIdentifier + " ").report(() -> "failed to pass mapping: " + exception.getMessage()); + return; + } + + itemConsumer.accept(new BedrockItem(bedrockIdentifier, definition.textureName(), texture, + AttachableMapper.mapItem(componentPatch, bedrockIdentifier, additionalTextureConsumer), + customGeometry.map(geometry -> GeometryMapper.mapGeometry(definition.textureName(), geometry)))); } } } diff --git a/src/main/java/org/geysermc/packgenerator/mapping/attachable/AttachableMapper.java b/src/main/java/org/geysermc/packgenerator/mapping/attachable/AttachableMapper.java index 90568b0..e24cb0a 100644 --- a/src/main/java/org/geysermc/packgenerator/mapping/attachable/AttachableMapper.java +++ b/src/main/java/org/geysermc/packgenerator/mapping/attachable/AttachableMapper.java @@ -4,10 +4,11 @@ import com.mojang.datafixers.util.Pair; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.model.EquipmentAssetManager; import net.minecraft.client.resources.model.EquipmentClientInfo; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.component.DataComponents; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.equipment.Equippable; import org.geysermc.packgenerator.mixin.EntityRenderDispatcherAccessor; import org.geysermc.packgenerator.pack.attachable.BedrockAttachable; @@ -17,9 +18,10 @@ import java.util.function.Consumer; public class AttachableMapper { - public static Optional mapItem(ItemStack stack, ResourceLocation bedrockIdentifier, Consumer textureConsumer) { + public static Optional mapItem(DataComponentPatch components, ResourceLocation bedrockIdentifier, Consumer textureConsumer) { // Crazy optional statement - return Optional.ofNullable(stack.get(DataComponents.EQUIPPABLE)) + return Optional.ofNullable(components.get(DataComponents.EQUIPPABLE)) + .flatMap(optional -> (Optional) optional) .flatMap(equippable -> { EquipmentAssetManager equipmentAssets = ((EntityRenderDispatcherAccessor) Minecraft.getInstance().getEntityRenderDispatcher()).getEquipmentAssets(); return equippable.assetId().map(asset -> Pair.of(equippable.slot(), equipmentAssets.get(asset))); diff --git a/src/main/java/org/geysermc/packgenerator/mapping/geyser/GeyserMappings.java b/src/main/java/org/geysermc/packgenerator/mapping/geyser/GeyserMappings.java index 68185a1..960c3b8 100644 --- a/src/main/java/org/geysermc/packgenerator/mapping/geyser/GeyserMappings.java +++ b/src/main/java/org/geysermc/packgenerator/mapping/geyser/GeyserMappings.java @@ -10,13 +10,15 @@ import net.minecraft.util.ProblemReporter; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import org.geysermc.packgenerator.CodecUtil; +import org.geysermc.packgenerator.mapping.BedrockItemConsumer; +import org.geysermc.packgenerator.mapping.BedrockItemMapper; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.function.Function; public class GeyserMappings { @@ -73,20 +75,12 @@ public class GeyserMappings { return mappings.size(); } - public void map(ItemStack stack, ResourceLocation model, ProblemReporter reporter, BiConsumer mappingTextureConsumer) { + public void map(ItemStack stack, ResourceLocation model, ProblemReporter reporter, BedrockItemConsumer itemConsumer, Consumer additionalTextureConsumer) { String displayName = stack.getHoverName().getString(); int protectionValue = 0; // TODO check the attributes - GeyserItemMapper.mapItem(model, displayName, protectionValue, stack.getComponentsPatch(), reporter, - (mapping, texture) -> { - try { - map(stack.getItemHolder(), mapping); - } catch (IllegalArgumentException exception) { - reporter.forChild(() -> "mapping with bedrock identifier " + mapping.bedrockIdentifier() + " ").report(() -> "failed to add mapping to mappings file: " + exception.getMessage()); - return; - } - mappingTextureConsumer.accept(mapping, texture); - }); + BedrockItemMapper.mapItem(model, displayName, protectionValue, stack.getComponentsPatch(), reporter, + mapping -> map(stack.getItemHolder(), mapping), itemConsumer, additionalTextureConsumer); } public Map, Collection> mappings() { diff --git a/src/main/java/org/geysermc/packgenerator/pack/BedrockItem.java b/src/main/java/org/geysermc/packgenerator/pack/BedrockItem.java new file mode 100644 index 0000000..7df8ee6 --- /dev/null +++ b/src/main/java/org/geysermc/packgenerator/pack/BedrockItem.java @@ -0,0 +1,21 @@ +package org.geysermc.packgenerator.pack; + +import net.minecraft.resources.ResourceLocation; +import org.geysermc.packgenerator.pack.attachable.BedrockAttachable; +import org.geysermc.packgenerator.pack.geometry.BedrockGeometry; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; + +public record BedrockItem(ResourceLocation identifier, String textureName, ResourceLocation texture, Optional attachable, Optional geometry) { + + public void save(Path attachableDirectory, Path geometryDirectory) throws IOException { + if (attachable.isPresent()) { + attachable.get().save(attachableDirectory); + } + if (geometry.isPresent()) { + geometry.get().save(geometryDirectory); + } + } +} diff --git a/src/main/java/org/geysermc/packgenerator/pack/BedrockPack.java b/src/main/java/org/geysermc/packgenerator/pack/BedrockPack.java index 5248e5e..bd5cfad 100644 --- a/src/main/java/org/geysermc/packgenerator/pack/BedrockPack.java +++ b/src/main/java/org/geysermc/packgenerator/pack/BedrockPack.java @@ -10,10 +10,8 @@ import net.minecraft.world.item.ItemStack; import org.apache.commons.io.IOUtils; import org.geysermc.packgenerator.CodecUtil; import org.geysermc.packgenerator.PackConstants; -import org.geysermc.packgenerator.mapping.attachable.AttachableMapper; import org.geysermc.packgenerator.mapping.geyser.GeyserMappings; import org.geysermc.packgenerator.mixin.SplashRendererAccessor; -import org.geysermc.packgenerator.pack.attachable.BedrockAttachable; import org.jetbrains.annotations.NotNull; import java.io.FileOutputStream; @@ -22,7 +20,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Optional; @@ -34,6 +31,7 @@ public class BedrockPack { private static final Path EXPORT_DIRECTORY = FabricLoader.getInstance().getGameDir().resolve("geyser"); private static final Path PACK_DIRECTORY = Path.of("pack"); private static final Path ATTACHABLES_DIRECTORY = Path.of("attachables"); + private static final Path GEOMETRY_DIRECTORY = Path.of("models/entity"); private static final Path MAPPINGS_FILE = Path.of("geyser_mappings.json"); private static final Path MANIFEST_FILE = Path.of("manifest.json"); @@ -47,9 +45,9 @@ public class BedrockPack { private final PackManifest manifest; private final GeyserMappings mappings; private final BedrockTextures.Builder itemTextures; - private final List attachables = new ArrayList<>(); - private final Set texturesToExport = new HashSet<>(); + private final Set bedrockItems = new HashSet<>(); + private final Set texturesToExport = new HashSet<>(); private final Set modelsMapped = new HashSet<>(); private final ProblemReporter.Collector reporter; @@ -101,11 +99,11 @@ public class BedrockPack { } }; - mappings.map(stack, model, mapReporter, (mapping, texture) -> { - itemTextures.withItemTexture(mapping, texture.getPath()); - texturesToExport.add(texture); - AttachableMapper.mapItem(stack, mapping.bedrockIdentifier(), texturesToExport::add).ifPresent(attachables::add); - }); + mappings.map(stack, model, mapReporter, bedrockItem -> { + itemTextures.withItemTexture(bedrockItem); + texturesToExport.add(bedrockItem.texture()); + bedrockItems.add(bedrockItem); + }, texturesToExport::add); return Optional.of(problems.get()); } @@ -120,11 +118,11 @@ public class BedrockPack { reporter.forChild(() -> "saving Geyser mappings, pack manifest, and texture atlas ").report(() -> "failed to save to pack: " + exception); success = false; } - for (BedrockAttachable attachable : attachables) { + for (BedrockItem item : bedrockItems) { try { - attachable.save(packPath.resolve(ATTACHABLES_DIRECTORY)); + item.save(packPath.resolve(ATTACHABLES_DIRECTORY), packPath.resolve(GEOMETRY_DIRECTORY)); } catch (IOException exception) { - reporter.forChild(() -> "attachable for bedrock item " + attachable.info().identifier() + " ").report(() -> "failed to save to pack: " + exception); + reporter.forChild(() -> "files for bedrock item " + item.identifier() + " ").report(() -> "failed to save to pack: " + exception); success = false; } } @@ -166,7 +164,7 @@ Textures tried to export: %d -- PROBLEM REPORT -- %s """.formatted(randomSummaryComment(), name, mappings.size(), itemTextures.build().size(), - attachables.size(), texturesToExport.size(), reporter.getTreeReport()); + bedrockItems.size(), texturesToExport.size(), reporter.getTreeReport()); } private static String randomSummaryComment() { diff --git a/src/main/java/org/geysermc/packgenerator/pack/BedrockTextures.java b/src/main/java/org/geysermc/packgenerator/pack/BedrockTextures.java index 35688ec..1437d3c 100644 --- a/src/main/java/org/geysermc/packgenerator/pack/BedrockTextures.java +++ b/src/main/java/org/geysermc/packgenerator/pack/BedrockTextures.java @@ -2,7 +2,6 @@ package org.geysermc.packgenerator.pack; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; -import org.geysermc.packgenerator.mapping.geyser.GeyserSingleDefinition; import java.util.HashMap; import java.util.List; @@ -33,8 +32,8 @@ public record BedrockTextures(Map textures) { public static class Builder { private final Map textures = new HashMap<>(); - public Builder withItemTexture(GeyserSingleDefinition mapping, String texturePath) { - return withTexture(mapping.textureName(), TEXTURES_FOLDER + texturePath); + public Builder withItemTexture(BedrockItem item) { + return withTexture(item.textureName(), TEXTURES_FOLDER + item.texture().getPath()); } public Builder withTexture(String name, String texture) { diff --git a/src/main/java/org/geysermc/packgenerator/pack/geometry/BedrockGeometry.java b/src/main/java/org/geysermc/packgenerator/pack/geometry/BedrockGeometry.java index 4cd6084..54bb6ec 100644 --- a/src/main/java/org/geysermc/packgenerator/pack/geometry/BedrockGeometry.java +++ b/src/main/java/org/geysermc/packgenerator/pack/geometry/BedrockGeometry.java @@ -203,8 +203,8 @@ public record BedrockGeometry(BedrockVersion formatVersion, List> FACE_MAP_CODEC = Codec.unboundedMap(Direction.CODEC, Face.CODEC); public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - ExtraCodecs.VECTOR3F.fieldOf("uvOrigin").forGetter(Cube::origin), - ExtraCodecs.VECTOR3F.fieldOf("uvSize").forGetter(Cube::size), + ExtraCodecs.VECTOR3F.fieldOf("origin").forGetter(Cube::origin), + ExtraCodecs.VECTOR3F.fieldOf("size").forGetter(Cube::size), ExtraCodecs.VECTOR3F.optionalFieldOf("rotation", VECTOR3F_ZERO).forGetter(Cube::size), ExtraCodecs.VECTOR3F.optionalFieldOf("pivot", VECTOR3F_ZERO).forGetter(Cube::pivot), Codec.FLOAT.optionalFieldOf("inflate", 0.0F).forGetter(Cube::inflate),