From 4a5391bf2257f6b97d02ac2227089bd8b695775c Mon Sep 17 00:00:00 2001 From: LatvianModder Date: Mon, 21 Oct 2024 16:30:34 +0300 Subject: [PATCH] Added resource key recipe component --- .../mods/kubejs/BuiltinKubeJSPlugin.java | 5 ++ .../recipe/component/EnumComponent.java | 28 +++++---- .../recipe/component/RegistryComponent.java | 52 +++++++++------- .../component/ResourceKeyComponent.java | 60 +++++++++++++++++++ .../recipe/component/TagKeyComponent.java | 9 ++- 5 files changed, 118 insertions(+), 36 deletions(-) create mode 100644 src/main/java/dev/latvian/mods/kubejs/recipe/component/ResourceKeyComponent.java diff --git a/src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java b/src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java index b5404e54c..50c7f35d2 100644 --- a/src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java +++ b/src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java @@ -109,6 +109,7 @@ import dev.latvian.mods.kubejs.recipe.component.NestedRecipeComponent; import dev.latvian.mods.kubejs.recipe.component.NumberComponent; import dev.latvian.mods.kubejs.recipe.component.RegistryComponent; +import dev.latvian.mods.kubejs.recipe.component.ResourceKeyComponent; import dev.latvian.mods.kubejs.recipe.component.SizedFluidIngredientComponent; import dev.latvian.mods.kubejs.recipe.component.SizedIngredientComponent; import dev.latvian.mods.kubejs.recipe.component.StringComponent; @@ -697,12 +698,16 @@ public void registerRecipeComponents(RecipeComponentFactoryRegistry registry) { registry.register(BookCategoryComponent.CRAFTING_BOOK_CATEGORY); registry.register(BookCategoryComponent.COOKING_BOOK_CATEGORY); + registry.register(ResourceKeyComponent.DIMENSION); + registry.register(ResourceKeyComponent.LOOT_TABLE); + registry.register("tag", TagKeyComponent.FACTORY); registry.register("registry_element", RegistryComponent.FACTORY); registry.register("enum", EnumComponent.FACTORY); registry.register("map", MapRecipeComponent.FACTORY); registry.register("pattern", MapRecipeComponent.PATTERN_FACTORY); registry.register("either", EitherRecipeComponent.FACTORY); + registry.register("resource_key", ResourceKeyComponent.FACTORY); } @Override diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/EnumComponent.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/EnumComponent.java index 7c02d18e9..46904b752 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/EnumComponent.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/EnumComponent.java @@ -1,6 +1,7 @@ package dev.latvian.mods.kubejs.recipe.component; import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; import dev.latvian.mods.kubejs.error.KubeRuntimeException; import dev.latvian.mods.kubejs.recipe.schema.RecipeComponentFactory; import dev.latvian.mods.rhino.type.EnumTypeInfo; @@ -22,24 +23,13 @@ public record EnumComponent & StringRepresentable>(String cust } var clazz = Class.forName(cname); - var typeInfo = TypeInfo.of(clazz); if (!(typeInfo instanceof EnumTypeInfo enumTypeInfo)) { throw new KubeRuntimeException("Class " + clazz.getTypeName() + " is not an enum!"); } - return new EnumComponent("", enumTypeInfo, Codec.STRING.xmap(s -> { - for (var c : enumTypeInfo.enumConstants()) { - if (c instanceof RemappedEnumConstant r && r.getRemappedEnumConstantName().equalsIgnoreCase(s)) { - return c; - } else if (c instanceof Enum e && e.name().equalsIgnoreCase(s)) { - return c; - } - } - - throw new KubeRuntimeException("Enum value '" + s + "' of " + clazz.getName() + " not found"); - }, EnumTypeInfo::getName)); + return new EnumComponent<>(enumTypeInfo); } catch (Exception ex) { throw new KubeRuntimeException("Error loading class " + cname + " for EnumComponent", ex); } @@ -49,6 +39,20 @@ public static & StringRepresentable> EnumComponent of(Stri return new EnumComponent<>(customName, (EnumTypeInfo) TypeInfo.of(enumClass), codec); } + public EnumComponent(EnumTypeInfo typeInfo) { + this("", typeInfo, (Codec) Codec.STRING.flatXmap(s -> { + for (var c : typeInfo.enumConstants()) { + if (c instanceof RemappedEnumConstant r && r.getRemappedEnumConstantName().equalsIgnoreCase(s)) { + return DataResult.success(c); + } else if (c instanceof Enum e && e.name().equalsIgnoreCase(s)) { + return DataResult.success(c); + } + } + + return DataResult.error(() -> "Enum value '" + s + "' of " + typeInfo.asClass().getName() + " not found"); + }, o -> DataResult.success(EnumTypeInfo.getName(o)))); + } + @Override public Codec codec() { return codec; diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/RegistryComponent.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/RegistryComponent.java index 30b4b0ab2..9f51b1056 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/RegistryComponent.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/RegistryComponent.java @@ -3,14 +3,17 @@ import com.google.gson.JsonPrimitive; import com.mojang.serialization.Codec; import dev.latvian.mods.kubejs.fluid.FluidWrapper; +import dev.latvian.mods.kubejs.holder.HolderWrapper; import dev.latvian.mods.kubejs.item.ItemStackJS; import dev.latvian.mods.kubejs.recipe.KubeRecipe; import dev.latvian.mods.kubejs.recipe.schema.RecipeComponentFactory; import dev.latvian.mods.kubejs.registry.RegistryType; +import dev.latvian.mods.kubejs.script.KubeJSContext; import dev.latvian.mods.kubejs.util.ID; import dev.latvian.mods.kubejs.util.RegistryAccessContainer; import dev.latvian.mods.rhino.Context; import dev.latvian.mods.rhino.type.TypeInfo; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.RegistryFixedCodec; @@ -22,8 +25,8 @@ import net.neoforged.neoforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; -public record RegistryComponent(Registry registry, @Nullable RegistryType regType, Codec codec) implements RecipeComponent { - @SuppressWarnings({"unchecked", "rawtypes"}) +public record RegistryComponent(Registry registry, @Nullable RegistryType regType, Codec> codec) implements RecipeComponent> { + @SuppressWarnings({"rawtypes"}) public static final RecipeComponentFactory FACTORY = (registries, storage, reader) -> { reader.skipWhitespace(); reader.expect('<'); @@ -31,11 +34,16 @@ public record RegistryComponent(Registry registry, @Nullable RegistryType< var regId = ResourceLocation.read(reader); reader.expect('>'); var key = ResourceKey.createRegistryKey(regId); - return new RegistryComponent(registries.access().registry(key).orElseThrow(), RegistryType.ofKey(key), RegistryFixedCodec.create(key)); + return new RegistryComponent(registries, key); }; + @SuppressWarnings({"unchecked", "rawtypes"}) + public RegistryComponent(RegistryAccessContainer registries, ResourceKey key) { + this((Registry) registries.access().registry(key).orElseThrow(), (RegistryType) RegistryType.ofKey(key), RegistryFixedCodec.create(key)); + } + @Override - public Codec codec() { + public Codec> codec() { return codec; } @@ -46,29 +54,31 @@ public TypeInfo typeInfo() { @Override @SuppressWarnings("unchecked") - public T wrap(Context cx, KubeRecipe recipe, Object from) { + public Holder wrap(Context cx, KubeRecipe recipe, Object from) { if (registry == BuiltInRegistries.ITEM) { if (from instanceof ItemStack is) { - return (T) is.getItem(); - } else if (from instanceof Item) { - return (T) from; + return (Holder) is.getItem().builtInRegistryHolder(); + } else if (from instanceof Item item) { + return (Holder) item.builtInRegistryHolder(); } else { - return (T) ItemStackJS.wrap(RegistryAccessContainer.of(cx), from).getItem(); + return (Holder) ItemStackJS.wrap(RegistryAccessContainer.of(cx), from).getItemHolder(); } } else if (registry == BuiltInRegistries.FLUID) { if (from instanceof FluidStack fs) { - return (T) fs.getFluid(); - } else if (from instanceof Fluid) { - return (T) from; + return (Holder) fs.getFluid().builtInRegistryHolder(); + } else if (from instanceof Fluid fluid) { + return (Holder) fluid.builtInRegistryHolder(); } else { - return (T) FluidWrapper.wrap(RegistryAccessContainer.of(cx), from).getFluid(); + return (Holder) FluidWrapper.wrap(RegistryAccessContainer.of(cx), from).getFluidHolder(); } + } else if (regType != null) { + return (Holder) HolderWrapper.wrap((KubeJSContext) cx, from, regType.type()); + } else if (from instanceof ResourceKey key) { + return registry.getHolderOrThrow((ResourceKey) key); + } else if (from instanceof CharSequence || from instanceof ResourceLocation) { + return registry.getHolderOrThrow(ResourceKey.create(registry.key(), ID.mc(from.toString()))); } else { - if (regType != null && regType.baseClass().isInstance(from)) { - return (T) from; - } - - return registry.get(ID.mc(from)); + throw new IllegalStateException("Missing key in " + registry.key() + ": " + from); } } @@ -78,11 +88,11 @@ public boolean hasPriority(Context cx, KubeRecipe recipe, Object from) { } @Override - public void buildUniqueId(UniqueIdBuilder builder, T value) { - var id = registry.getKey(value); + public void buildUniqueId(UniqueIdBuilder builder, Holder value) { + var id = value.getKey(); if (id != null) { - builder.append(id); + builder.append(id.location()); } } diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/ResourceKeyComponent.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/ResourceKeyComponent.java new file mode 100644 index 000000000..2afa08f4d --- /dev/null +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/ResourceKeyComponent.java @@ -0,0 +1,60 @@ +package dev.latvian.mods.kubejs.recipe.component; + +import com.mojang.serialization.Codec; +import dev.latvian.mods.kubejs.recipe.KubeRecipe; +import dev.latvian.mods.kubejs.recipe.schema.RecipeComponentFactory; +import dev.latvian.mods.kubejs.registry.RegistryType; +import dev.latvian.mods.kubejs.util.ID; +import dev.latvian.mods.rhino.Context; +import dev.latvian.mods.rhino.type.TypeInfo; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.storage.loot.LootTable; + +public record ResourceKeyComponent(ResourceKey> registryKey) implements RecipeComponent> { + public static final RecipeComponent> DIMENSION = new ResourceKeyComponent<>(Registries.DIMENSION); + public static final RecipeComponent> LOOT_TABLE = new ResourceKeyComponent<>(Registries.LOOT_TABLE); + + @SuppressWarnings({"rawtypes"}) + public static final RecipeComponentFactory FACTORY = (registries, storage, reader) -> { + reader.skipWhitespace(); + reader.expect('<'); + reader.skipWhitespace(); + var regId = ResourceLocation.read(reader); + reader.expect('>'); + var key = ResourceKey.createRegistryKey(regId); + return new ResourceKeyComponent(key); + }; + + @Override + public Codec> codec() { + return ResourceKey.codec(registryKey); + } + + @Override + public TypeInfo typeInfo() { + var reg = RegistryType.ofKey(registryKey); + return reg == null ? TypeInfo.of(ResourceKey.class) : TypeInfo.of(ResourceKey.class).withParams(reg.type()); + } + + @Override + public ResourceKey wrap(Context cx, KubeRecipe recipe, Object from) { + return ResourceKey.create(registryKey, ID.mc(from)); + } + + @Override + public String toString() { + var key = (ResourceKey) registryKey; + + if (key == Registries.DIMENSION) { + return "dimension_resource_key"; + } else if (key == Registries.LOOT_TABLE) { + return "loot_table_resource_key"; + } else { + return "resource_key<" + registryKey.location() + ">"; + } + } +} \ No newline at end of file diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/TagKeyComponent.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/TagKeyComponent.java index fbe28d853..e742575da 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/TagKeyComponent.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/TagKeyComponent.java @@ -27,15 +27,18 @@ public record TagKeyComponent(ResourceKey> registry, Ty public static final RecipeComponent> BIOME = new TagKeyComponent<>(Registries.BIOME, TypeInfo.of(Biome.class)); public static final RecipeComponent> FLUID = new TagKeyComponent<>(Registries.FLUID, TypeInfo.of(Fluid.class)); + private static TagKeyComponent of(ResourceKey> registry) { + var r = RegistryType.ofKey(registry); + return new TagKeyComponent<>((ResourceKey) registry, r != null ? r.type() : TypeInfo.NONE); + } + public static final RecipeComponentFactory FACTORY = (registries, storage, reader) -> { reader.skipWhitespace(); reader.expect('<'); reader.skipWhitespace(); var registry = ResourceKey.createRegistryKey(ResourceLocation.read(reader)); reader.expect('>'); - - var r = RegistryType.ofKey(registry); - return new TagKeyComponent<>(registry, r != null ? r.type() : TypeInfo.NONE); + return of(registry); }; @Override