diff --git a/src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java b/src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java index ed3c7b6aa..3fa9e5361 100644 --- a/src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java +++ b/src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java @@ -123,6 +123,7 @@ import dev.latvian.mods.kubejs.recipe.schema.minecraft.ShapelessKubeRecipe; import dev.latvian.mods.kubejs.recipe.viewer.RecipeViewerEvents; import dev.latvian.mods.kubejs.registry.BuilderTypeRegistry; +import dev.latvian.mods.kubejs.registry.ServerRegistryRegistry; import dev.latvian.mods.kubejs.script.BindingRegistry; import dev.latvian.mods.kubejs.script.DataComponentTypeInfoRegistry; import dev.latvian.mods.kubejs.script.PlatformWrapper; @@ -160,6 +161,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.ChatType; import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; @@ -170,22 +172,46 @@ import net.minecraft.util.valueproviders.FloatProvider; import net.minecraft.util.valueproviders.IntProvider; import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.damagesource.DamageType; import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.entity.animal.WolfVariant; import net.minecraft.world.entity.decoration.PaintingVariant; import net.minecraft.world.item.ArmorItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.JukeboxSong; import net.minecraft.world.item.Tier; +import net.minecraft.world.item.armortrim.TrimMaterial; +import net.minecraft.world.item.armortrim.TrimPattern; import net.minecraft.world.item.component.Fireworks; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.item.enchantment.ItemEnchantments; +import net.minecraft.world.item.enchantment.providers.EnchantmentProvider; import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.MultiNoiseBiomeSourceParameterList; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BannerPattern; import net.minecraft.world.level.block.state.properties.BlockSetType; import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.levelgen.DensityFunction; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorPreset; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import net.minecraft.world.level.levelgen.presets.WorldPreset; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureSet; +import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool; import net.minecraft.world.level.levelgen.structure.templatesystem.RuleTest; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorType; +import net.minecraft.world.level.levelgen.synth.NormalNoise; import net.minecraft.world.level.material.MapColor; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.functions.CopyNameFunction; @@ -266,20 +292,49 @@ public void registerBuilderTypes(BuilderTypeRegistry registry) { }); registry.addDefault(NeoForgeRegistries.Keys.FLUID_TYPES, FluidTypeBuilder.class, FluidTypeBuilder::new); - // FIXME registry.addDefault(Registries.ENCHANTMENT, EnchantmentBuilder.class, EnchantmentBuilder::new); registry.addDefault(Registries.MOB_EFFECT, BasicMobEffect.Builder.class, BasicMobEffect.Builder::new); registry.addDefault(Registries.POTION, PotionBuilder.class, PotionBuilder::new); registry.addDefault(Registries.PARTICLE_TYPE, ParticleTypeBuilder.class, ParticleTypeBuilder::new); - registry.addDefault(Registries.PAINTING_VARIANT, PaintingVariantBuilder.class, PaintingVariantBuilder::new); registry.addDefault(Registries.CUSTOM_STAT, CustomStatBuilder.class, CustomStatBuilder::new); registry.addDefault(Registries.POINT_OF_INTEREST_TYPE, PoiTypeBuilder.class, PoiTypeBuilder::new); registry.addDefault(Registries.VILLAGER_TYPE, VillagerTypeBuilder.class, VillagerTypeBuilder::new); registry.addDefault(Registries.VILLAGER_PROFESSION, VillagerProfessionBuilder.class, VillagerProfessionBuilder::new); registry.addDefault(Registries.CREATIVE_MODE_TAB, CreativeTabBuilder.class, CreativeTabBuilder::new); registry.addDefault(Registries.ARMOR_MATERIAL, ArmorMaterialBuilder.class, ArmorMaterialBuilder::new); + + // FIXME registry.addDefault(Registries.ENCHANTMENT, EnchantmentBuilder.class, EnchantmentBuilder::new); + registry.addDefault(Registries.PAINTING_VARIANT, PaintingVariantBuilder.class, PaintingVariantBuilder::new); registry.addDefault(Registries.JUKEBOX_SONG, JukeboxSongBuilder.class, JukeboxSongBuilder::new); + } - registry.serverRegistry(Registries.PAINTING_VARIANT, PaintingVariant.DIRECT_CODEC, PaintingVariant.class); + @Override + public void registerServerRegistries(ServerRegistryRegistry registry) { + // VanillaRegistries + registry.register(Registries.DIMENSION_TYPE, DimensionType.DIRECT_CODEC, DimensionType.class); + registry.register(Registries.CONFIGURED_CARVER, ConfiguredWorldCarver.DIRECT_CODEC, TypeInfo.of(ConfiguredWorldCarver.class)); + registry.register(Registries.CONFIGURED_FEATURE, ConfiguredFeature.DIRECT_CODEC, TypeInfo.of(ConfiguredFeature.class)); + registry.register(Registries.PLACED_FEATURE, PlacedFeature.DIRECT_CODEC, PlacedFeature.class); + registry.register(Registries.STRUCTURE, Structure.DIRECT_CODEC, Structure.class); + registry.register(Registries.STRUCTURE_SET, StructureSet.DIRECT_CODEC, StructureSet.class); + registry.register(Registries.PROCESSOR_LIST, StructureProcessorType.DIRECT_CODEC, StructureProcessorList.class); + registry.register(Registries.TEMPLATE_POOL, StructureTemplatePool.DIRECT_CODEC, StructureTemplatePool.class); + registry.register(Registries.BIOME, Biome.DIRECT_CODEC, Biome.class); + registry.register(Registries.MULTI_NOISE_BIOME_SOURCE_PARAMETER_LIST, MultiNoiseBiomeSourceParameterList.DIRECT_CODEC, MultiNoiseBiomeSourceParameterList.class); + registry.register(Registries.NOISE, NormalNoise.NoiseParameters.DIRECT_CODEC, NormalNoise.NoiseParameters.class); + registry.register(Registries.DENSITY_FUNCTION, DensityFunction.DIRECT_CODEC, DensityFunction.class); + registry.register(Registries.NOISE_SETTINGS, NoiseGeneratorSettings.DIRECT_CODEC, NoiseGeneratorSettings.class); + registry.register(Registries.WORLD_PRESET, WorldPreset.DIRECT_CODEC, WorldPreset.class); + registry.register(Registries.FLAT_LEVEL_GENERATOR_PRESET, FlatLevelGeneratorPreset.DIRECT_CODEC, FlatLevelGeneratorPreset.class); + registry.register(Registries.CHAT_TYPE, ChatType.DIRECT_CODEC, ChatType.class); + registry.register(Registries.TRIM_PATTERN, TrimPattern.DIRECT_CODEC, TrimPattern.class); + registry.register(Registries.TRIM_MATERIAL, TrimMaterial.DIRECT_CODEC, TrimMaterial.class); + registry.register(Registries.WOLF_VARIANT, WolfVariant.DIRECT_CODEC, WolfVariant.class); + registry.register(Registries.PAINTING_VARIANT, PaintingVariant.DIRECT_CODEC, PaintingVariant.class); + registry.register(Registries.DAMAGE_TYPE, DamageType.DIRECT_CODEC, DamageType.class); + registry.register(Registries.BANNER_PATTERN, BannerPattern.DIRECT_CODEC, BannerPattern.class); + registry.register(Registries.ENCHANTMENT, Enchantment.DIRECT_CODEC, Enchantment.class); + registry.register(Registries.ENCHANTMENT_PROVIDER, EnchantmentProvider.DIRECT_CODEC, EnchantmentProvider.class); + registry.register(Registries.JUKEBOX_SONG, JukeboxSong.DIRECT_CODEC, JukeboxSong.class); } @Override diff --git a/src/main/java/dev/latvian/mods/kubejs/bindings/BlockWrapper.java b/src/main/java/dev/latvian/mods/kubejs/bindings/BlockWrapper.java index 78d11845f..d64695359 100644 --- a/src/main/java/dev/latvian/mods/kubejs/bindings/BlockWrapper.java +++ b/src/main/java/dev/latvian/mods/kubejs/bindings/BlockWrapper.java @@ -12,7 +12,6 @@ import net.minecraft.commands.arguments.blocks.BlockStateParser; import net.minecraft.core.Direction; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -98,7 +97,11 @@ public static List getTypeList() { public static List getTaggedIds(ResourceLocation tag) { return Util.make(new LinkedList<>(), list -> { for (var holder : BuiltInRegistries.BLOCK.getTagOrEmpty(Tags.block(tag))) { - holder.unwrapKey().map(ResourceKey::location).ifPresent(list::add); + var l = holder.getKey(); + + if (l != null) { + list.add(l.location()); + } } }); } diff --git a/src/main/java/dev/latvian/mods/kubejs/bindings/SizedIngredientWrapper.java b/src/main/java/dev/latvian/mods/kubejs/bindings/SizedIngredientWrapper.java index 35720f7cd..486c2309f 100644 --- a/src/main/java/dev/latvian/mods/kubejs/bindings/SizedIngredientWrapper.java +++ b/src/main/java/dev/latvian/mods/kubejs/bindings/SizedIngredientWrapper.java @@ -23,6 +23,11 @@ public interface SizedIngredientWrapper { @Info("An ingredient that matches everything") SizedIngredient all = new SizedIngredient(IngredientWrapper.all, 1); + @Info("Returns a sized ingredient of the input") + static SizedIngredient of(SizedIngredient ingredient) { + return ingredient; + } + @Info("Returns a sized ingredient of the input") static SizedIngredient of(Ingredient ingredient, int count) { return new SizedIngredient(ingredient, count); diff --git a/src/main/java/dev/latvian/mods/kubejs/core/RegistryObjectKJS.java b/src/main/java/dev/latvian/mods/kubejs/core/RegistryObjectKJS.java index 224467eb6..7e69901cc 100644 --- a/src/main/java/dev/latvian/mods/kubejs/core/RegistryObjectKJS.java +++ b/src/main/java/dev/latvian/mods/kubejs/core/RegistryObjectKJS.java @@ -31,8 +31,7 @@ public interface RegistryObjectKJS { default ResourceKey kjs$getKey() { try { - var h = kjs$asHolder(); - return h instanceof Holder.Reference ref ? ref.key() : h.unwrapKey().orElseThrow(); + return kjs$asHolder().getKey(); } catch (Exception ex) { return kjs$getRegistry().getResourceKey((T) this).orElseThrow(); } diff --git a/src/main/java/dev/latvian/mods/kubejs/item/ItemBuilder.java b/src/main/java/dev/latvian/mods/kubejs/item/ItemBuilder.java index a0ae442bc..e55a73fcc 100644 --- a/src/main/java/dev/latvian/mods/kubejs/item/ItemBuilder.java +++ b/src/main/java/dev/latvian/mods/kubejs/item/ItemBuilder.java @@ -290,11 +290,21 @@ public ItemBuilder name(NameCallback name) { Set the food properties of the item. """) public ItemBuilder food(Consumer b) { - foodBuilder = new FoodBuilder(); + if (foodBuilder == null) { + foodBuilder = new FoodBuilder(); + } + b.accept(foodBuilder); return this; } + @Info(""" + Set the food nutrition and saturation of the item. + """) + public ItemBuilder food(int nutrition, float saturation) { + return food(b -> b.nutrition(nutrition).saturation(saturation)); + } + @Info("Makes the item fire resistant like netherite tools (or not).") public ItemBuilder fireResistant(boolean isFireResistant) { fireResistant = isFireResistant; diff --git a/src/main/java/dev/latvian/mods/kubejs/level/BlockContainerJS.java b/src/main/java/dev/latvian/mods/kubejs/level/BlockContainerJS.java index 43bd7a2f3..a2ebfa32b 100644 --- a/src/main/java/dev/latvian/mods/kubejs/level/BlockContainerJS.java +++ b/src/main/java/dev/latvian/mods/kubejs/level/BlockContainerJS.java @@ -396,7 +396,8 @@ public EntityArrayList getPlayersInRadius() { } public ResourceLocation getBiomeId() { - return minecraftLevel.getBiome(pos).unwrapKey().orElse(Biomes.PLAINS).location(); + var k = minecraftLevel.getBiome(pos).getKey(); + return k == null ? Biomes.PLAINS.location() : k.location(); } @Override diff --git a/src/main/java/dev/latvian/mods/kubejs/plugin/KubeJSPlugin.java b/src/main/java/dev/latvian/mods/kubejs/plugin/KubeJSPlugin.java index 6a57fb3ff..9677f030c 100644 --- a/src/main/java/dev/latvian/mods/kubejs/plugin/KubeJSPlugin.java +++ b/src/main/java/dev/latvian/mods/kubejs/plugin/KubeJSPlugin.java @@ -15,6 +15,7 @@ import dev.latvian.mods.kubejs.recipe.schema.RecipeSchemaRegistry; import dev.latvian.mods.kubejs.recipe.viewer.RecipeViewerEntryType; import dev.latvian.mods.kubejs.registry.BuilderTypeRegistry; +import dev.latvian.mods.kubejs.registry.ServerRegistryRegistry; import dev.latvian.mods.kubejs.script.BindingRegistry; import dev.latvian.mods.kubejs.script.DataComponentTypeInfoRegistry; import dev.latvian.mods.kubejs.script.ScriptManager; @@ -45,6 +46,9 @@ default void afterInit() { default void registerBuilderTypes(BuilderTypeRegistry registry) { } + default void registerServerRegistries(ServerRegistryRegistry registry) { + } + /** * Call {@link EventGroupRegistry#register(EventGroup)} for event groups your mod adds */ diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/KubeRecipe.java b/src/main/java/dev/latvian/mods/kubejs/recipe/KubeRecipe.java index 93318feb8..b0ddd22c2 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/KubeRecipe.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/KubeRecipe.java @@ -7,8 +7,8 @@ import dev.latvian.mods.kubejs.core.RecipeLikeKJS; import dev.latvian.mods.kubejs.error.KubeRuntimeException; import dev.latvian.mods.kubejs.error.MissingComponentException; -import dev.latvian.mods.kubejs.recipe.component.RecipeComponentBuilderMap; import dev.latvian.mods.kubejs.recipe.component.RecipeComponentValue; +import dev.latvian.mods.kubejs.recipe.component.RecipeComponentValueMap; import dev.latvian.mods.kubejs.recipe.ingredientaction.ConsumeAction; import dev.latvian.mods.kubejs.recipe.ingredientaction.CustomIngredientAction; import dev.latvian.mods.kubejs.recipe.ingredientaction.DamageAction; @@ -51,7 +51,7 @@ public class KubeRecipe implements RecipeLikeKJS, CustomJavaToJsWrapper { public SourceLine sourceLine = SourceLine.UNKNOWN; public String modifyResult = ""; - private RecipeComponentBuilderMap valueMap = RecipeComponentBuilderMap.EMPTY; + private RecipeComponentValueMap valueMap = RecipeComponentValueMap.EMPTY; private RecipeComponentValue[] inputValues; private RecipeComponentValue[] outputValues; @@ -156,7 +156,7 @@ public void initValues(boolean created) { } if (!type.schemaType.schema.keys.isEmpty()) { - valueMap = new RecipeComponentBuilderMap(type.schemaType.schema.keys); + valueMap = new RecipeComponentValueMap(type.schemaType.schema.keys); if (created) { for (var v : valueMap.holders) { diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/EitherRecipeComponent.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/EitherRecipeComponent.java index 672096f49..a26b2d043 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/EitherRecipeComponent.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/EitherRecipeComponent.java @@ -67,23 +67,6 @@ public Either replace(Context cx, KubeRecipe recipe, Either original } } - @Override - public boolean checkValueHasChanged(Either oldValue, Either newValue) { - if (oldValue != null && newValue != null) { - var left = oldValue.left(); - - if (left.isPresent()) { - if (high.checkValueHasChanged(left.get(), newValue.left().get())) { - return true; - } - } else if (low.checkValueHasChanged(oldValue.right().get(), newValue.right().get())) { - return true; - } - } - - return oldValue != newValue; - } - @Override public void buildUniqueId(UniqueIdBuilder builder, Either value) { var left = value.left(); diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponent.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponent.java index 5b589737b..f01ea4afb 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponent.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponent.java @@ -37,18 +37,12 @@ */ @Nullable public interface RecipeComponent { - static RecipeComponentBuilder builder() { - return new RecipeComponentBuilder(4); + static RecipeComponentBuilder builder(List keys) { + return new RecipeComponentBuilder(keys); } - static RecipeComponentBuilder builder(RecipeKey... key) { - var b = new RecipeComponentBuilder(key.length); - - for (var k : key) { - b.add(k); - } - - return b; + static RecipeComponentBuilder builder(RecipeComponentBuilder.Key... keys) { + return new RecipeComponentBuilder(List.of(keys)); } /** @@ -196,10 +190,6 @@ default String checkEmpty(RecipeKey key, T value) { return ""; } - default boolean checkValueHasChanged(T oldValue, T newValue) { - return oldValue != newValue; - } - default void buildUniqueId(UniqueIdBuilder builder, T value) { builder.append(value.toString()); } diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentBuilder.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentBuilder.java index 7acc41c62..4b33927b4 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentBuilder.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentBuilder.java @@ -1,12 +1,13 @@ package dev.latvian.mods.kubejs.recipe.component; import com.google.gson.JsonObject; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.MapLike; +import com.mojang.serialization.RecordBuilder; import dev.latvian.mods.kubejs.recipe.KubeRecipe; -import dev.latvian.mods.kubejs.recipe.RecipeKey; import dev.latvian.mods.kubejs.recipe.match.ReplacementMatchInfo; import dev.latvian.mods.kubejs.util.Cast; import dev.latvian.mods.rhino.Context; @@ -15,23 +16,53 @@ import dev.latvian.mods.rhino.type.TypeInfo; import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; -public class RecipeComponentBuilder implements RecipeComponent { - public final List> keys; - public Predicate> hasPriority; +public class RecipeComponentBuilder implements RecipeComponent> { + public record Key(String name, RecipeComponent component, boolean optional, boolean alwaysWrite) { + public Key(String name, RecipeComponent component, boolean optional) { + this(name, component, optional, false); + } - public RecipeComponentBuilder(int init) { - this.keys = new ArrayList<>(init); + public Key(String name, RecipeComponent component) { + this(name, component, false); + } + + @Override + public String toString() { + return name + (optional ? "?" : "") + (alwaysWrite ? "!" : "") + ": " + component; + } } - public RecipeComponentBuilder add(RecipeKey key) { - keys.add(key); - return this; + public record Value(Key key, int index, Object value) implements Map.Entry { + @Override + public Key getKey() { + return key; + } + + @Override + public Object getValue() { + return value; + } + + @Override + public Object setValue(Object object) { + throw new UnsupportedOperationException(); + } + } + + public final List keys; + public Predicate> hasPriority; + + public RecipeComponentBuilder(List keys) { + this.keys = List.copyOf(keys); } public RecipeComponentBuilder hasPriority(Predicate> hasPriority) { @@ -40,50 +71,54 @@ public RecipeComponentBuilder hasPriority(Predicate> hasPriority) { } public RecipeComponentBuilder createCopy() { - var copy = new RecipeComponentBuilder(keys.size()); - copy.keys.addAll(keys); + var copy = new RecipeComponentBuilder(keys); copy.hasPriority = hasPriority; return copy; } - @Override - public Codec codec() { - return new Codec<>() { + public MapCodec> mapCodec() { + return new MapCodec<>() { @Override - public DataResult> decode(DynamicOps ops, T input) { - /* - for (var holder : value.holders) { - holder.key.component.readFromJson(recipe, Cast.to(holder), json); + public Stream keys(DynamicOps ops) { + return keys.stream().map(Key::name).map(ops::createString); + } - if (!holder.key.optional() && holder.value == null) { - throw new IllegalArgumentException("Missing required key '" + holder.key + "'!"); + @Override + public DataResult> decode(DynamicOps ops, MapLike input) { + var map = new HashMap(keys.size()); + var keyMap = new HashMap(); + + keys.forEach(key -> keyMap.put(key.name, key)); + + input.entries().forEach(entry -> { + var key = keyMap.get(ops.getStringValue(entry.getFirst()).getOrThrow()); + + if (key != null) { + map.put(key, new Value(key, keys.indexOf(key), key.component.codec().decode(ops, entry.getSecond()))); } - } - */ + }); - // return ops.getMapEntries(input).flatMap(map -> { - return DataResult.error(() -> "I don't understand codecs well enough yet"); + return DataResult.success(map); } @Override - public DataResult encode(RecipeComponentBuilderMap input, DynamicOps ops, T prefix) { + public RecordBuilder encode(Map input, DynamicOps ops, RecordBuilder prefix) { var builder = ops.mapBuilder(); - /* - for (var val : value.holders) { - if (val.value != null) { - var vc = new RecipeComponentValue<>(val.key, val.getIndex()); - vc.value = Cast.to(val.value); - val.key.component.writeToJson(recipe, Cast.to(vc), json); - } + for (var entry : input.values()) { + builder.add(ops.createString(entry.key.name), entry.key.component.codec().encodeStart(ops, Cast.to(entry.value))); } - */ - return builder.build(prefix); + return builder; } }; } + @Override + public Codec> codec() { + return mapCodec().codec(); + } + @Override public TypeInfo typeInfo() { var list = new ArrayList(keys.size()); @@ -127,9 +162,9 @@ public boolean hasPriority(Context cx, KubeRecipe recipe, Object from) { } @Override - public boolean matches(Context cx, KubeRecipe recipe, RecipeComponentBuilderMap value, ReplacementMatchInfo match) { - for (var e : value.holders) { - if (e.matches(cx, recipe, match)) { + public boolean matches(Context cx, KubeRecipe recipe, Map value, ReplacementMatchInfo match) { + for (var e : value.values()) { + if (e.key.component.matches(cx, recipe, Cast.to(e.value), match)) { return true; } } @@ -138,40 +173,43 @@ public boolean matches(Context cx, KubeRecipe recipe, RecipeComponentBuilderMap } @Override - public RecipeComponentBuilderMap replace(Context cx, KubeRecipe recipe, RecipeComponentBuilderMap original, ReplacementMatchInfo match, Object with) { - for (var e : original.holders) { - if (e.replace(cx, recipe, match, with)) { - original.hasChanged = true; + public Map replace(Context cx, KubeRecipe recipe, Map original, ReplacementMatchInfo match, Object with) { + var replaced = original; + + for (var e : original.values()) { + var r = e.key.component.replace(cx, recipe, Cast.to(e.value), match, with); + + if (r != e.value) { + if (replaced == original) { + replaced = new LinkedHashMap<>(original); + } + + replaced.put(e.key, new Value(e.key, e.index, r)); } } - return original; + return replaced; } @Override - public void buildUniqueId(UniqueIdBuilder builder, RecipeComponentBuilderMap value) { + public void buildUniqueId(UniqueIdBuilder builder, Map map) { boolean first = true; - for (var entry : value.entrySet()) { - if (entry.getValue() != null) { + for (var value : map.values()) { + if (value.value != null) { if (first) { first = false; } else { builder.appendSeparator(); } - entry.getKey().component.buildUniqueId(builder, Cast.to(entry.getValue())); + value.key.component.buildUniqueId(builder, Cast.to(value.value)); } } } @Override public String toString() { - return keys.stream().map(RecipeKey::toString).collect(Collectors.joining(", ", "builder<", ">")); - } - - @Override - public boolean checkValueHasChanged(RecipeComponentBuilderMap oldValue, RecipeComponentBuilderMap newValue) { - return newValue.hasChanged; + return keys.stream().map(Key::toString).collect(Collectors.joining(", ", "{", "}")); } } diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentValue.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentValue.java index a4a58da7a..4045c6488 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentValue.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentValue.java @@ -38,7 +38,7 @@ public boolean matches(Context cx, KubeRecipe recipe, ReplacementMatchInfo match public boolean replace(Context cx, KubeRecipe recipe, ReplacementMatchInfo match, Object with) { var newValue = value == null ? null : key.component.replace(cx, recipe, value, match, with); - if (key.component.checkValueHasChanged(value, newValue)) { + if (value != newValue) { value = newValue; write(); return true; diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentBuilderMap.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentValueMap.java similarity index 75% rename from src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentBuilderMap.java rename to src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentValueMap.java index 87e921ce2..45c721f4e 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentBuilderMap.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/RecipeComponentValueMap.java @@ -11,24 +11,13 @@ import java.util.Objects; import java.util.Set; -public class RecipeComponentBuilderMap extends AbstractMap, Object> { - public static final RecipeComponentBuilderMap EMPTY = new RecipeComponentBuilderMap(RecipeComponentValue.EMPTY_ARRAY); +public class RecipeComponentValueMap extends AbstractMap, Object> { + public static final RecipeComponentValueMap EMPTY = new RecipeComponentValueMap(RecipeComponentValue.EMPTY_ARRAY); public final RecipeComponentValue[] holders; private Set, Object>> holderSet; - public boolean hasChanged; - public RecipeComponentBuilderMap(RecipeComponentBuilder builder) { - this.holders = new RecipeComponentValue[builder.keys.size()]; - - for (int i = 0; i < holders.length; i++) { - this.holders[i] = new RecipeComponentValue<>(builder.keys.get(i), i); - } - - this.hasChanged = false; - } - - public RecipeComponentBuilderMap(RecipeComponentValue[] holders) { + public RecipeComponentValueMap(RecipeComponentValue[] holders) { this.holders = new RecipeComponentValue[holders.length]; for (int i = 0; i < holders.length; i++) { @@ -36,7 +25,7 @@ public RecipeComponentBuilderMap(RecipeComponentValue[] holders) { } } - public RecipeComponentBuilderMap(List> keys) { + public RecipeComponentValueMap(List> keys) { this.holders = new RecipeComponentValue[keys.size()]; for (int i = 0; i < holders.length; i++) { @@ -103,7 +92,7 @@ public int hashCode() { public boolean equals(Object o) { if (o == this) { return true; - } else if (o instanceof RecipeComponentBuilderMap map) { + } else if (o instanceof RecipeComponentValueMap map) { if (holders.length != map.holders.length) { return false; } else { diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeSchemaStorage.java b/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeSchemaStorage.java index 5ed7fcd04..4fee51eef 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeSchemaStorage.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeSchemaStorage.java @@ -7,6 +7,7 @@ import dev.latvian.mods.kubejs.plugin.KubeJSPlugin; import dev.latvian.mods.kubejs.plugin.KubeJSPlugins; import dev.latvian.mods.kubejs.recipe.component.RecipeComponent; +import dev.latvian.mods.kubejs.recipe.component.RecipeComponentBuilder; import dev.latvian.mods.kubejs.script.ScriptType; import dev.latvian.mods.kubejs.util.JsonUtils; import dev.latvian.mods.kubejs.util.RegistryAccessContainer; @@ -14,6 +15,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -130,6 +132,63 @@ public RecipeComponent getComponent(RegistryAccessContainer registries, Strin public RecipeComponent readComponent(RegistryAccessContainer registries, StringReader reader) throws Exception { reader.skipWhitespace(); + + if (!reader.canRead()) { + throw new IllegalArgumentException("Nothing to read"); + } + + if (reader.peek() == '{') { + reader.skip(); + + var keys = new ArrayList(); + + while (true) { + reader.skipWhitespace(); + + if (!reader.canRead()) { + throw new IllegalArgumentException("Expected key name"); + } + + var name = reader.readString(); + var optional = false; + var alwaysWrite = false; + + reader.skipWhitespace(); + + if (reader.canRead() && reader.peek() == '?') { + reader.skip(); + reader.skipWhitespace(); + optional = true; + } + + if (reader.canRead() && reader.peek() == '!') { + reader.skip(); + reader.skipWhitespace(); + alwaysWrite = true; + } + + reader.expect(':'); + reader.skipWhitespace(); + + var component = readComponent(registries, reader); + + keys.add(new RecipeComponentBuilder.Key(name, component, optional, alwaysWrite)); + + reader.skipWhitespace(); + + if (!reader.canRead()) { + throw new IllegalArgumentException("Unexpected EOL"); + } else if (reader.peek() == ',') { + reader.skip(); + } else if (reader.peek() == '}') { + reader.skip(); + break; + } + } + + return new RecipeComponentBuilder(keys); + } + var key = reader.readUnquotedString(); if (reader.canRead() && reader.peek() == ':') { @@ -148,7 +207,7 @@ public RecipeComponent readComponent(RegistryAccessContainer registries, Stri } if (component == null) { - throw new UnsupportedOperationException("Recipe Component '" + key + "' not found"); + throw new NullPointerException("Recipe Component '" + key + "' not found"); } reader.skipWhitespace(); diff --git a/src/main/java/dev/latvian/mods/kubejs/registry/BuilderTypeRegistry.java b/src/main/java/dev/latvian/mods/kubejs/registry/BuilderTypeRegistry.java index 854edf84f..fe4501817 100644 --- a/src/main/java/dev/latvian/mods/kubejs/registry/BuilderTypeRegistry.java +++ b/src/main/java/dev/latvian/mods/kubejs/registry/BuilderTypeRegistry.java @@ -1,7 +1,5 @@ package dev.latvian.mods.kubejs.registry; -import com.mojang.serialization.Codec; -import dev.latvian.mods.rhino.type.TypeInfo; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; @@ -19,10 +17,4 @@ interface Callback { default void addDefault(ResourceKey> registry, Class> builderType, BuilderFactory factory) { of(registry, reg -> reg.addDefault(builderType, factory)); } - - void serverRegistry(ResourceKey> registry, Codec directCodec, TypeInfo typeInfo); - - default void serverRegistry(ResourceKey> registry, Codec directCodec, Class type) { - serverRegistry(registry, directCodec, TypeInfo.of(type)); - } } diff --git a/src/main/java/dev/latvian/mods/kubejs/registry/BuilderTypeRegistryHandler.java b/src/main/java/dev/latvian/mods/kubejs/registry/BuilderTypeRegistryHandler.java index b65f1e368..8b7c2a13e 100644 --- a/src/main/java/dev/latvian/mods/kubejs/registry/BuilderTypeRegistryHandler.java +++ b/src/main/java/dev/latvian/mods/kubejs/registry/BuilderTypeRegistryHandler.java @@ -16,10 +16,11 @@ import java.util.Map; import java.util.function.Consumer; -public record BuilderTypeRegistryHandler(Map, Info> map) implements BuilderTypeRegistry { +public record BuilderTypeRegistryHandler(Map, Info> map) implements BuilderTypeRegistry, ServerRegistryRegistry { public static final Lazy, Info>> INFO = Lazy.of(() -> { var handler = new BuilderTypeRegistryHandler(new IdentityHashMap<>()); KubeJSPlugins.forEachPlugin(handler, KubeJSPlugin::registerBuilderTypes); + KubeJSPlugins.forEachPlugin(handler, KubeJSPlugin::registerServerRegistries); return handler.map; }); @@ -66,7 +67,7 @@ public void of(ResourceKey> registry, Consumer> call } @Override - public void serverRegistry(ResourceKey> registry, Codec directCodec, TypeInfo typeInfo) { + public void register(ResourceKey> registry, Codec directCodec, TypeInfo typeInfo) { var info = map.computeIfAbsent(registry, k -> new Info<>()); info.directCodec = (Codec) directCodec; info.typeInfo = typeInfo == null ? TypeInfo.NONE : typeInfo; diff --git a/src/main/java/dev/latvian/mods/kubejs/registry/ServerRegistryRegistry.java b/src/main/java/dev/latvian/mods/kubejs/registry/ServerRegistryRegistry.java new file mode 100644 index 000000000..a0079ef08 --- /dev/null +++ b/src/main/java/dev/latvian/mods/kubejs/registry/ServerRegistryRegistry.java @@ -0,0 +1,14 @@ +package dev.latvian.mods.kubejs.registry; + +import com.mojang.serialization.Codec; +import dev.latvian.mods.rhino.type.TypeInfo; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; + +public interface ServerRegistryRegistry { + void register(ResourceKey> registry, Codec directCodec, TypeInfo typeInfo); + + default void register(ResourceKey> registry, Codec directCodec, Class type) { + register(registry, directCodec, TypeInfo.of(type)); + } +} diff --git a/src/main/java/dev/latvian/mods/kubejs/server/BasicCommandKubeEvent.java b/src/main/java/dev/latvian/mods/kubejs/server/BasicCommandKubeEvent.java index ec71151d2..1055a07f8 100644 --- a/src/main/java/dev/latvian/mods/kubejs/server/BasicCommandKubeEvent.java +++ b/src/main/java/dev/latvian/mods/kubejs/server/BasicCommandKubeEvent.java @@ -3,6 +3,7 @@ import dev.latvian.mods.kubejs.entity.KubeEntityEvent; import dev.latvian.mods.kubejs.level.BlockContainerJS; import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; import org.jetbrains.annotations.Nullable; @@ -10,6 +11,7 @@ public class BasicCommandKubeEvent implements KubeEntityEvent { private final Level level; private final Entity entity; + private final ServerPlayer serverPlayer; private final BlockPos pos; public final String id; public final String input; @@ -17,6 +19,7 @@ public class BasicCommandKubeEvent implements KubeEntityEvent { public BasicCommandKubeEvent(Level level, @Nullable Entity entity, BlockPos pos, String id, String input) { this.level = level; this.entity = entity; + this.serverPlayer = entity instanceof ServerPlayer p ? p : null; this.pos = pos; this.id = id; this.input = input; @@ -32,10 +35,17 @@ public Level getLevel() { } @Override + @Nullable public Entity getEntity() { return entity; } + @Override + @Nullable + public ServerPlayer getPlayer() { + return serverPlayer; + } + public BlockContainerJS getBlock() { return this.getLevel().kjs$getBlock(pos); } diff --git a/src/main/java/dev/latvian/mods/kubejs/util/ID.java b/src/main/java/dev/latvian/mods/kubejs/util/ID.java index f5d505bee..83b754634 100644 --- a/src/main/java/dev/latvian/mods/kubejs/util/ID.java +++ b/src/main/java/dev/latvian/mods/kubejs/util/ID.java @@ -62,7 +62,7 @@ static ResourceLocation of(@Nullable Object o, boolean preferKJS) { } else if (o instanceof ResourceKey key) { return key.location(); } else if (o instanceof Holder holder) { - return holder.unwrapKey().get().location(); + return holder.getKey().location(); } else if (o instanceof RegistryObjectKJS key) { return key.kjs$getIdLocation(); } diff --git a/src/main/java/dev/latvian/mods/kubejs/util/registrypredicate/RegistryHolderPredicate.java b/src/main/java/dev/latvian/mods/kubejs/util/registrypredicate/RegistryHolderPredicate.java index 85c1f7f8e..5b1d182f1 100644 --- a/src/main/java/dev/latvian/mods/kubejs/util/registrypredicate/RegistryHolderPredicate.java +++ b/src/main/java/dev/latvian/mods/kubejs/util/registrypredicate/RegistryHolderPredicate.java @@ -14,7 +14,7 @@ public String toString() { if (value instanceof Holder.Reference ref) { return ref.key().location().toString(); } else { - return value.unwrapKey().get().location().toString(); + return value.getKey().location().toString(); } } catch (Exception ex) { return String.valueOf(value.value()); diff --git a/src/main/java/dev/latvian/mods/kubejs/util/registrypredicate/RegistryNamespacePredicate.java b/src/main/java/dev/latvian/mods/kubejs/util/registrypredicate/RegistryNamespacePredicate.java index 1fbd5c41e..0d413248a 100644 --- a/src/main/java/dev/latvian/mods/kubejs/util/registrypredicate/RegistryNamespacePredicate.java +++ b/src/main/java/dev/latvian/mods/kubejs/util/registrypredicate/RegistryNamespacePredicate.java @@ -8,7 +8,7 @@ public boolean test(Holder holder) { if (holder instanceof Holder.Reference ref) { return ref.key().location().getNamespace().equals(namespace); } else { - return holder.unwrapKey().get().location().getNamespace().equals(namespace); + return holder.getKey().location().getNamespace().equals(namespace); } } diff --git a/src/main/java/dev/latvian/mods/kubejs/util/registrypredicate/RegistryRegExpPredicate.java b/src/main/java/dev/latvian/mods/kubejs/util/registrypredicate/RegistryRegExpPredicate.java index a1fcd4d11..1d487e7f0 100644 --- a/src/main/java/dev/latvian/mods/kubejs/util/registrypredicate/RegistryRegExpPredicate.java +++ b/src/main/java/dev/latvian/mods/kubejs/util/registrypredicate/RegistryRegExpPredicate.java @@ -12,7 +12,7 @@ public boolean test(Holder holder) { if (holder instanceof Holder.Reference ref) { return pattern.matcher(ref.key().location().toString()).find(); } else { - return pattern.matcher(holder.unwrapKey().get().location().toString()).find(); + return pattern.matcher(holder.getKey().location().toString()).find(); } } catch (Exception ex) { return false;