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

Make pack saving abstract

This commit is contained in:
Eclipse
2025-10-14 10:59:57 +00:00
parent a38cbdf413
commit 6a1fe997ba
11 changed files with 137 additions and 104 deletions

View File

@@ -6,31 +6,22 @@ import net.minecraft.client.resources.model.EquipmentAssetManager;
import net.minecraft.client.resources.model.EquipmentClientInfo; import net.minecraft.client.resources.model.EquipmentClientInfo;
import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.ResolvedModel; import net.minecraft.client.resources.model.ResolvedModel;
import net.minecraft.core.HolderLookup;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.item.equipment.EquipmentAsset; import net.minecraft.world.item.equipment.EquipmentAsset;
import org.geysermc.rainbow.client.accessor.ResolvedModelAccessor; import org.geysermc.rainbow.client.accessor.ResolvedModelAccessor;
import org.geysermc.rainbow.client.mixin.EntityRenderDispatcherAccessor; import org.geysermc.rainbow.client.mixin.EntityRenderDispatcherAccessor;
import org.geysermc.rainbow.mapping.AssetResolver; import org.geysermc.rainbow.mapping.AssetResolver;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
public class MinecraftAssetResolver implements AssetResolver { public class MinecraftAssetResolver implements AssetResolver {
private final ModelManager modelManager; private final ModelManager modelManager;
private final EquipmentAssetManager equipmentAssetManager; private final EquipmentAssetManager equipmentAssetManager;
private final ResourceManager resourceManager;
private final HolderLookup.Provider registries;
public MinecraftAssetResolver(Minecraft minecraft) { public MinecraftAssetResolver(Minecraft minecraft) {
modelManager = minecraft.getModelManager(); modelManager = minecraft.getModelManager();
equipmentAssetManager = ((EntityRenderDispatcherAccessor) minecraft.getEntityRenderDispatcher()).getEquipmentAssets(); equipmentAssetManager = ((EntityRenderDispatcherAccessor) minecraft.getEntityRenderDispatcher()).getEquipmentAssets();
resourceManager = minecraft.getResourceManager();
registries = Objects.requireNonNull(minecraft.level).registryAccess();
} }
@Override @Override
@@ -47,14 +38,4 @@ public class MinecraftAssetResolver implements AssetResolver {
public Optional<EquipmentClientInfo> getEquipmentInfo(ResourceKey<EquipmentAsset> key) { public Optional<EquipmentClientInfo> getEquipmentInfo(ResourceKey<EquipmentAsset> key) {
return Optional.of(equipmentAssetManager.get(key)); return Optional.of(equipmentAssetManager.get(key));
} }
@Override
public InputStream getTexture(ResourceLocation location) throws IOException {
return resourceManager.open(location);
}
@Override
public HolderLookup.Provider registries() {
return registries;
}
} }

View File

@@ -0,0 +1,60 @@
package org.geysermc.rainbow.client;
import com.google.gson.JsonElement;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.JsonOps;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.core.HolderLookup;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import org.apache.commons.io.IOUtils;
import org.geysermc.rainbow.CodecUtil;
import org.geysermc.rainbow.mapping.PackSerializer;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
public class MinecraftPackSerializer implements PackSerializer {
private final HolderLookup.Provider registries;
private final ResourceManager resourceManager;
public MinecraftPackSerializer(Minecraft minecraft) {
registries = Objects.requireNonNull(minecraft.level).registryAccess();
resourceManager = minecraft.getResourceManager();
}
@Override
public <T> CompletableFuture<?> saveJson(Codec<T> codec, T object, Path path) {
DynamicOps<JsonElement> ops = RegistryOps.create(JsonOps.INSTANCE, registries);
return CompletableFuture.runAsync(() -> {
try {
CodecUtil.trySaveJson(codec, object, path.resolveSibling(path.getFileName() + ".json"), ops);
} catch (IOException exception) {
// TODO log
}
}, Util.backgroundExecutor().forName("PackSerializer-saveJson"));
}
@Override
public CompletableFuture<?> saveTexture(ResourceLocation texture, Path path) {
return CompletableFuture.runAsync(() -> {
ResourceLocation texturePath = texture.withPath(p -> "textures/" + p + ".png");
try (InputStream inputTexture = resourceManager.open(texturePath)) {
CodecUtil.ensureDirectoryExists(path.getParent());
try (OutputStream outputTexture = new FileOutputStream(path.toFile())) {
IOUtils.copy(inputTexture, outputTexture);
}
} catch (IOException exception) {
// TODO log
}
}, Util.backgroundExecutor().forName("PackSerializer-saveTexture"));
}
}

View File

@@ -18,6 +18,7 @@ import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer; import java.util.function.Consumer;
public final class PackManager { public final class PackManager {
@@ -32,7 +33,7 @@ public final class PackManager {
private static final Path EXPORT_DIRECTORY = FabricLoader.getInstance().getGameDir().resolve(Rainbow.MOD_ID); private static final Path EXPORT_DIRECTORY = FabricLoader.getInstance().getGameDir().resolve(Rainbow.MOD_ID);
private static final Path PACK_DIRECTORY = Path.of("pack"); private static final Path PACK_DIRECTORY = Path.of("pack");
private static final Path MAPPINGS_FILE = Path.of("geyser_mappings.json"); private static final Path MAPPINGS_FILE = Path.of("geyser_mappings");
private static final Path PACK_ZIP_FILE = Path.of("pack.zip"); private static final Path PACK_ZIP_FILE = Path.of("pack.zip");
private static final Path REPORT_FILE = Path.of("report.txt"); private static final Path REPORT_FILE = Path.of("report.txt");
@@ -44,7 +45,8 @@ public final class PackManager {
} }
Path packDirectory = createPackDirectory(name); Path packDirectory = createPackDirectory(name);
BedrockPack pack = BedrockPack.builder(name, packDirectory.resolve(MAPPINGS_FILE), packDirectory.resolve(PACK_DIRECTORY), new MinecraftAssetResolver(Minecraft.getInstance())) BedrockPack pack = BedrockPack.builder(name, packDirectory.resolve(MAPPINGS_FILE), packDirectory.resolve(PACK_DIRECTORY),
new MinecraftPackSerializer(Minecraft.getInstance()), new MinecraftAssetResolver(Minecraft.getInstance()))
.withPackZipFile(packDirectory.resolve(PACK_ZIP_FILE)) .withPackZipFile(packDirectory.resolve(PACK_ZIP_FILE))
.withGeometryRenderer(MinecraftGeometryRenderer.INSTANCE) .withGeometryRenderer(MinecraftGeometryRenderer.INSTANCE)
.reportSuccesses() .reportSuccesses()
@@ -64,17 +66,18 @@ public final class PackManager {
return currentPack.map(pack -> EXPORT_DIRECTORY.resolve(pack.name())); return currentPack.map(pack -> EXPORT_DIRECTORY.resolve(pack.name()));
} }
public Optional<Boolean> finish() { public boolean finish() {
Optional<Boolean> success = currentPack.map(pack -> { currentPack.map(pack -> {
try { try {
Files.writeString(getExportPath().orElseThrow().resolve(REPORT_FILE), createPackSummary(pack)); Files.writeString(getExportPath().orElseThrow().resolve(REPORT_FILE), createPackSummary(pack));
} catch (IOException exception) { } catch (IOException exception) {
// TODO log // TODO log
} }
return pack.save(); return pack.save();
}); }).ifPresent(CompletableFuture::join);
boolean wasPresent = currentPack.isPresent();
currentPack = Optional.empty(); currentPack = Optional.empty();
return success; return wasPresent;
} }
private static String createPackSummary(BedrockPack pack) { private static String createPackSummary(BedrockPack pack) {

View File

@@ -113,14 +113,13 @@ public class PackGeneratorCommand {
.then(ClientCommandManager.literal("finish") .then(ClientCommandManager.literal("finish")
.executes(context -> { .executes(context -> {
Optional<Path> exportPath = packManager.getExportPath(); Optional<Path> exportPath = packManager.getExportPath();
packManager.finish().ifPresentOrElse(success -> { if (packManager.finish()) {
if (!success) { // TODO error when exporting fails
context.getSource().sendError(Component.translatable("commands.rainbow.pack_finished_error"));
} else {
context.getSource().sendFeedback(Component.translatable("commands.rainbow.pack_finished_successfully") context.getSource().sendFeedback(Component.translatable("commands.rainbow.pack_finished_successfully")
.withStyle(style -> style.withUnderlined(true).withClickEvent(new ClickEvent.OpenFile(exportPath.orElseThrow())))); .withStyle(style -> style.withUnderlined(true).withClickEvent(new ClickEvent.OpenFile(exportPath.orElseThrow()))));
} else {
context.getSource().sendError(NO_PACK_CREATED);
} }
}, () -> context.getSource().sendError(NO_PACK_CREATED));
return 0; return 0;
}) })
) )

View File

@@ -3,13 +3,10 @@ package org.geysermc.rainbow.mapping;
import net.minecraft.client.renderer.item.ClientItem; import net.minecraft.client.renderer.item.ClientItem;
import net.minecraft.client.resources.model.EquipmentClientInfo; import net.minecraft.client.resources.model.EquipmentClientInfo;
import net.minecraft.client.resources.model.ResolvedModel; import net.minecraft.client.resources.model.ResolvedModel;
import net.minecraft.core.HolderLookup;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.equipment.EquipmentAsset; import net.minecraft.world.item.equipment.EquipmentAsset;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional; import java.util.Optional;
public interface AssetResolver { public interface AssetResolver {
@@ -19,8 +16,4 @@ public interface AssetResolver {
Optional<ClientItem> getClientItem(ResourceLocation location); Optional<ClientItem> getClientItem(ResourceLocation location);
Optional<EquipmentClientInfo> getEquipmentInfo(ResourceKey<EquipmentAsset> key); Optional<EquipmentClientInfo> getEquipmentInfo(ResourceKey<EquipmentAsset> key);
InputStream getTexture(ResourceLocation location) throws IOException;
HolderLookup.Provider registries();
} }

View File

@@ -0,0 +1,14 @@
package org.geysermc.rainbow.mapping;
import com.mojang.serialization.Codec;
import net.minecraft.resources.ResourceLocation;
import java.nio.file.Path;
import java.util.concurrent.CompletableFuture;
public interface PackSerializer {
<T> CompletableFuture<?> saveJson(Codec<T> codec, T object, Path path);
CompletableFuture<?> saveTexture(ResourceLocation texture, Path path);
}

View File

@@ -2,26 +2,27 @@ package org.geysermc.rainbow.pack;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import org.geysermc.rainbow.Rainbow; import org.geysermc.rainbow.Rainbow;
import org.geysermc.rainbow.mapping.PackSerializer;
import org.geysermc.rainbow.pack.animation.BedrockAnimation; import org.geysermc.rainbow.pack.animation.BedrockAnimation;
import org.geysermc.rainbow.pack.attachable.BedrockAttachable; import org.geysermc.rainbow.pack.attachable.BedrockAttachable;
import org.geysermc.rainbow.pack.geometry.BedrockGeometry; import org.geysermc.rainbow.pack.geometry.BedrockGeometry;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
public record BedrockItem(ResourceLocation identifier, String textureName, ResourceLocation texture, boolean exportTexture, Optional<BedrockAttachable> attachable, public record BedrockItem(ResourceLocation identifier, String textureName, ResourceLocation texture, boolean exportTexture, Optional<BedrockAttachable> attachable,
Optional<BedrockGeometry> geometry, Optional<BedrockAnimation> animation) { Optional<BedrockGeometry> geometry, Optional<BedrockAnimation> animation) {
public void save(Path attachableDirectory, Path geometryDirectory, Path animationDirectory) throws IOException { public List<CompletableFuture<?>> save(PackSerializer serializer, Path attachableDirectory, Path geometryDirectory, Path animationDirectory) {
if (attachable.isPresent()) { return Stream.concat(
attachable.get().save(attachableDirectory); attachable.stream().map(present -> present.save(serializer, attachableDirectory)),
} Stream.concat(
if (geometry.isPresent()) { geometry.stream().map(present -> present.save(serializer, geometryDirectory)),
geometry.get().save(geometryDirectory); animation.stream().map(present -> present.save(serializer, animationDirectory, Rainbow.fileSafeResourceLocation(identifier)))
} )
if (animation.isPresent()) { ).toList();
animation.get().save(animationDirectory, Rainbow.fileSafeResourceLocation(identifier));
}
} }
} }

View File

@@ -1,44 +1,42 @@
package org.geysermc.rainbow.pack; package org.geysermc.rainbow.pack;
import com.mojang.serialization.JsonOps;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponents; import net.minecraft.core.component.DataComponents;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.ProblemReporter; import net.minecraft.util.ProblemReporter;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.CustomModelData; import net.minecraft.world.item.component.CustomModelData;
import org.apache.commons.io.IOUtils;
import org.geysermc.rainbow.CodecUtil; import org.geysermc.rainbow.CodecUtil;
import org.geysermc.rainbow.PackConstants; import org.geysermc.rainbow.PackConstants;
import org.geysermc.rainbow.mapping.AssetResolver; import org.geysermc.rainbow.mapping.AssetResolver;
import org.geysermc.rainbow.mapping.BedrockItemMapper; import org.geysermc.rainbow.mapping.BedrockItemMapper;
import org.geysermc.rainbow.mapping.PackContext; import org.geysermc.rainbow.mapping.PackContext;
import org.geysermc.rainbow.mapping.PackSerializer;
import org.geysermc.rainbow.mapping.geometry.GeometryRenderer; import org.geysermc.rainbow.mapping.geometry.GeometryRenderer;
import org.geysermc.rainbow.mapping.geometry.NoopGeometryRenderer; import org.geysermc.rainbow.mapping.geometry.NoopGeometryRenderer;
import org.geysermc.rainbow.definition.GeyserMappings; import org.geysermc.rainbow.definition.GeyserMappings;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
public class BedrockPack { public class BedrockPack {
private final String name; private final String name;
private final PackPaths paths; private final PackPaths paths;
private final PackSerializer serializer;
private final BedrockTextures.Builder itemTextures = BedrockTextures.builder(); private final BedrockTextures.Builder itemTextures = BedrockTextures.builder();
private final Set<BedrockItem> bedrockItems = new HashSet<>(); private final Set<BedrockItem> bedrockItems = new HashSet<>();
@@ -50,11 +48,12 @@ public class BedrockPack {
private final PackManifest manifest; private final PackManifest manifest;
private final ProblemReporter.Collector reporter; private final ProblemReporter.Collector reporter;
public BedrockPack(String name, PackPaths paths, AssetResolver assetResolver, public BedrockPack(String name, PackPaths paths, PackSerializer serializer, AssetResolver assetResolver,
GeometryRenderer geometryRenderer, ProblemReporter.Collector reporter, GeometryRenderer geometryRenderer, ProblemReporter.Collector reporter,
boolean reportSuccesses) { boolean reportSuccesses) {
this.name = name; this.name = name;
this.paths = paths; this.paths = paths;
this.serializer = serializer;
// Not reading existing item mappings/texture atlas for now since that doesn't work all that well yet // Not reading existing item mappings/texture atlas for now since that doesn't work all that well yet
this.context = new PackContext(new GeyserMappings(), paths, item -> { this.context = new PackContext(new GeyserMappings(), paths, item -> {
@@ -121,50 +120,29 @@ public class BedrockPack {
return map(stack); return map(stack);
} }
public boolean save() { public CompletableFuture<?> save() {
boolean success = true; List<CompletableFuture<?>> futures = new ArrayList<>();
try { futures.add(serializer.saveJson(GeyserMappings.CODEC, context.mappings(), paths.mappings()));
CodecUtil.trySaveJson(GeyserMappings.CODEC, context.mappings(), paths.mappings(), RegistryOps.create(JsonOps.INSTANCE, context.assetResolver().registries())); futures.add(serializer.saveJson(PackManifest.CODEC, manifest, paths.manifest()));
CodecUtil.trySaveJson(PackManifest.CODEC, manifest, paths.manifest()); futures.add(serializer.saveJson(BedrockTextureAtlas.CODEC, BedrockTextureAtlas.itemAtlas(name, itemTextures), paths.itemAtlas()));
CodecUtil.trySaveJson(BedrockTextureAtlas.CODEC, BedrockTextureAtlas.itemAtlas(name, itemTextures), paths.itemAtlas());
} catch (IOException | NullPointerException exception) {
reporter.forChild(() -> "saving Geyser mappings, pack manifest, and texture atlas ").report(() -> "failed to save to pack: " + exception);
success = false;
}
for (BedrockItem item : bedrockItems) { for (BedrockItem item : bedrockItems) {
try { futures.addAll(item.save(serializer, paths.attachables(), paths.geometry(), paths.animation()));
item.save(paths.attachables(), paths.geometry(), paths.animation());
} catch (IOException exception) {
reporter.forChild(() -> "files for bedrock item " + item.identifier() + " ").report(() -> "failed to save to pack: " + exception);
success = false;
}
} }
for (ResourceLocation texture : texturesToExport) { for (ResourceLocation texture : texturesToExport) {
texture = texture.withPath(path -> "textures/" + path + ".png"); futures.add(serializer.saveTexture(texture, paths.packRoot().resolve(BedrockTextures.TEXTURES_FOLDER + texture.getPath() + ".png")));
try (InputStream inputTexture = context.assetResolver().getTexture(texture)) {
Path texturePath = paths.packRoot().resolve(texture.getPath());
CodecUtil.ensureDirectoryExists(texturePath.getParent());
try (OutputStream outputTexture = new FileOutputStream(texturePath.toFile())) {
IOUtils.copy(inputTexture, outputTexture);
}
} catch (IOException exception) {
ResourceLocation finalTexture = texture;
reporter.forChild(() -> "texture " + finalTexture + " ").report(() -> "failed to save to pack: " + exception);
success = false;
}
} }
if (paths.zipOutput().isPresent()) { if (paths.zipOutput().isPresent()) {
try { try {
CodecUtil.tryZipDirectory(paths.packRoot(), paths.zipOutput().get()); CodecUtil.tryZipDirectory(paths.packRoot(), paths.zipOutput().get());
} catch (IOException exception) { } catch (IOException exception) {
success = false; // TODO log
} }
} }
return success; return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new));
} }
public int getMappings() { public int getMappings() {
@@ -192,8 +170,8 @@ public class BedrockPack {
List.of(new PackManifest.Module(name, PackConstants.DEFAULT_PACK_DESCRIPTION, UUID.randomUUID(), BedrockVersion.of(0)))); List.of(new PackManifest.Module(name, PackConstants.DEFAULT_PACK_DESCRIPTION, UUID.randomUUID(), BedrockVersion.of(0))));
} }
public static Builder builder(String name, Path mappingsPath, Path packRootPath, AssetResolver assetResolver) { public static Builder builder(String name, Path mappingsPath, Path packRootPath, PackSerializer packSerializer, AssetResolver assetResolver) {
return new Builder(name, mappingsPath, packRootPath, assetResolver); return new Builder(name, mappingsPath, packRootPath, packSerializer, assetResolver);
} }
public static class Builder { public static class Builder {
@@ -201,12 +179,13 @@ public class BedrockPack {
private static final Path GEOMETRY_DIRECTORY = Path.of("models/entity"); private static final Path GEOMETRY_DIRECTORY = Path.of("models/entity");
private static final Path ANIMATION_DIRECTORY = Path.of("animations"); private static final Path ANIMATION_DIRECTORY = Path.of("animations");
private static final Path MANIFEST_FILE = Path.of("manifest.json"); private static final Path MANIFEST_FILE = Path.of("manifest");
private static final Path ITEM_ATLAS_FILE = Path.of("textures/item_texture.json"); private static final Path ITEM_ATLAS_FILE = Path.of("textures/item_texture");
private final String name; private final String name;
private final Path mappingsPath; private final Path mappingsPath;
private final Path packRootPath; private final Path packRootPath;
private final PackSerializer packSerializer;
private final AssetResolver assetResolver; private final AssetResolver assetResolver;
private UnaryOperator<Path> attachablesPath = resolve(ATTACHABLES_DIRECTORY); private UnaryOperator<Path> attachablesPath = resolve(ATTACHABLES_DIRECTORY);
private UnaryOperator<Path> geometryPath = resolve(GEOMETRY_DIRECTORY); private UnaryOperator<Path> geometryPath = resolve(GEOMETRY_DIRECTORY);
@@ -218,11 +197,12 @@ public class BedrockPack {
private ProblemReporter.Collector reporter; private ProblemReporter.Collector reporter;
private boolean reportSuccesses = false; private boolean reportSuccesses = false;
public Builder(String name, Path mappingsPath, Path packRootPath, AssetResolver assetResolver) { public Builder(String name, Path mappingsPath, Path packRootPath, PackSerializer packSerializer, AssetResolver assetResolver) {
this.name = name; this.name = name;
this.mappingsPath = mappingsPath; this.mappingsPath = mappingsPath;
this.packRootPath = packRootPath; this.packRootPath = packRootPath;
this.reporter = new ProblemReporter.Collector(() -> "Bedrock pack " + name + " "); this.reporter = new ProblemReporter.Collector(() -> "Bedrock pack " + name + " ");
this.packSerializer = packSerializer;
this.assetResolver = assetResolver; this.assetResolver = assetResolver;
} }
@@ -295,7 +275,7 @@ public class BedrockPack {
PackPaths paths = new PackPaths(mappingsPath, packRootPath, attachablesPath.apply(packRootPath), PackPaths paths = new PackPaths(mappingsPath, packRootPath, attachablesPath.apply(packRootPath),
geometryPath.apply(packRootPath), animationPath.apply(packRootPath), manifestPath.apply(packRootPath), geometryPath.apply(packRootPath), animationPath.apply(packRootPath), manifestPath.apply(packRootPath),
itemAtlasPath.apply(packRootPath), Optional.ofNullable(packZipFile)); itemAtlasPath.apply(packRootPath), Optional.ofNullable(packZipFile));
return new BedrockPack(name, paths, assetResolver, geometryRenderer, reporter, reportSuccesses); return new BedrockPack(name, paths, packSerializer, assetResolver, geometryRenderer, reporter, reportSuccesses);
} }
private static UnaryOperator<Path> resolve(Path child) { private static UnaryOperator<Path> resolve(Path child) {

View File

@@ -5,14 +5,15 @@ import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult; import com.mojang.serialization.DataResult;
import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder;
import org.geysermc.rainbow.CodecUtil; import org.geysermc.rainbow.CodecUtil;
import org.geysermc.rainbow.mapping.PackSerializer;
import org.geysermc.rainbow.pack.BedrockVersion; import org.geysermc.rainbow.pack.BedrockVersion;
import org.joml.Vector3fc; import org.joml.Vector3fc;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture;
public record BedrockAnimation(BedrockVersion formatVersion, Map<String, AnimationDefinition> definitions) { public record BedrockAnimation(BedrockVersion formatVersion, Map<String, AnimationDefinition> definitions) {
public static final BedrockVersion FORMAT_VERSION = BedrockVersion.of(1, 8, 0); public static final BedrockVersion FORMAT_VERSION = BedrockVersion.of(1, 8, 0);
@@ -24,8 +25,8 @@ public record BedrockAnimation(BedrockVersion formatVersion, Map<String, Animati
).apply(instance, BedrockAnimation::new) ).apply(instance, BedrockAnimation::new)
); );
public void save(Path animationDirectory, String identifier) throws IOException { public CompletableFuture<?> save(PackSerializer serializer, Path animationDirectory, String identifier) {
CodecUtil.trySaveJson(CODEC, this, animationDirectory.resolve(identifier + ".animation.json")); return serializer.saveJson(CODEC, this, animationDirectory.resolve(identifier + ".animation"));
} }
public static Builder builder() { public static Builder builder() {

View File

@@ -9,15 +9,14 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.ExtraCodecs; import net.minecraft.util.ExtraCodecs;
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.rainbow.CodecUtil;
import org.geysermc.rainbow.PackConstants; import org.geysermc.rainbow.PackConstants;
import org.geysermc.rainbow.Rainbow; import org.geysermc.rainbow.Rainbow;
import org.geysermc.rainbow.mapping.PackSerializer;
import org.geysermc.rainbow.pack.BedrockTextures; import org.geysermc.rainbow.pack.BedrockTextures;
import org.geysermc.rainbow.pack.BedrockVersion; import org.geysermc.rainbow.pack.BedrockVersion;
import org.geysermc.rainbow.pack.geometry.BedrockGeometry; import org.geysermc.rainbow.pack.geometry.BedrockGeometry;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumMap; import java.util.EnumMap;
@@ -25,6 +24,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream; import java.util.stream.Stream;
public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo info) { public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo info) {
@@ -35,9 +35,9 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf
).apply(instance, BedrockAttachable::new) ).apply(instance, BedrockAttachable::new)
); );
public void save(Path attachablesDirectory) throws IOException { public CompletableFuture<?> save(PackSerializer serializer, Path attachablesDirectory) {
// Get a safe attachable path by using Geyser's way of getting icons // Get a safe attachable path by using Geyser's way of getting icons
CodecUtil.trySaveJson(CODEC, this, attachablesDirectory.resolve(Rainbow.fileSafeResourceLocation(info.identifier) + ".json")); return serializer.saveJson(CODEC, this, attachablesDirectory.resolve(Rainbow.fileSafeResourceLocation(info.identifier)));
} }
public static Builder builder(ResourceLocation identifier) { public static Builder builder(ResourceLocation identifier) {

View File

@@ -5,12 +5,12 @@ import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import org.geysermc.rainbow.CodecUtil; import org.geysermc.rainbow.CodecUtil;
import org.geysermc.rainbow.mapping.PackSerializer;
import org.geysermc.rainbow.pack.BedrockVersion; import org.geysermc.rainbow.pack.BedrockVersion;
import org.joml.Vector2fc; import org.joml.Vector2fc;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.joml.Vector3fc; import org.joml.Vector3fc;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -18,6 +18,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture;
public record BedrockGeometry(BedrockVersion formatVersion, List<GeometryDefinition> definitions) { public record BedrockGeometry(BedrockVersion formatVersion, List<GeometryDefinition> definitions) {
public static final BedrockVersion FORMAT_VERSION = BedrockVersion.of(1, 21, 0); public static final BedrockVersion FORMAT_VERSION = BedrockVersion.of(1, 21, 0);
@@ -31,8 +32,8 @@ public record BedrockGeometry(BedrockVersion formatVersion, List<GeometryDefinit
).apply(instance, BedrockGeometry::new) ).apply(instance, BedrockGeometry::new)
); );
public void save(Path geometryDirectory) throws IOException { public CompletableFuture<?> save(PackSerializer serializer, Path geometryDirectory) {
CodecUtil.trySaveJson(CODEC, this, geometryDirectory.resolve(definitions.getFirst().info.identifier + ".geo.json")); return serializer.saveJson(CODEC, this, geometryDirectory.resolve(definitions.getFirst().info.identifier + ".geo"));
} }
public static BedrockGeometry of(GeometryDefinition... definitions) { public static BedrockGeometry of(GeometryDefinition... definitions) {