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

More final tweaks

This commit is contained in:
Eclipse
2025-10-16 14:07:22 +00:00
parent 2cc85d6c91
commit 3296b5a59e
12 changed files with 94 additions and 73 deletions

View File

@@ -14,8 +14,7 @@ public class Rainbow {
return ResourceLocation.fromNamespaceAndPath(MOD_ID, path);
}
// TODO rename remove file
public static String fileSafeResourceLocation(ResourceLocation location) {
public static String safeResourceLocation(ResourceLocation location) {
return location.toString().replace(':', '.').replace('/', '_');
}

View File

@@ -0,0 +1,51 @@
package org.geysermc.rainbow;
import com.mojang.logging.LogUtils;
import org.slf4j.Logger;
import java.io.IOException;
import java.util.Optional;
public final class RainbowIO {
private static final Logger LOGGER = LogUtils.getLogger();
private RainbowIO() {}
public static <T> T safeIO(IOSupplier<T> supplier, T defaultValue) {
try {
return supplier.get();
} catch (IOException exception) {
LOGGER.error("Failed to perform IO operation!", exception);
return defaultValue;
}
}
public static <T> Optional<T> safeIO(IOSupplier<T> supplier) {
try {
return Optional.ofNullable(supplier.get());
} catch (IOException exception) {
LOGGER.error("Failed to perform IO operation!", exception);
return Optional.empty();
}
}
public static void safeIO(IORunnable runnable) {
try {
runnable.run();
} catch (IOException exception) {
LOGGER.error("Failed to perform IO operation!", exception);
}
}
@FunctionalInterface
public interface IOSupplier<T> {
T get() throws IOException;
}
@FunctionalInterface
public interface IORunnable {
void run() throws IOException;
}
}

View File

@@ -61,7 +61,7 @@ public record GeyserBaseDefinition(ResourceLocation bedrockIdentifier, Optional<
}
public String textureName() {
return bedrockOptions.icon.orElse(Rainbow.fileSafeResourceLocation(bedrockIdentifier));
return bedrockOptions.icon.orElse(Rainbow.safeResourceLocation(bedrockIdentifier));
}
public record BedrockOptions(Optional<String> icon, boolean allowOffhand, boolean displayHandheld, int protectionValue, List<ResourceLocation> tags) {

View File

@@ -71,9 +71,9 @@ public class BedrockItemMapper {
}
public static void tryMapStack(ItemStack stack, int customModelData, ProblemReporter reporter, PackContext context) {
// TODO Improve this, use resouce log in problemreporter
ItemModel.Unbaked vanillaModel = context.assetResolver().getClientItem(stack.get(DataComponents.ITEM_MODEL)).map(ClientItem::model).orElseThrow();
ProblemReporter childReporter = reporter.forChild(() -> "item model " + vanillaModel + " with custom model data " + customModelData + " ");
ResourceLocation itemModel = stack.get(DataComponents.ITEM_MODEL);
ItemModel.Unbaked vanillaModel = context.assetResolver().getClientItem(itemModel).map(ClientItem::model).orElseThrow();
ProblemReporter childReporter = reporter.forChild(() -> "item model " + itemModel + " with custom model data " + customModelData + " ");
if (vanillaModel instanceof RangeSelectItemModel.Unbaked(RangeSelectItemModelProperty property, float scale, List<RangeSelectItemModel.Entry> entries, Optional<ItemModel.Unbaked> fallback)) {
// WHY, Mojang?
if (property instanceof net.minecraft.client.renderer.item.properties.numeric.CustomModelDataProperty(int index)) {

View File

@@ -44,7 +44,7 @@ public record BedrockGeometryContext(Optional<Supplier<StitchedGeometry>> geomet
// This check should probably be done differently (actually check if the model is 2D or 3D)
ResourceLocation modelLocation = ResourceLocation.parse(model.debugName());
String safeIdentifier = Rainbow.fileSafeResourceLocation(bedrockIdentifier);
String safeIdentifier = Rainbow.safeResourceLocation(bedrockIdentifier);
geometry = Optional.of(Suppliers.memoize(() -> {
StitchedTextures stitchedTextures = StitchedTextures.stitchModelTextures(textures, context);

View File

@@ -2,7 +2,6 @@ package org.geysermc.rainbow.mapping.geometry;
import com.mojang.blaze3d.platform.NativeImage;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.renderer.texture.SpriteContents;
import net.minecraft.client.renderer.texture.SpriteLoader;
@@ -12,12 +11,12 @@ import net.minecraft.client.resources.model.Material;
import net.minecraft.data.AtlasIds;
import net.minecraft.resources.ResourceLocation;
import org.geysermc.rainbow.Rainbow;
import org.geysermc.rainbow.RainbowIO;
import org.geysermc.rainbow.mapping.PackContext;
import org.geysermc.rainbow.mixin.SpriteContentsAccessor;
import org.geysermc.rainbow.mixin.SpriteLoaderAccessor;
import org.geysermc.rainbow.mixin.TextureSlotsAccessor;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
@@ -50,20 +49,20 @@ public record StitchedTextures(Map<String, TextureAtlasSprite> sprites, Supplier
// Atlas ID doesn't matter much here, but BLOCKS is the most appropriate
// Not sure if 1024 should be the max supported texture size, but it seems to work
SpriteLoader spriteLoader = new SpriteLoader(AtlasIds.BLOCKS, 1024, 16, 16);
List<SpriteContents> sprites = textures.distinct().map(texture -> readSpriteContents(texture, context)).toList();
List<SpriteContents> sprites = textures.distinct()
.map(texture -> readSpriteContents(texture, context))
.<SpriteContents>mapMulti(Optional::ifPresent)
.toList();
return ((SpriteLoaderAccessor) spriteLoader).invokeStitch(sprites, 0, Util.backgroundExecutor());
}
private static SpriteContents readSpriteContents(ResourceLocation location, PackContext context) {
// TODO decorate path util
// TODO don't use ResourceManager
// TODO IO is on main thread here?
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);
} catch (IOException exception) {
throw new RuntimeException(exception);
}
private static Optional<SpriteContents> 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);
}
});
}
private static NativeImage stitchTextureAtlas(SpriteLoader.Preparations preparations) {

View File

@@ -32,7 +32,7 @@ public record BedrockItem(ResourceLocation identifier, String textureName, Bedro
CompletableFuture.allOf(attachableTextures.stream().map(textureSaver).toArray(CompletableFuture[]::new)),
stitchedGeometry.map(StitchedGeometry::geometry).map(geometry -> geometry.save(serializer, geometryDirectory)).orElse(noop()),
stitchedGeometry.map(StitchedGeometry::stitchedTextures).map(textureSaver).orElse(noop()),
geometryContext.animation().map(context -> context.animation().save(serializer, animationDirectory, Rainbow.fileSafeResourceLocation(identifier))).orElse(noop())
geometryContext.animation().map(context -> context.animation().save(serializer, animationDirectory, Rainbow.safeResourceLocation(identifier))).orElse(noop())
);
})
);

View File

@@ -13,6 +13,7 @@ import net.minecraft.world.item.component.CustomModelData;
import org.geysermc.rainbow.CodecUtil;
import org.geysermc.rainbow.PackConstants;
import org.geysermc.rainbow.Rainbow;
import org.geysermc.rainbow.RainbowIO;
import org.geysermc.rainbow.image.NativeImageUtil;
import org.geysermc.rainbow.mapping.AssetResolver;
import org.geysermc.rainbow.mapping.BedrockItemMapper;
@@ -131,22 +132,12 @@ public class BedrockPack {
Function<TextureHolder, CompletableFuture<?>> textureSaver = texture -> {
ResourceLocation textureLocation = Rainbow.decorateTextureLocation(texture.location());
return texture.supplier()
.flatMap(image -> {
try {
return Optional.of(NativeImageUtil.writeToByteArray(image.get()));
} catch (IOException exception) {
// TODO log
return Optional.empty();
}
})
.or(() -> {
.flatMap(image -> RainbowIO.safeIO(() -> NativeImageUtil.writeToByteArray(image.get())))
.or(() -> RainbowIO.safeIO(() -> {
try (InputStream textureStream = context.assetResolver().openAsset(textureLocation)) {
return Optional.of(textureStream.readAllBytes());
} catch (IOException exception) {
// TODO log
return Optional.empty();
return textureStream.readAllBytes();
}
})
}))
.map(bytes -> serializer.saveTexture(bytes, paths.packRoot().resolve(textureLocation.getPath())))
.orElse(CompletableFuture.completedFuture(null));
};
@@ -156,11 +147,7 @@ public class BedrockPack {
}
if (paths.zipOutput().isPresent()) {
try {
CodecUtil.tryZipDirectory(paths.packRoot(), paths.zipOutput().get());
} catch (IOException exception) {
// TODO log
}
RainbowIO.safeIO(() -> CodecUtil.tryZipDirectory(paths.packRoot(), paths.zipOutput().get()));
}
if (reporter instanceof AutoCloseable closeable) {

View File

@@ -37,7 +37,7 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf
public CompletableFuture<?> save(PackSerializer serializer, Path attachablesDirectory) {
// Get a safe attachable path by using Geyser's way of getting icons
return serializer.saveJson(CODEC, this, attachablesDirectory.resolve(Rainbow.fileSafeResourceLocation(info.identifier) + ".json"));
return serializer.saveJson(CODEC, this, attachablesDirectory.resolve(Rainbow.safeResourceLocation(info.identifier) + ".json"));
}
public static Builder builder(ResourceLocation identifier) {