Merge branch 'immersivePortals'

Thanks Acuadragon100!
This commit is contained in:
James Seibel
2026-06-01 07:45:25 -05:00
parent de33cbce2b
commit a94cd91a97
51 changed files with 917 additions and 396 deletions
@@ -77,43 +77,6 @@ public class CleanroomClientProxy implements AbstractModInitializer.IEventProxy
} }
//==============//
// world events //
//==============//
@SubscribeEvent
public void clientLevelLoadEvent(WorldEvent.Load event)
{
LOGGER.info("level load");
World level = event.getWorld();
if (!(level instanceof WorldClient clientLevel))
{
return;
}
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel, true);
ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper);
}
@SubscribeEvent
public void clientLevelUnloadEvent(WorldEvent.Unload event)
{
LOGGER.info("level unload");
World level = event.getWorld();
if (!(level instanceof WorldClient clientLevel))
{
return;
}
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel);
ClientApi.INSTANCE.clientLevelUnloadEvent(clientLevelWrapper);
}
//==============// //==============//
// chunk events // // chunk events //
//==============// //==============//
@@ -26,7 +26,6 @@ import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
@@ -61,9 +60,8 @@ public class MixinEntityRenderer
return; return;
} }
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
MinecraftRenderWrapper renderWrapper = (MinecraftRenderWrapper)SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); MinecraftRenderWrapper renderWrapper = (MinecraftRenderWrapper)SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
renderWrapper.setLightmapId(lightmapTexture.getGlTextureId(), clientLevel); renderWrapper.setLightmapId(lightmapTexture.getGlTextureId());
} }
@Inject(at = @At("RETURN"), method = "setupFog") @Inject(at = @At("RETURN"), method = "setupFog")
@@ -0,0 +1,60 @@
package com.seibel.distanthorizons.common.commonMixins;
#if MC_VER > MC_1_12_2
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.modAccessor.AbstractImmersivePortalsAccessorCommon;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.phys.Vec3;
public class MixinImmersivePortalsRenderStatesCommon
{
/**
* Used to access variables that will change when rendering
* different levels with Immersive Portals
* (ie player/camera position level reference)
* but that we only want for the loaded level.
*/
public static void saveVolatileOriginals()
{
Minecraft mc = Minecraft.getInstance();
AbstractImmersivePortalsAccessorCommon.actualLevel = mc.level;
// clear everything if the player is missing
// (ie the world hasn't loaded yet)
if (mc.player == null)
{
AbstractImmersivePortalsAccessorCommon.actualBlockPos = null;
AbstractImmersivePortalsAccessorCommon.actualChunkPos = null;
AbstractImmersivePortalsAccessorCommon.actualCameraPos = null;
return;
}
// player block pos
BlockPos playerBlockPos = mc.player.blockPosition();
AbstractImmersivePortalsAccessorCommon.actualBlockPos = new DhBlockPos(playerBlockPos.getX(), playerBlockPos.getY(), playerBlockPos.getZ());
// player chunk pos
#if MC_VER < MC_1_17_1
ChunkPos playerChunkPos = new ChunkPos(mc.player.blockPosition());
#else
ChunkPos playerChunkPos = mc.player.chunkPosition();
#endif
AbstractImmersivePortalsAccessorCommon.actualChunkPos = McObjectConverter.Convert(playerChunkPos);
// camera pos
#if MC_VER <= MC_1_21_10
Vec3 cameraPos = mc.gameRenderer.getMainCamera().getPosition();
#else
Vec3 cameraPos = mc.gameRenderer.getMainCamera().position();
#endif
AbstractImmersivePortalsAccessorCommon.actualCameraPos = new Vec3d(cameraPos.x(), cameraPos.y(), cameraPos.z());
}
}
#endif
@@ -7,6 +7,7 @@ import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IImmersivePortalsAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@@ -26,6 +27,7 @@ import net.minecraft.world.level.material.FluidState;
import net.minecraft.client.renderer.FogRenderer; import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.FogRenderer.FogMode; import net.minecraft.client.renderer.FogRenderer.FogMode;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
#elif MC_VER < MC_1_21_3 #elif MC_VER < MC_1_21_3
@@ -50,6 +52,11 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
#else #else
import net.minecraft.world.level.material.FogType; import net.minecraft.world.level.material.FogType;
import net.minecraft.client.renderer.fog.FogRenderer;
import net.minecraft.client.renderer.fog.FogData;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
#endif #endif
@@ -104,6 +111,15 @@ public class MixinVanillaFogCommon
cancelFog = cancelFog && !Config.Client.Advanced.Graphics.Fog.enableVanillaFog.get(); cancelFog = cancelFog && !Config.Client.Advanced.Graphics.Fog.enableVanillaFog.get();
// since DH won't render through immersive portals
// the vanilla fog should be enabled
IImmersivePortalsAccessor immersivePortals = ModAccessorInjector.INSTANCE.get(IImmersivePortalsAccessor.class);
if (immersivePortals != null
&& immersivePortals.isRenderingPortal())
{
cancelFog = false;
}
return cancelFog; return cancelFog;
} }
#if MC_VER <= MC_1_12_2 #if MC_VER <= MC_1_12_2
@@ -124,4 +140,6 @@ public class MixinVanillaFogCommon
return cameraNotInFluid; return cameraNotInFluid;
} }
} }
@@ -1,5 +1,6 @@
package com.seibel.distanthorizons.common.wrappers.level; package com.seibel.distanthorizons.common.wrappers.level;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager; import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
@@ -8,17 +9,27 @@ import net.minecraft.client.multiplayer.WorldClient;
#else #else
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
#endif #endif
import net.minecraft.client.Minecraft;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
public class KeyedClientLevelManager implements IKeyedClientLevelManager public class KeyedClientLevelManager implements IKeyedClientLevelManager
{ {
public static final KeyedClientLevelManager INSTANCE = new KeyedClientLevelManager(); public static final KeyedClientLevelManager INSTANCE = new KeyedClientLevelManager();
/** This is set and managed by the ClientApi for servers with support for DH. */ /** Stores the server-provided keys indexed by dimension name for persistence. */
@Nullable private final Map<String, KeyInfo> keysByDimensionName = new ConcurrentHashMap<>();
private IServerKeyedClientLevel serverKeyedLevel = null;
/** Cache for already keyed level wrappers to maintain object identity. */
private final Map<#if MC_VER > MC_1_12_2 ClientLevel #else WorldClient #endif, IServerKeyedClientLevel>
keyedLevelsCache = Collections.synchronizedMap(new WeakHashMap<>());
/** Allows to keep level manager enabled between loading different keyed levels */ /** Allows to keep level manager enabled between loading different keyed levels */
private boolean enabled = false; private volatile boolean enabled = false;
@@ -41,32 +52,140 @@ public class KeyedClientLevelManager implements IKeyedClientLevelManager
@Override @Override
@Nullable @Nullable
public IServerKeyedClientLevel getServerKeyedLevel() { return this.serverKeyedLevel; } public IServerKeyedClientLevel getServerKeyedLevel()
{
#if MC_VER > MC_1_12_2
return this.getServerKeyedLevel(Minecraft.getInstance().level);
#else
return this.getServerKeyedLevel(Minecraft.getMinecraft().world);
#endif
}
@Nullable
public IServerKeyedClientLevel getServerKeyedLevel(@Nullable #if MC_VER > MC_1_12_2 ClientLevel #else WorldClient #endif level)
{
if (level == null)
{
return null;
}
// We synchronize on the cache map to ensure atomicity of the lookup-and-populate sequence.
// This prevents multiple threads from creating duplicate wrappers for the same level.
synchronized (this.keyedLevelsCache)
{
// Check the cache first
IServerKeyedClientLevel cached = this.keyedLevelsCache.get(level);
if (cached != null)
{
return cached;
}
// Determine the dimension name for this level
// We use bypassLevelKeyManager=true to avoid recursion back into this manager
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level, true);
if (wrappedLevel == null)
{
return null;
}
String dimensionName = wrappedLevel.getDimensionName();
KeyInfo info = this.keysByDimensionName.get(dimensionName);
if (info == null)
{
return null;
}
// Create and cache a new keyed wrapper
IServerKeyedClientLevel keyedLevel = new ServerKeyedClientLevelWrapper(level, info.serverKey, info.levelKey);
this.keyedLevelsCache.put(level, keyedLevel);
return keyedLevel;
}
}
@Override @Override
public IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String serverKey, String levelKey) public IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String serverKey, String levelKey)
{ {
IServerKeyedClientLevel keyedLevel; // 1. Determine the target dimension name
#if MC_VER <= MC_1_12_2 String targetDimensionName = clientLevel.getDimensionName();
keyedLevel = new ServerKeyedClientLevelWrapper((WorldClient) clientLevel.getWrappedMcObject(), serverKey, levelKey); int separatorIndex = levelKey.lastIndexOf("@");
#else if (separatorIndex != -1)
keyedLevel = new ServerKeyedClientLevelWrapper((ClientLevel) clientLevel.getWrappedMcObject(), serverKey, levelKey); {
#endif targetDimensionName = levelKey.substring(separatorIndex + 1);
}
this.serverKeyedLevel = keyedLevel; final String finalTargetDimensionName = targetDimensionName;
// 2. Store the key for this dimension
this.keysByDimensionName.put(finalTargetDimensionName, new KeyInfo(serverKey, levelKey));
this.enabled = true; this.enabled = true;
return keyedLevel;
// 3. Clear the cache for this dimension to ensure new wrappers are created with the new key
// (though in practice keys shouldn't change mid-session)
//
// We synchronize manually on the map to ensure atomicity of the compound removal operation
// and to prevent race conditions or deadlocks with other threads accessing the map.
// We avoid calling ClientLevelWrapper.getWrapper() inside the lock to prevent circular lock dependencies.
synchronized (this.keyedLevelsCache)
{
this.keyedLevelsCache.keySet().removeIf(level ->
{
#if MC_VER <= MC_1_12_2
String levelDim = level.provider.getDimensionType().getName() + ":" + level.provider.getDimension();
#elif MC_VER <= MC_1_21_10
String levelDim = level.dimension().location().toString();
#else
String levelDim = level.dimension().identifier().toString();
#endif
return levelDim.equals(finalTargetDimensionName);
});
}
// 4. Return the keyed wrapper for whatever level the core passed us,
// but only if it matches the dimension we just keyed.
return this.getServerKeyedLevel((#if MC_VER > MC_1_12_2 ClientLevel #else WorldClient #endif) clientLevel.getWrappedMcObject());
} }
@Override @Override
public void clearKeyedLevel() { this.serverKeyedLevel = null; } public void clearKeyedLevel()
{
synchronized (this.keyedLevelsCache)
{
this.keyedLevelsCache.clear();
this.keysByDimensionName.clear();
}
}
@Override @Override
public boolean isEnabled() { return this.enabled; } public boolean isEnabled() { return this.enabled; }
@Override @Override
public void disable() { this.enabled = false; } public void disable()
{
this.enabled = false;
this.clearKeyedLevel();
}
//================//
// helper classes //
//================//
//region
private static class KeyInfo
{
public final String serverKey;
public final String levelKey;
public KeyInfo(String serverKey, String levelKey)
{
this.serverKey = serverKey;
this.levelKey = levelKey;
}
}
//endregion //endregion
} }
@@ -0,0 +1,65 @@
package com.seibel.distanthorizons.common.wrappers.minecraft;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
import org.jetbrains.annotations.Nullable;
#if MC_VER > MC_1_12_2
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
#else
import net.minecraft.world.WorldServer;
#endif
#if MC_VER <= MC_1_12_2
#elif MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
#endif
#if MC_VER > MC_1_19_2
import net.minecraft.core.registries.Registries;
#elif MC_VER > MC_1_12_2
import net.minecraft.core.Registry;
#endif
public abstract class AbstractMinecraftSharedWrapper implements IMinecraftSharedWrapper
{
@Nullable
protected ResourceKey<Level> deserializeDimensionResourceKey(String dimensionResourceLocation)
{
#if MC_VER <= MC_1_12_2
int dimensionID;
try
{
dimensionID = Integer.parseInt(dimensionResourceLocation.substring(dimensionResourceLocation.indexOf(":")+1));
}
catch (NumberFormatException ignored)
{
return null;
}
#else
#if MC_VER <= MC_1_21_10
ResourceLocation dimResourceLocation = ResourceLocation.tryParse(dimensionResourceLocation);
#else
Identifier dimResourceLocation = Identifier.tryParse(dimensionResourceLocation);
#endif
if (dimResourceLocation == null)
{
return null;
}
#if MC_VER > MC_1_19_2
ResourceKey<Level> dimensionKey = ResourceKey.create(Registries.DIMENSION, dimResourceLocation);
#else
ResourceKey<Level> dimensionKey = ResourceKey.create(Registry.DIMENSION_REGISTRY, dimResourceLocation);
#endif
#endif
return dimensionKey;
}
}
@@ -26,9 +26,13 @@ import com.mojang.blaze3d.platform.Window;
#endif #endif
import com.seibel.distanthorizons.common.wrappers.gui.NativeDialogUtil; import com.seibel.distanthorizons.common.wrappers.gui.NativeDialogUtil;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure; import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler; import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IImmersivePortalsAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
@@ -48,14 +52,20 @@ import net.minecraft.profiler.Profiler;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.DimensionType;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.DimensionManager;
#else #else
import net.minecraft.CrashReport; import net.minecraft.CrashReport;
import net.minecraft.client.CloudStatus; import net.minecraft.client.CloudStatus;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
#endif #endif
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -74,13 +84,25 @@ import net.minecraft.client.GraphicsStatus;
#else #else
#endif #endif
#if MC_VER <= MC_1_12_2
import net.minecraft.util.ResourceLocation;
#elif MC_VER <= MC_1_21_10
#else
import net.minecraft.resources.Identifier;
#endif
#if MC_VER > MC_1_19_2
import net.minecraft.core.registries.Registries;
#elif MC_VER > MC_1_12_2
#endif
/** /**
* A singleton that wraps the Minecraft object. * A singleton that wraps the Minecraft object.
* *
* @author James Seibel * @author James Seibel
*/ */
public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecraftSharedWrapper public class MinecraftClientWrapper extends AbstractMinecraftSharedWrapper implements IMinecraftClientWrapper
{ {
private static final DhLogger LOGGER = new DhLoggerBuilder().build(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@@ -95,6 +117,12 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
private ProfilerWrapper profilerWrapper; private ProfilerWrapper profilerWrapper;
/** Delayed accessing is necessary since this object will be created before the mod accessors are bound. */
private static class DelayedAccessors
{
public static final IImmersivePortalsAccessor IMMERSIVE_PORTALS = ModAccessorInjector.INSTANCE.get(IImmersivePortalsAccessor.class);
}
//======================// //======================//
@@ -232,6 +260,15 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
return new DhBlockPos(0, 0, 0); return new DhBlockPos(0, 0, 0);
} }
if (DelayedAccessors.IMMERSIVE_PORTALS != null)
{
DhBlockPos pos = DelayedAccessors.IMMERSIVE_PORTALS.getActualPlayerBlockPos();
if (pos != null)
{
return pos;
}
}
#if MC_VER <= MC_1_12_2 #if MC_VER <= MC_1_12_2
BlockPos playerPos = player.getPosition(); BlockPos playerPos = player.getPosition();
#else #else
@@ -253,7 +290,16 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
return new DhChunkPos(0, 0); return new DhChunkPos(0, 0);
} }
#if MC_VER <= MC_1_12_2 if (DelayedAccessors.IMMERSIVE_PORTALS != null)
{
DhChunkPos pos = DelayedAccessors.IMMERSIVE_PORTALS.getActualPlayerChunkPos();
if (pos != null)
{
return pos;
}
}
#if MC_VER <= MC_1_12_2
ChunkPos playerPos = new ChunkPos(player.getPosition()); ChunkPos playerPos = new ChunkPos(player.getPosition());
#elif MC_VER < MC_1_17_1 #elif MC_VER < MC_1_17_1
ChunkPos playerPos = new ChunkPos(player.blockPosition()); ChunkPos playerPos = new ChunkPos(player.blockPosition());
@@ -285,6 +331,16 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
@Nullable @Nullable
public IClientLevelWrapper getWrappedClientLevel(boolean bypassLevelKeyManager) public IClientLevelWrapper getWrappedClientLevel(boolean bypassLevelKeyManager)
{ {
if (!bypassLevelKeyManager
&& DelayedAccessors.IMMERSIVE_PORTALS != null)
{
IClientLevelWrapper level = DelayedAccessors.IMMERSIVE_PORTALS.getActualClientLevelWrapper();
if (level != null)
{
return level;
}
}
#if MC_VER <= MC_1_12_2 #if MC_VER <= MC_1_12_2
WorldClient level = MINECRAFT.world; WorldClient level = MINECRAFT.world;
#else #else
@@ -583,6 +639,25 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
} }
} }
@Nullable
@Override
public IServerLevelWrapper getWrappedServerLevelWithDimensionResourceLocation(String dimensionResourceLocation)
{
if (!this.hasSinglePlayerServer())
{
return null;
}
ResourceKey<Level> dimensionKey = this.deserializeDimensionResourceKey(dimensionResourceLocation);
#if MC_VER <= MC_1_12_2
WorldServer mcLevel = MINECRAFT.getIntegratedServer().getWorld(dimensionKey);
#else
ServerLevel mcLevel = MINECRAFT.getSingleplayerServer().getLevel(dimensionKey);
#endif
return ServerLevelWrapper.getWrapper(mcLevel);
}
//endregion //endregion
@@ -22,6 +22,8 @@ package com.seibel.distanthorizons.common.wrappers.minecraft;
import java.awt.Color; import java.awt.Color;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.jetbrains.annotations.Nullable;
#if MC_VER > MC_1_12_2 #if MC_VER > MC_1_12_2
import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.pipeline.RenderTarget;
import com.mojang.blaze3d.platform.NativeImage; import com.mojang.blaze3d.platform.NativeImage;
@@ -30,20 +32,24 @@ import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.api.enums.config.EDhApiLodShading; import com.seibel.distanthorizons.api.enums.config.EDhApiLodShading;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter; import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper; import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi; import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
import com.seibel.distanthorizons.coreapi.util.ColorUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
#elif MC_VER < MC_1_21_3
import net.minecraft.client.renderer.FogRenderer;
#elif MC_VER < MC_1_21_6 #elif MC_VER < MC_1_21_6
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import net.minecraft.client.renderer.FogRenderer; import net.minecraft.client.renderer.FogRenderer;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
#else #else
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import net.minecraft.client.renderer.fog.FogData; import net.minecraft.client.renderer.fog.FogData;
import net.minecraft.client.renderer.fog.FogRenderer; import net.minecraft.client.renderer.fog.FogRenderer;
#endif #endif
@@ -60,6 +66,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.core.util.math.Vec3d; import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.math.Vec3f; import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IImmersivePortalsAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
#if MC_VER <= MC_1_12_2 #if MC_VER <= MC_1_12_2
@@ -101,6 +108,7 @@ import com.mojang.blaze3d.opengl.GlTexture;
#else #else
import net.minecraft.world.attribute.EnvironmentAttributes; import net.minecraft.world.attribute.EnvironmentAttributes;
import com.mojang.blaze3d.textures.GpuTexture; import com.mojang.blaze3d.textures.GpuTexture;
import org.joml.Vector4f;
#endif #endif
/** /**
@@ -112,6 +120,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
public static final MinecraftRenderWrapper INSTANCE = new MinecraftRenderWrapper(); public static final MinecraftRenderWrapper INSTANCE = new MinecraftRenderWrapper();
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class); private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final DhLogger LOGGER = new DhLoggerBuilder().build(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@@ -121,6 +130,12 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
private static final Minecraft MC = Minecraft.getInstance(); private static final Minecraft MC = Minecraft.getInstance();
#endif #endif
/** Delayed accessing is necessary since this object will be created before the mod accessors are bound. */
private static class DelayedAccessors
{
public static final IImmersivePortalsAccessor IMMERSIVE_PORTALS = ModAccessorInjector.INSTANCE.get(IImmersivePortalsAccessor.class);
}
/** /**
* In the case of immersive portals multiple levels may be active at once, causing conflicting lightmaps. <br> * In the case of immersive portals multiple levels may be active at once, causing conflicting lightmaps. <br>
* Requiring the use of multiple {@link LightMapWrapper}. * Requiring the use of multiple {@link LightMapWrapper}.
@@ -202,6 +217,12 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override @Override
public Vec3d getCameraExactPosition() public Vec3d getCameraExactPosition()
{ {
if (DelayedAccessors.IMMERSIVE_PORTALS != null)
{
Vec3d cameraPos = DelayedAccessors.IMMERSIVE_PORTALS.getActualCameraPos();
if (cameraPos != null) return cameraPos;
}
#if MC_VER <= MC_1_12_2 #if MC_VER <= MC_1_12_2
RenderManager rm = MC.getRenderManager(); RenderManager rm = MC.getRenderManager();
return new Vec3d(rm.viewerPosX, rm.viewerPosY, rm.viewerPosZ); return new Vec3d(rm.viewerPosX, rm.viewerPosY, rm.viewerPosZ);
@@ -571,9 +592,6 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
#endif #endif
} }
@Override
public ILightMapWrapper getLightmapWrapper(@NotNull ILevelWrapper level) { return this.lightmapByDimensionType.get(level.getDimensionType()); }
@Override @Override
public boolean isFogStateSpecial() public boolean isFogStateSpecial()
{ {
@@ -598,94 +616,90 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
#endif #endif
} }
//==========//
// lightmap //
//==========//
//region
@Override
public ILightMapWrapper getLightmapWrapper(@NotNull ILevelWrapper level) { return this.lightmapByDimensionType.get(level.getDimensionType()); }
/** /**
* It's better to use {@link MinecraftRenderWrapper#setLightmapId(int, IClientLevelWrapper)} if possible, * It's better to use {@link MinecraftRenderWrapper#setLightmapId(int)} if possible,
* however old MC versions don't support it. * however old MC versions don't support it.
*/ */
#if MC_VER > MC_1_12_2 #if MC_VER > MC_1_12_2
public void updateLightmap(NativeImage lightPixels, IClientLevelWrapper level) public void updateLightmap(NativeImage lightPixels)
{ {
IClientLevelWrapper clientLevel = getLightmapClientLevelWrapper();
if (clientLevel == null)
{
return;
}
// Using ClientLevelWrapper as the key would be better, but we don't have a consistent way to create the same // Using ClientLevelWrapper as the key would be better, but we don't have a consistent way to create the same
// object for the same MC level and/or the same hash, // object for the same MC level and/or the same hash,
// so this will have to do for now // so this will have to do for now
IDimensionTypeWrapper dimensionType = level.getDimensionType(); IDimensionTypeWrapper dimensionType = clientLevel.getDimensionType();
LightMapWrapper wrapper = this.lightmapByDimensionType.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper()); LightMapWrapper wrapper = this.lightmapByDimensionType.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper());
wrapper.uploadLightmap(lightPixels); wrapper.uploadLightmap(lightPixels);
} }
#endif #endif
public void setLightmapId(int tetxureId, IClientLevelWrapper level) public void setLightmapId(int textureId)
{ {
IClientLevelWrapper clientLevel = getLightmapClientLevelWrapper();
if (clientLevel == null)
{
return;
}
// Using ClientLevelWrapper as the key would be better, but we don't have a consistent way to create the same // Using ClientLevelWrapper as the key would be better, but we don't have a consistent way to create the same
// object for the same MC level and/or the same hash, // object for the same MC level and/or the same hash,
// so this will have to do for now // so this will have to do for now
IDimensionTypeWrapper dimensionType = level.getDimensionType(); IDimensionTypeWrapper dimensionType = clientLevel.getDimensionType();
LightMapWrapper wrapper = this.lightmapByDimensionType.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper()); LightMapWrapper wrapper = this.lightmapByDimensionType.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper());
wrapper.setLightmapId(tetxureId); wrapper.setLightmapId(textureId);
} }
#if MC_VER <= MC_1_21_10 #if MC_VER <= MC_1_21_10
#else #else
public void setLightmapGpuTexture(GpuTexture gpuTexture, IClientLevelWrapper level) public void setLightmapGpuTexture(GpuTexture gpuTexture)
{ {
IClientLevelWrapper clientLevel = getLightmapClientLevelWrapper();
if (clientLevel == null)
{
return;
}
// Using ClientLevelWrapper as the key would be better, but we don't have a consistent way to create the same // Using ClientLevelWrapper as the key would be better, but we don't have a consistent way to create the same
// object for the same MC level and/or the same hash, // object for the same MC level and/or the same hash,
// so this will have to do for now // so this will have to do for now
IDimensionTypeWrapper dimensionType = level.getDimensionType(); IDimensionTypeWrapper dimensionType = clientLevel.getDimensionType();
LightMapWrapper wrapper = this.lightmapByDimensionType.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper()); LightMapWrapper wrapper = this.lightmapByDimensionType.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper());
wrapper.setLightmapGpuTexture(gpuTexture); wrapper.setLightmapGpuTexture(gpuTexture);
} }
#endif #endif
@Override /** special logic is necessary in order for Immersive Portals to work correctly */
public float getShade(EDhDirection lodDirection) private static @Nullable IClientLevelWrapper getLightmapClientLevelWrapper()
{ {
EDhApiLodShading lodShading = Config.Client.Advanced.Graphics.Quality.lodShading.get(); IClientLevelWrapper clientLevel = ClientApi.RENDER_STATE.clientLevelWrapper;
switch (lodShading) if (clientLevel == null)
{ {
default: clientLevel = MC_CLIENT.getWrappedClientLevel();
case AUTO:
#if MC_VER <= MC_1_12_2
// 1.12.2 has no getShade, fall through to ENABLED
#else
if (MC.level != null)
{
Direction mcDir = McObjectConverter.Convert(lodDirection);
#if MC_VER <= MC_1_21_11
return MC.level.getShade(mcDir, true);
#else
return MC.level.cardinalLighting().byFace(mcDir);
#endif
}
else
{
return 0.0f;
}
#endif
case ENABLED:
switch (lodDirection)
{
case DOWN:
return 0.5F;
default:
case UP:
return 1.0F;
case NORTH:
case SOUTH:
return 0.8F;
case WEST:
case EAST:
return 0.6F;
}
case DISABLED:
return 1.0F;
} }
return clientLevel;
} }
//endregion
} }
@@ -1,12 +1,34 @@
package com.seibel.distanthorizons.common.wrappers.minecraft; package com.seibel.distanthorizons.common.wrappers.minecraft;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.dedicated.DedicatedServer;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
#if MC_VER > MC_1_12_2
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
#else
import net.minecraft.world.WorldServer;
#endif
#if MC_VER <= MC_1_12_2
#elif MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
#endif
#if MC_VER > MC_1_19_2
import net.minecraft.core.registries.Registries;
#elif MC_VER > MC_1_12_2
import net.minecraft.core.Registry;
#endif
import java.io.File; import java.io.File;
public class MinecraftServerWrapper implements IMinecraftSharedWrapper public class MinecraftServerWrapper extends AbstractMinecraftSharedWrapper
{ {
public static final MinecraftServerWrapper INSTANCE = new MinecraftServerWrapper(); public static final MinecraftServerWrapper INSTANCE = new MinecraftServerWrapper();
@@ -64,5 +86,23 @@ public class MinecraftServerWrapper implements IMinecraftSharedWrapper
} }
@Nullable
@Override
public IServerLevelWrapper getWrappedServerLevelWithDimensionResourceLocation(String dimensionResourceLocation)
{
if (this.dedicatedServer == null)
{
throw new IllegalStateException("Trying to get the server mcLevel before dedicated server completed initialization!");
}
ResourceKey<Level> dimensionKey = this.deserializeDimensionResourceKey(dimensionResourceLocation);
#if MC_VER <= MC_1_12_2
WorldServer mcLevel = dedicatedServer.getWorld(dimensionKey);
#else
ServerLevel mcLevel = dedicatedServer.getLevel(dimensionKey);
#endif
return ServerLevelWrapper.getWrapper(mcLevel);
}
} }
@@ -0,0 +1,76 @@
/*
* 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.wrappers.modAccessor;
#if MC_VER <= MC_1_12_2
public abstract class AbstractImmersivePortalsAccessorCommon {}
#else
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractImmersivePortalsAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.multiplayer.ClientLevel;
import org.jetbrains.annotations.Nullable;
#if MC_VER > MC_1_19_2
import org.joml.Matrix4f;
#else
#endif
#if MC_VER < MC_1_17_1
import java.lang.reflect.Field;
#endif
public abstract class AbstractImmersivePortalsAccessorCommon extends AbstractImmersivePortalsAccessor
{
// We don't use the fields in RenderStates because they are not volatile.
@Nullable
public static volatile ClientLevel actualLevel;
@Nullable
public static volatile DhBlockPos actualBlockPos;
@Nullable
public static volatile DhChunkPos actualChunkPos;
@Nullable
public static volatile Vec3d actualCameraPos;
@Override
@Nullable
public DhBlockPos getActualPlayerBlockPos() { return actualBlockPos; }
@Override
@Nullable
public DhChunkPos getActualPlayerChunkPos() { return actualChunkPos; }
@Override
@Nullable
public IClientLevelWrapper getActualClientLevelWrapper() { return ClientLevelWrapper.getWrapper(actualLevel, false); }
@Override
@Nullable
public Vec3d getActualCameraPos() { return actualCameraPos; }
}
#endif
@@ -1,5 +1,6 @@
package com.seibel.distanthorizons.common.wrappers.world; package com.seibel.distanthorizons.common.wrappers.world;
import com.seibel.distanthorizons.api.enums.config.EDhApiLodShading;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper; import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper;
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper; import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper;
@@ -9,13 +10,20 @@ import com.seibel.distanthorizons.api.objects.data.IDhApiFullDataSource;
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
import com.seibel.distanthorizons.common.wrappers.block.ClientBlockStateColorCache; import com.seibel.distanthorizons.common.wrappers.block.ClientBlockStateColorCache;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.level.KeyedClientLevelManager;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.level.*; import com.seibel.distanthorizons.core.level.*;
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable;
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.block.IBlockStateWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
@@ -32,6 +40,7 @@ import net.minecraft.block.state.IBlockState;
#else #else
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
#endif #endif
@@ -44,9 +53,7 @@ import java.awt.*;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Collections; import java.util.*;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function; import java.util.function.Function;
@@ -80,7 +87,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
private static final Map< private static final Map<
#if MC_VER <= MC_1_12_2 WorldClient #else ClientLevel #endif, #if MC_VER <= MC_1_12_2 WorldClient #else ClientLevel #endif,
WeakReference<ClientLevelWrapper>> LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL = Collections.synchronizedMap(new WeakHashMap<>()); WeakReference<ClientLevelWrapper>> LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL = Collections.synchronizedMap(new WeakHashMap<>());
private static final IKeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = SingletonInjector.INSTANCE.get(IKeyedClientLevelManager.class); private static final KeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = KeyedClientLevelManager.INSTANCE;
#if MC_VER <= MC_1_12_2 #if MC_VER <= MC_1_12_2
private static final Minecraft MINECRAFT = Minecraft.getMinecraft(); private static final Minecraft MINECRAFT = Minecraft.getMinecraft();
@@ -90,6 +97,12 @@ public class ClientLevelWrapper implements IClientLevelWrapper
private static final ThreadLocal<DhBlockPosMutable> MUTABLE_BLOCK_POS_THREAD_LOCAL = ThreadLocal.withInitial(DhBlockPosMutable::new); private static final ThreadLocal<DhBlockPosMutable> MUTABLE_BLOCK_POS_THREAD_LOCAL = ThreadLocal.withInitial(DhBlockPosMutable::new);
private static final Timer CLIENT_CLEANUP_TIMER = TimerUtil.CreateTimer("ClientLevelTickCleanup");
private static final TimerTask CLIENT_CLEANUP_TASK = TimerUtil.createTimerTask(ClientLevelWrapper::tickCleanup);
/** how long in milliseconds can a level be unused before it's automatically unloaded */
private static final long INACTIVE_TIME_BEFORE_UNLOADED_IN_MS = 30 * 1000;
#if MC_VER <= MC_1_12_2 #if MC_VER <= MC_1_12_2
@@ -110,8 +123,9 @@ public class ClientLevelWrapper implements IClientLevelWrapper
private boolean cloudColorFailLogged = false; private boolean cloudColorFailLogged = false;
private BlockStateWrapper dirtBlockWrapper; private volatile BlockStateWrapper dirtBlockWrapper;
private IDhLevel dhLevel; private volatile IDhLevel dhLevel;
private volatile long lastAccessTime = System.currentTimeMillis();
@@ -126,11 +140,88 @@ public class ClientLevelWrapper implements IClientLevelWrapper
//==================// //======================//
// instance methods // // inactivity unloading //
//==================// //======================//
//region //region
@Override
public synchronized void markAccessed() { this.lastAccessTime = System.currentTimeMillis(); }
public synchronized long getLastAccessTime() { return this.lastAccessTime; }
static
{
// fire 20 times per second (i.e. 50ms interval)
CLIENT_CLEANUP_TIMER.scheduleAtFixedRate(CLIENT_CLEANUP_TASK, 0, 1000 / 20);
}
public static void tickCleanup()
{
#if MC_VER <= MC_1_12_2
WorldClient clientLevel = MINECRAFT.world;
#else
ClientLevel clientLevel = MINECRAFT.level;
#endif
if (clientLevel == null)
{
return;
}
long currentTime = System.currentTimeMillis();
ArrayList<ClientLevelWrapper> levelsToUnload = new ArrayList<>();
synchronized(LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL) // should only be run on one thread at a time, but just in case
{
for (WeakReference<ClientLevelWrapper> ref : LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.values())
{
ClientLevelWrapper levelWrapper = ref.get();
if (levelWrapper != null
&& levelWrapper.level != clientLevel)
{
// We use the synchronized getter to prevent race conditions with markAccessed()
long inactiveTimeMs = currentTime - levelWrapper.getLastAccessTime();
if (inactiveTimeMs > INACTIVE_TIME_BEFORE_UNLOADED_IN_MS)
{
levelsToUnload.add(levelWrapper);
}
}
}
}
for (ClientLevelWrapper wrapper : levelsToUnload)
{
// Re-verify all conditions inside a synchronized block on the wrapper
// to ensure atomicity with respect to markAccessed()
synchronized(wrapper)
{
long inactiveTimeMs = currentTime - wrapper.getLastAccessTime();
if (wrapper.level != clientLevel
&& inactiveTimeMs > INACTIVE_TIME_BEFORE_UNLOADED_IN_MS)
{
LOGGER.debug("Unloading level [" + wrapper.getDhIdentifier() + "] due to inactivity");
wrapper.tryUnloadFromWorld();
}
}
}
}
//endregion
//================//
// level handling //
//================//
//region
@Override
public void setDhLevel(IDhLevel dhLevel) { this.dhLevel = dhLevel; }
@Override
public IDhLevel getDhLevel() { return this.dhLevel; }
/** /**
* can be used when speed is important and the same level is likely to be passed in, * can be used when speed is important and the same level is likely to be passed in,
* IE rendering. * IE rendering.
@@ -140,9 +231,13 @@ public class ClientLevelWrapper implements IClientLevelWrapper
@Nullable IClientLevelWrapper levelWrapper, @Nullable IClientLevelWrapper levelWrapper,
@NotNull #if MC_VER <= MC_1_12_2 WorldClient #else ClientLevel #endif level) @NotNull #if MC_VER <= MC_1_12_2 WorldClient #else ClientLevel #endif level)
{ {
if (KEYED_CLIENT_LEVEL_MANAGER.isEnabled() && KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel() != levelWrapper) if (KEYED_CLIENT_LEVEL_MANAGER.isEnabled())
{ {
return getWrapper(level); IServerKeyedClientLevel keyedLevel = KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel(level);
if (keyedLevel != levelWrapper)
{
return getWrapper(level);
}
} }
ClientLevelWrapper clientLevelWrapper = (ClientLevelWrapper)levelWrapper; ClientLevelWrapper clientLevelWrapper = (ClientLevelWrapper)levelWrapper;
@@ -172,9 +267,28 @@ public class ClientLevelWrapper implements IClientLevelWrapper
} }
// used if the client is connected to a server that defines the currently loaded level // used if the client is connected to a server that defines the currently loaded level
IServerKeyedClientLevel overrideLevel = KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel(); IServerKeyedClientLevel overrideLevel = KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel(level);
if (overrideLevel != null) if (overrideLevel != null)
{ {
// if the currently loaded level wrapper doesn't match what's incoming, unload it
WeakReference<ClientLevelWrapper> levelRef = LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.get(level);
if (levelRef != null
&& levelRef.get() != overrideLevel)
{
ClientLevelWrapper levelWrapper = levelRef.get();
if (levelWrapper != null)
{
levelWrapper.tryUnloadFromWorld();
}
levelRef = null;
}
if (levelRef == null
&& overrideLevel instanceof ClientLevelWrapper)
{
LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.put(level, new WeakReference<>((ClientLevelWrapper) overrideLevel));
}
return overrideLevel; return overrideLevel;
} }
} }
@@ -337,7 +451,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
} }
#if MC_VER <= MC_1_12_2 #if MC_VER <= MC_1_12_2
this.dimensionName = this.level.provider.getDimensionType().getName(); this.dimensionName = this.level.provider.getDimensionType().getName() + ":" + this.level.provider.getDimension();
#elif MC_VER <= MC_1_21_10 #elif MC_VER <= MC_1_21_10
this.dimensionName = this.level.dimension().location().toString(); this.dimensionName = this.level.dimension().location().toString();
#else #else
@@ -443,6 +557,15 @@ public class ClientLevelWrapper implements IClientLevelWrapper
@Override @Override
public #if MC_VER <= MC_1_12_2 WorldClient #else ClientLevel #endif getWrappedMcObject() { return this.level; } public #if MC_VER <= MC_1_12_2 WorldClient #else ClientLevel #endif getWrappedMcObject() { return this.level; }
private void tryUnloadFromWorld()
{
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world == null
|| !world.unloadLevel(this))
{
this.onUnload();
}
}
@Override @Override
public void onUnload() public void onUnload()
{ {
@@ -504,16 +627,11 @@ public class ClientLevelWrapper implements IClientLevelWrapper
//===================// //===========//
// generic rendering // // rendering //
//===================// //===========//
//region //region
@Override
public void setDhLevel(IDhLevel dhLevel) { this.dhLevel = dhLevel; }
@Override
public IDhLevel getDhLevel() { return this.dhLevel; }
@Override @Override
public IDhApiCustomRenderRegister getRenderRegister() public IDhApiCustomRenderRegister getRenderRegister()
{ {
@@ -604,6 +722,45 @@ public class ClientLevelWrapper implements IClientLevelWrapper
#endif #endif
} }
@Override
public float getShade(EDhDirection lodDirection)
{
EDhApiLodShading lodShading = Config.Client.Advanced.Graphics.Quality.lodShading.get();
switch (lodShading)
{
default:
case AUTO:
#if MC_VER <= MC_1_12_2
// 1.12.2 level doesn't have a getShade method, fall through to ENABLED
#else
Direction mcDir = McObjectConverter.Convert(lodDirection);
#if MC_VER <= MC_1_21_11
return this.level.getShade(mcDir, true);
#else
return this.level.cardinalLighting().byFace(mcDir);
#endif
#endif
case ENABLED:
switch (lodDirection)
{
case DOWN:
return 0.5F;
default:
case UP:
return 1.0F;
case NORTH:
case SOUTH:
return 0.8F;
case WEST:
case EAST:
return 0.6F;
}
case DISABLED:
return 1.0F;
}
}
//endregion //endregion
@@ -210,7 +210,7 @@ public class ServerLevelWrapper implements IServerLevelWrapper
public String getDimensionName() public String getDimensionName()
{ {
#if MC_VER <= MC_1_12_2 #if MC_VER <= MC_1_12_2
return this.level.provider.getDimensionType().getName(); return this.level.provider.getDimensionType().getName() + ":" + this.level.provider.getDimension();
#elif MC_VER <= MC_1_21_10 #elif MC_VER <= MC_1_21_10
return this.level.dimension().location().toString(); return this.level.dimension().location().toString();
#else #else
+1 -22
View File
@@ -46,28 +46,7 @@ dependencies {
addMod("com.github.quiqueck:BCLib:${rootProject.bclib_version}", rootProject.enable_bclib) addMod("com.github.quiqueck:BCLib:${rootProject.bclib_version}", rootProject.enable_bclib)
// Canvas // Canvas
addMod("io.vram:canvas-fabric-${rootProject.canvas_version}", rootProject.enable_canvas) addMod("io.vram:canvas-fabric-${project.canvas_version}", rootProject.enable_canvas)
// Immersive Portals
if (rootProject.enable_immersive_portals == "1") {
modCompileOnly("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${rootProject.immersive_portals_version}")
}
else if (rootProject.enable_immersive_portals == "2") {
modImplementation ("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${rootProject.immersive_portals_version}") {
exclude(group: "net.fabricmc.fabric-api")
transitive(false)
}
modImplementation("com.github.iPortalTeam.ImmersivePortalsMod:q_misc_util:${rootProject.immersive_portals_version}") {
exclude(group: "net.fabricmc.fabric-api")
transitive(false)
}
modImplementation("com.github.iPortalTeam.ImmersivePortalsMod:build:${rootProject.immersive_portals_version}") {
exclude(group: "net.fabricmc.fabric-api")
transitive(false)
}
api("com.github.LlamaLad7:MixinExtras:0.2.0-beta.4")
annotationProcessor("com.github.LlamaLad7:MixinExtras:0.2.0-beta.4")
}
} }
@@ -116,6 +116,7 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new); this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
this.tryCreateModCompatAccessor("bclib", IBCLibAccessor.class, BCLibAccessor::new); this.tryCreateModCompatAccessor("bclib", IBCLibAccessor.class, BCLibAccessor::new);
this.tryCreateModCompatAccessor("c2me", IC2meAccessor.class, C2meAccessor::new); this.tryCreateModCompatAccessor("c2me", IC2meAccessor.class, C2meAccessor::new);
this.tryCreateModCompatAccessor("imm_ptl_core", IImmersivePortalsAccessor.class, ImmersivePortalsAccessorFabric::new);
#if MC_VER >= MC_1_19_4 #if MC_VER >= MC_1_19_4
// 1.19.4 is the lowest version Iris supports DH // 1.19.4 is the lowest version Iris supports DH
this.tryCreateModCompatAccessor("iris", IIrisAccessor.class, IrisAccessor::new); this.tryCreateModCompatAccessor("iris", IIrisAccessor.class, IrisAccessor::new);
@@ -31,10 +31,9 @@ public class MixinClientPacketListener
@Inject(method = "handleLogin", at = @At("RETURN")) @Inject(method = "handleLogin", at = @At("RETURN"))
void onHandleLoginEnd(CallbackInfo ci) void onHandleLoginEnd(CallbackInfo ci)
{ {
ClientApi.INSTANCE.onClientOnlyConnected(); ClientApi.INSTANCE.onClientOnlyConnected();
ClientApi.INSTANCE.clientLevelLoadEvent(ClientLevelWrapper.getWrapper(this.level, true));
} }
#if MC_VER < MC_1_19_4 #if MC_VER < MC_1_19_4
@Inject(method = "cleanup", at = @At("HEAD")) @Inject(method = "cleanup", at = @At("HEAD"))
#else #else
@@ -61,11 +60,12 @@ public class MixinClientPacketListener
return; return;
} }
// Important to get the level from the chunk because the client level might be different if Immersive Portals is present.
ClientLevel clientLevel = (ClientLevel) chunk.getLevel();
executor.execute(() -> executor.execute(() ->
{ {
IClientLevelWrapper clientLevel = ClientLevelWrapper.getWrapper((ClientLevel) this.level); IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel);
SharedApi.INSTANCE.applyChunkUpdate(new ChunkWrapper(chunk, clientLevel), clientLevel); SharedApi.INSTANCE.applyChunkUpdate(new ChunkWrapper(chunk, clientLevelWrapper), clientLevelWrapper);
}); });
} }
@@ -0,0 +1,23 @@
package com.seibel.distanthorizons.fabric.mixins.client;
import com.seibel.distanthorizons.common.commonMixins.MixinImmersivePortalsRenderStatesCommon;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Pseudo
#if MC_VER > MC_1_16_5
@Mixin(targets = "qouteall.imm_ptl.core.render.context_management.RenderStates")
#else
@Mixin(targets = "com.qouteall.immersive_portals.render.context_management.RenderStates")
#endif
public class MixinImmersivePortalsRenderStates
{
@Inject(method = "updatePreRenderInfo", at = @At("HEAD"))
private static void preRender(CallbackInfo ci)
{ MixinImmersivePortalsRenderStatesCommon.saveVolatileOriginals(); }
}
@@ -174,8 +174,6 @@ public class MixinLevelRenderer
ClientApi.RENDER_STATE.partialTickTime = MinecraftRenderWrapper.INSTANCE.getPartialTickTime(); ClientApi.RENDER_STATE.partialTickTime = MinecraftRenderWrapper.INSTANCE.getPartialTickTime();
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, this.level); ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, this.level);
#if MC_VER < MC_1_21_6 #if MC_VER < MC_1_21_6
if (renderType.equals(RenderType.translucent())) if (renderType.equals(RenderType.translucent()))
{ {
@@ -20,6 +20,7 @@
package com.seibel.distanthorizons.fabric.mixins.client; package com.seibel.distanthorizons.fabric.mixins.client;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
@@ -85,18 +86,6 @@ public class MixinLightTexture
public void render(LightmapRenderState renderState, CallbackInfo ci) public void render(LightmapRenderState renderState, CallbackInfo ci)
#endif #endif
{ {
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
if (mc == null)
{
return;
}
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
if (clientLevel == null)
{
return;
}
// lazy initialization to make sure we don't call this too early // lazy initialization to make sure we don't call this too early
if (this.renderWrapper == null) if (this.renderWrapper == null)
{ {
@@ -105,29 +94,29 @@ public class MixinLightTexture
#if MC_VER < MC_1_21_3 #if MC_VER < MC_1_21_3
this.renderWrapper.updateLightmap(this.lightPixels, clientLevel); this.renderWrapper.updateLightmap(this.lightPixels);
#elif MC_VER < MC_1_21_5 #elif MC_VER < MC_1_21_5
this.renderWrapper.setLightmapId(this.target.getColorTextureId(), clientLevel); this.renderWrapper.setLightmapId(this.target.getColorTextureId());
#elif MC_VER <= MC_1_21_10 #elif MC_VER <= MC_1_21_10
GlTexture glTexture = (GlTexture) this.texture; GlTexture glTexture = (GlTexture) this.texture;
this.renderWrapper.setLightmapId(glTexture.glId(), clientLevel); this.renderWrapper.setLightmapId(glTexture.glId());
#elif MC_VER <= MC_26_1_2 #elif MC_VER <= MC_26_1_2
// both options are available since the renderer can be changed to either Blaze3D or OpenGL // both options are available since the renderer can be changed to either Blaze3D or OpenGL
GlTexture glTexture = (GlTexture) this.texture; GlTexture glTexture = (GlTexture) this.texture;
this.renderWrapper.setLightmapId(glTexture.glId(), clientLevel); this.renderWrapper.setLightmapId(glTexture.glId());
this.renderWrapper.setLightmapGpuTexture(this.texture, clientLevel); this.renderWrapper.setLightmapGpuTexture(this.texture);
#else #else
// this will only be used when using native GL rendering // this will only be used when using native GL rendering
if (this.texture instanceof GlTexture) if (this.texture instanceof GlTexture)
{ {
GlTexture glTexture = (GlTexture) this.texture; GlTexture glTexture = (GlTexture) this.texture;
this.renderWrapper.setLightmapId(glTexture.glId(), clientLevel); this.renderWrapper.setLightmapId(glTexture.glId());
} }
// this will be used for Blaze3D OpenGL and Vulkan // this will be used for Blaze3D OpenGL and Vulkan
this.renderWrapper.setLightmapGpuTexture(this.texture, clientLevel); this.renderWrapper.setLightmapGpuTexture(this.texture);
#endif #endif
} }
@@ -3,8 +3,6 @@ package com.seibel.distanthorizons.fabric.mixins.client;
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch; import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
import com.seibel.distanthorizons.common.commonMixins.DhUpdateScreenBase; import com.seibel.distanthorizons.common.commonMixins.DhUpdateScreenBase;
import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen; import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.installer.GitlabGetter; import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
@@ -107,22 +105,6 @@ public abstract class MixinMinecraft
} }
#endif #endif
@Inject(at = @At("HEAD"), method = "updateLevelInEngines")
public void updateLevelInEngines(ClientLevel level, CallbackInfo ci)
{
if (this.lastLevel != null && level != this.lastLevel)
{
ClientApi.INSTANCE.clientLevelUnloadEvent(ClientLevelWrapper.getWrapper(this.lastLevel));
}
if (level != null)
{
ClientApi.INSTANCE.clientLevelLoadEvent(ClientLevelWrapper.getWrapper(level, true));
}
this.lastLevel = level;
}
@Inject(at = @At("HEAD"), method = "close()V") @Inject(at = @At("HEAD"), method = "close()V")
public void close(CallbackInfo ci) { SelfUpdater.onClose(); } public void close(CallbackInfo ci) { SelfUpdater.onClose(); }
@@ -0,0 +1,27 @@
/*
* 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.fabric.wrappers.modAccessor;
import com.seibel.distanthorizons.common.wrappers.modAccessor.AbstractImmersivePortalsAccessorCommon;
public class ImmersivePortalsAccessorFabric extends AbstractImmersivePortalsAccessorCommon
{
}
@@ -106,60 +106,6 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
} }
//==============//
// world events //
//==============//
@SubscribeEvent
#if MC_VER < MC_1_19_2
public void clientLevelLoadEvent(WorldEvent.Load event)
#else
public void clientLevelLoadEvent(LevelEvent.Load event)
#endif
{
LOGGER.info("level load");
#if MC_VER < MC_1_19_2
LevelAccessor level = event.getWorld();
#else
LevelAccessor level = event.getLevel();
#endif
if (!(level instanceof ClientLevel))
{
return;
}
ClientLevel clientLevel = (ClientLevel) level;
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel, true);
ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper);
}
@SubscribeEvent
#if MC_VER < MC_1_19_2
public void clientLevelUnloadEvent(WorldEvent.Unload event)
#else
public void clientLevelUnloadEvent(LevelEvent.Unload event)
#endif
{
LOGGER.info("level unload");
#if MC_VER < MC_1_19_2
LevelAccessor level = event.getWorld();
#else
LevelAccessor level = event.getLevel();
#endif
if (!(level instanceof ClientLevel))
{
return;
}
ClientLevel clientLevel = (ClientLevel) level;
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel);
ClientApi.INSTANCE.clientLevelUnloadEvent(clientLevelWrapper);
}
//==============// //==============//
// chunk events // // chunk events //
//==============// //==============//
@@ -22,13 +22,13 @@ package com.seibel.distanthorizons.forge;
import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.CommandDispatcher;
import com.seibel.distanthorizons.common.AbstractModInitializer; import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen; import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.*;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
import com.seibel.distanthorizons.forge.wrappers.modAccessor.ImmersivePortalsAccessorForge;
import com.seibel.distanthorizons.forge.wrappers.modAccessor.ModChecker; import com.seibel.distanthorizons.forge.wrappers.modAccessor.ModChecker;
import com.seibel.distanthorizons.forge.wrappers.modAccessor.OptifineAccessor; import com.seibel.distanthorizons.forge.wrappers.modAccessor.OptifineAccessor;
import com.seibel.distanthorizons.forge.wrappers.modAccessor.OculusAccessor; import com.seibel.distanthorizons.forge.wrappers.modAccessor.OculusAccessor;
@@ -104,6 +104,18 @@ public class ForgeMain extends AbstractModInitializer
{ {
this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new); this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
this.tryCreateModCompatAccessor("oculus", IIrisAccessor.class, OculusAccessor::new); this.tryCreateModCompatAccessor("oculus", IIrisAccessor.class, OculusAccessor::new);
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
// We ideally want to detect imm_ptl_core, but 1.16.5 doesn't provide that mod id.
if (modChecker.isModLoaded("imm_ptl_core")
|| modChecker.isModLoaded("immersive_portals"))
{
ModAccessorInjector.INSTANCE.bind(IImmersivePortalsAccessor.class, new ImmersivePortalsAccessorForge());
}
else
{
LOGGER.debug("Skipping mod compatibility accessor for: Immersive Portals");
}
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY, ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY,
@@ -45,15 +45,7 @@ public class MixinFogRenderer
remap = #if MC_VER == MC_1_17_1 || MC_VER == MC_1_18_2 false #else true #endif ) // Remap messiness due to this being weird in forge remap = #if MC_VER == MC_1_17_1 || MC_VER == MC_1_18_2 false #else true #endif ) // Remap messiness due to this being weird in forge
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, float partTick, CallbackInfo callback) private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, float partTick, CallbackInfo callback)
{ {
#if MC_VER < MC_1_21_6 if (MixinVanillaFogCommon.cancelFog(camera, fogMode))
boolean cancelFog = MixinVanillaFogCommon.cancelFog(camera, fogMode);
#elif MC_VER < MC_1_21_6
boolean cancelFog = MixinVanillaFogCommon.cancelFog(camera);
#else
boolean cancelFog = MixinVanillaFogCommon.cancelFog();
#endif
if (cancelFog)
{ {
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
RenderSystem.fogStart(A_REALLY_REALLY_BIG_VALUE); RenderSystem.fogStart(A_REALLY_REALLY_BIG_VALUE);
@@ -0,0 +1,23 @@
package com.seibel.distanthorizons.forge.mixins.client;
import com.seibel.distanthorizons.common.commonMixins.MixinImmersivePortalsRenderStatesCommon;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Pseudo
#if MC_VER > MC_1_16_5
@Mixin(targets = "qouteall.imm_ptl.core.render.context_management.RenderStates")
#else
@Mixin(targets = "com.qouteall.immersive_portals.render.context_management.RenderStates")
#endif
public class MixinImmersivePortalsRenderStates
{
@Inject(method = "updatePreRenderInfo", at = @At("HEAD"))
private static void preRender(CallbackInfo ci)
{ MixinImmersivePortalsRenderStatesCommon.saveVolatileOriginals(); }
}
@@ -46,14 +46,7 @@ public class MixinLightTexture
@Inject(method = "updateLightTexture(F)V", at = @At("RETURN")) @Inject(method = "updateLightTexture(F)V", at = @At("RETURN"))
public void updateLightTexture(float partialTicks, CallbackInfo ci) public void updateLightTexture(float partialTicks, CallbackInfo ci)
{ {
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); MinecraftRenderWrapper.INSTANCE.updateLightmap(this.lightPixels);
if (mc == null || mc.getWrappedClientLevel() == null)
{
return;
}
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
MinecraftRenderWrapper.INSTANCE.updateLightmap(this.lightPixels, clientLevel);
} }
} }
@@ -0,0 +1,27 @@
/*
* 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.forge.wrappers.modAccessor;
import com.seibel.distanthorizons.common.wrappers.modAccessor.AbstractImmersivePortalsAccessorCommon;
public class ImmersivePortalsAccessorForge extends AbstractImmersivePortalsAccessorCommon
{
}
@@ -30,14 +30,12 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.neoforged.neoforge.client.event.RenderLevelStageEvent; import net.neoforged.neoforge.client.event.RenderLevelStageEvent;
import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.level.LevelEvent;
import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
@@ -52,13 +50,7 @@ import net.neoforged.neoforge.client.event.InputEvent;
import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.bus.api.SubscribeEvent;
import org.lwjgl.opengl.GL32; import org.lwjgl.opengl.GL32;
#if MC_VER < MC_1_20_6
import net.neoforged.neoforge.event.TickEvent;
#else
import net.neoforged.neoforge.client.event.ClientTickEvent;
import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.AbstractExecutorService;
#endif
public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
@@ -73,43 +65,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
//==============//
// world events //
//==============//
@SubscribeEvent
public void clientLevelLoadEvent(LevelEvent.Load event)
{
LOGGER.info("level load");
LevelAccessor level = event.getLevel();
if (!(level instanceof ClientLevel))
{
return;
}
ClientLevel clientLevel = (ClientLevel) level;
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel, true);
ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper);
}
@SubscribeEvent
public void clientLevelUnloadEvent(LevelEvent.Unload event)
{
LOGGER.info("level unload");
LevelAccessor level = event.getLevel();
if (!(level instanceof ClientLevel))
{
return;
}
ClientLevel clientLevel = (ClientLevel) level;
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel);
ClientApi.INSTANCE.clientLevelUnloadEvent(clientLevelWrapper);
}
//==============// //==============//
// chunk events // // chunk events //
//==============// //==============//
@@ -163,11 +118,16 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
//LOGGER.trace("break or block attack at blockPos: " + event.getPos()); //LOGGER.trace("break or block attack at blockPos: " + event.getPos());
ChunkAccess chunk = level.getChunk(event.getPos()); ChunkAccess chunk = level.getChunk(event.getPos());
SharedApi.INSTANCE.applyChunkUpdate(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel); this.onBlockChangeEvent(level, chunk);
}); });
} }
} }
} }
private void onBlockChangeEvent(LevelAccessor level, ChunkAccess chunk)
{
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(level);
SharedApi.INSTANCE.applyChunkUpdate(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel);
}
@@ -260,8 +220,7 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
#else #else
// handled via the same mixin as fabric for consistency // handled via the same mixin as fabric for consistency
#endif #endif
try try
{ {
// should generally only need to be set once per game session // should generally only need to be set once per game session
@@ -30,16 +30,10 @@ import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.*;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.C2meAccessor; import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.*;
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.IrisAccessor;
import com.seibel.distanthorizons.neoforge.wrappers.NeoforgeMinecraftRenderWrapper; import com.seibel.distanthorizons.neoforge.wrappers.NeoforgeMinecraftRenderWrapper;
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.ModChecker;
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.OptifineAccessor;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.neoforged.bus.api.EventPriority; import net.neoforged.bus.api.EventPriority;
@@ -148,6 +142,7 @@ public class NeoforgeMain extends AbstractModInitializer
{ {
this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new); this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
this.tryCreateModCompatAccessor("c2me", IC2meAccessor.class, C2meAccessor::new); this.tryCreateModCompatAccessor("c2me", IC2meAccessor.class, C2meAccessor::new);
this.tryCreateModCompatAccessor("immersive_portals_core", IImmersivePortalsAccessor.class, ImmersivePortalsAccessorNeoForge::new);
#if MC_VER >= MC_1_20_6 #if MC_VER >= MC_1_20_6
// 1.20.6 is the lowest version Iris supports Neoforge // 1.20.6 is the lowest version Iris supports Neoforge
@@ -1,11 +1,8 @@
package com.seibel.distanthorizons.neoforge.mixins.client; package com.seibel.distanthorizons.neoforge.mixins.client;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.api.internal.ClientApi;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.multiplayer.ClientPacketListener;
import org.spongepowered.asm.mixin.Mixin; 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.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -13,14 +10,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ClientPacketListener.class) @Mixin(ClientPacketListener.class)
public class MixinClientPacketListener public class MixinClientPacketListener
{ {
@Shadow
private ClientLevel level;
@Inject(method = "handleLogin", at = @At("RETURN")) @Inject(method = "handleLogin", at = @At("RETURN"))
void onHandleLoginEnd(CallbackInfo ci) void onHandleLoginEnd(CallbackInfo ci)
{ {
ClientApi.INSTANCE.onClientOnlyConnected(); ClientApi.INSTANCE.onClientOnlyConnected();
ClientApi.INSTANCE.clientLevelLoadEvent(ClientLevelWrapper.getWrapper(this.level, true));
} }
#if MC_VER < MC_1_19_4 #if MC_VER < MC_1_19_4
@@ -0,0 +1,19 @@
package com.seibel.distanthorizons.neoforge.mixins.client;
import com.seibel.distanthorizons.common.commonMixins.MixinImmersivePortalsRenderStatesCommon;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Pseudo
@Mixin(targets = "qouteall.imm_ptl.core.render.context_management.RenderStates")
public class MixinImmersivePortalsRenderStates
{
@Inject(method = "updatePreRenderInfo", at = @At("HEAD"))
private static void preRender(CallbackInfo ci)
{ MixinImmersivePortalsRenderStatesCommon.saveVolatileOriginals(); }
}
@@ -90,18 +90,6 @@ public class MixinLightTexture
public void render(LightmapRenderState renderState, CallbackInfo ci) public void render(LightmapRenderState renderState, CallbackInfo ci)
#endif #endif
{ {
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
if (mc == null || mc.getWrappedClientLevel() == null)
{
return;
}
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
if (clientLevel == null)
{
return;
}
// lazy initialization to make sure we don't call this too early // lazy initialization to make sure we don't call this too early
if (this.renderWrapper == null) if (this.renderWrapper == null)
{ {
@@ -110,21 +98,21 @@ public class MixinLightTexture
#if MC_VER < MC_1_21_3 #if MC_VER < MC_1_21_3
renderWrapper.updateLightmap(this.lightPixels, clientLevel); renderWrapper.updateLightmap(this.lightPixels);
#elif MC_VER < MC_1_21_5 #elif MC_VER < MC_1_21_5
renderWrapper.setLightmapId(this.target.getColorTextureId(), clientLevel); renderWrapper.setLightmapId(this.target.getColorTextureId());
#elif MC_VER < MC_1_21_9 #elif MC_VER < MC_1_21_9
GlTexture glTexture = (GlTexture) this.texture; GlTexture glTexture = (GlTexture) this.texture;
renderWrapper.setLightmapId(glTexture.glId(), clientLevel); renderWrapper.setLightmapId(glTexture.glId());
#elif MC_VER <= MC_1_21_10 #elif MC_VER <= MC_1_21_10
GlTexture glTexture = (GlTexture) this.texture; GlTexture glTexture = (GlTexture) this.texture;
renderWrapper.setLightmapId(glTexture.glId(), clientLevel); renderWrapper.setLightmapId(glTexture.glId());
#else #else
// both options are available since the renderer can be changed to either Blaze3D or OpenGL // both options are available since the renderer can be changed to either Blaze3D or OpenGL
int id = NeoforgeTextureUnwrapper.getGlTextureIdFromGpuTexture(this.texture); int id = NeoforgeTextureUnwrapper.getGlTextureIdFromGpuTexture(this.texture);
renderWrapper.setLightmapId(id, clientLevel); renderWrapper.setLightmapId(id);
renderWrapper.setLightmapGpuTexture(this.texture, clientLevel); renderWrapper.setLightmapGpuTexture(this.texture);
#endif #endif
} }
@@ -0,0 +1,26 @@
/*
* 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.neoforge.wrappers.modAccessor;
import com.seibel.distanthorizons.common.wrappers.modAccessor.AbstractImmersivePortalsAccessorCommon;
public class ImmersivePortalsAccessorNeoForge extends AbstractImmersivePortalsAccessorCommon
{
}
-2
View File
@@ -25,7 +25,6 @@ fabric_api_version=0.42.0+1.16
sodium_version=mc1.16.5-0.2.0 sodium_version=mc1.16.5-0.2.0
iris_version=1.4.4+1.16.5 iris_version=1.4.4+1.16.5
bclib_version= bclib_version=
immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API # iris - needs 1.7.4+ to support the DH API
@@ -44,7 +43,6 @@ fabric_api_version=0.42.0+1.16
enable_iris=1 enable_iris=1
# not available via github, use curse.maven if necessary # not available via github, use curse.maven if necessary
enable_bclib=0 enable_bclib=0
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# Forge loader # Forge loader
-2
View File
@@ -25,7 +25,6 @@ fabric_api_version=0.46.1+1.17
sodium_version=mc1.17.1-0.3.4 sodium_version=mc1.17.1-0.3.4
iris_version=1.17.x-v1.2.7 iris_version=1.17.x-v1.2.7
bclib_version=0.5.5 bclib_version=0.5.5
immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API # iris - needs 1.7.4+ to support the DH API
@@ -43,7 +42,6 @@ fabric_api_version=0.46.1+1.17
enable_sodium=1 enable_sodium=1
enable_iris=0 enable_iris=0
enable_bclib=1 enable_bclib=1
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# Forge loader # Forge loader
-2
View File
@@ -26,7 +26,6 @@ fabric_api_version=0.76.0+1.18.2
sodium_version=mc1.18.2-0.4.1 sodium_version=mc1.18.2-0.4.1
iris_version=1.6.10+1.18.2 iris_version=1.6.10+1.18.2
bclib_version=1.4.6 bclib_version=1.4.6
immersive_portals_version=v1.4.11-1.18
canvas_version=mc118:1.0.2616 canvas_version=mc118:1.0.2616
# iris - needs 1.7.4+ to support the DH API # iris - needs 1.7.4+ to support the DH API
@@ -44,7 +43,6 @@ fabric_api_version=0.76.0+1.18.2
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=1 enable_bclib=1
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
quilt_loader_version=0.19.1 quilt_loader_version=0.19.1
-2
View File
@@ -24,7 +24,6 @@ fabric_api_version=0.76.1+1.19.2
sodium_version=mc1.19.2-0.4.4 sodium_version=mc1.19.2-0.4.4
iris_version=1.6.10+1.19.2 iris_version=1.6.10+1.19.2
bclib_version=2.1.6 bclib_version=2.1.6
immersive_portals_version=
canvas_version=mc119-1.0.2480 canvas_version=mc119-1.0.2480
# iris - needs 1.7.4+ to support the DH API # iris - needs 1.7.4+ to support the DH API
@@ -42,7 +41,6 @@ fabric_api_version=0.76.1+1.19.2
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=1 enable_bclib=1
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# Forge loader # Forge loader
-2
View File
@@ -23,7 +23,6 @@ fabric_api_version=0.87.1+1.19.4
sodium_version=mc1.19.4-0.4.10 sodium_version=mc1.19.4-0.4.10
iris_version=1.6.10+1.19.4 iris_version=1.6.10+1.19.4
bclib_version=2.3.3 bclib_version=2.3.3
immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API # iris - needs 1.7.4+ to support the DH API
@@ -41,7 +40,6 @@ fabric_api_version=0.87.1+1.19.4
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=1 enable_bclib=1
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# Forge loader # Forge loader
-2
View File
@@ -23,7 +23,6 @@ fabric_api_version=0.92.6+1.20.1
sodium_version=mc1.20.1-0.5.3 sodium_version=mc1.20.1-0.5.3
iris_version=1.6.10+1.20.1 iris_version=1.6.10+1.20.1
bclib_version=3.0.13 bclib_version=3.0.13
immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API # iris - needs 1.7.4+ to support the DH API
@@ -42,7 +41,6 @@ fabric_api_version=0.92.6+1.20.1
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=1 enable_bclib=1
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# Forge loader # Forge loader
-2
View File
@@ -23,7 +23,6 @@ fabric_api_version=0.90.4+1.20.2
sodium_version=mc1.20.2-0.5.3 sodium_version=mc1.20.2-0.5.3
iris_version=1.6.10+1.20.2 iris_version=1.6.10+1.20.2
bclib_version=3.0.13 bclib_version=3.0.13
immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API # iris - needs 1.7.4+ to support the DH API
@@ -42,7 +41,6 @@ fabric_api_version=0.90.4+1.20.2
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=1 enable_bclib=1
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# Forge loader # Forge loader
-2
View File
@@ -24,7 +24,6 @@ fabric_api_version=0.91.2+1.20.4
sodium_version=mc1.20.3-0.5.4 sodium_version=mc1.20.3-0.5.4
iris_version=1.6.13+1.20.4 iris_version=1.6.13+1.20.4
bclib_version= bclib_version=
immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API # iris - needs 1.7.4+ to support the DH API
@@ -43,7 +42,6 @@ fabric_api_version=0.91.2+1.20.4
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=0 enable_bclib=0
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# Forge loader # Forge loader
-2
View File
@@ -24,7 +24,6 @@ fabric_api_version=0.97.8+1.20.6
sodium_version=mc1.20.6-0.5.8 sodium_version=mc1.20.6-0.5.8
iris_version=1.7.0+1.20.6 iris_version=1.7.0+1.20.6
bclib_version= bclib_version=
immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API # iris - needs 1.7.4+ to support the DH API
@@ -43,7 +42,6 @@ fabric_api_version=0.97.8+1.20.6
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=0 enable_bclib=0
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# NeoForge loader # NeoForge loader
-2
View File
@@ -24,7 +24,6 @@ fabric_api_version=0.116.11+1.21.1
sodium_version=mc1.21.1-0.6.2-fabric sodium_version=mc1.21.1-0.6.2-fabric
iris_version=1.8.1+1.21.1-fabric iris_version=1.8.1+1.21.1-fabric
bclib_version= bclib_version=
immersive_portals_version=
canvas_version= canvas_version=
# iris - needs 1.7.4+ to support the DH API # iris - needs 1.7.4+ to support the DH API
@@ -43,7 +42,6 @@ fabric_api_version=0.116.11+1.21.1
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=0 enable_bclib=0
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# NeoForge loader # NeoForge loader
-2
View File
@@ -23,7 +23,6 @@ fabric_api_version=0.138.4+1.21.10
sodium_version=mc1.21.10-0.7.2-fabric sodium_version=mc1.21.10-0.7.2-fabric
iris_version=1.9.6+1.21.10-fabric iris_version=1.9.6+1.21.10-fabric
bclib_version= bclib_version=
immersive_portals_version=
canvas_version= canvas_version=
# vertigo - prevents DH from seeing the full chunk, causing holes # vertigo - prevents DH from seeing the full chunk, causing holes
@@ -41,7 +40,6 @@ fabric_api_version=0.138.4+1.21.10
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=0 enable_bclib=0
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# NeoForge loader # NeoForge loader
-2
View File
@@ -23,7 +23,6 @@ fabric_api_version=0.139.4+1.21.11
sodium_version=mc1.21.11-0.8.0-fabric sodium_version=mc1.21.11-0.8.0-fabric
iris_version=1.10.0+1.21.11-fabric iris_version=1.10.0+1.21.11-fabric
bclib_version= bclib_version=
immersive_portals_version=
canvas_version= canvas_version=
# vertigo - prevents DH from seeing the full chunk, causing holes # vertigo - prevents DH from seeing the full chunk, causing holes
@@ -41,7 +40,6 @@ fabric_api_version=0.139.4+1.21.11
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=0 enable_bclib=0
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# NeoForge loader # NeoForge loader
-2
View File
@@ -24,7 +24,6 @@ fabric_api_version=0.110.0+1.21.3
sodium_version=mc1.21.3-0.6.0-fabric sodium_version=mc1.21.3-0.6.0-fabric
iris_version=1.8.0+1.21.3-fabric iris_version=1.8.0+1.21.3-fabric
bclib_version= bclib_version=
immersive_portals_version=
canvas_version= canvas_version=
# fabric-api 0.110.0 fixed a bug in MC 1.21.3 with the rendering API DH relied on # fabric-api 0.110.0 fixed a bug in MC 1.21.3 with the rendering API DH relied on
@@ -43,7 +42,6 @@ fabric_api_version=0.110.0+1.21.3
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=0 enable_bclib=0
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# NeoForge loader # NeoForge loader
-2
View File
@@ -24,7 +24,6 @@ fabric_api_version=0.110.5+1.21.4
sodium_version=mc1.21.4-0.6.2-fabric sodium_version=mc1.21.4-0.6.2-fabric
iris_version=1.8.2+1.21.4-fabric iris_version=1.8.2+1.21.4-fabric
bclib_version= bclib_version=
immersive_portals_version=
canvas_version= canvas_version=
# vertigo - prevents DH from seeing the full chunk, causing holes # vertigo - prevents DH from seeing the full chunk, causing holes
@@ -42,7 +41,6 @@ fabric_api_version=0.110.5+1.21.4
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=0 enable_bclib=0
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# NeoForge loader # NeoForge loader
-2
View File
@@ -23,7 +23,6 @@ fabric_api_version=0.119.5+1.21.5
sodium_version=mc1.21.5-0.6.11-fabric sodium_version=mc1.21.5-0.6.11-fabric
iris_version=1.8.10+1.21.5-fabric iris_version=1.8.10+1.21.5-fabric
bclib_version= bclib_version=
immersive_portals_version=
canvas_version= canvas_version=
# Iris - some versions of 1.8.11 nightly builds may not work, but the ones after 2025-03-30 should # Iris - some versions of 1.8.11 nightly builds may not work, but the ones after 2025-03-30 should
@@ -42,7 +41,6 @@ fabric_api_version=0.119.5+1.21.5
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=0 enable_bclib=0
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# NeoForge loader # NeoForge loader
-2
View File
@@ -23,7 +23,6 @@ fabric_api_version=0.127.0+1.21.6
sodium_version=mc1.21.6-0.6.13-fabric sodium_version=mc1.21.6-0.6.13-fabric
iris_version=1.9.0+1.21.6-fabric iris_version=1.9.0+1.21.6-fabric
bclib_version= bclib_version=
immersive_portals_version=
canvas_version= canvas_version=
# vertigo - prevents DH from seeing the full chunk, causing holes # vertigo - prevents DH from seeing the full chunk, causing holes
@@ -41,7 +40,6 @@ fabric_api_version=0.127.0+1.21.6
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=0 enable_bclib=0
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# NeoForge loader # NeoForge loader
-2
View File
@@ -23,7 +23,6 @@ fabric_api_version=0.133.4+1.21.8
sodium_version=mc1.21.6-0.6.13-fabric sodium_version=mc1.21.6-0.6.13-fabric
iris_version=1.9.1+1.21.7-fabric iris_version=1.9.1+1.21.7-fabric
bclib_version= bclib_version=
immersive_portals_version=
canvas_version= canvas_version=
# vertigo - prevents DH from seeing the full chunk, causing holes # vertigo - prevents DH from seeing the full chunk, causing holes
@@ -41,7 +40,6 @@ fabric_api_version=0.133.4+1.21.8
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=0 enable_bclib=0
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# NeoForge loader # NeoForge loader
-2
View File
@@ -23,7 +23,6 @@ fabric_api_version=0.134.0+1.21.9
sodium_version=mc1.21.10-0.7.2-fabric sodium_version=mc1.21.10-0.7.2-fabric
iris_version=1.9.3+1.21.9-fabric iris_version=1.9.3+1.21.9-fabric
bclib_version= bclib_version=
immersive_portals_version=
canvas_version= canvas_version=
# vertigo - prevents DH from seeing the full chunk, causing holes # vertigo - prevents DH from seeing the full chunk, causing holes
@@ -41,7 +40,6 @@ fabric_api_version=0.134.0+1.21.9
enable_lithium=0 enable_lithium=0
enable_iris=1 enable_iris=1
enable_bclib=0 enable_bclib=0
enable_immersive_portals=0
enable_canvas=0 enable_canvas=0
# NeoForge loader # NeoForge loader