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

Work on datagen module

This commit is contained in:
Eclipse
2025-10-14 11:53:47 +00:00
parent 269a18b9df
commit e9e07016ac
12 changed files with 229 additions and 4 deletions

9
datagen/build.gradle.kts Normal file
View File

@@ -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"))
}

View File

@@ -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<Item, ClientItem> itemInfosMap;
private Map<ResourceLocation, ModelInstance> 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<Item, ClientItem> itemInfosMap) {
this.itemInfosMap = itemInfosMap;
}
public void setModels(Map<ResourceLocation, ModelInstance> models) {
this.models = models;
}
private record Serializer(CachedOutput output, HolderLookup.Provider registries, PackOutput.PathProvider provider) implements PackSerializer {
@Override
public <T> CompletableFuture<?> saveJson(Codec<T> 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<ResourceLocation, ClientItem> itemInfosMap;
private final Map<ResourceLocation, ModelInstance> models;
private ModelResolver(Map<Item, ClientItem> itemInfosMap, Map<ResourceLocation, ModelInstance> models) {
this.itemInfosMap = new HashMap<>();
for (Map.Entry<Item, ClientItem> entry : itemInfosMap.entrySet()) {
this.itemInfosMap.put(entry.getKey().builtInRegistryHolder().key().location(), entry.getValue());
}
this.models = models;
}
@Override
public Optional<ResolvedModel> getResolvedModel(ResourceLocation location) {
return Optional.ofNullable(models.get(location));
}
@Override
public Optional<ClientItem> getClientItem(ResourceLocation location) {
return Optional.ofNullable(itemInfosMap.get(location));
}
@Override
public Optional<EquipmentClientInfo> getEquipmentInfo(ResourceKey<EquipmentAsset> key) {
return Optional.empty(); // TODO
}
}
}

View File

@@ -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<Item, ClientItem> getItemInfos();
}

View File

@@ -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;
}
}

View File

@@ -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<ResourceLocation, ModelInstance> getModels();
}

View File

@@ -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"
}
}
}
}

View File

@@ -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
}
}