diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
index a190fb110..000000000
--- a/.dockerignore
+++ /dev/null
@@ -1,19 +0,0 @@
-**/.git
-**/.gitlab
-**/.cache
-
-buildAllJars
-
-**/_Misc Files
-*.bat
-*.md
-*.sh
-*.txt
-
-coreSubProjects/*.md
-coreSubProjects/*.txt
-
-**/.gitignore
-**/.gitattributes
-**/.gitlab-cy.yml
-**/.gitmodules
diff --git a/.run/distant-horizons [cleanroom_runClient].run.xml b/.run/distant-horizons [cleanroom_runClient].run.xml
new file mode 100644
index 000000000..5fb0dac77
--- /dev/null
+++ b/.run/distant-horizons [cleanroom_runClient].run.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+
+
+
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 3044ee64e..000000000
--- a/Dockerfile
+++ /dev/null
@@ -1,12 +0,0 @@
-FROM eclipse-temurin:25-jdk
-
-WORKDIR /home/build/
-COPY ./gradlew .
-RUN chmod +x ./gradlew
-CMD echo "\r========== [CLEAN: $MC_VER] ==========" && \
- ./gradlew clean -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
- echo "\r========== [BUILD: $MC_VER] ==========" && \
- ./gradlew build -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
- echo "\r========== [MERGE: $MC_VER] ==========" && \
- ./gradlew mergeJars -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
- echo "\r========== [DONE: $MC_VER] =========="
diff --git a/build.gradle b/build.gradle
index 982ccf12c..af874eef2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,10 +4,10 @@ plugins {
}
forgix {
- autoRun = true
// add the mod loaders to the end of the jar
// put together in the format: "a", "a-b", "a-b-c"
+ int loaderCount = 0;
String modLoaders = "";
((String) gradle.builds_for)
.split(",")
@@ -20,7 +20,13 @@ forgix {
}
modLoaders += loaderName;
+
+ loaderCount++;
}
+
+ // run if there are multiple launchers that need merging
+ autoRun = (loaderCount > 1);
+
// merged jars are named in the format:
// "DistantHorizons-3.0.1-b-dev-26.1-fabric-neoforge.jar"
archiveClassifier = modLoaders
diff --git a/buildSrc/src/main/groovy/dh-loader.gradle b/buildSrc/src/main/groovy/dh-loader.gradle
index 838e869ce..852d42f23 100644
--- a/buildSrc/src/main/groovy/dh-loader.gradle
+++ b/buildSrc/src/main/groovy/dh-loader.gradle
@@ -6,6 +6,7 @@ import org.apache.tools.zip.ZipOutputStream
import javax.annotation.Nonnull
import java.util.function.Function
import java.util.function.Predicate
+import groovy.json.JsonSlurper
// Convention plugin for all MC-facing subprojects (common + loaders).
// Common uses this directly; loaders use it via unimined-fabric/forge/neoforge.
@@ -23,6 +24,9 @@ plugins {
def isNotCommonProject = project.name != "common"
+if (isNotCommonProject) {
+ evaluationDependsOn(":common")
+}
// ==================== Version Properties ====================
@@ -54,7 +58,12 @@ repositories {
url "https://www.cursemaven.com"
content { includeGroup "curse.maven" }
}
- maven { url "https://repo.spongepowered.org/maven/" }
+ maven {
+ url "https://repo.spongepowered.org/maven/"
+ // exclusion is needed since sponge has a deprecated version of fabric
+ // that gradle would prefer to get over the up-to-date version modrinth provides
+ content { excludeGroupByRegex "net\\.fabricmc(\\..*)?" }
+ }
maven { url "https://maven.terraformersmc.com/" }
maven { url "https://maven.neoforged.net/releases/" }
flatDir {
@@ -116,6 +125,15 @@ if (isNotCommonProject) {
'Multi-Release': true,
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain',
)
+ if (project.name == "cleanroom") {
+ attributes(
+ 'ModType': 'CRL',
+ 'MixinConfigs': "${mod_id}.default.mixin.json,${mod_id}.mod.mixin.json",
+ 'FMLCorePlugin': 'com.seibel.distanthorizons.cleanroom.DistantHorizonsLoadingPlugin',
+ 'FMLCorePluginContainsFMLMod': true,
+ 'FMLAT': "src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons_at.cfg"
+ )
+ }
}
}
}
@@ -128,8 +146,14 @@ unimined.minecraft(sourceSets.main, true) {
if (gradle.ext.minecraft_version.startsWith("1.")) { // 26.1+ doesn't use obfuscation
mappings {
- mojmap()
- devNamespace "mojmap"
+ if(gradle.ext.minecraft_version.startsWith("1.12.2")){
+ mcp("stable", "39-1.12")
+ }
+ else{
+ mojmap()
+ devNamespace "mojmap"
+ }
+
}
}
}
@@ -160,18 +184,22 @@ if (isNotCommonProject) {
source(project(":common").sourceSets.main.allSource)
}
} else {
- // Common: fabric for compilation + access widener, no jar remapping or runs
unimined.minecraft {
- fabric {
- loader gradle.ext.fabric_loader_version
- accessWidener project.file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
+ if (gradle.ext.minecraft_version.equals("1.12.2")) {
+ cleanroom {
+ loader gradle.ext.cleanroom_loader_version
+ }
+ } else {
+ fabric {
+ loader gradle.ext.fabric_loader_version
+ accessWidener project.file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
+ }
}
defaultRemapJar = false
runs.off = true
}
}
-
// ==================== Configurations ====================
evaluationDependsOn(":core")
@@ -341,12 +369,25 @@ if (isNotCommonProject) {
def loaderPaths = configurations.minecraftLibraries.resolve().collect { it.path }.toSet()
tasks.withType(JavaExec).configureEach { runTask ->
dependsOn(shadowJar)
- classpath = files(shadowJar.archiveFile) + classpath.filter { file ->
- !file.path.contains(project.buildDir.path) &&
- !file.path.contains("core${File.separator}build") &&
- !file.path.contains("api${File.separator}build") &&
- !file.path.contains("common${File.separator}build") &&
- !(shadowedPaths.contains(file.path) && !loaderPaths.contains(file.path))
+ if (project.name != "cleanroom") {
+ classpath = files(shadowJar.archiveFile) + classpath.filter { file ->
+ file != shadowJar.archiveFile.get().asFile &&
+ !file.path.contains(project.buildDir.path) &&
+ !file.path.contains("core${File.separator}build") &&
+ !file.path.contains("api${File.separator}build") &&
+ !file.path.contains("common${File.separator}build") &&
+ !(shadowedPaths.contains(file.path) && !loaderPaths.contains(file.path))
+ }
+ } else {
+ // For cleanroom, don't put shadow jar on app classpath.
+ // crl.dev.extrapath loads it via LaunchClassLoader instead.
+ classpath = classpath.filter { file ->
+ !file.path.contains(project.buildDir.path) &&
+ !file.path.contains("core${File.separator}build") &&
+ !file.path.contains("api${File.separator}build") &&
+ !file.path.contains("common${File.separator}build") &&
+ !(shadowedPaths.contains(file.path) && !loaderPaths.contains(file.path))
+ }
}
// Shared run directory so all loaders use the same worlds
@@ -361,6 +402,31 @@ if (isNotCommonProject) {
!arg.startsWith("-XX:MaxGCPauseMillis")
}
runTask.jvmArgs = filteredArgs
+
+ if(project.name == "forge"
+ || project.name == "neoforge"
+ || project.name == "cleanroom")
+ {
+ // fix (Neo)forge, Cleanroom debug running
+ doFirst {
+ def modsDir = rootProject.file("run/${isClient ? 'client' : 'server'}/mods")
+ modsDir.mkdirs()
+
+ // Remove any stale DH jars before copying the fresh one
+ modsDir.listFiles()?.each({ file ->
+ if (file.name.startsWith(rootProject.mod_name))
+ {
+ file.delete()
+ }
+ });
+
+ // Copy shadow jar into mods folder so (Neo)Forge discovers it properly
+ copy {
+ from shadowJar.archiveFile
+ into modsDir
+ }
+ }
+ }
// JVM args
runTask.jvmArgs(
@@ -371,7 +437,8 @@ if (isNotCommonProject) {
//"-XX:+ZGenerational",
rootProject.minecraftMemoryJavaArg,
)
- if (isClient) {
+ if (isClient)
+ {
runTask.jvmArgs(
"-Dminecraft.api.auth.host=https://nope.invalid",
"-Dminecraft.api.account.host=https://nope.invalid",
@@ -382,11 +449,23 @@ if (isNotCommonProject) {
// use a consistent username for easier debugging in a given world (vs randomly teleporting to a new user each time the game boots)
"--username", "Dev",
// "--renderDebugLabels" is a Mojang command to show render names in RenderDoc
- "--renderDebugLabels",
+ "--renderDebugLabels"
+ )
+
+ // enabling tracy causes constant memory growth so it isn't always desired
+ if (rootProject.minecraftEnableTracy == "true")
+ {
// "--tracy" is a Mojang command to allow individual frames to be debugged using Tracy https://github.com/wolfpld/tracy/releases/tag/v0.13.1
- "--tracy")
+ runTask.args("--tracy")
+ }
+
+
}
}
+
+ tasks.downgradeJar.inputFile.set(tasks.named("remapJar").flatMap { it.archiveFile })
+ tasks.jar.finalizedBy(tasks.named("remapJar"))
+ tasks.named("remapJar").configure { finalizedBy(tasks.shadeDowngradedApi) }
}
}
@@ -398,6 +477,7 @@ if (isNotCommonProject) {
def resourceTargets = [
"build_info.json",
"fabric.mod.json",
+ "mcmod.info",
"quilt.mod.json",
"META-INF/mods.toml",
"META-INF/neoforge.mods.toml",
@@ -408,6 +488,7 @@ if (isNotCommonProject) {
// Quilt contributors
def quilt_contributors = []
def mod_author_list = rootProject.mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",")
+ def cleanroom_author_list = rootProject.mod_authors.replace('[', '').replace(']', '').split(',').collect({ it.trim().replace('"', '') }).join('", "')
for (dev in mod_author_list) {
quilt_contributors.push("\"${dev.strip()}\": \"Developer\"")
}
@@ -425,9 +506,11 @@ if (isNotCommonProject) {
def replaceProperties = [
version : rootProject.mod_version,
+ mod_id : rootProject.mod_id,
mod_name : rootProject.mod_readable_name,
group : rootProject.maven_group,
authors : rootProject.mod_authors,
+ cleanroom_authors : cleanroom_author_list,
description : rootProject.mod_description,
homepage : rootProject.mod_homepage,
source : rootProject.mod_source,
@@ -445,6 +528,7 @@ if (isNotCommonProject) {
fabric_incompatibility_list : rootProject.fabric_incompatibility_list,
fabric_recommend_list : rootProject.fabric_recommend_list,
neoforge_version_range : rootProject.neoforge_version_range,
+ logo_path : "assets/distanthorizons/icon.png"
]
inputs.properties replaceProperties
@@ -455,7 +539,7 @@ if (isNotCommonProject) {
// Remove unused access wideners
exclude { file ->
- if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener") {
+ if ((file.name.contains(".distanthorizons.accesswidener") && file.name != "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener")) {
return true
}
return false
@@ -475,6 +559,25 @@ if (isNotCommonProject) {
from fileTree(project(":core").file("src/main/resources"))
into project.file("build/resources/main")
}
+
+ tasks.register("convertJsonToLang") {
+ dependsOn(copyCoreResources)
+
+ File input = project.file("build/resources/main/assets/distanthorizons/lang/en_us.json")
+ File output = project.file("build/resources/main/assets/distanthorizons/lang/en_us.lang")
+ inputs.file(input)
+ outputs.file(output)
+ doLast {
+ output.withWriter("UTF-8") { writer ->
+ writer.writeLine("#PARSE_ESCAPES")
+ new JsonSlurper()
+ .parse(input)
+ .each { key, value ->
+ writer.writeLine("${key}=${value.toString().replace("%", "%%").replace("\n", "\\n")}")
+ }
+ }
+ }
+ }
// ==================== JVMDowngrader ====================
diff --git a/buildSrc/src/main/groovy/unimined-cleanroom.gradle b/buildSrc/src/main/groovy/unimined-cleanroom.gradle
new file mode 100644
index 000000000..04112af95
--- /dev/null
+++ b/buildSrc/src/main/groovy/unimined-cleanroom.gradle
@@ -0,0 +1,15 @@
+plugins {
+ id 'dh-loader'
+}
+
+unimined.minecraft {
+ cleanroom {
+ loader gradle.ext.cleanroom_loader_version
+ useToolchains = false
+ accessTransformer project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons_at.cfg")
+ runs.all {
+ systemProperty("crl.dev.mixin", "${mod_id}.default.mixin.json,${mod_id}.mod.mixin.json")
+ systemProperty("fml.coreMods.load", "com.seibel.distanthorizons.cleanroom.DistantHorizonsLoadingPlugin")
+ }
+ }
+}
\ No newline at end of file
diff --git a/cleanroom/build.gradle b/cleanroom/build.gradle
new file mode 100644
index 000000000..3f021d12b
--- /dev/null
+++ b/cleanroom/build.gradle
@@ -0,0 +1,48 @@
+plugins {
+ id 'unimined-cleanroom'
+}
+
+
+// ==================== Mod Dependency Helper ====================
+
+def addMod(path, enabled) {
+ if (enabled == "2")
+ dependencies { modImplementation(path) }
+ else if (enabled == "1")
+ dependencies { compileOnly(path) }
+}
+
+
+// ==================== Dependencies ====================
+
+dependencies {
+
+}
+
+
+// ==================== Tasks ====================
+
+task deleteResources(type: Delete) {
+ delete file("build/resources/main")
+}
+
+processResources {
+ rename '(.+_at.cfg)', 'META-INF/$1'
+ dependsOn(copyCoreResources)
+ dependsOn(convertJsonToLang)
+ // dependsOn(copyCommonLoaderResources)
+}
+
+tasks.named('runClient') {
+ dependsOn(copyCoreResources)
+ // dependsOn(copyCommonLoaderResources)
+ finalizedBy(deleteResources)
+}
+
+sourcesJar {
+ def commonSources = project(":common").sourcesJar
+ dependsOn commonSources
+ from commonSources.archiveFile.map { zipTree(it) }
+}
+
+
diff --git a/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/CleanroomClientProxy.java b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/CleanroomClientProxy.java
new file mode 100644
index 000000000..f8fa56352
--- /dev/null
+++ b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/CleanroomClientProxy.java
@@ -0,0 +1,251 @@
+/*
+ * 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 .
+ */
+
+package com.seibel.distanthorizons.cleanroom;
+
+import com.seibel.distanthorizons.common.AbstractModInitializer;
+import com.seibel.distanthorizons.common.util.ProxyUtil;
+import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
+import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
+import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
+import com.seibel.distanthorizons.core.api.internal.ClientApi;
+import com.seibel.distanthorizons.core.api.internal.ServerApi;
+import com.seibel.distanthorizons.core.api.internal.SharedApi;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.logging.DhLogger;
+import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
+import com.seibel.distanthorizons.core.logging.f3.F3Screen;
+import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
+import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
+import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
+
+import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
+import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.multiplayer.WorldClient;
+import net.minecraft.world.World;
+import net.minecraft.world.chunk.Chunk;
+import net.minecraftforge.client.event.RenderGameOverlayEvent;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+import net.minecraftforge.event.world.ChunkEvent;
+import net.minecraftforge.event.world.WorldEvent;
+import net.minecraftforge.fml.common.FMLCommonHandler;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.InputEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+import org.jetbrains.annotations.NotNull;
+import org.lwjgl.glfw.GLFW;
+import org.lwjgl.opengl.GL32;
+
+import java.util.concurrent.AbstractExecutorService;
+
+public class CleanroomClientProxy implements AbstractModInitializer.IEventProxy
+{
+ private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
+ private static final CleanroomPluginPacketSender PACKET_SENDER = (CleanroomPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
+ private static final DhLogger LOGGER = new DhLoggerBuilder().build();
+
+ private static World GetEventLevel(WorldEvent e) { return e.getWorld(); }
+
+
+ @Override
+ public void registerEvents()
+ {
+ MinecraftForge.EVENT_BUS.register(this);
+ MinecraftForge.EVENT_BUS.register(FMLCommonHandler.instance());
+ CleanroomPluginPacketSender.setPacketHandler(ClientApi.INSTANCE::pluginMessageReceived);
+ }
+
+
+
+ //==============//
+ // 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 //
+ //==============//
+ //region
+
+ @SubscribeEvent
+ public void rightClickBlockEvent(PlayerInteractEvent.RightClickBlock event)
+ {
+ if (MC.clientConnectedToDedicatedServer())
+ {
+ World level = event.getWorld();
+
+ ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(level);
+ if (SharedApi.isChunkAtBlockPosAlreadyUpdating(wrappedLevel, event.getPos().getX(), event.getPos().getZ()))
+ {
+ return;
+ }
+
+ AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
+ if (executor != null)
+ {
+ executor.execute(() ->
+ {
+ Chunk chunk = level.getChunk(event.getPos());
+ SharedApi.INSTANCE.applyChunkUpdate(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel);
+ });
+ }
+ }
+ }
+ @SubscribeEvent
+ public void leftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event)
+ {
+ if (MC.clientConnectedToDedicatedServer())
+ {
+ World level = event.getWorld();
+
+ ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(level);
+ if (SharedApi.isChunkAtBlockPosAlreadyUpdating(wrappedLevel, event.getPos().getX(), event.getPos().getZ()))
+ {
+ return;
+ }
+
+ AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
+ if (executor != null)
+ {
+ executor.execute(() ->
+ {
+ Chunk chunk = level.getChunk(event.getPos());
+ SharedApi.INSTANCE.applyChunkUpdate(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel);
+ });
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void clientChunkLoadEvent(ChunkEvent.Load event)
+ {
+ if (MC.clientConnectedToDedicatedServer())
+ {
+ ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
+ IChunkWrapper chunkWrapper = new ChunkWrapper(event.getChunk(), wrappedLevel);
+ SharedApi.INSTANCE.applyChunkUpdate(chunkWrapper, wrappedLevel);
+ }
+ }
+
+ //endregion
+
+
+
+ //==============//
+ // key bindings //
+ //==============//
+ //region
+
+ @SubscribeEvent
+ public void registerKeyBindings(InputEvent.KeyInputEvent event)
+ {
+ /* if (Minecraft.getMinecraft().player == null)
+ {
+ return;
+ }
+ if (event.getAction() != GLFW.GLFW_PRESS)
+ {
+ return;
+ }
+
+ ClientApi.INSTANCE.keyPressedEvent(event.getKey());*/
+ }
+
+ //endregion
+
+
+
+ //===========//
+ // rendering //
+ //===========//
+ //region
+
+ @SubscribeEvent
+ public void afterLevelRenderEvent(TickEvent.RenderTickEvent event)
+ {
+ if (event.type.equals(TickEvent.RenderTickEvent.Type.RENDER))
+ {
+ try
+ {
+ // should generally only need to be set once per game session
+ // allows DH to render directly to Optifine's level frame buffer,
+ // allowing better shader support
+ MinecraftRenderWrapper.INSTANCE.finalLevelFrameBufferId = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING);
+ }
+ catch (Exception | Error e)
+ {
+ LOGGER.error("Unexpected error in afterLevelRenderEvent: "+e.getMessage(), e);
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onRenderOverlay(RenderGameOverlayEvent.Text event)
+ {
+ Minecraft mc = Minecraft.getMinecraft();
+ if (event.isCanceled()
+ || !mc.gameSettings.showDebugInfo)
+ {
+ return;
+ }
+
+ F3Screen.addStringToDisplay(event.getRight());
+ }
+
+ //endregion
+
+
+
+}
diff --git a/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/CleanroomMain.java b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/CleanroomMain.java
new file mode 100644
index 000000000..3055d707b
--- /dev/null
+++ b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/CleanroomMain.java
@@ -0,0 +1,147 @@
+/*
+ * 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 .
+ */
+
+package com.seibel.distanthorizons.cleanroom;
+
+import com.seibel.distanthorizons.cleanroom.modAccessor.ModChecker;
+import com.seibel.distanthorizons.common.AbstractModInitializer;
+import com.seibel.distanthorizons.common.commands.CommandInitializer;
+import com.seibel.distanthorizons.common.wrappers.worldGeneration.InternalServerGenerator;
+import com.seibel.distanthorizons.core.api.internal.ServerApi;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
+import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
+import com.seibel.distanthorizons.coreapi.ModInfo;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.world.World;
+import net.minecraftforge.common.ForgeChunkManager;
+import net.minecraftforge.fml.common.FMLCommonHandler;
+import net.minecraftforge.fml.common.Mod;
+import net.minecraftforge.fml.common.event.*;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.config.Configurator;
+
+
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * Initialize and setup the Mod.
+ * If you are looking for the real start of the mod
+ * check out the ClientProxy.
+ */
+@Mod(modid = ModInfo.ID, name = ModInfo.NAME, version = ModInfo.VERSION)
+public class CleanroomMain extends AbstractModInitializer
+{
+ @Mod.Instance
+ public static CleanroomMain instance;
+
+ @Mod.EventHandler
+ public void preinit(FMLPreInitializationEvent event)
+ {
+ Configurator.setLevel("org.sqlite", Level.INFO);
+ ForgeChunkManager.setForcedChunkLoadingCallback(CleanroomMain.instance, (tickets, world) -> { });
+ }
+
+ @Mod.EventHandler
+ public void init(FMLInitializationEvent event)
+ {
+ if (FMLCommonHandler.instance().getEffectiveSide().isClient())
+ {
+ this.onInitializeClient();
+ }
+ else
+ {
+ this.onInitializeServer();
+ }
+ }
+
+ @Override
+ protected void createInitialSharedBindings()
+ {
+ SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
+ SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new CleanroomPluginPacketSender());
+ }
+ @Override
+ protected void createInitialClientBindings() { /* no additional setup needed currently */ }
+
+ @Override
+ protected IEventProxy createClientProxy() { return new CleanroomClientProxy(); }
+
+ @Override
+ protected IEventProxy createServerProxy(boolean isDedicated) { return new CleanroomServerProxy(isDedicated); }
+
+ @Override
+ protected void initializeModCompat()
+ {
+
+ }
+
+/* @Override
+ protected void subscribeRegisterCommandsEvent(Consumer> eventHandler)
+ { MinecraftForge.EVENT_BUS.addListener((RegisterCommandsEvent e) -> { eventHandler.accept(e.getDispatcher()); }); }*/
+
+ @Override
+ protected void subscribeClientStartedEvent(Runnable eventHandler)
+ {
+ // Just run the event handler, since there are no proper ClientLifecycleEvent for the client
+ // to signify readiness other than FmlClientSetupEvent
+ eventHandler.run();
+ }
+
+ @Mod.EventHandler
+ public void onServerStarting(FMLServerStartingEvent event)
+ {
+ event.registerServerCommand(CommandInitializer.initCommands());
+ }
+
+ @Mod.EventHandler
+ public void onServerAboutToStart(FMLServerAboutToStartEvent event)
+ {
+ if (eventHandlerStartServer != null)
+ {
+ eventHandlerStartServer.accept(event.getServer());
+ }
+ }
+
+ Consumer eventHandlerStartServer;
+
+ @Override
+ protected void subscribeServerStartingEvent(Consumer eventHandler)
+ {
+ eventHandlerStartServer = eventHandler;
+ }
+
+ @Override
+ protected void runDelayedSetup() { SingletonInjector.INSTANCE.runDelayedSetup(); }
+
+ // ServerWorldLoadEvent
+ @Mod.EventHandler
+ public void dedicatedWorldLoadEvent(FMLServerAboutToStartEvent event)
+ {
+ ServerApi.INSTANCE.serverLoadEvent(event.getServer().isDedicatedServer());
+ }
+
+ // ServerWorldUnloadEvent
+ @Mod.EventHandler
+ public void serverWorldUnloadEvent(FMLServerStoppingEvent event)
+ {
+ ServerApi.INSTANCE.serverUnloadEvent();
+ }
+}
diff --git a/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/CleanroomPluginPacketSender.java b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/CleanroomPluginPacketSender.java
new file mode 100644
index 000000000..05ed2c9c6
--- /dev/null
+++ b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/CleanroomPluginPacketSender.java
@@ -0,0 +1,115 @@
+/*
+ * 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 .
+ */
+
+package com.seibel.distanthorizons.cleanroom;
+
+import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
+import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
+import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
+import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
+import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
+import io.netty.buffer.ByteBuf;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraftforge.fml.common.network.NetworkRegistry;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
+import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
+import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
+import net.minecraftforge.fml.relauncher.Side;
+
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+public class CleanroomPluginPacketSender extends AbstractPluginPacketSender
+{
+ public static final SimpleNetworkWrapper PLUGIN_CHANNEL =
+ NetworkRegistry.INSTANCE.newSimpleChannel(
+ AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE
+ );
+
+ public static void setPacketHandler(Consumer consumer)
+ {
+ setPacketHandler((player, message) -> consumer.accept(message));
+ }
+ static BiConsumer consumerPacket;
+ public static void setPacketHandler(BiConsumer consumer)
+ {
+ PLUGIN_CHANNEL.registerMessage(MessageWrapper.Handler.class, MessageWrapper.class, 0, Side.CLIENT);
+ PLUGIN_CHANNEL.registerMessage(MessageWrapper.Handler.class, MessageWrapper.class, 0, Side.SERVER);
+ consumerPacket = consumer;
+ }
+
+ @Override
+ public void sendToServer(AbstractNetworkMessage message)
+ {
+ PLUGIN_CHANNEL.sendToServer(new MessageWrapper(message));
+ }
+
+ @Override
+ public void sendToClient(EntityPlayerMP serverPlayer, AbstractNetworkMessage message)
+ {
+ PLUGIN_CHANNEL.sendTo(new MessageWrapper(message), serverPlayer);
+ }
+
+ // Forge doesn't support using abstract classes
+ @SuppressWarnings({"ClassCanBeRecord", "RedundantSuppression"})
+ public static class MessageWrapper implements IMessage
+ {
+ public AbstractNetworkMessage message;
+
+ public MessageWrapper(AbstractNetworkMessage message) { this.message = message; }
+
+ public MessageWrapper()
+ {
+ // For reflection
+ }
+
+ @Override
+ public void fromBytes(ByteBuf buf) {
+ int messageId = buf.readByte();
+ message = MessageRegistry.INSTANCE.createMessage(messageId);
+ message.decode(buf);
+ }
+
+ @Override
+ public void toBytes(ByteBuf buf) {
+ buf.writeByte(MessageRegistry.INSTANCE.getMessageId(message));
+ message.encode(buf);
+ }
+
+ public static class Handler implements IMessageHandler
+ {
+ @Override
+ public IMessage onMessage(MessageWrapper wrapper, MessageContext context) {
+ if (wrapper.message != null)
+ {
+ if (context.side == Side.SERVER)
+ {
+ consumerPacket.accept(ServerPlayerWrapper.getWrapper(context.getServerHandler().player), wrapper.message);
+ }
+ else {
+ consumerPacket.accept(null, wrapper.message);
+ }
+ }
+ return null; // No response needed
+ }
+ }
+ }
+
+}
diff --git a/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/CleanroomServerProxy.java b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/CleanroomServerProxy.java
new file mode 100644
index 000000000..2d88eaebe
--- /dev/null
+++ b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/CleanroomServerProxy.java
@@ -0,0 +1,181 @@
+/*
+ * 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 .
+ */
+
+package com.seibel.distanthorizons.cleanroom;
+
+import com.seibel.distanthorizons.common.AbstractModInitializer;
+import com.seibel.distanthorizons.common.commands.CommandInitializer;
+import com.seibel.distanthorizons.common.commonMixins.MixinChunkMapCommon;
+import com.seibel.distanthorizons.common.util.ProxyUtil;
+import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
+import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
+import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
+import com.seibel.distanthorizons.common.wrappers.worldGeneration.InternalServerGenerator;
+import com.seibel.distanthorizons.core.api.internal.ServerApi;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.logging.DhLogger;
+import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
+import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
+import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldServer;
+import net.minecraftforge.common.ForgeChunkManager;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.event.world.ChunkDataEvent;
+import net.minecraftforge.event.world.ChunkEvent;
+import net.minecraftforge.event.world.WorldEvent;
+import net.minecraftforge.fml.common.FMLCommonHandler;
+import net.minecraftforge.fml.common.Mod;
+import net.minecraftforge.fml.common.event.FMLServerAboutToStartEvent;
+import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
+import net.minecraftforge.fml.common.event.FMLServerStoppingEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.PlayerEvent;
+
+import java.lang.reflect.Field;
+
+import static com.seibel.distanthorizons.cleanroom.CleanroomMain.instance;
+
+public class CleanroomServerProxy implements AbstractModInitializer.IEventProxy
+{
+ private static final CleanroomPluginPacketSender PACKET_SENDER = (CleanroomPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
+ private static World GetEventLevel(WorldEvent e) { return e.getWorld(); }
+
+ private static final DhLogger LOGGER = new DhLoggerBuilder().build();
+ private final ServerApi serverApi = ServerApi.INSTANCE;
+ private final boolean isDedicated;
+
+
+
+ @Override
+ public void registerEvents()
+ {
+ MinecraftForge.EVENT_BUS.register(this);
+ FMLCommonHandler.instance().bus().register(this);
+ if (this.isDedicated)
+ {
+ PACKET_SENDER.setPacketHandler(ServerApi.INSTANCE::pluginMessageReceived);
+ }
+ }
+
+
+
+ //=============//
+ // constructor //
+ //=============//
+ //region
+
+ public CleanroomServerProxy(boolean isDedicated) { this.isDedicated = isDedicated; }
+
+ //endregion
+
+
+
+ //========//
+ // events //
+ //========//
+ //region
+
+ // ServerLevelLoadEvent
+ @SubscribeEvent
+ public void serverLevelLoadEvent(WorldEvent.Load event)
+ {
+ if (GetEventLevel(event) instanceof WorldServer)
+ {
+ this.serverApi.serverLevelLoadEvent(getServerLevelWrapper((WorldServer) GetEventLevel(event)));
+ }
+ }
+
+ // ServerLevelUnloadEvent
+ @SubscribeEvent
+ public void serverLevelUnloadEvent(WorldEvent.Unload event)
+ {
+ if (GetEventLevel(event) instanceof WorldServer)
+ {
+ this.serverApi.serverLevelUnloadEvent(getServerLevelWrapper((WorldServer) GetEventLevel(event)));
+ }
+ }
+
+ @SubscribeEvent
+ public void serverChunkLoadEvent(ChunkEvent.Load event)
+ {
+ ILevelWrapper levelWrapper = ProxyUtil.getLevelWrapper(GetEventLevel(event));
+ IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), levelWrapper);
+ this.serverApi.serverChunkLoadEvent(chunk, levelWrapper);
+ }
+
+ @SubscribeEvent
+ public void serverChunkSaveEvent(ChunkDataEvent.Save event)
+ {
+ if (event.getWorld() instanceof WorldServer worldServer)
+ {
+ MixinChunkMapCommon.onChunkSave(worldServer, event.getChunk());
+ }
+ }
+
+ @SubscribeEvent
+ public void playerLoggedInEvent(PlayerEvent.PlayerLoggedInEvent event)
+ { this.serverApi.serverPlayerJoinEvent(getServerPlayerWrapper(event)); }
+
+ @SubscribeEvent
+ public void playerLoggedOutEvent(PlayerEvent.PlayerLoggedOutEvent event)
+ { this.serverApi.serverPlayerDisconnectEvent(getServerPlayerWrapper(event)); }
+
+ @SubscribeEvent
+ public void playerChangedDimensionEvent(PlayerEvent.PlayerChangedDimensionEvent event)
+ {
+ this.serverApi.serverPlayerLevelChangeEvent(
+ getServerPlayerWrapper(event),
+ getServerLevelWrapper(event.fromDim, event),
+ getServerLevelWrapper(event.toDim, event)
+ );
+ }
+
+ //endregion
+
+
+
+ //================//
+ // helper methods //
+ //================//
+ //region
+
+ private static ServerLevelWrapper getServerLevelWrapper(WorldServer level) { return ServerLevelWrapper.getWrapper(level); }
+
+ private static ServerLevelWrapper getServerLevelWrapper(int dimensionId, PlayerEvent event)
+ {
+ MinecraftServer server = event.player.getServer();
+ if (server == null)
+ {
+ LOGGER.error("getServerLevelWrapper: server is null for player {}", event.player.getName());
+ return null;
+ }
+ return getServerLevelWrapper(server.getWorld(dimensionId));
+ }
+
+ private static ServerPlayerWrapper getServerPlayerWrapper(PlayerEvent event)
+ { return ServerPlayerWrapper.getWrapper((EntityPlayerMP) event.player); }
+
+ //endregion
+
+
+}
diff --git a/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/DistantHorizonsConfigPlugin.java b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/DistantHorizonsConfigPlugin.java
new file mode 100644
index 000000000..3a693feaf
--- /dev/null
+++ b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/DistantHorizonsConfigPlugin.java
@@ -0,0 +1,56 @@
+/*
+ * 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 .
+ */
+
+package com.seibel.distanthorizons.cleanroom;
+
+import net.minecraftforge.fml.common.Loader;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.objectweb.asm.tree.ClassNode;
+import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
+import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
+
+import java.util.List;
+import java.util.Set;
+
+public class DistantHorizonsConfigPlugin implements IMixinConfigPlugin
+{
+ private static final Logger LOGGER = LogManager.getLogger();
+
+ @Override
+ public void onLoad(String mixinPackage)
+ { }
+
+ @Override
+ public boolean shouldApplyMixin(String targetClassName, String mixinClassName)
+ {
+/* return switch (mixinClassName.split("\\.")[5]) {
+ case "mist" -> Loader.isModLoaded("mist");
+ default -> true;
+ };*/
+ return true;
+ }
+
+ @Override public String getRefMapperConfig() { return null; }
+ @Override public void acceptTargets(Set myTargets, Set otherTargets) { }
+ @Override public List getMixins() { return null; }
+ @Override public void preApply(String targetClassName, ClassNode classNode, String mixinClassName, IMixinInfo mixinInfo) { }
+ @Override public void postApply(String targetClassName, ClassNode classNode, String mixinClassName, IMixinInfo mixinInfo) { }
+
+}
diff --git a/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/DistantHorizonsLoadingPlugin.java b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/DistantHorizonsLoadingPlugin.java
new file mode 100644
index 000000000..a604cba7f
--- /dev/null
+++ b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/DistantHorizonsLoadingPlugin.java
@@ -0,0 +1,52 @@
+/*
+ * 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 .
+ */
+
+package com.seibel.distanthorizons.cleanroom;
+
+import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Map;
+
+public class DistantHorizonsLoadingPlugin implements IFMLLoadingPlugin
+{
+ @Override
+ public @Nullable String[] getASMTransformerClass()
+ {
+ return new String[0];
+ }
+ @Override
+ public @Nullable String getModContainerClass()
+ {
+ return null;
+ }
+ @Override
+ public @Nullable String getSetupClass()
+ {
+ return null;
+ }
+ @Override
+ public void injectData(Map data) { }
+ @Override
+ public @Nullable String getAccessTransformerClass()
+ {
+ return null;
+ }
+
+}
diff --git a/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/client/MixinEntityRenderer.java b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/client/MixinEntityRenderer.java
new file mode 100644
index 000000000..bb9be72b2
--- /dev/null
+++ b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/client/MixinEntityRenderer.java
@@ -0,0 +1,84 @@
+/*
+ * 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 .
+ */
+
+package com.seibel.distanthorizons.cleanroom.mixins.client;
+
+import com.seibel.distanthorizons.common.commonMixins.MixinVanillaFogCommon;
+import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
+import com.seibel.distanthorizons.core.api.internal.ClientApi;
+import com.seibel.distanthorizons.core.config.Config;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
+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.renderer.EntityRenderer;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.texture.DynamicTexture;
+import net.minecraft.init.MobEffects;
+import org.apache.logging.log4j.Logger;
+import org.spongepowered.asm.mixin.Final;
+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.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(EntityRenderer.class)
+public class MixinEntityRenderer
+{
+ @Shadow
+ @Final
+ private DynamicTexture lightmapTexture;
+
+ @Shadow @Final private Minecraft mc;
+ @Shadow @Final private static Logger LOGGER;
+ private static final float A_REALLY_REALLY_BIG_VALUE = 420694206942069.F;
+ private static final float A_EVEN_LARGER_VALUE = 42069420694206942069.F;
+
+ @Inject(at = @At("TAIL"), method = "updateLightmap")
+ public void onUpdateLightmap(float patrialTicks, CallbackInfo ci)
+ {
+ IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
+ if (mc == null || mc.getWrappedClientLevel() == null)
+ {
+ return;
+ }
+
+ IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
+ MinecraftRenderWrapper renderWrapper = (MinecraftRenderWrapper)SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
+ renderWrapper.setLightmapId(lightmapTexture.getGlTextureId(), clientLevel);
+ }
+
+ @Inject(at = @At("RETURN"), method = "setupFog")
+ private void disableSetupFog(int startCoords, float partialTicks, CallbackInfo ci)
+ {
+ boolean cancelFog = MixinVanillaFogCommon.cancelFog(startCoords, mc);
+ if (cancelFog)
+ {
+ GlStateManager.setFogStart(A_REALLY_REALLY_BIG_VALUE);
+ GlStateManager.setFogEnd(A_EVEN_LARGER_VALUE);
+ ClientApi.RENDER_STATE.vanillaFogEnabled = false;
+ }
+ else
+ {
+ ClientApi.RENDER_STATE.vanillaFogEnabled = true;
+ }
+ }
+}
diff --git a/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/client/MixinNetHandlerPlayClient.java b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/client/MixinNetHandlerPlayClient.java
new file mode 100644
index 000000000..3f99f5f7c
--- /dev/null
+++ b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/client/MixinNetHandlerPlayClient.java
@@ -0,0 +1,46 @@
+/*
+ * 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 .
+ */
+
+package com.seibel.distanthorizons.cleanroom.mixins.client;
+
+import com.seibel.distanthorizons.core.api.internal.ClientApi;
+import net.minecraft.client.network.NetHandlerPlayClient;
+import net.minecraft.network.play.server.SPacketJoinGame;
+import net.minecraft.util.text.ITextComponent;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(NetHandlerPlayClient.class)
+public class MixinNetHandlerPlayClient
+{
+ @Inject(method = "handleJoinGame", at = @At("RETURN"))
+ private void onHandleJoinGameEnd(SPacketJoinGame packet, CallbackInfo ci)
+ {
+ ClientApi.INSTANCE.onClientOnlyConnected();
+ }
+
+ @Inject(method = "onDisconnect", at = @At("RETURN"))
+ private void onDisconnect(ITextComponent reason, CallbackInfo ci)
+ {
+ ClientApi.INSTANCE.onClientOnlyDisconnected();
+ }
+
+}
diff --git a/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/client/MixinOptionsScreen.java b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/client/MixinOptionsScreen.java
new file mode 100644
index 000000000..82fa8cb47
--- /dev/null
+++ b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/client/MixinOptionsScreen.java
@@ -0,0 +1,83 @@
+/*
+ * 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 .
+ */
+
+package com.seibel.distanthorizons.cleanroom.mixins.client;
+
+import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
+import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
+import com.seibel.distanthorizons.core.config.Config;
+import com.seibel.distanthorizons.coreapi.ModInfo;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiOptions;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.util.ResourceLocation;
+import org.spongepowered.asm.mixin.Mixin;
+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.callback.CallbackInfo;
+
+/**
+ * Adds a button to the menu to goto the config
+ *
+ * @author coolGi
+ * @version 12-02-2021
+ */
+@Mixin(GuiOptions.class)
+public class MixinOptionsScreen extends GuiScreen
+{
+ // Get the texture for the button
+ @Unique private static final ResourceLocation ICON_TEXTURE = new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
+
+ @Unique private static final int button_id = 99;
+
+ @Inject(at = @At("HEAD"), method = "initGui")
+ private void lodconfig$init(CallbackInfo ci)
+ {
+ if (Config.Client.showDhOptionsButtonInMinecraftUi.get())
+ this.buttonList.add(
+ (new TexturedButtonWidget(
+ button_id,
+ // Where the button is on the screen
+ this.width / 2 - 180, this.height / 6 - 12,
+ // Width and height of the button
+ 20, 20,
+ // Offset
+ 0, 0,
+ // Some textuary stuff
+ 20, ICON_TEXTURE, 20, 40,
+ // Create the button and tell it where to go
+ // For now it goes to the client option by default
+ // Add a title to the button
+ ModInfo.ID + ".title")));
+
+ }
+
+ @Inject(at = @At("HEAD"), method = "actionPerformed", cancellable = true)
+ private void lodconfig$actionPerformed(GuiButton button, CallbackInfo ci)
+ {
+ if (button.id == button_id)
+ {
+ Minecraft.getMinecraft().displayGuiScreen(GetConfigScreen.getScreen(this));
+ ci.cancel();
+ }
+ }
+
+}
diff --git a/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/client/MixinRenderGlobal.java b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/client/MixinRenderGlobal.java
new file mode 100644
index 000000000..44ba6e158
--- /dev/null
+++ b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/client/MixinRenderGlobal.java
@@ -0,0 +1,81 @@
+/*
+ * 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 .
+ */
+
+package com.seibel.distanthorizons.cleanroom.mixins.client;
+
+import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
+import com.seibel.distanthorizons.core.api.internal.ClientApi;
+import com.seibel.distanthorizons.core.util.math.Mat4f;
+import net.minecraft.client.multiplayer.WorldClient;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.RenderGlobal;
+import net.minecraft.entity.Entity;
+import net.minecraft.util.BlockRenderLayer;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL15;
+import org.lwjgl.opengl.GL20;
+import org.lwjgl.opengl.GL30;
+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.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+@Mixin(RenderGlobal.class)
+public class MixinRenderGlobal
+{
+ @Shadow private WorldClient world;
+
+ @Inject(method = "renderBlockLayer(Lnet/minecraft/util/BlockRenderLayer;DILnet/minecraft/entity/Entity;)I", at = @At("HEAD"))
+ private void renderChunkLayer(BlockRenderLayer blockLayerIn, double partialTicks, int pass, Entity entityIn, CallbackInfoReturnable cir)
+ {
+ if (blockLayerIn == BlockRenderLayer.SOLID)
+ {
+ float[] mcProjMatrixRaw = new float[16];
+ GL11.glGetFloatv(GL11.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
+ ClientApi.RENDER_STATE.mcProjectionMatrix = new Mat4f(mcProjMatrixRaw);
+ ClientApi.RENDER_STATE.mcProjectionMatrix.transpose();
+
+ float[] mcModelViewRaw = new float[16];
+ GL11.glGetFloatv(GL11.GL_MODELVIEW_MATRIX, mcModelViewRaw);
+ ClientApi.RENDER_STATE.mcModelViewMatrix = new Mat4f(mcModelViewRaw);
+ ClientApi.RENDER_STATE.mcModelViewMatrix.transpose();
+
+ ClientApi.RENDER_STATE.partialTickTime = (float) partialTicks;
+ ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, this.world);
+
+ int blendSrc = GL11.glGetInteger(GL11.GL_BLEND_SRC);
+ int blendDst = GL11.glGetInteger(GL11.GL_BLEND_DST);
+ int boundTexture = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
+
+ ClientApi.INSTANCE.renderLods();
+
+ GL30.glBindVertexArray(0);
+ GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
+ GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
+ GL20.glUseProgram(0);
+
+ //Restore vanilla states
+ GlStateManager.depthFunc(GL11.GL_LEQUAL);
+ GlStateManager.bindTexture(boundTexture);
+ GlStateManager.tryBlendFuncSeparate(blendSrc, blendDst, GL11.GL_ONE, GL11.GL_ZERO);
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/server/MixinEntityPlayerMP.java b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/server/MixinEntityPlayerMP.java
new file mode 100644
index 000000000..300cb53f5
--- /dev/null
+++ b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/mixins/server/MixinEntityPlayerMP.java
@@ -0,0 +1,66 @@
+/*
+ * 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 .
+ */
+
+package com.seibel.distanthorizons.cleanroom.mixins.server;
+
+import com.seibel.distanthorizons.common.wrappers.misc.IMixinServerPlayer;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.world.WorldServer;
+import net.minecraftforge.common.util.ITeleporter;
+import org.jetbrains.annotations.Nullable;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+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.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+@Mixin(EntityPlayerMP.class)
+public abstract class MixinEntityPlayerMP implements IMixinServerPlayer
+{
+ @Shadow
+ @Final
+ public MinecraftServer server;
+
+ @Unique
+ @Nullable
+ private volatile WorldServer distantHorizons$dimensionChangeDestination;
+
+
+
+ @Override
+ @Nullable
+ public WorldServer distantHorizons$getDimensionChangeDestination()
+ { return this.distantHorizons$dimensionChangeDestination; }
+
+ @Inject(at = @At("HEAD"), method = "changeDimension(ILnet/minecraftforge/common/util/ITeleporter;)Lnet/minecraft/entity/Entity;")
+ public void setDimensionChangeDestination(int destinationDimensionID, ITeleporter teleporter, CallbackInfoReturnable cir)
+ { this.distantHorizons$dimensionChangeDestination = this.server.getWorld(destinationDimensionID); }
+
+ @Inject(at = @At("RETURN"), method = "clearInvulnerableDimensionChange")
+ public void clearDimensionChangeDestination(CallbackInfo ci)
+ { this.distantHorizons$dimensionChangeDestination = null; }
+
+
+
+}
diff --git a/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/modAccessor/ModChecker.java b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/modAccessor/ModChecker.java
new file mode 100644
index 000000000..970082aa6
--- /dev/null
+++ b/cleanroom/src/main/java/com/seibel/distanthorizons/cleanroom/modAccessor/ModChecker.java
@@ -0,0 +1,52 @@
+/*
+ * 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 .
+ */
+
+package com.seibel.distanthorizons.cleanroom.modAccessor;
+
+import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
+import net.minecraftforge.fml.common.Loader;
+import net.minecraftforge.fml.common.ModContainer;
+
+import java.io.File;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+public class ModChecker implements IModChecker
+{
+ public static final ModChecker INSTANCE = new ModChecker();
+
+ @Override
+ public boolean isModLoaded(String modid)
+ {
+ return Loader.isModLoaded(modid);
+ }
+
+ @Override
+ public File modLocation(String modid)
+ {
+ Stream foundStream = Loader.instance().getModList().stream().filter(x -> x.getModId().equals(modid));
+ Optional container = foundStream.findFirst();
+ if (!container.isPresent())
+ {
+ throw new RuntimeException("Mod not found: " + modid);
+ }
+ return container.get().getSource();
+ }
+
+}
diff --git a/cleanroom/src/main/resources/distanthorizons.default.mixin.json b/cleanroom/src/main/resources/distanthorizons.default.mixin.json
new file mode 100644
index 000000000..3a766233c
--- /dev/null
+++ b/cleanroom/src/main/resources/distanthorizons.default.mixin.json
@@ -0,0 +1,17 @@
+{
+ "required": true,
+ "package": "com.seibel.distanthorizons.cleanroom.mixins",
+ "compatibilityLevel": "JAVA_8",
+ "target": "@env(DEFAULT)",
+ "mixins": [],
+ "minVersion": "0.8.7",
+ "server": [
+ "server.MixinEntityPlayerMP"
+ ],
+ "client": [
+ "client.MixinEntityRenderer",
+ "client.MixinNetHandlerPlayClient",
+ "client.MixinOptionsScreen",
+ "client.MixinRenderGlobal"
+ ]
+}
\ No newline at end of file
diff --git a/cleanroom/src/main/resources/distanthorizons.mod.mixin.json b/cleanroom/src/main/resources/distanthorizons.mod.mixin.json
new file mode 100644
index 000000000..970fb1a67
--- /dev/null
+++ b/cleanroom/src/main/resources/distanthorizons.mod.mixin.json
@@ -0,0 +1,11 @@
+{
+ "required": false,
+ "package": "com.seibel.distanthorizons.cleanroom.mixins.mod",
+ "compatibilityLevel": "JAVA_8",
+ "target": "@env(MOD)",
+ "mixins": [],
+ "minVersion": "0.8.7",
+ "plugin": "com.seibel.distanthorizons.cleanroom.DistantHorizonsConfigPlugin",
+ "client": [
+ ]
+}
\ No newline at end of file
diff --git a/cleanroom/src/main/resources/mcmod.info b/cleanroom/src/main/resources/mcmod.info
new file mode 100644
index 000000000..e8757de68
--- /dev/null
+++ b/cleanroom/src/main/resources/mcmod.info
@@ -0,0 +1,12 @@
+[{
+ "modid": "${mod_id}",
+ "name": "${mod_name}",
+ "version": "${version}",
+ "mcversion": "1.12.2",
+ "description": "${description}",
+ "authorList": ["${cleanroom_authors}"],
+ "credits": "",
+ "url": "",
+ "updateJSON": "",
+ "logoFile": "${logo_path}"
+}]
\ No newline at end of file
diff --git a/cleanroom/src/main/resources/pack.mcmeta b/cleanroom/src/main/resources/pack.mcmeta
new file mode 100644
index 000000000..daa17a8dc
--- /dev/null
+++ b/cleanroom/src/main/resources/pack.mcmeta
@@ -0,0 +1,6 @@
+{
+ "pack": {
+ "description": "${mod_name} Resources",
+ "pack_format": 3
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java b/common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java
index 4ebc2491a..17bec1ddc 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java
@@ -1,6 +1,5 @@
package com.seibel.distanthorizons.common;
-import com.mojang.brigadier.CommandDispatcher;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
@@ -30,7 +29,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccesso
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.ModInfo;
-import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import com.seibel.distanthorizons.core.logging.DhLogger;
@@ -39,6 +37,11 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
+#if MC_VER > MC_1_12_2
+import com.mojang.brigadier.CommandDispatcher;
+import net.minecraft.commands.CommandSourceStack;
+#endif
+
/**
* Base for all mod loader initializers
* and handles most setup.
@@ -62,7 +65,9 @@ public abstract class AbstractModInitializer
protected abstract IEventProxy createServerProxy(boolean isDedicated);
protected abstract void initializeModCompat();
+ #if MC_VER > MC_1_12_2
protected abstract void subscribeRegisterCommandsEvent(Consumer> eventHandler);
+ #endif
protected abstract void subscribeClientStartedEvent(Runnable eventHandler);
protected abstract void subscribeServerStartingEvent(Consumer eventHandler);
@@ -130,8 +135,10 @@ public abstract class AbstractModInitializer
this.initializeModCompat();
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized, adding event subscribers...");
+ #if MC_VER > MC_1_12_2
this.commandInitializer = new CommandInitializer();
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer.initCommands(dispatcher); });
+ #endif
this.subscribeServerStartingEvent(server ->
{
@@ -141,11 +148,20 @@ public abstract class AbstractModInitializer
Initializer.postConfigInit();
this.postInit();
this.postServerInit();
+ #if MC_VER > MC_1_12_2
this.commandInitializer.onServerReady();
+ #endif
this.checkForUpdates();
- LOGGER.info(ModInfo.READABLE_NAME + " server Initialized at " + server.getServerDirectory());
+ String serverFolderPath;
+ #if MC_VER <= MC_1_12_2
+ serverFolderPath = server.getDataDirectory() + "";
+ #else
+ serverFolderPath = server.getServerDirectory() + "";
+ #endif
+
+ LOGGER.info(ModInfo.READABLE_NAME + " server Initialized at " + serverFolderPath);
});
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/AbstractPluginPacketSender.java b/common/src/main/java/com/seibel/distanthorizons/common/AbstractPluginPacketSender.java
index dd2b400dc..a4b5d6235 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/AbstractPluginPacketSender.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/AbstractPluginPacketSender.java
@@ -12,10 +12,17 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSende
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import io.netty.buffer.ByteBufUtil;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.network.PacketBuffer;
+#else
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
+#endif
-#if MC_VER <= MC_1_21_10
+#if MC_VER <= MC_1_12_2
+import net.minecraft.util.ResourceLocation;
+#elif MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
@@ -30,7 +37,9 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
.fileLevelConfig(Config.Common.Logging.logNetworkEventToFile)
.build();
- #if MC_VER <= MC_1_20_6
+ #if MC_VER <= MC_1_12_2
+ public static final String WRAPPER_PACKET_RESOURCE = "channelDH"; // resource_namespace + packet_path > 20 characters
+ #elif MC_VER <= MC_1_20_6
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
#elif MC_VER <= MC_1_21_10
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
@@ -52,14 +61,14 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
@Override
public final void sendToClient(IServerPlayerWrapper serverPlayer, AbstractNetworkMessage message)
{
- this.sendToClient((ServerPlayer) serverPlayer.getWrappedMcObject(), message);
+ this.sendToClient(#if MC_VER <= MC_1_12_2 (EntityPlayerMP) #else (ServerPlayer) #endif serverPlayer.getWrappedMcObject(), message);
}
- public abstract void sendToClient(ServerPlayer serverPlayer, AbstractNetworkMessage message);
+ public abstract void sendToClient(#if MC_VER <= MC_1_12_2 EntityPlayerMP #else ServerPlayer #endif serverPlayer, AbstractNetworkMessage message);
@Override
public abstract void sendToServer(AbstractNetworkMessage message);
- public AbstractNetworkMessage decodeMessage(FriendlyByteBuf in)
+ public AbstractNetworkMessage decodeMessage(#if MC_VER <= MC_1_12_2 PacketBuffer #else FriendlyByteBuf #endif in)
{
AbstractNetworkMessage message = null;
@@ -100,7 +109,7 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
}
}
- public void encodeMessage(FriendlyByteBuf out, AbstractNetworkMessage message)
+ public void encodeMessage(#if MC_VER <= MC_1_12_2 PacketBuffer #else FriendlyByteBuf #endif out, AbstractNetworkMessage message)
{
// This is intentionally unhandled, because errors related to this are unlikely to appear in wild
Objects.requireNonNull(message);
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/commands/AbstractCommand.java b/common/src/main/java/com/seibel/distanthorizons/common/commands/AbstractCommand.java
index 01e177ef2..4e8d38eb0 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/commands/AbstractCommand.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/commands/AbstractCommand.java
@@ -1,5 +1,9 @@
package com.seibel.distanthorizons.common.commands;
+#if MC_VER <= MC_1_12_2
+public abstract class AbstractCommand {}
+
+#else
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
@@ -100,3 +104,4 @@ public abstract class AbstractCommand
}
}
+#endif
\ No newline at end of file
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/commands/CommandInitializer.java b/common/src/main/java/com/seibel/distanthorizons/common/commands/CommandInitializer.java
index dc29975a9..ba0456a32 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/commands/CommandInitializer.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/commands/CommandInitializer.java
@@ -1,12 +1,26 @@
package com.seibel.distanthorizons.common.commands;
-
+#if MC_VER <= MC_1_12_2
+import com.seibel.distanthorizons.core.config.ConfigHandler;
+import com.seibel.distanthorizons.core.config.types.AbstractConfigBase;
+import com.seibel.distanthorizons.core.config.types.ConfigEntry;
+import com.seibel.distanthorizons.core.logging.f3.F3Screen;
+import net.minecraft.command.CommandBase;
+import net.minecraft.command.ICommand;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.text.TextComponentString;
+#else
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.minecraft.commands.CommandSourceStack;
+import static net.minecraft.commands.Commands.literal;
+#endif
import org.jetbrains.annotations.Nullable;
+import java.util.ArrayList;
+import java.util.List;
+
import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_CODEC_CRASH_MESSAGE;
-import static net.minecraft.commands.Commands.literal;
#if MC_VER <= MC_1_21_10
#else
@@ -25,6 +39,70 @@ public class CommandInitializer
#endif
+
+ #if MC_VER <= MC_1_12_2
+ public static ICommand initCommands()
+ {
+ return new CommandBase()
+ {
+ @Override
+ public String getName() { return "dh"; }
+
+ @Override
+ public String getUsage(ICommandSender sender) { return "/dh "; }
+
+ @Override
+ public void execute(MinecraftServer server, ICommandSender sender, String[] args)
+ {
+ if (args.length == 0)
+ {
+ if (DEBUG_CODEC_CRASH_MESSAGE)
+ {
+ sender.sendMessage(new TextComponentString("Usage: /dh "));
+ }
+ else
+ {
+ sender.sendMessage(new TextComponentString("Usage: /dh configEntry, String value)
+ {
+ Class> type = configEntry.getType();
+
+ if (type == Boolean.class) ((ConfigEntry) configEntry).set(Boolean.parseBoolean(value));
+ else if (type == Integer.class) ((ConfigEntry) configEntry).set(Integer.parseInt(value));
+ else if (type == Double.class) ((ConfigEntry) configEntry).set(Double.parseDouble(value));
+ else if (type == Float.class) ((ConfigEntry) configEntry).set(Float.parseFloat(value));
+ else if (type == Long.class) ((ConfigEntry) configEntry).set(Long.parseLong(value));
+ else if (type == String.class) ((ConfigEntry) configEntry).set(value);
+ else if (type.isEnum()) ((ConfigEntry) configEntry).set(Enum.valueOf((Class) type, value));
+ else throw new RuntimeException("Unsupported config type: " + type.getSimpleName());
+ }
+ public void execute(ICommandSender sender, String[] args)
+ {
+ if (args.length < 2)
+ {
+ sender.sendMessage(new TextComponentString("Usage: /dh config [value]"));
+ return;
+ }
+
+ String configName = args[1];
+ AbstractConfigBase> found = null;
+ for (AbstractConfigBase> entry : ConfigHandler.INSTANCE.configBaseList)
+ {
+ if (entry instanceof ConfigEntry && configName.equals(((ConfigEntry>) entry).getChatCommandName()))
+ {
+ found = entry;
+ break;
+ }
+ }
+
+ if (found == null)
+ {
+ sender.sendMessage(new TextComponentString("Unknown config: " + configName));
+ return;
+ }
+
+ ConfigEntry> configEntry = (ConfigEntry>) found;
+ if (args.length == 2)
+ {
+ sender.sendMessage(new TextComponentString("Current value of " + configName + " is " + configEntry.get()));
+ }
+ else
+ {
+ String value = args[2];
+ try
+ {
+ setConfigValue(configEntry, value);
+ sender.sendMessage(new TextComponentString("Changed " + configName + " to " + value));
+ }
+ catch (Exception e)
+ {
+ sender.sendMessage(new TextComponentString("Invalid value: " + value));
+ }
+ }
+ }
+
+ #else
+
private static final List> commandArguments = Arrays.asList(
new CommandArgumentData<>(Integer.class, configEntry -> integer(configEntry.getMin(), configEntry.getMax()), IntegerArgumentType::getInteger),
new CommandArgumentData<>(Double.class, configEntry -> doubleArg(configEntry.getMin(), configEntry.getMax()), DoubleArgumentType::getDouble),
@@ -150,5 +221,6 @@ public class ConfigCommand extends AbstractCommand
}
}
+ #endif
-}
\ No newline at end of file
+}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/commands/CrashCommand.java b/common/src/main/java/com/seibel/distanthorizons/common/commands/CrashCommand.java
index 7c6f09d71..5b9fd17d2 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/commands/CrashCommand.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/commands/CrashCommand.java
@@ -1,15 +1,60 @@
package com.seibel.distanthorizons.common.commands;
-import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerState;
import com.seibel.distanthorizons.core.network.messages.base.CodecCrashMessage;
+
+#if MC_VER <= MC_1_12_2
+import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.util.text.TextComponentString;
+#else
import net.minecraft.commands.CommandSourceStack;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import static net.minecraft.commands.Commands.literal;
+#endif
+
public class CrashCommand extends AbstractCommand
{
+ #if MC_VER <= MC_1_12_2
+ public void execute(ICommandSender sender, String[] args)
+ {
+ if (!(sender instanceof EntityPlayerMP))
+ {
+ sender.sendMessage(new TextComponentString("This command can only be run by a player"));
+ return;
+ }
+
+ if (args.length < 2)
+ {
+ sender.sendMessage(new TextComponentString("Usage: /dh crash "));
+ return;
+ }
+
+ if (SharedApi.tryGetDhServerWorld() == null) return;
+
+ ServerPlayerState serverPlayerState = SharedApi.tryGetDhServerWorld()
+ .getServerPlayerStateManager()
+ .getConnectedPlayer(ServerPlayerWrapper.getWrapper((EntityPlayerMP) sender));
+
+ if (serverPlayerState == null) return;
+
+ switch (args[1])
+ {
+ case "encode":
+ serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.ENCODE));
+ break;
+ case "decode":
+ serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.DECODE));
+ break;
+ default:
+ sender.sendMessage(new TextComponentString("Usage: /dh crash "));
+ }
+ }
+ #else
@Override
public LiteralArgumentBuilder buildCommand()
{
@@ -40,5 +85,6 @@ public class CrashCommand extends AbstractCommand
return 1;
}));
}
+ #endif
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/commands/DebugCommand.java b/common/src/main/java/com/seibel/distanthorizons/common/commands/DebugCommand.java
index 88b1c8311..77a21d783 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/commands/DebugCommand.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/commands/DebugCommand.java
@@ -1,25 +1,44 @@
package com.seibel.distanthorizons.common.commands;
-import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
+
+#if MC_VER <= MC_1_12_2
+import net.minecraft.command.ICommandSender;
+import net.minecraft.util.text.TextComponentString;
+#else
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.minecraft.commands.CommandSourceStack;
+import static net.minecraft.commands.Commands.literal;
+#endif
+
import java.util.ArrayList;
import java.util.List;
-import static net.minecraft.commands.Commands.literal;
public class DebugCommand extends AbstractCommand
{
+ private static String getDebugString()
+ {
+ List lines = new ArrayList<>();
+ F3Screen.addStringToDisplay(lines);
+ return String.join("\n", lines);
+ }
+
+ #if MC_VER > MC_1_12_2
@Override
public LiteralArgumentBuilder buildCommand()
{
- return literal("debug")
- .executes(c -> {
- List lines = new ArrayList<>();
- F3Screen.addStringToDisplay(lines);
- return this.sendSuccessResponse(c, String.join("\n", lines), false);
- });
+ return literal("debug")
+ .executes(c -> {
+ return this.sendSuccessResponse(c, getDebugString(), false);
+ });
}
+ #else
+ public void execute(ICommandSender sender)
+ {
+ sender.sendMessage(new TextComponentString(getDebugString()));
+ }
+ #endif
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/commands/PregenCommand.java b/common/src/main/java/com/seibel/distanthorizons/common/commands/PregenCommand.java
index 3cb0a88de..367b9d1be 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/commands/PregenCommand.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/commands/PregenCommand.java
@@ -1,27 +1,36 @@
package com.seibel.distanthorizons.common.commands;
-import com.mojang.brigadier.builder.LiteralArgumentBuilder;
-import com.mojang.brigadier.context.CommandContext;
-import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.generation.PregenManager;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
import com.seibel.distanthorizons.core.world.DhServerWorld;
+
+#if MC_VER <= MC_1_12_2
+import net.minecraft.command.ICommandSender;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.text.TextComponentString;
+import net.minecraft.world.WorldServer;
+#else
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.arguments.DimensionArgument;
import net.minecraft.commands.arguments.coordinates.ColumnPosArgument;
import net.minecraft.server.level.ColumnPos;
import net.minecraft.server.level.ServerLevel;
-import java.util.Objects;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.CompletableFuture;
-
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static net.minecraft.commands.Commands.argument;
import static net.minecraft.commands.Commands.literal;
+#endif
+
+import java.util.Objects;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+
public class PregenCommand extends AbstractCommand
{
@@ -31,6 +40,101 @@ public class PregenCommand extends AbstractCommand
return world.getPregenManager();
}
+ #if MC_VER <= MC_1_12_2
+ public void execute(MinecraftServer server, ICommandSender sender, String[] args)
+ {
+ if (args.length < 2)
+ {
+ sender.sendMessage(new TextComponentString("Usage: /dh pregen "));
+ return;
+ }
+
+ switch (args[1])
+ {
+ case "status":
+ {
+ String statusString = this.getPregenManager().getStatusString();
+ sender.sendMessage(new TextComponentString(
+ statusString != null ? statusString : "Pregen is not running"));
+ break;
+ }
+ case "start":
+ {
+ if (args.length < 5)
+ {
+ sender.sendMessage(new TextComponentString("Usage: /dh pregen start "));
+ return;
+ }
+
+ try
+ {
+ String dimensionName = args[2];
+ int x = Integer.parseInt(args[3]);
+ int z = Integer.parseInt(args[4]);
+ int chunkRadius = args.length >= 6 ? Integer.parseInt(args[5]) : 32;
+
+ // find the world by dimension name
+ WorldServer world = null;
+ for (WorldServer w : server.worlds)
+ {
+ if (w.provider.getDimensionType().getName().equals(dimensionName))
+ {
+ world = w;
+ break;
+ }
+ }
+
+ if (world == null)
+ {
+ sender.sendMessage(new TextComponentString("Unknown dimension: " + dimensionName));
+ return;
+ }
+
+ sender.sendMessage(new TextComponentString("Starting pregen. Progress will be in the server console."));
+
+ final ICommandSender finalSender = sender;
+ CompletableFuture future = this.getPregenManager().startPregen(
+ ServerLevelWrapper.getWrapper(world),
+ new DhBlockPos2D(x, z),
+ chunkRadius
+ );
+
+ future.whenComplete((result, throwable) -> {
+ if (throwable instanceof CancellationException)
+ {
+ finalSender.sendMessage(new TextComponentString("Pregen is cancelled"));
+ return;
+ }
+ else if (throwable != null)
+ {
+ finalSender.sendMessage(new TextComponentString("Pregen failed: " + throwable.getMessage()));
+ return;
+ }
+ finalSender.sendMessage(new TextComponentString("Pregen is complete"));
+ });
+ }
+ catch (NumberFormatException e)
+ {
+ sender.sendMessage(new TextComponentString("Invalid number format"));
+ }
+ break;
+ }
+ case "stop":
+ {
+ CompletableFuture runningPregen = this.getPregenManager().getRunningPregen();
+ if (runningPregen == null)
+ {
+ sender.sendMessage(new TextComponentString("Pregen is not running"));
+ return;
+ }
+ runningPregen.cancel(true);
+ break;
+ }
+ default:
+ sender.sendMessage(new TextComponentString("Unknown subcommand: " + args[1]));
+ }
+ }
+ #else
@Override
public LiteralArgumentBuilder buildCommand()
{
@@ -110,5 +214,5 @@ public class PregenCommand extends AbstractCommand
runningPregen.cancel(true);
return 1;
}
-
+ #endif
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/commonMixins/DhUpdateScreenBase.java b/common/src/main/java/com/seibel/distanthorizons/common/commonMixins/DhUpdateScreenBase.java
index e40507521..98293d7c3 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/commonMixins/DhUpdateScreenBase.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/commonMixins/DhUpdateScreenBase.java
@@ -1,5 +1,6 @@
package com.seibel.distanthorizons.common.commonMixins;
+#if MC_VER > MC_1_12_2
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
import com.seibel.distanthorizons.core.config.Config;
@@ -11,16 +12,18 @@ import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.screens.TitleScreen;
+#if MC_VER <= MC_1_12_2
+#else
+import net.minecraft.client.gui.screens.TitleScreen;
+#endif
import java.util.ArrayList;
public class DhUpdateScreenBase
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
- private static final Minecraft MC = Minecraft.getInstance();
-
+ private static final Minecraft MC = Minecraft #if MC_VER <= MC_1_12_2 .getMinecraft() #else .getInstance() #endif;
public static void tryShowUpdateScreenAndRunAutoUpdateStartup(Runnable runnable)
@@ -86,3 +89,4 @@ public class DhUpdateScreenBase
}
}
+#endif
\ No newline at end of file
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/commonMixins/MixinChunkMapCommon.java b/common/src/main/java/com/seibel/distanthorizons/common/commonMixins/MixinChunkMapCommon.java
index 4f04819d0..b72886fb4 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/commonMixins/MixinChunkMapCommon.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/commonMixins/MixinChunkMapCommon.java
@@ -6,15 +6,23 @@ import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.world.WorldServer;
+import net.minecraft.world.chunk.Chunk;
+#else
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk;
+#endif
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public class MixinChunkMapCommon
{
-
+ #if MC_VER <= MC_1_12_2
+ public static void onChunkSave(WorldServer level, Chunk chunk)
+ #else
public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable ci)
+ #endif
{
IServerLevelWrapper levelWrapper = ServerLevelWrapper.getWrapper(level);
@@ -37,7 +45,7 @@ public class MixinChunkMapCommon
// is this chunk being saved to disk?
- boolean savingChunkToDisk = ci.getReturnValue();
+ boolean savingChunkToDisk = #if MC_VER <= MC_1_12_2 true #else ci.getReturnValue() #endif;
// true means a chunk was saved to disk
if (!savingChunkToDisk)
{
@@ -50,7 +58,12 @@ public class MixinChunkMapCommon
// MC has a tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks)
// this logic should prevent that from happening
- #if MC_VER <= MC_1_17_1
+ #if MC_VER <= MC_1_12_2
+ if (!chunk.isTerrainPopulated() || !chunk.isLightPopulated())
+ {
+ return;
+ }
+ #elif MC_VER <= MC_1_17_1
if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
{
return;
@@ -67,7 +80,12 @@ public class MixinChunkMapCommon
// biome validation //
// some chunks may be missing their biomes, which cause issues when attempting to save them
- #if MC_VER <= MC_1_17_1
+ #if MC_VER <= MC_1_12_2
+ if (chunk. getBiomeArray() == null)
+ {
+ return;
+ }
+ #elif MC_VER <= MC_1_17_1
if (chunk.getBiomes() == null)
{
return;
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/commonMixins/MixinVanillaFogCommon.java b/common/src/main/java/com/seibel/distanthorizons/common/commonMixins/MixinVanillaFogCommon.java
index ee90f8499..e198607f9 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/commonMixins/MixinVanillaFogCommon.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/commonMixins/MixinVanillaFogCommon.java
@@ -12,11 +12,18 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapp
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
+#if MC_VER <= MC_1_12_2
+#else
+import net.minecraft.client.Camera;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
+#endif
-#if MC_VER < MC_1_17_1
+#if MC_VER <= MC_1_12_2
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.init.MobEffects;
+#elif MC_VER < MC_1_17_1
import net.minecraft.world.level.material.FluidState;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.FogRenderer.FogMode;
@@ -57,16 +64,18 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
public class MixinVanillaFogCommon
{
-
- #if MC_VER < MC_1_21_6
+ #if MC_VER <= MC_1_12_2
+ public static boolean cancelFog(int startCoords, Minecraft mc)
+ #elif MC_VER < MC_1_21_6
public static boolean cancelFog(Camera camera, FogRenderer.FogMode fogMode)
#else
public static boolean cancelFog()
#endif
{
-
- #if MC_VER < MC_1_21_6
+ #if MC_VER <= MC_1_12_2
+ EntityPlayerSP entity = mc.player;
+ #elif MC_VER < MC_1_21_6
Entity entity = camera.getEntity();
#elif MC_VER <= MC_1_21_10
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
@@ -76,13 +85,23 @@ public class MixinVanillaFogCommon
Entity entity = camera.entity();
#endif
-
+ #if MC_VER <= MC_1_12_2
+ boolean cameraNotInFluid = cameraNotInFluid(mc);
+ #else
boolean cameraNotInFluid = cameraNotInFluid(camera);
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ boolean isSpecialFog = entity.isPotionActive(MobEffects.BLINDNESS);
+ #else
boolean isSpecialFog = (entity instanceof LivingEntity) && ((LivingEntity) entity).hasEffect(MobEffects.BLINDNESS);
+ #endif
boolean cancelFog = !isSpecialFog;
cancelFog = cancelFog && cameraNotInFluid;
- #if MC_VER < MC_1_21_6
+ #if MC_VER <= MC_1_12_2
+ cancelFog = cancelFog && startCoords == 0; // 0 = terrain fog
+ #elif MC_VER < MC_1_21_6
cancelFog = cancelFog && (fogMode == FogRenderer.FogMode.FOG_TERRAIN);
#endif
@@ -100,10 +119,15 @@ public class MixinVanillaFogCommon
return cancelFog;
}
-
+ #if MC_VER <= MC_1_12_2
+ private static boolean cameraNotInFluid(Minecraft mc)
+ #else
private static boolean cameraNotInFluid(Camera camera)
+ #endif
{
- #if MC_VER < MC_1_17_1
+ #if MC_VER <= MC_1_12_2
+ boolean cameraNotInFluid = mc.getRenderViewEntity() != null && !mc.world.getBlockState(mc.getRenderViewEntity().getPosition()).getMaterial().isLiquid();
+ #elif MC_VER < MC_1_17_1
FluidState fluidState = camera.getFluidInCamera();
boolean cameraNotInFluid = fluidState.isEmpty();
#else
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/BlazeDhGenericObjectRenderer.java b/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/BlazeDhGenericObjectRenderer.java
index be403eaaa..fd92d28fe 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/BlazeDhGenericObjectRenderer.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/BlazeDhGenericObjectRenderer.java
@@ -57,6 +57,7 @@ import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.render.RenderParams;
+import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
@@ -615,5 +616,27 @@ public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
+ //================//
+ // base overrides //
+ //================//
+ //region
+
+ @Override
+ public void close()
+ {
+ // close is called outside the render thread and buffer closing must be done on the render thread
+ RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Generic Obj Cleanup", () ->
+ {
+ if (this.vertUniformBuffer != null)
+ {
+ this.vertUniformBuffer.close();
+ }
+ });
+ }
+
+ //endregion
+
+
+
}
#endif
\ No newline at end of file
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/generic/GlGenericObjectRenderer.java b/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/generic/GlGenericObjectRenderer.java
index a6fbb61b1..5670cf08e 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/generic/GlGenericObjectRenderer.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/generic/GlGenericObjectRenderer.java
@@ -748,4 +748,27 @@ public class GlGenericObjectRenderer implements IDhGenericRenderer
+ //================//
+ // base overrides //
+ //================//
+ //region
+
+ @Override
+ public void close()
+ {
+ if (this.boxVertexBuffer != null)
+ {
+ this.boxVertexBuffer.close();
+ }
+
+ if (this.boxIndexBuffer != null)
+ {
+ this.boxIndexBuffer.close();
+ }
+ }
+
+ //endregion
+
+
+
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/GLState.java b/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/GLState.java
index 6107a7a24..b5f9bb355 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/GLState.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/GLState.java
@@ -97,7 +97,9 @@ public class GLState implements AutoCloseable
{
this.frameBufferTexture0 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
this.frameBufferTexture1 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
- this.frameBufferDepthTexture = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
+
+ int depthType = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
+ this.frameBufferDepthTexture = (depthType == GL32.GL_TEXTURE) ? GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) : 0;
}
else
{
@@ -179,9 +181,21 @@ public class GLState implements AutoCloseable
// attempting to set textures on the default frame buffer (ID 0) will throw errors
if (frameBufferSet)
{
- GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.frameBufferTexture0, 0);
- GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_TEXTURE_2D, this.frameBufferTexture1, 0);
- GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_TEXTURE_2D, this.frameBufferDepthTexture, 0);
+ if (GL32.glIsTexture(this.frameBufferTexture0))
+ {
+ GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.frameBufferTexture0, 0);
+ }
+
+ if (this.frameBufferTexture1 != 0 && GL32.glIsTexture(this.frameBufferTexture1))
+ {
+ GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_TEXTURE_2D, this.frameBufferTexture1, 0);
+ }
+
+ if (GL32.glIsTexture(this.frameBufferDepthTexture))
+ {
+ GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_TEXTURE_2D, this.frameBufferDepthTexture, 0);
+ }
+
}
GL32.glBindVertexArray(GL32.glIsVertexArray(this.vao) ? this.vao : 0);
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/buffer/GLBuffer.java b/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/buffer/GLBuffer.java
index bcde6edbf..27aad3dc0 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/buffer/GLBuffer.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/buffer/GLBuffer.java
@@ -23,11 +23,17 @@ import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.config.Config;
+import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
+import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.ThreadUtil;
+import com.seibel.distanthorizons.core.util.objects.Pair;
+import com.seibel.distanthorizons.core.util.objects.pooling.PhantomLoggingHelper;
+import com.seibel.distanthorizons.coreapi.ModInfo;
+import com.seibel.distanthorizons.coreapi.util.StringUtil;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL44;
@@ -35,6 +41,8 @@ import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
@@ -50,14 +58,35 @@ public class GLBuffer implements AutoCloseable
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
+ // TODO move to a shared location that can be handled by both GL and Blaze3D buffers
+ /** if enabled the number of GC'ed buffers will be logged */
+ private static final boolean LOG_PHANTOM_RECOVERY = ModInfo.IS_DEV_BUILD;
+ /** If enabled buffers allocation/upload stacks will be logged when GC'ed. */
+ private static final boolean LOG_PHANTOM_ALLOCATION_STACKS = false; // disabled by default due to the increased GC load
+
public static final double BUFFER_EXPANSION_MULTIPLIER = 1.3;
public static final double BUFFER_SHRINK_TRIGGER = BUFFER_EXPANSION_MULTIPLIER * BUFFER_EXPANSION_MULTIPLIER;
+
+ /**
+ * On macOS the legacy OpenGL -> Metal bridge crashes with SIGBUS in
+ * {@code _platform_memmove} when {@code glBufferData} or {@code glBufferSubData}
+ * are called with a large ByteBuffer in one shot. To work around it, we split
+ * the upload into smaller sub-data calls that each fit comfortably inside the
+ * driver's internal staging path.
+ * 256 KiB tuned empirically against macOS 26.5 — a 1 MiB chunk still
+ * tripped the same {@code _platform_memmove} crash inside
+ * {@code glBufferSubData_Exec}, but 256 KiB consistently survives.
+ */
+ public static final int MAC_UPLOAD_CHUNK_BYTES = 256 * 1024;
+ /** Threshold above which the chunked path kicks in on macOS. */
+ public static final int MAC_UPLOAD_CHUNK_THRESHOLD = MAC_UPLOAD_CHUNK_BYTES;
/** the number of active buffers, can be used for debugging */
public static AtomicInteger bufferCount = new AtomicInteger(0);
private static final int PHANTOM_REF_CHECK_TIME_IN_MS = 5 * 1000;
private static final ConcurrentHashMap, Integer> PHANTOM_TO_BUFFER_ID = new ConcurrentHashMap<>();
private static final ConcurrentHashMap> BUFFER_ID_TO_PHANTOM = new ConcurrentHashMap<>();
+ private static final ConcurrentHashMap BUFFER_ID_TO_ALLOCATION_STRING = new ConcurrentHashMap<>();
private static final ReferenceQueue PHANTOM_REFERENCE_QUEUE = new ReferenceQueue<>();
private static final ThreadPoolExecutor CLEANUP_THREAD = ThreadUtil.makeSingleDaemonThreadPool("GLBuffer Cleanup");
@@ -128,8 +157,9 @@ public class GLBuffer implements AutoCloseable
long writeStamp = renderStampLock.writeLock();
try
{
- int oldId = this.id;
+ final int oldId = this.id;
this.id = GLMC.glGenBuffers();
+ //LOGGER.info("created [" + newId + "].");
// destroy the old buffer
// after the new one has been created
@@ -139,7 +169,7 @@ public class GLBuffer implements AutoCloseable
{
// this ID doesn't need to be tracked anymore
tryRemoveBufferIdFromPhantom(oldId);
- destroyBufferIdNow(oldId);
+ destroyBufferIdNow(oldId, "destroyOldAndCreate");
}
@@ -149,6 +179,8 @@ public class GLBuffer implements AutoCloseable
PhantomReference phantom = new PhantomReference<>(this, PHANTOM_REFERENCE_QUEUE);
PHANTOM_TO_BUFFER_ID.put(phantom, this.id);
BUFFER_ID_TO_PHANTOM.put(this.id, phantom);
+
+ this.updateAllocationStackTrace();
}
finally
{
@@ -181,7 +213,8 @@ public class GLBuffer implements AutoCloseable
this.id = 0;
this.size = 0;
- RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer destroyAsync", () -> { destroyBufferIdNow(idToDelete); });
+ //LOGGER.info("async destroy [" + idToDelete + "].");
+ RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer destroyAsync", () -> { destroyBufferIdNow(idToDelete, "destroyAsync"); });
}
finally
{
@@ -189,49 +222,43 @@ public class GLBuffer implements AutoCloseable
}
}
- private static void destroyBufferIdNow(int id)
+ private static void destroyBufferIdNow(int id, String cause)
{
// only delete valid buffers
if (id == 0)
{
- LOGGER.warn("Attempted to destroy a buffer with ID 0, VRAM memory leaks may occur.");
+ LOGGER.warn("Attempted to destroy a buffer with ID 0, VRAM memory leaks may occur, cause: ["+cause+"].");
return;
}
bufferCount.decrementAndGet();
+ GLMC.glDeleteBuffers(id);
- // destroy the buffer if it exists,
- // the buffer may not exist if the destroy method is called twice
- if (GL32.glIsBuffer(id))
+ if (Config.Client.Advanced.Debugging.logBufferGarbageCollection.get())
{
- GLMC.glDeleteBuffers(id);
-
- if (Config.Client.Advanced.Debugging.logBufferGarbageCollection.get())
- {
- LOGGER.info("destroyed buffer [" + id + "], remaining: [" + BUFFER_ID_TO_PHANTOM.size() + "]");
- }
- }
- else
- {
- // shouldn't happen, but just in case
- LOGGER.warn("Attempted to destroy a non buffer object with ID ["+id+"].");
+ LOGGER.info("destroyed buffer [" + id + "], remaining: [" + BUFFER_ID_TO_PHANTOM.size() + "], cause: ["+cause+"].");
}
}
/** should be called before {@link GLBuffer#destroyBufferIdNow} */
private static void tryRemoveBufferIdFromPhantom(int id)
{
- if (BUFFER_ID_TO_PHANTOM.containsKey(id))
+ // will contain nothing if stack tracking isn't enabled
+ BUFFER_ID_TO_ALLOCATION_STRING.remove(id);
+
+ PhantomReference extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.remove(id);
+ if (phantom != null)
{
- Reference extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.get(id);
-
// if we are manually closing this buffer, we don't want the phantom reference to accidentally close it again
// this can cause a race condition were we accidentally delete an in-use buffer and cause NVIDIA
// to throw an EXCEPTION_ACCESS_VIOLATION when we attempt to render it
phantom.clear();
- PHANTOM_TO_BUFFER_ID.remove(phantom);
- BUFFER_ID_TO_PHANTOM.remove(id);
+ Integer phantomId = PHANTOM_TO_BUFFER_ID.remove(phantom);
+ if (phantomId == null)
+ {
+ LOGGER.warn("No Phantom->ID binding stored for ID ["+id+"]");
+ }
}
else
{
@@ -322,8 +349,25 @@ public class GLBuffer implements AutoCloseable
LodUtil.assertTrue(!this.bufferStorage, "Buffer is bufferStorage but its trying to use bufferData upload method!");
int bbSize = bb.limit() - bb.position();
- GL32.glBufferData(this.getBufferBindingTarget(), bb, bufferDataHint);
+ int target = this.getBufferBindingTarget();
+
+ if (shouldUploadToGpuInChunks(bbSize))
+ {
+ // Two-step path used on macOS to dodge the Apple OpenGL -> Metal
+ // memmove SIGBUS triggered by uploading a large ByteBuffer in one
+ // glBufferData call:
+ // 1) allocate-only with the size overload (no memcpy)
+ // 2) fill the buffer through chunked glBufferSubData calls
+ GL32.glBufferData(target, (long) bbSize, bufferDataHint);
+ subDataUploadInChunks(target, 0, bb, MAC_UPLOAD_CHUNK_BYTES);
+ }
+ else
+ {
+ GL32.glBufferData(target, bb, bufferDataHint);
+ }
this.size = bbSize;
+
+ this.updateAllocationStackTrace();
}
/** Requires the buffer to be bound */
protected void uploadSubData(ByteBuffer bb, int maxExpansionSize, int bufferDataHint)
@@ -331,14 +375,30 @@ public class GLBuffer implements AutoCloseable
LodUtil.assertTrue(!this.bufferStorage, "Buffer is bufferStorage but its trying to use subData upload method!");
int bbSize = bb.limit() - bb.position();
+ int target = this.getBufferBindingTarget();
if (this.size < bbSize || this.size > bbSize * BUFFER_SHRINK_TRIGGER)
{
int newSize = (int) (bbSize * BUFFER_EXPANSION_MULTIPLIER);
- if (newSize > maxExpansionSize) newSize = maxExpansionSize;
- GL32.glBufferData(this.getBufferBindingTarget(), newSize, bufferDataHint);
+ if (newSize > maxExpansionSize)
+ {
+ newSize = maxExpansionSize;
+ }
+
+ // allocate-only — no memcpy, safe on macOS regardless of size
+ GL32.glBufferData(target, (long) newSize, bufferDataHint);
this.size = newSize;
}
- GL32.glBufferSubData(this.getBufferBindingTarget(), 0, bb);
+
+ if (shouldUploadToGpuInChunks(bbSize))
+ {
+ subDataUploadInChunks(target, 0, bb, MAC_UPLOAD_CHUNK_BYTES);
+ }
+ else
+ {
+ GL32.glBufferSubData(target, 0, bb);
+ }
+
+ this.updateAllocationStackTrace();
}
//endregion
@@ -396,6 +456,91 @@ public class GLBuffer implements AutoCloseable
}
}
+ /**
+ * macOS-only mitigation for the SIGBUS in
+ * {@code libsystem_platform.dylib _platform_memmove} that happens when the
+ * Apple OpenGL -> Metal translation layer copies a single large ByteBuffer
+ * out of LWJGL into driver memory. Splitting the copy into
+ * {@link #MAC_UPLOAD_CHUNK_BYTES} slices keeps every memmove inside a size
+ * the bridge handles reliably.
+ */
+ private static boolean shouldUploadToGpuInChunks(int byteCount)
+ {
+ return EPlatform.get() == EPlatform.MACOS
+ && byteCount > MAC_UPLOAD_CHUNK_THRESHOLD;
+ }
+
+ /**
+ * Uploads {@code bb} into the currently bound buffer at {@code baseOffset}
+ * using a sequence of {@link GL32#glBufferSubData(int, long, ByteBuffer)}
+ * calls of at most {@code chunkBytes} each. The buffer's position/limit are
+ * restored before returning.
+ */
+ private static void subDataUploadInChunks(int target, int baseOffset, ByteBuffer bb, int chunkBytes)
+ {
+ final int origPos = bb.position();
+ final int origLimit = bb.limit();
+ try
+ {
+ final int total = origLimit - origPos;
+ int uploaded = 0;
+ while (uploaded < total)
+ {
+ int chunk = Math.min(chunkBytes, total - uploaded);
+ bb.position(origPos + uploaded);
+ bb.limit(origPos + uploaded + chunk);
+ GL32.glBufferSubData(target, (long) (baseOffset + uploaded), bb);
+ uploaded += chunk;
+ // Force the driver to drain its command queue between chunks
+ // so the OpenGL -> Metal bridge processes (and frees) each
+ // staging copy before the next sub-data call piles another
+ // memmove on top of it.
+ if (uploaded < total)
+ {
+ GL32.glFlush();
+ }
+ }
+ }
+ finally
+ {
+ bb.limit(origLimit);
+ bb.position(origPos);
+ }
+ }
+
+ /**
+ * used to help track down leaks where the buffer isn't properly closed
+ * Note: this probably needs extending to accept a stack trace from outside where it's being called
+ * since it's often called on the render thread in an un-helpful location.
+ */
+ public void updateAllocationStackTrace()
+ {
+ if (LOG_PHANTOM_ALLOCATION_STACKS)
+ {
+ String stack;
+
+ RenderThreadTaskHandler.QueuedRunnable parentQueuedRunnable;
+ // if this is running on the render thread, try getting the render task's stack trace instead
+ // since it's a lot more helpful than wherever the render thread tasks themselves are being run from
+ if (RenderThreadTaskHandler.INSTANCE.isCurrentThread()
+ && (parentQueuedRunnable = RenderThreadTaskHandler.INSTANCE.getCurrentlyRunningTask()) != null
+ && parentQueuedRunnable.stackTrace != null)
+ {
+ // trim off the getStacktrace() and queueRunningOnRenderThread() methods
+ StackTraceElement[] trimmedElements = Arrays.copyOfRange(parentQueuedRunnable.stackTrace, 2, parentQueuedRunnable.stackTrace.length);
+ stack = StringUtil.join("\n", trimmedElements).intern();
+ }
+ else
+ {
+ // not running on the render thread, use the normal stack trace
+ StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
+ stack = StringUtil.join("\n", stackTraceElements).intern();
+ }
+
+ BUFFER_ID_TO_ALLOCATION_STRING.put(this.id, stack);
+ }
+ }
+
//endregion
@@ -407,8 +552,13 @@ public class GLBuffer implements AutoCloseable
private static void runPhantomReferenceCleanupLoop()
{
+ // these arrays are stored here so they don't have to be re-allocated each loop
+ ArrayList> allocationStackTraceCountPairList = new ArrayList<>();
+
while (true)
{
+ allocationStackTraceCountPairList.clear();
+
try
{
try
@@ -417,20 +567,53 @@ public class GLBuffer implements AutoCloseable
}
catch (InterruptedException ignore) { }
+ int collectedCount = 0;
Reference extends GLBuffer> phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
while (phantomRef != null)
{
// destroy the buffer if it hasn't been cleared yet
- if (PHANTOM_TO_BUFFER_ID.containsKey(phantomRef))
+ Integer idRef = PHANTOM_TO_BUFFER_ID.remove((PhantomReference extends GLBuffer>)phantomRef); // cast to make IntelliJ happy
+ if (idRef != null)
{
- int id = PHANTOM_TO_BUFFER_ID.get(phantomRef);
- RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer phantom destroy", () -> { destroyBufferIdNow(id); });
- //LOGGER.warn("Buffer Phantom collected, ID: ["+id+"]");
+ BUFFER_ID_TO_PHANTOM.remove(idRef);
+ final int id = idRef;
+ RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer phantom destroy", () -> { destroyBufferIdNow(id, "runPhantomReferenceCleanupLoop"); });
+ //LOGGER.info("Buffer Phantom collected, ID: ["+id+"]");
+
+ if (LOG_PHANTOM_ALLOCATION_STACKS) // stack trace shouldn't be null, but just in case
+ {
+ String stack = BUFFER_ID_TO_ALLOCATION_STRING.get(idRef);
+ PhantomLoggingHelper.putAndIncrementTrackingString(stack, allocationStackTraceCountPairList);
+ }
+ }
+ else
+ {
+ LOGGER.warn("Failed to find Buffer ID for phantom reference: ["+phantomRef+"]");
}
+
+ collectedCount++;
phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
}
+
+
+
+ if (LOG_PHANTOM_RECOVERY)
+ {
+ // we only want to log when something has been returned
+ if (collectedCount != 0)
+ {
+ LOGGER.warn("GLBuffer phantom recovered: ["+ F3Screen.NUMBER_FORMAT.format(collectedCount)+"].");
+
+ // log stack traces if present
+ if (LOG_PHANTOM_ALLOCATION_STACKS)
+ {
+ PhantomLoggingHelper.LogAllocationStackTracePairCounts(LOGGER, allocationStackTraceCountPairList);
+ }
+ }
+ }
+
}
catch (Exception e)
{
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/buffer/GLIndexBuffer.java b/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/buffer/GLIndexBuffer.java
index 56793aabb..0a8db0883 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/buffer/GLIndexBuffer.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/render/openGl/glObject/buffer/GLIndexBuffer.java
@@ -37,10 +37,11 @@ public class GLIndexBuffer extends GLBuffer
protected int glType = GL32.GL_UNSIGNED_INT;
public int getGlType() { return this.glType; }
- public GLIndexBuffer(boolean isBufferStorage)
- {
- super(isBufferStorage);
- }
+
+
+ public GLIndexBuffer(boolean isBufferStorage) { super(isBufferStorage); }
+
+
@Override
public void destroyAsync()
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/util/ProxyUtil.java b/common/src/main/java/com/seibel/distanthorizons/common/util/ProxyUtil.java
index b603288b3..5af15153f 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/util/ProxyUtil.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/util/ProxyUtil.java
@@ -22,23 +22,34 @@ package com.seibel.distanthorizons.common.util;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.client.multiplayer.WorldClient;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldServer;
+#else
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.LevelAccessor;
-
+#endif
public class ProxyUtil
{
- public static ILevelWrapper getLevelWrapper(LevelAccessor level)
+ public static ILevelWrapper getLevelWrapper(
+ #if MC_VER <= MC_1_12_2 World #else LevelAccessor #endif level
+ )
{
ILevelWrapper levelWrapper;
- if (level instanceof ServerLevel)
+ if (level instanceof #if MC_VER <= MC_1_12_2 WorldServer #else ServerLevel #endif)
{
- levelWrapper = ServerLevelWrapper.getWrapper((ServerLevel) level);
+ levelWrapper = ServerLevelWrapper.getWrapper(
+ #if MC_VER <= MC_1_12_2 (WorldServer) #else (ServerLevel) #endif level
+ );
}
else
{
- levelWrapper = ClientLevelWrapper.getWrapper((ClientLevel) level);
+ levelWrapper = ClientLevelWrapper.getWrapper(
+ #if MC_VER <= MC_1_12_2 (WorldClient) #else (ClientLevel) #endif level
+ );
}
return levelWrapper;
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/McObjectConverter.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/McObjectConverter.java
index cff8c85e7..aa08f77db 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/McObjectConverter.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/McObjectConverter.java
@@ -26,9 +26,15 @@ import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.util.math.Mat4f;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.ChunkPos;
+#else
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.ChunkPos;
+#endif
/**
* This class converts to and from Minecraft objects (Ex: Matrix4f)
@@ -47,7 +53,8 @@ public class McObjectConverter
/** 4x4 float matrix converter */
public static Mat4f Convert(
- #if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
+ #if MC_VER <= MC_1_12_2 org.joml.Matrix4f
+ #elif MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
#elif MC_VER < MC_1_21_6 org.joml.Matrix4f
#else org.joml.Matrix4fc
#endif
@@ -56,21 +63,24 @@ public class McObjectConverter
FloatBuffer buffer = FloatBuffer.allocate(16);
storeMatrix(mcMatrix, buffer);
Mat4f matrix = new Mat4f(buffer);
- #if MC_VER < MC_1_19_4
+ #if MC_VER > MC_1_12_2 && MC_VER < MC_1_19_4
matrix.transpose(); // In 1.19.3 and later, we no longer need to transpose it
#endif
return matrix;
}
/** Taken from Minecraft's com.mojang.math.Matrix4f class from 1.18.2 */
private static void storeMatrix(
- #if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
+ #if MC_VER <= MC_1_12_2 org.joml.Matrix4f
+ #elif MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
#elif MC_VER < MC_1_21_6 org.joml.Matrix4f
#else org.joml.Matrix4fc
#endif
matrix,
FloatBuffer buffer)
{
- #if MC_VER < MC_1_19_4
+ #if MC_VER <= MC_1_12_2
+ matrix.get(buffer);
+ #elif MC_VER < MC_1_19_4
matrix.store(buffer);
#else
// Mojang starts to use joml's Matrix4f libary in 1.19.3 so we copy their store method and use it here if its newer than 1.19.3
@@ -94,35 +104,37 @@ public class McObjectConverter
}
- static final Direction[] directions;
+ static final #if MC_VER <= MC_1_12_2 EnumFacing[] #else Direction[] #endif directions;
static final EDhDirection[] lodDirections;
static
{
EDhDirection[] lodDirs = EDhDirection.values();
- directions = new Direction[lodDirs.length];
+
+ directions = new #if MC_VER <= MC_1_12_2 EnumFacing #else Direction #endif[lodDirs.length];
+
lodDirections = new EDhDirection[lodDirs.length];
for (EDhDirection lodDir : lodDirs)
{
- Direction dir;
+ #if MC_VER <= MC_1_12_2 EnumFacing #else Direction #endif dir;
switch (lodDir.name().toUpperCase())
{
case "DOWN":
- dir = Direction.DOWN;
+ dir = #if MC_VER <= MC_1_12_2 EnumFacing #else Direction #endif.DOWN;
break;
case "UP":
- dir = Direction.UP;
+ dir = #if MC_VER <= MC_1_12_2 EnumFacing #else Direction #endif.UP;
break;
case "NORTH":
- dir = Direction.NORTH;
+ dir = #if MC_VER <= MC_1_12_2 EnumFacing #else Direction #endif.NORTH;
break;
case "SOUTH":
- dir = Direction.SOUTH;
+ dir = #if MC_VER <= MC_1_12_2 EnumFacing #else Direction #endif.SOUTH;
break;
case "WEST":
- dir = Direction.WEST;
+ dir = #if MC_VER <= MC_1_12_2 EnumFacing #else Direction #endif.WEST;
break;
case "EAST":
- dir = Direction.EAST;
+ dir = #if MC_VER <= MC_1_12_2 EnumFacing #else Direction #endif.EAST;
break;
default:
dir = null;
@@ -150,7 +162,7 @@ public class McObjectConverter
#endif
}
- public static Direction Convert(EDhDirection lodDirection) { return directions[lodDirection.ordinal()]; }
- public static EDhDirection Convert(Direction direction) { return lodDirections[direction.ordinal()]; }
+ public static #if MC_VER <= MC_1_12_2 EnumFacing #else Direction #endif Convert(EDhDirection lodDirection) { return directions[lodDirection.ordinal()]; }
+ public static EDhDirection Convert(#if MC_VER <= MC_1_12_2 EnumFacing #else Direction #endif direction) { return lodDirections[direction.ordinal()]; }
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/VersionConstants.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/VersionConstants.java
index f18c8db09..efd96f845 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/VersionConstants.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/VersionConstants.java
@@ -51,7 +51,10 @@ public class VersionConstants implements IVersionConstants
// it can't load client classes when running as a dedicated server,
// which was how we were dynamically accessing the MC version string
- #if MC_VER == MC_1_16_5
+ #if MC_VER == MC_1_12_2
+ return "1.12.2";
+
+ #elif MC_VER == MC_1_16_5
return "1.16.5";
#elif MC_VER == MC_1_17_1
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java
index 2dca01e27..8af7cb4fd 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java
@@ -46,17 +46,30 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
-import net.minecraft.client.multiplayer.ClientLevel;
+
#if MC_VER > MC_1_17_1
import net.minecraft.core.Holder;
#endif
+
+#if MC_VER <= MC_1_12_2
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.client.multiplayer.WorldClient;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldServer;
+import net.minecraft.world.biome.Biome;
+import net.minecraft.world.chunk.Chunk;
+#else
+import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
+import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
+#endif
import java.io.IOException;
+import java.util.HashSet;
/**
* This handles creating abstract wrapper objects.
@@ -84,7 +97,6 @@ public class WrapperFactory implements IWrapperFactory
this.renderDefinition = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
return this.renderDefinition;
}
-
//endregion
@@ -115,7 +127,7 @@ public class WrapperFactory implements IWrapperFactory
throw new ClassCastException("levelWrapper must be returned by DH and of type ["+ILevelWrapper.class.getName()+"].");
}
- return BiomeWrapper.deserialize(resourceLocationString, (ILevelWrapper)levelWrapper);
+ return BiomeWrapper.deserialize(resourceLocationString, (ILevelWrapper)levelWrapper);
}
@Override
public IDhApiBlockStateWrapper getDefaultBlockStateWrapper(String resourceLocationString, IDhApiLevelWrapper levelWrapper) throws IOException, ClassCastException
@@ -125,19 +137,19 @@ public class WrapperFactory implements IWrapperFactory
throw new ClassCastException("Invalid ["+IDhApiLevelWrapper.class.getSimpleName()+"] value given. Level wrapper object must be one given by the DH API (it can't be a custom implementation), specifically of type ["+ILevelWrapper.class.getName()+"].");
}
- return BlockStateWrapper.deserialize(resourceLocationString, (ILevelWrapper)levelWrapper);
+ return BlockStateWrapper.deserialize(resourceLocationString, (ILevelWrapper)levelWrapper);
}
@Override
public IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BiomeWrapper.deserialize(str, levelWrapper); }
- @Override
+ @Override
public IBiomeWrapper getPlainsBiomeWrapper(ILevelWrapper levelWrapper)
{
try
{
return BiomeWrapper.deserialize(BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING, levelWrapper);
}
- catch (IOException e)
+ catch (IOException e)
{
throw new LodUtil.AssertFailureException("Unable to parse plains resource string ["+BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING+"], error:\n " + e.getMessage());
}
@@ -192,25 +204,25 @@ public class WrapperFactory implements IWrapperFactory
// correct number of parameters from the API
// chunk
- if (!(objectArray[0] instanceof ChunkAccess))
+ if (!(objectArray[0] instanceof #if MC_VER <= MC_1_12_2 Chunk #else ChunkAccess #endif))
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
- ChunkAccess chunk = (ChunkAccess) objectArray[0];
+ #if MC_VER <= MC_1_12_2 Chunk #else ChunkAccess #endif chunk = (#if MC_VER <= MC_1_12_2 Chunk #else ChunkAccess #endif) objectArray[0];
// level / light source
- if (!(objectArray[1] instanceof Level))
+ if (!(objectArray[1] instanceof #if MC_VER <= MC_1_12_2 World #else Level #endif))
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
// the level is needed for the DH level wrapper...
- Level level = (Level) objectArray[1];
+ #if MC_VER <= MC_1_12_2 World #else Level #endif level = (#if MC_VER <= MC_1_12_2 World #else Level #endif) objectArray[1];
// level wrapper
- ILevelWrapper levelWrapper = level.isClientSide()
- ? ClientLevelWrapper.getWrapper((ClientLevel)level)
- : ServerLevelWrapper.getWrapper((ServerLevel)level);
+ ILevelWrapper levelWrapper = #if MC_VER <= MC_1_12_2 !level.isRemote #else level.isClientSide() #endif
+ ? ClientLevelWrapper.getWrapper((#if MC_VER <= MC_1_12_2 WorldClient #else ClientLevel #endif)level)
+ : ServerLevelWrapper.getWrapper((#if MC_VER <= MC_1_12_2 WorldServer #else ServerLevel #endif)level);
return new ChunkWrapper(chunk, levelWrapper);
@@ -231,11 +243,11 @@ public class WrapperFactory implements IWrapperFactory
String[] expectedClassNames;
//#if MC_VER <= MC_1_XX_X
- expectedClassNames = new String[]
- {
- ChunkAccess.class.getName(),
- "[ServerLevel] or [ClientLevel]" // Classes are not referenced by names to avoid exception when one of them is missing
- };
+ expectedClassNames = new String[]
+ {
+ #if MC_VER <= MC_1_12_2 Chunk #else ChunkAccess #endif.class.getName(),
+ "[ServerLevel] or [ClientLevel]" // Classes are not referenced by names to avoid exception when one of them is missing
+ };
//#endif
return createWrapperErrorMessage("Chunk wrapper", expectedClassNames, objectArray);
@@ -258,7 +270,7 @@ public class WrapperFactory implements IWrapperFactory
// documentation should be in the API interface
- public IDhApiBiomeWrapper getBiomeWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper)
+ public IDhApiBiomeWrapper getBiomeWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper)
{
// confirm the API level wrapper is also a Core wrapper
if (!(levelWrapper instanceof ILevelWrapper))
@@ -327,12 +339,12 @@ public class WrapperFactory implements IWrapperFactory
{
throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray));
}
- if (!(objectArray[0] instanceof BlockState))
+ if (!(objectArray[0] instanceof #if MC_VER <= MC_1_12_2 IBlockState #else BlockState #endif))
{
throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray));
}
- BlockState blockState = (BlockState) objectArray[0];
+ #if MC_VER <= MC_1_12_2 IBlockState #else BlockState #endif blockState = (#if MC_VER <= MC_1_12_2 IBlockState #else BlockState #endif) objectArray[0];
return BlockStateWrapper.fromBlockState(blockState, coreLevelWrapper);
//#endif
}
@@ -344,7 +356,7 @@ public class WrapperFactory implements IWrapperFactory
{
String[] expectedClassNames;
- #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
+ #if MC_VER <= MC_1_17_1
expectedClassNames = new String[] { Biome.class.getName() };
#else
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
@@ -367,8 +379,8 @@ public class WrapperFactory implements IWrapperFactory
{
// error header
StringBuilder message = new StringBuilder(
- wrapperName + " creation failed. \n" +
- "Expected object array parameters: \n");
+ wrapperName + " creation failed. \n" +
+ "Expected object array parameters: \n");
// expected parameters
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/AbstractDhTintGetter.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/AbstractDhTintGetter.java
index cbf9c6529..e6361fb32 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/AbstractDhTintGetter.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/AbstractDhTintGetter.java
@@ -1,5 +1,5 @@
package com.seibel.distanthorizons.common.wrappers.block;
-
+#if MC_VER > MC_1_12_2
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.BlockBiomeWrapperPair;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
@@ -11,10 +11,14 @@ import com.seibel.distanthorizons.core.util.FullDataPointUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.Minecraft;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.world.biome.Biome;
+#else
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.biome.Biome;
+#endif
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
@@ -45,8 +49,6 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
#endif
private static final ConcurrentHashMap COLOR_BY_BLOCK_BIOME_PAIR = new ConcurrentHashMap<>();
- /** returned if the color cache is incomplete */
- public static final int INVALID_COLOR = -1;
protected BiomeWrapper biomeWrapper;
@@ -98,7 +100,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
* Can be called by DH directly, skipping some of MC's logic
* to speed up tint getting slightly.
*
- * @return {@link AbstractDhTintGetter#INVALID_COLOR} if any of the biomes needed for this position
+ * @return {@link ClientBlockStateColorCache#INVALID_COLOR} if any of the biomes needed for this position
* were not cached. In that case calling {@link AbstractDhTintGetter#getBlockTint(BlockPos, ColorResolver)}
* will need to be called by MC's ColorResolver so we can
* populate the color cache.
@@ -159,9 +161,9 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
int id = FullDataPointUtil.getId(dataPoint);
BiomeWrapper biomeWrapper = (BiomeWrapper) this.fullDataSource.mapping.getBiomeWrapper(id);
int color = this.tryGetClientBiomeColor(colorResolver, biomeWrapper);
- if (color == INVALID_COLOR)
+ if (color == ClientBlockStateColorCache.INVALID_COLOR)
{
- return INVALID_COLOR;
+ return ClientBlockStateColorCache.INVALID_COLOR;
}
@@ -210,7 +212,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
// no color resolver is present,
// the cache needs to be populated before
// we can use the fast path
- return INVALID_COLOR;
+ return ClientBlockStateColorCache.INVALID_COLOR;
}
@@ -363,3 +365,4 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
}
+#endif
\ No newline at end of file
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BiomeWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BiomeWrapper.java
index 0d557f2df..68b06278d 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BiomeWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BiomeWrapper.java
@@ -28,12 +28,15 @@ import java.util.concurrent.ConcurrentMap;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
-import net.minecraft.world.level.Level;
import com.seibel.distanthorizons.core.logging.DhLogger;
-
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
-#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
+#if MC_VER > MC_1_12_2
+import net.minecraft.world.level.Level;
+#endif
+
+#if MC_VER <= MC_1_12_2
+#elif MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
import net.minecraft.core.Registry;
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
import net.minecraft.core.Holder;
@@ -45,14 +48,21 @@ import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
#endif
-#if MC_VER <= MC_1_21_10
+#if MC_VER <= MC_1_12_2
+import net.minecraft.util.ResourceLocation;
+#elif MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
import net.minecraft.core.component.DataComponentMap;
#endif
+#if MC_VER <= MC_1_12_2
+import net.minecraft.world.biome.Biome;
+#else
import net.minecraft.world.level.biome.Biome;
+#endif
+
#if MC_VER >= MC_1_18_2
import net.minecraft.world.level.biome.Biomes;
@@ -108,8 +118,13 @@ public class BiomeWrapper implements IBiomeWrapper
//==============//
// constructors //
//==============//
+ //region
- public static BiomeWrapper getBiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder #endif biome, ILevelWrapper levelWrapper)
+ #if MC_VER < MC_1_18_2
+ public static BiomeWrapper getBiomeWrapper(Biome biome, ILevelWrapper levelWrapper)
+ #else
+ public static BiomeWrapper getBiomeWrapper(Holder biome, ILevelWrapper levelWrapper)
+ #endif
{
if (biome == null)
{
@@ -129,7 +144,12 @@ public class BiomeWrapper implements IBiomeWrapper
return newWrapper;
}
}
- private BiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder #endif biome, ILevelWrapper levelWrapper)
+
+ #if MC_VER < MC_1_18_2
+ private BiomeWrapper(Biome biome, ILevelWrapper levelWrapper)
+ #else
+ private BiomeWrapper(Holder biome, ILevelWrapper levelWrapper)
+ #endif
{
this.biome = biome;
this.serialString = this.serialize(levelWrapper);
@@ -138,11 +158,14 @@ public class BiomeWrapper implements IBiomeWrapper
//LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]");
}
+ //endregion
+
//=========//
// methods //
//=========//
+ //region
@Override
public String getName()
@@ -188,11 +211,14 @@ public class BiomeWrapper implements IBiomeWrapper
@Override
public String toString() { return this.getSerialString(); }
+ //endregion
+
//=======================//
// serialization methods //
//=======================//
+ //region
public String serialize(ILevelWrapper levelWrapper)
{
@@ -219,8 +245,10 @@ public class BiomeWrapper implements IBiomeWrapper
// generate the serial string //
+ #if MC_VER > MC_1_12_2
Level level = (Level)levelWrapper.getWrappedMcObject();
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
+ #endif
#if MC_VER <= MC_1_21_10
ResourceLocation resourceLocation;
@@ -228,7 +256,9 @@ public class BiomeWrapper implements IBiomeWrapper
Identifier resourceLocation;
#endif
- #if MC_VER <= MC_1_17_1
+ #if MC_VER <= MC_1_12_2
+ resourceLocation = biome.getRegistryName();
+ #elif MC_VER <= MC_1_17_1
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome);
#elif MC_VER <= MC_1_19_2
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value());
@@ -293,11 +323,16 @@ public class BiomeWrapper implements IBiomeWrapper
{
try
{
+ #if MC_VER > MC_1_12_2
Level level = (Level) levelWrapper.getWrappedMcObject();
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
-
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ BiomeDeserializeResult deserializeResult = deserializeBiome(resourceLocationString);
+ #else
BiomeDeserializeResult deserializeResult = deserializeBiome(resourceLocationString, registryAccess);
-
+ #endif
if (!deserializeResult.success)
@@ -325,7 +360,11 @@ public class BiomeWrapper implements IBiomeWrapper
}
}
+ #if MC_VER <= MC_1_12_2
+ public static BiomeDeserializeResult deserializeBiome(String resourceLocationString) throws IOException
+ #else
public static BiomeDeserializeResult deserializeBiome(String resourceLocationString, net.minecraft.core.RegistryAccess registryAccess) throws IOException
+ #endif
{
// parse the resource location
int separatorIndex = resourceLocationString.indexOf(":");
@@ -356,7 +395,10 @@ public class BiomeWrapper implements IBiomeWrapper
boolean success;
- #if MC_VER <= MC_1_17_1
+ #if MC_VER <= MC_1_12_2
+ Biome biome = Biome.REGISTRY.getObject(resourceLocation);
+ success = (biome != null);
+ #elif MC_VER <= MC_1_17_1
Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
success = (biome != null);
#elif MC_VER <= MC_1_19_2
@@ -400,10 +442,14 @@ public class BiomeWrapper implements IBiomeWrapper
return new BiomeDeserializeResult(success, biome);
}
+ //endregion
+
+
//================//
// helper classes //
//================//
+ //region
public static class BiomeDeserializeResult
{
@@ -413,14 +459,21 @@ public class BiomeWrapper implements IBiomeWrapper
public final Biome biome;
#else
public final Holder biome;
- #endif
+ #endif
- public BiomeDeserializeResult(boolean success, #if MC_VER < MC_1_18_2 Biome #else Holder #endif biome)
+ #if MC_VER < MC_1_18_2
+ public BiomeDeserializeResult(boolean success, Biome biome)
+ #else
+ public BiomeDeserializeResult(boolean success, Holder biome)
+ #endif
{
this.success = success;
this.biome = biome;
}
}
+ //endregion
+
+
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java
index f20398970..bcd895020 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java
@@ -32,12 +32,20 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrappe
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.block.*;
+import net.minecraft.init.Blocks;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.block.properties.IProperty;
+import net.minecraftforge.fluids.IFluidBlock;
+#else
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.BeaconBeamBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.state.BlockState;
+#endif
import com.seibel.distanthorizons.core.logging.DhLogger;
import java.awt.*;
@@ -61,7 +69,7 @@ import net.minecraft.world.level.Level;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.world.level.EmptyBlockGetter;
-#else
+#elif MC_VER > MC_1_12_2
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.Level;
import net.minecraft.core.BlockPos;
@@ -70,12 +78,15 @@ import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.core.Holder;
#endif
-#if MC_VER <= MC_1_21_10
+#if MC_VER <= MC_1_12_2
+import net.minecraft.util.ResourceLocation;
+#elif MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
#endif
+
public class BlockStateWrapper implements IBlockStateWrapper
{
/** example "minecraft:water" */
@@ -87,7 +98,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
// must be defined before AIR, otherwise a null pointer will be thrown
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
+ #if MC_VER <= MC_1_12_2
+ public static final ConcurrentHashMap WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>();
+ #else
public static final ConcurrentHashMap WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>();
+ #endif
public static final ConcurrentHashMap WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>();
public static final String AIR_STRING = "AIR";
@@ -114,7 +129,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
// properties //
@Nullable
+ #if MC_VER <= MC_1_12_2
+ public final IBlockState blockState;
+ #else
public final BlockState blockState;
+ #endif
/** technically final, but since it requires a method call to generate it can't be marked as such */
private String serialString;
private final int hashCode;
@@ -139,27 +158,71 @@ public class BlockStateWrapper implements IBlockStateWrapper
// constructors //
//==============//
//region
-
/**
- * Can be faster than {@link BlockStateWrapper#fromBlockState(BlockState, ILevelWrapper)}
+ * Can be faster than BlockStateWrapper#fromBlockState(BlockState, ILevelWrapper)
* in cases where the same block state is expected to be referenced multiple times.
*/
+ #if MC_VER <= MC_1_12_2
+ public static BlockStateWrapper fromBlockState(IBlockState blockState, ILevelWrapper levelWrapper, IBlockStateWrapper guess)
+ #else
public static BlockStateWrapper fromBlockState(BlockState blockState, ILevelWrapper levelWrapper, IBlockStateWrapper guess)
+ #endif
{
- BlockState guessBlockState = (guess == null || guess.isAir()) ? null : (BlockState) guess.getWrappedMcObject();
- BlockState inputBlockState = (blockState == null || blockState.isAir()) ? null : blockState;
-
- if (guess instanceof BlockStateWrapper
- && guessBlockState == inputBlockState)
- {
- return (BlockStateWrapper) guess;
- }
- else
+ if (guess == null)
{
return fromBlockState(blockState, levelWrapper);
}
+
+
+ // guess block state
+ BlockStateWrapper wrapperGuess = (BlockStateWrapper) guess;
+ #if MC_VER <= MC_1_12_2
+ IBlockState guessBlockState;
+ #else
+ BlockState guessBlockState;
+ #endif
+ if(isAir(wrapperGuess.blockState))
+ {
+ guessBlockState = null;
+ }
+ else
+ {
+ #if MC_VER <= MC_1_12_2
+ guessBlockState = (IBlockState) guess.getWrappedMcObject();
+ #else
+ guessBlockState = (BlockState) guess.getWrappedMcObject();
+ #endif
+ }
+
+ // input block state
+ #if MC_VER <= MC_1_12_2
+ IBlockState inputBlockState;
+ #else
+ BlockState inputBlockState;
+ #endif
+ if (isAir(blockState))
+ {
+ inputBlockState = null;
+ }
+ else
+ {
+ inputBlockState = blockState;
+ }
+
+
+ if (guessBlockState == inputBlockState)
+ {
+ return (BlockStateWrapper) guess;
+ }
+
+ return fromBlockState(blockState, levelWrapper);
}
+
+ #if MC_VER <= MC_1_12_2
+ public static BlockStateWrapper fromBlockState(@Nullable IBlockState blockState, ILevelWrapper levelWrapper)
+ #else
public static BlockStateWrapper fromBlockState(@Nullable BlockState blockState, ILevelWrapper levelWrapper)
+ #endif
{
// air is a special case
if (isAir(blockState))
@@ -208,9 +271,12 @@ public class BlockStateWrapper implements IBlockStateWrapper
}
}
}
- private BlockStateWrapper(
- @Nullable BlockState blockState, ILevelWrapper levelWrapper,
- @Nullable DhApiBlockStateWrapperCreatedEvent.EventParam overrideEventParam)
+
+ #if MC_VER <= MC_1_12_2
+ private BlockStateWrapper(@Nullable IBlockState blockState, ILevelWrapper levelWrapper, @Nullable DhApiBlockStateWrapperCreatedEvent.EventParam overrideEventParam)
+ #else
+ private BlockStateWrapper(@Nullable BlockState blockState, ILevelWrapper levelWrapper, @Nullable DhApiBlockStateWrapperCreatedEvent.EventParam overrideEventParam)
+ #endif
{
this.blockState = blockState;
this.serialString = serialize(blockState, levelWrapper);
@@ -228,11 +294,13 @@ public class BlockStateWrapper implements IBlockStateWrapper
}
else
{
- #if MC_VER < MC_1_20_1
- this.isLiquid = this.blockState.getMaterial().isLiquid() || !this.blockState.getFluidState().isEmpty();
- #else
+ #if MC_VER <= MC_1_12_2
+ this.isLiquid = this.blockState.getMaterial().isLiquid() || this.blockState.getBlock() instanceof IFluidBlock;
+ #elif MC_VER < MC_1_20_1
+ this.isLiquid = this.blockState.getMaterial().isLiquid() || !this.blockState.getFluidState().isEmpty();
+ #else
this.isLiquid = !this.blockState.getFluidState().isEmpty();
- #endif
+ #endif
}
}
@@ -332,9 +400,21 @@ public class BlockStateWrapper implements IBlockStateWrapper
&& !this.isBeaconBlock)
{
Block block = this.blockState.getBlock();
+ int colorInt;
+ #if MC_VER <= MC_1_12_2
+ if (block instanceof BlockStainedGlass)
+ {
+ colorInt = blockState.getValue(BlockStainedGlass.COLOR).getColorValue();
+ beaconTintColor = ColorUtil.toColorObjRGB(colorInt);
+ }
+ else if (block instanceof BlockStainedGlassPane)
+ {
+ colorInt = blockState.getValue(BlockStainedGlassPane.COLOR).getColorValue();
+ beaconTintColor = ColorUtil.toColorObjRGB(colorInt);
+ }
+ #else
if (block instanceof BeaconBeamBlock)
{
- int colorInt;
#if MC_VER <= MC_1_19_4
colorInt = ((BeaconBeamBlock) block).getColor().getMaterialColor().col;
#else
@@ -343,6 +423,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
beaconTintColor = ColorUtil.toColorObjRGB(colorInt);
}
+ #endif
}
this.beaconTintColor = beaconTintColor;
@@ -392,8 +473,10 @@ public class BlockStateWrapper implements IBlockStateWrapper
if (this.blockState != null)
{
int mcColor = 0;
-
- #if MC_VER < MC_1_20_1
+
+ #if MC_VER <= MC_1_12_2
+ mcColor = this.blockState.getMaterial().getMaterialMapColor().colorValue;
+ #elif MC_VER < MC_1_20_1
mcColor = this.blockState.getMaterial().getColor().col;
#else
mcColor = this.blockState.getMapColor(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).col;
@@ -420,7 +503,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
#if MC_VER < MC_1_20_1
this.isSolid = this.blockState.getMaterial().isSolid();
#else
- this.isSolid = !this.blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty();
+ this.isSolid = !this.blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty();
#endif
}
}
@@ -431,76 +514,193 @@ public class BlockStateWrapper implements IBlockStateWrapper
// static constructor helpers //
//region
- private static EDhApiBlockMaterial calculateEDhApiBlockMaterialId(
- @Nullable BlockState blockState,
- String lowercaseSerialString,
- boolean isLiquid
- )
+ #if MC_VER <= MC_1_12_2
+ private static EDhApiBlockMaterial calculateEDhApiBlockMaterialId(@Nullable IBlockState blockState, String lowercaseSerialString, boolean isLiquid)
+ #else
+ private static EDhApiBlockMaterial calculateEDhApiBlockMaterialId(@Nullable BlockState blockState, String lowercaseSerialString, boolean isLiquid)
+ #endif
{
- if (blockState == null)
+ if (isAir(blockState))
{
return EDhApiBlockMaterial.AIR;
}
- if (blockState.is(BlockTags.LEAVES)
+
+ //========//
+ // leaves //
+ //========//
+ //region
+
+ boolean isLeafBlock;
+ #if MC_VER <= MC_1_12_2
+ isLeafBlock = blockState.getBlock() instanceof BlockLeaves;
+ #else
+ isLeafBlock = blockState.is(BlockTags.LEAVES);
+ #endif
+ if (isLeafBlock
|| lowercaseSerialString.contains("bamboo")
|| lowercaseSerialString.contains("cactus")
|| lowercaseSerialString.contains("chorus_flower")
|| lowercaseSerialString.contains("mushroom")
- )
+ )
{
return EDhApiBlockMaterial.LEAVES;
}
- else if (blockState.is(Blocks.LAVA))
+
+ //endregion
+
+
+
+ //======//
+ // lava //
+ //======//
+ //region
+
+ boolean isLavaBlock;
+ #if MC_VER <= MC_1_12_2
+ isLavaBlock = blockState.getBlock() == Blocks.LAVA || blockState.getBlock() == Blocks.FLOWING_LAVA;
+ #else
+ isLavaBlock = blockState.is(Blocks.LAVA);
+ #endif
+ if (isLavaBlock)
{
return EDhApiBlockMaterial.LAVA;
}
- else if (isLiquid
- || blockState.is(Blocks.WATER))
+
+ //endregion
+
+
+
+ //=======//
+ // water //
+ //=======//
+ //region
+
+ boolean isWaterBlock;
+ #if MC_VER <= MC_1_12_2
+ isWaterBlock = blockState.getBlock() == Blocks.WATER || blockState.getBlock() == Blocks.FLOWING_WATER;
+ #else
+ isWaterBlock = blockState.is(Blocks.WATER);
+ #endif
+ if (isLiquid
+ || isWaterBlock)
{
return EDhApiBlockMaterial.WATER;
}
- else if (blockState.getSoundType() == SoundType.WOOD
+
+ //endregion
+
+
+
+ //======//
+ // wood //
+ //======//
+ //region
+
+ boolean isWoodSoundingBlock;
+ #if MC_VER <= MC_1_12_2
+ isWoodSoundingBlock = blockState.getBlock().getSoundType() == SoundType.WOOD;
+ #else
+ isWoodSoundingBlock = blockState.getSoundType() == SoundType.WOOD;
+ #endif
+
+ boolean isCherryWood;
+ #if MC_VER <= MC_1_19_2
+ isCherryWood = false;
+ #else
+ isCherryWood = blockState.getSoundType() == SoundType.CHERRY_WOOD;
+ #endif
+
+ if (isWoodSoundingBlock
|| lowercaseSerialString.contains("root")
- #if MC_VER >= MC_1_19_4
- || blockState.getSoundType() == SoundType.CHERRY_WOOD
- #endif
- )
+ || isCherryWood
+ )
{
return EDhApiBlockMaterial.WOOD;
}
- else if (blockState.getSoundType() == SoundType.METAL
- #if MC_VER >= MC_1_19_2
- || blockState.getSoundType() == SoundType.COPPER
- #endif
- #if MC_VER >= MC_1_20_4
- || blockState.getSoundType() == SoundType.COPPER_BULB
- || blockState.getSoundType() == SoundType.COPPER_GRATE
- #endif
- )
+
+ //endregion
+
+
+
+ //=======//
+ // metal //
+ //=======//
+ //region
+
+ boolean isMetalSoundingBlock;
+ #if MC_VER <= MC_1_12_2
+ isMetalSoundingBlock = blockState.getBlock().getSoundType() == SoundType.METAL;
+ #else
+ isMetalSoundingBlock = blockState.getSoundType() == SoundType.METAL;
+ #endif
+
+ boolean isCopperSounding;
+ #if MC_VER <= MC_1_18_2
+ isCopperSounding = false;
+ #elif MC_VER <= MC_1_20_2
+ isCopperSounding = blockState.getSoundType() == SoundType.COPPER;
+ #else
+ isCopperSounding
+ = blockState.getSoundType() == SoundType.COPPER
+ || blockState.getSoundType() == SoundType.COPPER_BULB
+ || blockState.getSoundType() == SoundType.COPPER_GRATE;
+ #endif
+
+ if (isMetalSoundingBlock
+ || isCopperSounding)
{
return EDhApiBlockMaterial.METAL;
}
- else if (
- lowercaseSerialString.contains("grass_block")
- || lowercaseSerialString.contains("grass_slab")
- )
+
+ //endregion
+
+
+
+ //=======//
+ // grass //
+ //=======//
+ //region
+
+ if (lowercaseSerialString.contains("grass_block")
+ || lowercaseSerialString.contains("grass_slab")
+ )
{
return EDhApiBlockMaterial.GRASS;
}
- else if (
+
+ //endregion
+
+
+
+ //======//
+ // dirt //
+ //======//
+ //region
+
+ if (
lowercaseSerialString.contains("dirt")
- || lowercaseSerialString.contains("gravel")
- || lowercaseSerialString.contains("mud")
- || lowercaseSerialString.contains("podzol")
- || lowercaseSerialString.contains("mycelium")
- )
+ || lowercaseSerialString.contains("gravel")
+ || lowercaseSerialString.contains("mud")
+ || lowercaseSerialString.contains("podzol")
+ || lowercaseSerialString.contains("mycelium")
+ )
{
return EDhApiBlockMaterial.DIRT;
}
+
+ //endregion
+
+
+
+ //===========//
+ // deepslate //
+ //===========//
+ //region
+
#if MC_VER >= MC_1_17_1
- else if (blockState.getSoundType() == SoundType.DEEPSLATE
+ if (blockState.getSoundType() == SoundType.DEEPSLATE
|| blockState.getSoundType() == SoundType.DEEPSLATE_BRICKS
|| blockState.getSoundType() == SoundType.DEEPSLATE_TILES
|| blockState.getSoundType() == SoundType.POLISHED_DEEPSLATE
@@ -509,41 +709,75 @@ public class BlockStateWrapper implements IBlockStateWrapper
return EDhApiBlockMaterial.DEEPSLATE;
}
#endif
- else if (lowercaseSerialString.contains("snow"))
- {
- return EDhApiBlockMaterial.SNOW;
- }
- else if (lowercaseSerialString.contains("sand"))
- {
- return EDhApiBlockMaterial.SAND;
- }
- else if (lowercaseSerialString.contains("terracotta"))
- {
- return EDhApiBlockMaterial.TERRACOTTA;
- }
- else if (blockState.is(BlockTags.BASE_STONE_NETHER))
+
+ //endregion
+
+
+
+ //============//
+ // netherrack //
+ //============//
+ //region
+
+ boolean isNetherRack;
+ #if MC_VER <= MC_1_12_2
+ isNetherRack = blockState.getBlock() == Blocks.NETHERRACK;
+ #else
+ isNetherRack = blockState.is(BlockTags.BASE_STONE_NETHER);
+ #endif
+
+ if (isNetherRack)
{
return EDhApiBlockMaterial.NETHER_STONE;
}
- else if (lowercaseSerialString.contains("stone")
+
+ //endregion
+
+
+
+ //=============//
+ // misc/simple //
+ //=============//
+ //region
+
+ if (lowercaseSerialString.contains("snow"))
+ {
+ return EDhApiBlockMaterial.SNOW;
+ }
+
+ if (lowercaseSerialString.contains("sand"))
+ {
+ return EDhApiBlockMaterial.SAND;
+ }
+
+ if (lowercaseSerialString.contains("terracotta"))
+ {
+ return EDhApiBlockMaterial.TERRACOTTA;
+ }
+
+ if (lowercaseSerialString.contains("stone")
|| lowercaseSerialString.contains("ore"))
{
return EDhApiBlockMaterial.STONE;
}
- else if (blockState.getLightEmission() > 0)
+
+ if (getLightEmission(blockState) > 0)
{
return EDhApiBlockMaterial.ILLUMINATED;
}
- else
- {
- return EDhApiBlockMaterial.UNKNOWN;
- }
+
+ //endregion
+
+
+
+ return EDhApiBlockMaterial.UNKNOWN;
}
- private static int calculateOpacity(
- @Nullable BlockState blockState,
- boolean isAir, boolean isLiquid
- )
+ #if MC_VER <= MC_1_12_2
+ private static int calculateOpacity(@Nullable IBlockState blockState, boolean isAir, boolean isLiquid)
+ #else
+ private static int calculateOpacity(@Nullable BlockState blockState, boolean isAir, boolean isLiquid)
+ #endif
{
// get block properties (defaults to the values used by air)
boolean canOcclude = getCanOcclude(blockState);
@@ -582,24 +816,40 @@ public class BlockStateWrapper implements IBlockStateWrapper
return opacity;
}
+
+ #if MC_VER <= MC_1_12_2
+ private static boolean getCanOcclude(@Nullable IBlockState blockState)
+ #else
private static boolean getCanOcclude(@Nullable BlockState blockState)
+ #endif
{
// defaults to the value used by air
boolean canOcclude = false;
if (blockState != null)
{
+ #if MC_VER <= MC_1_12_2
+ canOcclude = blockState.getMaterial().isSolid();
+ #else
canOcclude = blockState.canOcclude();
+ #endif
}
return canOcclude;
}
+
+ #if MC_VER <= MC_1_12_2
+ private static boolean getPropagatesSkyLightDown(@Nullable IBlockState blockState)
+ #else
private static boolean getPropagatesSkyLightDown(@Nullable BlockState blockState)
+ #endif
{
// defaults to the value used by air
boolean propagatesSkyLightDown = true;
if (blockState != null)
{
- #if MC_VER < MC_1_21_3
+ #if MC_VER <= MC_1_12_2
+ propagatesSkyLightDown = blockState.getBlock().getLightOpacity(blockState) == 0;
+ #elif MC_VER < MC_1_21_3
propagatesSkyLightDown = blockState.propagatesSkylightDown(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
#else
propagatesSkyLightDown = blockState.propagatesSkylightDown();
@@ -659,8 +909,10 @@ public class BlockStateWrapper implements IBlockStateWrapper
return waterSurfaceReplacementBlocks;
}
- ObjectOpenHashSet baseIgnoredBlock = new ObjectOpenHashSet<>();
- waterSurfaceReplacementBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.waterSurfaceBlockReplacementCsv, baseIgnoredBlock, levelWrapper);
+ ObjectOpenHashSet baseIgnoredBlockResourceSet = new ObjectOpenHashSet<>();
+ waterSurfaceReplacementBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.waterSurfaceBlockReplacementCsv, baseIgnoredBlockResourceSet, levelWrapper);
+ waterSubsurfaceReplacementBlocks.remove(AIR);
+
return waterSurfaceReplacementBlocks;
}
public static ObjectOpenHashSet getWaterSubsurfaceReplacementBlocks(ILevelWrapper levelWrapper)
@@ -671,8 +923,12 @@ public class BlockStateWrapper implements IBlockStateWrapper
return waterSubsurfaceReplacementBlocks;
}
- ObjectOpenHashSet baseIgnoredBlock = new ObjectOpenHashSet<>();
- waterSubsurfaceReplacementBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.waterSubSurfaceBlockReplacementCsv, baseIgnoredBlock, levelWrapper);
+ ObjectOpenHashSet baseIgnoredBlockResourceSet = new ObjectOpenHashSet<>();
+ waterSubsurfaceReplacementBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.waterSubSurfaceBlockReplacementCsv, baseIgnoredBlockResourceSet, levelWrapper);
+ // air will be present if any invalid resource locations are present
+ // but we don't want to replace air with water, that'll cause monoliths
+ waterSubsurfaceReplacementBlocks.remove(AIR);
+
return waterSubsurfaceReplacementBlocks;
}
public static IBlockStateWrapper getWaterBlockStateWrapper(ILevelWrapper levelWrapper)
@@ -740,8 +996,17 @@ public class BlockStateWrapper implements IBlockStateWrapper
if (defaultBlockStateToIgnore != AIR)
{
// add all possible blockstates (to account for light blocks with different light values and such)
+ #if MC_VER <= MC_1_12_2
+ List blockStatesToIgnore = defaultBlockStateToIgnore.blockState.getBlock().getBlockState().getValidStates();
+ #else
List blockStatesToIgnore = defaultBlockStateToIgnore.blockState.getBlock().getStateDefinition().getPossibleStates();
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ for (IBlockState blockState : blockStatesToIgnore)
+ #else
for (BlockState blockState : blockStatesToIgnore)
+ #endif
{
BlockStateWrapper newBlockToIgnore = fromBlockState(blockState, levelWrapper);
blockStateWrappers.add(newBlockToIgnore);
@@ -788,7 +1053,25 @@ public class BlockStateWrapper implements IBlockStateWrapper
public int getOpacity() { return this.opacity; }
@Override
- public int getLightEmission() { return (this.blockState != null) ? this.blockState.getLightEmission() : 0; }
+ public int getLightEmission() { return getLightEmission(this.blockState); }
+ #if MC_VER <= MC_1_12_2
+ public static int getLightEmission(IBlockState blockState)
+ #else
+ public static int getLightEmission(BlockState blockState)
+ #endif
+ {
+ if (blockState == null)
+ {
+ return 0;
+ }
+
+ #if MC_VER <= MC_1_12_2
+ return blockState.getLightValue();
+ #else
+ return blockState.getLightEmission();
+ #endif
+ }
+
@Override
public String getSerialString() { return this.serialString; }
@@ -798,7 +1081,23 @@ public class BlockStateWrapper implements IBlockStateWrapper
@Override
public boolean isAir() { return isAir(this.blockState); }
- public static boolean isAir(BlockState blockState) { return blockState == null || blockState.isAir(); }
+ #if MC_VER <= MC_1_12_2
+ public static boolean isAir(IBlockState blockState)
+ #else
+ public static boolean isAir(BlockState blockState)
+ #endif
+ {
+ if (blockState == null)
+ {
+ return true;
+ }
+
+ #if MC_VER <= MC_1_12_2
+ return blockState.getBlock() == Blocks.AIR;
+ #else
+ return blockState.isAir();
+ #endif
+ }
@Override
public boolean isSolid() { return this.isSolid; }
@@ -832,7 +1131,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
//=======================//
//region
+ #if MC_VER <= MC_1_12_2
+ private static String serialize(IBlockState blockState, ILevelWrapper levelWrapper)
+ #else
private static String serialize(BlockState blockState, ILevelWrapper levelWrapper)
+ #endif
{
if (blockState == null)
{
@@ -854,7 +1157,9 @@ public class BlockStateWrapper implements IBlockStateWrapper
Identifier resourceLocation;
#endif
- #if MC_VER <= MC_1_17_1
+ #if MC_VER <= MC_1_12_2
+ resourceLocation = blockState.getBlock().getRegistryName();
+ #elif MC_VER <= MC_1_17_1
resourceLocation = Registry.BLOCK.getKey(blockState.getBlock());
#elif MC_VER <= MC_1_19_2
resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(blockState.getBlock());
@@ -953,7 +1258,9 @@ public class BlockStateWrapper implements IBlockStateWrapper
#endif
Block block;
- #if MC_VER <= MC_1_17_1
+ #if MC_VER <= MC_1_12_2
+ block = Block.REGISTRY.getObject(resourceLocation);
+ #elif MC_VER <= MC_1_17_1
block = Registry.BLOCK.get(resourceLocation);
#elif MC_VER <= MC_1_19_2
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
@@ -982,11 +1289,24 @@ public class BlockStateWrapper implements IBlockStateWrapper
// attempt to find the blockstate from all possibilities
+ #if MC_VER <= MC_1_12_2
+ IBlockState foundState = null;
+ #else
BlockState foundState = null;
+ #endif
if (blockStatePropertiesString != null)
{
+ #if MC_VER <= MC_1_12_2
+ List possibleStateList = block.getBlockState().getValidStates();
+ #else
List possibleStateList = block.getStateDefinition().getPossibleStates();
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ for (IBlockState possibleState : possibleStateList)
+ #else
for (BlockState possibleState : possibleStateList)
+ #endif
{
String possibleStatePropertiesString = serializeBlockStateProperties(possibleState);
if (possibleStatePropertiesString.equals(blockStatePropertiesString))
@@ -1010,7 +1330,12 @@ public class BlockStateWrapper implements IBlockStateWrapper
}
}
- foundState = block.defaultBlockState();
+
+ #if MC_VER <= MC_1_12_2
+ foundState = block.getDefaultState();
+ #else
+ foundState = block.defaultBlockState();
+ #endif
}
foundWrapper = fromBlockState(foundState, levelWrapper);
@@ -1035,26 +1360,44 @@ public class BlockStateWrapper implements IBlockStateWrapper
}
/** used to compare and save BlockStates based on their properties */
+ #if MC_VER <= MC_1_12_2
+ private static String serializeBlockStateProperties(IBlockState blockState)
+ #else
private static String serializeBlockStateProperties(BlockState blockState)
+ #endif
{
// get the property list for this block (doesn't contain this block state's values, just the names and possible values)
- java.util.Collection> blockPropertyCollection = blockState.getProperties();
+ #if MC_VER <= MC_1_12_2
+ java.util.Collection> blockPropertyCollection = blockState.getPropertyKeys();
+ List> sortedBlockPropteryList = new ArrayList<>(blockPropertyCollection);
+ #else
+ java.util.Collection> blockPropertyCollection = blockState.getProperties();;
+ List> sortedBlockPropteryList = new ArrayList<>(blockPropertyCollection);
+ #endif
// alphabetically sort the list so they are always in the same order
- List> sortedBlockPropteryList = new ArrayList<>(blockPropertyCollection);
sortedBlockPropteryList.sort((a, b) -> a.getName().compareTo(b.getName()));
StringBuilder stringBuilder = new StringBuilder();
+ #if MC_VER <= MC_1_12_2
+ for (IProperty> property : sortedBlockPropteryList)
+ #else
for (net.minecraft.world.level.block.state.properties.Property> property : sortedBlockPropteryList)
+ #endif
{
String propertyName = property.getName();
String value = "NULL";
+
+ #if MC_VER <= MC_1_12_2
+ value = blockState.getValue(property).toString();
+ #else
if (blockState.hasProperty(property))
{
value = blockState.getValue(property).toString();
}
+ #endif
stringBuilder.append("{");
stringBuilder.append(propertyName).append(RESOURCE_LOCATION_SEPARATOR).append(value);
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java
index ee776f4b8..f83856c39 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java
@@ -32,22 +32,31 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapp
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.EnumBlockRenderType;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.block.BlockRotatedPillar;
+import net.minecraft.block.*;
+import net.minecraft.client.multiplayer.WorldClient;
+import net.minecraft.client.renderer.color.BlockColors;
+import net.minecraft.util.math.BlockPos;
+#else
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.state.BlockState;
-import com.seibel.distanthorizons.core.logging.DhLogger;
import net.minecraft.world.level.block.state.properties.SlabType;
+#endif
+import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.Nullable;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
+import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
#if MC_VER >= MC_1_19_2
import net.minecraft.util.RandomSource;
#else
-import java.util.Random;
#endif
#if MC_VER < MC_1_21_5
@@ -64,19 +73,32 @@ import net.minecraft.client.color.block.BlockTintSource;
/**
* This stores and calculates the colors
- * the given {@link BlockState} should have based
+ * the given BlockState should have based
* on the given {@link IClientLevelWrapper}.
- *
+ *
* @see ColorUtil
*/
public class ClientBlockStateColorCache
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
+ #if MC_VER <= MC_1_12_2
+ private static final Minecraft MC = Minecraft.getMinecraft();
+ #else
private static final Minecraft MC = Minecraft.getInstance();
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ #else
private static final HashSet BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>();
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ private static final HashSet BROKEN_BLOCK_STATES = new HashSet<>();
+ #else
private static final HashSet BROKEN_BLOCK_STATES = new HashSet<>();
+ #endif
/**
* Methods using MC's "RandomSource" object aren't thread safe
@@ -88,18 +110,33 @@ public class ClientBlockStateColorCache
*/
private static final ReentrantLock RESOLVE_LOCK = new ReentrantLock();
+ public static final int INVALID_COLOR = -1;
+
/** This is the order each direction on a block is processed when attempting to get the texture/color */
+ #if MC_VER <= MC_1_12_2
+ private static final @Nullable EnumFacing[] COLOR_RESOLUTION_DIRECTION_ORDER =
+ {
+ EnumFacing.UP,
+ null, // null represents "unculled" faces, IE the top of farmland
+ EnumFacing.NORTH,
+ EnumFacing.EAST,
+ EnumFacing.WEST,
+ EnumFacing.SOUTH,
+ EnumFacing.DOWN
+ };
+ #else
private static final @Nullable Direction[] COLOR_RESOLUTION_DIRECTION_ORDER =
- {
+ {
Direction.UP,
null, // null represents "unculled" faces, IE the top of farmland
- Direction.NORTH,
- Direction.EAST,
- Direction.WEST,
- Direction.SOUTH,
- Direction.DOWN
+ Direction.NORTH,
+ Direction.EAST,
+ Direction.WEST,
+ Direction.SOUTH,
+ Direction.DOWN
};
+ #endif
private static final int FLOWER_COLOR_SCALE = 5;
@@ -113,7 +150,11 @@ public class ClientBlockStateColorCache
#endif
private final IClientLevelWrapper clientLevelWrapper;
+ #if MC_VER <= MC_1_12_2
+ private final IBlockState blockState;
+ #else
private final BlockState blockState;
+ #endif
private final BlockStateWrapper blockStateWrapper;
private boolean isColorResolved = false;
@@ -191,8 +232,10 @@ public class ClientBlockStateColorCache
};
// these are threadlocals since AbstractDhTintGetter use local variables to handle color queries
+ #if MC_VER > MC_1_12_2
private static final ThreadLocal TintWithoutLevelOverrideGetter = ThreadLocal.withInitial(TintWithoutLevelOverrider::new);
private static final ThreadLocal TintOverrideGetter = ThreadLocal.withInitial(TintGetterOverride::new);
+ #endif
private static final ThreadLocal ColorOverrideEventParamGetter = ThreadLocal.withInitial(DhApiBlockColorOverrideEvent.EventParam::new);
//endregion
@@ -204,7 +247,11 @@ public class ClientBlockStateColorCache
//=============//
//region
+ #if MC_VER <= MC_1_12_2
+ public ClientBlockStateColorCache(IBlockState blockState, IClientLevelWrapper clientLevelWrapper)
+ #else
public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper clientLevelWrapper)
+ #endif
{
this.blockState = blockState;
this.blockStateWrapper = BlockStateWrapper.fromBlockState(blockState, clientLevelWrapper);
@@ -220,6 +267,7 @@ public class ClientBlockStateColorCache
//===================//
// color calculation //
//===================//
+ //region
private void resolveColors()
{
@@ -233,17 +281,44 @@ public class ClientBlockStateColorCache
// getQuads() isn't thread safe so we need to put this logic in a lock
RESOLVE_LOCK.lock();
- if (this.blockState.getFluidState().isEmpty())
+ #if MC_VER <= MC_1_12_2
+ if (this.blockState.getRenderType() == EnumBlockRenderType.ENTITYBLOCK_ANIMATED)
+ {
+ this.needPostTinting = false;
+ this.tintIndex = 0;
+ this.baseColor = ColorUtil.argbToInt(255,
+ this.blockStateWrapper.getMapColor().getRed(),
+ this.blockStateWrapper.getMapColor().getGreen(),
+ this.blockStateWrapper.getMapColor().getBlue());
+ this.isColorResolved = true;
+ return;
+ }
+ #endif
+
+ if (!this.blockStateWrapper.isLiquid())
{
// look for the first non-empty direction
List quads = null;
- for (Direction direction : COLOR_RESOLUTION_DIRECTION_ORDER)
+
+ #if MC_VER <= MC_1_12_2
+ EnumFacing direction;
+ #else
+ Direction direction;
+ #endif
+
+ for (int i = 0; i < COLOR_RESOLUTION_DIRECTION_ORDER.length; i++)
{
+ direction = COLOR_RESOLUTION_DIRECTION_ORDER[i];
quads = this.getQuadsForDirection(direction);
if (quads != null && !quads.isEmpty()
&& !(
+ #if MC_VER <= MC_1_12_2
+ this.blockState.getBlock() instanceof BlockRotatedPillar
+ && direction == EnumFacing.UP
+ #else
this.blockState.getBlock() instanceof RotatedPillarBlock
&& direction == Direction.UP
+ #endif
)
)
{
@@ -260,39 +335,57 @@ public class ClientBlockStateColorCache
&& !quads.isEmpty()
&& quads.get(0) != null)
{
- BakedQuad firstQuad = quads.get(0);
+ try
+ {
+ BakedQuad firstQuad = quads.get(0);
+
+ #if MC_VER <= MC_1_12_2
+ this.needPostTinting = firstQuad.hasTintIndex();
+ #elif MC_VER <= MC_1_21_11
+ this.needPostTinting = firstQuad.isTinted();
+ #else
+ this.needPostTinting = firstQuad.materialInfo().isTinted();
+ #endif
- #if MC_VER <= MC_1_21_11
- this.needPostTinting = firstQuad.isTinted();
- #else
- this.needPostTinting = firstQuad.materialInfo().isTinted();
- #endif
-
- #if MC_VER <= MC_1_21_4
- this.tintIndex = firstQuad.getTintIndex();
- #elif MC_VER <= MC_1_21_11
- this.tintIndex = firstQuad.tintIndex();
- #else
- this.tintIndex = firstQuad.materialInfo().tintIndex();
- #endif
-
- #if MC_VER < MC_1_17_1
- this.baseColor = calculateColorFromTexture(
- firstQuad.sprite,
- EColorMode.getColorMode(this.blockState.getBlock()));
- #elif MC_VER < MC_1_21_5
- this.baseColor = calculateColorFromTexture(
- firstQuad.getSprite(),
- EColorMode.getColorMode(this.blockState.getBlock()));
- #elif MC_VER <= MC_1_21_11
- this.baseColor = calculateColorFromTexture(
- firstQuad.sprite(),
- EColorMode.getColorMode(this.blockState.getBlock()));
- #else
- this.baseColor = calculateColorFromTexture(
- firstQuad.materialInfo().sprite(),
- EColorMode.getColorMode(this.blockState.getBlock()));
- #endif
+ #if MC_VER <= MC_1_21_4
+ this.tintIndex = firstQuad.getTintIndex();
+ #elif MC_VER <= MC_1_21_11
+ this.tintIndex = firstQuad.tintIndex();
+ #else
+ this.tintIndex = firstQuad.materialInfo().tintIndex();
+ #endif
+
+ #if MC_VER < MC_1_17_1 && MC_VER > MC_1_12_2
+ this.baseColor = calculateColorFromTexture(
+ firstQuad.sprite,
+ EColorMode.getColorMode(this.blockState.getBlock()));
+ #elif MC_VER < MC_1_21_5
+ this.baseColor = calculateColorFromTexture(
+ firstQuad.getSprite(),
+ EColorMode.getColorMode(this.blockState.getBlock()));
+ #elif MC_VER <= MC_1_21_11
+ this.baseColor = calculateColorFromTexture(
+ firstQuad.sprite(),
+ EColorMode.getColorMode(this.blockState.getBlock()));
+ #else
+ this.baseColor = calculateColorFromTexture(
+ firstQuad.materialInfo().sprite(),
+ EColorMode.getColorMode(this.blockState.getBlock()));
+ #endif
+ }
+ catch (Exception e)
+ {
+ // Shouldn't normally happen, but there was at least
+ // one report of MC's texture being un-loaded
+ // which prevented us from getting the texture.
+ // So we should have some basic backup logic.
+
+ LOGGER.warn("Failed to get texture color for block ["+this.blockStateWrapper.getSerialString()+"] due to: ["+e.getMessage()+"], falling back to particle color.");
+
+ this.needPostTinting = false;
+ this.tintIndex = 0;
+ this.baseColor = this.getParticleIconColor();
+ }
}
else
{
@@ -322,20 +415,43 @@ public class ClientBlockStateColorCache
@Nullable
private List getUnculledQuads() { return this.getQuadsForDirection(null); }
@Nullable
+ #if MC_VER <= MC_1_12_2
+ private List getQuadsForDirection(@Nullable EnumFacing direction)
+ #else
private List getQuadsForDirection(@Nullable Direction direction)
+ #endif
{
+ #if MC_VER <= MC_1_12_2
+ IBlockState effectiveBlockState = this.blockState;
+ #else
BlockState effectiveBlockState = this.blockState;
+ #endif
// if this block is a slab, use it's double variant so we can get the top face,
// otherwise the color will use the side, which isn't as accurate
+ #if MC_VER <= MC_1_12_2
+ if (this.blockState.getBlock() instanceof BlockSlab && !((BlockSlab) this.blockState.getBlock()).isDouble())
+ {
+ effectiveBlockState = this.blockState.withProperty(BlockSlab.HALF, BlockSlab.EnumBlockHalf.TOP);
+ }
+ #else
if (this.blockState.getBlock() instanceof SlabBlock)
{
effectiveBlockState = this.blockState.setValue( SlabBlock.TYPE, SlabType.DOUBLE );
}
+ #endif
List quads;
- #if MC_VER < MC_1_21_5
+ #if MC_VER <= MC_1_12_2
+ try {
+ quads = MC.getBlockRendererDispatcher().getModelForState(effectiveBlockState).getQuads(effectiveBlockState, direction, RANDOM.nextLong());
+ }
+ catch (Exception e)
+ {
+ quads = Collections.emptyList();
+ }
+ #elif MC_VER < MC_1_21_5
quads = MC.getModelManager().getBlockModelShaper().
getBlockModel(effectiveBlockState).getQuads(effectiveBlockState, direction, RANDOM);
#elif MC_VER <= MC_1_21_11
@@ -392,29 +508,29 @@ public class ClientBlockStateColorCache
//_ OpenGL RGBA format Java Order: 0xAA BB GG RR
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
+ #if MC_VER <= MC_1_12_2
+ int b = (tempColor & 0x000000FF);
+ int g = (tempColor & 0x0000FF00) >>> 8;
+ int r = (tempColor & 0x00FF0000) >>> 16;
+ int a = (tempColor & 0xFF000000) >>> 24;
+ #else
int r = (tempColor & 0x000000FF);
int g = (tempColor & 0x0000FF00) >>> 8;
int b = (tempColor & 0x00FF0000) >>> 16;
int a = (tempColor & 0xFF000000) >>> 24;
+ #endif
+
int scale = 1;
if (colorMode == EColorMode.Leaves)
{
- //switch (//FIXME add config option)
- // case BLACK:
- // a = 255; //simulate black background of fast leaves
- // break;
- // case IGNORE:
- if (a == 0) {
- continue; //same long grass
- }
- else
- {
- a = 255; //just in case there are semi transparent pixels
- }
- // break;
- // case TRANSPARENT:
- // break; //do nothing, let it count towards transparency
-
+ if (a == 0)
+ {
+ continue; //same long grass
+ }
+ else
+ {
+ a = 255; //just in case there are semi transparent pixels
+ }
}
else if (a == 0 && colorMode != EColorMode.Glass)
{
@@ -460,7 +576,9 @@ public class ClientBlockStateColorCache
}
private static int getTextureWidth(TextureAtlasSprite texture)
{
- #if MC_VER < MC_1_19_4
+ #if MC_VER <= MC_1_12_2
+ return texture.getIconWidth();
+ #elif MC_VER < MC_1_19_4
return texture.getWidth();
#else
return texture.contents().width();
@@ -468,7 +586,9 @@ public class ClientBlockStateColorCache
}
private static int getTextureHeight(TextureAtlasSprite texture)
{
- #if MC_VER < MC_1_19_4
+ #if MC_VER <= MC_1_12_2
+ return texture.getIconHeight();
+ #elif MC_VER < MC_1_19_4
return texture.getHeight();
#else
return texture.contents().height();
@@ -502,7 +622,9 @@ public class ClientBlockStateColorCache
private int getParticleIconColor()
{
return calculateColorFromTexture(
- #if MC_VER <= MC_1_21_11
+ #if MC_VER <= MC_1_12_2
+ Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelShapes().getTexture(this.blockState),
+ #elif MC_VER <= MC_1_21_11
Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState),
#else
Minecraft.getInstance().getModelManager().getBlockStateModelSet().get(this.blockState).particleMaterial().sprite(),
@@ -510,16 +632,20 @@ public class ClientBlockStateColorCache
EColorMode.getColorMode(this.blockState.getBlock()));
}
+ //endregion
+
//===============//
// public getter //
//===============//
+ //region
public int getColor(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, DhBlockPos blockPos)
{
// only get the tint if the block needs to be tinted
- int tintColor = AbstractDhTintGetter.INVALID_COLOR;
+ int tintColor = ClientBlockStateColorCache.INVALID_COLOR;
+
if (this.needPostTinting)
{
// don't try tinting blocks that don't support our method of tint getting
@@ -532,28 +658,62 @@ public class ClientBlockStateColorCache
// attempt to get the tint
try
{
+ #if MC_VER <= MC_1_12_2
+ // 1.12.2 doesn't have BlockAndTintGetter -> get tintColor from biome
+ WorldClient world = (WorldClient) this.clientLevelWrapper.getWrappedMcObject();
+ BlockPos mcPos = new BlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ());
+
+ Block block = this.blockState.getBlock();
+ if (block instanceof BlockGrass
+ || block instanceof BlockBush)
+ {
+ tintColor = biomeWrapper.biome.getGrassColorAtPos(mcPos);
+ }
+ else if (block instanceof BlockLeaves)
+ {
+ tintColor = biomeWrapper.biome.getFoliageColorAtPos(mcPos);
+ }
+ else if (block instanceof BlockLiquid) // We don't want lava to fall into the else block
+ {
+ if(block == Blocks.WATER
+ || block == Blocks.FLOWING_WATER)
+ {
+ tintColor = biomeWrapper.biome.getWaterColor();
+ }
+ }
+ else
+ {
+ BlockColors blockColors = Minecraft.getMinecraft().getBlockColors();
+ tintColor = blockColors.colorMultiplier(blockState, world, mcPos, this.tintIndex);
+
+ if (tintColor == ClientBlockStateColorCache.INVALID_COLOR)
+ {
+ tintColor = blockColors.getColor(blockState, world, mcPos);
+ }
+ }
+ #else
// try to use the fast tint getter logic first
if (!BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
{
try
- {
+ {
TintWithoutLevelOverrider tintOverride = TintWithoutLevelOverrideGetter.get();
tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper);
// try using DH's cached tint values first if possible
tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos));
- if (tintColor == AbstractDhTintGetter.INVALID_COLOR)
+ if (tintColor == ClientBlockStateColorCache.INVALID_COLOR)
{
// one or more tint values weren't calculated,
// we need MC's color resolver
- #if MC_VER <= MC_1_21_11
- tintColor = Minecraft.getInstance()
+ #if MC_VER <= MC_1_21_11
+ tintColor = Minecraft.getInstance()
.getBlockColors()
.getColor(this.blockState,
tintOverride, // tintOverride will save the result of this query to speed up future queries
McObjectConverter.Convert(blockPos),
this.tintIndex);
- #else
+ #else
BlockTintSource tintSource = Minecraft.getInstance()
.getBlockColors()
.getTintSource(this.blockState, this.tintIndex);
@@ -564,18 +724,12 @@ public class ClientBlockStateColorCache
{
BlockPos mcPos = McObjectConverter.Convert(blockPos);
tintColor = tintSource.colorInWorld(this.blockState, tintOverride, mcPos);
- if (tintColor == -1)
+ if (tintColor == ClientBlockStateColorCache.INVALID_COLOR)
{
tintColor = tintSource.colorAsTerrainParticle(this.blockState, tintOverride, mcPos);
}
}
- if (tintColor == -1)
- {
- // no color found, use the base color
- tintColor = AbstractDhTintGetter.INVALID_COLOR;
- }
-
// save this color to speed up future queries
TintWithoutLevelOverrider.setStaticColor(this.blockStateWrapper, biomeWrapper, tintColor);
// try to get the blended color with this new information
@@ -585,44 +739,47 @@ public class ClientBlockStateColorCache
}
catch (Exception e)
{
- #if MC_VER <= MC_1_21_11
- // this exception generally occurs if the tint requires other blocks besides itself
- LOGGER.debug("Unable to use ["+ TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e);
- BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState);
- #else
+ #if MC_VER <= MC_1_21_11
+ // this exception generally occurs if the tint requires other blocks besides itself
+ LOGGER.debug("Unable to use ["+ TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e);
+ BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState);
+ #else
// only display the error once per block/biome type to reduce log spam
if (!BROKEN_BLOCK_STATES.contains(this.blockState))
{
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: [" + e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
BROKEN_BLOCK_STATES.add(this.blockState);
}
- #endif
+ #endif
}
}
+ #endif
+
// level-specific logic is only needed for MC 1.21.11 and older
- #if MC_VER <= MC_1_21_11
- // use the level logic only if requested
- if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
- {
- // the level shouldn't be used all the time due to it breaking some blocks tinting
- // specifically oceans don't render correctly
-
- TintGetterOverride tintOverride = TintOverrideGetter.get();
- tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper);
-
- tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos));
- if (tintColor == AbstractDhTintGetter.INVALID_COLOR)
+ #if MC_VER <= MC_1_21_11 && MC_VER > MC_1_12_2
+ // use the level logic only if requested
+ if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
{
- tintColor = Minecraft.getInstance()
- .getBlockColors()
- .getColor(this.blockState,
- tintOverride,
- McObjectConverter.Convert(blockPos),
- this.tintIndex);
+ // the level shouldn't be used all the time due to it breaking some blocks tinting
+ // specifically oceans don't render correctly
+
+ TintGetterOverride tintOverride = TintOverrideGetter.get();
+ tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper);
+
+ tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos));
+ if (tintColor == ClientBlockStateColorCache.INVALID_COLOR)
+ {
+ tintColor = Minecraft.getInstance()
+ .getBlockColors()
+ .getColor(this.blockState,
+ tintOverride,
+ McObjectConverter.Convert(blockPos),
+ this.tintIndex);
+ }
}
- }
- #endif
+ #endif
+
}
catch (Exception e)
{
@@ -637,7 +794,7 @@ public class ClientBlockStateColorCache
int returnColor;
- if (tintColor != AbstractDhTintGetter.INVALID_COLOR)
+ if (tintColor != ClientBlockStateColorCache.INVALID_COLOR)
{
returnColor = ColorUtil.multiplyARGBwithRGB(this.baseColor, tintColor);
}
@@ -667,6 +824,8 @@ public class ClientBlockStateColorCache
return returnColor;
}
+ //endregion
+
//================//
@@ -684,14 +843,54 @@ public class ClientBlockStateColorCache
static EColorMode getColorMode(Block block)
{
- if (block instanceof LeavesBlock)
+
+
+
+ //========//
+ // leaves //
+ //========//
+ //region
+
+ boolean isLeavesBlock;
+ #if MC_VER <= MC_1_12_2
+ isLeavesBlock = block instanceof BlockLeaves;
+ #else
+ isLeavesBlock = block instanceof LeavesBlock;
+ #endif
+ if (isLeavesBlock)
{
return Leaves;
}
- if (block instanceof FlowerBlock)
+
+ //endregion
+
+
+
+ //========//
+ // flower //
+ //========//
+ //region
+
+ boolean isFlowerBlock;
+ #if MC_VER <= MC_1_12_2
+ isFlowerBlock = block instanceof BlockFlower;
+ #else
+ isFlowerBlock = block instanceof FlowerBlock;
+ #endif
+ if (isFlowerBlock)
{
return Flower;
}
+
+ //endregion
+
+
+
+ //=============//
+ // misc/simple //
+ //=============//
+ //region
+
if (block.toString().contains("glass"))
{
return Glass;
@@ -700,6 +899,11 @@ public class ClientBlockStateColorCache
{
return Chisel;
}
+
+ //endregion
+
+
+
return Default;
}
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TextureAtlasSpriteWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TextureAtlasSpriteWrapper.java
index f6a678afd..1fa5f0ae2 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TextureAtlasSpriteWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TextureAtlasSpriteWrapper.java
@@ -38,7 +38,10 @@ public class TextureAtlasSpriteWrapper
{
public static int getPixelRGBA(TextureAtlasSprite sprite, int frameIndex, int x, int y)
{
- #if MC_VER < MC_1_17_1
+ #if MC_VER <= MC_1_12_2
+ int[][] frameData = sprite.getFrameTextureData(frameIndex);
+ return frameData[0][y * sprite.getIconWidth() + x];
+ #elif MC_VER < MC_1_17_1
return sprite.mainImage[0].getPixelRGBA(
x + sprite.framesX[frameIndex] * sprite.getWidth(),
y + sprite.framesY[frameIndex] * sprite.getHeight());
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintGetterOverride.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintGetterOverride.java
index 1e9bfb0e4..3554b5efb 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintGetterOverride.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintGetterOverride.java
@@ -18,7 +18,7 @@
*/
package com.seibel.distanthorizons.common.wrappers.block;
-
+#if MC_VER > MC_1_12_2
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.core.BlockPos;
@@ -189,3 +189,4 @@ public class TintGetterOverride extends AbstractDhTintGetter
}
+#endif
\ No newline at end of file
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintWithoutLevelOverrider.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintWithoutLevelOverrider.java
index 406b625c7..af932f3c8 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintWithoutLevelOverrider.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintWithoutLevelOverrider.java
@@ -18,7 +18,7 @@
*/
package com.seibel.distanthorizons.common.wrappers.block;
-
+#if MC_VER > MC_1_12_2
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.LevelReader;
@@ -109,3 +109,4 @@ public class TintWithoutLevelOverrider extends AbstractDhTintGetter
}
+#endif
\ No newline at end of file
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java
index 022c3fb93..d6fc4fe41 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java
@@ -31,12 +31,19 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IMutableBlockPosWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
-
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
+import net.minecraft.world.chunk.Chunk;
+import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
+#else
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.levelgen.Heightmap;
+#endif
import com.seibel.distanthorizons.core.logging.DhLogger;
@@ -67,9 +74,10 @@ import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.LevelChunkSection;
#endif
-#if MC_VER <= MC_1_20_4
+#if MC_VER <= MC_1_12_2
+#elif MC_VER <= MC_1_20_4
import net.minecraft.world.level.chunk.ChunkStatus;
-#else
+#elif MC_VER > MC_1_12_2
import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif
@@ -86,8 +94,12 @@ public class ChunkWrapper implements IChunkWrapper
private static boolean heightmapThreadWarningLogged = false;
-
+ #if MC_VER <= MC_1_12_2
+ private final Chunk chunk;
+ #else
private final ChunkAccess chunk;
+ #endif
+
private final DhChunkPos chunkPos;
private final ILevelWrapper wrappedLevel;
@@ -112,13 +124,17 @@ public class ChunkWrapper implements IChunkWrapper
//=============//
// constructor //
//=============//
-
+ //region
/**
* Note: this constructor should be very
* fast since it will be called frequently on the MC
* server thread and a slow method will cause server lag.
*/
+ #if MC_VER <= MC_1_12_2
+ public ChunkWrapper(Chunk chunk, ILevelWrapper wrappedLevel)
+ #else
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel)
+ #endif
{
this.chunk = chunk;
this.wrappedLevel = wrappedLevel;
@@ -133,15 +149,22 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public ChunkWrapper copy() { return new ChunkWrapper(this.chunk, this.wrappedLevel); }
+ //endregion
+
//=========//
// getters //
//=========//
+ //region
@Override
public int getHeight() { return getHeight(this.chunk); }
+ #if MC_VER <= MC_1_12_2
+ public static int getHeight(Chunk chunk)
+ #else
public static int getHeight(ChunkAccess chunk)
+ #endif
{
#if MC_VER < MC_1_17_1
return 255;
@@ -152,7 +175,11 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public int getInclusiveMinBuildHeight() { return getInclusiveMinBuildHeight(this.chunk); }
+ #if MC_VER <= MC_1_12_2
+ public static int getInclusiveMinBuildHeight(Chunk chunk)
+ #else
public static int getInclusiveMinBuildHeight(ChunkAccess chunk)
+ #endif
{
#if MC_VER < MC_1_17_1
return 0;
@@ -165,9 +192,15 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public int getExclusiveMaxBuildHeight() { return getExclusiveMaxBuildHeight(this.chunk); }
+ #if MC_VER <= MC_1_12_2
+ public static int getExclusiveMaxBuildHeight(Chunk chunk)
+ #else
public static int getExclusiveMaxBuildHeight(ChunkAccess chunk)
+ #endif
{
- #if MC_VER < MC_1_21_3
+ #if MC_VER <= MC_1_12_2
+ return 256;
+ #elif MC_VER < MC_1_21_3
return chunk.getMaxBuildHeight();
#else
// +1 since Minecraft made the max value inclusive
@@ -188,7 +221,11 @@ public class ChunkWrapper implements IChunkWrapper
this.minNonEmptyHeight = this.getInclusiveMinBuildHeight();
// determine the lowest empty section (bottom up)
+ #if MC_VER <= MC_1_12_2
+ ExtendedBlockStorage[] sections = this.chunk.getBlockStorageArray();
+ #else
LevelChunkSection[] sections = this.chunk.getSections();
+ #endif
for (int index = 0; index < sections.length; index++)
{
if (sections[index] == null)
@@ -220,7 +257,11 @@ public class ChunkWrapper implements IChunkWrapper
this.maxNonEmptyHeight = this.getExclusiveMaxBuildHeight();
// determine the highest empty section (top down)
+ #if MC_VER <= MC_1_12_2
+ ExtendedBlockStorage[] sections = this.chunk.getBlockStorageArray();
+ #else
LevelChunkSection[] sections = this.chunk.getSections();
+ #endif
for (int index = sections.length-1; index >= 0; index--)
{
// update at each position to fix using the max height if the chunk is empty
@@ -240,11 +281,13 @@ public class ChunkWrapper implements IChunkWrapper
return this.maxNonEmptyHeight;
}
+ #if MC_VER <= MC_1_12_2
+ private static boolean isChunkSectionEmpty(ExtendedBlockStorage section)
+ #else
private static boolean isChunkSectionEmpty(LevelChunkSection section)
+ #endif
{
- #if MC_VER == MC_1_16_5
- return section.isEmpty();
- #elif MC_VER == MC_1_17_1
+ #if MC_VER <= MC_1_17_1
return section.isEmpty();
#else
return section.hasOnlyAir();
@@ -322,7 +365,11 @@ public class ChunkWrapper implements IChunkWrapper
// will be null if we want to use MC heightmaps
if (this.solidHeightMap == null)
{
+ #if MC_VER <= MC_1_12_2
+ return this.chunk.getHeightValue(xRel, zRel);
+ #else
return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE).getFirstAvailable(xRel, zRel);
+ #endif
}
else
{
@@ -337,19 +384,30 @@ public class ChunkWrapper implements IChunkWrapper
if (this.lightBlockingHeightMap == null)
{
+ #if MC_VER <= MC_1_12_2
+ return this.chunk.getHeightValue(xRel, zRel);
+ #else
return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING).getFirstAvailable(xRel, zRel);
+ #endif
}
else
{
return this.lightBlockingHeightMap[xRel][zRel];
- }
+ }
}
@Override
public IBiomeWrapper getBiome(int relX, int relY, int relZ)
{
- #if MC_VER < MC_1_17_1
+ #if MC_VER <= MC_1_12_2
+ BlockPos.MutableBlockPos blockPos = MUTABLE_BLOCK_POS_REF.get();
+ blockPos.setPos(relX, relY, relZ);
+
+ World world = (World) this.wrappedLevel.getWrappedMcObject();
+
+ return BiomeWrapper.getBiomeWrapper(this.chunk.getBiome(blockPos, world.getBiomeProvider()), wrappedLevel);
+ #elif MC_VER < MC_1_17_1
return BiomeWrapper.getBiomeWrapper(this.chunk.getBiomes().getNoiseBiome(
relX >> 2, relY >> 2, relZ >> 2),
this.wrappedLevel);
@@ -357,10 +415,6 @@ public class ChunkWrapper implements IChunkWrapper
return BiomeWrapper.getBiomeWrapper(this.chunk.getBiomes().getNoiseBiome(
QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)),
this.wrappedLevel);
- #elif MC_VER < MC_1_18_2
- return BiomeWrapper.getBiomeWrapper(this.chunk.getNoiseBiome(
- QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)),
- this.wrappedLevel);
#else
//Now returns a Holder instead of Biome
return BiomeWrapper.getBiomeWrapper(this.chunk.getNoiseBiome(
@@ -376,9 +430,13 @@ public class ChunkWrapper implements IChunkWrapper
BlockPos.MutableBlockPos blockPos = MUTABLE_BLOCK_POS_REF.get();
+ #if MC_VER <= MC_1_12_2
+ blockPos.setPos(relX, relY, relZ);
+ #else
blockPos.setX(relX);
blockPos.setY(relY);
blockPos.setZ(relZ);
+ #endif
try
{
@@ -401,9 +459,13 @@ public class ChunkWrapper implements IChunkWrapper
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
BlockPos.MutableBlockPos pos = (BlockPos.MutableBlockPos)mcBlockPos.getWrappedMcObject();
+ #if MC_VER <= MC_1_12_2
+ pos.setPos(relX, relY, relZ);
+ #else
pos.setX(relX);
pos.setY(relY);
pos.setZ(relZ);
+ #endif
try
{
@@ -513,8 +575,14 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public DhChunkPos getChunkPos() { return this.chunkPos; }
- public ChunkAccess getChunk() { return this.chunk; }
+ #if MC_VER <= MC_1_12_2
+ public Chunk getChunk()
+ #else
+ public ChunkAccess getChunk()
+ #endif
+ { return this.chunk; }
+ #if MC_VER > MC_1_12_2
public void trySetStatus(ChunkStatus status) { trySetStatus(this.getChunk(), status); }
/** does nothing if the chunk object doesn't support setting it's status */
public static void trySetStatus(ChunkAccess chunk, ChunkStatus status)
@@ -538,21 +606,53 @@ public class ChunkWrapper implements IChunkWrapper
return chunk.getPersistedStatus();
#endif
}
+ #endif
@Override
- public int getMaxBlockX() { return this.chunk.getPos().getMaxBlockX(); }
+ public int getMaxBlockX()
+ {
+ #if MC_VER <= MC_1_12_2
+ return this.chunk.getPos().getXEnd();
+ #else
+ return this.chunk.getPos().getMaxBlockX();
+ #endif
+ }
@Override
- public int getMaxBlockZ() { return this.chunk.getPos().getMaxBlockZ(); }
+ public int getMaxBlockZ()
+ {
+ #if MC_VER <= MC_1_12_2
+ return this.chunk.getPos().getZEnd();
+ #else
+ return this.chunk.getPos().getMaxBlockZ();
+ #endif
+ }
@Override
- public int getMinBlockX() { return this.chunk.getPos().getMinBlockX(); }
+ public int getMinBlockX()
+ {
+ #if MC_VER <= MC_1_12_2
+ return this.chunk.getPos().getXStart();
+ #else
+ return this.chunk.getPos().getMinBlockX();
+ #endif
+ }
@Override
- public int getMinBlockZ() { return this.chunk.getPos().getMinBlockZ(); }
+ public int getMinBlockZ()
+ {
+ #if MC_VER <= MC_1_12_2
+ return this.chunk.getPos().getZStart();
+ #else
+ return this.chunk.getPos().getMinBlockZ();
+ #endif
+ }
+
+ //endregion
//==========//
// lighting //
//==========//
+ //region
@Override
public void setIsDhSkyLightCorrect(boolean isDhLightCorrect) { this.isDhSkyLightCorrect = isDhLightCorrect; }
@@ -629,8 +729,23 @@ public class ChunkWrapper implements IChunkWrapper
{
this.blockLightPosList = new ArrayList<>();
-
- #if MC_VER < MC_1_20_1
+ //1.12.2 doesn't store lights we must bruteforce it
+ #if MC_VER <= MC_1_12_2
+ for (int x = 0; x < 16; x++)
+ {
+ for (int z = 0; z < 16; z++)
+ {
+ for (int y = 0; y < 256; y++)
+ {
+ IBlockState blockState = this.chunk.getBlockState(x, y, z);
+ if (blockState.getLightValue() > 0)
+ {
+ this.blockLightPosList.add(new DhBlockPos(this.chunk.getPos().getXStart() + x, y, this.chunk.getPos().getZStart() + z));
+ }
+ }
+ }
+ }
+ #elif MC_VER < MC_1_20_1
this.chunk.getLights().forEach((blockPos) ->
{
this.blockLightPosList.add(new DhBlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ()));
@@ -652,11 +767,14 @@ public class ChunkWrapper implements IChunkWrapper
return this.blockLightPosList;
}
+ //endregion
+
//================//
// base overrides //
//================//
+ //region
@Override
public String toString() { return this.chunk.getClass().getSimpleName() + this.chunk.getPos(); }
@@ -672,4 +790,8 @@ public class ChunkWrapper implements IChunkWrapper
// return this.blockBiomeHashCode;
//}
+ //endregion
+
+
+
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/DhScreen.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/DhScreen.java
index b2f4f3571..87da07d77 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/DhScreen.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/DhScreen.java
@@ -1,12 +1,19 @@
package com.seibel.distanthorizons.common.wrappers.gui;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.util.text.ITextComponent;
+#else
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
+#endif
-#if MC_VER < MC_1_20_1
+#if MC_VER <= MC_1_12_2
+#elif MC_VER < MC_1_20_1
import com.mojang.blaze3d.vertex.PoseStack;
#elif MC_VER <= MC_1_21_11
import net.minecraft.client.gui.GuiGraphics;
@@ -16,26 +23,73 @@ import net.minecraft.client.gui.GuiGraphicsExtractor;
import java.util.List;
+#if MC_VER <= MC_1_12_2
+public class DhScreen extends GuiScreen
+#else
public class DhScreen extends Screen
+#endif
{
+ #if MC_VER <= MC_1_12_2
+ protected ITextComponent title;
+ #endif
- protected DhScreen(Component $$0)
+ #if MC_VER <= MC_1_12_2
+ protected DhScreen(ITextComponent title)
{
- super($$0);
+ this.title = title;
}
+ #else
+ protected DhScreen(Component title)
+ {
+ super(title);
+ }
+ #endif
// addRenderableWidget in 1.17 and over
// addButton in 1.16 and below
+ #if MC_VER <= MC_1_12_2
+ protected GuiButton addBtn(GuiButton button)
+ #else
protected Button addBtn(Button button)
+ #endif
{
- #if MC_VER < MC_1_17_1
+ #if MC_VER <= MC_1_12_2
+ this.buttonList.add(button);
+ return button;
+ #elif MC_VER < MC_1_17_1
return this.addButton(button);
#else
return this.addRenderableWidget(button);
#endif
}
- #if MC_VER < MC_1_20_1
+ #if MC_VER <= MC_1_12_2
+ @Override
+ protected void actionPerformed(GuiButton button)
+ {
+ OnPressed handler = GuiHelper.HANDLER_BY_BUTTON.get(button);
+ if (handler != null)
+ {
+ handler.pressed(button);
+ }
+ }
+
+ protected void DhDrawCenteredString(ITextComponent text, int x, int y, int color) {
+ drawCenteredString(fontRenderer, text.getFormattedText(), x, y, color);
+ }
+
+ protected void DhDrawString(ITextComponent text, int x, int y, int color) {
+ drawString(fontRenderer, text.getFormattedText(), x, y, color);
+ }
+
+ protected void DhRenderComponentTooltip(List list, int x, int y) {
+ drawHoveringText(list.stream().map(ITextComponent::getFormattedText).toList(), x, y, fontRenderer);
+ }
+
+ protected void DhRenderTooltip(ITextComponent text, int x, int y) {
+ drawHoveringText(List.of(text.getFormattedText()), x, y, fontRenderer);
+ }
+ #elif MC_VER < MC_1_20_1
protected void DhDrawCenteredString(PoseStack guiStack, Font font, Component text, int x, int y, int color)
{
drawCenteredString(guiStack, font, text, x, y, color);
@@ -112,7 +166,4 @@ public class DhScreen extends Screen
guiStack.setTooltipForNextFrame(font, text, x, y);
}
#endif
-
-
-
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/GetConfigScreen.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/GetConfigScreen.java
index 9fc094553..6b86db0b1 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/GetConfigScreen.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/GetConfigScreen.java
@@ -4,14 +4,22 @@ import com.seibel.distanthorizons.common.wrappers.gui.classicConfig.ClassicConfi
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.coreapi.ModInfo;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.client.gui.GuiScreen;
+#else
import net.minecraft.client.gui.screens.Screen;
+#endif
import com.seibel.distanthorizons.core.logging.DhLogger;
public class GetConfigScreen
{
protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
+ #if MC_VER <= MC_1_12_2
+ public static GuiScreen getScreen(GuiScreen parent)
+ #else
public static Screen getScreen(Screen parent)
+ #endif
{
if (ModInfo.IS_DEV_BUILD)
{
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/GuiHelper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/GuiHelper.java
index 46fe7010d..8df4ce1ac 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/GuiHelper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/GuiHelper.java
@@ -1,11 +1,21 @@
package com.seibel.distanthorizons.common.wrappers.gui;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiTextField;
+import net.minecraft.util.text.ITextComponent;
+import net.minecraft.util.text.TextComponentString;
+import net.minecraft.util.text.TextComponentTranslation;
+import java.util.HashMap;
+import java.util.Map;
+#else
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
+#endif
-#if MC_VER < MC_1_19_2
+#if MC_VER < MC_1_19_2 && MC_VER > MC_1_12_2
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
#endif
@@ -15,57 +25,99 @@ public class GuiHelper
/**
* Helper static methods for versional compat
*/
+ #if MC_VER <= MC_1_12_2
+ public static final Map HANDLER_BY_BUTTON = new HashMap<>();
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ public static GuiButton MakeBtn(ITextComponent base, int posX, int posZ, int width, int height, OnPressed action)
+ #else
public static Button MakeBtn(Component base, int posX, int posZ, int width, int height, Button.OnPress action)
+ #endif
{
- #if MC_VER < MC_1_19_4
+ #if MC_VER <= MC_1_12_2
+ GuiButton button = new GuiButton(HANDLER_BY_BUTTON.size(), posX, posZ, width, height, base.getFormattedText());
+ HANDLER_BY_BUTTON.put(button, action);
+ return button;
+ #elif MC_VER < MC_1_19_4
return new Button(posX, posZ, width, height, base, action);
#else
return Button.builder(base, action).bounds(posX, posZ, width, height).build();
#endif
}
+ #if MC_VER <= MC_1_12_2
+ public static ITextComponent TextOrLiteral(String text)
+ #else
public static MutableComponent TextOrLiteral(String text)
+ #endif
{
- #if MC_VER < MC_1_19_2
+ #if MC_VER <= MC_1_12_2
+ return new TextComponentString(text);
+ #elif MC_VER < MC_1_19_2
return new TextComponent(text);
#else
return Component.literal(text);
#endif
}
+ #if MC_VER <= MC_1_12_2
+ public static ITextComponent TextOrTranslatable(String text)
+ #else
public static MutableComponent TextOrTranslatable(String text)
+ #endif
{
- #if MC_VER < MC_1_19_2
+ #if MC_VER <= MC_1_12_2
+ return new TextComponentString(text);
+ #elif MC_VER < MC_1_19_2
return new TextComponent(text);
#else
return Component.translatable(text);
#endif
}
+ #if MC_VER <= MC_1_12_2
+ public static ITextComponent Translatable(String text, Object... args)
+ #else
public static MutableComponent Translatable(String text, Object... args)
+ #endif
{
- #if MC_VER < MC_1_19_2
+ #if MC_VER <= MC_1_12_2
+ return new TextComponentTranslation(text, args);
+ #elif MC_VER < MC_1_19_2
return new TranslatableComponent(text, args);
#else
return Component.translatable(text, args);
#endif
}
- public static void SetX(AbstractWidget w, int x)
+ #if MC_VER <= MC_1_12_2
+ public static void SetX(GuiButton widget, int x)
+ #else
+ public static void SetX(AbstractWidget widget, int x)
+ #endif
{
#if MC_VER < MC_1_19_4
- w.x = x;
+ widget.x = x;
#else
- w.setX(x);
+ widget.setX(x);
#endif
}
- public static void SetY(AbstractWidget w, int y)
+ #if MC_VER <= MC_1_12_2
+ public static void SetY(GuiTextField textField, int y) { textField.y = y; }
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ public static void SetY(GuiButton widget, int y)
+ #else
+ public static void SetY(AbstractWidget widget, int y)
+ #endif
{
#if MC_VER < MC_1_19_4
- w.y = y;
+ widget.y = y;
#else
- w.setY(y);
+ widget.setY(y);
#endif
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/LangWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/LangWrapper.java
index 7f14108fd..17136c8f3 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/LangWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/LangWrapper.java
@@ -1,21 +1,34 @@
package com.seibel.distanthorizons.common.wrappers.gui;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.client.resources.I18n;
+#else
import net.minecraft.client.resources.language.I18n;
+#endif
public class LangWrapper implements ILangWrapper
{
public static final LangWrapper INSTANCE = new LangWrapper();
+
@Override
public boolean langExists(String str)
{
+ #if MC_VER <= MC_1_12_2
+ return I18n.hasKey(str);
+ #else
return I18n.exists(str);
+ #endif
}
@Override
public String getLang(String str)
{
+ #if MC_VER <= MC_1_12_2
+ return I18n.format(str);
+ #else
return I18n.get(str);
+ #endif
}
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/MinecraftScreen.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/MinecraftScreen.java
index 9e1f4ae30..2da926ba0 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/MinecraftScreen.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/MinecraftScreen.java
@@ -1,17 +1,27 @@
package com.seibel.distanthorizons.common.wrappers.gui;
+#if MC_VER <= MC_1_12_2
+import org.lwjglx.opengl.Display;
+#else
import com.mojang.blaze3d.platform.Window;
-
+#endif
import com.seibel.distanthorizons.core.config.gui.AbstractScreen;
import net.minecraft.client.Minecraft;
+
+#if MC_VER > MC_1_12_2
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.screens.Screen;
+#endif
import org.jetbrains.annotations.NotNull;
-#if MC_VER < MC_1_20_1
+#if MC_VER <= MC_1_12_2
+import net.minecraft.client.gui.GuiListExtended;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.GuiSlot;
+#elif MC_VER < MC_1_20_1
import com.mojang.blaze3d.vertex.PoseStack;
#elif MC_VER <= MC_1_21_11
import net.minecraft.client.gui.GuiGraphics;
@@ -24,19 +34,29 @@ import java.util.*;
public class MinecraftScreen
{
+ #if MC_VER <= MC_1_12_2
+ public static GuiScreen getScreen(GuiScreen parent, AbstractScreen screen, String translationName)
+ #else
public static Screen getScreen(Screen parent, AbstractScreen screen, String translationName)
+ #endif
{
return new ConfigScreenRenderer(parent, screen, translationName);
}
private static class ConfigScreenRenderer extends DhScreen
{
+ #if MC_VER <= MC_1_12_2
+ private final GuiScreen parent;
+ #else
private final Screen parent;
+ #endif
private ConfigListWidget configListWidget;
private AbstractScreen screen;
-
- #if MC_VER < MC_1_19_2
+ #if MC_VER <= MC_1_12_2
+ public static net.minecraft.util.text.TextComponentTranslation translate(String str, Object... args)
+ { return new net.minecraft.util.text.TextComponentTranslation(str, args); }
+ #elif MC_VER < MC_1_19_2
public static net.minecraft.network.chat.TranslatableComponent translate(String str, Object... args)
{ return new net.minecraft.network.chat.TranslatableComponent(str, args); }
#else
@@ -44,10 +64,16 @@ public class MinecraftScreen
{ return net.minecraft.network.chat.Component.translatable(str, args); }
#endif
+ #if MC_VER <= MC_1_12_2
+ protected ConfigScreenRenderer(GuiScreen parent, AbstractScreen screen, String translationName)
+ #else
protected ConfigScreenRenderer(Screen parent, AbstractScreen screen, String translationName)
+ #endif
{
super(translate(translationName));
- #if MC_VER < MC_1_21_9
+ #if MC_VER <= MC_1_12_2
+ screen.minecraftWindow = Display.getWindow();
+ #elif MC_VER < MC_1_21_9
screen.minecraftWindow = Minecraft.getInstance().getWindow().getWindow();
#else
screen.minecraftWindow = Minecraft.getInstance().getWindow().handle();
@@ -57,30 +83,53 @@ public class MinecraftScreen
}
@Override
+ #if MC_VER <= MC_1_12_2
+ public void initGui()
+ #else
protected void init()
+ #endif
{
- super.init(); // Init Minecraft's screen
+ #if MC_VER <= MC_1_12_2
+ super.initGui();
+ #else
+ super.init();
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ this.screen.width = Display.getWidth();
+ this.screen.height = Display.getHeight();
+ #else
Window mcWindow = this.minecraft.getWindow();
this.screen.width = mcWindow.getWidth();
this.screen.height = mcWindow.getHeight();
+ #endif
this.screen.scaledWidth = this.width;
this.screen.scaledHeight = this.height;
this.screen.init(); // Init our own config screen
+ #if MC_VER <= MC_1_12_2
+ this.configListWidget = new ConfigListWidget(this.mc, this.width, this.height, 0, 0, 25); // Select the area to tint
+ #else
this.configListWidget = new ConfigListWidget(this.minecraft, this.width, this.height, 0, 0, 25); // Select the area to tint
+ #endif
- #if MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
+ #if MC_VER <= MC_1_12_2
+ #elif MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
if (this.minecraft != null && this.minecraft.level != null) // Check if in game
{
this.configListWidget.setRenderBackground(false); // Disable from rendering
}
#endif
+ #if MC_VER > MC_1_12_2
this.addWidget(this.configListWidget); // Add the tint to the things to be rendered
+ #endif
}
@Override
- #if MC_VER < MC_1_20_1
+ #if MC_VER <= MC_1_12_2
+ public void drawScreen(int mouseX, int mouseY, float delta)
+ #elif MC_VER < MC_1_20_1
public void render(PoseStack matrices, int mouseX, int mouseY, float delta)
#elif MC_VER <= MC_1_21_11
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
@@ -88,7 +137,9 @@ public class MinecraftScreen
public void extractRenderState(GuiGraphicsExtractor matrices, int mouseX, int mouseY, float delta)
#endif
{
- #if MC_VER < MC_1_20_2
+ #if MC_VER <= MC_1_12_2
+ this.drawDefaultBackground();
+ #elif MC_VER < MC_1_20_2
this.renderBackground(matrices); // Render background
#elif MC_VER < MC_1_21_6
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
@@ -96,7 +147,9 @@ public class MinecraftScreen
// background blur is already being rendered, rendering again causes the game to crash
#endif
- #if MC_VER <= MC_1_21_11
+ #if MC_VER <= MC_1_12_2
+ this.configListWidget.drawScreen(mouseX, mouseY, delta);
+ #elif MC_VER <= MC_1_21_11
this.configListWidget.render(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
#else
this.configListWidget.extractRenderState(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
@@ -106,55 +159,86 @@ public class MinecraftScreen
this.screen.mouseY = mouseY;
this.screen.render(delta); // Render everything on the main screen
- #if MC_VER <= MC_1_21_11
+ #if MC_VER <= MC_1_12_2
+ super.drawScreen(mouseX, mouseY, delta); // Render the vanilla stuff (currently only used for the background and tint)
+ #elif MC_VER <= MC_1_21_11
super.render(matrices, mouseX, mouseY, delta); // Render the vanilla stuff (currently only used for the background and tint)
#else
super.extractRenderState(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
#endif
}
- #if MC_VER <= MC_1_21_10
@Override
+ #if MC_VER <= MC_1_12_2
+ public void setWorldAndResolution(Minecraft mc, int width, int height)
+ #elif MC_VER <= MC_1_21_10
public void resize(Minecraft mc, int width, int height)
#else
- @Override
public void resize(int width, int height)
#endif
{
// Resize Minecraft's screen
- #if MC_VER <= MC_1_21_10
+ #if MC_VER <= MC_1_12_2
+ super.setWorldAndResolution(mc, width, height);
+ #elif MC_VER <= MC_1_21_10
super.resize(mc, width, height);
#else
super.resize(width, height);
#endif
-
+ #if MC_VER <= MC_1_12_2
+ this.screen.width = Display.getWidth();
+ this.screen.height = Display.getHeight();
+ #else
Window mcWindow = this.minecraft.getWindow();
this.screen.width = mcWindow.getWidth();
this.screen.height = mcWindow.getHeight();
+ #endif;
this.screen.scaledWidth = this.width;
this.screen.scaledHeight = this.height;
this.screen.onResize(); // Resize our screen
}
@Override
+ #if MC_VER <= MC_1_12_2
+ public void updateScreen()
+ #else
public void tick()
+ #endif
{
+ #if MC_VER <= MC_1_12_2
+ super.updateScreen(); // Tick Minecraft's screen
+ #else
super.tick(); // Tick Minecraft's screen
+ #endif
+
this.screen.tick(); // Tick our screen
if (this.screen.close) // If we decide to close the screen, then actually close the screen
{
+ #if MC_VER <= MC_1_12_2
+ this.onGuiClosed();
+ #else
this.onClose();
+ #endif
}
}
@Override
+ #if MC_VER <= MC_1_12_2
+ public void onGuiClosed()
+ #else
public void onClose()
+ #endif
{
this.screen.onClose(); // Close our screen
+ #if MC_VER <= MC_1_12_2
+ Objects.requireNonNull(this.mc).displayGuiScreen(this.parent); // Goto the parent screen
+ #else
Objects.requireNonNull(this.minecraft).setScreen(this.parent); // Goto the parent screen
+ #endif
}
+ #if MC_VER > MC_1_12_2
@Override
public void onFilesDrop(@NotNull List files)
{ this.screen.onFilesDrop(files); }
@@ -163,10 +247,14 @@ public class MinecraftScreen
@Override
public boolean shouldCloseOnEsc()
{ return this.screen.shouldCloseOnEsc; }
-
+ #endif
}
+ #if MC_VER <= MC_1_12_2
+ public static class ConfigListWidget extends GuiListExtended
+ #else
public static class ConfigListWidget extends ContainerObjectSelectionList
+ #endif
{
public ConfigListWidget(Minecraft minecraftClient, int canvasWidth, int canvasHeight, int topMargin, int botMargin, int itemSpacing)
{
@@ -178,6 +266,18 @@ public class MinecraftScreen
this.centerListVertically = false;
}
+ #if MC_VER <= MC_1_12_2
+ @Override
+ protected int getSize()
+ {
+ return 0;
+ }
+ @Override
+ public IGuiListEntry getListEntry(int index)
+ {
+ return null;
+ }
+ #endif
}
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/OnPressed.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/OnPressed.java
new file mode 100644
index 000000000..3227ab477
--- /dev/null
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/OnPressed.java
@@ -0,0 +1,9 @@
+package com.seibel.distanthorizons.common.wrappers.gui;
+
+#if MC_VER <= MC_1_12_2
+import net.minecraft.client.gui.GuiButton;
+
+public interface OnPressed {
+ void pressed(GuiButton button);
+}
+#endif
\ No newline at end of file
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/TexturedButtonWidget.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/TexturedButtonWidget.java
index f51f5fe3d..5609f5749 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/TexturedButtonWidget.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/TexturedButtonWidget.java
@@ -19,13 +19,21 @@
package com.seibel.distanthorizons.common.wrappers.gui;
+#if MC_VER > MC_1_12_2
import net.minecraft.network.chat.Component;
+#endif
#if MC_VER >= MC_1_17_1
import net.minecraft.client.gui.components.Button;
#endif
-#if MC_VER < MC_1_17_1
+
+#if MC_VER <= MC_1_12_2
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.util.ResourceLocation;
+#elif MC_VER < MC_1_17_1
import net.minecraft.client.gui.components.ImageButton;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
@@ -53,7 +61,9 @@ import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.renderer.RenderPipelines;
#endif
-#if MC_VER <= MC_1_21_10
+#if MC_VER <= MC_1_12_2
+import net.minecraft.util.ResourceLocation;
+#elif MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
@@ -65,7 +75,10 @@ import net.minecraft.resources.Identifier;
* @author coolGi
* @version 2023-10-03
*/
-#if MC_VER < MC_1_20_2
+#if MC_VER <= MC_1_12_2
+@SuppressWarnings("deprecation") // we use a few deprecated Mojang functions (as expected when running on old MC versions)
+public class TexturedButtonWidget extends GuiButton
+#elif MC_VER < MC_1_20_2
@SuppressWarnings("deprecation") // we use a few deprecated Mojang functions (as expected when running on old MC versions)
public class TexturedButtonWidget extends ImageButton
#else
@@ -75,7 +88,7 @@ public class TexturedButtonWidget extends Button
{
public final boolean renderBackground;
- #if MC_VER >= MC_1_20_2
+ #if MC_VER >= MC_1_20_2 || MC_VER <= MC_1_12_2
private final int u;
private final int v;
private final int hoveredVOffset;
@@ -90,30 +103,41 @@ public class TexturedButtonWidget extends Button
private final int textureHeight;
#endif
-
- public TexturedButtonWidget(
- int x, int y, int width, int height, int u, int v, int hoveredVOffset,
- #if MC_VER <= MC_1_21_10 ResourceLocation textureResourceLocation,
- #else Identifier textureResourceLocation,
- #endif
- int textureWidth, int textureHeight, OnPress pressAction, Component text)
+ #if MC_VER <= MC_1_12_2
+ public TexturedButtonWidget(int id, int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, int textureWidth, int textureHeight, String text)
+ {
+ this(id, x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, text, true);
+ }
+ #elif MC_VER <= MC_1_21_10
+ public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text)
{
this(x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, pressAction, text, true);
}
- public TexturedButtonWidget(
- int x, int y, int width, int height, int u, int v, int hoveredVOffset,
- #if MC_VER <= MC_1_21_10 ResourceLocation textureResourceLocation,
- #else Identifier textureResourceLocation,
- #endif
- int textureWidth, int textureHeight, OnPress pressAction, Component text,
- boolean renderBackground)
+ #else
+ public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, Identifier textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text)
{
- #if MC_VER < MC_1_20_2
+ this(x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, pressAction, text, true);
+ }
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ public TexturedButtonWidget(int id, int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, int textureWidth, int textureHeight, String text, boolean renderBackground)
+ #elif MC_VER <= MC_1_21_10
+ public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text, boolean renderBackground)
+ #else
+ public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, Identifier textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text, boolean renderBackground)
+ #endif
+ {
+ #if MC_VER <= MC_1_12_2
+ super(id, x, y, width, height, text);
+ #elif MC_VER < MC_1_20_2
super(x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, pressAction, text);
#else
// We don't pass in the text option since it will render (we normally pass it in for narration)
super(x, y, width, height, Component.empty(), pressAction, DEFAULT_NARRATION);
+ #endif
+ #if MC_VER >= MC_1_20_2 || MC_VER <= MC_1_12_2
this.u = u;
this.v = v;
this.hoveredVOffset = hoveredVOffset;
@@ -127,7 +151,27 @@ public class TexturedButtonWidget extends Button
this.renderBackground = renderBackground;
}
- #if MC_VER < MC_1_20_2
+ #if MC_VER <= MC_1_12_2
+ @Override
+ public void drawButton(Minecraft mc, int mouseX, int mouseY, float partialTicks) {
+ if (this.visible) {
+ //Render vanilla background
+ mc.getTextureManager().bindTexture(BUTTON_TEXTURES);
+ GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+ this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
+ int i = this.getHoverState(this.hovered);
+ GlStateManager.enableBlend();
+ GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
+ GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
+ this.drawTexturedModalRect(this.x, this.y, 0, 46 + i * 20, this.width / 2, this.height);
+ this.drawTexturedModalRect(this.x + this.width / 2, this.y, 200 - this.width / 2, 46 + i * 20, this.width / 2, this.height);
+
+ //Render DH texture
+ mc.getTextureManager().bindTexture(textureResourceLocation);
+ drawModalRectWithCustomSizedTexture(this.x, this.y, this.u, (hoveredVOffset * (i - 1)), this.width, this.height, this.textureWidth, this.textureHeight);
+ }
+ }
+ #elif MC_VER < MC_1_20_2
#if MC_VER < MC_1_19_4
@Override
public void renderButton(PoseStack matrices, int mouseX, int mouseY, float delta)
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/classicConfig/ClassicConfigGUI.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/classicConfig/ClassicConfigGUI.java
index fad8baa43..7ca4dfaa4 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/classicConfig/ClassicConfigGUI.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/classicConfig/ClassicConfigGUI.java
@@ -12,17 +12,24 @@ import com.seibel.distanthorizons.core.config.types.enums.EConfigCommentTextPosi
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
import net.minecraft.client.Minecraft;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.client.gui.*;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.util.text.ITextComponent;
+#else
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
+#endif
import com.seibel.distanthorizons.core.logging.DhLogger;
+
import org.jetbrains.annotations.NotNull;
-
-#if MC_VER < MC_1_20_1
+#if MC_VER <= MC_1_12_2
+#elif MC_VER < MC_1_20_1
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.GuiComponent;
#elif MC_VER <= MC_1_21_11
@@ -67,6 +74,7 @@ public class ClassicConfigGUI
//==============//
// Initializers //
//==============//
+ //region
// Some regexes to check if an input is valid
public static final Pattern INTEGER_ONLY_REGEX = Pattern.compile("(-?[0-9]*)");
@@ -87,25 +95,46 @@ public class ClassicConfigGUI
}
+ //endregion
+
//==============//
// GUI handling //
//==============//
-
+ //region
/** if you want to get this config gui's screen call this */
+ #if MC_VER <= MC_1_12_2
+ public static GuiScreen getScreen(GuiScreen parent, String category)
+ #else
public static Screen getScreen(Screen parent, String category)
+ #endif
{ return new DhConfigScreen(parent, category); }
+ //endregion
+
//================//
// helper classes //
//================//
+ //region
+ #if MC_VER <= MC_1_12_2
+ public static class ConfigListWidget extends GuiListExtended
+ #else
public static class ConfigListWidget extends ContainerObjectSelectionList
+ #endif
{
+ #if MC_VER <= MC_1_12_2
+ public List children = new ArrayList<>();
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ FontRenderer textRenderer;
+ #else
Font textRenderer;
+ #endif
public ConfigListWidget(Minecraft minecraftClient, int canvasWidth, int canvasHeight, int topMargin, int botMargin, int itemSpacing)
{
@@ -116,40 +145,121 @@ public class ClassicConfigGUI
#endif
this.centerListVertically = false;
+ #if MC_VER <= MC_1_12_2
+ this.textRenderer = minecraftClient.fontRenderer;
+ #else
this.textRenderer = minecraftClient.font;
+ #endif
}
- public void addButton(DhConfigScreen gui, AbstractConfigBase dhConfigType, AbstractWidget button, AbstractWidget resetButton, AbstractWidget indexButton, Component text)
- { this.addEntry(new DhButtonEntry(gui, dhConfigType, button, text, resetButton, indexButton)); }
+ #if MC_VER <= MC_1_12_2
+ @Override
+ protected int getSize()
+ {
+ return this.children.size();
+ }
@Override
- public int getRowWidth() { return 10_000; }
-
- public AbstractWidget getHoveredButton(double mouseX, double mouseY)
+ public IGuiListEntry getListEntry(int index)
{
- for (DhButtonEntry buttonEntry : this.children())
+ return this.children.get(index);
+ }
+
+ @Override
+ protected void drawContainerBackground(Tessellator tessellator)
+ {
+ if (this.mc.world != null)
{
- AbstractWidget button = buttonEntry.button;
- if (button != null
- && button.visible)
+ return; // in-game don't draw dirt background
+ }
+ super.drawContainerBackground(tessellator);
+ }
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ public void addButton(DhConfigScreen gui, AbstractConfigBase dhConfigType, Gui button, GuiButton resetButton, GuiButton indexButton, ITextComponent text)
+ #else
+ public void addButton(DhConfigScreen gui, AbstractConfigBase dhConfigType, AbstractWidget button, AbstractWidget resetButton, AbstractWidget indexButton, Component text)
+ #endif
+ {
+ #if MC_VER <= MC_1_12_2
+ this.children.add(new DhButtonEntry(gui, dhConfigType, button, text, resetButton, indexButton));
+ #else
+ this.addEntry(new DhButtonEntry(gui, dhConfigType, button, text, resetButton, indexButton));
+ #endif
+ }
+
+ @Override
+ #if MC_VER <= MC_1_12_2
+ public int getListWidth()
+ #else
+ public int getRowWidth()
+ #endif
+ { return 10_000; }
+
+ #if MC_VER <= MC_1_12_2
+ public Gui getHoveredButton(double mouseX, double mouseY)
+ #else
+ public AbstractWidget getHoveredButton(double mouseX, double mouseY)
+ #endif
+ {
+ #if MC_VER <= MC_1_12_2
+ for (DhButtonEntry buttonEntry : this.children)
+ #else
+ for (DhButtonEntry buttonEntry : this.children())
+ #endif
+ {
+ #if MC_VER <= MC_1_12_2
+ Gui gui = buttonEntry.button;
+ if (gui == null) continue;
+
+ double minX, minY, maxX, maxY;
+
+ if (gui instanceof GuiButton button)
{
- #if MC_VER < MC_1_19_4
- double minX = button.x;
- double minY = button.y;
- #else
- double minX = button.getX();
- double minY = button.getY();
- #endif
-
- double maxX = minX + button.getWidth();
- double maxY = minY + button.getHeight();
-
- if (mouseX >= minX && mouseX < maxX
- && mouseY >= minY && mouseY < maxY)
- {
- return button;
- }
+ if (!button.visible) continue;
+ minX = button.x;
+ minY = button.y;
+ maxX = minX + button.width;
+ maxY = minY + button.height;
}
+ else if (gui instanceof GuiTextField field)
+ {
+ if (!field.getVisible()) continue;
+ minX = field.x;
+ minY = field.y;
+ maxX = minX + field.width;
+ maxY = minY + field.height;
+ }
+ else
+ {
+ continue;
+ }
+
+ if (mouseX >= minX && mouseX < maxX && mouseY >= minY && mouseY < maxY)
+ {
+ return gui;
+ }
+ #else
+ AbstractWidget button = (AbstractWidget) buttonEntry.button;
+ if (button == null || !button.visible) continue;
+
+ #if MC_VER < MC_1_19_4
+ double minX = button.x;
+ double minY = button.y;
+ #else
+ double minX = button.getX();
+ double minY = button.getY();
+ #endif
+
+ double maxX = minX + button.getWidth();
+ double maxY = minY + button.getHeight();
+
+ if (mouseX >= minX && mouseX < maxX && mouseY >= minY && mouseY < maxY)
+ {
+ return button;
+ }
+ #endif
}
return null;
@@ -157,32 +267,60 @@ public class ClassicConfigGUI
}
-
+ #if MC_VER <= MC_1_12_2
+ public static class DhButtonEntry implements GuiListExtended.IGuiListEntry
+ #else
public static class DhButtonEntry extends ContainerObjectSelectionList.Entry
+ #endif
{
+ #if MC_VER <= MC_1_12_2
+ private static final FontRenderer textRenderer = Minecraft.getMinecraft().fontRenderer;
+ #else
private static final Font textRenderer = Minecraft.getInstance().font;
-
- private final AbstractWidget button;
+ #endif
private final DhConfigScreen gui;
-
- private final AbstractWidget resetButton;
+ #if MC_VER <= MC_1_12_2
+ public final Gui button;
+ public final Gui resetButton;
+ public final Gui indexButton;
+ #else
private final AbstractWidget indexButton;
+ private final AbstractWidget resetButton;
+ private final AbstractWidget button;
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ private final ITextComponent text;
+ #else
private final Component text;
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ private final List children = new ArrayList<>();
+ #else
private final List children = new ArrayList<>();
+ #endif
@NotNull
private final EConfigCommentTextPosition textPosition;
public final AbstractConfigBase dhConfigType;
+ #if MC_VER <= MC_1_12_2
+ public static final Map TEXT_BY_WIDGET = new HashMap<>();
+ public static final Map BUTTON_BY_WIDGET = new HashMap<>();
+ #else
public static final Map TEXT_BY_WIDGET = new HashMap<>();
public static final Map BUTTON_BY_WIDGET = new HashMap<>();
+ #endif
- public DhButtonEntry(
- DhConfigScreen gui, AbstractConfigBase dhConfigType,
- AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton)
+ #if MC_VER <= MC_1_12_2
+ public DhButtonEntry(DhConfigScreen gui, AbstractConfigBase dhConfigType, Gui button, ITextComponent text, GuiButton resetButton, GuiButton indexButton)
+ #else
+ public DhButtonEntry(DhConfigScreen gui, AbstractConfigBase dhConfigType, AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton)
+ #endif
{
TEXT_BY_WIDGET.put(button, text);
BUTTON_BY_WIDGET.put(button, this);
@@ -225,7 +363,9 @@ public class ClassicConfigGUI
@Override
- #if MC_VER < MC_1_20_1
+ #if MC_VER <= MC_1_12_2
+ public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected, float tickDelta)
+ #elif MC_VER < MC_1_20_1
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
#elif MC_VER < MC_1_21_9
public void render(GuiGraphics matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
@@ -250,18 +390,40 @@ public class ClassicConfigGUI
if (this.button != null)
{
- SetY(this.button, y);
- #if MC_VER <= MC_1_21_11
- this.button.render(matrices, mouseX, mouseY, tickDelta);
+ #if MC_VER <= MC_1_12_2
+ if (this.button instanceof GuiButton guiButton)
+ {
+ SetY(guiButton, y);
+ guiButton.drawButton(Minecraft.getMinecraft(), mouseX, mouseY, tickDelta);
+ }
+ if (this.button instanceof GuiTextField guiTextField)
+ {
+ SetY(guiTextField, y);
+ guiTextField.drawTextBox();
+ }
#else
- this.button.extractRenderState(matrices, mouseX, mouseY, tickDelta);
+ SetY(this.button, y);
+ {
+ #if MC_VER <= MC_1_21_11
+ this.button.render(matrices, mouseX, mouseY, tickDelta);
+ #else
+ this.button.extractRenderState(matrices, mouseX, mouseY, tickDelta);
+ #endif
+ }
#endif
}
if (this.resetButton != null)
{
+ #if MC_VER <= MC_1_12_2
+ SetY((GuiButton) this.resetButton, y);
+ #else
SetY(this.resetButton, y);
- #if MC_VER <= MC_1_21_11
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ ((GuiButton) this.resetButton).drawButton(Minecraft.getMinecraft(), mouseX, mouseY, tickDelta);
+ #elif MC_VER <= MC_1_21_11
this.resetButton.render(matrices, mouseX, mouseY, tickDelta);
#else
this.resetButton.extractRenderState(matrices, mouseX, mouseY, tickDelta);
@@ -270,8 +432,15 @@ public class ClassicConfigGUI
if (this.indexButton != null)
{
+ #if MC_VER <= MC_1_12_2
+ SetY((GuiButton) this.indexButton, y);
+ #else
SetY(this.indexButton, y);
- #if MC_VER <= MC_1_21_11
+ #endif
+
+ #if MC_VER <= MC_1_12_2
+ ((GuiButton) this.indexButton).drawButton(Minecraft.getMinecraft(), mouseX, mouseY, tickDelta);
+ #elif MC_VER <= MC_1_21_11
this.indexButton.render(matrices, mouseX, mouseY, tickDelta);
#else
this.indexButton.extractRenderState(matrices, mouseX, mouseY, tickDelta);
@@ -280,7 +449,11 @@ public class ClassicConfigGUI
if (this.text != null)
{
+ #if MC_VER <= MC_1_12_2
+ int translatedLength = textRenderer.getStringWidth(this.text.getFormattedText());
+ #else
int translatedLength = textRenderer.width(this.text);
+ #endif
int textXPos;
if (this.textPosition == EConfigCommentTextPosition.RIGHT_JUSTIFIED)
@@ -313,17 +486,21 @@ public class ClassicConfigGUI
throw new UnsupportedOperationException("No text position render defined for [" + this.textPosition + "]");
}
-
- #if MC_VER < MC_1_20_1
+ #if MC_VER <= MC_1_12_2
+ textRenderer.drawString(
+ this.text.getFormattedText(),
+ textXPos, y + 5,
+ 0xFFFFFF);
+ #elif MC_VER < MC_1_20_1
GuiComponent.drawString(matrices, textRenderer,
- this.text,
- textXPos, y + 5,
- 0xFFFFFF);
+ this.text,
+ textXPos, y + 5,
+ 0xFFFFFF);
#elif MC_VER < MC_1_21_6
- matrices.drawString(textRenderer,
- this.text,
- textXPos, y + 5,
- 0xFFFFFF);
+ matrices.drawString(textRenderer,
+ this.text,
+ textXPos, y + 5,
+ 0xFFFFFF);
#elif MC_VER <= MC_1_21_11
matrices.drawString(textRenderer,
this.text,
@@ -344,9 +521,25 @@ public class ClassicConfigGUI
}
}
+ #if MC_VER <= MC_1_12_2
+ @Override
+ public void updatePosition(int slotIndex, int x, int y, float partialTicks) { }
+
+ @Override
+ public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY)
+ {
+ return false; // handled in DhConfigScreen.mouseClicked
+ }
+
+ @Override
+ public void mouseReleased(int slotIndex, int x, int y, int mouseEvent, int relativeX, int relativeY) { }
+ #endif
+
+ #if MC_VER > MC_1_12_2
@Override
public @NotNull List extends GuiEventListener> children()
{ return this.children; }
+ #endif
#if MC_VER >= MC_1_17_1
@Override
@@ -358,11 +551,14 @@ public class ClassicConfigGUI
}
+ //endregion
+
//================//
// event handling //
//================//
+ //region
public static class ConfigCoreInterface implements IConfigGui
{
@@ -381,4 +577,5 @@ public class ClassicConfigGUI
}
+ //endregion
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/classicConfig/DhConfigScreen.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/classicConfig/DhConfigScreen.java
index c5c4a110a..073b6b242 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/classicConfig/DhConfigScreen.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/classicConfig/DhConfigScreen.java
@@ -13,14 +13,18 @@ import java.util.regex.Pattern;
import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui;
import com.seibel.distanthorizons.common.wrappers.gui.DhScreen;
+import com.seibel.distanthorizons.common.wrappers.gui.GuiHelper;
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
import com.seibel.distanthorizons.common.wrappers.gui.config.ConfigGuiInfo;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.types.*;
+#if MC_VER <= MC_1_12_2
+import com.seibel.distanthorizons.common.wrappers.gui.OnPressed;
+#else
import com.seibel.distanthorizons.common.wrappers.gui.updater.ChangelogScreen;
-
+#endif
import com.seibel.distanthorizons.core.config.types.enums.EConfigCommentTextPosition;
import com.seibel.distanthorizons.core.config.types.enums.EConfigValidity;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
@@ -30,8 +34,15 @@ import com.seibel.distanthorizons.core.util.AnnotationUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
-import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
+#if MC_VER <= MC_1_12_2
+import net.minecraft.client.gui.*;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.util.text.ITextComponent;
+import net.minecraft.util.text.Style;
+import net.minecraft.util.text.TextFormatting;
+#else
+import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;
@@ -40,12 +51,13 @@ import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
+#endif
import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-
-#if MC_VER < MC_1_20_1
+#if MC_VER <= MC_1_12_2
+#elif MC_VER < MC_1_20_1
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.GuiComponent;
#elif MC_VER <= MC_1_21_11
@@ -58,14 +70,18 @@ import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.narration.NarratableEntry;
#endif
-#if MC_VER <= MC_1_21_10
+#if MC_VER <= MC_1_12_2
+import net.minecraft.util.ResourceLocation;
+#elif MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
#endif
import org.lwjgl.glfw.GLFW;
+#if MC_VER > MC_1_12_2
import com.mojang.blaze3d.platform.InputConstants;
+#endif
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.Translatable;
@@ -79,21 +95,34 @@ class DhConfigScreen extends DhScreen
private static final MinecraftClientWrapper MC_CLIENT = MinecraftClientWrapper.INSTANCE;
-
+ #if MC_VER <= MC_1_12_2
+ private final GuiScreen parent;
+ #else
private final Screen parent;
+ #endif
+
private final String category;
private ClassicConfigGUI.ConfigListWidget configListWidget;
private boolean reload = false;
+ #if MC_VER <= MC_1_12_2
+ private GuiButton doneButton;
+ #else
private Button doneButton;
+ #endif
//=============//
// constructor //
//=============//
+ //region
+ #if MC_VER <= MC_1_12_2
+ protected DhConfigScreen(GuiScreen parent, String category)
+ #else
protected DhConfigScreen(Screen parent, String category)
+ #endif
{
super(Translatable(
LANG_WRAPPER.langExists(ModInfo.ID + ".config" + (category.isEmpty() ? "." + category : "") + ".title") ?
@@ -104,25 +133,50 @@ class DhConfigScreen extends DhScreen
this.category = category;
}
+ //endregion
+
+
+ //===================//
+ // menu UI lifecycle //
+ //===================//
+ //region
+
@Override
+ #if MC_VER <= MC_1_12_2
+ public void updateScreen() { super.updateScreen(); }
+ #else
public void tick() { super.tick(); }
+ #endif
-
-
+ //endregion
+
+
+
//==================//
// menu UI creation //
//==================//
+ //region
@Override
+ #if MC_VER <= MC_1_12_2
+ public void initGui()
+ #else
protected void init()
+ #endif
{
+ #if MC_VER <= MC_1_12_2
+ super.initGui();
+ #else
super.init();
+ #endif
+
if (!this.reload)
{
ConfigHandler.INSTANCE.configFileHandler.loadFromFile();
}
+ #if MC_VER > MC_1_12_2
// Changelog button
if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get()
// we only have changelogs for stable builds
@@ -161,6 +215,7 @@ class DhConfigScreen extends DhScreen
Translatable(ModInfo.ID + ".updater.title")
));
}
+ #endif
// back button
@@ -170,7 +225,11 @@ class DhConfigScreen extends DhScreen
(button) ->
{
ConfigHandler.INSTANCE.configFileHandler.loadFromFile();
+ #if MC_VER <= MC_1_12_2
+ Objects.requireNonNull(this.mc).displayGuiScreen(this.parent);
+ #else
Objects.requireNonNull(this.minecraft).setScreen(this.parent);
+ #endif
}));
// done/close button
@@ -181,19 +240,30 @@ class DhConfigScreen extends DhScreen
(button) ->
{
ConfigHandler.INSTANCE.configFileHandler.saveToFile();
+ #if MC_VER <= MC_1_12_2
+ Objects.requireNonNull(this.mc).displayGuiScreen(this.parent);
+ #else
Objects.requireNonNull(this.minecraft).setScreen(this.parent);
+ #endif
}));
+ #if MC_VER <= MC_1_12_2
+ this.configListWidget = new ClassicConfigGUI.ConfigListWidget(this.mc, this.width * 2, this.height, 32, 32, 25);
+ #else
this.configListWidget = new ClassicConfigGUI.ConfigListWidget(this.minecraft, this.width * 2, this.height, 32, 32, 25);
+ #endif
- #if MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
+ #if MC_VER <= MC_1_12_2
+ #elif MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
if (this.minecraft != null && this.minecraft.level != null)
{
this.configListWidget.setRenderBackground(false);
}
#endif
+ #if MC_VER > MC_1_12_2
this.addWidget(this.configListWidget);
+ #endif
for (AbstractConfigBase> configEntry : ConfigHandler.INSTANCE.configBaseList)
{
@@ -356,18 +426,35 @@ class DhConfigScreen extends DhScreen
private static void setupBooleanMenuOption(ConfigEntry booleanConfigEntry)
{
// For boolean
+ #if MC_VER <= MC_1_12_2
+ Function