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

Better BedrockVersion codec/manifest generation, allow reopening packs

This commit is contained in:
Eclipse
2025-06-29 12:14:25 +00:00
parent e02edae7cd
commit 449a9a6283
7 changed files with 112 additions and 27 deletions

View File

@@ -3,12 +3,10 @@ package org.geysermc.packgenerator;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.network.chat.Component;
import java.io.IOException;
import java.nio.file.Files;
@@ -27,6 +25,17 @@ public class CodecUtil {
}).fieldOf(field).forGetter(object -> value);
}
public static <T> T tryReadJson(Codec<T> codec, Path path) throws IOException {
try {
String raw = Files.readString(path);
JsonElement json = GSON.fromJson(raw, JsonElement.class);
return codec.parse(JsonOps.INSTANCE, json).getOrThrow();
} catch (IOException exception) {
GeyserMappingsGenerator.LOGGER.warn("Failed to read JSON file {}!", path, exception);
throw exception;
}
}
public static <T> void trySaveJson(Codec<T> codec, T object, Path path) throws IOException {
JsonElement json = codec.encodeStart(JsonOps.INSTANCE, object).getOrThrow();
@@ -34,7 +43,7 @@ public class CodecUtil {
ensureDirectoryExists(path.getParent());
Files.writeString(path, GSON.toJson(json));
} catch (IOException exception) {
GeyserMappingsGenerator.LOGGER.warn("Failed to write file " + path + "!", exception);
GeyserMappingsGenerator.LOGGER.warn("Failed to write file {}!", path, exception);
throw exception;
}
}

View File

@@ -14,6 +14,8 @@ import java.io.IOException;
public class GeyserMappingsGenerator implements ClientModInitializer {
public static final String MOD_ID = "geyser-mappings-generator";
public static final String NAME = "Geyser Mappings Generator";
public static final Logger LOGGER = LogUtils.getLogger();
@Override

View File

@@ -0,0 +1,8 @@
package org.geysermc.packgenerator;
import org.geysermc.packgenerator.pack.BedrockVersion;
public class PackConstants {
public static final String DEFAULT_PACK_DESCRIPTION = "A resourcepack generated by " + GeyserMappingsGenerator.NAME;
public static final BedrockVersion ENGINE_VERSION = BedrockVersion.of(1, 21, 0);
}

View File

@@ -6,17 +6,21 @@ import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import org.geysermc.packgenerator.mappings.GeyserMappings;
import org.geysermc.packgenerator.pack.BedrockVersion;
import org.geysermc.packgenerator.pack.PackManifest;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.UUID;
import java.util.function.Function;
public final class PackManager {
private static final Path EXPORT_DIRECTORY = FabricLoader.getInstance().getGameDir().resolve("geyser");
private static final Function<Path, Path> PACK_DIRECTORY = path -> path.resolve("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 MANIFEST_FILE = Path.of("manifest.json");
private static final PackManager INSTANCE = new PackManager();
@@ -30,14 +34,14 @@ public final class PackManager {
public void startPack(String name) throws CommandSyntaxException, IOException {
if (currentPackName != null) {
throw new SimpleCommandExceptionType(Component.literal("Already started a pack with name " + currentPackName)).create();
throw new SimpleCommandExceptionType(Component.literal("Already started a pack (" + currentPackName + ")")).create();
}
exportPath = createPackDirectory(name);
packPath = exportPath.resolve(PACK_DIRECTORY);
mappings = readOrCreateMappings(exportPath.resolve(MAPPINGS_FILE));
manifest = readOrCreateManifest(name, packPath.resolve(MANIFEST_FILE));
currentPackName = name;
exportPath = createPackDirectory(currentPackName);
packPath = PACK_DIRECTORY.apply(exportPath);
mappings = new GeyserMappings();
manifest = new PackManifest(new PackManifest.Header(name, "PLACEHOLDER", UUID.randomUUID(), "PLACEHOLDER"),
List.of(new PackManifest.Module(new PackManifest.Header(name, "PLACEHOLDER", UUID.randomUUID(), "PLACEHOLDER"))));
}
public boolean map(ItemStack stack, boolean throwOnModelMissing) throws CommandSyntaxException {
@@ -58,8 +62,8 @@ public final class PackManager {
public void finish() throws CommandSyntaxException, IOException {
ensurePackIsCreated();
CodecUtil.trySaveJson(GeyserMappings.CODEC, mappings, exportPath.resolve("geyser_mappings.json"));
CodecUtil.trySaveJson(PackManifest.CODEC, manifest, packPath.resolve("manifest.json"));
CodecUtil.trySaveJson(GeyserMappings.CODEC, mappings, exportPath.resolve(MAPPINGS_FILE));
CodecUtil.trySaveJson(PackManifest.CODEC, manifest, packPath.resolve(MANIFEST_FILE));
currentPackName = null;
}
@@ -76,6 +80,22 @@ public final class PackManager {
return path;
}
private static GeyserMappings readOrCreateMappings(Path path) throws IOException {
if (Files.exists(path)) {
return CodecUtil.tryReadJson(GeyserMappings.CODEC, path);
}
return new GeyserMappings();
}
private static PackManifest readOrCreateManifest(String name, Path path) throws IOException {
if (Files.exists(path)) {
return CodecUtil.tryReadJson(PackManifest.CODEC, path).increment();
}
return new PackManifest(
new PackManifest.Header(name, PackConstants.DEFAULT_PACK_DESCRIPTION, UUID.randomUUID(), BedrockVersion.of(1), PackConstants.ENGINE_VERSION),
List.of(new PackManifest.Module(name, PackConstants.DEFAULT_PACK_DESCRIPTION, UUID.randomUUID(), BedrockVersion.of(1))));
}
public static PackManager getInstance() {
return INSTANCE;
}

View File

@@ -1,5 +1,6 @@
package org.geysermc.packgenerator.mappings.predicate;
import com.google.common.base.Suppliers;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
@@ -8,6 +9,8 @@ import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.StringRepresentable;
import org.jetbrains.annotations.NotNull;
import java.util.function.Supplier;
public record GeyserConditionPredicate(Property property, boolean expected) implements GeyserPredicate {
public static final MapCodec<GeyserConditionPredicate> CODEC = RecordCodecBuilder.mapCodec(instance ->
@@ -33,24 +36,24 @@ public record GeyserConditionPredicate(Property property, boolean expected) impl
Type type();
enum Type implements StringRepresentable {
BROKEN("broken", MapCodec.unit(GeyserConditionPredicate.BROKEN)),
DAMAGED("damaged", MapCodec.unit(GeyserConditionPredicate.DAMAGED)),
CUSTOM_MODEL_DATA("custom_model_data", CustomModelData.CODEC),
HAS_COMPONENT("has_component", HasComponent.CODEC),
FISHING_ROD_CAST("fishing_rod_cast", MapCodec.unit(GeyserConditionPredicate.FISHING_ROD_CAST));
BROKEN("broken", () -> MapCodec.unit(GeyserConditionPredicate.BROKEN)),
DAMAGED("damaged", () -> MapCodec.unit(GeyserConditionPredicate.DAMAGED)),
CUSTOM_MODEL_DATA("custom_model_data", () -> CustomModelData.CODEC),
HAS_COMPONENT("has_component", () -> HasComponent.CODEC),
FISHING_ROD_CAST("fishing_rod_cast", () -> MapCodec.unit(GeyserConditionPredicate.FISHING_ROD_CAST));
public static final Codec<Type> CODEC = StringRepresentable.fromEnum(Type::values);
private final String name;
private final MapCodec<? extends Property> codec;
private final Supplier<MapCodec<? extends Property>> codec;
Type(String name, MapCodec<? extends Property> codec) {
Type(String name, Supplier<MapCodec<? extends Property>> codec) {
this.name = name;
this.codec = codec;
this.codec = Suppliers.memoize(codec::get);
}
public MapCodec<? extends Property> codec() {
return codec;
return codec.get();
}
@Override

View File

@@ -0,0 +1,27 @@
package org.geysermc.packgenerator.pack;
import com.mojang.serialization.Codec;
import java.util.List;
public record BedrockVersion(int major, int minor, int patch) {
public static final Codec<BedrockVersion> CODEC = Codec.INT.listOf(3, 3)
.xmap(list -> BedrockVersion.of(list.getFirst(), list.get(1), list.getLast()),
version -> List.of(version.major, version.minor, version.patch));
public static BedrockVersion of(int patch) {
return of(0, 0, patch);
}
public static BedrockVersion of(int minor, int patch) {
return of(0, minor, patch);
}
public static BedrockVersion of(int major, int minor, int patch) {
return new BedrockVersion(major, minor, patch);
}
public BedrockVersion increment() {
return new BedrockVersion(major, minor, patch + 1);
}
}

View File

@@ -20,25 +20,41 @@ public record PackManifest(Header header, List<Module> modules) {
).apply(instance, (formatVersion, header, modules) -> new PackManifest(header, modules))
);
public record Header(String name, String description, UUID uuid, String version) {
public PackManifest increment() {
return new PackManifest(header.increment(), modules.stream().map(Module::increment).toList());
}
public record Header(String name, String description, UUID uuid, BedrockVersion version, BedrockVersion minEngineVersion) {
public static final MapCodec<Header> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
instance.group(
Codec.STRING.fieldOf("name").forGetter(Header::name),
Codec.STRING.fieldOf("description").forGetter(Header::description),
UUIDUtil.STRING_CODEC.fieldOf("uuid").forGetter(Header::uuid),
Codec.STRING.fieldOf("version").forGetter(Header::version)
BedrockVersion.CODEC.fieldOf("version").forGetter(Header::version),
BedrockVersion.CODEC.fieldOf("min_engine_version").forGetter(Header::minEngineVersion)
).apply(instance, Header::new)
);
public static final Codec<Header> CODEC = MAP_CODEC.codec();
public Header increment() {
return new Header(name, description, uuid, version.increment(), minEngineVersion);
}
}
public record Module(Header header) {
public record Module(String name, String description, UUID uuid, BedrockVersion version) {
public static final Codec<Module> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
CodecUtil.unitVerifyCodec(Codec.STRING, "type", "resources"),
Header.MAP_CODEC.forGetter(Module::header)
).apply(instance, (type, header) -> new Module(header))
Codec.STRING.fieldOf("name").forGetter(Module::name),
Codec.STRING.fieldOf("description").forGetter(Module::description),
UUIDUtil.STRING_CODEC.fieldOf("uuid").forGetter(Module::uuid),
BedrockVersion.CODEC.fieldOf("version").forGetter(Module::version)
).apply(instance, (type, name, description, uuid, version) -> new Module(name, description, uuid, version))
);
public Module increment() {
return new Module(name, description, uuid, version.increment());
}
}
}