1.20.2 now builds (config looks odd, and updater disabled)

This commit is contained in:
coolGi
2023-10-01 22:32:19 +10:30
parent aeb7cf6ff1
commit fee8dc9b13
14 changed files with 204 additions and 94 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ build:
stage: build
parallel:
matrix:
- MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1"]
- MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2"]
script:
# this both runs the unit tests and assembles the code
- ./gradlew clean -PmcVer="${MC_VER}" -PgitMainBranch="${CI_COMMIT_BRANCH}" -PgitMainCommit="${CI_COMMIT_SHA}" -PgitCoreCommit="Unavailable (built by Gitlab CI)" --gradle-user-home cache/;
+7
View File
@@ -20,6 +20,13 @@ If you want to see a quick demo, check out a video covering the mod here:
### This branch supports the following versions of Minecraft:
#### 1.20.2
Fabric: 0.14.22\
Fabric API: 0.89.2+1.20.2\
Forge: 48.0.13\
Parchment: 1.19.3:2023.03.25\
Modmenu: 8.0.0
#### 1.20.1, 1.20 (Default)
Fabric: 0.14.21\
Fabric API: 0.85.0+1.20.1\
@@ -387,7 +387,11 @@ public class ClassicConfigGUI
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
#endif
{
#if MC_1_20_2
this.renderBackground(matrices, mouseX, mouseY, delta); // Renders background
#else
this.renderBackground(matrices); // Renders background
#endif
this.list.render(matrices, mouseX, mouseY, delta); // Render buttons
DhDrawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
@@ -72,7 +72,11 @@ public class MinecraftScreen
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
#endif
{
#if MC_1_20_2
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
#else
this.renderBackground(matrices); // Render background
#endif
this.list.render(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
screen.mouseX = mouseX;
@@ -31,28 +31,40 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
#endif
#if MC_1_20_2
import net.minecraft.client.gui.components.WidgetSprites;
#endif
/**
* Creates a button with a texture on it
*/
// TODO: Is this still needed? Can we switch to vanilla's ImageButton?
//
// Note after 1.20.2: They changed how buttons work, and are asking for a WidgetSprites.
// This should probably still exist so that code only needs to be changed here to work on all mc versions
public class TexturedButtonWidget extends ImageButton
{
#if POST_MC_1_17_1
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, ResourceLocation texture, OnPress pressAction)
#if MC_1_20_2
public static WidgetSprites locationToSprite(int width, int height, int u, int v, int hoveredVOffset, ResourceLocation resourceLocation)
{
super(x, y, width, height, u, v, texture, pressAction);
}
#endif
// FIXME[1.20.2]: Fix this
//Registries.
//
//ResourceLocation unfocused = new ResourceLocation();
//ResourceLocation focused = new ResourceLocation(resourceLocation.getNamespace(), resourceLocation.getPath());
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation texture, int textureWidth, int textureHeight, OnPress pressAction)
{
super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction);
return new WidgetSprites(resourceLocation, resourceLocation);
}
#endif
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation texture, int textureWidth, int textureHeight, OnPress pressAction, Component text)
{
#if MC_1_20_2
super(x, y, width, height, locationToSprite(textureWidth, textureHeight, u, v, hoveredVOffset, texture), pressAction, text);
#else
super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction, text);
#endif
}
#if PRE_MC_1_19_2
@@ -150,7 +150,11 @@ public class ChangelogScreen extends DhScreen
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
#endif
{
#if MC_1_20_2
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
#else
this.renderBackground(matrices); // Render background
#endif
if (!usable)
return;
@@ -77,7 +77,7 @@ public class UpdateModScreen extends DhScreen
// Logo image
this.addBtn(new ImageButton(
this.addBtn(new TexturedButtonWidget(
// Where the button is on the screen
this.width / 2 - 65, this.height / 2 - 110,
// Width and height of the button
@@ -151,7 +151,11 @@ public class UpdateModScreen extends DhScreen
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
#endif
{
#if MC_1_20_2
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
#else
this.renderBackground(matrices); // Render background
#endif
// Render the text's
@@ -42,6 +42,9 @@ import com.mojang.math.Vector3f;
#else
import org.joml.Vector3f;
#endif
#if MC_1_20_2
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
#endif
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import com.seibel.distanthorizons.coreapi.util.math.Vec3d;
@@ -294,6 +297,16 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
{
try
{
#if MC_1_20_2
LevelRenderer levelRenderer = MC.levelRenderer;
Collection<SectionRenderDispatcher.RenderSection> chunks = levelRenderer.visibleSections;
return (chunks.stream().map((chunk) -> {
AABB chunkBoundingBox = chunk.getBoundingBox();
return new DhChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
Math.floorDiv((int) chunkBoundingBox.minZ, 16));
}).collect(Collectors.toCollection(HashSet::new)));
#else
LevelRenderer levelRenderer = MC.levelRenderer;
Collection<LevelRenderer.RenderChunkInfo> chunks =
#if PRE_MC_1_18_2 levelRenderer.renderChunks;
@@ -306,6 +319,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
return new DhChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
Math.floorDiv((int) chunkBoundingBox.minZ, 16));
}).collect(Collectors.toCollection(HashSet::new)));
#endif
}
catch (LinkageError e)
{
@@ -0,0 +1,36 @@
accessWidener v1 named
# used when determining where to save files to
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
# used when rendering
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
# used for grabbing vanilla rendered chunks
accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
#accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chunk Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;
# world generation
# accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
# lod generation from save file
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
accessible field net/minecraft/world/level/chunk/storage/IOWorker storage Lnet/minecraft/world/level/chunk/storage/RegionFileStorage;
accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage regionCache Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage folder Ljava/nio/file/Path;
# grabbing textures
accessible class net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture
accessible method net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture getFrameX (I)I
accessible method net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture getFrameY (I)I
accessible field net/minecraft/client/renderer/texture/SpriteContents animatedTexture Lnet/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture;
accessible field net/minecraft/client/renderer/texture/SpriteContents originalImage Lcom/mojang/blaze3d/platform/NativeImage;
# hacky stuff
accessible field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
mutable field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
accessible field net/minecraft/client/gui/components/AbstractSelectionList scrollAmount D # Hack to bypass vanilla's setScrollAmount's clamp
@@ -94,11 +94,16 @@ public class MixinLevelRenderer
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLcom/mojang/math/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
#else
#elif PRE_MC_1_20_2
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
#else
@Inject(at = @At("HEAD"),
method = "Lnet/minecraft/client/renderer/LevelRenderer;renderLevel(Lcom/mojang/blaze3d/vertex/PoseStack;FJZLnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/GameRenderer;Lnet/minecraft/client/renderer/LightTexture;Lorg/joml/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo callback)
#endif
{
// FIXME completely disables rendering when sodium is installed
@@ -25,16 +25,25 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Minecraft.class)
public class MixinMinecraft
{
#if PRE_MC_1_20_1
#if MC_1_20_2
// FIXME
//@Redirect(
// method = "Lnet/minecraft/client/Minecraft;buildInitialScreens(Lnet/minecraft/client/Minecraft$GameLoadCookie;)Ljava/lang/Runnable;",
// at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V")
//)
public void onOpenScreen(Screen guiScreen)
{
Minecraft instance = Minecraft.getInstance();
#elif MC_1_20_1
@Redirect(
method = "<init>(Lnet/minecraft/client/main/GameConfig;)V",
method = "Lnet/minecraft/client/Minecraft;setInitialScreen(Lcom/mojang/realmsclient/client/RealmsClient;Lnet/minecraft/server/packs/resources/ReloadInstance;Lnet/minecraft/client/main/GameConfig$QuickPlayData;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V")
)
public void onOpenScreen(Minecraft instance, Screen guiScreen)
{
#else
@Redirect(
method = "Lnet/minecraft/client/Minecraft;setInitialScreen(Lcom/mojang/realmsclient/client/RealmsClient;Lnet/minecraft/server/packs/resources/ReloadInstance;Lnet/minecraft/client/main/GameConfig$QuickPlayData;)V",
method = "<init>(Lnet/minecraft/client/main/GameConfig;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V")
)
public void onOpenScreen(Minecraft instance, Screen guiScreen)
@@ -28,13 +28,8 @@ import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LightTexture;
import org.joml.Matrix4f;
#endif
import com.seibel.distanthorizons.common.rendering.SeamlessOverdraw;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import net.minecraft.client.Camera;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.GameRenderer;
@@ -47,22 +42,14 @@ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.nio.FloatBuffer;
#if PRE_MC_1_17_1
import org.lwjgl.opengl.GL15;
#endif
/**
* This class is used to mix in my rendering code
* before Minecraft starts rendering blocks.
* If this wasn't done, and we used Forge's
* render last event, the LODs would render on top
* of the normal terrain. <br><br>
* of the normal terrain.
*
* This is also the mixin for rendering the clouds
*
@@ -78,82 +65,48 @@ public class MixinLevelRenderer
@Unique
private static float previousPartialTicks = 0;
// TODO: Is there any reason why this is here? Can it be deleted?
public MixinLevelRenderer()
{
throw new NullPointerException("Null cannot be cast to non-null type.");
}
// Inject rendering at first call to renderChunkLayer
// HEAD or RETURN
#if PRE_MC_1_17_1
@Inject(at = @At("RETURN"), method = "renderSky(Lcom/mojang/blaze3d/vertex/PoseStack;F)V")
private void renderSky(PoseStack matrixStackIn, float partialTicks, CallbackInfo callback)
#else
@Inject(method = "renderClouds", at = @At("HEAD"), cancellable = true)
public void renderClouds(PoseStack poseStack, Matrix4f projectionMatrix, float partialTicks, double cameraX, double cameraY, double cameraZ, CallbackInfo ci)
#endif
{
// get the partial ticks since renderBlockLayer doesn't
// have access to them
previousPartialTicks = partialTicks;
}
#else
@Inject(method = "renderClouds", at = @At("HEAD"), cancellable = true)
public void renderClouds(PoseStack poseStack, Matrix4f projectionMatrix, float tickDelta, double cameraX, double cameraY, double cameraZ, CallbackInfo ci) {
// get the partial ticks since renderChunkLayer doesn't
// have access to them
previousPartialTicks = tickDelta;
}
#endif
// TODO: Can we move this to forge's client proxy similarly to how fabric does it
#if PRE_MC_1_17_1
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDD)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack matrixStackIn, double xIn, double yIn, double zIn, CallbackInfo callback)
#elif PRE_MC_1_19_4
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLcom/mojang/math/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
#elif PRE_MC_1_20_2
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
#else
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLcom/mojang/math/Matrix4f;)V",
method = "Lnet/minecraft/client/renderer/LevelRenderer;renderLevel(Lcom/mojang/blaze3d/vertex/PoseStack;FJZLnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/GameRenderer;Lnet/minecraft/client/renderer/LightTexture;Lorg/joml/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
#else
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
private void renderChunkLayer(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo callback)
#endif
{
// get MC's model view and projection matrices
#if MC_1_16_5
// get the matrices from the OpenGL fixed pipeline
float[] mcProjMatrixRaw = new float[16];
GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
Mat4f mcProjectionMatrix = new Mat4f(mcProjMatrixRaw);
mcProjectionMatrix.transpose();
Mat4f mcModelViewMatrix = McObjectConverter.Convert(matrixStackIn.last().pose());
#else
// get the matrices directly from MC
Mat4f mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose());
Mat4f mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
#endif
// only render before solid blocks
if (renderType.equals(RenderType.solid()))
{
ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(level), mcModelViewMatrix, mcProjectionMatrix, previousPartialTicks);
// experimental proof-of-concept option
if (Config.Client.Advanced.Graphics.AdvancedGraphics.seamlessOverdraw.get())
{
float[] matrixFloatArray = SeamlessOverdraw.overwriteMinecraftNearFarClipPlanes(mcProjectionMatrix, previousPartialTicks);
#if MC_1_16_5
SeamlessOverdraw.applyLegacyProjectionMatrix(matrixFloatArray);
#elif PRE_MC_1_19_4
projectionMatrix.load(FloatBuffer.wrap(matrixFloatArray));
#else
projectionMatrix.set(matrixFloatArray);
#endif
}
}
// FIXME completely disables rendering when sodium is installed
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
{
callback.cancel();
@@ -174,4 +127,5 @@ public class MixinLevelRenderer
ChunkWrapper.syncedUpdateClientLightStatus();
}
}
@@ -25,16 +25,25 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Minecraft.class)
public class MixinMinecraft
{
#if PRE_MC_1_20
#if MC_1_20_2
// FIXME
//@Redirect(
// method = "Lnet/minecraft/client/Minecraft;buildInitialScreens(Lnet/minecraft/client/Minecraft$GameLoadCookie;)Ljava/lang/Runnable;",
// at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V")
//)
public void onOpenScreen(Screen guiScreen)
{
Minecraft instance = Minecraft.getInstance();
#elif MC_1_20_1
@Redirect(
method = "<init>(Lnet/minecraft/client/main/GameConfig;)V",
method = "Lnet/minecraft/client/Minecraft;setInitialScreen(Lcom/mojang/realmsclient/client/RealmsClient;Lnet/minecraft/server/packs/resources/ReloadInstance;Lnet/minecraft/client/main/GameConfig$QuickPlayData;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V")
)
public void onOpenScreen(Minecraft instance, Screen guiScreen)
{
#else
@Redirect(
method = "Lnet/minecraft/client/Minecraft;setInitialScreen(Lcom/mojang/realmsclient/client/RealmsClient;Lnet/minecraft/server/packs/resources/ReloadInstance;Lnet/minecraft/client/main/GameConfig$QuickPlayData;)V",
method = "<init>(Lnet/minecraft/client/main/GameConfig;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V")
)
public void onOpenScreen(Minecraft instance, Screen guiScreen)
@@ -59,10 +68,7 @@ public class MixinMinecraft
}
}
@Inject(at = @At("HEAD"), method = "close()V", remap = false)
public void close(CallbackInfo ci)
{
SelfUpdater.onClose();
}
@Inject(at = @At("HEAD"), method = "close()V")
public void close(CallbackInfo ci) { SelfUpdater.onClose(); }
}
+51
View File
@@ -0,0 +1,51 @@
# 1.20.2 version
java_version=17
minecraft_version=1.20.2
parchment_version=1.19.3:2023.06.25
compatible_minecraft_versions=["1.20.2"]
accessWidenerVersion=1_20_2
builds_for=fabric,forge
# Fabric loader
fabric_loader_version=0.14.22
fabric_api_version=0.89.2+1.20.2
# Fabric mod versions
modmenu_version=8.0.0
starlight_version_fabric=
phosphor_version_fabric=
lithium_version=
sodium_version=mc1.20.2-0.5.3
iris_version=1.6.9+1.20.2
bclib_version=3.0.13
immersive_portals_version=
canvas_version=
fabric_incompatibility_list={ }
fabric_recommend_list={ "indium": "*" }
# Fabric mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_sodium=1
enable_lithium=0
enable_iris=1
enable_bclib=1
enable_immersive_portals=0
enable_canvas=0
# Forge loader
forge_version=48.0.13
# Forge mod versions
starlight_version_forge=
terraforged_version=
# Forge mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
enable_terrafirmacraft=0