Move Optifine code out of ReflectionHandler and into AbstractOptifineAccessor

This commit is contained in:
James Seibel
2022-11-24 19:09:52 -06:00
parent 4a7af41397
commit 2b1837e812
8 changed files with 163 additions and 163 deletions
@@ -37,7 +37,7 @@ public interface IBindable
* If no circular dependencies are required this method
* doesn't have to be implemented.
*/
public default void finishDelayedSetup() { }
default void finishDelayedSetup() { }
/**
* Returns if this dependency has been setup yet. <Br> <Br>
@@ -45,6 +45,6 @@ public interface IBindable
* If this object doesn't require a delayed setup, this
* method doesn't have to be implemented and should always return true.
*/
public default boolean getDelayedSetupComplete() { return true; }
default boolean getDelayedSetupComplete() { return true; }
}
@@ -35,18 +35,13 @@ import com.seibel.lod.core.interfaces.dependencyInjection.IBindable;
* different MC versions.
*
* @author James Seibel
* @version 3-5-2022
* @version 2022-11-24
*/
public interface IReflectionHandler extends IBindable
{
/** @return Whether Optifine is set to render fog or not. */
EFogDrawMode getFogDrawMode();
/** @return if Vivecraft is present. Attempts to find the "VRRenderer" class. */
boolean vivecraftPresent();
/** @return if Sodium (or a sodium like) mod is present. Attempts to find the "SodiumWorldRenderer" class. */
/** @return if Sodium (or a sodium like) mod is present. */
boolean sodiumPresent();
boolean optifinePresent();
}
@@ -20,186 +20,69 @@
package com.seibel.lod.core;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor;
import org.apache.logging.log4j.Logger;
import com.seibel.lod.api.enums.rendering.EFogDrawMode;
/**
* A singleton used to get variables from methods
* where they are private or potentially absent.
* For example: the fog setting in Optifine or the
* presence/absence of Vivecraft.
* A singleton used to determine if a class is present or
* access variables from methods where they are private
* or potentially absent. <br><br>
*
* For example: presence/absence of Optifine.
*
* @author James Seibel
* @version 2022-7-15
* @version 2022-11-24
*/
public class ReflectionHandler implements IReflectionHandler
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
public static ReflectionHandler instance;
private Field ofFogField = null;
private Object mcOptionsObject;
public static final ReflectionHandler INSTANCE = new ReflectionHandler();
// populated when the methods are called the first time
private Boolean sodiumPresent = null;
private boolean optifinePresent = false;
private boolean delayedSetupDone = false;
private Boolean optifinePresent = false;
@Override
public void finishDelayedSetup()
{
mcOptionsObject = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).getOptionsObject();
setupFogField(mcOptionsObject.getClass().getDeclaredFields());
this.delayedSetupDone = true;
}
@Override
public boolean getDelayedSetupComplete() { return this.delayedSetupDone; }
private ReflectionHandler()
{
mcOptionsObject = null;
}
/**
* @return the ReflectionHandler just created
* @throws IllegalStateException if a ReflectionHandler already exists
*/
public static ReflectionHandler createSingleton() throws IllegalStateException
{
if (instance != null)
{
throw new IllegalStateException();
}
instance = new ReflectionHandler();
return instance;
}
private ReflectionHandler() { }
//===================//
// is [mod] present? //
//===================//
/** finds the Optifine fog type field */
private void setupFogField(Field[] optionFields)
{
// try and find the ofFogType variable in gameSettings
for (Field field : optionFields)
{
if (field.getName().equals("ofFogType"))
{
optifinePresent = true;
ofFogField = field;
return;
}
}
// we didn't find the field,
// either optifine isn't installed, or
// optifine changed the name of the variable
LOGGER.info("Unable to find the Optifine fog field. If Optifine isn't installed this can be ignored.");
}
/**
* Get what type of fog optifine is currently set to render.
* @return the fog quality
*/
@Override
public EFogDrawMode getFogDrawMode()
{
if (ofFogField == null)
{
// either optifine isn't installed,
// the variable name was changed, or
// the setup method wasn't called yet.
return EFogDrawMode.FOG_ENABLED;
}
int returnNum = 0;
try
{
returnNum = (int) ofFogField.get(mcOptionsObject);
}
catch (IllegalArgumentException | IllegalAccessException e)
{
e.printStackTrace();
}
switch (returnNum)
{
default:
case 0:
// optifine's "default" option,
// it should never be called in this case
// normal options
case 1: // fast
case 2: // fancy
return EFogDrawMode.FOG_ENABLED;
case 3: // off
return EFogDrawMode.FOG_DISABLED;
}
}
/** Detect if Vivecraft is present. Attempts to find the "VRRenderer" class. */
@Override
public boolean vivecraftPresent()
{
try
{
Class.forName("org.vivecraft.provider.VRRenderer");
return true;
}
catch (ClassNotFoundException ignored)
{
LOGGER.info(ReflectionHandler.class.getSimpleName() + ": Vivecraft not detected.");
}
return false;
}
@Override
public boolean optifinePresent()
{
return optifinePresent;
if (this.optifinePresent == null)
{
// call the base accessor so we don't have duplicate code
this.optifinePresent = AbstractOptifineAccessor.isOptifinePresent();
}
return this.optifinePresent;
}
@Override
public boolean sodiumPresent()
{
// we don't want to run a potentially expensive
// reflection search operation every time this method is called
if (sodiumPresent == null)
if (this.sodiumPresent == null)
{
try
{
Class.forName("me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer");
sodiumPresent = true;
this.sodiumPresent = true;
}
catch (ClassNotFoundException e)
{
sodiumPresent = false;
this.sodiumPresent = false;
}
}
return sodiumPresent;
return this.sodiumPresent;
}
}
@@ -28,7 +28,7 @@ import org.apache.logging.log4j.Logger;
import java.lang.invoke.MethodHandles;
/**
* This class takes care of dependency injection for mods accessors. (for mod compatibility
* This class takes care of dependency injection for mod accessors. (for mod compatibility
* support). <Br> <Br>
*
* If a IModAccessor returns null either that means the mod isn't loaded in the game
@@ -21,10 +21,11 @@ package com.seibel.lod.core.render.fog;
import com.seibel.lod.api.enums.rendering.*;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.IReflectionHandler;
import com.seibel.lod.core.dependencyInjection.ModAccessorInjector;
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.render.glObject.shader.Shader;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -39,11 +40,11 @@ import static com.seibel.lod.core.render.glObject.GLProxy.GL_LOGGER;
*
* @author Leetom
* @author James Seibel
* @version 2022-4-14
* @version 2022-11-24
*/
public class LodFogConfig
{
private static final IReflectionHandler REFLECTION_HANDLER = SingletonInjector.INSTANCE.get(IReflectionHandler.class);
private static final IOptifineAccessor OPTIFINE = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
private static final ILodConfigWrapperSingleton CONFIG = SingletonInjector.INSTANCE.get(ILodConfigWrapperSingleton.class);
public static final boolean DEBUG_DUMP_GENERATED_CODE = false;
@@ -62,9 +63,10 @@ public class LodFogConfig
public static LodFogConfig generateFogConfig()
{
EFogDrawMode fogMode = CONFIG.client().graphics().fogQuality().getFogDrawMode();
if (fogMode == EFogDrawMode.USE_OPTIFINE_SETTING)
fogMode = REFLECTION_HANDLER.getFogDrawMode();
if (fogMode == EFogDrawMode.USE_OPTIFINE_SETTING && OPTIFINE != null)
{
fogMode = OPTIFINE.getFogDrawMode();
}
return new LodFogConfig(fogMode);
}
@@ -0,0 +1,113 @@
package com.seibel.lod.core.wrapperInterfaces.modAccessor;
import com.seibel.lod.api.enums.rendering.EFogDrawMode;
import com.seibel.lod.core.ReflectionHandler;
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import java.lang.reflect.Field;
/**
* Contains any shared code between Optifine for Forge (official Optifine)
* and Optifine on Fabric (unofficial ports).
*
* @version 2022-11-24
* @author James Seibel
*/
public abstract class AbstractOptifineAccessor implements IOptifineAccessor
{
public Field ofFogField = null;
public Object mcOptionsObject = null;
//=======//
// setup //
//=======//
public void finishDelayedSetup()
{
this.mcOptionsObject = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).getOptionsObject();
this.ofFogField = getOptifineFogField();
}
/** Returns null if Optifine isn't installed. */
public static Field getOptifineFogField()
{
Object mcOptions = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).getOptionsObject();
// try and find the ofFogType variable in gameSettings
for (Field field : mcOptions.getClass().getDeclaredFields())
{
if (field.getName().equals("ofFogType"))
{
return field;
}
}
return null;
}
/**
* Should not be called frequently since this uses reflection calls to determine if Optifine is present. <br>
* Use {@link ReflectionHandler#optifinePresent()} instead.
*/
public static boolean isOptifinePresent() { return getOptifineFogField() != null; }
//===================//
// interface methods //
//===================//
@Override
public EFogDrawMode getFogDrawMode()
{
if (this.ofFogField == null)
{
// either optifine isn't installed,
// the variable name was changed, or
// the setup method wasn't called yet.
return EFogDrawMode.FOG_ENABLED;
}
int returnNum = 0;
try
{
returnNum = (int) this.ofFogField.get(this.mcOptionsObject);
}
catch (IllegalArgumentException | IllegalAccessException e)
{
e.printStackTrace();
}
switch (returnNum)
{
default:
case 0: // optifine's "default" option,
// it should never be used, so default to fog Enabled
// normal options
case 1: // fast
case 2: // fancy
return EFogDrawMode.FOG_ENABLED;
case 3: // off
return EFogDrawMode.FOG_DISABLED;
}
}
public double getRenderResolutionMultiplier()
{
/*
* TODO remove comment when done, this is just here as reference
* Returns the percentage multiplier of the screen's current resolution. <br>
* 1.0 = 100% <br>
* 1.5 = 150% <br>
*/
// TODO
return 1.0;
}
}
@@ -25,6 +25,8 @@ import com.seibel.lod.core.interfaces.dependencyInjection.IBindable;
* @author Leetom
* @version 3-5-2022
*/
public interface IModAccessor extends IBindable {
public interface IModAccessor extends IBindable
{
String getModName();
}
@@ -19,23 +19,28 @@
package com.seibel.lod.core.wrapperInterfaces.modAccessor;
import com.seibel.lod.api.enums.rendering.EFogDrawMode;
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.pos.DhChunkPos;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import java.lang.reflect.Field;
import java.util.HashSet;
public interface IOptifineAccessor extends IModAccessor
{
/** Can be null */
HashSet<DhChunkPos> getNormalRenderedChunks();
/** Get what type of fog optifine is currently set to render. */
EFogDrawMode getFogDrawMode();
/**
* Returns the percentage multiplier of the screen's current resolution. <br>
* 1.0 = 100% <br>
* 1.5 = 150% <br>
*/
default double getRenderResolutionMultiplier()
{
return 1.0;
}
double getRenderResolutionMultiplier();
}