1
0
mirror of https://github.com/GeyserMC/Rainbow.git synced 2025-12-19 14:59:16 +00:00

Refactors (unfinished), actually generate geometry files

This commit is contained in:
Eclipse
2025-07-04 14:50:10 +00:00
parent 419511bfff
commit cc5c7216b5
8 changed files with 89 additions and 46 deletions

View File

@@ -0,0 +1,9 @@
package org.geysermc.packgenerator.mapping;
import org.geysermc.packgenerator.pack.BedrockItem;
@FunctionalInterface
public interface BedrockItemConsumer {
void accept(BedrockItem item);
}

View File

@@ -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<ResourceLocation> 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<GeyserSingleDefinition, ResourceLocation> mappingTextureConsumer) {
Consumer<GeyserSingleDefinition> mappingConsumer, BedrockItemConsumer itemConsumer, Consumer<ResourceLocation> 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<SimpleUnbakedGeometry> 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<GeyserPredicate> predicateStack, ResourceLocation model, String displayName, int protectionValue, DataComponentPatch componentPatch, ProblemReporter reporter,
BiConsumer<GeyserSingleDefinition, ResourceLocation> mappingTextureConsumer) {
Consumer<GeyserSingleDefinition> mappingConsumer, BedrockItemConsumer itemConsumer, Consumer<ResourceLocation> 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<SimpleUnbakedGeometry> 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))));
}
}
}

View File

@@ -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<BedrockAttachable> mapItem(ItemStack stack, ResourceLocation bedrockIdentifier, Consumer<ResourceLocation> textureConsumer) {
public static Optional<BedrockAttachable> mapItem(DataComponentPatch components, ResourceLocation bedrockIdentifier, Consumer<ResourceLocation> textureConsumer) {
// Crazy optional statement
return Optional.ofNullable(stack.get(DataComponents.EQUIPPABLE))
return Optional.ofNullable(components.get(DataComponents.EQUIPPABLE))
.flatMap(optional -> (Optional<Equippable>) optional)
.flatMap(equippable -> {
EquipmentAssetManager equipmentAssets = ((EntityRenderDispatcherAccessor) Minecraft.getInstance().getEntityRenderDispatcher()).getEquipmentAssets();
return equippable.assetId().map(asset -> Pair.of(equippable.slot(), equipmentAssets.get(asset)));

View File

@@ -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<GeyserSingleDefinition, ResourceLocation> mappingTextureConsumer) {
public void map(ItemStack stack, ResourceLocation model, ProblemReporter reporter, BedrockItemConsumer itemConsumer, Consumer<ResourceLocation> 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<Holder<Item>, Collection<GeyserMapping>> mappings() {

View File

@@ -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<BedrockAttachable> attachable, Optional<BedrockGeometry> geometry) {
public void save(Path attachableDirectory, Path geometryDirectory) throws IOException {
if (attachable.isPresent()) {
attachable.get().save(attachableDirectory);
}
if (geometry.isPresent()) {
geometry.get().save(geometryDirectory);
}
}
}

View File

@@ -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<BedrockAttachable> attachables = new ArrayList<>();
private final Set<ResourceLocation> texturesToExport = new HashSet<>();
private final Set<BedrockItem> bedrockItems = new HashSet<>();
private final Set<ResourceLocation> texturesToExport = new HashSet<>();
private final Set<ResourceLocation> 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() {

View File

@@ -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<String, String> textures) {
public static class Builder {
private final Map<String, String> 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) {

View File

@@ -203,8 +203,8 @@ public record BedrockGeometry(BedrockVersion formatVersion, List<GeometryDefinit
private static final Codec<Map<Direction, Face>> FACE_MAP_CODEC = Codec.unboundedMap(Direction.CODEC, Face.CODEC);
public static final Codec<Cube> 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),