From 14329fbb13ccfec1390cd24a53f2274e6b4e8a01 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sat, 18 Oct 2025 11:57:32 +0000 Subject: [PATCH] Only stitch/export first frame of animation --- .../client/MinecraftAssetResolver.java | 17 ++++++---- .../rainbow/datagen/RainbowModelProvider.java | 15 +++++++-- .../rainbow/mapping/AssetResolver.java | 5 ++- .../mapping/texture/BuiltInTextureHolder.java | 15 +++++---- .../mapping/texture/StitchedTextures.java | 10 +++--- .../mapping/texture/TextureResource.java | 32 +++++++++++++++++++ 6 files changed, 70 insertions(+), 24 deletions(-) create mode 100644 rainbow/src/main/java/org/geysermc/rainbow/mapping/texture/TextureResource.java diff --git a/client/src/main/java/org/geysermc/rainbow/client/MinecraftAssetResolver.java b/client/src/main/java/org/geysermc/rainbow/client/MinecraftAssetResolver.java index 7a4acab..56c634d 100644 --- a/client/src/main/java/org/geysermc/rainbow/client/MinecraftAssetResolver.java +++ b/client/src/main/java/org/geysermc/rainbow/client/MinecraftAssetResolver.java @@ -2,31 +2,33 @@ package org.geysermc.rainbow.client; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.item.ClientItem; +import net.minecraft.client.renderer.texture.SpriteContents; +import net.minecraft.client.resources.model.AtlasManager; import net.minecraft.client.resources.model.EquipmentAssetManager; import net.minecraft.client.resources.model.EquipmentClientInfo; import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.ResolvedModel; +import net.minecraft.data.AtlasIds; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.world.item.equipment.EquipmentAsset; import org.geysermc.rainbow.client.accessor.ResolvedModelAccessor; import org.geysermc.rainbow.client.mixin.EntityRenderDispatcherAccessor; import org.geysermc.rainbow.mapping.AssetResolver; +import org.geysermc.rainbow.mapping.texture.TextureResource; +import org.geysermc.rainbow.mixin.SpriteContentsAccessor; -import java.io.IOException; -import java.io.InputStream; import java.util.Optional; public class MinecraftAssetResolver implements AssetResolver { private final ModelManager modelManager; private final EquipmentAssetManager equipmentAssetManager; - private final ResourceManager resourceManager; + private final AtlasManager atlasManager; public MinecraftAssetResolver(Minecraft minecraft) { modelManager = minecraft.getModelManager(); equipmentAssetManager = ((EntityRenderDispatcherAccessor) minecraft.getEntityRenderDispatcher()).getEquipmentAssets(); - resourceManager = minecraft.getResourceManager(); + atlasManager = minecraft.getAtlasManager(); } @Override @@ -45,7 +47,8 @@ public class MinecraftAssetResolver implements AssetResolver { } @Override - public InputStream openAsset(ResourceLocation location) throws IOException { - return resourceManager.open(location); + public Optional getBlockTexture(ResourceLocation location) { + SpriteContents contents = atlasManager.getAtlasOrThrow(AtlasIds.BLOCKS).getSprite(location).contents(); + return Optional.of(new TextureResource(((SpriteContentsAccessor) contents).getOriginalImage(), contents.width(), contents.height())); } } diff --git a/datagen/src/main/java/org/geysermc/rainbow/datagen/RainbowModelProvider.java b/datagen/src/main/java/org/geysermc/rainbow/datagen/RainbowModelProvider.java index de390b3..487257e 100644 --- a/datagen/src/main/java/org/geysermc/rainbow/datagen/RainbowModelProvider.java +++ b/datagen/src/main/java/org/geysermc/rainbow/datagen/RainbowModelProvider.java @@ -1,7 +1,7 @@ package org.geysermc.rainbow.datagen; -import com.google.common.hash.HashCode; import com.google.common.hash.Hashing; +import com.mojang.blaze3d.platform.NativeImage; import com.mojang.serialization.Codec; import net.fabricmc.fabric.api.client.datagen.v1.provider.FabricModelProvider; import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; @@ -10,6 +10,7 @@ import net.minecraft.client.data.models.model.ModelInstance; import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.renderer.block.model.ItemModelGenerator; import net.minecraft.client.renderer.item.ClientItem; +import net.minecraft.client.resources.metadata.animation.AnimationMetadataSection; import net.minecraft.client.resources.model.EquipmentClientInfo; import net.minecraft.client.resources.model.ResolvedModel; import net.minecraft.client.resources.model.UnbakedModel; @@ -28,6 +29,7 @@ import org.geysermc.rainbow.Rainbow; import org.geysermc.rainbow.RainbowIO; import org.geysermc.rainbow.mapping.AssetResolver; import org.geysermc.rainbow.mapping.PackSerializer; +import org.geysermc.rainbow.mapping.texture.TextureResource; import org.geysermc.rainbow.pack.BedrockPack; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -196,8 +198,15 @@ public abstract class RainbowModelProvider extends FabricModelProvider { } @Override - public InputStream openAsset(ResourceLocation location) throws IOException { - return resourceManager.open(location); + public Optional getBlockTexture(ResourceLocation location) { + return resourceManager.getResource(Rainbow.decorateTextureLocation(location)) + .flatMap(resource -> RainbowIO.safeIO(() -> { + Optional animationMetadata = resource.metadata().getSection(AnimationMetadataSection.TYPE); + try (InputStream textureStream = resource.open()) { + NativeImage texture = NativeImage.read(textureStream); + return new TextureResource(texture, animationMetadata.map(animation -> animation.calculateFrameSize(texture.getWidth(), texture.getHeight()))); + } + })); } } } diff --git a/rainbow/src/main/java/org/geysermc/rainbow/mapping/AssetResolver.java b/rainbow/src/main/java/org/geysermc/rainbow/mapping/AssetResolver.java index 922017e..58a985a 100644 --- a/rainbow/src/main/java/org/geysermc/rainbow/mapping/AssetResolver.java +++ b/rainbow/src/main/java/org/geysermc/rainbow/mapping/AssetResolver.java @@ -6,9 +6,8 @@ import net.minecraft.client.resources.model.ResolvedModel; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.equipment.EquipmentAsset; +import org.geysermc.rainbow.mapping.texture.TextureResource; -import java.io.IOException; -import java.io.InputStream; import java.util.Optional; public interface AssetResolver { @@ -19,5 +18,5 @@ public interface AssetResolver { Optional getEquipmentInfo(ResourceKey key); - InputStream openAsset(ResourceLocation location) throws IOException; + Optional getBlockTexture(ResourceLocation location); } diff --git a/rainbow/src/main/java/org/geysermc/rainbow/mapping/texture/BuiltInTextureHolder.java b/rainbow/src/main/java/org/geysermc/rainbow/mapping/texture/BuiltInTextureHolder.java index b25f067..c90126e 100644 --- a/rainbow/src/main/java/org/geysermc/rainbow/mapping/texture/BuiltInTextureHolder.java +++ b/rainbow/src/main/java/org/geysermc/rainbow/mapping/texture/BuiltInTextureHolder.java @@ -1,13 +1,13 @@ package org.geysermc.rainbow.mapping.texture; +import com.mojang.blaze3d.platform.NativeImage; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.ProblemReporter; -import org.geysermc.rainbow.Rainbow; import org.geysermc.rainbow.RainbowIO; +import org.geysermc.rainbow.image.NativeImageUtil; import org.geysermc.rainbow.mapping.AssetResolver; -import java.io.FileNotFoundException; -import java.io.InputStream; +import java.util.Objects; import java.util.Optional; public class BuiltInTextureHolder extends TextureHolder { @@ -21,9 +21,12 @@ public class BuiltInTextureHolder extends TextureHolder { @Override public Optional load(AssetResolver assetResolver, ProblemReporter reporter) { return RainbowIO.safeIO(() -> { - try (InputStream texture = assetResolver.openAsset(Rainbow.decorateTextureLocation(source))) { - return texture.readAllBytes(); - } catch (FileNotFoundException | NullPointerException exception) { + try (TextureResource texture = assetResolver.getBlockTexture(source).orElse(null)) { + Objects.requireNonNull(texture); + try (NativeImage firstFrame = texture.getFirstFrame(false)) { + return NativeImageUtil.writeToByteArray(firstFrame); + } + } catch (NullPointerException exception) { reportMissing(reporter); return null; } diff --git a/rainbow/src/main/java/org/geysermc/rainbow/mapping/texture/StitchedTextures.java b/rainbow/src/main/java/org/geysermc/rainbow/mapping/texture/StitchedTextures.java index fc2aa20..7ecc66f 100644 --- a/rainbow/src/main/java/org/geysermc/rainbow/mapping/texture/StitchedTextures.java +++ b/rainbow/src/main/java/org/geysermc/rainbow/mapping/texture/StitchedTextures.java @@ -6,7 +6,6 @@ import net.minecraft.client.renderer.block.model.TextureSlots; import net.minecraft.client.renderer.texture.SpriteContents; import net.minecraft.client.renderer.texture.SpriteLoader; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.metadata.animation.FrameSize; import net.minecraft.client.resources.model.Material; import net.minecraft.data.AtlasIds; import net.minecraft.resources.ResourceLocation; @@ -17,7 +16,6 @@ import org.geysermc.rainbow.mixin.SpriteContentsAccessor; import org.geysermc.rainbow.mixin.SpriteLoaderAccessor; import org.geysermc.rainbow.mixin.TextureSlotsAccessor; -import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -58,10 +56,12 @@ public record StitchedTextures(Map sprites, Supplier private static Optional readSpriteContents(ResourceLocation location, PackContext context) { return RainbowIO.safeIO(() -> { - try (InputStream textureStream = context.assetResolver().openAsset(Rainbow.decorateTextureLocation(location))) { - NativeImage texture = NativeImage.read(textureStream); - return new SpriteContents(location, new FrameSize(texture.getWidth(), texture.getHeight()), texture); + try (TextureResource texture = context.assetResolver().getBlockTexture(location).orElse(null)) { + if (texture != null) { + return new SpriteContents(location, texture.sizeOfFrame(), texture.getFirstFrame(true)); + } } + return null; }); } diff --git a/rainbow/src/main/java/org/geysermc/rainbow/mapping/texture/TextureResource.java b/rainbow/src/main/java/org/geysermc/rainbow/mapping/texture/TextureResource.java new file mode 100644 index 0000000..dbaad8f --- /dev/null +++ b/rainbow/src/main/java/org/geysermc/rainbow/mapping/texture/TextureResource.java @@ -0,0 +1,32 @@ +package org.geysermc.rainbow.mapping.texture; + +import com.mojang.blaze3d.platform.NativeImage; +import net.minecraft.client.resources.metadata.animation.FrameSize; + +import java.util.Optional; + +public record TextureResource(NativeImage texture, Optional frameSize) implements AutoCloseable { + + public TextureResource(NativeImage texture, int width, int height) { + this(texture, texture.getWidth() != width || texture.getHeight() != height ? Optional.of(new FrameSize(width, height)) : Optional.empty()); + } + + public NativeImage getFirstFrame(boolean copy) { + if (frameSize.isEmpty() && !copy) { + return texture; + } + FrameSize size = sizeOfFrame(); + NativeImage firstFrame = new NativeImage(size.width(), size.height(), false); + texture.copyRect(firstFrame, 0, 0, 0, 0, size.width(), size.height(), false, false); + return firstFrame; + } + + public FrameSize sizeOfFrame() { + return frameSize.orElseGet(() -> new FrameSize(texture.getWidth(), texture.getHeight())); + } + + @Override + public void close() { + texture.close(); + } +}