From 62d1695c32b70f32ddce79200c7d3ab7e836ebd9 Mon Sep 17 00:00:00 2001 From: FalsePattern Date: Sat, 6 Jan 2024 22:09:41 +0100 Subject: [PATCH] miscellaneous performance fixes --- .../com/falsepattern/lumina/api/LumiAPI.java | 2 +- .../lumina/api/world/LumiWorldWrapper.java | 2 +- .../falsepattern/lumina/internal/LUMINA.java | 9 +++ .../internal/mixin/hook/LightingHooks.java | 59 ++++++++++++++----- .../mixin/interfaces/LumiWorldRootCache.java | 27 +++++++++ .../common/lumi/LumiWorldRootImplMixin.java | 20 ++++++- .../internal/world/WorldProviderManager.java | 34 +++++++---- 7 files changed, 124 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/falsepattern/lumina/internal/mixin/interfaces/LumiWorldRootCache.java diff --git a/src/main/java/com/falsepattern/lumina/api/LumiAPI.java b/src/main/java/com/falsepattern/lumina/api/LumiAPI.java index be5f286..acc312e 100644 --- a/src/main/java/com/falsepattern/lumina/api/LumiAPI.java +++ b/src/main/java/com/falsepattern/lumina/api/LumiAPI.java @@ -42,7 +42,7 @@ private LumiAPI() { throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); } - public static @NotNull Iterable lumiWorldsFromBaseWorld(@NotNull World worldBase) { + public static @NotNull LumiWorld[] lumiWorldsFromBaseWorld(@NotNull World worldBase) { return WORLD_WRAPPER.lumiWorldsFromBaseWorld(worldBase); } diff --git a/src/main/java/com/falsepattern/lumina/api/world/LumiWorldWrapper.java b/src/main/java/com/falsepattern/lumina/api/world/LumiWorldWrapper.java index e76642b..6784270 100644 --- a/src/main/java/com/falsepattern/lumina/api/world/LumiWorldWrapper.java +++ b/src/main/java/com/falsepattern/lumina/api/world/LumiWorldWrapper.java @@ -24,5 +24,5 @@ @SuppressWarnings("unused") public interface LumiWorldWrapper { - @NotNull @Unmodifiable Iterable lumiWorldsFromBaseWorld(@Nullable World worldBase); + @NotNull @Unmodifiable LumiWorld[] lumiWorldsFromBaseWorld(@Nullable World worldBase); } diff --git a/src/main/java/com/falsepattern/lumina/internal/LUMINA.java b/src/main/java/com/falsepattern/lumina/internal/LUMINA.java index 3446328..2e98c51 100644 --- a/src/main/java/com/falsepattern/lumina/internal/LUMINA.java +++ b/src/main/java/com/falsepattern/lumina/internal/LUMINA.java @@ -17,12 +17,14 @@ package com.falsepattern.lumina.internal; +import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import com.falsepattern.chunk.api.DataRegistry; +import com.falsepattern.falsetweaks.api.ThreadedChunkUpdates; import lombok.NoArgsConstructor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -46,8 +48,15 @@ public static Logger createLogger(String name) { return LogManager.getLogger(MOD_NAME + "|" + name); } + private static boolean falseTweaks; @Mod.EventHandler public void preInit(FMLPreInitializationEvent evt) { + falseTweaks = Loader.isModLoaded("falsetweaks"); + } + + + public static boolean lumi$isThreadedUpdates() { + return falseTweaks && ThreadedChunkUpdates.isEnabled(); } @Mod.EventHandler diff --git a/src/main/java/com/falsepattern/lumina/internal/mixin/hook/LightingHooks.java b/src/main/java/com/falsepattern/lumina/internal/mixin/hook/LightingHooks.java index 928b798..f1afe00 100644 --- a/src/main/java/com/falsepattern/lumina/internal/mixin/hook/LightingHooks.java +++ b/src/main/java/com/falsepattern/lumina/internal/mixin/hook/LightingHooks.java @@ -19,11 +19,14 @@ import com.falsepattern.lumina.api.LumiChunkAPI; import com.falsepattern.lumina.api.lighting.LightType; +import com.falsepattern.lumina.api.world.LumiWorld; import com.falsepattern.lumina.api.world.LumiWorldRoot; import cpw.mods.fml.relauncher.SideOnly; import lombok.experimental.UtilityClass; import lombok.val; import lombok.var; +import org.jetbrains.annotations.NotNull; + import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; @@ -56,7 +59,9 @@ public static int getCurrentLightValue(Chunk chunkBase, val posZ = (chunkBase.zPosition << 4) + subChunkPosZ; var maxLightValue = 0; - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val lightingEngine = world.lumi$lightingEngine(); val lightValue = lightingEngine.getCurrentLightValue(lightType, posX, posY, posZ); maxLightValue = Math.max(maxLightValue, lightValue); @@ -75,7 +80,9 @@ public static int getCurrentLightValueUncached(Chunk chunkBase, val posZ = (chunkBase.zPosition << 4) + subChunkPosZ; var maxLightValue = 0; - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val lightingEngine = world.lumi$lightingEngine(); val lightValue = lightingEngine.getCurrentLightValueUncached(lightType, posX, posY, posZ); maxLightValue = Math.max(maxLightValue, lightValue); @@ -94,7 +101,9 @@ public static int getMaxBrightness(Chunk chunkBase, val posZ = (chunkBase.zPosition << 4) + subChunkPosZ; var maxLightValue = 0; - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val lightValue = world.lumi$getBrightness(lightType, posX, posY, posZ); maxLightValue = Math.max(maxLightValue, lightValue); } @@ -105,7 +114,9 @@ public static boolean isChunkFullyLit(Chunk chunkBase) { val worldBase = chunkBase.worldObj; var chunkHasLighting = true; - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val lightingEngine = world.lumi$lightingEngine(); val chunk = world.lumi$wrap(chunkBase); chunkHasLighting &= lightingEngine.isChunkFullyLit(chunk); @@ -117,7 +128,9 @@ public static void handleChunkInit(Chunk chunkBase) { val worldBase = chunkBase.worldObj; resetPrecipitationHeightMap(chunkBase); - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val chunk = world.lumi$wrap(chunkBase); LumiChunkAPI.scheduleChunkLightingEngineInit(chunk); } @@ -128,7 +141,9 @@ public static void handleClientChunkInit(Chunk chunkBase) { val worldBase = chunkBase.worldObj; resetPrecipitationHeightMap(chunkBase); - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val lightingEngine = world.lumi$lightingEngine(); val chunk = world.lumi$wrap(chunkBase); lightingEngine.handleClientChunkInit(chunk); @@ -138,7 +153,9 @@ public static void handleClientChunkInit(Chunk chunkBase) { public static void handleSubChunkInit(Chunk chunkBase, ExtendedBlockStorage subChunkBase) { val worldBase = chunkBase.worldObj; - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val lightingEngine = world.lumi$lightingEngine(); val chunk = world.lumi$wrap(chunkBase); val subChunk = world.lumi$wrap(subChunkBase); @@ -149,7 +166,9 @@ public static void handleSubChunkInit(Chunk chunkBase, ExtendedBlockStorage subC public static void handleSubChunkInit(Chunk chunkBase, int chunkPosY) { val worldBase = chunkBase.worldObj; - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val lightingEngine = world.lumi$lightingEngine(); val chunk = world.lumi$wrap(chunkBase); val subChunk = chunk.lumi$getSubChunk(chunkPosY); @@ -160,7 +179,9 @@ public static void handleSubChunkInit(Chunk chunkBase, int chunkPosY) { public static void handleChunkLoad(Chunk chunkBase) { val worldBase = chunkBase.worldObj; - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val lightingEngine = world.lumi$lightingEngine(); val chunk = world.lumi$wrap(chunkBase); lightingEngine.handleChunkLoad(chunk); @@ -172,7 +193,9 @@ public static void doRandomChunkLightingUpdates(Chunk chunkBase) { // return; // // val worldBase = chunkBase.worldObj; -// for (val world : lumiWorldsFromBaseWorld(worldBase)) { +// @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); +// for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { +// var world = lumiWorldsFromBaseWorld[i]; // val chunk = world.lumi$wrap(chunkBase); // val lightingEngine = world.lumi$lightingEngine(); // lightingEngine.doRandomChunkLightingUpdates(chunk); @@ -182,7 +205,9 @@ public static void doRandomChunkLightingUpdates(Chunk chunkBase) { public static void resetQueuedRandomLightUpdates(Chunk chunkBase) { val worldBase = chunkBase.worldObj; - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val chunk = world.lumi$wrap(chunkBase); chunk.lumi$resetQueuedRandomLightUpdates(); } @@ -196,7 +221,9 @@ public static void updateLightingForBlock(Chunk chunkBase, val posX = (chunkBase.xPosition << 4) + subChunkPosX; val posZ = (chunkBase.zPosition << 4) + subChunkPosZ; - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val lightingEngine = world.lumi$lightingEngine(); lightingEngine.updateLightingForBlock(posX, posY, posZ); } @@ -208,7 +235,9 @@ public static void scheduleLightingUpdate(World worldBase, int posY, int posZ) { val lightType = LightType.of(baseLightType); - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val lightingEngine = world.lumi$lightingEngine(); lightingEngine.scheduleLightingUpdate(lightType, posX, posY, posZ); } @@ -220,7 +249,9 @@ public static void processLightUpdates(Chunk chunkBase) { } public static void processLightUpdates(World worldBase) { - for (val world : lumiWorldsFromBaseWorld(worldBase)) { + @NotNull LumiWorld[] lumiWorldsFromBaseWorld = lumiWorldsFromBaseWorld(worldBase); + for (int i = 0; i < lumiWorldsFromBaseWorld.length; i++) { + var world = lumiWorldsFromBaseWorld[i]; val lightingEngine = world.lumi$lightingEngine(); lightingEngine.processLightingUpdatesForAllTypes(); } diff --git a/src/main/java/com/falsepattern/lumina/internal/mixin/interfaces/LumiWorldRootCache.java b/src/main/java/com/falsepattern/lumina/internal/mixin/interfaces/LumiWorldRootCache.java new file mode 100644 index 0000000..60d42ae --- /dev/null +++ b/src/main/java/com/falsepattern/lumina/internal/mixin/interfaces/LumiWorldRootCache.java @@ -0,0 +1,27 @@ +/* + * This file is part of LUMINA. + * + * LUMINA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LUMINA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with LUMINA. If not, see . + */ + +package com.falsepattern.lumina.internal.mixin.interfaces; + +import com.falsepattern.lumina.api.world.LumiWorld; + +import java.util.Iterator; + +public interface LumiWorldRootCache { + LumiWorld[] lumi$getLumiWorlds(); + void lumi$setLumiWorlds(LumiWorld[] lumiWorlds); +} diff --git a/src/main/java/com/falsepattern/lumina/internal/mixin/mixins/common/lumi/LumiWorldRootImplMixin.java b/src/main/java/com/falsepattern/lumina/internal/mixin/mixins/common/lumi/LumiWorldRootImplMixin.java index 0d35114..5cedaf3 100644 --- a/src/main/java/com/falsepattern/lumina/internal/mixin/mixins/common/lumi/LumiWorldRootImplMixin.java +++ b/src/main/java/com/falsepattern/lumina/internal/mixin/mixins/common/lumi/LumiWorldRootImplMixin.java @@ -20,10 +20,13 @@ import com.falsepattern.falsetweaks.api.ThreadedChunkUpdates; import com.falsepattern.lumina.api.cache.LumiBlockCacheRoot; import com.falsepattern.lumina.api.chunk.LumiChunkRoot; +import com.falsepattern.lumina.api.world.LumiWorld; import com.falsepattern.lumina.api.world.LumiWorldRoot; +import com.falsepattern.lumina.internal.LUMINA; import com.falsepattern.lumina.internal.cache.MultiHeadBlockCacheRoot; import com.falsepattern.lumina.internal.cache.ReadThroughBlockCacheRoot; import com.falsepattern.lumina.internal.config.LumiConfig; +import com.falsepattern.lumina.internal.mixin.interfaces.LumiWorldRootCache; import com.falsepattern.lumina.internal.world.DefaultWorldProvider; import lombok.val; import net.minecraft.block.Block; @@ -50,12 +53,13 @@ @Unique @Mixin(value = World.class, priority = LUMI_ROOT_IMPL_MIXIN_PRIORITY) -public abstract class LumiWorldRootImplMixin implements IBlockAccess, LumiWorldRoot { +public abstract class LumiWorldRootImplMixin implements IBlockAccess, LumiWorldRoot, LumiWorldRootCache { // region Shadow @Final @Shadow public WorldProvider provider; + @Shadow protected IChunkProvider chunkProvider; @Shadow @@ -88,6 +92,18 @@ public abstract class LumiWorldRootImplMixin implements IBlockAccess, LumiWorldR private LumiBlockCacheRoot lumi$blockCacheRoot = null; + private LumiWorld[] lumi$lumiWorlds; + + @Override + public LumiWorld[] lumi$getLumiWorlds() { + return lumi$lumiWorlds; + } + + @Override + public void lumi$setLumiWorlds(LumiWorld[] lumiWorlds) { + lumi$lumiWorlds = lumiWorlds; + } + @Inject(method = LUMI_WORLD_INIT_HOOK_METHOD, at = @At("RETURN"), remap = false, @@ -99,7 +115,7 @@ private void lumiWorldRootInit(CallbackInfo ci) { } int cacheCount = LumiConfig.CACHE_COUNT; - if (cacheCount <= 0 || (Loader.isModLoaded("falsetweaks") && ThreadedChunkUpdates.isEnabled() && lumi$isClientSide())) { + if (cacheCount <= 0 || (LUMINA.lumi$isThreadedUpdates() && lumi$isClientSide())) { this.lumi$blockCacheRoot = new ReadThroughBlockCacheRoot(this); } else { this.lumi$blockCacheRoot = new MultiHeadBlockCacheRoot(this, cacheCount); diff --git a/src/main/java/com/falsepattern/lumina/internal/world/WorldProviderManager.java b/src/main/java/com/falsepattern/lumina/internal/world/WorldProviderManager.java index d8c5aaa..d211872 100644 --- a/src/main/java/com/falsepattern/lumina/internal/world/WorldProviderManager.java +++ b/src/main/java/com/falsepattern/lumina/internal/world/WorldProviderManager.java @@ -24,10 +24,13 @@ import com.falsepattern.lumina.internal.LumiDefaultValues; import com.falsepattern.lumina.internal.collection.WeakIdentityHashMap; import com.falsepattern.lumina.internal.event.EventPoster; +import com.falsepattern.lumina.internal.mixin.interfaces.LumiWorldRootCache; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import lombok.val; import net.minecraft.world.World; + +import lombok.var; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,7 +50,6 @@ public final class WorldProviderManager implements LumiWorldProviderRegistry, Lu private static final WorldProviderManager INSTANCE = new WorldProviderManager(); private final List worldProviders = new ArrayList<>(); - private final Map> providedWorlds = new WeakIdentityHashMap<>(); private boolean isRegistered = false; private boolean isHijacked = false; @@ -138,16 +140,22 @@ public void registerWorldProvider(@NotNull LumiWorldProvider worldProvider) { worldProviders.add(worldProvider); } + private static final LumiWorld[] NULL_ARR = new LumiWorld[0]; + @Override - public @NotNull @Unmodifiable Iterable lumiWorldsFromBaseWorld(@Nullable World worldBase) { + public @NotNull @Unmodifiable LumiWorld[] lumiWorldsFromBaseWorld(@Nullable World worldBase) { if (!isRegistered) { LOG.error(new IllegalStateException("No world providers exist during registration, " + "an empty iterable will be returned.")); - return Collections.emptyList(); + return NULL_ARR; } if (worldBase == null) - return Collections.emptyList(); - return providedWorlds.computeIfAbsent(worldBase, this::collectProvidedWorlds); + return NULL_ARR; + var worlds = ((LumiWorldRootCache)worldBase).lumi$getLumiWorlds(); + if (worlds == null) { + ((LumiWorldRootCache)worldBase).lumi$setLumiWorlds(worlds = collectProvidedWorlds(worldBase)); + } + return worlds; } public @Nullable LumiWorldProvider getWorldProviderByInternalID(int internalWorldProviderID) { @@ -160,11 +168,15 @@ public int worldProviderCount() { return worldProviders.size(); } - private Iterable collectProvidedWorlds(World worldBase) { - val worldList = worldProviders.stream() - .map(worldProvider -> worldProvider.provideWorld(worldBase)) - .filter(Objects::nonNull) - .collect(Collectors.toCollection(ArrayList::new)); - return Collections.unmodifiableList(worldList); + private LumiWorld[] collectProvidedWorlds(World worldBase) { + val worldList = new ArrayList(); + for (int i = 0, worldProvidersSize = worldProviders.size(); i < worldProvidersSize; i++) { + LumiWorldProvider worldProvider = worldProviders.get(i); + LumiWorld lumiWorld = worldProvider.provideWorld(worldBase); + if (lumiWorld != null) { + worldList.add(lumiWorld); + } + } + return worldList.toArray(new LumiWorld[0]); } }