From c7f2d41695a7840a4254b8ae79a90b7565ebae0d Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 20 Feb 2023 11:25:39 -0500 Subject: [PATCH] More KubeJS optimizations --- .../org/embeddedt/modernfix/ModernFix.java | 4 +++ .../modernfix/duck/ICachedIngredientJS.java | 14 +++++++++ .../perf/kubejs/CustomIngredientMixin.java | 28 +++++++++++++++++ .../mixin/perf/kubejs/IDFilterMixin.java | 30 +++++++++++++++++++ .../mixin/perf/kubejs/RecipeEventJSMixin.java | 22 +++++++++++++- .../mixin/perf/kubejs/RecipeJSMixin.java | 21 +++++++++++++ .../perf/kubejs/TagIngredientJSMixin.java | 19 +++++++++++- .../embeddedt/modernfix/util/KubeUtil.java | 17 +++++++---- src/main/resources/modernfix.mixins.json | 4 ++- 9 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/duck/ICachedIngredientJS.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/CustomIngredientMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/IDFilterMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index 7e5a53fd..3e4ee13a 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -5,6 +5,7 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.ExtensionPoint; +import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; @@ -17,6 +18,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.core.config.ModernFixConfig; import org.embeddedt.modernfix.structure.AsyncLocator; +import org.embeddedt.modernfix.util.KubeUtil; import java.lang.management.ManagementFactory; @@ -42,6 +44,8 @@ public class ModernFix { DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> MinecraftForge.EVENT_BUS.register(new ModernFixClient())); ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG); + if(ModList.get().isLoaded("kubejs")) + MinecraftForge.EVENT_BUS.register(KubeUtil.class); } @SubscribeEvent diff --git a/src/main/java/org/embeddedt/modernfix/duck/ICachedIngredientJS.java b/src/main/java/org/embeddedt/modernfix/duck/ICachedIngredientJS.java new file mode 100644 index 00000000..31519af6 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/duck/ICachedIngredientJS.java @@ -0,0 +1,14 @@ +package org.embeddedt.modernfix.duck; + +import dev.latvian.kubejs.item.ItemStackJS; + +import java.util.Set; + +public interface ICachedIngredientJS { + /** + * Returns a cached list of item stacks for the given ingredient. The user must not attempt to modify any contents + * of these stacks. + * @return cached set of stacks + */ + Set getCachedStacks(); +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/CustomIngredientMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/CustomIngredientMixin.java new file mode 100644 index 00000000..8257fa5e --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/CustomIngredientMixin.java @@ -0,0 +1,28 @@ +package org.embeddedt.modernfix.mixin.perf.kubejs; + +import dev.latvian.kubejs.item.ItemStackJS; +import dev.latvian.kubejs.item.ingredient.CustomIngredient; +import net.minecraft.world.item.crafting.Ingredient; +import org.embeddedt.modernfix.duck.ICachedIngredientJS; +import org.embeddedt.modernfix.util.KubeUtil; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import java.util.Set; + +@Mixin(CustomIngredient.class) +public abstract class CustomIngredientMixin implements ICachedIngredientJS { + @Shadow @Final private Ingredient ingredient; + + @Shadow public abstract Set getStacks(); + + @Override + public Set getCachedStacks() { + Set itemSet = KubeUtil.ingredientItemCache.get(this.ingredient); + if(itemSet == null) { + itemSet = this.getStacks(); + KubeUtil.ingredientItemCache.put(this.ingredient, itemSet); + } + return itemSet; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/IDFilterMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/IDFilterMixin.java new file mode 100644 index 00000000..c3a962ef --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/IDFilterMixin.java @@ -0,0 +1,30 @@ +package org.embeddedt.modernfix.mixin.perf.kubejs; + +import dev.latvian.kubejs.recipe.RecipeJS; +import dev.latvian.kubejs.recipe.filter.IDFilter; +import net.minecraft.resources.ResourceLocation; +import org.embeddedt.modernfix.util.KubeUtil; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(IDFilter.class) +public class IDFilterMixin { + @Shadow @Final private ResourceLocation id; + private RecipeJS _target; + private boolean _targetSearched = false; + + /** + * @author embeddedt + * @reason avoid scanning every recipe + */ + @Overwrite(remap = false) + public boolean test(RecipeJS recipe) { + if(!_targetSearched) { + _target = KubeUtil.originalRecipesByHash.get(this.id); + _targetSearched = true; + } + return recipe == _target; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java index d6b49c95..45fe65cd 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeEventJSMixin.java @@ -1,22 +1,30 @@ package org.embeddedt.modernfix.mixin.perf.kubejs; +import com.google.gson.JsonObject; import cpw.mods.modlauncher.api.LamdbaExceptionUtils; import dev.latvian.kubejs.recipe.RecipeEventJS; import dev.latvian.kubejs.recipe.RecipeJS; import dev.latvian.kubejs.recipe.filter.RecipeFilter; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.crafting.RecipeManager; +import org.embeddedt.modernfix.util.KubeUtil; import org.embeddedt.modernfix.util.ModUtil; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.List; +import java.util.Map; import java.util.function.Consumer; import java.util.stream.Collectors; @Mixin(RecipeEventJS.class) public class RecipeEventJSMixin { - @Shadow @Final private List originalRecipes; + @Shadow(remap = false) @Final private List originalRecipes; /** * @author embeddedt @@ -31,4 +39,16 @@ public class RecipeEventJSMixin { filtered.forEach(consumer); } } + + @Inject(method = "post(Lnet/minecraft/world/item/crafting/RecipeManager;Ljava/util/Map;)V", at = @At(value = "INVOKE", target = "Ldev/latvian/kubejs/recipe/RecipeEventJS;post(Ldev/latvian/kubejs/script/ScriptType;Ljava/lang/String;)Z", remap = false)) + private void buildRecipeRegistry(RecipeManager manager, Map jsonMap, CallbackInfo ci) { + for(RecipeJS recipe : this.originalRecipes) { + KubeUtil.originalRecipesByHash.put(recipe.getOrCreateId(), recipe); + } + } + + @Inject(method = "post(Lnet/minecraft/world/item/crafting/RecipeManager;Ljava/util/Map;)V", at = @At("RETURN")) + private void clearRecipeRegistry(RecipeManager manager, Map jsonMap, CallbackInfo ci) { + KubeUtil.originalRecipesByHash.clear(); + } } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeJSMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeJSMixin.java index 9b04fa90..e15b7b54 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeJSMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/RecipeJSMixin.java @@ -1,12 +1,18 @@ package org.embeddedt.modernfix.mixin.perf.kubejs; +import dev.latvian.kubejs.item.ItemStackJS; +import dev.latvian.kubejs.item.ingredient.IngredientJS; +import dev.latvian.kubejs.item.ingredient.TagIngredientJS; import dev.latvian.kubejs.recipe.RecipeJS; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Recipe; +import org.embeddedt.modernfix.duck.ICachedIngredientJS; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; +import java.util.Set; + @Mixin(RecipeJS.class) public class RecipeJSMixin { /** @@ -19,4 +25,19 @@ public class RecipeJSMixin { return recipe.getResultItem(); } } + + @Redirect(method = "*", at = @At(value = "INVOKE", target = "Ldev/latvian/kubejs/item/ingredient/IngredientJS;anyStackMatches(Ldev/latvian/kubejs/item/ingredient/IngredientJS;)Z", remap = false)) + private boolean optimizeMatching(IngredientJS target, IngredientJS given) { + if((target instanceof TagIngredientJS && given instanceof ItemStackJS) || !(target instanceof ICachedIngredientJS)) { + /* we already have an optimized code path for this */ + return target.anyStackMatches(given); + } else { + Set givenStacks = ((ICachedIngredientJS)target).getCachedStacks(); + for(ItemStackJS stack : givenStacks) { + if(given.test(stack)) + return true; + } + return false; + } + } } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java index 080ef036..88a75047 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java @@ -5,16 +5,22 @@ import dev.latvian.kubejs.item.ingredient.IngredientJS; import dev.latvian.kubejs.item.ingredient.TagIngredientJS; import net.minecraft.tags.Tag; import net.minecraft.world.item.Item; +import org.embeddedt.modernfix.duck.ICachedIngredientJS; +import org.embeddedt.modernfix.util.KubeUtil; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.util.Set; + @Mixin(TagIngredientJS.class) -public abstract class TagIngredientJSMixin { +public abstract class TagIngredientJSMixin implements ICachedIngredientJS { @Shadow public abstract Tag getActualTag(); + @Shadow public abstract Set getStacks(); + /** * @author embeddedt * @reason avoid pointless construction of many ItemStack objects @@ -25,4 +31,15 @@ public abstract class TagIngredientJSMixin { cir.setReturnValue(((ItemStackJS)ingredient).getItem().is(this.getActualTag())); } } + + @Override + public Set getCachedStacks() { + Tag ourTag = this.getActualTag(); + Set itemSet = KubeUtil.tagItemCache.get(ourTag); + if(itemSet == null) { + itemSet = this.getStacks(); + KubeUtil.tagItemCache.put(ourTag, itemSet); + } + return itemSet; + } } diff --git a/src/main/java/org/embeddedt/modernfix/util/KubeUtil.java b/src/main/java/org/embeddedt/modernfix/util/KubeUtil.java index 1f453d47..2df2f735 100644 --- a/src/main/java/org/embeddedt/modernfix/util/KubeUtil.java +++ b/src/main/java/org/embeddedt/modernfix/util/KubeUtil.java @@ -1,20 +1,27 @@ package org.embeddedt.modernfix.util; +import dev.latvian.kubejs.item.ItemStackJS; +import dev.latvian.kubejs.recipe.RecipeJS; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.Tag; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.event.AddReloadListenerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import org.embeddedt.modernfix.ModernFix; -import java.util.HashMap; -import java.util.Set; +import java.util.*; -@Mod.EventBusSubscriber(modid = ModernFix.MODID) public class KubeUtil { public static final HashMap> matchedIdsForRegex = new HashMap<>(); + public static final HashMap originalRecipesByHash = new HashMap<>(); + public static Map> ingredientItemCache = Collections.synchronizedMap(new WeakHashMap<>()); + public static Map, Set> tagItemCache = Collections.synchronizedMap(new WeakHashMap<>()); + @SubscribeEvent public static void clearRegexCache(AddReloadListenerEvent event) { matchedIdsForRegex.clear(); + ingredientItemCache.clear(); + tagItemCache.clear(); } } diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index eb6d129c..06b9688f 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -45,7 +45,9 @@ "perf.kubejs.TagIngredientJSMixin", "perf.kubejs.TagWrapperMixin", "perf.kubejs.RecipeEventJSMixin", - "perf.kubejs.RecipeJSMixin" + "perf.kubejs.RecipeJSMixin", + "perf.kubejs.IDFilterMixin", + "perf.kubejs.CustomIngredientMixin" ], "client": [ "feature.measure_time.MinecraftMixin",