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:
@@ -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('/', '_');
|
||||
}
|
||||
|
||||
|
||||
51
rainbow/src/main/java/org/geysermc/rainbow/RainbowIO.java
Normal file
51
rainbow/src/main/java/org/geysermc/rainbow/RainbowIO.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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())
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user