diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_loot_loading/ForgeHooksMixin.java b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_loot_loading/ForgeHooksMixin.java new file mode 100644 index 00000000..5d1340db --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_loot_loading/ForgeHooksMixin.java @@ -0,0 +1,57 @@ +package org.embeddedt.modernfix.common.mixin.perf.faster_loot_loading; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraftforge.common.ForgeHooks; +import org.apache.commons.lang3.function.TriFunction; +import org.apache.logging.log4j.Logger; +import org.embeddedt.modernfix.annotation.FeatureLevel; +import org.embeddedt.modernfix.annotation.RequiresFeatureLevel; +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 java.util.Optional; + +import static net.minecraftforge.common.ForgeHooks.loadLootTable; + +@Mixin(value = ForgeHooks.class, remap = false) +@RequiresFeatureLevel(FeatureLevel.BETA) +public class ForgeHooksMixin { + @Shadow + @Final + private static Logger LOGGER; + + private static boolean mfix$isVanillaTable(JsonElement data) { + if (!(data instanceof JsonObject obj)) { + return false; + } + var vanillaMarker = obj.getAsJsonPrimitive("mfix$isVanillaTable"); + if (vanillaMarker == null) { + return false; + } + return vanillaMarker.getAsBoolean(); + } + + /** + * @author embeddedt + * @reason avoid getResource() call per loot table by using injected marker + */ + @Overwrite + public static TriFunction> getLootTableDeserializer(Gson gson, String directory) { + return (location, data, resourceManager) -> { + try { + boolean custom = !mfix$isVanillaTable(data); + return Optional.ofNullable(loadLootTable(gson, location, data, custom)); + } catch (Exception exception) { + LOGGER.error("Couldn't parse element {}:{}", directory, location, exception); + return Optional.empty(); + } + }; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_loot_loading/LootDataManagerMixin.java b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_loot_loading/LootDataManagerMixin.java new file mode 100644 index 00000000..741c8458 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_loot_loading/LootDataManagerMixin.java @@ -0,0 +1,41 @@ +package org.embeddedt.modernfix.common.mixin.perf.faster_loot_loading; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.resources.FileToIdConverter; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.world.level.storage.loot.LootDataManager; +import net.minecraft.world.level.storage.loot.LootDataType; +import org.embeddedt.modernfix.annotation.FeatureLevel; +import org.embeddedt.modernfix.annotation.RequiresFeatureLevel; +import org.spongepowered.asm.mixin.Mixin; +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.Map; + +@Mixin(LootDataManager.class) +@RequiresFeatureLevel(FeatureLevel.BETA) +public class LootDataManagerMixin { + /** + * @author embeddedt + * @reason inject a marker for vanilla loot tables into the JSON so that we can retrieve it from the deserializer + */ + @Inject(method = "lambda$scheduleElementParse$5", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/packs/resources/SimpleJsonResourceReloadListener;scanDirectory(Lnet/minecraft/server/packs/resources/ResourceManager;Ljava/lang/String;Lcom/google/gson/Gson;Ljava/util/Map;)V", shift = At.Shift.AFTER)) + private static void mfix$scanAndCapture(ResourceManager resourceManager, LootDataType lootDataType, Map map, CallbackInfo ci, + @Local(ordinal = 1) Map lootTables) { + FileToIdConverter converter = FileToIdConverter.json(lootDataType.directory()); + var lootTableResourceMap = converter.listMatchingResources(resourceManager); + for (var entry : lootTableResourceMap.entrySet()) { + if (lootTables.get(converter.fileToId(entry.getKey())) instanceof JsonObject obj) { + var resource = entry.getValue(); + if (resource != null && !resource.isBuiltin()) { + obj.addProperty("mfix$isVanillaTable", true); + } + } + } + } +}