From a69c2899479503f69cd716d17f2fd333f08aba8a Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sun, 19 Oct 2025 17:48:58 +0000 Subject: [PATCH] Fix 3D icon inclusion in pack.zip, use right head animation identifier --- .../geysermc/rainbow/client/PackManager.java | 4 +-- .../client/command/PackGeneratorCommand.java | 8 ++--- .../client/render/RenderedTextureHolder.java | 34 +++++++++++++++---- .../mapping/animation/AnimationMapper.java | 2 +- .../geysermc/rainbow/pack/BedrockPack.java | 10 +++--- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/client/src/main/java/org/geysermc/rainbow/client/PackManager.java b/client/src/main/java/org/geysermc/rainbow/client/PackManager.java index b00253d..75b733b 100644 --- a/client/src/main/java/org/geysermc/rainbow/client/PackManager.java +++ b/client/src/main/java/org/geysermc/rainbow/client/PackManager.java @@ -68,11 +68,11 @@ public final class PackManager { return currentPack.map(pack -> EXPORT_DIRECTORY.resolve(pack.name())); } - public boolean finish() { + public boolean finish(Runnable onFinish) { currentPack.map(pack -> { RainbowIO.safeIO(() -> Files.writeString(getExportPath().orElseThrow().resolve(REPORT_FILE), createPackSummary(pack))); return pack.save(); - }).ifPresent(CompletableFuture::join); + }).ifPresent(future -> future.thenRun(onFinish)); boolean wasPresent = currentPack.isPresent(); currentPack = Optional.empty(); return wasPresent; diff --git a/client/src/main/java/org/geysermc/rainbow/client/command/PackGeneratorCommand.java b/client/src/main/java/org/geysermc/rainbow/client/command/PackGeneratorCommand.java index 7b36272..02ca8c5 100644 --- a/client/src/main/java/org/geysermc/rainbow/client/command/PackGeneratorCommand.java +++ b/client/src/main/java/org/geysermc/rainbow/client/command/PackGeneratorCommand.java @@ -113,11 +113,9 @@ public class PackGeneratorCommand { .then(ClientCommandManager.literal("finish") .executes(context -> { Optional exportPath = packManager.getExportPath(); - if (packManager.finish()) { - // TODO error when exporting fails - context.getSource().sendFeedback(Component.translatable("commands.rainbow.pack_finished_successfully") - .withStyle(style -> style.withUnderlined(true).withClickEvent(new ClickEvent.OpenFile(exportPath.orElseThrow())))); - } else { + Runnable onFinish = () -> context.getSource().sendFeedback(Component.translatable("commands.rainbow.pack_finished_successfully").withStyle(style + -> style.withUnderlined(true).withClickEvent(new ClickEvent.OpenFile(exportPath.orElseThrow())))); + if (!packManager.finish(onFinish)) { context.getSource().sendError(NO_PACK_CREATED); } return 0; diff --git a/client/src/main/java/org/geysermc/rainbow/client/render/RenderedTextureHolder.java b/client/src/main/java/org/geysermc/rainbow/client/render/RenderedTextureHolder.java index 3fe0a8e..961a1da 100644 --- a/client/src/main/java/org/geysermc/rainbow/client/render/RenderedTextureHolder.java +++ b/client/src/main/java/org/geysermc/rainbow/client/render/RenderedTextureHolder.java @@ -28,6 +28,9 @@ import java.nio.file.Path; import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; public class RenderedTextureHolder extends TextureHolder { private final ItemStack stackToRender; @@ -53,18 +56,31 @@ public class RenderedTextureHolder extends TextureHolder { Objects.requireNonNull(sizeBounds); OversizedItemRenderState oversizedRenderState = new OversizedItemRenderState(guiItemRenderState, sizeBounds.left(), sizeBounds.top(), sizeBounds.right() + 4, sizeBounds.bottom() + 4); + Lock lock = new ReentrantLock(); + Condition condition = lock.newCondition(); + try (OversizedItemRenderer itemRenderer = new OversizedItemRenderer(Minecraft.getInstance().renderBuffers().bufferSource())) { //noinspection DataFlowIssue ((PictureInPictureCopyRenderer) itemRenderer).rainbow$allowTextureCopy(); itemRenderer.prepare(oversizedRenderState, new GuiRenderState(), 4); - writeAsPNG(serializer, path, ((PictureInPictureRendererAccessor) itemRenderer).getTexture()); + writeAsPNG(serializer, path, ((PictureInPictureRendererAccessor) itemRenderer).getTexture(), lock, condition); } - return CompletableFuture.completedFuture(null); + + return CompletableFuture.runAsync(() -> { + lock.lock(); + try { + condition.await(); + } catch (InterruptedException ignored) { + } finally { + lock.unlock(); + } + }); } // Simplified TextureUtil#writeAsPNG with some modifications to flip the image and just generate it at full size - private static void writeAsPNG(PackSerializer serializer, Path path, GpuTexture texture) { + private static void writeAsPNG(PackSerializer serializer, Path path, GpuTexture texture, Lock lock, Condition condition) { RenderSystem.assertOnRenderThread(); + int width = texture.getWidth(0); int height = texture.getHeight(0); int bufferSize = texture.getFormat().pixelSize() * width * height; @@ -83,12 +99,18 @@ public class RenderedTextureHolder extends TextureHolder { } } - serializer.saveTexture(NativeImageUtil.writeToByteArray(image), path); + serializer.saveTexture(NativeImageUtil.writeToByteArray(image), path).join(); + lock.lock(); + try { + condition.signalAll(); + } finally { + lock.unlock(); + } } }); + } finally { + buffer.close(); } - - buffer.close(); }; commandEncoder.copyTextureToBuffer(texture, buffer, 0, writer, 0); } diff --git a/rainbow/src/main/java/org/geysermc/rainbow/mapping/animation/AnimationMapper.java b/rainbow/src/main/java/org/geysermc/rainbow/mapping/animation/AnimationMapper.java index 2857e03..7e063bc 100644 --- a/rainbow/src/main/java/org/geysermc/rainbow/mapping/animation/AnimationMapper.java +++ b/rainbow/src/main/java/org/geysermc/rainbow/mapping/animation/AnimationMapper.java @@ -48,6 +48,6 @@ public class AnimationMapper { .withAnimation(identifier + ".head", BedrockAnimation.animation() .withLoopMode(BedrockAnimation.LoopMode.LOOP) .withBone(bone, headPosition, headRotation, headScale)) - .build(), "animation." + identifier + ".hold_first_person", "animation." + identifier + ".hold_third_person", identifier + ".head"); + .build(), "animation." + identifier + ".hold_first_person", "animation." + identifier + ".hold_third_person", "animation." + identifier + ".head"); } } diff --git a/rainbow/src/main/java/org/geysermc/rainbow/pack/BedrockPack.java b/rainbow/src/main/java/org/geysermc/rainbow/pack/BedrockPack.java index c22fd64..dce3352 100644 --- a/rainbow/src/main/java/org/geysermc/rainbow/pack/BedrockPack.java +++ b/rainbow/src/main/java/org/geysermc/rainbow/pack/BedrockPack.java @@ -134,17 +134,17 @@ public class BedrockPack { futures.add(item.save(serializer, paths.attachables(), paths.geometry(), paths.animation(), textureSaver)); } - if (paths.zipOutput().isPresent()) { - RainbowIO.safeIO(() -> CodecUtil.tryZipDirectory(paths.packRoot(), paths.zipOutput().get())); - } - if (reporter instanceof AutoCloseable closeable) { try { closeable.close(); } catch (Exception ignored) {} } - return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)); + CompletableFuture packSerializingFinished = CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)); + if (paths.zipOutput().isPresent()) { + return packSerializingFinished.thenAcceptAsync(object -> RainbowIO.safeIO(() -> CodecUtil.tryZipDirectory(paths.packRoot(), paths.zipOutput().get()))); + } + return packSerializingFinished; } public int getMappings() {