diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java index fbdf99b7f..3ce9883fb 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java @@ -2,11 +2,9 @@ package com.seibel.distanthorizons.common.wrappers.world; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister; -import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelUnloadEvent; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; import com.seibel.distanthorizons.common.wrappers.block.ClientBlockStateColorCache; -import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.level.KeyedClientLevelManager; import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; @@ -15,21 +13,18 @@ import com.seibel.distanthorizons.core.level.*; import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; -import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.util.TimerUtil; import com.seibel.distanthorizons.core.world.AbstractDhWorld; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; -import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; -import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.ChunkAccess; import com.seibel.distanthorizons.core.logging.DhLogger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,17 +33,11 @@ import java.awt.*; import java.io.File; import java.io.IOException; import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.Map; -import java.util.WeakHashMap; +import java.util.*; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -#if MC_VER <= MC_1_20_4 -import net.minecraft.world.level.chunk.ChunkStatus; -#else -import net.minecraft.world.level.chunk.status.ChunkStatus; -#endif #if MC_VER < MC_1_21_3 import net.minecraft.world.phys.Vec3; @@ -86,7 +75,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper private volatile BlockStateWrapper dirtBlockWrapper; private volatile IDhLevel dhLevel; - private volatile long lastRenderTime = System.currentTimeMillis(); + private volatile long lastAccessTime = System.currentTimeMillis(); //=============// @@ -106,17 +95,14 @@ public class ClientLevelWrapper implements IClientLevelWrapper //region @Override - public synchronized void markRendered() { - this.lastRenderTime = System.currentTimeMillis(); - } - public synchronized long getLastRenderTime() { return this.lastRenderTime; } - public boolean isDhLevelLoaded() { - return this.dhLevel != null; + public synchronized void markAccessed() { + this.lastAccessTime = System.currentTimeMillis(); } + public synchronized long getLastAccessTime() { return this.lastAccessTime; } - private static final java.util.Timer CLIENT_CLEANUP_TIMER = com.seibel.distanthorizons.core.util.TimerUtil.CreateTimer("ClientLevelTickCleanup"); + private static final Timer CLIENT_CLEANUP_TIMER = TimerUtil.CreateTimer("ClientLevelTickCleanup"); - private static final java.util.TimerTask CLIENT_CLEANUP_TASK = com.seibel.distanthorizons.core.util.TimerUtil.createTimerTask(() -> com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper.tickCleanup()); + private static final TimerTask CLIENT_CLEANUP_TASK = TimerUtil.createTimerTask(ClientLevelWrapper::tickCleanup); static { @@ -124,24 +110,33 @@ public class ClientLevelWrapper implements IClientLevelWrapper CLIENT_CLEANUP_TIMER.scheduleAtFixedRate(CLIENT_CLEANUP_TASK, 0, 1000 / 20); } + private void unload() { + AbstractDhWorld world = SharedApi.getAbstractDhWorld(); + if (world != null) { + world.unloadLevel(this); + } else { + this.onUnload(); + } + } + public static void tickCleanup() { if (MINECRAFT.level == null) { return; } long currentTime = System.currentTimeMillis(); long timeout = 30 * 1000; - - java.util.List toUnload = new java.util.ArrayList<>(); + + List toUnload = new ArrayList<>(); synchronized(LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL) { - for (java.lang.ref.WeakReference ref : LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.values()) + for (WeakReference ref : LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.values()) { ClientLevelWrapper wrapper = ref.get(); - if (wrapper != null && wrapper.isDhLevelLoaded() && wrapper.level != MINECRAFT.level) + if (wrapper != null && wrapper.level != MINECRAFT.level) { - // We use the synchronized getter to prevent race conditions with markRendered() - if (currentTime - wrapper.getLastRenderTime() > timeout) + // We use the synchronized getter to prevent race conditions with markAccessed() + if (currentTime - wrapper.getLastAccessTime() > timeout) { toUnload.add(wrapper); } @@ -152,20 +147,13 @@ public class ClientLevelWrapper implements IClientLevelWrapper for (ClientLevelWrapper wrapper : toUnload) { // Re-verify all conditions inside a synchronized block on the wrapper - // to ensure atomicity with respect to markRendered() + // to ensure atomicity with respect to markAccessed() synchronized(wrapper) { - if (wrapper.isDhLevelLoaded() && wrapper.level != MINECRAFT.level && currentTime - wrapper.getLastRenderTime() > timeout) + if (wrapper.level != MINECRAFT.level && currentTime - wrapper.getLastAccessTime() > timeout) { LOGGER.debug("Unloading level " + wrapper.getDhIdentifier() + " due to inactivity"); - AbstractDhWorld world = SharedApi.getAbstractDhWorld(); - if (world != null) { - world.unloadLevel(wrapper); - ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(wrapper)); - } - if (wrapper.isDhLevelLoaded()) { - wrapper.onUnload(); - } + wrapper.unload(); } } } @@ -255,6 +243,17 @@ public class ClientLevelWrapper implements IClientLevelWrapper if (overrideLevel != null) { + WeakReference levelRef = LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.get(level); + if (levelRef != null && levelRef.get() != overrideLevel) + { + ClientLevelWrapper l = levelRef.get(); + if (l != null) l.unload(); + levelRef = null; + } + if (levelRef == null && overrideLevel instanceof ClientLevelWrapper) + { + LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.put(level, new WeakReference<>((ClientLevelWrapper) overrideLevel)); + } return overrideLevel; } } diff --git a/coreSubProjects b/coreSubProjects index dcb049d4c..949124f8d 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit dcb049d4c2cf0e46b1949982f3404b489b95f171 +Subproject commit 949124f8dc1b901aab54df4d5661727a52d6a66c diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLevelRenderer.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLevelRenderer.java index 3089f1d33..cfe545f5b 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLevelRenderer.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLevelRenderer.java @@ -194,11 +194,6 @@ public class MixinLevelRenderer ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrix); ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, this.level); - if (ClientApi.RENDER_STATE.clientLevelWrapper instanceof ClientLevelWrapper) - { - ((ClientLevelWrapper) ClientApi.RENDER_STATE.clientLevelWrapper).markRendered(); - } - // only crash during development if (ModInfo.IS_DEV_BUILD) { diff --git a/gradle.properties b/gradle.properties index e640f3d00..98cafaa56 100644 --- a/gradle.properties +++ b/gradle.properties @@ -47,7 +47,7 @@ versionStr= # This defines what MC version Intellij will use for the preprocessor # and what version is used automatically by build and run commands -mcVer=1.21.6 +mcVer=1.21.1 # Defines the maximum amount of memory Minecraft is allowed when run in a development environment minecraftMemoryJavaArg=-Xmx6G