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

Attachable generation from equipment assets

This commit is contained in:
Eclipse
2025-07-01 11:17:43 +00:00
parent cc317e34d1
commit ca16aa08f6
7 changed files with 74 additions and 3 deletions

View File

@@ -0,0 +1,40 @@
package org.geysermc.packgenerator.mapping.attachable;
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.DataComponents;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.ItemStack;
import org.geysermc.packgenerator.mixin.EntityRenderDispatcherAccessor;
import org.geysermc.packgenerator.pack.attachable.BedrockAttachable;
import java.util.List;
import java.util.Optional;
public class AttachableMapper {
public static Optional<BedrockAttachable> mapItem(ItemStack stack, ResourceLocation bedrockIdentifier) {
// Crazy optional statement
return Optional.ofNullable(stack.get(DataComponents.EQUIPPABLE))
.flatMap(equippable -> {
EquipmentAssetManager equipmentAssets = ((EntityRenderDispatcherAccessor) Minecraft.getInstance().getEntityRenderDispatcher()).getEquipmentAssets();
return equippable.assetId().map(asset -> Pair.of(equippable.slot(), equipmentAssets.get(asset)));
})
.filter(assetInfo -> assetInfo.getSecond() != EquipmentAssetManager.MISSING)
.map(assetInfo -> assetInfo
.mapSecond(info -> info.getLayers(getLayer(assetInfo.getFirst()))))
.filter(assetInfo -> !assetInfo.getSecond().isEmpty())
.map(assetInfo -> BedrockAttachable.equipment(bedrockIdentifier, assetInfo.getFirst(), getTexture(assetInfo.getSecond(), getLayer(assetInfo.getFirst()))));
}
private static EquipmentClientInfo.LayerType getLayer(EquipmentSlot slot) {
return slot == EquipmentSlot.LEGS ? EquipmentClientInfo.LayerType.HUMANOID_LEGGINGS : EquipmentClientInfo.LayerType.HUMANOID;
}
private static String getTexture(List<EquipmentClientInfo.Layer> info, EquipmentClientInfo.LayerType layer) {
return "entity/equipment/" + layer.getSerializedName() + "/" + info.getFirst().textureId().getPath();
}
}

View File

@@ -49,7 +49,7 @@ public record GeyserMapping(ResourceLocation model, ResourceLocation bedrockIden
return bedrockOptions.icon.orElse(iconFromResourceLocation(bedrockIdentifier)); return bedrockOptions.icon.orElse(iconFromResourceLocation(bedrockIdentifier));
} }
private static String iconFromResourceLocation(ResourceLocation location) { public static String iconFromResourceLocation(ResourceLocation location) {
return location.toString().replace(':', '.').replace('/', '_'); return location.toString().replace(':', '.').replace('/', '_');
} }

View File

@@ -0,0 +1,13 @@
package org.geysermc.packgenerator.mixin;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.resources.model.EquipmentAssetManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(EntityRenderDispatcher.class)
public interface EntityRenderDispatcherAccessor {
@Accessor
EquipmentAssetManager getEquipmentAssets();
}

View File

@@ -4,6 +4,7 @@ import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import org.geysermc.packgenerator.CodecUtil; import org.geysermc.packgenerator.CodecUtil;
import org.geysermc.packgenerator.PackConstants; import org.geysermc.packgenerator.PackConstants;
import org.geysermc.packgenerator.mapping.attachable.AttachableMapper;
import org.geysermc.packgenerator.mapping.geyser.GeyserMappings; import org.geysermc.packgenerator.mapping.geyser.GeyserMappings;
import org.geysermc.packgenerator.pack.attachable.BedrockAttachable; import org.geysermc.packgenerator.pack.attachable.BedrockAttachable;
@@ -16,6 +17,7 @@ import java.util.UUID;
public class BedrockPack { public class BedrockPack {
private static final Path EXPORT_DIRECTORY = FabricLoader.getInstance().getGameDir().resolve("geyser"); private static final Path EXPORT_DIRECTORY = FabricLoader.getInstance().getGameDir().resolve("geyser");
private static final Path PACK_DIRECTORY = Path.of("pack"); private static final Path PACK_DIRECTORY = Path.of("pack");
private static final Path ATTACHABLES_DIRECTORY = Path.of("attachables");
private static final Path MAPPINGS_FILE = Path.of("geyser_mappings.json"); private static final Path MAPPINGS_FILE = Path.of("geyser_mappings.json");
private static final Path MANIFEST_FILE = Path.of("manifest.json"); private static final Path MANIFEST_FILE = Path.of("manifest.json");
@@ -44,13 +46,19 @@ public class BedrockPack {
} }
public void map(ItemStack stack) { public void map(ItemStack stack) {
mappings.map(stack, mapping -> itemTextures.withItemTexture(mapping, mapping.bedrockIdentifier().getPath())); mappings.map(stack, mapping -> {
itemTextures.withItemTexture(mapping, mapping.bedrockIdentifier().getPath());
AttachableMapper.mapItem(stack, mapping.bedrockIdentifier()).ifPresent(attachables::add);
});
} }
public void save() throws IOException { public void save() throws IOException {
CodecUtil.trySaveJson(GeyserMappings.CODEC, mappings, exportPath.resolve(MAPPINGS_FILE)); CodecUtil.trySaveJson(GeyserMappings.CODEC, mappings, exportPath.resolve(MAPPINGS_FILE));
CodecUtil.trySaveJson(PackManifest.CODEC, manifest, packPath.resolve(MANIFEST_FILE)); CodecUtil.trySaveJson(PackManifest.CODEC, manifest, packPath.resolve(MANIFEST_FILE));
CodecUtil.trySaveJson(BedrockTextureAtlas.CODEC, BedrockTextureAtlas.itemAtlas(name, itemTextures), packPath.resolve(ITEM_ATLAS_FILE)); CodecUtil.trySaveJson(BedrockTextureAtlas.CODEC, BedrockTextureAtlas.itemAtlas(name, itemTextures), packPath.resolve(ITEM_ATLAS_FILE));
for (BedrockAttachable attachable : attachables) {
attachable.save(packPath.resolve(ATTACHABLES_DIRECTORY));
}
} }
private static Path createPackDirectory(String name) throws IOException { private static Path createPackDirectory(String name) throws IOException {

View File

@@ -10,7 +10,7 @@ public record BedrockVersion(int major, int minor, int patch) {
.xmap(list -> BedrockVersion.of(list.getFirst(), list.get(1), list.getLast()), .xmap(list -> BedrockVersion.of(list.getFirst(), list.get(1), list.getLast()),
version -> List.of(version.major, version.minor, version.patch)); version -> List.of(version.major, version.minor, version.patch));
public static final Codec<BedrockVersion> STRING_CODEC = Codec.STRING.comapFlatMap(string -> { public static final Codec<BedrockVersion> STRING_CODEC = Codec.STRING.comapFlatMap(string -> {
String[] segments = string.split("\."); String[] segments = string.split("\\.");
if (segments.length != 3) { if (segments.length != 3) {
return DataResult.error(() -> "Semantic version must consist of 3 versions"); return DataResult.error(() -> "Semantic version must consist of 3 versions");
} }

View File

@@ -5,11 +5,15 @@ import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.StringRepresentable; import net.minecraft.util.StringRepresentable;
import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.EquipmentSlot;
import org.geysermc.packgenerator.CodecUtil;
import org.geysermc.packgenerator.PackConstants; import org.geysermc.packgenerator.PackConstants;
import org.geysermc.packgenerator.mapping.geyser.GeyserMapping;
import org.geysermc.packgenerator.pack.BedrockTextures; import org.geysermc.packgenerator.pack.BedrockTextures;
import org.geysermc.packgenerator.pack.BedrockVersion; import org.geysermc.packgenerator.pack.BedrockVersion;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
@@ -39,6 +43,11 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf
.build(); .build();
} }
public void save(Path attachablesPath) throws IOException {
// Get a save attachable path by using Geyser's way of getting icons
CodecUtil.trySaveJson(CODEC, this, attachablesPath.resolve(GeyserMapping.iconFromResourceLocation(info.identifier)));
}
public static class Builder { public static class Builder {
private final ResourceLocation identifier; private final ResourceLocation identifier;
private final EnumMap<DisplaySlot, String> materials = new EnumMap<>(DisplaySlot.class); private final EnumMap<DisplaySlot, String> materials = new EnumMap<>(DisplaySlot.class);

View File

@@ -8,6 +8,7 @@
"BlockModelWrapperMixin", "BlockModelWrapperMixin",
"BlockModelWrapperMixin$UnbakedMixin", "BlockModelWrapperMixin$UnbakedMixin",
"ConditionalItemModelAccessor", "ConditionalItemModelAccessor",
"EntityRenderDispatcherAccessor",
"SelectItemModelAccessor", "SelectItemModelAccessor",
"SelectItemModelMixin", "SelectItemModelMixin",
"SelectItemModelMixin$UnbakedSwitchMixin" "SelectItemModelMixin$UnbakedSwitchMixin"