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:
@@ -3,12 +3,10 @@ package org.geysermc.packgenerator;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.DataResult;
|
import com.mojang.serialization.DataResult;
|
||||||
import com.mojang.serialization.JsonOps;
|
import com.mojang.serialization.JsonOps;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@@ -27,6 +25,17 @@ public class CodecUtil {
|
|||||||
}).fieldOf(field).forGetter(object -> value);
|
}).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 {
|
public static <T> void trySaveJson(Codec<T> codec, T object, Path path) throws IOException {
|
||||||
JsonElement json = codec.encodeStart(JsonOps.INSTANCE, object).getOrThrow();
|
JsonElement json = codec.encodeStart(JsonOps.INSTANCE, object).getOrThrow();
|
||||||
|
|
||||||
@@ -34,7 +43,7 @@ public class CodecUtil {
|
|||||||
ensureDirectoryExists(path.getParent());
|
ensureDirectoryExists(path.getParent());
|
||||||
Files.writeString(path, GSON.toJson(json));
|
Files.writeString(path, GSON.toJson(json));
|
||||||
} catch (IOException exception) {
|
} catch (IOException exception) {
|
||||||
GeyserMappingsGenerator.LOGGER.warn("Failed to write file " + path + "!", exception);
|
GeyserMappingsGenerator.LOGGER.warn("Failed to write file {}!", path, exception);
|
||||||
throw exception;
|
throw exception;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import java.io.IOException;
|
|||||||
|
|
||||||
public class GeyserMappingsGenerator implements ClientModInitializer {
|
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();
|
public static final Logger LOGGER = LogUtils.getLogger();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -6,17 +6,21 @@ import net.fabricmc.loader.api.FabricLoader;
|
|||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.geysermc.packgenerator.mappings.GeyserMappings;
|
import org.geysermc.packgenerator.mappings.GeyserMappings;
|
||||||
|
import org.geysermc.packgenerator.pack.BedrockVersion;
|
||||||
import org.geysermc.packgenerator.pack.PackManifest;
|
import org.geysermc.packgenerator.pack.PackManifest;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public final class PackManager {
|
public final class PackManager {
|
||||||
private static final Path EXPORT_DIRECTORY = FabricLoader.getInstance().getGameDir().resolve("geyser");
|
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();
|
private static final PackManager INSTANCE = new PackManager();
|
||||||
|
|
||||||
@@ -30,14 +34,14 @@ public final class PackManager {
|
|||||||
|
|
||||||
public void startPack(String name) throws CommandSyntaxException, IOException {
|
public void startPack(String name) throws CommandSyntaxException, IOException {
|
||||||
if (currentPackName != null) {
|
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;
|
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 {
|
public boolean map(ItemStack stack, boolean throwOnModelMissing) throws CommandSyntaxException {
|
||||||
@@ -58,8 +62,8 @@ public final class PackManager {
|
|||||||
public void finish() throws CommandSyntaxException, IOException {
|
public void finish() throws CommandSyntaxException, IOException {
|
||||||
ensurePackIsCreated();
|
ensurePackIsCreated();
|
||||||
|
|
||||||
CodecUtil.trySaveJson(GeyserMappings.CODEC, mappings, exportPath.resolve("geyser_mappings.json"));
|
CodecUtil.trySaveJson(GeyserMappings.CODEC, mappings, exportPath.resolve(MAPPINGS_FILE));
|
||||||
CodecUtil.trySaveJson(PackManifest.CODEC, manifest, packPath.resolve("manifest.json"));
|
CodecUtil.trySaveJson(PackManifest.CODEC, manifest, packPath.resolve(MANIFEST_FILE));
|
||||||
|
|
||||||
currentPackName = null;
|
currentPackName = null;
|
||||||
}
|
}
|
||||||
@@ -76,6 +80,22 @@ public final class PackManager {
|
|||||||
return path;
|
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() {
|
public static PackManager getInstance() {
|
||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.geysermc.packgenerator.mappings.predicate;
|
package org.geysermc.packgenerator.mappings.predicate;
|
||||||
|
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
@@ -8,6 +9,8 @@ import net.minecraft.util.ExtraCodecs;
|
|||||||
import net.minecraft.util.StringRepresentable;
|
import net.minecraft.util.StringRepresentable;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public record GeyserConditionPredicate(Property property, boolean expected) implements GeyserPredicate {
|
public record GeyserConditionPredicate(Property property, boolean expected) implements GeyserPredicate {
|
||||||
|
|
||||||
public static final MapCodec<GeyserConditionPredicate> CODEC = RecordCodecBuilder.mapCodec(instance ->
|
public static final MapCodec<GeyserConditionPredicate> CODEC = RecordCodecBuilder.mapCodec(instance ->
|
||||||
@@ -33,24 +36,24 @@ public record GeyserConditionPredicate(Property property, boolean expected) impl
|
|||||||
Type type();
|
Type type();
|
||||||
|
|
||||||
enum Type implements StringRepresentable {
|
enum Type implements StringRepresentable {
|
||||||
BROKEN("broken", MapCodec.unit(GeyserConditionPredicate.BROKEN)),
|
BROKEN("broken", () -> MapCodec.unit(GeyserConditionPredicate.BROKEN)),
|
||||||
DAMAGED("damaged", MapCodec.unit(GeyserConditionPredicate.DAMAGED)),
|
DAMAGED("damaged", () -> MapCodec.unit(GeyserConditionPredicate.DAMAGED)),
|
||||||
CUSTOM_MODEL_DATA("custom_model_data", CustomModelData.CODEC),
|
CUSTOM_MODEL_DATA("custom_model_data", () -> CustomModelData.CODEC),
|
||||||
HAS_COMPONENT("has_component", HasComponent.CODEC),
|
HAS_COMPONENT("has_component", () -> HasComponent.CODEC),
|
||||||
FISHING_ROD_CAST("fishing_rod_cast", MapCodec.unit(GeyserConditionPredicate.FISHING_ROD_CAST));
|
FISHING_ROD_CAST("fishing_rod_cast", () -> MapCodec.unit(GeyserConditionPredicate.FISHING_ROD_CAST));
|
||||||
|
|
||||||
public static final Codec<Type> CODEC = StringRepresentable.fromEnum(Type::values);
|
public static final Codec<Type> CODEC = StringRepresentable.fromEnum(Type::values);
|
||||||
|
|
||||||
private final String name;
|
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.name = name;
|
||||||
this.codec = codec;
|
this.codec = Suppliers.memoize(codec::get);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapCodec<? extends Property> codec() {
|
public MapCodec<? extends Property> codec() {
|
||||||
return codec;
|
return codec.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,25 +20,41 @@ public record PackManifest(Header header, List<Module> modules) {
|
|||||||
).apply(instance, (formatVersion, header, modules) -> new PackManifest(header, 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 ->
|
public static final MapCodec<Header> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
|
||||||
instance.group(
|
instance.group(
|
||||||
Codec.STRING.fieldOf("name").forGetter(Header::name),
|
Codec.STRING.fieldOf("name").forGetter(Header::name),
|
||||||
Codec.STRING.fieldOf("description").forGetter(Header::description),
|
Codec.STRING.fieldOf("description").forGetter(Header::description),
|
||||||
UUIDUtil.STRING_CODEC.fieldOf("uuid").forGetter(Header::uuid),
|
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)
|
).apply(instance, Header::new)
|
||||||
);
|
);
|
||||||
public static final Codec<Header> CODEC = MAP_CODEC.codec();
|
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 ->
|
public static final Codec<Module> CODEC = RecordCodecBuilder.create(instance ->
|
||||||
instance.group(
|
instance.group(
|
||||||
CodecUtil.unitVerifyCodec(Codec.STRING, "type", "resources"),
|
CodecUtil.unitVerifyCodec(Codec.STRING, "type", "resources"),
|
||||||
Header.MAP_CODEC.forGetter(Module::header)
|
Codec.STRING.fieldOf("name").forGetter(Module::name),
|
||||||
).apply(instance, (type, header) -> new Module(header))
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user