add immersive portals support

This commit is contained in:
Michael Harvey
2025-12-20 00:27:37 +01:00
committed by Acuadragon100
parent 40040294e7
commit e65b1e2dfc
25 changed files with 195 additions and 71 deletions
@@ -0,0 +1,92 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program 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, version 3.
*
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.DhLogger;
/**
* Runtime detection and compatibility handling for Immersive Portals
*/
public class ImmersivePortalsCompat
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static volatile Boolean isImmersivePortalsPresent = null;
private static volatile Boolean isImmersivePortalsActive = null;
/**
* Check if Immersive Portals is present in the mod environment
*/
public static boolean isImmersivePortalsPresent()
{
if (isImmersivePortalsPresent == null)
{
synchronized (ImmersivePortalsCompat.class)
{
if (isImmersivePortalsPresent == null)
{
try
{
// Try to load an Immersive Portals class
Class.forName("qouteall.imm_ptl.core.IPMcHelper");
isImmersivePortalsPresent = true;
LOGGER.info("Immersive Portals detected - enabling compatibility features");
}
catch (ClassNotFoundException e)
{
isImmersivePortalsPresent = false;
LOGGER.debug("Immersive Portals not detected - using standard level management");
}
}
}
}
return isImmersivePortalsPresent;
}
/**
* Check if Immersive Portals compatibility should be active
* This checks both presence and configuration
*/
public static boolean isImmersivePortalsActive()
{
if (isImmersivePortalsActive == null)
{
synchronized (ImmersivePortalsCompat.class)
{
if (isImmersivePortalsActive == null)
{
// TODO: Add configuration check here
isImmersivePortalsActive = isImmersivePortalsPresent();
}
}
}
return isImmersivePortalsActive;
}
/**
* Reset detection cache (useful for testing)
*/
public static void resetDetection()
{
isImmersivePortalsPresent = null;
isImmersivePortalsActive = null;
}
}
@@ -6,6 +6,7 @@ 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.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.level.*;
@@ -79,9 +80,9 @@ public class ClientLevelWrapper implements IClientLevelWrapper
private boolean cloudColorFailLogged = false;
private BlockStateWrapper dirtBlockWrapper;
private IDhLevel dhLevel;
private volatile BlockStateWrapper dirtBlockWrapper;
private volatile IDhLevel dhLevel;
private volatile long lastRenderTime = System.currentTimeMillis();
//=============//
@@ -100,6 +101,55 @@ public class ClientLevelWrapper implements IClientLevelWrapper
//==================//
//region
public synchronized void markRendered() {
this.lastRenderTime = System.currentTimeMillis();
}
public long getLastRenderTime() { return this.lastRenderTime; }
public boolean isDhLevelLoaded() {
return this.dhLevel != null;
}
public static void tickCleanup()
{
if (MINECRAFT.level == null) { return; }
long currentTime = System.currentTimeMillis();
long timeout = 30 * 1000;
java.util.List<ClientLevelWrapper> toUnload = new java.util.ArrayList<>();
synchronized(LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL)
{
for (java.lang.ref.WeakReference<ClientLevelWrapper> ref : LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.values())
{
ClientLevelWrapper wrapper = ref.get();
if (wrapper != null && wrapper.isDhLevelLoaded() && wrapper.level != MINECRAFT.level)
{
if (currentTime - wrapper.getLastRenderTime() > timeout)
{
toUnload.add(wrapper);
}
}
}
}
for (ClientLevelWrapper wrapper : toUnload)
{
// Re-verify all conditions inside a synchronized block on the wrapper
// to ensure atomicity with respect to markRendered()
synchronized(wrapper)
{
if (wrapper.isDhLevelLoaded() && wrapper.level != MINECRAFT.level && currentTime - wrapper.getLastRenderTime() > timeout)
{
LOGGER.debug("Unloading level " + wrapper.getDhIdentifier() + " due to inactivity");
ClientApi.INSTANCE.clientLevelUnloadEvent(wrapper);
}
}
}
}
/**
* can be used when speed is important and the same level is likely to be passed in,
* IE rendering.
@@ -62,7 +62,7 @@ public class ServerLevelWrapper implements IServerLevelWrapper
private static final Map<ServerLevel, WeakReference<ServerLevelWrapper>> LEVEL_WRAPPER_REF_BY_SERVER_LEVEL = Collections.synchronizedMap(new WeakHashMap<>());
private final ServerLevel level;
private IDhLevel dhLevel;
private volatile IDhLevel dhLevel;
/**
* this name is cached to prevent issues during shutdown where