More KubeJS optimizations

This commit is contained in:
embeddedt 2023-02-20 11:25:39 -05:00
parent 02230095b7
commit c7f2d41695
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
9 changed files with 151 additions and 8 deletions

View File

@ -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

View File

@ -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<ItemStackJS> getCachedStacks();
}

View File

@ -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<ItemStackJS> getStacks();
@Override
public Set<ItemStackJS> getCachedStacks() {
Set<ItemStackJS> itemSet = KubeUtil.ingredientItemCache.get(this.ingredient);
if(itemSet == null) {
itemSet = this.getStacks();
KubeUtil.ingredientItemCache.put(this.ingredient, itemSet);
}
return itemSet;
}
}

View File

@ -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;
}
}

View File

@ -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<RecipeJS> originalRecipes;
@Shadow(remap = false) @Final private List<RecipeJS> 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<ResourceLocation, JsonObject> 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<ResourceLocation, JsonObject> jsonMap, CallbackInfo ci) {
KubeUtil.originalRecipesByHash.clear();
}
}

View File

@ -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<ItemStackJS> givenStacks = ((ICachedIngredientJS)target).getCachedStacks();
for(ItemStackJS stack : givenStacks) {
if(given.test(stack))
return true;
}
return false;
}
}
}

View File

@ -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<Item> getActualTag();
@Shadow public abstract Set<ItemStackJS> 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<ItemStackJS> getCachedStacks() {
Tag<Item> ourTag = this.getActualTag();
Set<ItemStackJS> itemSet = KubeUtil.tagItemCache.get(ourTag);
if(itemSet == null) {
itemSet = this.getStacks();
KubeUtil.tagItemCache.put(ourTag, itemSet);
}
return itemSet;
}
}

View File

@ -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<String, Set<ResourceLocation>> matchedIdsForRegex = new HashMap<>();
public static final HashMap<ResourceLocation, RecipeJS> originalRecipesByHash = new HashMap<>();
public static Map<Ingredient, Set<ItemStackJS>> ingredientItemCache = Collections.synchronizedMap(new WeakHashMap<>());
public static Map<Tag<Item>, Set<ItemStackJS>> tagItemCache = Collections.synchronizedMap(new WeakHashMap<>());
@SubscribeEvent
public static void clearRegexCache(AddReloadListenerEvent event) {
matchedIdsForRegex.clear();
ingredientItemCache.clear();
tagItemCache.clear();
}
}

View File

@ -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",