From e9e07016acd0e0f9d6b86bc80fa286ebb697547f Mon Sep 17 00:00:00 2001 From: Eclipse Date: Tue, 14 Oct 2025 11:53:47 +0000 Subject: [PATCH] Work on datagen module --- client/build.gradle.kts | 2 +- .../main/resources/rainbow-client.mixins.json | 1 - datagen/build.gradle.kts | 9 ++ .../rainbow/datagen/RainbowModelProvider.java | 113 ++++++++++++++++++ .../mixin/ItemInfoCollectorAccessor.java | 15 +++ .../datagen/mixin/ModelProviderMixin.java | 31 +++++ .../mixin/SimpleModelCollectorAccessor.java | 15 +++ datagen/src/main/resources/fabric.mod.json | 30 +++++ .../resources/rainbow-datagen.mixins.json | 14 +++ rainbow/src/main/resources/fabric.mod.json | 1 - .../src/main/resources/rainbow.mixins.json | 1 - settings.gradle.kts | 1 + 12 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 datagen/build.gradle.kts create mode 100644 datagen/src/main/java/org/geysermc/rainbow/datagen/RainbowModelProvider.java create mode 100644 datagen/src/main/java/org/geysermc/rainbow/datagen/mixin/ItemInfoCollectorAccessor.java create mode 100644 datagen/src/main/java/org/geysermc/rainbow/datagen/mixin/ModelProviderMixin.java create mode 100644 datagen/src/main/java/org/geysermc/rainbow/datagen/mixin/SimpleModelCollectorAccessor.java create mode 100644 datagen/src/main/resources/fabric.mod.json create mode 100644 datagen/src/main/resources/rainbow-datagen.mixins.json diff --git a/client/build.gradle.kts b/client/build.gradle.kts index 7ad5470..4b8e0ef 100644 --- a/client/build.gradle.kts +++ b/client/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } dependencies { - // Implement namedElements so IntelliJ can use it correctly, but include the remapped build + // Implement namedElements so IDEs can use it correctly, but include the remapped build implementation(project(path = ":rainbow", configuration = "namedElements")) include(project(":rainbow")) } diff --git a/client/src/main/resources/rainbow-client.mixins.json b/client/src/main/resources/rainbow-client.mixins.json index bc5f880..a55d09a 100644 --- a/client/src/main/resources/rainbow-client.mixins.json +++ b/client/src/main/resources/rainbow-client.mixins.json @@ -3,7 +3,6 @@ "minVersion": "0.8", "package": "org.geysermc.rainbow.client.mixin", "compatibilityLevel": "JAVA_21", - "mixins": [], "client": [ "EntityRenderDispatcherAccessor", "GuiItemRenderStateMixin", diff --git a/datagen/build.gradle.kts b/datagen/build.gradle.kts new file mode 100644 index 0000000..4b8e0ef --- /dev/null +++ b/datagen/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("rainbow.base-conventions") +} + +dependencies { + // Implement namedElements so IDEs can use it correctly, but include the remapped build + implementation(project(path = ":rainbow", configuration = "namedElements")) + include(project(":rainbow")) +} diff --git a/datagen/src/main/java/org/geysermc/rainbow/datagen/RainbowModelProvider.java b/datagen/src/main/java/org/geysermc/rainbow/datagen/RainbowModelProvider.java new file mode 100644 index 0000000..a5cc5f4 --- /dev/null +++ b/datagen/src/main/java/org/geysermc/rainbow/datagen/RainbowModelProvider.java @@ -0,0 +1,113 @@ +package org.geysermc.rainbow.datagen; + +import com.mojang.serialization.Codec; +import net.fabricmc.fabric.api.client.datagen.v1.provider.FabricModelProvider; +import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; +import net.minecraft.client.data.models.model.ModelInstance; +import net.minecraft.client.renderer.item.ClientItem; +import net.minecraft.client.resources.model.EquipmentClientInfo; +import net.minecraft.client.resources.model.ResolvedModel; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.data.CachedOutput; +import net.minecraft.data.DataProvider; +import net.minecraft.data.PackOutput; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.equipment.EquipmentAsset; +import org.geysermc.rainbow.mapping.AssetResolver; +import org.geysermc.rainbow.mapping.PackSerializer; +import org.geysermc.rainbow.pack.BedrockPack; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +public abstract class RainbowModelProvider extends FabricModelProvider { + private final HolderLookup.Provider registries; + private final PackOutput.PathProvider bedrockPackPathProvider; + private Map itemInfosMap; + private Map models; + + public RainbowModelProvider(FabricDataOutput output, HolderLookup.Provider registries) { + super(output); + this.registries = registries; + bedrockPackPathProvider = output.createPathProvider(PackOutput.Target.RESOURCE_PACK, "bedrock"); + } + + @Override + public @NotNull CompletableFuture run(CachedOutput output) { + CompletableFuture vanillaModels = super.run(output); + + BedrockPack pack = BedrockPack.builder("rainbow", Path.of("geyser_mappings"), Path.of("pack"), + new Serializer(output, registries, bedrockPackPathProvider), new ModelResolver(itemInfosMap)).build(); + + for (Item item : itemInfosMap.keySet()) { + pack.map(getVanillaItem(item).builtInRegistryHolder(), getVanillaDataComponentPatch(item)); + } + + return CompletableFuture.allOf(vanillaModels, pack.save()); + } + + protected abstract Item getVanillaItem(Item modded); + + protected DataComponentPatch getVanillaDataComponentPatch(Item modded) { + DataComponentPatch.Builder builder = DataComponentPatch.builder(); + modded.components().forEach(builder::set); + return builder.build(); + } + + public void setItemInfosMap(Map itemInfosMap) { + this.itemInfosMap = itemInfosMap; + } + + public void setModels(Map models) { + this.models = models; + } + + private record Serializer(CachedOutput output, HolderLookup.Provider registries, PackOutput.PathProvider provider) implements PackSerializer { + + @Override + public CompletableFuture saveJson(Codec codec, T object, Path path) { + ResourceLocation location = ResourceLocation.withDefaultNamespace(path.toString()); + return DataProvider.saveStable(output, registries, codec, object, provider.json(location)); + } + + @Override + public CompletableFuture saveTexture(ResourceLocation texture, Path path) { + return CompletableFuture.completedFuture(null); + } + } + + private static class ModelResolver implements AssetResolver { + private final Map itemInfosMap; + private final Map models; + + private ModelResolver(Map itemInfosMap, Map models) { + this.itemInfosMap = new HashMap<>(); + for (Map.Entry entry : itemInfosMap.entrySet()) { + this.itemInfosMap.put(entry.getKey().builtInRegistryHolder().key().location(), entry.getValue()); + } + this.models = models; + } + + @Override + public Optional getResolvedModel(ResourceLocation location) { + return Optional.ofNullable(models.get(location)); + } + + @Override + public Optional getClientItem(ResourceLocation location) { + return Optional.ofNullable(itemInfosMap.get(location)); + } + + @Override + public Optional getEquipmentInfo(ResourceKey key) { + return Optional.empty(); // TODO + } + } +} diff --git a/datagen/src/main/java/org/geysermc/rainbow/datagen/mixin/ItemInfoCollectorAccessor.java b/datagen/src/main/java/org/geysermc/rainbow/datagen/mixin/ItemInfoCollectorAccessor.java new file mode 100644 index 0000000..2afb1ff --- /dev/null +++ b/datagen/src/main/java/org/geysermc/rainbow/datagen/mixin/ItemInfoCollectorAccessor.java @@ -0,0 +1,15 @@ +package org.geysermc.rainbow.datagen.mixin; + +import net.minecraft.client.renderer.item.ClientItem; +import net.minecraft.world.item.Item; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(targets = "net.minecraft.client.data.models.ModelProvider$ItemInfoCollector") +public interface ItemInfoCollectorAccessor { + + @Accessor + Map getItemInfos(); +} diff --git a/datagen/src/main/java/org/geysermc/rainbow/datagen/mixin/ModelProviderMixin.java b/datagen/src/main/java/org/geysermc/rainbow/datagen/mixin/ModelProviderMixin.java new file mode 100644 index 0000000..2cf9664 --- /dev/null +++ b/datagen/src/main/java/org/geysermc/rainbow/datagen/mixin/ModelProviderMixin.java @@ -0,0 +1,31 @@ +package org.geysermc.rainbow.datagen.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.client.data.models.ModelProvider; +import net.minecraft.data.DataProvider; +import org.geysermc.rainbow.datagen.RainbowModelProvider; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(ModelProvider.class) +public abstract class ModelProviderMixin implements DataProvider { + + @WrapOperation(method = "run", at = @At(value = "NEW", target = "Lnet/minecraft/client/data/models/ModelProvider$ItemInfoCollector;")) + public Object setItemInfosInRainbowModelProvider(Operation original) { + Object itemInfoCollector = original.call(); + if ((Object) this instanceof RainbowModelProvider rainbowModelProvider) { + rainbowModelProvider.setItemInfosMap(((ItemInfoCollectorAccessor) itemInfoCollector).getItemInfos()); + } + return itemInfoCollector; + } + + @WrapOperation(method = "run", at = @At(value = "NEW", target = "Lnet/minecraft/client/data/models/ModelProvider$SimpleModelCollector;")) + public Object setModelsInRainbowModelProvider(Operation original) { + Object simpleModelCollector = original.call(); + if ((Object) this instanceof RainbowModelProvider rainbowModelProvider) { + rainbowModelProvider.setModels(((SimpleModelCollectorAccessor) simpleModelCollector).getModels()); + } + return simpleModelCollector; + } +} diff --git a/datagen/src/main/java/org/geysermc/rainbow/datagen/mixin/SimpleModelCollectorAccessor.java b/datagen/src/main/java/org/geysermc/rainbow/datagen/mixin/SimpleModelCollectorAccessor.java new file mode 100644 index 0000000..e21983c --- /dev/null +++ b/datagen/src/main/java/org/geysermc/rainbow/datagen/mixin/SimpleModelCollectorAccessor.java @@ -0,0 +1,15 @@ +package org.geysermc.rainbow.datagen.mixin; + +import net.minecraft.client.data.models.model.ModelInstance; +import net.minecraft.resources.ResourceLocation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(targets = "net.minecraft.client.data.models.ModelProvider$SimpleModelCollector") +public interface SimpleModelCollectorAccessor { + + @Accessor + Map getModels(); +} diff --git a/datagen/src/main/resources/fabric.mod.json b/datagen/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..ff57f94 --- /dev/null +++ b/datagen/src/main/resources/fabric.mod.json @@ -0,0 +1,30 @@ +{ + "schemaVersion": 1, + "id": "rainbow-datagen", + "version": "${version}", + "name": "Rainbow", + "description": "Rainbow is a mod to generate Geyser item mappings and bedrock resourcepacks for use with Geyser's custom item API (v2)", + "authors": [ + "GeyserMC contributors" + ], + "contact": { + "homepage": "https://github.com/GeyserMC/rainbow", + "issues": "https://github.com/GeyserMC/rainbow/issues", + "sources": "https://github.com/GeyserMC/rainbow" + }, + "license": "MIT", + "environment": "client", + "mixins": [], + "depends": { + "fabricloader": ">=${loader_version}", + "fabric-api": "*", + "minecraft": "${supported_versions}" + }, + "custom": { + "modmenu": { + "links": { + "modmenu.discord": "https://discord.gg/GeyserMC" + } + } + } +} diff --git a/datagen/src/main/resources/rainbow-datagen.mixins.json b/datagen/src/main/resources/rainbow-datagen.mixins.json new file mode 100644 index 0000000..574147d --- /dev/null +++ b/datagen/src/main/resources/rainbow-datagen.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "org.geysermc.rainbow.datagen.mixin", + "compatibilityLevel": "JAVA_21", + "client": [ + "ItemInfoCollectorAccessor", + "ModelProviderMixin", + "SimpleModelCollectorAccessor" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/rainbow/src/main/resources/fabric.mod.json b/rainbow/src/main/resources/fabric.mod.json index 1677e20..a672300 100644 --- a/rainbow/src/main/resources/fabric.mod.json +++ b/rainbow/src/main/resources/fabric.mod.json @@ -13,7 +13,6 @@ "sources": "https://github.com/GeyserMC/rainbow" }, "license": "MIT", - "icon": "assets/rainbow/icon.png", "environment": "client", "mixins": [ "rainbow.mixins.json" diff --git a/rainbow/src/main/resources/rainbow.mixins.json b/rainbow/src/main/resources/rainbow.mixins.json index 887a686..5e7f32d 100644 --- a/rainbow/src/main/resources/rainbow.mixins.json +++ b/rainbow/src/main/resources/rainbow.mixins.json @@ -3,7 +3,6 @@ "minVersion": "0.8", "package": "org.geysermc.rainbow.mixin", "compatibilityLevel": "JAVA_21", - "mixins": [], "client": [ "LateBoundIdMapperAccessor", "RangeSelectItemModelAccessor", diff --git a/settings.gradle.kts b/settings.gradle.kts index bc119e5..f44dcdb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -11,5 +11,6 @@ pluginManagement { include(":rainbow") include(":client") +include(":datagen") rootProject.name = "rainbow-parent"