diff --git a/.gitignore b/.gitignore
index 16bdd9507..e876e032c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,9 @@ build.properties
# Sqlite databases
*.sqlite
+*.sqlite-journal
+*.sqlite-shm
+*.sqlite-wal
+
+# Don't add access transformers to git as they're dynamically generated
+accesstransformer.cfg
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8097c0218..181343627 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,6 +1,6 @@
# use Eclipse's JDK
# The ci should always use a unix(-like) OS to work
-image: eclipse-temurin:17
+image: eclipse-temurin:21
# all stages need to be defined here
# TODO: Make stages depend on what is in versionProperties
@@ -30,7 +30,7 @@ build:
stage: build
parallel:
matrix:
- - MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4"]
+ - MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6", "1.21"]
script:
# this both runs the unit tests and assembles the code
- ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
@@ -40,17 +40,24 @@ build:
name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
- Merged/*.jar
+ - quilt/build/libs/*.jar
- fabric/build/libs/*.jar
- forge/build/libs/*.jar
- - quilt/build/libs/*.jar
+ - neoforge/build/libs/*.jar
exclude:
# TODO: There is a lot of duplicate stuff here, try to maybe make it smaller
- fabric/build/libs/*-all.jar
+ - fabric/build/libs/*-dev.jar
- fabric/build/libs/*-sources.jar
- - forge/build/libs/*-all.jar
- - forge/build/libs/*-sources.jar
- quilt/build/libs/*-all.jar
+ - quilt/build/libs/*-dev.jar
- quilt/build/libs/*-sources.jar
+ - forge/build/libs/*-all.jar
+ - forge/build/libs/*-dev.jar
+ - forge/build/libs/*-sources.jar
+ - neoforge/build/libs/*-all.jar
+ - neoforge/build/libs/*-dev.jar
+ - neoforge/build/libs/*-sources.jar
expire_in: 14 days
when: always
extends: .build_java
diff --git a/Readme.md b/Readme.md
index f51af7521..0e3ec6701 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1,18 +1,16 @@
#
Distant Horizons
+_See farther without turning your game into a slide show._
-> A mod that adds a Level of Detail System to Minecraft
-
+
# What is Distant Horizons?
-Distant Horizons is a Minecraft mod that adds a Level Of Detail (LOD) system to\
-render simplified chunks outside the normal render distance\
-allowing for an increased view distance without harming performance.
+Distant Horizons is a mod which implements a [Level of Detail](https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics)) system to Minecraft.\
+This allows for far greater render distances without harming performance by gradually lowering the quality of distant terrain.
-In other words: this mod lets you see farther without turning your game into a slide show.\
-If you want to see a quick demo, check out a video covering the mod here:
+Below is a video demonstrating the system:
-
+
@@ -20,6 +18,14 @@ If you want to see a quick demo, check out a video covering the mod here:
### This branch supports the following versions of Minecraft:
+#### 1.20.4, 1.20.3 (Default)
+Fabric: 0.15.1\
+Fabric API: 0.91.2+1.20.4\
+Forge: 49.0.30\
+NeoForge: 118-beta\
+Parchment: 1.20.2:2023.12.10\
+Modmenu: 9.0.0-pre.1
+
#### 1.20.2
Fabric: 0.14.24\
Fabric API: 0.90.4+1.20.2\
@@ -27,7 +33,7 @@ Forge: 48.0.13\
Parchment: 1.20.1:2023.09.03\
Modmenu: 8.0.0
-#### 1.20.1, 1.20 (Default)
+#### 1.20.1, 1.20
Fabric: 0.14.24\
Fabric API: 0.90.4+1.20.1\
Forge: 47.2.1\
@@ -73,14 +79,15 @@ Modmenu: 1.16.22
- 1.18.1, 1.18
- 1.19.1, 1.19
- 1.19.3
-
+
+
### Plugin and Library versions
-Fabric loom: 1.1.+\
-Forge gradle (Using Architectury): 3.4-SNAPSHOT\
+Gradle: 8.5\
+Fabric loom: 1.4-SNAPSHOT\
+Architectury loom (Forge gradle replacement): 1.4-SNAPSHOT\
Sponge vanilla gradle: 0.2.1-SNAPSHOT\
-Sponge mixin: 0.8.5\
Java Preprocessor plugin: Manifold Preprocessor
@@ -93,7 +100,7 @@ Java Preprocessor plugin: Manifold Preprocessor
Visit https://www.oracle.com/java/technologies/downloads/ for installers.
* Git or someway to clone git projects.
Visit https://git-scm.com/ for installers.
-* (Not required) Any Java IDE with plugins that support Manifold, for example Intellij IDEA.
+* (Not required) Any Java IDE with plugins that support Manifold, for example IntelliJ IDEA.
**If using IntelliJ:**
1. Install the Manifold plugin
@@ -106,17 +113,14 @@ Java Preprocessor plugin: Manifold Preprocessor
3. Make sure eclipse has the JDK 17 installed. (This is needed so that eclipse can run minecraft)
4. Import the project into eclipse
-
+
## Switching Versions
To switch between different Minecraft versions, change `mcVer=1.?` in the `gradle.properties` file.
-If running in an IDE, to ensure the IDE noticed the version change, run any gradle command to refresh gradle. (In IntellJ you will also need to do a gradle sync if it didn't happen automatically.)
->Note: There may be a `java.nio.file.FileSystemException` thrown when running the command after switching versions. To fix it, either restart your IDE (as your IDE is probably locking a file) or use a tool like LockHunter to unlock the linked file(s). (Generally it is a lib file under `common\build\lib`, `forge\build\lib`, or `fabric\build\lib`). \
-> If anyone knows how to solve this issue please let us know here: \
-> https://gitlab.com/jeseibel/distant-horizons/-/issues/233
-
+If running in an IDE, to ensure the IDE noticed the version change, run any gradle command to refresh gradle.\
+In IntelliJ, you will also need to do a gradle sync if it didn't happen automatically.
@@ -130,21 +134,20 @@ From the File Explorer:
2. Download the core from https://gitlab.com/jeseibel/distant-horizons-core and extract into a folder called `coreSubProjects`
3. Open a terminal emulator in the project folder (On Windows you can type `cmd` in the title bar)
4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows)
-5. Merge the jars wih `./gradlew mergeJars`
+5. Merge the jars with `./gradlew mergeJars`
6. The compiled jar file will be in the folder `Merged`
From the command line:
1. `git clone --recurse-submodules https://gitlab.com/jeseibel/distant-horizons.git`
-2. `cd minecraft-lod-mod`
+2. `cd distant-horizons`
3. `./gradlew assemble`
4. `./gradlew mergeJars`
5. The compiled jar file will be in the folder `Merged`
Run tests with: `./gradlew test`
->Note: You can add the arg: `-PmcVer=?` to tell gradle to build a selected MC version instead of having to modify the `gradle.properties` file. \
-> Example: `./gradlew assemble -PmcVer=1.18.2`
-
+>Note: You can add the argument `-PmcVer=?` to tell gradle to build a selected MC version instead of having to modify the `gradle.properties` file.\
+> For example: `./gradlew assemble -PmcVer=1.18.2`
@@ -154,7 +157,6 @@ Run tests with: `./gradlew test`
You can also locally compile the DH jars without a Java environment by using Docker. Where `` is the version of Minecraft to compile for (ie `1.20.1`), or the keyword `all`. See [Versions](#minecraft-and-library-versions) for a list of all supported values.
-
## Other commands
@@ -163,6 +165,7 @@ You can also locally compile the DH jars without a Java environment by using Doc
`./gradlew clean` to delete any compiled code.
+
## Note to self
@@ -170,7 +173,7 @@ The Minecraft source code is NOT added to your workspace in an editable way. Min
Source code uses Mojang mappings & [Parchment](https://parchmentmc.org/) mappings.
-To generate the source code run `./gradlew genSources`\
+To generate the source code run `./gradlew genSources`
If your IDE fails to auto-detect the source jars when browsing Minecraft classes; manually select the JAR file ending with -sources.jar when prompted by your IDE.
(In IntelliJ it's at the top where it says "choose sources" when browsing a Minecraft class)
@@ -178,12 +181,12 @@ If your IDE fails to auto-detect the source jars when browsing Minecraft classes
## Other Useful commands
-Run the standalone jar: `./gradlew run`\
-Build the standalone jar: `./gradlew core:build`\
-Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build`\
-Only build Forge: `./gradlew fabric:assemble` or `./gradlew forge:build`\
-Run the Fabric client (for debugging): `./gradlew fabric:runClient`\
-Run the Forge client (for debugging): `./gradlew forge:runClient`
+Run the standalone jar: `./gradlew run`
+Build the standalone jar: `./gradlew core:build`
+Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build`
+Only build Forge: `./gradlew forge:assemble` or `./gradlew forge:build`
+Run the Fabric client (for debugging): `./gradlew fabric:runClient`
+Run the Forge client (for debugging): `./gradlew forge:runClient`
To build all versions: `./buildAll` (all builds will end up in the `Merged` folder)
@@ -197,7 +200,7 @@ https://github.com/PacifistMC/Forgix
LZ4 for Java (data compression)\
https://github.com/lz4/lz4-java
-NightConfig for Json & Toml (config handling)\
+NightConfig for JSON & TOML (config handling)\
https://github.com/TheElectronWill/night-config
SVG Salamander for SVG support (not being used atm)\
diff --git a/build.gradle b/build.gradle
index ddef8baec..fb9650a7d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,77 +1,52 @@
plugins {
id "java"
- // Plugin to handle dependencies
- id "com.github.johnrengelman.shadow" version '7.1.2' apply false
+ // Plugin to put dependencies inside our final jar
+ id "com.github.johnrengelman.shadow" version '8.1.1' apply false
// Plugin to create merged jars
- id "io.github.pacifistmc.forgix" version "1.2.6"
+ id "io.github.pacifistmc.forgix" version "1.2.9"
// Manifold preprocessor
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
- // Provides mc libraries to core
-// id "org.spongepowered.gradle.vanilla" version '0.2.1-SNAPSHOT' apply false
-
// Architectury is used here only as a replacement for forge's own loom
- id "dev.architectury.loom" version "1.3.+" apply false
+ id "dev.architectury.loom" version "1.6-SNAPSHOT" apply false
}
+
/**
* Creates the list of preprocessors to use.
*
* @param mcVers array of all MC versions
* @param mcIndex array index of the currently active MC version
*/
-def writeBuildGradlePredefine(List mcVers, int mcIndex) {
- ArrayList redefineList = new ArrayList()
-
- for (int i = 0; i < mcVers.size(); i++) {
- String mcStr = mcVers[i].replace(".", "_")
-
- if (mcIndex < i) {
- // exclusive before
- // FIXME doesn't function correctly for 1.16.5 (IE the first item in the list)
- redefineList.add("PRE_MC_" + mcStr)
- }
- if (mcIndex <= i) {
- // inclusive before
- redefineList.add("PRE_AND_MC_" + mcStr)
- }
-
- if (mcIndex == i) {
- // exact
- redefineList.add("MC_" + mcStr)
- }
-
- if (mcIndex > i) {
- // inclusive after
- redefineList.add("POST_AND_MC_" + mcStr)
- }
- if (mcIndex >= i) {
- // exclusive after
- redefineList.add("POST_MC_" + mcStr)
- }
- }
-
+def writeBuildGradlePredefine(List mcVers, int mcIndex)
+{
// Build the list of preprocessors to use
- StringBuilder sb = new StringBuilder()
+ StringBuilder sb = new StringBuilder();
- sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n")
+ sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n");
+
+
+ for (int i = 0; i < mcVers.size(); i++)
+ {
+ String verStr = mcVers[i].replace(".", "_");
+ sb.append("MC_" + verStr + "=" + i.toString() + "\n");
+
+ if (mcIndex == i)
+ sb.append("MC_VER=" + i.toString() + "\n");
+ }
+
// Check if this is a development build
- if (mod_version.toLowerCase().contains("dev")) {
+ if (mod_version.toLowerCase().contains("dev"))
+ {
// WARNING: only use this for logging, we don't want to have confusion
// when a method doesn't work correctly in the release build.
- sb.append("DEV_BUILD")
- sb.append("=\n")
+ sb.append("DEV_BUILD=\n");
}
- // Build the MC version preprocessors
- for (String redefinedVersion : redefineList) {
- sb.append(redefinedVersion)
- sb.append("=\n")
- }
new File(projectDir, "build.properties").text = sb.toString()
}
@@ -79,7 +54,7 @@ def writeBuildGradlePredefine(List mcVers, int mcIndex) {
// Transfers the values set in settings.gradle to the rest of the project
project.gradle.ext.getProperties().each { prop ->
rootProject.ext.set(prop.key, prop.value)
-// println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
+ //println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
}
// Sets up manifold stuff
writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
@@ -98,6 +73,12 @@ forgix {
forge {
jarLocation = "build/libs/DistantHorizons-forge-${rootProject.versionStr}.jar"
}
+
+ if (findProject(":neoforge"))
+ custom {
+ projectName = "neoforge"
+ jarLocation = "build/libs/DistantHorizons-neoforge-${rootProject.versionStr}.jar"
+ }
if (findProject(":fabric"))
fabric {
@@ -123,20 +104,21 @@ subprojects { p ->
apply plugin: "com.github.johnrengelman.shadow"
if (isMinecraftSubProject)
apply plugin: "systems.manifold.manifold-gradle-plugin"
- if (p == project(":core"))
- apply plugin: "application"
-// apply plugin: "org.spongepowered.gradle.vanilla" // Provides minecraft libraries
-
+
// Apply forge's loom
- if (findProject(":forge") && p == project(":forge"))
+ if ((findProject(":forge") && p == project(":forge")) ||
+ (findProject(":neoforge") && p == project(":neoforge"))
+ )
+ {
apply plugin: "dev.architectury.loom"
+ }
// Set the manifold version (may not be required tough)
manifold {
manifoldVersion = rootProject.manifold_version
}
-
+
// set up custom configurations (configurations are a way to handle dependencies)
configurations {
@@ -148,8 +130,8 @@ subprojects { p ->
// Configuration fpr core & api
coreProjects
shadowMe.extendsFrom(coreProjects)
-
-
+
+
// FIXME this additional configuration is necessary because forge
// needs forgeRuntimeLibrary, although adding it to shadowMe
// causes runtime issues where the libraries aren't properly added
@@ -158,18 +140,24 @@ subprojects { p ->
implementation.extendsFrom(forgeShadowMe)
shadowMe.extendsFrom(forgeShadowMe)
forgeRuntimeLibrary.extendsFrom(forgeShadowMe)
-
-
+
+
if (isMinecraftSubProject && p != project(":common")) {
// Shadow common
common
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
- developmentForge.extendsFrom common
+ if (findProject(":forge"))
+ developmentForge.extendsFrom common
+ if (findProject(":neoforge"))
+ developmentNeoForge.extendsFrom common
compileClasspath.extendsFrom coreProjects
runtimeClasspath.extendsFrom coreProjects
- developmentForge.extendsFrom coreProjects
+ if (findProject(":forge"))
+ developmentForge.extendsFrom coreProjects
+ if (findProject(":neoforge"))
+ developmentNeoForge.extendsFrom coreProjects
if (findProject(":fabricLike") && p != project(":fabricLike")) {
// Shadow fabricLike
@@ -177,26 +165,16 @@ subprojects { p ->
shadowFabricLike
compileClasspath.extendsFrom fabricLike
runtimeClasspath.extendsFrom fabricLike
- developmentForge.extendsFrom fabricLike
}
}
}
- // Let the application plugin know where the main class is
- // (This will point to a non-existent class in all sub-projects except "Core")
- if (p == project(":core")) {
- application {
- mainClass.set("com.seibel.distanthorizons.core.jar.JarMain")
- }
- }
-
dependencies {
//=====================//
// shared dependencies //
//=====================//
-
// Manifold
if (isMinecraftSubProject) {
annotationProcessor("systems.manifold:manifold-preprocessor:${rootProject.manifold_version}")
@@ -209,16 +187,26 @@ subprojects { p ->
implementation("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
// JOML
- implementation("org.joml:joml:${rootProject.joml_version}")
-
+ if (project.hasProperty("embed_joml") && embed_joml == "true")
+ forgeShadowMe("org.joml:joml:${rootProject.joml_version}")
+ else
+ implementation("org.joml:joml:${rootProject.joml_version}")
+
// JUnit tests
implementation("org.junit.jupiter:junit-jupiter:5.8.2")
implementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
implementation("junit:junit:4.13")
+
+ // FastUtil
+ // Note: MC 1.16 uses 8.2.1, and versions after use 8.5.12
+ // We cannot relocate this library since we call some MC classes that reference it
+ implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}")
+
// Compression
- forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}")
-
+ forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4
+ forgeShadowMe("org.tukaani:xz:${rootProject.xz_version}") // LZMA
+
// Sqlite Database
forgeShadowMe("org.xerial:sqlite-jdbc:${rootProject.sqlite_jdbc_version}")
@@ -289,13 +277,13 @@ subprojects { p ->
if (isMinecraftSubProject && p != project(":common")) {
configurations.push(project.configurations.shadowCommon) // Shadow the common subproject
relocate "com.seibel.distanthorizons.common", "loaderCommon.${p.name}.com.seibel.distanthorizons.common" // Move the loader files to a different location
-
+
if (findProject(":fabricLike") && p != project(":fabricLike")) {
configurations.push(project.configurations.shadowFabricLike) // Shadow the fabricLike subproject
relocate "com.seibel.distanthorizons.fabriclike", "loaderCommon.${p.name}.com.seibel.distanthorizons.fabriclike" // Move the loader files to a different location
}
}
- def librariesLocation = "distanthorizons.libraries"
+ def librariesLocation = "DistantHorizons.libraries"
// LWJGL
// Only ever shadow the dependencies we use otherwise some stuff would break when running on an external client
@@ -307,6 +295,10 @@ subprojects { p ->
// Sqlite Database
//At the moment, there is a bug in this library which doesnt allow it to be relocated
// relocate "org.sqlite", "${librariesLocation}.sqlite"
+
+ // JOML
+ if (project.hasProperty("embed_joml") && embed_joml == "true")
+ relocate "org.joml", "${librariesLocation}.joml"
// NightConfig (includes Toml & Json)
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
@@ -326,22 +318,23 @@ subprojects { p ->
// Put stuff from gradle.properties into the mod info
processResources {
def resourceTargets = [ // Location of where to inject the properties
- // Holds info like git commit
- // TODO: For some reason this script doesnt work with the core project
- "build_info.json",
+ // Holds info like git commit
+ // TODO: For some reason this script doesnt work with the core project
+ "build_info.json",
- // Properties for each of the loaders
- "fabric.mod.json",
- "quilt.mod.json",
- "META-INF/mods.toml",
+ // Properties for each of the loaders
+ "fabric.mod.json",
+ "quilt.mod.json",
+ "META-INF/mods.toml",
+ "META-INF/neoforge.mods.toml",
- // The mixins for each of the loaders
- "DistantHorizons."+ p.name +".fabricLike.mixins.json"
+ // The mixins for each of the loaders
+ "DistantHorizons."+ p.name +".fabricLike.mixins.json"
]
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
// Fix forge version numbering system as it is weird
- // For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"] which make more sense
+ // For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"]
def compatible_forgemc_versions = "${compatible_minecraft_versions}".replaceAll("\"", "").replaceAll("]", ",)")
// println compatible_forgemc_versions
@@ -354,9 +347,9 @@ subprojects { p ->
quilt_contributors.push("\"${dev.strip()}\": \"Developer\"")
}
quilt_contributors.reverse()
-// println quilt_contributors.join(", ")
+ //println quilt_contributors.join(", ")
- // TODOI: Find something we can use so we can basically re-map only when the jar is shadowed and relocated
+ // TODO: Find something we can use so we can basically re-map only when the jar is shadowed and relocated
// println p.tasks.findByName('shadowJar')
@@ -371,6 +364,7 @@ subprojects { p ->
println "Git or Git project not found"
}
+ // The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties
def replaceProperties = [
version : mod_version,
mod_name : mod_readable_name,
@@ -394,14 +388,14 @@ subprojects { p ->
fabric_incompatibility_list : fabric_incompatibility_list,
fabric_recommend_list : fabric_recommend_list,
]
- // The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties
-
+
+ // replace any properties in the sub-projects with the values defined here
inputs.properties replaceProperties
replaceProperties.put "project", project
filesMatching(resourceTargets) {
expand replaceProperties
}
-
+
intoTargets.each { target ->
if (file(target).exists()) {
copy {
@@ -423,7 +417,7 @@ subprojects { p ->
//// include "${accessWidenerVersion}.distanthorizons.accesswidener"
// Jank solution to remove all unused accesswideners
- // The line above would work..., except forge requires the original accesswidener file, meaning we require this jank solution to keep it
+ // The line above would work..., except that (neo)forge (well, mainly architectury) requires the original accesswidener file, meaning we require this jank solution to keep it
exclude { file ->
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${accessWidenerVersion}.distanthorizons.accesswidener") {
return true
@@ -437,9 +431,11 @@ subprojects { p ->
jar {
from "LICENSE.txt"
manifest {
- attributes 'Implementation-Title': rootProject.mod_name,
- 'Implementation-Version': rootProject.mod_version,
- 'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain' // When changing the main of the jar change this line
+ attributes(
+ 'Implementation-Title': rootProject.mod_name,
+ 'Implementation-Version': rootProject.mod_version,
+ 'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain' // When changing the main of the jar change this line
+ )
}
}
@@ -459,17 +455,10 @@ subprojects { p ->
}
}
*/
-
- // Run mergeJars when running build
- // TODO: Fix later
-// if (isMinecraftSubProject) {
-// build.finalizedBy(mergeJars)
-// assemble.finalizedBy(mergeJars)
-// }
}
allprojects { p ->
- // Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge")"
+ // Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")"
// Useful later on so we dont have duplicated code
def isMinecraftSubProject = p != project(":core") && p != project(":api")
@@ -484,8 +473,21 @@ allprojects { p ->
// this is the text that appears at the top of the overview (home) page
// and is used when bookmarking a page
javadoc.title = rootProject.mod_name + "-" + project.name
-
-
+
+ // Some annotations arent "technically" part of the official java standard,
+ // so we define it ourself here
+ javadoc {
+ configure( options ) {
+ tags(
+ 'todo:X"',
+ 'apiNote:a:API Note:',
+ 'implSpec:a:Implementation Requirements:',
+ 'implNote:a:Implementation Note:'
+ )
+ }
+ }
+
+
repositories {
// The central repo
mavenCentral()
@@ -522,15 +524,17 @@ allprojects { p ->
}
}
- // Required for ModMenu
- maven { url "https://maven.terraformersmc.com/" }
-
- // Required for Mixins & VanillaGradle
+ // VanillaGradle and Mixins in common
maven { url "https://repo.spongepowered.org/maven/" }
- // Required for Canvas (mod)
+ // Canvas mod
maven { url "https://maven.vram.io/" }
+ // ModMenu mod
+ maven { url "https://maven.terraformersmc.com/" }
+ // neoforge
+ maven { url "https://maven.neoforged.net/releases/" }
+
// These 3 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
flatDir {
dirs "${rootDir}/mods/fabric"
@@ -550,6 +554,7 @@ allprojects { p ->
includeGroup "forge-mod"
}
}
+ // TODO: If neoforged is ever needed, should we use that, or call it a forge mod?
}
// Adds some dependencies that are in vanilla but not in core
@@ -586,7 +591,6 @@ allprojects { p ->
implementation("com.google.code.findbugs:jsr305:3.0.2")
implementation("com.google.common:google-collect:0.5")
implementation("com.google.guava:guava:31.1-jre")
- implementation("it.unimi.dsi:fastutil:8.5.11")
}
}
diff --git a/buildSrc/src/main/java/AWToAT.java b/buildSrc/src/main/java/AWToAT.java
new file mode 100644
index 000000000..2f851b264
--- /dev/null
+++ b/buildSrc/src/main/java/AWToAT.java
@@ -0,0 +1,239 @@
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class AWToAT {
+ private static final Map ACCESS_POINT_MAP = new HashMap<>();
+
+ static {
+ ACCESS_POINT_MAP.put("accessible", "public");
+ ACCESS_POINT_MAP.put("extendable", "public-f");
+ ACCESS_POINT_MAP.put("mutable", "public-f");
+ }
+
+ public String minecraftVersion;
+
+ public File remap(File file, String minecraftVersion) {
+ this.minecraftVersion = minecraftVersion.replace("_", ".");
+ File atFile = createATFile(file);
+ processFile(file, atFile);
+ return atFile;
+ }
+
+ private File createATFile(File file) {
+ File metaInf = new File(file.getParentFile(), "META-INF");
+ if (!metaInf.exists() && !metaInf.mkdir()) throw new RuntimeException("Error creating META-INF folder");
+ File atFile = new File(metaInf, "accesstransformer.cfg");
+ try {
+ atFile.createNewFile();
+ } catch (IOException e) {
+ throw new RuntimeException("Error creating new file", e);
+ }
+ return atFile;
+ }
+
+ private void processFile(File file, File atFile) {
+ /* Validates if we need to recreate the Access Transformer file if it's out of date */
+ // Get the hash of the file
+ String fileHash = getFileHash(file);
+ try (Scanner atScanner = new Scanner(atFile)) {
+ // Check if the AT file is up-to-date by comparing the hash of the file with the hash stored in the AT file
+ boolean hashFound = false;
+ while (atScanner.hasNextLine()) {
+ String line = atScanner.nextLine();
+ if (hashCheck(line, fileHash)) {
+ hashFound = true;
+ }
+ }
+
+ // If the AT file is up-to-date, print a message and return
+ if (hashFound) {
+ System.out.println("Access Transformer file is already up to date.");
+ return;
+ }
+ } catch (FileNotFoundException ignored) {
+ // If the AT file does not exist, continue
+ }
+
+ /* Creates the Access Transformer file */
+ // Opens a scanner for reading the Access Widener file and a writer for writing to the Access Transformer file
+ try (Scanner scanner = new Scanner(file); FileWriter writer = new FileWriter(atFile)) {
+ // Create an ExecutorService with a fixed thread pool size equal to the number of available processors
+ ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
+ // List to hold Future objects representing results of computation
+ List> futures = new ArrayList<>();
+
+ // Write the hash of the file to the AT file
+ writer.write("#DH_MAPPING_HASH:" + fileHash + "\n");
+
+ // Read each line from the file
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine();
+ // Skip lines starting with "accessWidener", "#" or blank lines
+ if (line.startsWith("accessWidener") || line.startsWith("#") || line.isBlank()) continue;
+
+ // Submit the line to the executor service for processing
+ // The processing is done by the processLine method
+ futures.add(executor.submit(() -> processLine(line.split(" "))));
+ }
+
+ // Write the results to the output file
+ // The results are obtained by calling the get method on each Future
+ for (Future future : futures) {
+ writer.write(future.get());
+ }
+
+ // Shutdown the executor service to free up resources
+ executor.shutdown();
+ } catch (Exception e) {
+ throw new RuntimeException("Error reading or writing to file", e);
+ }
+ }
+
+ private String processLine(String[] fields) {
+ // fields[0] = access point like "accessible", "extendable", "mutable"
+ // fields[1] = type like "field", "method", "class"
+ // fields[2] = class name
+ // fields[3] = field/method name
+ // fields[4] = field/method descriptor
+
+ try {
+ // Store the original field/method name
+ String originalName = "";
+
+ // If there is a class name, replace the slashes with dots in the package name
+ if (fields.length > 2) fields[2] = fields[2].replace("/", ".");
+
+ // If there is a field/method name, store the original name and remap it to SRG
+ if (fields.length > 3) {
+ originalName = fields[3];
+ fields[3] = remapToSRG(fields[2], fields[3]);
+ }
+
+ StringBuilder line = new StringBuilder(ACCESS_POINT_MAP.getOrDefault(fields[0], "public")).append(" ");
+ switch (fields[1]) {
+ case "field":
+ line.append(fields[2]).append(" ").append(fields[3]).append(" #").append(originalName);
+ // It'll be like: access-point class-name field-name-SRG # field-name-Mojmap
+ // Eg: public net.minecraft.client.Minecraft f_90981_ # instance
+ break;
+ case "method":
+ line.append(fields[2]).append(" ").append(fields[3]).append(fields[4]).append(" #").append(originalName);
+ // It'll be like: access-point class-name method-name-SRG method-descriptor # method-name-Mojmap
+ // Eg: public net.minecraft.client.Minecraft m_172797_()Lnet/minecraft/client/Minecraft; # getInstance
+ break;
+ default:
+ line.append(fields[2]);
+ // It'll be like: access-point class-name
+ // Eg: public net.minecraft.client.Minecraft
+ break;
+ }
+ line.append("\n");
+ return line.toString();
+ } catch (Exception e) {
+ throw new RuntimeException("Error processing line", e);
+ }
+ }
+
+ private boolean hashCheck(String line, String fileHash) {
+ if (line.startsWith("#DH_MAPPING_HASH:")) {
+ String hash = line.substring(17);
+ return hash.equals(fileHash);
+ }
+ return false;
+ }
+
+ public String getFileHash(File file) {
+ try {
+ MessageDigest shaDigest = MessageDigest.getInstance("SHA-256");
+ try (InputStream fis = new FileInputStream(file)) {
+ byte[] byteArray = new byte[1024];
+ int bytesCount;
+
+ // Read file data and update in message digest
+ while ((bytesCount = fis.read(byteArray)) != -1) {
+ shaDigest.update(byteArray, 0, bytesCount);
+ }
+ }
+
+ byte[] bytes = shaDigest.digest();
+
+ // Convert byte array into signum representation
+ StringBuilder sb = new StringBuilder();
+ for (byte aByte : bytes) {
+ sb.append(Integer.toString((aByte & 0xff) + 0x100, 16).substring(1));
+ }
+
+ // Return complete hash
+ return sb.toString();
+ } catch (NoSuchAlgorithmException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+
+ // WARNING: BELOW LIES HIGHLY CURSED CODE AND MIGHT EVEN BE ILLEGAL
+
+
+
+
+ // Flag to track if there was an error in the GET request
+ boolean error = false;
+
+ /**
+ * This method returns a field or method name from Mojang mappings as SRG mappings.
+ * It makes a GET request to the Linkie API to fetch the SRG name.
+ *
+ * @param clazz The class name
+ * @param name The field or method name
+ * @return The SRG name
+ * @throws Exception If there is an error in the GET request or the SRG name is not found in the response
+ */
+ private String remapToSRG(String clazz, String name) throws Exception {
+ // Encode the class and field/method name to be used in the URL
+ String query = URLEncoder.encode(clazz + "." + name, StandardCharsets.UTF_8);
+ // Construct the URL for the GET request
+ String urlString = "https://linkieapi.shedaniel.me/api/search?namespace=mojang&query=" + query + "&version=" + this.minecraftVersion + "&limit=1&allowClasses=false&allowFields=true&allowMethods=true&translate=mojang_srg";
+ URL url = new URI(urlString).toURL();
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("GET");
+ int responseCode = conn.getResponseCode();
+ if (responseCode == HttpURLConnection.HTTP_OK) {
+ BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+ String inputLine;
+ StringBuilder content = new StringBuilder();
+ // Read the response line by line
+ while ((inputLine = in.readLine()) != null) {
+ content.append(inputLine);
+ }
+ in.close();
+ conn.disconnect();
+ // Regex to find the SRG name in the response
+ Pattern pattern = Pattern.compile("\"l\"\\s*:\\s*\\{[^}]*\"i\"\\s*:\\s*\"([^\"]*)\"");
+ Matcher matcher = pattern.matcher(content.toString());
+ if (matcher.find()) return matcher.group(1);
+ else throw new Exception("Couldn't find the SRG mapping for name: " + name + "\nCould not find 'i' in 'l' object in the response"); // `i` is the SRG name which is stored in the `l` JSON object
+ } else {
+ if (error) {
+ // If there was an error in the GET request, and we already tried again, throw an exception
+ throw new Exception("The GET request failed");
+ }
+ // If there was an error in the GET request, wait 2.5 seconds and try again as we probably got rate limited
+ error = true;
+ Thread.sleep(2500);
+ return remapToSRG(clazz, name);
+ }
+ }
+}
\ No newline at end of file
diff --git a/common/build.gradle b/common/build.gradle
index b61221fda..72e64e14d 100644
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -1,3 +1,13 @@
+
+// temporary fix for broken spongepowered version
+buildscript {
+ configurations.configureEach {
+ resolutionStrategy {
+ force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82'
+ }
+ }
+}
+
plugins {
id "org.spongepowered.gradle.vanilla" version "0.2.1-SNAPSHOT"
}
@@ -8,10 +18,6 @@ minecraft {
}
dependencies {
- // We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
- // Do NOT use other classes from fabric loader
-// modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
-
// So mixins can be written in common
compileOnly group:'org.spongepowered', name:'mixin', version:'0.8.5'
}
@@ -30,3 +36,4 @@ publishing {
// Add repositories to publish to here.
}
}
+
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java b/common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java
new file mode 100644
index 000000000..746ced882
--- /dev/null
+++ b/common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java
@@ -0,0 +1,182 @@
+package com.seibel.distanthorizons.common;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
+import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
+import com.seibel.distanthorizons.common.wrappers.DependencySetup;
+import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
+import com.seibel.distanthorizons.core.api.internal.SharedApi;
+import com.seibel.distanthorizons.core.config.Config;
+import com.seibel.distanthorizons.core.config.ConfigBase;
+import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
+import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.jar.ModJarInfo;
+import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
+import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor;
+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 org.apache.logging.log4j.Logger;
+
+import java.lang.invoke.MethodHandles;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Base for all mod loader initializers
+ * and handles most setup.
+ */
+public abstract class AbstractModInitializer
+{
+ protected static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
+
+ private CommandDispatcher commandDispatcher;
+
+
+
+ //==================//
+ // abstract methods //
+ //==================//
+
+ protected abstract void createInitialBindings();
+ protected abstract IEventProxy createClientProxy();
+ protected abstract IEventProxy createServerProxy(boolean isDedicated);
+ protected abstract void initializeModCompat();
+
+ protected abstract void subscribeRegisterCommandsEvent(Consumer> eventHandler);
+
+ protected abstract void subscribeClientStartedEvent(Runnable eventHandler);
+ protected abstract void subscribeServerStartingEvent(Consumer eventHandler);
+ protected abstract void runDelayedSetup();
+
+
+
+ //===================//
+ // initialize events //
+ //===================//
+
+ public void onInitializeClient()
+ {
+ DependencySetup.createClientBindings();
+
+ LOGGER.info("Initializing " + ModInfo.READABLE_NAME);
+ ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
+
+ this.startup();
+ this.printModInfo(true);
+
+ this.createClientProxy().registerEvents();
+ this.createServerProxy(false).registerEvents();
+
+ this.initializeModCompat();
+
+ LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
+ ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
+
+ // Client uses config for auto-updater, so it's initialized here instead of post-init stage
+ this.initConfig();
+
+ this.subscribeClientStartedEvent(this::postInit);
+ }
+
+ public void onInitializeServer()
+ {
+ DependencySetup.createServerBindings();
+
+ LOGGER.info("Initializing " + ModInfo.READABLE_NAME);
+ ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
+
+ this.startup();
+ this.printModInfo(false);
+
+ // This prevents returning uninitialized Config values,
+ // resulting from a circular reference mid-initialization in a static class
+ // noinspection ResultOfMethodCallIgnored
+ ThreadPresetConfigEventHandler.INSTANCE.toString();
+
+ this.createServerProxy(true).registerEvents();
+
+ LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
+ ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
+
+ this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandDispatcher = dispatcher; });
+
+ this.subscribeServerStartingEvent(server ->
+ {
+ MinecraftDedicatedServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server;
+
+ this.initConfig();
+ this.postInit();
+ this.initCommands();
+
+ LOGGER.info("Dedicated server initialized at " + server.getServerDirectory());
+ });
+ }
+
+
+
+ //===========================//
+ // inner initializer methods //
+ //===========================//
+
+ private void startup()
+ {
+ DependencySetup.createSharedBindings();
+ SharedApi.init();
+ this.createInitialBindings();
+ }
+
+ private void printModInfo(boolean printGitInfo)
+ {
+ LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
+
+ if (printGitInfo)
+ {
+ // Useful for dev builds
+ LOGGER.info("DH Branch: " + ModJarInfo.Git_Branch);
+ LOGGER.info("DH Commit: " + ModJarInfo.Git_Commit);
+ LOGGER.info("DH Jar Build Source: " + ModJarInfo.Build_Source);
+ }
+ }
+
+ protected void tryCreateModCompatAccessor(String modId, Class super T> accessorClass, Supplier accessorConstructor)
+ {
+ IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
+ if (modChecker.isModLoaded(modId))
+ {
+ //noinspection unchecked
+ ModAccessorInjector.INSTANCE.bind((Class extends IModAccessor>) accessorClass, accessorConstructor.get());
+ }
+ }
+
+ private void initConfig()
+ {
+ ConfigBase.INSTANCE = new ConfigBase(ModInfo.ID, ModInfo.NAME, Config.class, 2);
+ Config.completeDelayedSetup();
+ }
+
+ private void postInit()
+ {
+ LOGGER.info("Post-Initializing Mod");
+ this.runDelayedSetup();
+ LOGGER.info("Mod Post-Initialized");
+ }
+
+ private void initCommands() { /* currently unimplemented */ }
+
+
+
+ //================//
+ // helper classes //
+ //================//
+
+ public interface IEventProxy
+ {
+ void registerEvents();
+ }
+
+}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/LodCommonMain.java b/common/src/main/java/com/seibel/distanthorizons/common/LodCommonMain.java
deleted file mode 100644
index 922e519e4..000000000
--- a/common/src/main/java/com/seibel/distanthorizons/common/LodCommonMain.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * This file is part of the Distant Horizons mod
- * licensed under the GNU LGPL v3 License.
- *
- * Copyright (C) 2020-2023 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.common;
-
-import com.seibel.distanthorizons.common.forge.LodForgeMethodCaller;
-import com.seibel.distanthorizons.common.wrappers.DependencySetup;
-import com.seibel.distanthorizons.coreapi.ModInfo;
-import com.seibel.distanthorizons.core.api.internal.SharedApi;
-import com.seibel.distanthorizons.core.config.Config;
-import com.seibel.distanthorizons.core.config.ConfigBase;
-
-/**
- * This is the common main class
- *
- * @author Ran
- */
-public class LodCommonMain
-{
- public static boolean forge = false;
- public static LodForgeMethodCaller forgeMethodCaller;
-
-
-
- public static void startup(LodForgeMethodCaller forgeMethodCaller)
- {
- if (forgeMethodCaller != null)
- {
- LodCommonMain.forge = true;
- LodCommonMain.forgeMethodCaller = forgeMethodCaller;
- }
-
- DependencySetup.createSharedBindings();
- SharedApi.init();
-// if (!serverSided) {
-// new NetworkReceiver().register_Client();
-// } else {
-// new NetworkReceiver().register_Server();
-// }
- }
-
- public static void initConfig()
- {
- ConfigBase.INSTANCE = new ConfigBase(ModInfo.ID, ModInfo.NAME, Config.class, 2);
- Config.completeDelayedSetup();
- }
-
-}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/forge/LodForgeMethodCaller.java b/common/src/main/java/com/seibel/distanthorizons/common/forge/LodForgeMethodCaller.java
deleted file mode 100644
index 0d9b8da4a..000000000
--- a/common/src/main/java/com/seibel/distanthorizons/common/forge/LodForgeMethodCaller.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * This file is part of the Distant Horizons mod
- * licensed under the GNU LGPL v3 License.
- *
- * Copyright (C) 2020-2023 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.common.forge;
-
-import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
-import net.minecraft.client.renderer.block.model.BakedQuad;
-import net.minecraft.core.Direction;
-#if POST_MC_1_19_2
-import net.minecraft.util.RandomSource;
-#endif
-import net.minecraft.world.level.ColorResolver;
-import net.minecraft.world.level.biome.Biome;
-import net.minecraft.world.level.block.Block;
-import net.minecraft.world.level.block.state.BlockState;
-
-import java.util.List;
-import java.util.Random;
-
-/**
- * used for calling methods that forge modified
- * (forge modifies vanilla methods for some reason)
- *
- * @author Ran
- */
-public interface LodForgeMethodCaller
-{
- #if PRE_MC_1_19_2
- List getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, Random random); // FIXME: For 1.19
- #else
- List getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, RandomSource random); // FIXME: For 1.19
- #endif
-
- int colorResolverGetColor(ColorResolver resolver, Biome biome, double x, double z);
-
-}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/rendering/SeamlessOverdraw.java b/common/src/main/java/com/seibel/distanthorizons/common/rendering/SeamlessOverdraw.java
deleted file mode 100644
index 264dc636a..000000000
--- a/common/src/main/java/com/seibel/distanthorizons/common/rendering/SeamlessOverdraw.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * This file is part of the Distant Horizons mod
- * licensed under the GNU LGPL v3 License.
- *
- * Copyright (C) 2020-2023 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.common.rendering;
-
-#if PRE_MC_1_19_4
-
-import com.mojang.math.Matrix4f;
-#else
-
-import org.joml.Matrix4f;
-#endif
-import com.seibel.distanthorizons.core.config.Config;
-import com.seibel.distanthorizons.core.util.RenderUtil;
-import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
-import org.lwjgl.opengl.GL15;
-
-import java.nio.FloatBuffer;
-
-public class SeamlessOverdraw
-{
- /**
- * Proof-of-concept experimental option, not intended for normal use.
- * (Poorly) replaces Minecraft's far clip plane so it lines up with DH's near clip plane.
- */
- public static float[] overwriteMinecraftNearFarClipPlanes(Matrix4f minecraftProjectionMatrix, float previousPartialTicks)
- {
- float[] matrixFloatArray;
-
- #if PRE_MC_1_19_4
- FloatBuffer matrixFloatBuffer = FloatBuffer.allocate(16);
- minecraftProjectionMatrix.store(matrixFloatBuffer);
- matrixFloatArray = matrixFloatBuffer.array();
- #else
- // Passing float buffers in caused native code crashes, so we are passing in a float array instead
- matrixFloatArray = new float[16];
- minecraftProjectionMatrix.get(matrixFloatArray);
- #endif
-
- return overwriteMinecraftNearFarClipPlanes(matrixFloatArray, previousPartialTicks);
- }
-
- public static float[] overwriteMinecraftNearFarClipPlanes(Mat4f minecraftProjectionMatrix, float previousPartialTicks)
- {
- return overwriteMinecraftNearFarClipPlanes(minecraftProjectionMatrix.getValuesAsArray(), previousPartialTicks);
- }
-
- private static float[] overwriteMinecraftNearFarClipPlanes(float[] projectionMatrixFloatArray, float previousPartialTicks)
- {
- float dhFarClipPlane = RenderUtil.getNearClipPlaneDistanceInBlocks(previousPartialTicks);
-
- // works for fabric, bad not for forge for some reason :/
- float farClip = dhFarClipPlane * 5.1f; // magic number found via trial and error, James has no idea what it represents, except that it makes the seam between DH and vanilla rendering pretty close
- float nearClip = 0.5f; // this causes issues with some vanilla rendering, specifically the wireframe around selected blocks is slightly off. Unfortunately the ratio between the near and far clip plane can't be easily modified without completely screwing up the rendering.
-
- // these may be the wrong index locations in any version of MC other than 1.18.2
- projectionMatrixFloatArray[10] = -((farClip + nearClip) / (farClip - nearClip)); // near clip plane
- projectionMatrixFloatArray[11] = -((2 * farClip * nearClip) / (farClip - nearClip)); // far clip plane
-
-
- return projectionMatrixFloatArray;
- }
-
-
-
- //================//
- // helper methods //
- //================//
-
- public static void applyLegacyProjectionMatrix(float[] projectionMatrixFloatArray)
- {
- int glMatrixMode = GL15.glGetInteger(GL15.GL_MATRIX_MODE);
- GL15.glMatrixMode(GL15.GL_PROJECTION);
-
- GL15.glLoadMatrixf(projectionMatrixFloatArray);
-
- GL15.glMatrixMode(glMatrixMode);
- }
-
-}
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 c11e57c77..ebcab8af8 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
@@ -23,12 +23,6 @@ import java.nio.FloatBuffer;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
-#if PRE_MC_1_19_4
-import com.mojang.math.Matrix4f;
-#else
-import org.joml.Matrix4f;
-#endif
-
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
@@ -51,10 +45,31 @@ public class McObjectConverter
{
return y * 4 + x;
}
- /** Taken from Minecraft's com.mojang.math.Matrix4f class from 1.18.2 */
- private static void storeMatrix(Matrix4f matrix, FloatBuffer buffer)
+
+
+ /** 4x4 float matrix converter */
+ @Deprecated
+ public static Mat4f Convert(
+ #if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
+ #else org.joml.Matrix4f #endif
+ mcMatrix)
{
- #if PRE_MC_1_19_4
+ FloatBuffer buffer = FloatBuffer.allocate(16);
+ storeMatrix(mcMatrix, buffer);
+ Mat4f matrix = new Mat4f(buffer);
+ #if 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
+ #else org.joml.Matrix4f #endif
+ matrix,
+ FloatBuffer buffer)
+ {
+ #if 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
@@ -77,18 +92,6 @@ public class McObjectConverter
#endif
}
- /** 4x4 float matrix converter */
- public static Mat4f Convert(Matrix4f mcMatrix)
- {
- FloatBuffer buffer = FloatBuffer.allocate(16);
- storeMatrix(mcMatrix, buffer);
- Mat4f matrix = new Mat4f(buffer);
- #if PRE_MC_1_19_4
- matrix.transpose(); // In 1.19.3 and later, we no longer need to transpose it
- #endif
- return matrix;
- }
-
static final Direction[] directions;
static final EDhDirection[] lodDirections;
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 643a23f25..925ae4adb 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
@@ -59,7 +59,7 @@ public class VersionConstants implements IVersionConstants
@Override
public String getMinecraftVersion()
{
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
return Minecraft.getInstance().getGame().getVersion().getId();
#else
return SharedConstants.getCurrentVersion().getId();
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 6bc8d7907..115243c1d 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
@@ -19,7 +19,11 @@
package com.seibel.distanthorizons.common.wrappers;
+import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper;
+import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper;
import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGenerator;
+import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
+import com.seibel.distanthorizons.api.interfaces.factories.IDhApiWrapperFactory;
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
@@ -28,6 +32,7 @@ import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.core.level.IDhLevel;
import com.seibel.distanthorizons.core.level.IDhServerLevel;
+import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
@@ -35,9 +40,14 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
import net.minecraft.client.multiplayer.ClientLevel;
+#if MC_VER > MC_1_17_1
+import net.minecraft.core.Holder;
+#endif
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;
import java.io.IOException;
@@ -55,6 +65,9 @@ public class WrapperFactory implements IWrapperFactory
+ //==============//
+ // core methods //
+ //==============//
@Override
public AbstractBatchGenerationEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel)
@@ -71,10 +84,21 @@ public class WrapperFactory implements IWrapperFactory
@Override
public IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BiomeWrapper.deserialize(str, levelWrapper); }
+ @Override
+ public IBiomeWrapper getPlainsBiomeWrapper(ILevelWrapper levelWrapper) // TODO is there a way we could get this without the levelWrapper? it isn't necessary but would clean up the code a bit
+ {
+ try
+ {
+ return BiomeWrapper.deserialize(BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING, levelWrapper);
+ }
+ catch (IOException e)
+ {
+ throw new LodUtil.AssertFailureException("Unable to parse plains resource string ["+BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING+"], error:\n " + e.getMessage());
+ }
+ }
@Override
public IBlockStateWrapper deserializeBlockStateWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BlockStateWrapper.deserialize(str, levelWrapper); }
-
@Override
public IBlockStateWrapper getAirBlockStateWrapper() { return BlockStateWrapper.AIR; }
@@ -106,8 +130,7 @@ public class WrapperFactory implements IWrapperFactory
}
}
- // MC 1.16, 1.18, 1.19, 1.20
- #if POST_MC_1_17_1 || MC_1_16_5
+ #if MC_VER <= MC_1_21
else if (objectArray.length == 2)
{
// correct number of parameters from the API
@@ -156,7 +179,7 @@ public class WrapperFactory implements IWrapperFactory
#else
// Intentional compiler error to bring attention to the missing wrapper function.
// If you need to work on an unimplemented version but don't have the ability to implement this yet
- // you can comment it out, but please don't commit it. Someone will have to implement it .
+ // you can comment it out, but please don't commit it. Someone will have to implement it.
// After implementing the new version please read this method's javadocs for instructions
// on what other locations also need to be updated, the DhAPI specifically needs to
@@ -170,25 +193,167 @@ public class WrapperFactory implements IWrapperFactory
*/
private static String createChunkWrapperErrorMessage(Object[] objectArray)
{
- StringBuilder message = new StringBuilder(
- "Chunk wrapper creation failed. \n" +
- "Expected parameters: \n");
+ String[] expectedClassNames;
- // MC 1.16, 1.18, 1.19, 1.20
- #if POST_MC_1_17_1 || MC_1_16_5
- message.append("[" + ChunkAccess.class.getName() + "], \n");
- message.append("[" + ServerLevel.class.getName() + "] or [" + ClientLevel.class.getName() + "]. \n");
+ #if MC_VER <= MC_1_21
+ expectedClassNames = new String[]
+ {
+ ChunkAccess.class.getName(),
+ ServerLevel.class.getName() + "] or [" + ClientLevel.class.getName()
+ };
#else
// See preprocessor comment in createChunkWrapper() for full documentation
not implemented for this version of Minecraft!
#endif
+ return createWrapperErrorMessage("Chunk wrapper", expectedClassNames, objectArray);
+ }
+
+
+
+ //=============//
+ // api methods //
+ //=============//
+
+ // documentation should be in the API interface
+
+ public IDhApiBiomeWrapper getBiomeWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper)
+ {
+ // confirm the API level wrapper is also a Core wrapper
+ if (!(levelWrapper instanceof ILevelWrapper))
+ {
+ throw new ClassCastException("Unable to cast... only DH provided IDhApiLevelWrapper's can be used."); // TODO
+ }
+ ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
+
+
+
+ #if MC_VER < MC_1_20_4
+ if (objectArray.length != 1)
+ {
+ throw new ClassCastException(createBiomeWrapperErrorMessage(objectArray));
+ }
+ #endif
+
+ #if MC_VER < MC_1_18_2
+ if (!(objectArray[0] instanceof Biome))
+ {
+ throw new ClassCastException(createBiomeWrapperErrorMessage(objectArray));
+ }
+
+ Biome biome = (Biome) objectArray[0];
+ return BiomeWrapper.getBiomeWrapper(biome, coreLevelWrapper);
+ #elif MC_VER <= MC_1_21
+ if (!(objectArray[0] instanceof Holder) || !(((Holder>) objectArray[0]).value() instanceof Biome))
+ {
+ throw new ClassCastException(createBiomeWrapperErrorMessage(objectArray));
+ }
+
+ Holder biomeHolder = (Holder) objectArray[0];
+ return BiomeWrapper.getBiomeWrapper(biomeHolder, coreLevelWrapper);
+ #else
+ // See preprocessor comment in createChunkWrapper() for full documentation (not a typo, check createChunkWrapper()'s else statement for full documentation)
+ not implemented for this version of Minecraft!
+ #endif
+ }
+ /**
+ * Note: when this is updated for different MC versions,
+ * make sure you also update the documentation in {@link IDhApiWrapperFactory#getBiomeWrapper}.
+ */
+ private static String createBiomeWrapperErrorMessage(Object[] objectArray)
+ {
+ String[] expectedClassNames;
+
+ #if MC_VER < MC_1_18_2
+ expectedClassNames = new String[] { Biome.class.getName() };
+ #elif MC_VER <= MC_1_21
+ expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
+ #else
+ // See preprocessor comment in createChunkWrapper() for full documentation
+ not implemented for this version of Minecraft!
+ #endif
+
+ return createWrapperErrorMessage("Biome wrapper", expectedClassNames, objectArray);
+ }
+
+ public IDhApiBlockStateWrapper getBlockStateWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper)
+ {
+ // confirm the API level wrapper is also a Core wrapper
+ if (!(levelWrapper instanceof ILevelWrapper))
+ {
+ throw new ClassCastException("Unable to cast... only DH provided IDhApiLevelWrapper's can be used."); // TODO
+ }
+ ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
+
+
+
+ #if MC_VER <= MC_1_21
+ if (objectArray.length != 1)
+ {
+ throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray));
+ }
+ if (!(objectArray[0] instanceof BlockState))
+ {
+ throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray));
+ }
+
+ BlockState blockState = (BlockState) objectArray[0];
+ return BlockStateWrapper.fromBlockState(blockState, coreLevelWrapper);
+ #else
+ // See preprocessor comment in createChunkWrapper() for full documentation (not a typo, check createChunkWrapper()'s else statement for full documentation)
+ not implemented for this version of Minecraft!
+ #endif
+ }
+ /**
+ * Note: when this is updated for different MC versions,
+ * make sure you also update the documentation in {@link IDhApiWrapperFactory#getBlockStateWrapper}.
+ */
+ private static String createBlockStateWrapperErrorMessage(Object[] objectArray)
+ {
+ String[] expectedClassNames;
+
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
+ expectedClassNames = new String[] { Biome.class.getName() };
+ #elif MC_VER <= MC_1_21
+ expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
+ #else
+ // See preprocessor comment in createChunkWrapper() for full documentation
+ not implemented for this version of Minecraft!
+ #endif
+
+ return createWrapperErrorMessage("BlockState wrapper", expectedClassNames, objectArray);
+ }
+
+
+
+
+ //================//
+ // helper methods //
+ //================//
+
+ private static String createWrapperErrorMessage(String wrapperName, String[] expectedClassNames, Object[] objectArray)
+ {
+ // error header
+ StringBuilder message = new StringBuilder(
+ wrapperName + " creation failed. \n" +
+ "Expected object array parameters: \n");
+
+
+ // expected parameters
+ for (String expectedClassName : expectedClassNames)
+ {
+ message.append("[").append(expectedClassName).append("], \n");
+ }
+
+
+ // given parameters
if (objectArray.length != 0)
{
message.append("Given parameters: ");
for (Object obj : objectArray)
{
- message.append("[").append(obj.getClass().getName()).append("], ");
+ String objClassName = (obj != null) ? obj.getClass().getName() : "NULL";
+ message.append("[").append(objClassName).append("], ");
}
}
else
@@ -196,8 +361,8 @@ public class WrapperFactory implements IWrapperFactory
message.append(" No parameters given.");
}
+
return message.toString();
}
-
}
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 63fd98561..5f1b205b0 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
@@ -32,19 +32,9 @@ import org.apache.logging.log4j.Logger;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
-import net.minecraft.client.Minecraft;
-#if POST_MC_1_17
-import net.minecraft.core.Holder;
-import net.minecraft.resources.RegistryOps;
-#endif
-
-#if POST_MC_1_19_2
-#endif
-
-
-#if MC_1_16_5 || MC_1_17_1
+#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
import net.minecraft.core.Registry;
-#elif MC_1_18_2 || MC_1_19_2
+#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
@@ -56,7 +46,7 @@ import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
-#if !PRE_MC_1_18_2
+#if MC_VER >= MC_1_18_2
import net.minecraft.world.level.biome.Biomes;
#endif
@@ -64,32 +54,46 @@ import net.minecraft.world.level.biome.Biomes;
/** This class wraps the minecraft BlockPos.Mutable (and BlockPos) class */
public class BiomeWrapper implements IBiomeWrapper
{
+ // must be defined before AIR, otherwise a null pointer will be thrown
private static final Logger LOGGER = LogManager.getLogger();
- #if PRE_MC_1_18_2
+
+ #if MC_VER < MC_1_18_2
public static final ConcurrentMap WRAPPER_BY_BIOME = new ConcurrentHashMap<>();
#else
public static final ConcurrentMap, BiomeWrapper> WRAPPER_BY_BIOME = new ConcurrentHashMap<>();
#endif
- public static final String EMPTY_STRING = "EMPTY";
+ public static final ConcurrentHashMap WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>();
+
+ public static final String EMPTY_BIOME_STRING = "EMPTY";
public static final BiomeWrapper EMPTY_WRAPPER = new BiomeWrapper(null, null);
+ public static final String PLAINS_RESOURCE_LOCATION_STRING = "minecraft:plains";
+
/** keep track of broken biomes so we don't log every time */
- private static final HashSet BrokenResourceLocationStrings = new HashSet<>();
+ private static final HashSet brokenResourceLocationStrings = new HashSet<>();
+
+ /**
+ * Only display this warning once, otherwise the log may be spammed
+ * This is a known issue when joining Hypixel.
+ */
+ private static boolean emptyStringWarningLogged = false;
+ private static boolean emptyLevelSerializeFailLogged = false;
// properties //
- #if PRE_MC_1_18_2
+ #if MC_VER < MC_1_18_2
public final Biome biome;
#else
public final Holder biome;
#endif
/** technically final, but since it requires a method call to generate it can't be marked as such */
- private String serialString = null;
+ private String serialString;
+ private final int hashCode;
@@ -97,7 +101,7 @@ public class BiomeWrapper implements IBiomeWrapper
// constructors //
//==============//
- static public IBiomeWrapper getBiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder #endif biome, ILevelWrapper levelWrapper)
+ static public IBiomeWrapper getBiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder #endif biome, ILevelWrapper levelWrapper)
{
if (biome == null)
{
@@ -116,12 +120,21 @@ public class BiomeWrapper implements IBiomeWrapper
return newWrapper;
}
}
-
- private BiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder #endif biome, ILevelWrapper levelWrapper)
+ private BiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder #endif biome, ILevelWrapper levelWrapper)
{
this.biome = biome;
this.serialString = this.serialize(levelWrapper);
- LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]");
+ this.hashCode = Objects.hash(this.serialString);
+
+ //LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]");
+ }
+
+ /** should only be used to create {@link BiomeWrapper#EMPTY_WRAPPER} */
+ private BiomeWrapper()
+ {
+ this.biome = null;
+ this.serialString = EMPTY_BIOME_STRING;
+ this.hashCode = Objects.hash(this.serialString);
}
@@ -135,10 +148,10 @@ public class BiomeWrapper implements IBiomeWrapper
{
if (this == EMPTY_WRAPPER)
{
- return EMPTY_STRING;
+ return EMPTY_BIOME_STRING;
}
- #if PRE_MC_1_18_2
+ #if MC_VER < MC_1_18_2
return biome.toString();
#else
return this.biome.unwrapKey().orElse(Biomes.THE_VOID).registry().toString();
@@ -163,7 +176,7 @@ public class BiomeWrapper implements IBiomeWrapper
}
@Override
- public int hashCode() { return Objects.hash(this.getSerialString()); }
+ public int hashCode() { return this.hashCode; }
@Override
public String getSerialString() { return this.serialString; }
@@ -182,52 +195,75 @@ public class BiomeWrapper implements IBiomeWrapper
public String serialize(ILevelWrapper levelWrapper)
{
- if (levelWrapper == null)
+ if (this.biome == null)
{
- return EMPTY_STRING;
+ return EMPTY_BIOME_STRING;
}
- if (this.serialString == null)
+
+ // we can't generate a serial string if the level is null
+ if (levelWrapper == null)
{
- net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess();
+ if (!emptyLevelSerializeFailLogged)
+ {
+ emptyLevelSerializeFailLogged = true;
+ LOGGER.warn("Unable to serialize biome: [" + this.biome + "] because the passed in level wrapper is null. Future errors of this type won't be logged.");
+ }
- ResourceLocation resourceLocation;
- #if MC_1_16_5 || MC_1_17_1
- resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome);
- #elif MC_1_18_2 || MC_1_19_2
- resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value());
+ return EMPTY_BIOME_STRING;
+ }
+
+
+
+ // generate the serial string //
+
+ Level level = (Level)levelWrapper.getWrappedMcObject();
+ net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
+
+ ResourceLocation resourceLocation;
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
+ resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome);
+ #elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
+ resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value());
+ #else
+ resourceLocation = registryAccess.registryOrThrow(Registries.BIOME).getKey(this.biome.value());
+ #endif
+
+ if (resourceLocation == null)
+ {
+ String biomeName;
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
+ biomeName = this.biome.toString();
#else
- resourceLocation = registryAccess.registryOrThrow(Registries.BIOME).getKey(this.biome.value());
+ biomeName = this.biome.value().toString();
#endif
- if (resourceLocation == null)
- {
- String biomeName;
- #if MC_1_16_5 || MC_1_17_1
- biomeName = this.biome.toString();
- #else
- biomeName = this.biome.value().toString();
- #endif
-
- LOGGER.warn("unable to serialize: " + biomeName);
- // shouldn't normally happen, but just in case
- this.serialString = "";
- }
- else
- {
- this.serialString = resourceLocation.getNamespace() + ":" + resourceLocation.getPath();
- }
+ LOGGER.warn("unable to serialize: " + biomeName);
+ // shouldn't normally happen, but just in case
+ this.serialString = "";
+ }
+ else
+ {
+ this.serialString = resourceLocation.getNamespace() + ":" + resourceLocation.getPath();
}
return this.serialString;
}
+ // TODO would it be worth while to cache these objects in a ConcurrentHashMap?
public static IBiomeWrapper deserialize(String resourceLocationString, ILevelWrapper levelWrapper) throws IOException
{
- if (resourceLocationString.equals(EMPTY_STRING))
+ // we need the final string for the concurrent hash map later
+ final String finalResourceStateString = resourceLocationString;
+
+ if (resourceLocationString.equals(EMPTY_BIOME_STRING))
{
- LOGGER.warn("["+EMPTY_STRING+"] biome string deserialized. This may mean there was a file saving error or a biome saving error.");
+ if (!emptyStringWarningLogged)
+ {
+ emptyStringWarningLogged = true;
+ LOGGER.warn("[" + EMPTY_BIOME_STRING + "] biome string deserialized. This may mean the level was null when a save was attempted, a file saving error, or a biome saving error. Future errors will not be logged.");
+ }
return EMPTY_WRAPPER;
}
else if (resourceLocationString.trim().isEmpty() || resourceLocationString.equals(""))
@@ -236,53 +272,82 @@ public class BiomeWrapper implements IBiomeWrapper
return EMPTY_WRAPPER;
}
-
-
- // parse the resource location
- int separatorIndex = resourceLocationString.indexOf(":");
- if (separatorIndex == -1)
+ if (WRAPPER_BY_RESOURCE_LOCATION.containsKey(finalResourceStateString))
{
- throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "].");
+ return WRAPPER_BY_RESOURCE_LOCATION.get(finalResourceStateString);
}
- ResourceLocation resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
+
+ // if no wrapper is found, default to the empty wrapper
+ BiomeWrapper foundWrapper = EMPTY_WRAPPER;
try
{
- Level level = (Level)levelWrapper.getWrappedMcObject();
- net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
-
- boolean success;
- #if MC_1_16_5 || MC_1_17_1
- Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
- success = (biome != null);
- #elif MC_1_18_2 || MC_1_19_2
- Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
- success = (unwrappedBiome != null);
- Holder biome = new Holder.Direct<>(unwrappedBiome);
- #else
- Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
- success = (unwrappedBiome != null);
- Holder biome = new Holder.Direct<>(unwrappedBiome);
- #endif
-
-
-
- if (!success)
+ // parse the resource location
+ int separatorIndex = resourceLocationString.indexOf(":");
+ if (separatorIndex == -1)
{
- if (!BrokenResourceLocationStrings.contains(resourceLocationString))
- {
- BrokenResourceLocationStrings.add(resourceLocationString);
- LOGGER.warn("Unable to deserialize biome from string: [" + resourceLocationString + "]");
- }
- return EMPTY_WRAPPER;
+ throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "].");
}
- return getBiomeWrapper(biome, levelWrapper);
+ ResourceLocation resourceLocation;
+ try
+ {
+ #if MC_VER < MC_1_21
+ resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
+ #else
+ resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
+ #endif
+ }
+ catch (Exception e)
+ {
+ throw new IOException("No Resource Location found for the string: [" + resourceLocationString + "] Error: [" + e.getMessage() + "].");
+ }
+
+
+ try
+ {
+ Level level = (Level) levelWrapper.getWrappedMcObject();
+ net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
+
+ boolean success;
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
+ Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
+ success = (biome != null);
+ #elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
+ Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
+ success = (unwrappedBiome != null);
+ Holder biome = new Holder.Direct<>(unwrappedBiome);
+ #else
+ Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
+ success = (unwrappedBiome != null);
+ Holder biome = new Holder.Direct<>(unwrappedBiome);
+ #endif
+
+
+
+ if (!success)
+ {
+ if (!brokenResourceLocationStrings.contains(resourceLocationString))
+ {
+ brokenResourceLocationStrings.add(resourceLocationString);
+ LOGGER.warn("Unable to deserialize biome from string: [" + resourceLocationString + "]");
+ }
+ return EMPTY_WRAPPER;
+ }
+
+
+ foundWrapper = (BiomeWrapper) getBiomeWrapper(biome, levelWrapper);
+ return foundWrapper;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Failed to deserialize the string [" + finalResourceStateString + "] into a BiomeWrapper: " + e.getMessage(), e);
+ }
}
- catch (Exception e)
+ finally
{
- throw new IOException("Failed to deserialize the string [" + resourceLocationString + "] into a BiomeWrapper: " + e.getMessage(), e);
+ WRAPPER_BY_RESOURCE_LOCATION.putIfAbsent(finalResourceStateString, foundWrapper);
}
}
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 25aa8dd9b..52b30b922 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
@@ -24,7 +24,10 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrappe
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import net.minecraft.resources.ResourceLocation;
+import net.minecraft.tags.BlockTags;
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;
import org.apache.logging.log4j.Logger;
@@ -32,11 +35,11 @@ import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
-#if MC_1_16_5 || MC_1_17_1
+#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
import net.minecraft.core.Registry;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter;
-#elif MC_1_18_2 || MC_1_19_2
+#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
import net.minecraft.client.Minecraft;
import net.minecraft.world.level.Level;
import net.minecraft.core.BlockPos;
@@ -62,10 +65,13 @@ public class BlockStateWrapper implements IBlockStateWrapper
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public static final ConcurrentHashMap WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>();
+ public static final ConcurrentHashMap WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>();
public static final String AIR_STRING = "AIR";
public static final BlockStateWrapper AIR = new BlockStateWrapper(null, null);
+ public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt";
+
// TODO: Make this changeable through the config
public static final String[] RENDERER_IGNORED_BLOCKS_RESOURCE_LOCATIONS = { AIR_STRING, "minecraft:barrier", "minecraft:structure_void", "minecraft:light", "minecraft:tripwire" };
public static HashSet rendererIgnoredBlocks = null;
@@ -80,11 +86,14 @@ public class BlockStateWrapper implements IBlockStateWrapper
public final BlockState blockState;
/** 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;
/**
* Cached opacity value, -1 if not populated.
* Should be between {@link IBlockStateWrapper#FULLY_OPAQUE} and {@link IBlockStateWrapper#FULLY_OPAQUE}
*/
private int opacity = -1;
+ /** used by the Iris shader mod to determine how each LOD should be rendered */
+ private byte irisBlockMaterialId = 0;
@@ -116,7 +125,10 @@ public class BlockStateWrapper implements IBlockStateWrapper
{
this.blockState = blockState;
this.serialString = this.serialize(levelWrapper);
- LOGGER.trace("Created BlockStateWrapper ["+this.serialString+"] for ["+blockState+"]");
+ this.hashCode = Objects.hash(this.serialString);
+ this.irisBlockMaterialId = this.calculateIrisBlockMaterialId();
+
+ //LOGGER.trace("Created BlockStateWrapper ["+this.serialString+"] for ["+blockState+"] with material ID ["+this.irisBlockMaterialId+"]");
}
@@ -239,7 +251,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
}
@Override
- public int hashCode() { return Objects.hash(this.getSerialString()); }
+ public int hashCode() { return this.hashCode; }
@Override
@@ -252,7 +264,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
@Override
public boolean isSolid()
{
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
return this.blockState.getMaterial().isSolid();
#else
return !this.blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty();
@@ -267,13 +279,16 @@ public class BlockStateWrapper implements IBlockStateWrapper
return false;
}
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
return this.blockState.getMaterial().isLiquid() || !this.blockState.getFluidState().isEmpty();
#else
return !this.blockState.getFluidState().isEmpty();
#endif
}
+ @Override
+ public byte getIrisBlockMaterialId() { return this.irisBlockMaterialId; }
+
@Override
public String toString() { return this.getSerialString(); }
@@ -293,15 +308,15 @@ public class BlockStateWrapper implements IBlockStateWrapper
// older versions of MC have a static registry
- #if !(MC_1_16_5 || MC_1_17_1)
+ #if MC_VER > MC_1_17_1
Level level = (Level)levelWrapper.getWrappedMcObject();
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
#endif
ResourceLocation resourceLocation;
- #if MC_1_16_5 || MC_1_17_1
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
resourceLocation = Registry.BLOCK.getKey(this.blockState.getBlock());
- #elif MC_1_18_2 || MC_1_19_2
+ #elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(this.blockState.getBlock());
#else
resourceLocation = registryAccess.registryOrThrow(Registries.BLOCK).getKey(this.blockState.getBlock());
@@ -325,103 +340,139 @@ public class BlockStateWrapper implements IBlockStateWrapper
/** will only work if a level is currently loaded */
public static IBlockStateWrapper deserialize(String resourceStateString, ILevelWrapper levelWrapper) throws IOException
{
- if (resourceStateString.equals(AIR_STRING) || resourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case
+ // we need the final string for the concurrent hash map later
+ final String finalResourceStateString = resourceStateString;
+
+ if (finalResourceStateString.equals(AIR_STRING) || finalResourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case
{
return AIR;
}
-
-
- // try to parse out the BlockState
- String blockStatePropertiesString = null; // will be null if no properties were included
- int stateSeparatorIndex = resourceStateString.indexOf(STATE_STRING_SEPARATOR);
- if (stateSeparatorIndex != -1)
+ // attempt to use the existing wrapper
+ if (WRAPPER_BY_RESOURCE_LOCATION.containsKey(finalResourceStateString))
{
- // blockstate properties found
- blockStatePropertiesString = resourceStateString.substring(stateSeparatorIndex + STATE_STRING_SEPARATOR.length());
- resourceStateString = resourceStateString.substring(0, stateSeparatorIndex);
+ return WRAPPER_BY_RESOURCE_LOCATION.get(finalResourceStateString);
}
- // parse the resource location
- int resourceSeparatorIndex = resourceStateString.indexOf(RESOURCE_LOCATION_SEPARATOR);
- if (resourceSeparatorIndex == -1)
- {
- throw new IOException("Unable to parse Resource Location out of string: [" + resourceStateString + "].");
- }
- ResourceLocation resourceLocation = new ResourceLocation(resourceStateString.substring(0, resourceSeparatorIndex), resourceStateString.substring(resourceSeparatorIndex + 1));
-
- // attempt to get the BlockState from all possible BlockStates
+ // if no wrapper is found, default to air
+ BlockStateWrapper foundWrapper = AIR;
try
{
-
- #if !(MC_1_16_5 || MC_1_17_1)
- // use the given level if possible, otherwise try using the currently loaded one
- Level level = (levelWrapper != null ? (Level)levelWrapper.getWrappedMcObject() : null);
- level = (level == null ? Minecraft.getInstance().level : level);
- #endif
-
- Block block;
- #if MC_1_16_5 || MC_1_17_1
- block = Registry.BLOCK.get(resourceLocation);
- #elif MC_1_18_2 || MC_1_19_2
- net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
- block = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).get(resourceLocation);
- #else
- net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
- block = registryAccess.registryOrThrow(Registries.BLOCK).get(resourceLocation);
- #endif
-
-
- if (block == null)
+ // try to parse out the BlockState
+ String blockStatePropertiesString = null; // will be null if no properties were included
+ int stateSeparatorIndex = resourceStateString.indexOf(STATE_STRING_SEPARATOR);
+ if (stateSeparatorIndex != -1)
{
- // shouldn't normally happen, but here to make the compiler happy
- if (!BrokenResourceLocations.contains(resourceLocation))
- {
- BrokenResourceLocations.add(resourceLocation);
- LOGGER.warn("Unable to find BlockState with the resourceLocation [" + resourceLocation + "] and properties: [" + blockStatePropertiesString + "]. Air will be used instead, some data may be lost.");
- }
- return AIR;
+ // blockstate properties found
+ blockStatePropertiesString = resourceStateString.substring(stateSeparatorIndex + STATE_STRING_SEPARATOR.length());
+ resourceStateString = resourceStateString.substring(0, stateSeparatorIndex);
+ }
+
+ // parse the resource location
+ int separatorIndex = resourceStateString.indexOf(RESOURCE_LOCATION_SEPARATOR);
+ if (separatorIndex == -1)
+ {
+ throw new IOException("Unable to parse Resource Location out of string: [" + resourceStateString + "].");
+ }
+
+ ResourceLocation resourceLocation;
+ try
+ {
+ #if MC_VER < MC_1_21
+ resourceLocation = new ResourceLocation(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
+ #else
+ resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
+ #endif
+ }
+ catch (Exception e)
+ {
+ throw new IOException("No Resource Location found for the string: [" + resourceStateString + "] Error: [" + e.getMessage() + "].");
}
- // attempt to find the blockstate from all possibilities
- BlockState foundState = null;
- if (blockStatePropertiesString != null)
- {
- List possibleStateList = block.getStateDefinition().getPossibleStates();
- for (BlockState possibleState : possibleStateList)
- {
- String possibleStatePropertiesString = serializeBlockStateProperties(possibleState);
- if (possibleStatePropertiesString.equals(blockStatePropertiesString))
- {
- foundState = possibleState;
- break;
- }
- }
- }
- // use the default if no state was found or given
- if (foundState == null)
+ // attempt to get the BlockState from all possible BlockStates
+ try
{
- if (blockStatePropertiesString != null)
+
+ #if MC_VER > MC_1_17_1
+ // use the given level if possible, otherwise try using the currently loaded one
+ Level level = (levelWrapper != null ? (Level) levelWrapper.getWrappedMcObject() : null);
+ level = (level == null ? Minecraft.getInstance().level : level);
+ #endif
+
+ Block block;
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
+ block = Registry.BLOCK.get(resourceLocation);
+ #elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
+ net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
+ block = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).get(resourceLocation);
+ #else
+ net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
+ block = registryAccess.registryOrThrow(Registries.BLOCK).get(resourceLocation);
+ #endif
+
+
+ if (block == null)
{
- // we should have found a blockstate, but didn't
+ // shouldn't normally happen, but here to make the compiler happy
if (!BrokenResourceLocations.contains(resourceLocation))
{
BrokenResourceLocations.add(resourceLocation);
- LOGGER.warn("Unable to find BlockState for Block [" + resourceLocation + "] with properties: [" + blockStatePropertiesString + "]. Using the default block state.");
+ LOGGER.warn("Unable to find BlockState with the resourceLocation [" + resourceLocation + "] and properties: [" + blockStatePropertiesString + "]. Air will be used instead, some data may be lost.");
+ }
+
+ return AIR;
+ }
+
+
+ // attempt to find the blockstate from all possibilities
+ BlockState foundState = null;
+ if (blockStatePropertiesString != null)
+ {
+ List possibleStateList = block.getStateDefinition().getPossibleStates();
+ for (BlockState possibleState : possibleStateList)
+ {
+ String possibleStatePropertiesString = serializeBlockStateProperties(possibleState);
+ if (possibleStatePropertiesString.equals(blockStatePropertiesString))
+ {
+ foundState = possibleState;
+ break;
+ }
}
}
- foundState = block.defaultBlockState();
+ // use the default if no state was found or given
+ if (foundState == null)
+ {
+ if (blockStatePropertiesString != null)
+ {
+ // we should have found a blockstate, but didn't
+ if (!BrokenResourceLocations.contains(resourceLocation))
+ {
+ BrokenResourceLocations.add(resourceLocation);
+ LOGGER.warn("Unable to find BlockState for Block [" + resourceLocation + "] with properties: [" + blockStatePropertiesString + "]. Using the default block state.");
+ }
+ }
+
+ foundState = block.defaultBlockState();
+ }
+
+ foundWrapper = new BlockStateWrapper(foundState, levelWrapper);
+ return foundWrapper;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Failed to deserialize the string [" + finalResourceStateString + "] into a BlockStateWrapper: " + e.getMessage(), e);
}
- return new BlockStateWrapper(foundState, levelWrapper);
}
- catch (Exception e)
+ finally
{
- throw new IOException("Failed to deserialize the string [" + resourceStateString + "] into a BlockStateWrapper: " + e.getMessage(), e);
+ // put if absent in case two threads deserialize at the same time
+ // unfortunately we can't put everything in a computeIfAbsent() since we also throw exceptions
+ WRAPPER_BY_RESOURCE_LOCATION.putIfAbsent(finalResourceStateString, foundWrapper);
}
}
@@ -457,4 +508,111 @@ public class BlockStateWrapper implements IBlockStateWrapper
+ //==============//
+ // Iris methods //
+ //==============//
+
+ private byte calculateIrisBlockMaterialId()
+ {
+ if (this.blockState == null)
+ {
+ return IrisBlockMaterial.AIR;
+ }
+
+
+ String serialString = this.getSerialString().toLowerCase();
+
+ if (this.blockState.is(BlockTags.LEAVES)
+ || serialString.contains("bamboo")
+ || serialString.contains("cactus")
+ || serialString.contains("chorus_flower")
+ || serialString.contains("mushroom")
+ )
+ {
+ return IrisBlockMaterial.LEAVES;
+ }
+ else if (this.blockState.is(Blocks.LAVA))
+ {
+ return IrisBlockMaterial.LAVA;
+ }
+ else if (this.isLiquid() || this.blockState.is(Blocks.WATER))
+ {
+ return IrisBlockMaterial.WATER;
+ }
+ else if (this.blockState.getSoundType() == SoundType.WOOD
+ || serialString.contains("root")
+ #if MC_VER >= MC_1_19_4
+ || this.blockState.getSoundType() == SoundType.CHERRY_WOOD
+ #endif
+ )
+ {
+ return IrisBlockMaterial.WOOD;
+ }
+ else if (this.blockState.getSoundType() == SoundType.METAL
+ #if MC_VER >= MC_1_19_2
+ || this.blockState.getSoundType() == SoundType.COPPER
+ #endif
+ #if MC_VER >= MC_1_20_4
+ || this.blockState.getSoundType() == SoundType.COPPER_BULB
+ || this.blockState.getSoundType() == SoundType.COPPER_GRATE
+ #endif
+ )
+ {
+ return IrisBlockMaterial.METAL;
+ }
+ else if (serialString.contains("grass_block"))
+ {
+ return IrisBlockMaterial.GRASS;
+ }
+ else if (
+ serialString.contains("dirt")
+ || serialString.contains("gravel")
+ || serialString.contains("mud")
+ || serialString.contains("podzol")
+ || serialString.contains("mycelium")
+ )
+ {
+ return IrisBlockMaterial.DIRT;
+ }
+ #if MC_VER >= MC_1_17_1
+ else if (this.blockState.getSoundType() == SoundType.DEEPSLATE
+ || this.blockState.getSoundType() == SoundType.DEEPSLATE_BRICKS
+ || this.blockState.getSoundType() == SoundType.DEEPSLATE_TILES
+ || this.blockState.getSoundType() == SoundType.POLISHED_DEEPSLATE
+ || serialString.contains("deepslate") )
+ {
+ return IrisBlockMaterial.DEEPSLATE;
+ }
+ #endif
+ else if (this.serialString.contains("snow"))
+ {
+ return IrisBlockMaterial.SNOW;
+ }
+ else if (serialString.contains("sand"))
+ {
+ return IrisBlockMaterial.SAND;
+ }
+ else if (serialString.contains("terracotta"))
+ {
+ return IrisBlockMaterial.TERRACOTTA;
+ }
+ else if (this.blockState.is(BlockTags.BASE_STONE_NETHER))
+ {
+ return IrisBlockMaterial.NETHER_STONE;
+ }
+ else if (serialString.contains("stone")
+ || serialString.contains("ore"))
+ {
+ return IrisBlockMaterial.STONE;
+ }
+ else if (this.blockState.getLightEmission() > 0)
+ {
+ return IrisBlockMaterial.ILLUMINATED;
+ }
+ else
+ {
+ return IrisBlockMaterial.UNKOWN;
+ }
+ }
+
}
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 b5334f956..3b777e533 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
@@ -40,11 +40,11 @@ public class TextureAtlasSpriteWrapper
*/
public static int getPixelRGBA(TextureAtlasSprite sprite, int frameIndex, int x, int y)
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
return sprite.mainImage[0].getPixelRGBA(
x + sprite.framesX[frameIndex] * sprite.getWidth(),
y + sprite.framesY[frameIndex] * sprite.getHeight());
- #elif PRE_MC_1_19_4
+ #elif MC_VER < MC_1_19_4
if (sprite.animatedTexture != null)
{
x += sprite.animatedTexture.getFrameX(frameIndex) * sprite.width;
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintGetterOverrideFast.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintGetterOverrideFast.java
index 7a8a92e6e..f71095818 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintGetterOverrideFast.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintGetterOverrideFast.java
@@ -19,7 +19,6 @@
package com.seibel.distanthorizons.common.wrappers.block;
-import com.seibel.distanthorizons.common.LodCommonMain;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.*;
@@ -50,7 +49,7 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
private Biome _getBiome(BlockPos pos)
{
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
return parent.getBiome(pos).value();
#else
return parent.getBiome(pos);
@@ -58,18 +57,7 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
}
@Override
- public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
- {
- if (LodCommonMain.forgeMethodCaller != null)
- {
- return LodCommonMain.forgeMethodCaller.colorResolverGetColor(colorResolver, _getBiome(blockPos),
- blockPos.getX(), blockPos.getZ());
- }
- else
- {
- return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ());
- }
- }
+ public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) { return colorResolver.getColor(this._getBiome(blockPos), blockPos.getX(), blockPos.getZ()); }
@Override
public float getShade(Direction direction, boolean bl) { return this.parent.getShade(direction, bl); }
@@ -167,7 +155,7 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
return parent.getMaxBuildHeight();
}
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
@Override
public Optional getBlockEntity(BlockPos blockPos, BlockEntityType blockEntityType)
{
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintGetterOverrideSmooth.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintGetterOverrideSmooth.java
index 94015d4de..a840f3868 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintGetterOverrideSmooth.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintGetterOverrideSmooth.java
@@ -19,7 +19,6 @@
package com.seibel.distanthorizons.common.wrappers.block;
-import com.seibel.distanthorizons.common.LodCommonMain;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Cursor3D;
import net.minecraft.core.Direction;
@@ -53,7 +52,7 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter
private Biome _getBiome(BlockPos pos)
{
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
return parent.getBiome(pos).value();
#else
return parent.getBiome(pos);
@@ -74,16 +73,7 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter
while (cursor3D.advance())
{
mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
- int n;
- if (LodCommonMain.forgeMethodCaller != null)
- {
- n = LodCommonMain.forgeMethodCaller.colorResolverGetColor(colorResolver, _getBiome(mutableBlockPos),
- mutableBlockPos.getX(), mutableBlockPos.getZ());
- }
- else
- {
- n = colorResolver.getColor(_getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
- }
+ int n = colorResolver.getColor(this._getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
k += (n & 0xFF0000) >> 16;
l += (n & 0xFF00) >> 8;
@@ -93,177 +83,96 @@ public class TintGetterOverrideSmooth implements BlockAndTintGetter
}
@Override
- public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
- {
- return calculateBlockTint(blockPos, colorResolver);
- }
+ public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) { return this.calculateBlockTint(blockPos, colorResolver); }
@Override
public float getShade(Direction direction, boolean bl) { return this.parent.getShade(direction, bl); }
@Override
- public LevelLightEngine getLightEngine()
- {
- return parent.getLightEngine();
- }
+ public LevelLightEngine getLightEngine() { return this.parent.getLightEngine(); }
@Override
- public int getBrightness(LightLayer lightLayer, BlockPos blockPos)
- {
- return parent.getBrightness(lightLayer, blockPos);
- }
+ public int getBrightness(LightLayer lightLayer, BlockPos blockPos) { return this.parent.getBrightness(lightLayer, blockPos); }
@Override
- public int getRawBrightness(BlockPos blockPos, int i)
- {
- return parent.getRawBrightness(blockPos, i);
- }
+ public int getRawBrightness(BlockPos blockPos, int i) { return this.parent.getRawBrightness(blockPos, i); }
@Override
- public boolean canSeeSky(BlockPos blockPos)
- {
- return parent.canSeeSky(blockPos);
- }
+ public boolean canSeeSky(BlockPos blockPos) { return this.parent.canSeeSky(blockPos); }
@Override
@Nullable
- public BlockEntity getBlockEntity(BlockPos blockPos)
- {
- return parent.getBlockEntity(blockPos);
- }
+ public BlockEntity getBlockEntity(BlockPos blockPos) { return this.parent.getBlockEntity(blockPos); }
@Override
- public BlockState getBlockState(BlockPos blockPos)
- {
- return parent.getBlockState(blockPos);
- }
+ public BlockState getBlockState(BlockPos blockPos) { return this.parent.getBlockState(blockPos); }
@Override
- public FluidState getFluidState(BlockPos blockPos)
- {
- return parent.getFluidState(blockPos);
- }
+ public FluidState getFluidState(BlockPos blockPos) { return this.parent.getFluidState(blockPos); }
@Override
- public int getLightEmission(BlockPos blockPos)
- {
- return parent.getLightEmission(blockPos);
- }
+ public int getLightEmission(BlockPos blockPos) { return this.parent.getLightEmission(blockPos); }
@Override
- public int getMaxLightLevel()
- {
- return parent.getMaxLightLevel();
- }
+ public int getMaxLightLevel() { return this.parent.getMaxLightLevel(); }
@Override
- public Stream getBlockStates(AABB aABB)
- {
- return parent.getBlockStates(aABB);
- }
+ public Stream getBlockStates(AABB aABB) { return this.parent.getBlockStates(aABB); }
@Override
- public BlockHitResult clip(ClipContext clipContext)
- {
- return parent.clip(clipContext);
- }
+ public BlockHitResult clip(ClipContext clipContext) { return this.parent.clip(clipContext); }
@Override
@Nullable
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState)
{
- return parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
+ return this.parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
}
@Override
- public double getBlockFloorHeight(VoxelShape voxelShape, Supplier supplier)
- {
- return parent.getBlockFloorHeight(voxelShape, supplier);
- }
+ public double getBlockFloorHeight(VoxelShape voxelShape, Supplier supplier) { return this.parent.getBlockFloorHeight(voxelShape, supplier); }
@Override
- public double getBlockFloorHeight(BlockPos blockPos)
- {
- return parent.getBlockFloorHeight(blockPos);
- }
+ public double getBlockFloorHeight(BlockPos blockPos) { return this.parent.getBlockFloorHeight(blockPos); }
@Override
- public int getMaxBuildHeight()
- {
- return parent.getMaxBuildHeight();
- }
+ public int getMaxBuildHeight() { return this.parent.getMaxBuildHeight(); }
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
@Override
- public Optional getBlockEntity(BlockPos blockPos, BlockEntityType blockEntityType)
- {
- return parent.getBlockEntity(blockPos, blockEntityType);
- }
+ public Optional getBlockEntity(BlockPos blockPos, BlockEntityType blockEntityType) { return this.parent.getBlockEntity(blockPos, blockEntityType); }
@Override
- public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext)
- {
- return parent.isBlockInLine(clipBlockStateContext);
- }
+ public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) { return this.parent.isBlockInLine(clipBlockStateContext); }
@Override
- public int getHeight()
- {
- return parent.getHeight();
- }
+ public int getHeight() { return this.parent.getHeight(); }
@Override
- public int getMinBuildHeight()
- {
- return parent.getMinBuildHeight();
- }
+ public int getMinBuildHeight() { return this.parent.getMinBuildHeight(); }
@Override
- public int getSectionsCount()
- {
- return parent.getSectionsCount();
- }
+ public int getSectionsCount() { return this.parent.getSectionsCount(); }
@Override
- public int getMinSection()
- {
- return parent.getMinSection();
- }
+ public int getMinSection() { return this.parent.getMinSection(); }
@Override
- public int getMaxSection()
- {
- return parent.getMaxSection();
- }
+ public int getMaxSection() { return this.parent.getMaxSection(); }
@Override
- public boolean isOutsideBuildHeight(BlockPos blockPos)
- {
- return parent.isOutsideBuildHeight(blockPos);
- }
+ public boolean isOutsideBuildHeight(BlockPos blockPos) { return this.parent.isOutsideBuildHeight(blockPos); }
@Override
- public boolean isOutsideBuildHeight(int i)
- {
- return parent.isOutsideBuildHeight(i);
- }
+ public boolean isOutsideBuildHeight(int i) { return this.parent.isOutsideBuildHeight(i); }
@Override
- public int getSectionIndex(int i)
- {
- return parent.getSectionIndex(i);
- }
+ public int getSectionIndex(int i) { return this.parent.getSectionIndex(i); }
@Override
- public int getSectionIndexFromSectionY(int i)
- {
- return parent.getSectionIndexFromSectionY(i);
- }
+ public int getSectionIndexFromSectionY(int i) { return this.parent.getSectionIndexFromSectionY(i); }
@Override
- public int getSectionYFromSectionIndex(int i)
- {
- return parent.getSectionYFromSectionIndex(i);
- }
+ public int getSectionYFromSectionIndex(int i) { return this.parent.getSectionYFromSectionIndex(i); }
#endif
}
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 4f35469ea..4c27070fc 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
@@ -19,72 +19,120 @@
package com.seibel.distanthorizons.common.wrappers.block;
+import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
+import com.seibel.distanthorizons.core.util.ColorUtil;
+import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.*;
import net.minecraft.world.level.biome.Biome;
+import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
+import org.apache.logging.log4j.Logger;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-#if POST_MC_1_18_2
+#if MC_VER >= MC_1_18_2
import net.minecraft.core.Holder;
#endif
public class TintWithoutLevelOverrider implements BlockAndTintGetter
{
- final BiomeWrapper biome;
+ /**
+ * This will only ever be null if there was an issue with {@link IClientLevelWrapper#getPlainsBiomeWrapper()}
+ * but {@link Nullable} is there just in case.
+ */
+ @Nullable
+ private final Biome biome;
- public TintWithoutLevelOverrider(BiomeWrapper biome)
+
+
+ public TintWithoutLevelOverrider(BiomeWrapper biomeWrapper, IClientLevelWrapper clientLevelWrapper)
{
- this.biome = biome;
+ // try to get the wrapped biome
+ Biome unwrappedBiome = null;
+ if (biomeWrapper.biome != null)
+ {
+ unwrappedBiome = unwrap(biomeWrapper.biome);
+ }
+
+ if(unwrappedBiome == null)
+ {
+ // we are looking at the empty biome wrapper, try using plains as a backup
+ BiomeWrapper plainsBiomeWrapper = ((BiomeWrapper) clientLevelWrapper.getPlainsBiomeWrapper());
+ if (plainsBiomeWrapper != null)
+ {
+ unwrappedBiome = unwrap(plainsBiomeWrapper.biome);
+ }
+ }
+
+ this.biome = unwrappedBiome;
}
+
+
+
@Override
- public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
- {
- return colorResolver.getColor(_unwrap(biome.biome), blockPos.getX(), blockPos.getZ());
+ public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver)
+ {
+ if (this.biome != null)
+ {
+ return colorResolver.getColor(this.biome, blockPos.getX(), blockPos.getZ());
+ }
+ else
+ {
+ // hopefully unneeded debug color
+ return ColorUtil.CYAN;
+ }
}
- private Biome _unwrap(#if POST_MC_1_18_2 Holder #else Biome #endif biome)
+
+ private static Biome unwrap(#if MC_VER >= MC_1_18_2 Holder #else Biome #endif biome)
{
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
return biome.value();
#else
return biome;
#endif
}
+
+
+ //================//
+ // unused methods //
+ //================//
+
@Override
- public float getShade(Direction direction, boolean shade)
+ public float getShade(@NotNull Direction direction, boolean shade)
{
throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
- public LevelLightEngine getLightEngine()
+ public @NotNull LevelLightEngine getLightEngine()
{
throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Nullable
@Override
- public BlockEntity getBlockEntity(BlockPos pos)
+ public BlockEntity getBlockEntity(@NotNull BlockPos pos)
{
throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
- public BlockState getBlockState(BlockPos pos)
+ public @NotNull BlockState getBlockState(@NotNull BlockPos pos)
{
throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
- public FluidState getFluidState(BlockPos pos)
+ public @NotNull FluidState getFluidState(@NotNull BlockPos pos)
{
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
- #if MC_1_17_1 || POST_MC_1_18_2
+ #if MC_VER >= MC_1_17_1
@Override
public int getHeight()
{
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintWithoutLevelSmoothOverrider.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintWithoutLevelSmoothOverrider.java
index c4f4d4438..04a9b41b1 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintWithoutLevelSmoothOverrider.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TintWithoutLevelSmoothOverrider.java
@@ -30,7 +30,7 @@ import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import org.jetbrains.annotations.Nullable;
-#if POST_MC_1_18_2
+#if MC_VER >= MC_1_18_2
import net.minecraft.core.Holder;
#endif
@@ -49,9 +49,9 @@ public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter
{
return colorResolver.getColor(_unwrap(biome.biome), blockPos.getX(), blockPos.getZ());
}
- private Biome _unwrap(#if POST_MC_1_18_2 Holder #else Biome #endif biome)
+ private Biome _unwrap(#if MC_VER >= MC_1_18_2 Holder #else Biome #endif biome)
{
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
return biome.value();
#else
return biome;
@@ -116,7 +116,7 @@ public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter
}
- #if MC_1_17_1 || POST_MC_1_18_2
+ #if MC_VER >= MC_1_17_1
@Override
public int getHeight()
{
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java
index e078d6685..e05b1a966 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java
@@ -29,7 +29,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class ClientBlockDetailMap
{
private final ConcurrentHashMap blockCache = new ConcurrentHashMap<>();
- //private final ConcurrentHashMap<#if PRE_MC_1_18_2 Biome #else Holder #endif, Biome> biomeMap = new ConcurrentHashMap<>();
+ //private final ConcurrentHashMap<#if MC_VER < MC_1_18_2 Biome #else Holder #endif, Biome> biomeMap = new ConcurrentHashMap<>();
private final ClientLevelWrapper level;
public ClientBlockDetailMap(ClientLevelWrapper level) { this.level = level; }
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java
index a14db741f..52b81458c 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java
@@ -38,7 +38,7 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.FlowerBlock;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.RotatedPillarBlock;
-#if POST_MC_1_19_2
+#if MC_VER >= MC_1_19_2
import net.minecraft.util.RandomSource;
#else
import java.util.Random;
@@ -54,27 +54,31 @@ import java.util.List;
*/
public class ClientBlockStateCache
{
-
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final HashSet BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>();
private static final HashSet BROKEN_BLOCK_STATES = new HashSet<>();
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
public static final Random random = new Random(0);
#else
public static final RandomSource random = RandomSource.create();
#endif
+ public final IClientLevelWrapper levelWrapper;
public final BlockState blockState;
public final LevelReader level;
public final BlockPos pos;
+
+
+
public ClientBlockStateCache(BlockState blockState, IClientLevelWrapper samplingLevel, DhBlockPos samplingPos)
{
this.blockState = blockState;
- level = (LevelReader) samplingLevel.getWrappedMcObject();
- pos = McObjectConverter.Convert(samplingPos);
- resolveColors();
+ this.levelWrapper = samplingLevel;
+ this.level = (LevelReader) samplingLevel.getWrappedMcObject();
+ this.pos = McObjectConverter.Convert(samplingPos);
+ this.resolveColors();
//LOGGER.info("ClientBlocKCache created for {}", blockState);
}
@@ -91,18 +95,98 @@ public class ClientBlockStateCache
{
Default,
Flower,
- Leaves;
+ Leaves,
+ Chisel,
+ Glass;
static ColorMode getColorMode(Block b)
{
if (b instanceof LeavesBlock) return Leaves;
if (b instanceof FlowerBlock) return Flower;
+ if (b.toString().contains("glass")) return Glass;
+ if (b.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel;
return Default;
}
}
+
+ //Way to efficiently do this was suggested by IMS from sodium. This is where those numbers and support code was lifted from.
+ private static final int MIN_BITS = 0x39000000; // 2^(-13)
+ private static final int MAX_BITS = 0x3f7fffff; // 1.0 - f32::EPSILON
+ private static final float MIN_BOUND = Float.intBitsToFloat(MIN_BITS);
+ private static final float MAX_BOUND = Float.intBitsToFloat(MAX_BITS);
+
+ private static final int[] linearToSrgbTable = new int[] {
+ 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
+ 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
+ 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
+ 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
+ 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
+ 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
+ 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
+ 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
+ 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
+ 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
+ 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
+ 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
+ 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
+ };
+
+ private static final float[] srgbToLinearTable = new float[] {
+ 0.0f, 0.000303527f, 0.000607054f, 0.00091058103f, 0.001214108f, 0.001517635f, 0.0018211621f, 0.002124689f,
+ 0.002428216f, 0.002731743f, 0.00303527f, 0.0033465356f, 0.003676507f, 0.004024717f, 0.004391442f,
+ 0.0047769533f, 0.005181517f, 0.0056053917f, 0.0060488326f, 0.006512091f, 0.00699541f, 0.0074990317f,
+ 0.008023192f, 0.008568125f, 0.009134057f, 0.009721218f, 0.010329823f, 0.010960094f, 0.011612245f,
+ 0.012286487f, 0.012983031f, 0.013702081f, 0.014443844f, 0.015208514f, 0.015996292f, 0.016807375f,
+ 0.017641952f, 0.018500218f, 0.019382361f, 0.020288562f, 0.02121901f, 0.022173883f, 0.023153365f,
+ 0.02415763f, 0.025186857f, 0.026241222f, 0.027320892f, 0.028426038f, 0.029556843f, 0.03071345f, 0.03189604f,
+ 0.033104774f, 0.03433981f, 0.035601325f, 0.036889452f, 0.038204376f, 0.039546248f, 0.04091521f, 0.042311423f,
+ 0.043735042f, 0.045186214f, 0.046665095f, 0.048171833f, 0.049706575f, 0.051269468f, 0.052860655f, 0.05448028f,
+ 0.056128494f, 0.057805434f, 0.05951124f, 0.06124607f, 0.06301003f, 0.06480328f, 0.06662595f, 0.06847818f,
+ 0.07036011f, 0.07227186f, 0.07421358f, 0.07618539f, 0.07818743f, 0.08021983f, 0.082282715f, 0.084376216f,
+ 0.086500466f, 0.088655606f, 0.09084173f, 0.09305898f, 0.095307484f, 0.09758736f, 0.09989874f, 0.10224175f,
+ 0.10461649f, 0.10702311f, 0.10946172f, 0.111932434f, 0.11443538f, 0.116970696f, 0.11953845f, 0.12213881f,
+ 0.12477186f, 0.12743773f, 0.13013652f, 0.13286836f, 0.13563336f, 0.13843165f, 0.14126332f, 0.1441285f,
+ 0.1470273f, 0.14995982f, 0.15292618f, 0.1559265f, 0.15896086f, 0.16202943f, 0.16513224f, 0.16826946f,
+ 0.17144115f, 0.17464745f, 0.17788847f, 0.1811643f, 0.18447503f, 0.1878208f, 0.19120172f, 0.19461787f,
+ 0.19806935f, 0.2015563f, 0.20507877f, 0.2086369f, 0.21223079f, 0.21586053f, 0.21952623f, 0.22322798f,
+ 0.22696589f, 0.23074007f, 0.23455065f, 0.23839766f, 0.2422812f, 0.2462014f, 0.25015837f, 0.25415218f,
+ 0.2581829f, 0.26225072f, 0.26635566f, 0.27049786f, 0.27467737f, 0.27889434f, 0.2831488f, 0.2874409f,
+ 0.2917707f, 0.29613832f, 0.30054384f, 0.30498737f, 0.30946895f, 0.31398875f, 0.31854683f, 0.32314324f,
+ 0.32777813f, 0.33245158f, 0.33716366f, 0.34191445f, 0.3467041f, 0.3515327f, 0.35640025f, 0.36130688f,
+ 0.3662527f, 0.37123778f, 0.37626222f, 0.3813261f, 0.38642952f, 0.39157256f, 0.3967553f, 0.40197787f,
+ 0.4072403f, 0.4125427f, 0.41788515f, 0.42326775f, 0.42869055f, 0.4341537f, 0.43965724f, 0.44520125f,
+ 0.45078585f, 0.45641106f, 0.46207705f, 0.46778384f, 0.47353154f, 0.47932023f, 0.48514998f, 0.4910209f,
+ 0.49693304f, 0.5028866f, 0.50888145f, 0.5149178f, 0.5209957f, 0.52711535f, 0.5332766f, 0.5394797f,
+ 0.5457247f, 0.5520116f, 0.5583406f, 0.5647117f, 0.57112503f, 0.57758063f, 0.5840786f, 0.590619f, 0.597202f,
+ 0.60382754f, 0.61049575f, 0.61720675f, 0.62396055f, 0.63075733f, 0.637597f, 0.6444799f, 0.6514058f,
+ 0.65837497f, 0.66538745f, 0.67244333f, 0.6795426f, 0.68668544f, 0.69387203f, 0.70110214f, 0.70837605f,
+ 0.7156938f, 0.72305536f, 0.730461f, 0.7379107f, 0.7454045f, 0.75294244f, 0.76052475f, 0.7681514f, 0.77582246f,
+ 0.78353804f, 0.79129815f, 0.79910296f, 0.8069525f, 0.8148468f, 0.822786f, 0.8307701f, 0.83879924f, 0.84687346f,
+ 0.8549928f, 0.8631574f, 0.87136734f, 0.8796226f, 0.8879232f, 0.89626956f, 0.90466136f, 0.913099f, 0.92158204f,
+ 0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f
+ };
+
+ private static int linearToSrgb(float c) {
+ if (!(c > MIN_BOUND)) {
+ c = MIN_BOUND;
+ }
+
+ if (c > MAX_BOUND) {
+ c = MAX_BOUND;
+ }
+ int inputBits = Float.floatToRawIntBits(c);
+ int entry = linearToSrgbTable[((inputBits - MIN_BITS) >> 20)];
+
+ int bias = (entry >>> 16) << 9;
+ int scale = entry & 0xffff;
+ int t = (inputBits >>> 12) & 0xff;
+
+ return (bias + (scale * t)) >>> 16;
+ }
+ //////////////
private static int getWidth(TextureAtlasSprite texture)
{
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
return texture.getWidth();
#else
return texture.contents().width();
@@ -111,27 +195,30 @@ public class ClientBlockStateCache
private static int getHeight(TextureAtlasSprite texture)
{
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
return texture.getHeight();
#else
return texture.contents().height();
#endif
}
+
//TODO: Perhaps make this not just use the first frame?
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode)
{
int count = 0;
- double alpha = 0;
+ int alpha = 0;
double red = 0;
double green = 0;
double blue = 0;
int tempColor;
+ //make Chiseled block not render. Since ColorMode is set per block, you only need to check it once
+ if (colorMode != ColorMode.Chisel)
{
// textures normally use u and v instead of x and y
- for (int u = 0; u < getWidth(texture); u++)
+ for (int v = 0; v < getHeight(texture); v++)
{
- for (int v = 0; v < getHeight(texture); v++)
+ for (int u = 0; u < getWidth(texture); u++)
{
//note: Minecraft color format is: 0xAA BB GG RR
//________ DH mod color format is: 0xAA RR GG BB
@@ -139,33 +226,45 @@ public class ClientBlockStateCache
//_ OpenGL RGBA format Java Order: 0xAA BB GG RR
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
- double r = ((tempColor & 0x000000FF)) / 255.;
- double g = ((tempColor & 0x0000FF00) >>> 8) / 255.;
- double b = ((tempColor & 0x00FF0000) >>> 16) / 255.;
- double a = ((tempColor & 0xFF000000) >>> 24) / 255.;
+ int r = (tempColor & 0x000000FF);
+ int g = (tempColor & 0x0000FF00) >>> 8;
+ int b = (tempColor & 0x00FF0000) >>> 16;
+ int a = (tempColor & 0xFF000000) >>> 24;
int scale = 1;
-
if (colorMode == ColorMode.Leaves)
{
- r *= a;
- g *= a;
- b *= a;
- a = 1.;
+ //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
+
}
- else if (a == 0.)
+ else if (a == 0 && colorMode != ColorMode.Glass)
{
continue;
}
- else if (colorMode == ColorMode.Flower && (g + 0.1 < b || g + 0.1 < r))
+ else if (colorMode == ColorMode.Flower && (g + 25 < b || g + 25 < r))
{
scale = FLOWER_COLOR_SCALE;
}
-
count += scale;
- alpha += a * a * scale;
- red += r * r * scale;
- green += g * g * scale;
- blue += b * b * scale;
+ //apparently alpha is linear
+ alpha += a * scale;
+ //gamma correction is complicated
+ red += srgbToLinearTable[r] * a * scale;
+ green += srgbToLinearTable[g] * a * scale;
+ blue += srgbToLinearTable[b] * a * scale;
}
}
}
@@ -177,10 +276,16 @@ public class ClientBlockStateCache
{
// determine the average color
tempColor = ColorUtil.rgbToInt(
- (int) (Math.sqrt(alpha / count) * 255.),
- (int) (Math.sqrt(red / count) * 255.),
- (int) (Math.sqrt(green / count) * 255.),
- (int) (Math.sqrt(blue / count) * 255.));
+ alpha / count,
+ linearToSrgb((float) (red / (double) alpha)),
+ linearToSrgb((float) (green / (double) alpha)),
+ linearToSrgb((float) (blue / (double) alpha)));
+ }
+ //check if not missing texture
+ if (tempColor == ColorUtil.rgbToInt(255, 182, 0, 182))
+ {
+ //make it not render at all
+ tempColor = ColorUtil.rgbToInt(0, 255, 255, 255);
}
return tempColor;
}
@@ -195,7 +300,7 @@ public class ClientBlockStateCache
for (Direction direction : DIRECTION_ORDER)
{
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
- getBlockModel(blockState).getQuads(blockState, direction, random);
+ getBlockModel(blockState).getQuads(blockState, direction, random); // TODO getQuads sometimes throws a "makeThreadingException", is there anything we can do about that? Note: this isn't a critical issue, it just prints an ugly error and the render data will need to be regenered.
if (quads != null && !quads.isEmpty() &&
!(blockState.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP))
break;
@@ -211,7 +316,7 @@ public class ClientBlockStateCache
needShade = quads.get(0).isShade();
tintIndex = quads.get(0).getTintIndex();
baseColor = calculateColorFromTexture(
- #if PRE_MC_1_17_1 quads.get(0).sprite,
+ #if MC_VER < MC_1_17_1 quads.get(0).sprite,
#else quads.get(0).getSprite(), #endif
ColorMode.getColorMode(blockState.getBlock()));
}
@@ -262,7 +367,7 @@ public class ClientBlockStateCache
try
{
tintColor = Minecraft.getInstance().getBlockColors()
- .getColor(this.blockState, new TintWithoutLevelOverrider(biome), McObjectConverter.Convert(pos), this.tintIndex);
+ .getColor(this.blockState, new TintWithoutLevelOverrider(biome, this.levelWrapper), McObjectConverter.Convert(pos), this.tintIndex);
}
catch (UnsupportedOperationException e)
{
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ServerBlockDetailMap.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ServerBlockDetailMap.java
index 453761f53..22dfd9ca8 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ServerBlockDetailMap.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ServerBlockDetailMap.java
@@ -29,7 +29,7 @@ import net.minecraft.world.level.block.state.BlockState;
public class ServerBlockDetailMap
{
private final ConcurrentHashMap blockCache = new ConcurrentHashMap<>();
- //private final ConcurrentHashMap<#if PRE_MC_1_18_2 Biome #else Holder #endif, Biome> biomeMap = new ConcurrentHashMap<>();
+ //private final ConcurrentHashMap<#if MC_VER < MC_1_18_2 Biome #else Holder #endif, Biome> biomeMap = new ConcurrentHashMap<>();
private final ServerLevelWrapper level;
public ServerBlockDetailMap(ServerLevelWrapper level) { this.level = level; }
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkLightStorage.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkLightStorage.java
deleted file mode 100644
index 8d0a465c5..000000000
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkLightStorage.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * This file is part of the Distant Horizons mod
- * licensed under the GNU LGPL v3 License.
- *
- * Copyright (C) 2020-2023 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.common.wrappers.chunk;
-
-import com.seibel.distanthorizons.coreapi.util.BitShiftUtil;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * Compact, efficient storage for light levels.
- * all blocks only take up 4 bits in total,
- * and if a 16x16x16 area is detected to have the same light level in all positions,
- * then we store a single byte for that light level, instead of 2 kilobytes.
- *
- * @author Builderb0y
-*/
-public class ChunkLightStorage
-{
- /** the minimum Y level in the chunk which this storage is storing light levels for (inclusive). */
- public int minY;
- /** the maximum Y level in the chunk which this storage is storing light levels for (exclusive). */
- public int maxY;
-
- /** the data stored in this storage, split up into 16x16x16 areas. */
- public LightSection[] lightSections;
-
-
-
- public ChunkLightStorage(int minY, int maxY)
- {
- this.minY = minY;
- this.maxY = maxY;
- }
-
-
-
- public int get(int x, int y, int z)
- {
- if (y < this.minY)
- {
- return 0;
- }
- if (y >= this.maxY)
- {
- return 15;
- }
-
- if (this.lightSections != null)
- {
- LightSection lightSection = this.lightSections[BitShiftUtil.divideByPowerOfTwo(y - this.minY, 4)];
- if (lightSection != null)
- {
- return lightSection.get(x, y, z);
- }
- }
-
- return 0;
- }
-
- public void set(int x, int y, int z, int lightLevel)
- {
- if (y < this.minY || y >= this.maxY)
- {
- return;
- }
-
- //populate array if it doesn't exist.
- if (this.lightSections == null)
- {
- this.lightSections = new LightSection[BitShiftUtil.divideByPowerOfTwo(this.maxY - this.minY, 4)];
- }
-
- int index = (y - this.minY) >> 4;
- LightSection lightSection = this.lightSections[index];
-
- //populate lightSection in array if it doesn't exist.
- if (lightSection == null)
- {
- lightSection = new LightSection(0);
- this.lightSections[index] = lightSection;
- }
- lightSection.set(x, y, z, lightLevel);
- }
-
-
-
- //================//
- // helper classes //
- //================//
-
- public static class LightSection
- {
- public byte constantValue;
- public long[] data;
- public short[] counts;
-
- public LightSection(int initialValue)
- {
- this.constantValue = (byte) (initialValue);
- this.counts = new short[16];
- this.counts[initialValue] = 16 * 16 * 16;
- }
-
- public int get(int x, int y, int z)
- {
- if (this.constantValue >= 0)
- {
- return this.constantValue;
- }
-
- x &= 15;
- y &= 15;
- z &= 15;
- long bits = this.data[(z << 4) | x];
- return ((int) (bits >>> (y << 2))) & 15;
- }
-
- public void set(int x, int y, int z, int lightLevel)
- {
- int oldLightLevel = -1;
- if (this.constantValue >= 0)
- {
- oldLightLevel = this.constantValue;
-
- //if the light level didn't change, then there's nothing to do.
- if (oldLightLevel == lightLevel) return;
-
- //if we are a constant value and need to change something,
- //then that means we need to convert to a non-constant value.
- this.data = DataRecycler.get();
-
- //repeat oldLightLevel 16 times as a bit pattern.
- long payload = oldLightLevel;
- payload |= payload << 4;
- payload |= payload << 8;
- payload |= payload << 16;
- payload |= payload << 32;
-
- //fill our data with our constant value.
- Arrays.fill(this.data, payload);
-
- //we are no longer a constant value.
- this.constantValue = -1;
- }
-
- x &= 15;
- y &= 15;
- z &= 15;
- int index = (z << 4) | x;
- long bits = this.data[index];
- //if we weren't a constant value before, now's the time to initialize oldLightLevel.
- if (oldLightLevel < 0)
- {
- oldLightLevel = ((int) (bits >>> (y << 2))) & 15;
- }
- //clear the 4 bits that correspond to the light level at x, y, z...
- bits &= ~(15L << (y << 2));
- //...and then re-populate those bits with the new light level.
- bits |= ((long) (lightLevel)) << (y << 2);
- //store the updated bits in our data.
- this.data[index] = bits;
-
- //we have one less of the old light level...
- this.counts[oldLightLevel]--;
- //...and one more of the new level.
- //if the number associated with the new level is now 4096 (AKA 16 ^ 3),
- //then this implies every position in this section has the same light level,
- //and therefore we can convert back to a constant value.
- if (++this.counts[lightLevel] == 4096)
- {
- this.constantValue = (byte) (lightLevel);
- DataRecycler.reclaim(this.data);
- this.data = null;
- }
- }
-
- }
-
- static class DataRecycler
- {
- private static final ArrayList recycled = new ArrayList<>(256);
-
- static synchronized long[] get()
- {
- if (recycled.isEmpty())
- {
- return new long[256];
- }
- else
- {
- return recycled.remove(recycled.size() - 1);
- }
- }
-
- static synchronized void reclaim(long[] data) { if (recycled.size() < 256) recycled.add(data); }
- }
-
-}
\ 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 7f6a203b1..407da88f4 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
@@ -25,20 +25,18 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.Dh
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
-import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
-import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.client.multiplayer.ClientChunkCache;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.chunk.ChunkAccess;
-import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.levelgen.Heightmap;
@@ -47,39 +45,43 @@ import org.apache.logging.log4j.Logger;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
-#if POST_MC_1_17_1
+#if MC_VER >= MC_1_17_1
import net.minecraft.core.QuartPos;
#endif
-#if MC_1_16_5
+#if MC_VER == MC_1_16_5
import net.minecraft.world.level.chunk.LevelChunkSection;
#endif
-#if MC_1_17_1
+#if MC_VER == MC_1_17_1
import net.minecraft.world.level.chunk.LevelChunkSection;
#endif
-#if MC_1_18_2
+#if MC_VER == MC_1_18_2
import net.minecraft.world.level.chunk.LevelChunkSection;
#endif
-#if MC_1_19_2 || MC_1_19_4
+#if MC_VER == MC_1_19_2 || MC_VER == MC_1_19_4
import net.minecraft.world.level.chunk.LevelChunkSection;
#endif
-#if POST_MC_1_20_1
+#if MC_VER >= MC_1_20_1
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.core.SectionPos;
#endif
+#if MC_VER <= MC_1_20_4
+import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+#endif
+
+
public class ChunkWrapper implements IChunkWrapper
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
- /** useful for debugging, but can slow down chunk operations quite a bit due to being called every time. */
- private static final boolean RUN_RELATIVE_POS_INDEX_VALIDATION = ModInfo.IS_DEV_BUILD;
-
/** can be used for interactions with the underlying chunk where creating new BlockPos objects could cause issues for the garbage collector. */
private static final ThreadLocal MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos());
@@ -100,6 +102,11 @@ public class ChunkWrapper implements IChunkWrapper
private boolean useDhLighting;
+ private int minNonEmptyHeight = Integer.MIN_VALUE;
+ private int maxNonEmptyHeight = Integer.MAX_VALUE;
+
+ private int blockBiomeHashCode = 0;
+
/**
* Due to vanilla `isClientLightReady()` not being designed for use by a non-render thread, it may return 'true'
* before the light engine has ticked, (right after all light changes is marked by the engine to be processed).
@@ -139,34 +146,48 @@ public class ChunkWrapper implements IChunkWrapper
//=========//
- // methods //
+ // getters //
//=========//
@Override
- public int getHeight()
+ public int getHeight() { return getHeight(this.chunk); }
+ public static int getHeight(ChunkAccess chunk)
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
return 255;
#else
- return this.chunk.getHeight();
+ return chunk.getHeight();
#endif
}
@Override
- public int getMinBuildHeight()
+ public int getMinBuildHeight() { return getMinBuildHeight(this.chunk); }
+ public static int getMinBuildHeight(ChunkAccess chunk)
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
return 0;
#else
- return this.chunk.getMinBuildHeight();
+ return chunk.getMinBuildHeight();
#endif
}
- @Override
- public int getMaxBuildHeight() { return this.chunk.getMaxBuildHeight(); }
@Override
- public int getMinFilledHeight()
+ public int getMaxBuildHeight() { return getMaxBuildHeight(this.chunk); }
+ public static int getMaxBuildHeight(ChunkAccess chunk) { return chunk.getMaxBuildHeight(); }
+
+ @Override
+ public int getMinNonEmptyHeight()
{
+ if (this.minNonEmptyHeight != Integer.MIN_VALUE)
+ {
+ return this.minNonEmptyHeight;
+ }
+
+
+ // default if every section is empty or missing
+ this.minNonEmptyHeight = this.getMinBuildHeight();
+
+ // determine the lowest empty section (bottom up)
LevelChunkSection[] sections = this.chunk.getSections();
for (int index = 0; index < sections.length; index++)
{
@@ -175,27 +196,65 @@ public class ChunkWrapper implements IChunkWrapper
continue;
}
- #if MC_1_16_5
- if (!sections[index].isEmpty())
+ if (!isChunkSectionEmpty(sections[index]))
{
- // convert from an index to a block coordinate
- return this.chunk.getSections()[index].bottomBlockY() * 16;
+ this.minNonEmptyHeight = this.getChunkSectionMinHeight(index);
+ break;
}
- #elif MC_1_17_1
- if (!sections[index].isEmpty())
- {
- // convert from an index to a block coordinate
- return this.chunk.getSections()[index].bottomBlockY() * 16;
- }
- #else
- if (!sections[index].hasOnlyAir())
- {
- // convert from an index to a block coordinate
- return this.chunk.getSectionYFromSectionIndex(index) * 16;
- }
- #endif
}
- return Integer.MAX_VALUE;
+
+ return this.minNonEmptyHeight;
+ }
+
+
+ @Override
+ public int getMaxNonEmptyHeight()
+ {
+ if (this.maxNonEmptyHeight != Integer.MAX_VALUE)
+ {
+ return this.maxNonEmptyHeight;
+ }
+
+
+ // default if every section is empty or missing
+ this.maxNonEmptyHeight = this.getMaxBuildHeight();
+
+ // determine the highest empty section (top down)
+ LevelChunkSection[] sections = this.chunk.getSections();
+ for (int index = sections.length-1; index >= 0; index--)
+ {
+ if (sections[index] == null)
+ {
+ continue;
+ }
+
+ if (!isChunkSectionEmpty(sections[index]))
+ {
+ this.maxNonEmptyHeight = this.getChunkSectionMinHeight(index) + 16;
+ break;
+ }
+ }
+
+ return this.maxNonEmptyHeight;
+ }
+ private static boolean isChunkSectionEmpty(LevelChunkSection section)
+ {
+ #if MC_VER == MC_1_16_5
+ return section.isEmpty();
+ #elif MC_VER == MC_1_17_1
+ return section.isEmpty();
+ #else
+ return section.hasOnlyAir();
+ #endif
+ }
+ private int getChunkSectionMinHeight(int index)
+ {
+ // convert from an index to a block coordinate
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
+ return this.chunk.getSections()[index].bottomBlockY();
+ #else
+ return this.chunk.getSectionYFromSectionIndex(index) * 16;
+ #endif
}
@@ -206,19 +265,18 @@ public class ChunkWrapper implements IChunkWrapper
public int getLightBlockingHeightMapValue(int xRel, int zRel) { return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING).getFirstAvailable(xRel, zRel); }
-
@Override
public IBiomeWrapper getBiome(int relX, int relY, int relZ)
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
return BiomeWrapper.getBiomeWrapper(this.chunk.getBiomes().getNoiseBiome(
relX >> 2, relY >> 2, relZ >> 2),
this.wrappedLevel);
- #elif PRE_MC_1_18_2
+ #elif MC_VER < MC_1_18_2
return BiomeWrapper.getBiomeWrapper(this.chunk.getBiomes().getNoiseBiome(
QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)),
this.wrappedLevel);
- #elif PRE_MC_1_18_2
+ #elif MC_VER < MC_1_18_2
return BiomeWrapper.getBiomeWrapper(this.chunk.getNoiseBiome(
QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)),
this.wrappedLevel);
@@ -230,11 +288,35 @@ public class ChunkWrapper implements IChunkWrapper
#endif
}
+ @Override
+ public IBlockStateWrapper getBlockState(int relX, int relY, int relZ)
+ {
+ this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
+
+ BlockPos.MutableBlockPos blockPos = MUTABLE_BLOCK_POS_REF.get();
+
+ blockPos.setX(relX);
+ blockPos.setY(relY);
+ blockPos.setZ(relZ);
+
+ return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel);
+ }
+
@Override
public DhChunkPos getChunkPos() { return this.chunkPos; }
public ChunkAccess getChunk() { return this.chunk; }
+ public ChunkStatus getStatus() { return getStatus(this.getChunk()); }
+ public static ChunkStatus getStatus(ChunkAccess chunk)
+ {
+ #if MC_VER < MC_1_21
+ return chunk.getStatus();
+ #else
+ return chunk.getPersistedStatus();
+ #endif
+ }
+
@Override
public int getMaxBlockX() { return this.chunk.getPos().getMaxBlockX(); }
@Override
@@ -244,8 +326,11 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public int getMinBlockZ() { return this.chunk.getPos().getMinBlockZ(); }
- @Override
- public long getLongChunkPos() { return this.chunk.getPos().toLong(); }
+
+
+ //==========//
+ // lighting //
+ //==========//
@Override
public void setIsDhLightCorrect(boolean isDhLightCorrect) { this.isDhLightCorrect = isDhLightCorrect; }
@@ -253,8 +338,6 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public void setUseDhLighting(boolean useDhLighting) { this.useDhLighting = useDhLighting; }
-
-
@Override
public boolean isLightCorrect()
{
@@ -264,7 +347,7 @@ public class ChunkWrapper implements IChunkWrapper
}
- #if MC_1_16_5 || MC_1_17_1
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
return false; // MC's lighting engine doesn't work consistently enough to trust for 1.16 or 1.17
#else
if (this.chunk instanceof LevelChunk)
@@ -307,10 +390,11 @@ public class ChunkWrapper implements IChunkWrapper
{
if (this.blockLightStorage == null)
{
- this.blockLightStorage = new ChunkLightStorage(this.getMinBuildHeight(), this.getMaxBuildHeight());
+ this.blockLightStorage = ChunkLightStorage.createBlockLightStorage(this);
}
return this.blockLightStorage;
}
+ public void setBlockLightStorage(ChunkLightStorage lightStorage) { this.blockLightStorage = lightStorage; }
@Override
@@ -330,10 +414,11 @@ public class ChunkWrapper implements IChunkWrapper
{
if (this.skyLightStorage == null)
{
- this.skyLightStorage = new ChunkLightStorage(this.getMinBuildHeight(), this.getMaxBuildHeight());
+ this.skyLightStorage = ChunkLightStorage.createSkyLightStorage(this);
}
return this.skyLightStorage;
}
+ public void setSkyLightStorage(ChunkLightStorage lightStorage) { this.skyLightStorage = lightStorage; }
@Override
@@ -374,8 +459,12 @@ public class ChunkWrapper implements IChunkWrapper
}
}
+ /**
+ * FIXME synchronized is necessary for a rare issue where this method is called from two separate threads at the same time
+ * before the list has finished populating.
+ */
@Override
- public ArrayList getBlockLightPosList()
+ public synchronized ArrayList getBlockLightPosList()
{
// only populate the list once
if (this.blockLightPosList == null)
@@ -383,7 +472,7 @@ public class ChunkWrapper implements IChunkWrapper
this.blockLightPosList = new ArrayList<>();
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
this.chunk.getLights().forEach((blockPos) ->
{
this.blockLightPosList.add(new DhBlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ()));
@@ -399,6 +488,69 @@ public class ChunkWrapper implements IChunkWrapper
return this.blockLightPosList;
}
+ public static void syncedUpdateClientLightStatus()
+ {
+ #if MC_VER < MC_1_18_2
+ // TODO: Check what to do in 1.18.1 and older
+
+ // since we don't currently handle this list,
+ // clear it to prevent memory leaks
+ chunksNeedingClientLightUpdating.clear();
+
+ #else
+
+ // update the chunks client lighting
+ ChunkWrapper chunkWrapper = chunksNeedingClientLightUpdating.poll();
+ while (chunkWrapper != null)
+ {
+ chunkWrapper.updateIsClientLightingCorrect();
+ chunkWrapper = chunksNeedingClientLightUpdating.poll();
+ }
+
+ #endif
+ }
+ /** Should be called after client light updates are triggered. */
+ private void updateIsClientLightingCorrect()
+ {
+ if (this.chunk instanceof LevelChunk && ((LevelChunk) this.chunk).getLevel() instanceof ClientLevel)
+ {
+ LevelChunk levelChunk = (LevelChunk) this.chunk;
+ ClientChunkCache clientChunkCache = ((ClientLevel) levelChunk.getLevel()).getChunkSource();
+ this.isMcClientLightingCorrect = clientChunkCache.getChunkForLighting(this.chunk.getPos().x, this.chunk.getPos().z) != null &&
+ #if MC_VER <= MC_1_17_1
+ levelChunk.isLightCorrect();
+ #elif MC_VER < MC_1_20_1
+ levelChunk.isClientLightReady();
+ #else
+ checkLightSectionsOnChunk(levelChunk, levelChunk.getLevel().getLightEngine());
+ #endif
+ }
+ }
+ #if MC_VER >= MC_1_20_1
+ private static boolean checkLightSectionsOnChunk(LevelChunk chunk, LevelLightEngine engine)
+ {
+ LevelChunkSection[] sections = chunk.getSections();
+ int minY = chunk.getMinSection();
+ int maxY = chunk.getMaxSection();
+ for (int y = minY; y < maxY; ++y)
+ {
+ LevelChunkSection section = sections[chunk.getSectionIndexFromSectionY(y)];
+ if (section.hasOnlyAir()) continue;
+ if (!engine.lightOnInSection(SectionPos.of(chunk.getPos(), y)))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ #endif
+
+
+
+ //===============//
+ // other methods //
+ //===============//
+
@Override
public boolean doNearbyChunksExist()
{
@@ -425,146 +577,27 @@ public class ChunkWrapper implements IChunkWrapper
return true;
}
- public LevelReader getColorResolver() { return this.lightSource; }
-
- @Override
- public String toString() { return this.chunk.getClass().getSimpleName() + this.chunk.getPos(); }
-
- @Override
- public IBlockStateWrapper getBlockState(int relX, int relY, int relZ)
- {
- this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
-
- BlockPos.MutableBlockPos blockPos = MUTABLE_BLOCK_POS_REF.get();
-
- blockPos.setX(relX);
- blockPos.setY(relY);
- blockPos.setZ(relZ);
-
- return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel);
- }
-
@Override
public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; }
- public static void syncedUpdateClientLightStatus()
- {
- #if PRE_MC_1_18_2
- // TODO: Check what to do in 1.18.1 and older
-
- // since we don't currently handle this list,
- // clear it to prevent memory leaks
- chunksNeedingClientLightUpdating.clear();
-
- #else
-
- // update the chunks client lighting
- ChunkWrapper chunkWrapper = chunksNeedingClientLightUpdating.poll();
- while (chunkWrapper != null)
- {
- chunkWrapper.updateIsClientLightingCorrect();
- chunkWrapper = chunksNeedingClientLightUpdating.poll();
- }
-
- #endif
- }
- /** Should be called after client light updates are triggered. */
- private void updateIsClientLightingCorrect()
- {
- if (this.chunk instanceof LevelChunk && ((LevelChunk) this.chunk).getLevel() instanceof ClientLevel)
- {
- LevelChunk levelChunk = (LevelChunk) this.chunk;
- ClientChunkCache clientChunkCache = ((ClientLevel) levelChunk.getLevel()).getChunkSource();
- this.isMcClientLightingCorrect = clientChunkCache.getChunkForLighting(this.chunk.getPos().x, this.chunk.getPos().z) != null &&
- #if MC_1_16_5 || MC_1_17_1
- levelChunk.isLightCorrect();
- #elif PRE_MC_1_20_1
- levelChunk.isClientLightReady();
- #else
- checkLightSectionsOnChunk(levelChunk, levelChunk.getLevel().getLightEngine());
- #endif
- }
- }
- #if POST_MC_1_20_1
- private static boolean checkLightSectionsOnChunk(LevelChunk chunk, LevelLightEngine engine)
- {
- LevelChunkSection[] sections = chunk.getSections();
- int minY = chunk.getMinSection();
- int maxY = chunk.getMaxSection();
- for (int y = minY; y < maxY; ++y)
- {
- LevelChunkSection section = sections[chunk.getSectionIndexFromSectionY(y)];
- if (section.hasOnlyAir()) continue;
- if (!engine.lightOnInSection(SectionPos.of(chunk.getPos(), y)))
- {
- return false;
- }
- }
- return true;
- }
- #endif
-
-
//================//
- // helper methods //
+ // base overrides //
//================//
- /** used to prevent accidentally attempting to get/set values outside this chunk's boundaries */
- private void throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(int x, int y, int z) throws IndexOutOfBoundsException
- {
- if (!RUN_RELATIVE_POS_INDEX_VALIDATION)
- {
- return;
- }
-
-
- // FIXME +1 is to handle the fact that LodDataBuilder adds +1 to all block lighting calculations, also done in the constructor
- int minHeight = this.getMinBuildHeight();
- int maxHeight = this.getMaxBuildHeight() + 1;
-
- if (x < 0 || x >= LodUtil.CHUNK_WIDTH
- || z < 0 || z >= LodUtil.CHUNK_WIDTH
- || y < minHeight || y > maxHeight)
- {
- String errorMessage = "Relative position [" + x + "," + y + "," + z + "] out of bounds. \n" +
- "X/Z must be between 0 and 15 (inclusive) \n" +
- "Y must be between [" + minHeight + "] and [" + maxHeight + "] (inclusive).";
- throw new IndexOutOfBoundsException(errorMessage);
- }
- }
-
-
- /**
- * Converts a 3D position into a 1D array index.
- *
- * Source:
- * stackoverflow
- */
- public int relativeBlockPosToIndex(int xRel, int y, int zRel)
- {
- int yRel = y - this.getMinBuildHeight();
- return (zRel * LodUtil.CHUNK_WIDTH * this.getHeight()) + (yRel * LodUtil.CHUNK_WIDTH) + xRel;
- }
-
- /**
- * Converts a 3D position into a 1D array index.
- *
- * Source:
- * stackoverflow
- */
- public DhBlockPos indexToRelativeBlockPos(int index)
- {
- final int zRel = index / (LodUtil.CHUNK_WIDTH * this.getHeight());
- index -= (zRel * LodUtil.CHUNK_WIDTH * this.getHeight());
-
- final int y = index / LodUtil.CHUNK_WIDTH;
- final int yRel = y + this.getMinBuildHeight();
-
- final int xRel = index % LodUtil.CHUNK_WIDTH;
- return new DhBlockPos(xRel, yRel, zRel);
- }
+ @Override
+ public String toString() { return this.chunk.getClass().getSimpleName() + this.chunk.getPos(); }
+ //@Override
+ //public int hashCode()
+ //{
+ // if (this.blockBiomeHashCode == 0)
+ // {
+ // this.blockBiomeHashCode = this.getBlockBiomeHashCode();
+ // }
+ //
+ // return this.blockBiomeHashCode;
+ //}
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/ClassicConfigGUI.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/ClassicConfigGUI.java
index ac5a98482..ffb8d9412 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/ClassicConfigGUI.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/ClassicConfigGUI.java
@@ -16,7 +16,7 @@ import java.util.regex.Pattern;
// Logger (for debug stuff)
import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui;
-import com.seibel.distanthorizons.api.enums.config.EUpdateBranch;
+import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.config.types.*;
@@ -35,7 +35,7 @@ import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
-#if PRE_MC_1_20_1
+#if MC_VER < MC_1_20_1
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.GuiComponent;
#else
@@ -49,7 +49,7 @@ import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraft.client.resources.language.I18n; // translation
-#if POST_MC_1_17_1
+#if MC_VER >= MC_1_17_1
import net.minecraft.client.gui.narration.NarratableEntry;
#endif
import net.minecraft.resources.ResourceLocation;
@@ -98,6 +98,7 @@ public class ClassicConfigGUI
public static final int SpaceFromRightScreen = 10;
public static final int ButtonWidthSpacing = 5;
public static final int ResetButtonWidth = 40;
+ public static final int ResetButtonHeight = 20;
}
@@ -244,17 +245,23 @@ public class ClassicConfigGUI
}
// Changelog button
- if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() && Config.Client.Advanced.AutoUpdater.updateBranch.get() == EUpdateBranch.STABLE)
+ if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() && !ModInfo.IS_DEV_BUILD) // we only have changelogs for stable builds
{
this.addBtn(new TexturedButtonWidget(
// Where the button is on the screen
this.width - 28, this.height - 28,
// Width and height of the button
20, 20,
- // Offset
+ // texture UV Offset
0, 0,
// Some textuary stuff
- 0, new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"), 20, 20,
+ 0,
+ #if MC_VER < MC_1_21
+ new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
+ #else
+ ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
+ #endif
+ 20, 20,
// Create the button and tell it where to go
(buttonWidget) -> {
ChangelogScreen changelogScreen = new ChangelogScreen(this);
@@ -269,18 +276,25 @@ public class ClassicConfigGUI
}
- addBtn(MakeBtn(Translatable("distanthorizons.general.cancel"), this.width / 2 - 154, this.height - 28, 150, 20, button -> {
- ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile();
- Objects.requireNonNull(minecraft).setScreen(parent);
- }));
+ addBtn(MakeBtn(Translatable("distanthorizons.general.cancel"),
+ this.width / 2 - 154, this.height - 28,
+ 150, 20,
+ button ->
+ {
+ ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile();
+ Objects.requireNonNull(minecraft).setScreen(parent);
+ }));
doneButton = addBtn(MakeBtn(Translatable("distanthorizons.general.done"), this.width / 2 + 4, this.height - 28, 150, 20, (button) -> {
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
Objects.requireNonNull(minecraft).setScreen(parent);
}));
this.list = new ConfigListWidget(this.minecraft, this.width * 2, this.height, 32, 32, 25);
+
+ #if MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
if (this.minecraft != null && this.minecraft.level != null)
this.list.setRenderBackground(false);
+ #endif
this.addWidget(this.list);
@@ -311,6 +325,7 @@ public class ClassicConfigGUI
initEntry(info, this.translationPrefix);
Component name = Translatable(translationPrefix + info.getNameWCategory());
+
if (ConfigEntry.class.isAssignableFrom(info.getClass()))
{
Button.OnPress btnAction = button -> {
@@ -319,12 +334,12 @@ public class ClassicConfigGUI
this.reload = true;
Objects.requireNonNull(minecraft).setScreen(this);
};
- int a = this.width - ConfigScreenConfigs.SpaceFromRightScreen - 150 - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth;
- int b = 0;
- int c = ConfigScreenConfigs.ResetButtonWidth;
- int d = 20;
+ int posX = this.width - ConfigScreenConfigs.SpaceFromRightScreen - 150 - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth;
+ int posZ = 0;
- Button resetButton = MakeBtn(Translatable("distanthorizons.general.reset").withStyle(ChatFormatting.RED), a, b, c, d, btnAction);
+ Button resetButton = MakeBtn(Translatable("distanthorizons.general.reset").withStyle(ChatFormatting.RED),
+ posX, posZ, ConfigScreenConfigs.ResetButtonWidth, ConfigScreenConfigs.ResetButtonHeight,
+ btnAction);
if (((EntryInfo) info.guiValue).widget instanceof Map.Entry)
{
@@ -379,13 +394,13 @@ public class ClassicConfigGUI
}
@Override
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
public void render(PoseStack matrices, int mouseX, int mouseY, float delta)
#else
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
#endif
{
- #if PRE_MC_1_20_2 // 1.20.2 now enables this by default in the `this.list.render` function
+ #if MC_VER < MC_1_20_2 // 1.20.2 now enables this by default in the `this.list.render` function
this.renderBackground(matrices); // Renders background
#else
super.render(matrices, mouseX, mouseY, delta);
@@ -441,7 +456,7 @@ public class ClassicConfigGUI
}
}
}
- #if PRE_MC_1_20_2
+ #if MC_VER < MC_1_20_2
super.render(matrices, mouseX, mouseY, delta);
#endif
}
@@ -539,7 +554,7 @@ public class ClassicConfigGUI
public ConfigListWidget(Minecraft minecraftClient, int canvasWidth, int canvasHeight, int topMargin, int botMargin, int itemSpacing)
{
- #if PRE_MC_1_20_4
+ #if MC_VER < MC_1_20_4
super(minecraftClient, canvasWidth, canvasHeight, topMargin, canvasHeight - botMargin, itemSpacing);
#else
super(minecraftClient, canvasWidth, canvasHeight - (topMargin + botMargin), topMargin, itemSpacing);
@@ -605,7 +620,7 @@ public class ClassicConfigGUI
}
@Override
- #if PRE_MC_1_20_1
+ #if 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)
#else
public void render(GuiGraphics matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
@@ -627,7 +642,7 @@ public class ClassicConfigGUI
indexButton.render(matrices, mouseX, mouseY, tickDelta);
}
if (text != null && (!text.getString().contains("spacer") || button != null))
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF);
#else
matrices.drawString(textRenderer, text, 12, y + 5, 0xFFFFFF);
@@ -642,7 +657,7 @@ public class ClassicConfigGUI
// Only for 1.17 and over
// Remove in 1.16 and below
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
@Override
public List extends NarratableEntry> narratables()
{
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 fbeb7f4c3..5309e6565 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,7 +1,7 @@
package com.seibel.distanthorizons.common.wrappers.gui;
import net.minecraft.client.gui.Font;
-#if PRE_MC_1_20_1
+#if MC_VER < MC_1_20_1
import com.mojang.blaze3d.vertex.PoseStack;
#else
import net.minecraft.client.gui.GuiGraphics;
@@ -24,14 +24,14 @@ public class DhScreen extends Screen
// addButton in 1.16 and below
protected Button addBtn(Button button)
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
return this.addButton(button);
#else
return this.addRenderableWidget(button);
#endif
}
- #if PRE_MC_1_20_1
+ #if 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);
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 9e1a165a0..90c9299a5 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
@@ -36,7 +36,7 @@ public class GetConfigScreen
case JavaFX:
return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new ConfigScreen()), ModInfo.ID + ".title");
default:
- return null;
+ throw new IllegalArgumentException("No config screen implementation defined for ["+useScreen+"].");
}
}
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 1bd0655a1..46fe7010d 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
@@ -5,7 +5,7 @@ import net.minecraft.client.gui.components.Button;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
-#if PRE_MC_1_19_2
+#if MC_VER < MC_1_19_2
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
#endif
@@ -15,18 +15,18 @@ public class GuiHelper
/**
* Helper static methods for versional compat
*/
- public static Button MakeBtn(Component base, int a, int b, int c, int d, Button.OnPress action)
+ public static Button MakeBtn(Component base, int posX, int posZ, int width, int height, Button.OnPress action)
{
- #if PRE_MC_1_19_4
- return new Button(a, b, c, d, base, action);
+ #if MC_VER < MC_1_19_4
+ return new Button(posX, posZ, width, height, base, action);
#else
- return Button.builder(base, action).bounds(a, b, c, d).build();
+ return Button.builder(base, action).bounds(posX, posZ, width, height).build();
#endif
}
public static MutableComponent TextOrLiteral(String text)
{
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
return new TextComponent(text);
#else
return Component.literal(text);
@@ -35,7 +35,7 @@ public class GuiHelper
public static MutableComponent TextOrTranslatable(String text)
{
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
return new TextComponent(text);
#else
return Component.translatable(text);
@@ -44,7 +44,7 @@ public class GuiHelper
public static MutableComponent Translatable(String text, Object... args)
{
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
return new TranslatableComponent(text, args);
#else
return Component.translatable(text, args);
@@ -53,7 +53,7 @@ public class GuiHelper
public static void SetX(AbstractWidget w, int x)
{
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
w.x = x;
#else
w.setX(x);
@@ -62,7 +62,7 @@ public class GuiHelper
public static void SetY(AbstractWidget w, int y)
{
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
w.y = y;
#else
w.setY(y);
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 aaa804181..2efa317c1 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
@@ -4,7 +4,7 @@ import com.mojang.blaze3d.platform.Window;
import com.mojang.blaze3d.vertex.PoseStack;
import com.seibel.distanthorizons.core.config.gui.AbstractScreen;
import net.minecraft.client.Minecraft;
-#if POST_MC_1_20_1
+#if MC_VER >= MC_1_20_1
import net.minecraft.client.gui.GuiGraphics;
#endif
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
@@ -28,7 +28,7 @@ public class MinecraftScreen
private AbstractScreen screen;
- #if PRE_MC_1_19_2
+ #if 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);
@@ -60,19 +60,23 @@ public class MinecraftScreen
screen.init(); // Init our own config screen
this.list = new ConfigListWidget(this.minecraft, this.width, this.height, 0, 0, 25); // Select the area to tint
+
+ #if 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.list.setRenderBackground(false); // Disable from rendering
+ #endif
+
this.addWidget(this.list); // Add the tint to the things to be rendered
}
@Override
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
public void render(PoseStack matrices, int mouseX, int mouseY, float delta)
#else
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
#endif
{
- #if PRE_MC_1_20_2
+ #if MC_VER < MC_1_20_2
this.renderBackground(matrices); // Render background
#else
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
@@ -133,7 +137,7 @@ public class MinecraftScreen
{
public ConfigListWidget(Minecraft minecraftClient, int canvasWidth, int canvasHeight, int topMargin, int botMargin, int itemSpacing)
{
- #if PRE_MC_1_20_4
+ #if MC_VER < MC_1_20_4
super(minecraftClient, canvasWidth, canvasHeight, topMargin, canvasHeight - botMargin, itemSpacing);
#else
super(minecraftClient, canvasWidth, canvasHeight - (topMargin + botMargin), topMargin, itemSpacing);
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 866ef61c7..c69a9ad49 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
@@ -34,17 +34,17 @@ import net.minecraft.client.gui.components.ImageButton;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
-#if POST_MC_1_17_1
+#if MC_VER >= MC_1_17_1
import net.minecraft.client.renderer.GameRenderer;
#endif
-#if PRE_MC_1_20_1
+#if MC_VER < MC_1_20_1
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
#else
import net.minecraft.client.gui.GuiGraphics;
#endif
-#if PRE_MC_1_20_2
+#if MC_VER < MC_1_20_2
public class TexturedButtonWidget extends ImageButton
#else
public class TexturedButtonWidget extends Button
@@ -52,7 +52,7 @@ public class TexturedButtonWidget extends Button
{
public final boolean renderBackground;
- #if POST_MC_1_20_2
+ #if MC_VER >= MC_1_20_2
private final int u;
private final int v;
private final int hoveredVOffset;
@@ -69,7 +69,7 @@ public class TexturedButtonWidget extends Button
}
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation texture, int textureWidth, int textureHeight, OnPress pressAction, Component text, boolean renderBackground)
{
- #if PRE_MC_1_20_2
+ #if MC_VER < MC_1_20_2
super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction, text);
#else
// We don't pass on the text option as otherwise it will render (we normally pass it for narration)
@@ -89,13 +89,13 @@ public class TexturedButtonWidget extends Button
this.renderBackground = renderBackground;
}
- #if PRE_MC_1_20_2
- #if PRE_MC_1_19_4
+ #if 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) {
if (this.renderBackground) // Renders the background of the button
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
Minecraft.getInstance().getTextureManager().bind(WIDGETS_LOCATION);
RenderSystem.color4f(1.0F, 1.0F, 1.0F, this.alpha);
#else
@@ -108,7 +108,7 @@ public class TexturedButtonWidget extends Button
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.enableDepthTest();
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
this.blit(matrices, this.x, this.y, 0, 46 + i * 20, this.width / 2, this.height);
this.blit(matrices, this.x + this.width / 2, this.y, 200 - this.width / 2, 46 + i * 20, this.width / 2, this.height);
#else
@@ -120,7 +120,7 @@ public class TexturedButtonWidget extends Button
super.renderButton(matrices, mouseX, mouseY, delta);
}
#else
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
@Override
public void renderWidget(PoseStack matrices, int mouseX, int mouseY, float delta)
{
@@ -138,7 +138,7 @@ public class TexturedButtonWidget extends Button
if (!this.active) i = 0;
else if (this.isHovered) i = 2;
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.enableDepthTest();
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/updater/ChangelogScreen.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/updater/ChangelogScreen.java
index 0b3b493db..76adb6d58 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/updater/ChangelogScreen.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/updater/ChangelogScreen.java
@@ -15,11 +15,11 @@ import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
-#if POST_MC_1_17_1
+#if MC_VER >= MC_1_17_1
import net.minecraft.client.gui.narration.NarratableEntry;
#endif
-#if PRE_MC_1_20_1
+#if MC_VER < MC_1_20_1
import net.minecraft.client.gui.GuiComponent;
#else
import net.minecraft.client.gui.GuiGraphics;
@@ -144,13 +144,13 @@ public class ChangelogScreen extends DhScreen
}
@Override
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
public void render(PoseStack matrices, int mouseX, int mouseY, float delta)
#else
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
#endif
{
- #if PRE_MC_1_20_2
+ #if MC_VER < MC_1_20_2
this.renderBackground(matrices); // Render background
#else
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
@@ -161,17 +161,16 @@ public class ChangelogScreen extends DhScreen
// Set the scroll position to the mouse height relative to the screen
// This is a bit of a hack as we cannot scroll on this area
double scrollAmount = ((double) mouseY) / ((double) this.height) * 1.1 * this.changelogArea.getMaxScroll();
- #if MC_1_16_5 || MC_1_17_1
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
this.changelogArea.setScrollAmount(scrollAmount);
#else
this.changelogArea.scrollAmount = scrollAmount;
#endif
- this.changelogArea.render(matrices, mouseX, mouseY, delta); // Render the changelog
-
+ // render order matters, otherwise on 1.20.6+ the blurred background will render on top of the text
super.render(matrices, mouseX, mouseY, delta); // Render the buttons
-
+ this.changelogArea.render(matrices, mouseX, mouseY, delta); // Render the changelog
DhDrawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
}
@@ -187,7 +186,7 @@ public class ChangelogScreen extends DhScreen
public TextArea(Minecraft minecraftClient, int canvasWidth, int canvasHeight, int topMargin, int botMargin, int itemSpacing)
{
- #if PRE_MC_1_20_4
+ #if MC_VER < MC_1_20_4
super(minecraftClient, canvasWidth, canvasHeight, topMargin, canvasHeight - botMargin, itemSpacing);
#else
super(minecraftClient, canvasWidth, canvasHeight - (topMargin + botMargin), topMargin, itemSpacing);
@@ -225,7 +224,7 @@ public class ChangelogScreen extends DhScreen
return new ButtonEntry(text);
}
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
@Override
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
{
@@ -244,7 +243,7 @@ public class ChangelogScreen extends DhScreen
{
return children;
}
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
@Override
public List extends NarratableEntry> narratables()
{
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/updater/UpdateModScreen.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/updater/UpdateModScreen.java
index 5addfc306..f4d52e9d6 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/updater/UpdateModScreen.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/gui/updater/UpdateModScreen.java
@@ -1,23 +1,19 @@
package com.seibel.distanthorizons.common.wrappers.gui.updater;
-import com.mojang.blaze3d.platform.NativeImage;
-import com.seibel.distanthorizons.api.enums.config.EUpdateBranch;
+import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
import com.seibel.distanthorizons.common.wrappers.gui.DhScreen;
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
import com.seibel.distanthorizons.core.jar.ModJarInfo;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.config.Config;
-import com.seibel.distanthorizons.core.jar.JarUtils;
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
-import net.minecraft.client.Minecraft;
-#if POST_MC_1_20_1
+#if MC_VER >= MC_1_20_1
import net.minecraft.client.gui.GuiGraphics;
#else
import com.mojang.blaze3d.vertex.PoseStack;
#endif
import net.minecraft.client.gui.screens.Screen;
-import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.resources.ResourceLocation;
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
@@ -45,16 +41,18 @@ public class UpdateModScreen extends DhScreen
super(Translatable(ModInfo.ID + ".updater.title"));
this.parent = parent;
this.newVersionID = newVersionID;
-
- switch (Config.Client.Advanced.AutoUpdater.updateBranch.get()) {
- case STABLE:
- currentVer = ModInfo.VERSION;
- nextVer = ModrinthGetter.releaseNames.get(this.newVersionID);
- break;
- case NIGHTLY:
- currentVer = ModJarInfo.Git_Commit.substring(0,7);
- nextVer = this.newVersionID.substring(0,7);
- break;
+
+
+ EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
+ if (updateBranch == EDhApiUpdateBranch.STABLE)
+ {
+ this.currentVer = ModInfo.VERSION;
+ this.nextVer = ModrinthGetter.releaseNames.get(this.newVersionID);
+ }
+ else
+ {
+ this.currentVer = ModJarInfo.Git_Commit.substring(0,7);
+ this.nextVer = this.newVersionID.substring(0,7);
}
}
@@ -66,13 +64,6 @@ public class UpdateModScreen extends DhScreen
try
{
- // We cannot get assets from the root of the mod so we use this hack
- // TODO: Load the icon.png and logo.png in the mod initialise rather than here
- ResourceLocation logoLocation = new ResourceLocation(ModInfo.ID, "logo.png");
- Minecraft.getInstance().getTextureManager().register(
- logoLocation,
- new DynamicTexture(NativeImage.read(JarUtils.accessFile("logo.png")))
- );
// Logo image
@@ -84,7 +75,13 @@ public class UpdateModScreen extends DhScreen
// Offset
0, 0,
// Some textuary stuff
- 0, logoLocation, 130, 65,
+ 0,
+ #if MC_VER < MC_1_21
+ new ResourceLocation(ModInfo.ID, "logo.png"),
+ #else
+ ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "logo.png"),
+ #endif
+ 130, 65,
// Create the button and tell it where to go
// For now it goes to the client option by default
(buttonWidget) -> System.out.println("Nice, you found an easter egg :)"), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
@@ -99,7 +96,7 @@ public class UpdateModScreen extends DhScreen
e.printStackTrace();
}
- if (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EUpdateBranch.STABLE)
+ if (!ModInfo.IS_DEV_BUILD)
{
this.addBtn(new TexturedButtonWidget(
// Where the button is on the screen
@@ -109,7 +106,13 @@ public class UpdateModScreen extends DhScreen
// Offset
0, 0,
// Some textuary stuff
- 0, new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"), 20, 20,
+ 0,
+ #if MC_VER < MC_1_21
+ new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
+ #else
+ ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
+ #endif
+ 20, 20,
// Create the button and tell it where to go
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(new ChangelogScreen(this, this.newVersionID)), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
// Add a title to the button
@@ -146,29 +149,27 @@ public class UpdateModScreen extends DhScreen
}
@Override
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
public void render(PoseStack matrices, int mouseX, int mouseY, float delta)
#else
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
#endif
{
- #if PRE_MC_1_20_2
+ #if MC_VER < MC_1_20_2
this.renderBackground(matrices); // Render background
#else
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
#endif
+ // TODO: add the tooltips for the buttons
+ super.render(matrices, mouseX, mouseY, delta); // Render the buttons
+ // TODO: Add tooltips
// Render the text's
DhDrawCenteredString(matrices, this.font, Translatable(ModInfo.ID + ".updater.text1"), this.width / 2, this.height / 2 - 35, 0xFFFFFF);
DhDrawCenteredString(matrices, this.font,
Translatable(ModInfo.ID + ".updater.text2", currentVer, nextVer),
this.width / 2, this.height / 2 - 20, 0x52FD52);
-
- // TODO: add the tooltips for the buttons
- super.render(matrices, mouseX, mouseY, delta); // Render the buttons
-
- // TODO: Add tooltips
}
@Override
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftClientWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftClientWrapper.java
index 208387960..e7df9f1bc 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftClientWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftClientWrapper.java
@@ -25,7 +25,7 @@ import java.util.ArrayList;
import java.util.UUID;
import com.mojang.blaze3d.platform.NativeImage;
-import com.seibel.distanthorizons.api.enums.config.ELodShading;
+import com.seibel.distanthorizons.api.enums.config.EDhApiLodShading;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
@@ -47,7 +47,7 @@ import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
-#if PRE_MC_1_19_2
+#if MC_VER < MC_1_19_2
import net.minecraft.network.chat.TextComponent;
#endif
import net.minecraft.server.level.ServerLevel;
@@ -113,11 +113,11 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
@Override
public float getShade(EDhDirection lodDirection)
{
- ELodShading lodShading = Config.Client.Advanced.Graphics.AdvancedGraphics.lodShading.get();
+ EDhApiLodShading lodShading = Config.Client.Advanced.Graphics.AdvancedGraphics.lodShading.get();
switch (lodShading)
{
default:
- case MINECRAFT:
+ case AUTO:
if (this.mc.level != null)
{
Direction mcDir = McObjectConverter.Convert(lodDirection);
@@ -128,7 +128,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
return 0.0f;
}
- case OLD_LIGHTING:
+ case ENABLED:
switch (lodDirection)
{
case DOWN:
@@ -144,7 +144,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
return 0.6F;
}
- case NONE:
+ case DISABLED:
return 1.0F;
}
}
@@ -197,7 +197,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
@Override
public DhChunkPos getPlayerChunkPos()
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
ChunkPos playerPos = new ChunkPos(getPlayer().blockPosition());
#else
ChunkPos playerPos = getPlayer().chunkPosition();
@@ -262,7 +262,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
{
LocalPlayer p = getPlayer();
if (p == null) return;
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
p.sendMessage(new TextComponent(string), getPlayer().getUUID());
#else
p.sendSystemMessage(net.minecraft.network.chat.Component.translatable(string));
@@ -282,7 +282,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
{
LOGGER.error(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft...", exception);
CrashReport report = new CrashReport(errorMessage, exception);
- #if PRE_MC_1_20_4
+ #if MC_VER < MC_1_20_4
Minecraft.crash(report);
#else
Minecraft.getInstance().delayCrash(report);
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftDedicatedServerWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftDedicatedServerWrapper.java
index af701e598..bf09dc1bd 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftDedicatedServerWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftDedicatedServerWrapper.java
@@ -12,16 +12,20 @@ public class MinecraftDedicatedServerWrapper implements IMinecraftSharedWrapper
private MinecraftDedicatedServerWrapper() { }
public DedicatedServer dedicatedServer = null;
@Override
- public boolean isDedicatedServer()
- {
- return true;
- }
+ public boolean isDedicatedServer() { return true; }
@Override
public File getInstallationDirectory()
{
- if (dedicatedServer == null)
+ if (this.dedicatedServer == null)
+ {
throw new IllegalStateException("Trying to get Installation Direction before Dedicated server complete initialization!");
- return dedicatedServer.getServerDirectory();
+ }
+
+ #if MC_VER < MC_1_21
+ return this.dedicatedServer.getServerDirectory();
+ #else
+ return this.dedicatedServer.getServerDirectory().toFile();
+ #endif
}
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftRenderWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftRenderWrapper.java
index 6a05e158f..98fc1c3d3 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftRenderWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftRenderWrapper.java
@@ -21,9 +21,11 @@ package com.seibel.distanthorizons.common.wrappers.minecraft;
import java.awt.Color;
import java.lang.invoke.MethodHandles;
+import java.nio.FloatBuffer;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import com.mojang.blaze3d.pipeline.RenderTarget;
@@ -39,12 +41,13 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
-#if PRE_MC_1_19_4
-import com.mojang.math.Vector3f;
+#if MC_VER < MC_1_19_4
+import org.joml.Vector3f;
#else
+import org.joml.Matrix4f;
import org.joml.Vector3f;
#endif
-#if POST_MC_1_20_2
+#if MC_VER >= MC_1_20_2
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
#endif
@@ -67,7 +70,7 @@ import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.world.effect.MobEffects;
-#if PRE_MC_1_17_1
+#if MC_VER < MC_1_17_1
import net.minecraft.tags.FluidTags;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.material.FluidState;
@@ -78,6 +81,7 @@ import net.minecraft.world.level.material.FogType;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.apache.logging.log4j.Logger;
+import org.joml.Matrix4f;
/**
@@ -102,7 +106,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
* In the case of immersive portals multiple levels may be active at once, causing conflicting lightmaps.
* Requiring the use of multiple {@link LightMapWrapper}.
*/
- public HashMap lightmapByDimensionType = new HashMap<>();
+ public ConcurrentHashMap lightmapByDimensionType = new ConcurrentHashMap<>();
/**
* Holds the render buffer that should be used when displaying levels to the screen.
@@ -116,8 +120,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
public Vec3f getLookAtVector()
{
Camera camera = MC.gameRenderer.getMainCamera();
- Vector3f cameraDir = camera.getLookVector();
- return new Vec3f(cameraDir.x(), cameraDir.y(), cameraDir.z());
+ return new Vec3f(camera.getLookVector().x(), camera.getLookVector().y(), camera.getLookVector().z());
}
@Override
@@ -133,7 +136,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
public boolean playerHasBlindingEffect()
{
return MC.player.getActiveEffectsMap().get(MobEffects.BLINDNESS) != null
- #if POST_AND_MC_1_19_2
+ #if MC_VER >= MC_1_19_2
|| MC.player.getActiveEffectsMap().get(MobEffects.DARKNESS) != null // Deep dark effect
#endif
;
@@ -148,10 +151,27 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
return new Vec3d(projectedView.x, projectedView.y, projectedView.z);
}
+ @Override
+ public Mat4f getWorldViewMatrix()
+ {
+ Camera camera = MC.gameRenderer.getMainCamera();
+ Vector3f cameraVec3 = new Vector3f(
+ (float)camera.getPosition().x,
+ (float)camera.getPosition().y,
+ (float)camera.getPosition().z);
+ cameraVec3 = cameraVec3.negate();
+
+ Matrix4f matWorldView = new Matrix4f()
+ .rotateX((float)Math.toRadians(camera.getXRot()))
+ .rotateY((float)Math.toRadians(camera.getYRot() + 180f))
+ .translate(cameraVec3);
+ return new Mat4f(matWorldView);
+ }
+
@Override
public Mat4f getDefaultProjectionMatrix(float partialTicks)
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
return McObjectConverter.Convert(Minecraft.getInstance().gameRenderer.getProjectionMatrix(Minecraft.getInstance().gameRenderer.getMainCamera(), partialTicks, true));
#else
return McObjectConverter.Convert(MC.gameRenderer.getProjectionMatrix(MC.gameRenderer.getFov(MC.gameRenderer.getMainCamera(), partialTicks, true)));
@@ -161,7 +181,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override
public double getGamma()
{
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
return MC.options.gamma;
#else
return MC.options.gamma().get();
@@ -171,7 +191,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override
public Color getFogColor(float partialTicks)
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
float[] colorValues = new float[4];
GL15.glGetFloatv(GL15.GL_FOG_COLOR, colorValues);
#else
@@ -192,15 +212,24 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
{
if (MC.level.dimensionType().hasSkyLight())
{
- #if PRE_MC_1_17_1
- Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getBlockPosition(), MC.getFrameTime());
+ float frameTime;
+ #if MC_VER < MC_1_21
+ frameTime = MC.getFrameTime();
#else
- Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), MC.getFrameTime());
+ frameTime = MC.getTimer().getRealtimeDeltaTicks();
+ #endif
+
+ #if MC_VER < MC_1_17_1
+ Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getBlockPosition(), frameTime);
+ #else
+ Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);
#endif
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
}
else
+ {
return new Color(0, 0, 0);
+ }
}
@Override
@@ -213,7 +242,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override
public int getRenderDistance()
{
- #if PRE_MC_1_18_2
+ #if MC_VER < MC_1_18_2
//FIXME: How to resolve this?
return MC.options.renderDistance;
#else
@@ -261,12 +290,6 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override
public int getTargetFrameBuffer()
{
- int frameBufferOverrideId = DhApiRenderProxy.INSTANCE.targetFrameBufferOverride;
- if (frameBufferOverrideId != -1)
- {
- return frameBufferOverrideId;
- }
-
// used so we can access the framebuffer shaders end up rendering to
if (AbstractOptifineAccessor.optifinePresent())
{
@@ -321,15 +344,15 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
{
try
{
- #if PRE_MC_1_20_2
+ #if MC_VER < MC_1_20_2
LevelRenderer levelRenderer = MC.levelRenderer;
Collection chunks =
- #if PRE_MC_1_18_2 levelRenderer.renderChunks;
+ #if MC_VER < MC_1_18_2 levelRenderer.renderChunks;
#else levelRenderer.renderChunkStorage.get().renderChunks; #endif
return (chunks.stream().map((chunk) -> {
AABB chunkBoundingBox =
- #if PRE_MC_1_18_2 chunk.chunk.bb;
+ #if MC_VER < MC_1_18_2 chunk.chunk.bb;
#else chunk.chunk.getBoundingBox(); #endif
return new DhChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
Math.floorDiv((int) chunkBoundingBox.minZ, 16));
@@ -338,6 +361,15 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
LevelRenderer levelRenderer = MC.levelRenderer;
Collection chunks = levelRenderer.visibleSections;
+ return (chunks.stream().map((chunk) -> {
+ AABB chunkBoundingBox = chunk.getBoundingBox();
+ return new DhChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
+ Math.floorDiv((int) chunkBoundingBox.minZ, 16));
+ }).collect(Collectors.toCollection(HashSet::new)));
+ #else
+ LevelRenderer levelRenderer = MC.levelRenderer;
+ Collection chunks = levelRenderer.visibleSections;
+
return (chunks.stream().map((chunk) -> {
AABB chunkBoundingBox = chunk.getBoundingBox();
return new DhChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
@@ -371,7 +403,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override
public boolean isFogStateSpecial()
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
FluidState fluidState = camera.getFluidInCamera();
Entity entity = camera.getEntity();
@@ -392,11 +424,8 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
// so this will have to do for now
IDimensionTypeWrapper dimensionType = level.getDimensionType();
- if (!this.lightmapByDimensionType.containsKey(dimensionType))
- {
- this.lightmapByDimensionType.put(dimensionType, new LightMapWrapper());
- }
- this.lightmapByDimensionType.get(dimensionType).uploadLightmap(lightPixels);
+ LightMapWrapper wrapper = this.lightmapByDimensionType.compute(dimensionType, (dimType, oldWrapper) -> new LightMapWrapper());
+ wrapper.uploadLightmap(lightPixels);
}
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/LightMapWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/LightMapWrapper.java
index 39d1f3e4a..b6ed1265c 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/LightMapWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/LightMapWrapper.java
@@ -25,35 +25,39 @@ import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
-/**
- * @author James Seibel
- * @version 11-21-2021
- */
public class LightMapWrapper implements ILightMapWrapper
{
private int textureId = 0;
- public LightMapWrapper()
- {
- }
+
+ //==============//
+ // constructors //
+ //==============//
+
+ public LightMapWrapper() { }
private void createLightmap(NativeImage image)
{
- textureId = GL32.glGenTextures();
- GL32.glBindTexture(GL32.GL_TEXTURE_2D, textureId);
+ this.textureId = GL32.glGenTextures();
+ GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.textureId);
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, image.format().glFormat(), image.getWidth(), image.getHeight(),
0, image.format().glFormat(), GL32.GL_UNSIGNED_BYTE, (ByteBuffer) null);
}
+
+
+ //=========//
+ // methods //
+ //=========//
+
public void uploadLightmap(NativeImage image)
{
int currentBind = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
- GL32.glBindTexture(GL32.GL_TEXTURE_2D, textureId);
- if (textureId == 0)
+ GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.textureId);
+ if (this.textureId == 0)
{
- createLightmap(image);
+ this.createLightmap(image);
}
- // NativeImage::upload(int levelOfDetail, int xOffset, int yOffset, bool shouldCleanup?)
image.upload(0, 0, 0, false);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, currentBind);
}
@@ -66,9 +70,6 @@ public class LightMapWrapper implements ILightMapWrapper
}
@Override
- public void unbind()
- {
- GL32.glBindTexture(GL32.GL_TEXTURE_2D, 0);
- }
+ public void unbind() { GL32.glBindTexture(GL32.GL_TEXTURE_2D, 0); }
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/ServerPlayerWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/ServerPlayerWrapper.java
index b327c32a4..a9a401c04 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/ServerPlayerWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/ServerPlayerWrapper.java
@@ -33,7 +33,7 @@ public class ServerPlayerWrapper implements IServerPlayerWrapper
public IServerLevelWrapper getLevel()
{
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
return ServerLevelWrapper.getWrapper(this.serverPlayer.getLevel());
#else
return ServerLevelWrapper.getWrapper(this.serverPlayer.serverLevel());
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java
index 08ffe1656..29522508d 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java
@@ -25,13 +25,19 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource;
-import net.minecraft.world.level.chunk.ChunkStatus;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
+#if MC_VER <= MC_1_20_4
+import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+#endif
+
public class ClientLevelWrapper implements IClientLevelWrapper
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger(ClientLevelWrapper.class.getSimpleName());
@@ -41,6 +47,9 @@ public class ClientLevelWrapper implements IClientLevelWrapper
private final ClientLevel level;
private final ClientBlockDetailMap blockMap = new ClientBlockDetailMap(this);
+ private BlockStateWrapper dirtBlockWrapper;
+ private BiomeWrapper plainsBiomeWrapper;
+
//=============//
@@ -116,6 +125,46 @@ public class ClientLevelWrapper implements IClientLevelWrapper
return this.blockMap.getColor(((BlockStateWrapper) blockState).blockState, (BiomeWrapper) biome, pos);
}
+ @Override
+ public int getDirtBlockColor()
+ {
+ if (this.dirtBlockWrapper == null)
+ {
+ try
+ {
+ this.dirtBlockWrapper = (BlockStateWrapper) BlockStateWrapper.deserialize(BlockStateWrapper.DIRT_RESOURCE_LOCATION_STRING, this);
+ }
+ catch (IOException e)
+ {
+ // shouldn't happen, but just in case
+ LOGGER.warn("Unable to get dirt color with resource location ["+BlockStateWrapper.DIRT_RESOURCE_LOCATION_STRING+"] with level ["+this+"].", e);
+ return -1;
+ }
+ }
+
+ return this.blockMap.getColor(this.dirtBlockWrapper.blockState, BiomeWrapper.EMPTY_WRAPPER, DhBlockPos.ZERO);
+ }
+
+ @Override
+ public IBiomeWrapper getPlainsBiomeWrapper()
+ {
+ if (this.plainsBiomeWrapper == null)
+ {
+ try
+ {
+ this.plainsBiomeWrapper = (BiomeWrapper) BiomeWrapper.deserialize(BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING, this);
+ }
+ catch (IOException e)
+ {
+ // shouldn't happen, but just in case
+ LOGGER.warn("Unable to get planes biome with resource location ["+BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING+"] with level ["+this+"].", e);
+ return null;
+ }
+ }
+
+ return this.plainsBiomeWrapper;
+ }
+
@Override
public IDimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); }
@@ -136,7 +185,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
@Override
public int getMinHeight()
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
return 0;
#else
return this.level.getMinBuildHeight();
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java
index b6fea22b8..29eadb18e 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java
@@ -41,7 +41,12 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapp
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource;
+
+#if MC_VER <= MC_1_20_4
import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+#endif
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
@@ -130,7 +135,7 @@ public class ServerLevelWrapper implements IServerLevelWrapper
@Override
public int getMinHeight()
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
return 0;
#else
return level.getMinBuildHeight();
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java
index 8d238f508..b7a46b875 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java
@@ -35,6 +35,7 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.util.objects.EventTimer;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
+import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
@@ -56,7 +57,7 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepStruc
import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepStructureStart;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepSurface;
-#if POST_MC_1_19_4
+#if MC_VER >= MC_1_19_4
import net.minecraft.core.registries.Registries;
#else
import net.minecraft.core.Registry;
@@ -66,10 +67,10 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
-import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.UpgradeData;
+import net.minecraft.world.level.chunk.storage.IOWorker;
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
import net.minecraft.world.level.levelgen.DebugLevelSource;
import net.minecraft.world.level.levelgen.FlatLevelSource;
@@ -78,6 +79,12 @@ import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.nbt.CompoundTag;
import org.apache.logging.log4j.LogManager;
+#if MC_VER <= MC_1_20_4
+import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+#endif
+
/*
Total: 3.135214124s
=====================================
@@ -103,8 +110,6 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"),
() -> Config.Client.Advanced.Logging.logWorldGenLoadEvent.get());
- //TODO: Make actual proper support for StarLight
-
public static class PerfCalculator
{
private static final String[] TIME_NAMES = {
@@ -288,6 +293,9 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
+ //=================//
+ // synchronization //
+ //=================//
public T joinSync(CompletableFuture future)
{
@@ -338,7 +346,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
}
else if (event.hasTimeout(Config.Client.Advanced.WorldGenerator.worldGenerationTimeoutLengthInSeconds.get(), TimeUnit.SECONDS))
{
- EVENT_LOGGER.error("Batching World Generator: " + event + " timed out and terminated!");
+ EVENT_LOGGER.error("Batching World Generator: " + event + " timed out and terminated! Please lower your CPU load.");
EVENT_LOGGER.info("Dump PrefEvent: " + event.timer);
try
{
@@ -362,69 +370,11 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
}
}
- private static ProtoChunk EmptyChunk(ServerLevel level, ChunkPos chunkPos)
- {
- return new ProtoChunk(chunkPos, UpgradeData.EMPTY
- #if POST_MC_1_17_1 , level #endif
- #if POST_MC_1_18_2 , level.registryAccess().registryOrThrow(
- #if PRE_MC_1_19_4
- Registry.BIOME_REGISTRY
- #else
- Registries.BIOME
- #endif
- ), null #endif
- );
-
- }
- public ChunkAccess loadOrMakeChunk(ChunkPos chunkPos)
- {
- ServerLevel level = this.params.level;
-
- CompoundTag chunkData = null;
- try
- {
- // Warning: if multiple threads attempt to access this method at the same time,
- // it can throw EOFExceptions that are caught and logged by Minecraft
- //chunkData = level.getChunkSource().chunkMap.readChunk(chunkPos);
-
- RegionFileStorage storage = this.params.level.getChunkSource().chunkMap.worker.storage;
- RegionFileStorageExternalCache cache = this.getOrCreateRegionFileCache(storage);
- chunkData = cache.read(chunkPos);
- }
- catch (Exception e)
- {
- LOAD_LOGGER.error("DistantHorizons: Couldn't load or make chunk " + chunkPos + ". Error: " + e.getMessage(), e);
- }
-
- if (chunkData == null)
- {
- return EmptyChunk(level, chunkPos);
- }
- else
- {
- try
- {
- LOAD_LOGGER.info("DistantHorizons: Loading chunk " + chunkPos + " from disk.");
- return ChunkLoader.read(level, chunkPos, chunkData);
- }
- catch (Exception e)
- {
- LOAD_LOGGER.error("DistantHorizons: Couldn't load or make chunk " + chunkPos + ". Returning an empty chunk. Error: " + e.getMessage(), e);
- return EmptyChunk(level, chunkPos);
- }
- }
- }
- private static ArrayGridList GetCutoutFrom(ArrayGridList total, int border)
- {
- return new ArrayGridList<>(total, border, total.gridSize - border);
- }
-
- private static ArrayGridList GetCutoutFrom(ArrayGridList total, EDhApiWorldGenerationStep step)
- {
- return GetCutoutFrom(total, MaxBorderNeeded - BorderNeeded.get(step));
- }
+ //==================//
+ // world generation //
+ //==================//
public void generateLodFromList(GenerationEvent genEvent) throws InterruptedException
{
@@ -432,7 +382,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
ArrayGridList chunkWrapperList;
DhLitWorldGenRegion region;
- DummyLightEngine lightEngine;
+ DummyLightEngine dummyLightEngine;
LightGetterAdaptor adaptor;
int borderSize = MaxBorderNeeded;
@@ -445,50 +395,103 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
ArrayGridList totalChunks;
adaptor = new LightGetterAdaptor(this.params.level);
- lightEngine = new DummyLightEngine(adaptor);
+ dummyLightEngine = new DummyLightEngine(adaptor);
- EmptyChunkGenerator generator = (int x, int z) ->
+
+
+ //=============================//
+ // try getting existing chunks //
+ //=============================//
+
+ HashMap chunkSkyLightingByDhPos = new HashMap<>();
+ HashMap chunkBlockLightingByDhPos = new HashMap<>();
+ IEmptyChunkGeneratorFunc emptyChunkGeneratorFunc = (int x, int z) ->
{
ChunkPos chunkPos = new ChunkPos(x, z);
- ChunkAccess target = null;
+ DhChunkPos dhChunkPos = new DhChunkPos(x, z);
+ ChunkAccess newChunk = null;
try
{
- target = this.loadOrMakeChunk(chunkPos);
+ // get the chunk
+ CompoundTag chunkData = this.getChunkNbtData(chunkPos);
+ newChunk = this.loadOrMakeChunk(chunkPos, chunkData);
+
+ // get chunk lighting
+ ChunkLoader.CombinedChunkLightStorage combinedLights = ChunkLoader.readLight(newChunk, chunkData);
+ if (combinedLights != null)
+ {
+ chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage);
+ chunkBlockLightingByDhPos.put(dhChunkPos, combinedLights.blockLightStorage);
+ }
}
- catch (RuntimeException e2)
+ catch (RuntimeException loadChunkError)
{
// Continue...
}
- if (target == null)
+ if (newChunk == null)
{
- target = new ProtoChunk(chunkPos, UpgradeData.EMPTY
- #if POST_MC_1_17_1 , params.level #endif
- #if POST_MC_1_18_2 , params.biomes, null #endif
+ newChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY
+ #if MC_VER >= MC_1_17_1 , this.params.level #endif
+ #if MC_VER >= MC_1_18_2 , this.params.biomes, null #endif
);
}
- return target;
+ return newChunk;
};
+ totalChunks = new ArrayGridList<>(refSize, (x, z) -> emptyChunkGeneratorFunc.generate(x + refPosX, z + refPosZ));
- totalChunks = new ArrayGridList<>(refSize, (x, z) -> generator.generate(x + refPosX, z + refPosZ));
+ int radius = refSize / 2;
+ int centerX = refPosX + radius;
+ int centerZ = refPosZ + radius;
+
+ ChunkAccess centerChunk = totalChunks.stream().filter(chunk -> chunk.getPos().x == centerX && chunk.getPos().z == centerZ).findFirst().get();
genEvent.refreshTimeout();
- region = new DhLitWorldGenRegion(params.level, lightEngine, totalChunks,
- ChunkStatus.STRUCTURE_STARTS, refSize / 2, generator);
+ region = new DhLitWorldGenRegion(
+ centerX, centerZ,
+ centerChunk,
+ this.params.level, dummyLightEngine, totalChunks,
+ ChunkStatus.STRUCTURE_STARTS, radius, emptyChunkGeneratorFunc);
adaptor.setRegion(region);
- genEvent.threadedParam.makeStructFeat(region, params);
+ genEvent.threadedParam.makeStructFeat(region, this.params);
+
+ //=======================//
+ // create chunk wrappers //
+ //=======================//
+
chunkWrapperList = new ArrayGridList<>(totalChunks.gridSize);
totalChunks.forEachPos((x, z) ->
{
ChunkAccess chunk = totalChunks.get(x, z);
if (chunk != null)
{
- chunkWrapperList.set(x, z, new ChunkWrapper(chunk, region, serverlevel.getLevelWrapper()));
+ // wrap the chunk
+ ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, region, this.serverlevel.getLevelWrapper());
+ chunkWrapperList.set(x, z, chunkWrapper);
+
+ // try getting the chunk lighting
+ if (chunkBlockLightingByDhPos.containsKey(chunkWrapper.getChunkPos()))
+ {
+ chunkWrapper.setBlockLightStorage(chunkBlockLightingByDhPos.get(chunkWrapper.getChunkPos()));
+ chunkWrapper.setSkyLightStorage(chunkSkyLightingByDhPos.get(chunkWrapper.getChunkPos()));
+ chunkWrapper.setUseDhLighting(true);
+ chunkWrapper.setIsDhLightCorrect(true);
+ }
+ else
+ {
+ int k = 0;
+ }
}
});
+
+
+ //=================//
+ // generate chunks //
+ //=================//
+
this.generateDirect(genEvent, chunkWrapperList, borderSize, genEvent.targetGenerationStep, region);
genEvent.timer.nextEvent("cleanup");
}
@@ -507,7 +510,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
ChunkAccess target = wrappedChunk.getChunk();
if (target instanceof LevelChunk)
{
- #if MC_1_16_5 || MC_1_17_1
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
((LevelChunk) target).setLoaded(true);
#else
((LevelChunk) target).loaded = true;
@@ -519,8 +522,8 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
throw new RuntimeException("The generated chunk somehow has isLightCorrect() returning false");
}
- boolean isFull = target.getStatus() == ChunkStatus.FULL || target instanceof LevelChunk;
- #if POST_MC_1_18_2
+ boolean isFull = ChunkWrapper.getStatus(target) == ChunkStatus.FULL || target instanceof LevelChunk;
+ #if MC_VER >= MC_1_18_2
boolean isPartial = target.isOldNoiseGeneration();
#endif
if (isFull)
@@ -528,14 +531,14 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
LOAD_LOGGER.info("Detected full existing chunk at {}", target.getPos());
genEvent.resultConsumer.accept(wrappedChunk);
}
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
else if (isPartial)
{
LOAD_LOGGER.info("Detected old existing chunk at {}", target.getPos());
genEvent.resultConsumer.accept(wrappedChunk);
}
#endif
- else if (target.getStatus() == ChunkStatus.EMPTY)
+ else if (ChunkWrapper.getStatus(target) == ChunkStatus.EMPTY)
{
genEvent.resultConsumer.accept(wrappedChunk);
}
@@ -554,6 +557,85 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
PREF_LOGGER.infoInc("{}", genEvent.timer);
}
}
+ private CompoundTag getChunkNbtData(ChunkPos chunkPos)
+ {
+ ServerLevel level = this.params.level;
+
+ CompoundTag chunkData = null;
+ try
+ {
+ IOWorker ioWorker = level.getChunkSource().chunkMap.worker;
+
+ #if MC_VER <= MC_1_18_2
+ chunkData = ioWorker.load(chunkPos);
+ #else
+
+ // timeout should prevent locking up the thread if the ioWorker dies or has issues
+ int maxGetTimeInSec = Config.Client.Advanced.WorldGenerator.worldGenerationTimeoutLengthInSeconds.get();
+ CompletableFuture> future = ioWorker.loadAsync(chunkPos);
+ try
+ {
+ Optional data = future.get(maxGetTimeInSec, TimeUnit.SECONDS);
+ if (data.isPresent())
+ {
+ chunkData = data.get();
+ }
+ }
+ catch (Exception e)
+ {
+ LOAD_LOGGER.warn("Unable to get chunk at pos ["+chunkPos+"] after ["+maxGetTimeInSec+"] milliseconds.", e);
+ future.cancel(true);
+ }
+ #endif
+ }
+ catch (Exception e)
+ {
+ LOAD_LOGGER.error("DistantHorizons: Couldn't load or make chunk " + chunkPos + ". Error: " + e.getMessage(), e);
+ }
+
+ return chunkData;
+ }
+ private ChunkAccess loadOrMakeChunk(ChunkPos chunkPos, CompoundTag chunkData)
+ {
+ ServerLevel level = this.params.level;
+
+ if (chunkData == null)
+ {
+ return CreateEmptyChunk(level, chunkPos);
+ }
+ else
+ {
+ try
+ {
+ LOAD_LOGGER.info("DistantHorizons: Loading chunk [" + chunkPos + "] from disk.");
+ return ChunkLoader.read(level, chunkPos, chunkData);
+ }
+ catch (Exception e)
+ {
+ LOAD_LOGGER.error(
+ "DistantHorizons: couldn't load or make chunk at ["+chunkPos+"]." +
+ "Please try optimizing your world to fix this issue. \n" +
+ "World optimization can be done from the singleplayer world selection screen.\n" +
+ "Error: ["+e.getMessage()+"]."
+ , e);
+
+ return CreateEmptyChunk(level, chunkPos);
+ }
+ }
+ }
+ private static ProtoChunk CreateEmptyChunk(ServerLevel level, ChunkPos chunkPos)
+ {
+ return new ProtoChunk(chunkPos, UpgradeData.EMPTY
+ #if MC_VER >= MC_1_17_1 , level #endif
+ #if MC_VER >= MC_1_18_2 , level.registryAccess().registryOrThrow(
+ #if MC_VER < MC_1_19_4
+ Registry.BIOME_REGISTRY
+ #else
+ Registries.BIOME
+ #endif
+ ), null #endif
+ );
+ }
public void generateDirect(
GenerationEvent genEvent, ArrayGridList chunksToGenerate, int border,
@@ -648,7 +730,19 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
int maxSkyLight = this.serverlevel.getServerLevelWrapper().hasSkyLight() ? 15 : 0;
- ArrayList iChunkWrapperList = new ArrayList<>(chunksToGenerate);
+ // only light generated chunks,
+ // attempting to light un-generated chunks will cause lighting issues on bordering generated chunks
+ ArrayList iChunkWrapperList = new ArrayList<>();
+ for (int i = 0; i < chunksToGenerate.size(); i++) // regular for loop since enhanced for loops increase GC pressure slightly
+ {
+ ChunkWrapper chunkWrapper = chunksToGenerate.get(i);
+ if (chunkWrapper.getStatus() != ChunkStatus.EMPTY)
+ {
+ iChunkWrapperList.add(chunkWrapper);
+ }
+ }
+
+ // light each chunk in the list
for (int i = 0; i < iChunkWrapperList.size(); i++)
{
IChunkWrapper centerChunk = iChunkWrapperList.get(i);
@@ -663,19 +757,19 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
// if this isn't done everything else afterward may fail
Heightmap.primeHeightmaps(((ChunkWrapper)centerChunk).getChunk(), ChunkStatus.FEATURES.heightmapsAfter());
- // populate the lighting
- DhLightingEngine.INSTANCE.lightChunk(centerChunk, iChunkWrapperList, maxSkyLight);
+ // pre-generated chunks should have lighting but new ones won't
+ if (!centerChunk.isLightCorrect())
+ {
+ DhLightingEngine.INSTANCE.lightChunk(centerChunk, iChunkWrapperList, maxSkyLight);
+ }
}
genEvent.refreshTimeout();
}
}
+ private static ArrayGridList GetCutoutFrom(ArrayGridList total, int border) { return new ArrayGridList<>(total, border, total.gridSize - border); }
+ private static ArrayGridList GetCutoutFrom(ArrayGridList total, EDhApiWorldGenerationStep step) { return GetCutoutFrom(total, MaxBorderNeeded - BorderNeeded.get(step)); }
- public interface EmptyChunkGenerator
- {
- ChunkAccess generate(int x, int z);
-
- }
@Override
public int getEventCount() { return this.generationEventList.size(); }
@@ -724,6 +818,12 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
return genEvent.future;
}
+
+
+ //================//
+ // helper methods //
+ //================//
+
/**
* Called before code that may run for an extended period of time.
* This is necessary to allow canceling world gen since waiting
@@ -737,4 +837,16 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
}
}
+
+
+ //================//
+ // helper classes //
+ //================//
+
+ @FunctionalInterface
+ public interface IEmptyChunkGeneratorFunc
+ {
+ ChunkAccess generate(int x, int z);
+ }
+
}
\ No newline at end of file
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java
index 3bee78e77..46df3f13e 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java
@@ -26,13 +26,11 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
-import com.seibel.distanthorizons.core.generation.WorldGenerationQueue;
-import com.seibel.distanthorizons.core.util.ThreadUtil;
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.util.objects.EventTimer;
-import com.seibel.distanthorizons.core.util.threading.ThreadPools;
+import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import org.apache.logging.log4j.Logger;
@@ -123,7 +121,7 @@ public final class GenerationEvent
public boolean terminate()
{
LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN=======================");
- ThreadPools.WORLD_GEN_THREAD_FACTORY.dumpAllThreadStacks();
+ ThreadPoolUtil.WORLD_GEN_THREAD_FACTORY.dumpAllThreadStacks();
this.future.cancel(true);
return this.future.isCancelled();
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalParameters.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalParameters.java
index aafc01bb3..ac7e1c639 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalParameters.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalParameters.java
@@ -31,16 +31,16 @@ import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.chunk.ChunkGenerator;
-#if POST_MC_1_18_2
+#if MC_VER >= MC_1_18_2
import net.minecraft.world.level.chunk.storage.ChunkScanAccess;
#endif
import net.minecraft.world.level.levelgen.WorldGenSettings;
-#if PRE_MC_1_19_2
+#if MC_VER < MC_1_19_2
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
#else
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
import net.minecraft.world.level.levelgen.RandomState;
-#if POST_MC_1_19_4
+#if MC_VER >= MC_1_19_4
import net.minecraft.world.level.levelgen.WorldOptions;
import net.minecraft.core.registries.Registries;
#endif
@@ -50,13 +50,13 @@ import net.minecraft.world.level.storage.WorldData;
public final class GlobalParameters
{
public final ChunkGenerator generator;
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
public final StructureManager structures;
#else
public final StructureTemplateManager structures;
public final RandomState randomState;
#endif
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
public final WorldGenSettings worldGenSettings;
#else
public final WorldOptions worldOptions;
@@ -67,7 +67,7 @@ public final class GlobalParameters
public final RegistryAccess registry;
public final long worldSeed;
public final DataFixer fixerUpper;
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
public final BiomeManager biomeManager;
public final ChunkScanAccess chunkScanner; // FIXME: Figure out if this is actually needed
#endif
@@ -81,7 +81,7 @@ public final class GlobalParameters
WorldData worldData = server.getWorldData();
registry = server.registryAccess();
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
worldGenSettings = worldData.worldGenSettings();
biomes = registry.registryOrThrow(Registry.BIOME_REGISTRY);
worldSeed = worldGenSettings.seed();
@@ -90,14 +90,14 @@ public final class GlobalParameters
biomes = registry.registryOrThrow(Registries.BIOME);
worldSeed = worldOptions.seed();
#endif
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
biomeManager = new BiomeManager(level, BiomeManager.obfuscateSeed(worldSeed));
chunkScanner = level.getChunkSource().chunkScanner();
#endif
structures = server.getStructureManager();
generator = level.getChunkSource().getGenerator();
fixerUpper = server.getFixerUpper();
- #if POST_MC_1_19_2
+ #if MC_VER >= MC_1_19_2
randomState = level.getChunkSource().randomState();
#endif
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadedParameters.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadedParameters.java
index d5e391be5..71cc834c3 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadedParameters.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadedParameters.java
@@ -25,7 +25,7 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.Wo
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.WorldGenLevel;
-#if POST_MC_1_18_2
+#if MC_VER >= MC_1_18_2
import net.minecraft.world.level.levelgen.structure.StructureCheck;
#endif
@@ -35,7 +35,7 @@ public final class ThreadedParameters
final ServerLevel level;
public WorldGenStructFeatManager structFeat = null;
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
public StructureCheck structCheck;
#endif
boolean isValid = true;
@@ -63,9 +63,9 @@ public final class ThreadedParameters
previousGlobalParameters = param;
this.level = param.level;
- #if PRE_MC_1_18_2
+ #if MC_VER < MC_1_18_2
this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, level);
- #elif PRE_MC_1_19_2
+ #elif MC_VER < MC_1_19_2
this.structCheck = this.createStructureCheck(param);
#else
this.structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
@@ -80,15 +80,15 @@ public final class ThreadedParameters
public void makeStructFeat(WorldGenLevel genLevel, GlobalParameters param)
{
- #if PRE_MC_1_19_4
- structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel #if POST_MC_1_18_2 , structCheck #endif );
+ #if MC_VER < MC_1_19_4
+ structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel #if MC_VER >= MC_1_18_2 , structCheck #endif );
#else
structFeat = new WorldGenStructFeatManager(param.worldOptions, genLevel, structCheck);
#endif
}
- #if POST_MC_1_18_2 && PRE_MC_1_19_2
+ #if MC_VER >= MC_1_18_2 && MC_VER < MC_1_19_2
public void recreateStructureCheck()
{
if (previousGlobalParameters != null)
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkLoader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkLoader.java
index dda02fa40..5699051cb 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkLoader.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkLoader.java
@@ -22,9 +22,14 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
import com.google.common.collect.Maps;
import com.mojang.serialization.Codec;
import com.mojang.serialization.Dynamic;
+import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
+import com.seibel.distanthorizons.core.util.LodUtil;
+import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
+import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
@@ -37,13 +42,14 @@ import java.util.Objects;
import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
-#if POST_MC_1_19_4
+#if MC_VER >= MC_1_19_4
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
#endif
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtOps;
+import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.*;
@@ -55,35 +61,45 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.*;
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
import net.minecraft.world.level.levelgen.Heightmap;
-#if POST_MC_1_18_2
+#if MC_VER >= MC_1_18_2
import net.minecraft.world.level.levelgen.blending.BlendingData;
-#if PRE_MC_1_19_2
+#if MC_VER < MC_1_19_2
import net.minecraft.world.level.levelgen.feature.StructureFeature;
#endif
import net.minecraft.world.level.levelgen.structure.StructureStart;
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceSerializationContext;
import net.minecraft.world.ticks.LevelChunkTicks;
#endif
-#if POST_MC_1_18_2
+#if MC_VER >= MC_1_18_2
import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess;
-#if PRE_MC_1_19_2
+#if MC_VER < MC_1_19_2
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
#endif
#endif
-#if MC_1_16_5 || MC_1_17_1
+#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
import net.minecraft.world.level.material.Fluids;
#endif
+#if MC_VER == MC_1_20_6
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+import net.minecraft.world.level.chunk.status.ChunkType;
+#elif MC_VER == MC_1_21
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+import net.minecraft.world.level.chunk.status.ChunkType;
+#endif
+
import net.minecraft.world.level.material.Fluid;
public class ChunkLoader
{
- #if POST_MC_1_19_2
+ private static boolean zeroChunkPosErrorLogged = false;
+
+ #if MC_VER >= MC_1_19_2
private static final Codec> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
- #elif POST_MC_1_18_2
+ #elif MC_VER >= MC_1_18_2
private static final Codec> BLOCK_STATE_CODEC = PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
#endif
private static final String TAG_UPGRADE_DATA = "UpgradeData";
@@ -93,137 +109,17 @@ public class ChunkLoader
private static final String FLUID_TICKS_TAG_PRE18 = "LiquidTicks";
private static final ConfigBasedLogger LOGGER = BatchGenerationEnvironment.LOAD_LOGGER;
- #if POST_MC_1_18_2
- private static BlendingData readBlendingData(CompoundTag chunkData)
- {
- BlendingData blendingData = null;
- if (chunkData.contains("blending_data", 10))
- {
- @SuppressWarnings({"unchecked", "rawtypes"})
- Dynamic blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data"));
- blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial(LOGGER::error).orElse(null);
- }
- return blendingData;
- }
- #endif
+ private static boolean lightingSectionErrorLogged = false;
- private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData)
- {
- #if POST_MC_1_18_2
- #if PRE_MC_1_19_4
- Registry biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
- #else
- Registry biomes = level.registryAccess().registryOrThrow(Registries.BIOME);
- #endif
- #if PRE_MC_1_18_2
- Codec> biomeCodec = PalettedContainer.codec(
- biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
- #elif PRE_MC_1_19_2
- Codec>> biomeCodec = PalettedContainer.codec(
- biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
- #else
- Codec>> biomeCodec = PalettedContainer.codecRW(
- biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
- #endif
- #endif
- int i = #if PRE_MC_1_17_1 16; #else level.getSectionsCount(); #endif
- LevelChunkSection[] chunkSections = new LevelChunkSection[i];
-
- boolean isLightOn = chunkData.getBoolean("isLightOn");
- boolean hasSkyLight = level.dimensionType().hasSkyLight();
- ListTag tagSections = chunkData.getList("Sections", 10);
- if (tagSections.isEmpty()) tagSections = chunkData.getList("sections", 10);
-
- for (int j = 0; j < tagSections.size(); ++j)
- {
- CompoundTag tagSection = tagSections.getCompound(j);
- int sectionYPos = tagSection.getByte("Y");
-
- #if PRE_MC_1_18_2
- if (tagSection.contains("Palette", 9) && tagSection.contains("BlockStates", 12))
- {
- LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4);
- levelChunkSection.getStates().read(tagSection.getList("Palette", 10),
- tagSection.getLongArray("BlockStates"));
- levelChunkSection.recalcBlockCounts();
- if (!levelChunkSection.isEmpty())
- chunkSections[#if PRE_MC_1_17_1 sectionYPos #else level.getSectionIndexFromSectionY(sectionYPos) #endif ]
- = levelChunkSection;
- }
- #else
- int sectionId = level.getSectionIndexFromSectionY(sectionYPos);
- if (sectionId >= 0 && sectionId < chunkSections.length)
- {
- PalettedContainer blockStateContainer;
- #if PRE_MC_1_18_2
- PalettedContainer biomeContainer;
- #else
- PalettedContainer> biomeContainer;
- #endif
-
- blockStateContainer = tagSection.contains("block_states", 10)
- ? BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagSection.getCompound("block_states")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, LOGGER::error)
- : new PalettedContainer(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
-
- #if PRE_MC_1_18_2
- biomeContainer = tagSection.contains("biomes", 10)
- ? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, LOGGER::error)
- : new PalettedContainer(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
- #else
- biomeContainer = tagSection.contains("biomes", 10)
- ? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, i, (String) string)).getOrThrow(false, LOGGER::error)
- : new PalettedContainer>(biomes.asHolderIdMap(), biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
- #endif
- #if PRE_MC_1_20_1
- chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
- #else
- chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
- #endif
- }
- #endif
-
- }
- return chunkSections;
- }
- private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
- {
- CompoundTag tagHeightmaps = chunkData.getCompound("Heightmaps");
- for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
- {
- String heightmap = type.getSerializationKey();
- if (tagHeightmaps.contains(heightmap, 12))
- chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap));
- }
- Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
- }
- private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
- {
- ListTag tagPostProcessings = chunkData.getList("PostProcessing", 9);
- for (int n = 0; n < tagPostProcessings.size(); ++n)
- {
- ListTag listTag3 = tagPostProcessings.getList(n);
- for (int o = 0; o < listTag3.size(); ++o)
- {
- chunk.addPackedPostProcess(listTag3.getShort(o), n);
- }
- }
- }
-
- public static ChunkStatus.ChunkType readChunkType(CompoundTag tagLevel)
- {
- ChunkStatus chunkStatus = ChunkStatus.byName(tagLevel.getString("Status"));
- if (chunkStatus != null)
- {
- return chunkStatus.getChunkType();
- }
- return ChunkStatus.ChunkType.PROTOCHUNK;
- }
+ //============//
+ // read chunk //
+ //============//
public static LevelChunk read(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData)
{
- #if PRE_MC_1_18_2
+ #if MC_VER < MC_1_18_2
CompoundTag tagLevel = chunkData.getCompound("Level");
#else
CompoundTag tagLevel = chunkData;
@@ -232,50 +128,82 @@ public class ChunkLoader
ChunkPos actualPos = new ChunkPos(tagLevel.getInt("xPos"), tagLevel.getInt("zPos"));
if (!Objects.equals(chunkPos, actualPos))
{
- LOGGER.error("Chunk file at {} is in the wrong location; Ignoring. (Expected {}, got {})", chunkPos, chunkPos, actualPos);
- return null;
+ #if MC_VER > MC_1_17_1
+ if (actualPos.equals(ChunkPos.ZERO))
+ #else
+ if (actualPos.equals(ChunkPos.INVALID_CHUNK_POS))
+ #endif
+ {
+ if (!zeroChunkPosErrorLogged)
+ {
+ zeroChunkPosErrorLogged = true;
+
+ // explicit chunkPos toString is necessary otherwise the JDK 17 compiler breaks
+ LOGGER.warn("Chunk file at ["+chunkPos.toString()+"] doesn't have a chunk pos. \n" +
+ "This might happen if the world was created using an external program. \n" +
+ "DH will attempt to parse the chunk anyway and won't log this message again.\n" +
+ "If issues arise please try optimizing your world to fix this issue. \n" +
+ "World optimization can be done from the singleplayer world selection screen."+
+ "");
+ }
+ }
+ else
+ {
+ // everything is on one line to fix a JDK 17 compiler issue
+ // if the issue is ever resolved, feel free to make this multi-line for readability
+ LOGGER.error("Chunk file at ["+chunkPos.toString()+"] is in the wrong location. \nPlease try optimizing your world to fix this issue. \nWorld optimization can be done from the singleplayer world selection screen. \n(Expected pos: ["+chunkPos.toString()+"], actual ["+actualPos.toString()+"])");
+ return null;
+ }
}
- ChunkStatus.ChunkType chunkType = readChunkType(tagLevel);
- #if PRE_MC_1_18_2
- if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK)
- return null;
+ #if MC_VER < MC_1_20_6
+ ChunkStatus.ChunkType chunkType;
#else
- BlendingData blendingData = readBlendingData(tagLevel);
- #if PRE_MC_1_19_2
- if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || !blendingData.oldNoise()))
- return null;
- #else
- if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && blendingData == null)
- return null;
+ ChunkType chunkType;
#endif
+ chunkType = readChunkType(tagLevel);
+
+ #if MC_VER < MC_1_18_2
+ if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK)
+ return null;
+ #else
+
+ BlendingData blendingData = readBlendingData(tagLevel);
+ #if MC_VER < MC_1_19_2
+ if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || !blendingData.oldNoise()))
+ return null;
+ #else
+ if (chunkType == #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType.PROTOCHUNK #else ChunkType.PROTOCHUNK #endif && blendingData == null)
+ return null;
+ #endif
+
#endif
long inhabitedTime = tagLevel.getLong("InhabitedTime");
//================== Read params for making the LevelChunk ==================
UpgradeData upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
- ? new UpgradeData(tagLevel.getCompound(TAG_UPGRADE_DATA)#if POST_MC_1_17_1 , level #endif )
+ ? new UpgradeData(tagLevel.getCompound(TAG_UPGRADE_DATA)#if MC_VER >= MC_1_17_1 , level #endif )
: UpgradeData.EMPTY;
boolean isLightOn = tagLevel.getBoolean("isLightOn");
- #if PRE_MC_1_18_2
+ #if MC_VER < MC_1_18_2
ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer(
- level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY)#if POST_MC_1_17_1 , level #endif ,
+ level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY)#if MC_VER >= MC_1_17_1 , level #endif ,
chunkPos, level.getLevel().getChunkSource().getGenerator().getBiomeSource(),
tagLevel.contains("Biomes", 11) ? tagLevel.getIntArray("Biomes") : null);
TickList blockTicks = tagLevel.contains(BLOCK_TICKS_TAG_PRE18, 9)
? ChunkTickList.create(tagLevel.getList(BLOCK_TICKS_TAG_PRE18, 10), Registry.BLOCK::getKey, Registry.BLOCK::get)
: new ProtoTickList(block -> (block == null || block.defaultBlockState().isAir()), chunkPos,
- tagLevel.getList("ToBeTicked", 9)#if POST_MC_1_17_1 , level #endif );
+ tagLevel.getList("ToBeTicked", 9)#if MC_VER >= MC_1_17_1 , level #endif );
TickList fluidTicks = tagLevel.contains(FLUID_TICKS_TAG_PRE18, 9)
? ChunkTickList.create(tagLevel.getList(FLUID_TICKS_TAG_PRE18, 10), Registry.FLUID::getKey, Registry.FLUID::get)
: new ProtoTickList(fluid -> (fluid == null || fluid == Fluids.EMPTY), chunkPos,
- tagLevel.getList("LiquidsToBeTicked", 9)#if POST_MC_1_17_1 , level #endif );
+ tagLevel.getList("LiquidsToBeTicked", 9)#if MC_VER >= MC_1_17_1 , level #endif );
#else
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
LevelChunkTicks blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10),
string -> Registry.BLOCK.getOptional(ResourceLocation.tryParse(string)), chunkPos);
LevelChunkTicks fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10),
@@ -291,7 +219,7 @@ public class ChunkLoader
LevelChunkSection[] levelChunkSections = readSections(level, chunkPos, tagLevel);
// ====================== Make the chunk =========================
- #if PRE_MC_1_18_2
+ #if MC_VER < MC_1_18_2
LevelChunk chunk = new LevelChunk((Level) level.getLevel(), chunkPos, chunkBiomeContainer, upgradeData, blockTicks,
fluidTicks, inhabitedTime, levelChunkSections, null);
#else
@@ -305,11 +233,290 @@ public class ChunkLoader
readPostPocessings(chunk, chunkData);
return chunk;
}
+ private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData)
+ {
+ #if MC_VER >= MC_1_18_2
+ #if MC_VER < MC_1_19_4
+ Registry biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
+ #else
+ Registry biomes = level.registryAccess().registryOrThrow(Registries.BIOME);
+ #endif
+ #if MC_VER < MC_1_18_2
+ Codec> biomeCodec = PalettedContainer.codec(
+ biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
+ #elif MC_VER < MC_1_19_2
+ Codec>> biomeCodec = PalettedContainer.codec(
+ biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
+ #else
+ Codec>> biomeCodec = PalettedContainer.codecRW(
+ biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
+ #endif
+ #endif
+ int i = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif
+ LevelChunkSection[] chunkSections = new LevelChunkSection[i];
+
+ boolean isLightOn = chunkData.getBoolean("isLightOn");
+ boolean hasSkyLight = level.dimensionType().hasSkyLight();
+ ListTag tagSections = chunkData.getList("Sections", 10);
+ if (tagSections.isEmpty()) tagSections = chunkData.getList("sections", 10);
+
+ for (int j = 0; j < tagSections.size(); ++j)
+ {
+ CompoundTag tagSection = tagSections.getCompound(j);
+ int sectionYPos = tagSection.getByte("Y");
+
+ #if MC_VER < MC_1_18_2
+ if (tagSection.contains("Palette", 9) && tagSection.contains("BlockStates", 12))
+ {
+ LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4);
+ levelChunkSection.getStates().read(tagSection.getList("Palette", 10),
+ tagSection.getLongArray("BlockStates"));
+ levelChunkSection.recalcBlockCounts();
+ if (!levelChunkSection.isEmpty())
+ chunkSections[#if MC_VER < MC_1_17_1 sectionYPos #else level.getSectionIndexFromSectionY(sectionYPos) #endif ]
+ = levelChunkSection;
+ }
+ #else
+ int sectionId = level.getSectionIndexFromSectionY(sectionYPos);
+ if (sectionId >= 0 && sectionId < chunkSections.length)
+ {
+ PalettedContainer blockStateContainer;
+ #if MC_VER < MC_1_18_2
+ PalettedContainer biomeContainer;
+ #else
+ PalettedContainer> biomeContainer;
+ #endif
+
+ blockStateContainer = tagSection.contains("block_states", 10)
+ ? BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagSection.getCompound("block_states")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string))
+ #if MC_VER < MC_1_20_6
+ .getOrThrow(false, LOGGER::error)
+ #else
+ .getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null))
+ #endif
+ : new PalettedContainer(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
+
+ #if MC_VER < MC_1_18_2
+ biomeContainer = tagSection.contains("biomes", 10)
+ ? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, LOGGER::error)
+ : new PalettedContainer(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
+ #else
+
+ biomeContainer = tagSection.contains("biomes", 10)
+ ? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, i, (String) string))
+ #if MC_VER < MC_1_20_6
+ .getOrThrow(false, LOGGER::error)
+ #else
+ .getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null))
+ #endif
+ : new PalettedContainer>(biomes.asHolderIdMap(), biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
+ #endif
+
+ #if MC_VER < MC_1_20_1
+ chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
+ #else
+ chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
+ #endif
+ }
+ #endif
+
+ }
+ return chunkSections;
+ }
+ private static
+ #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType
+ #elif MC_VER < MC_1_21 ChunkType
+ #else ChunkType #endif
+ readChunkType(CompoundTag tagLevel)
+ {
+ ChunkStatus chunkStatus = ChunkStatus.byName(tagLevel.getString("Status"));
+ if (chunkStatus != null)
+ {
+ return chunkStatus.getChunkType();
+ }
+
+ return
+ #if MC_VER <= MC_1_20_4 ChunkStatus.ChunkType.PROTOCHUNK;
+ #else ChunkType.PROTOCHUNK; #endif
+ }
+ private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
+ {
+ CompoundTag tagHeightmaps = chunkData.getCompound("Heightmaps");
+ for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
+ {
+ String heightmap = type.getSerializationKey();
+ if (tagHeightmaps.contains(heightmap, 12))
+ chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap));
+ }
+ Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
+ }
+ private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
+ {
+ ListTag tagPostProcessings = chunkData.getList("PostProcessing", 9);
+ for (int n = 0; n < tagPostProcessings.size(); ++n)
+ {
+ ListTag listTag3 = tagPostProcessings.getList(n);
+ for (int o = 0; o < listTag3.size(); ++o)
+ {
+ chunk.addPackedPostProcess(listTag3.getShort(o), n);
+ }
+ }
+ }
+ #if MC_VER >= MC_1_18_2
+ private static BlendingData readBlendingData(CompoundTag chunkData)
+ {
+ BlendingData blendingData = null;
+ if (chunkData.contains("blending_data", 10))
+ {
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ Dynamic blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data"));
+ blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial(LOGGER::error).orElse(null);
+ }
+ return blendingData;
+ }
+ #endif
+
+
+
+ //=====================//
+ // read chunk lighting //
+ //=====================//
+
+ /**
+ * https://minecraft.wiki/w/Chunk_format
+ */
+ public static CombinedChunkLightStorage readLight(ChunkAccess chunk, CompoundTag chunkData)
+ {
+ #if MC_VER <= MC_1_17_1
+ // MC 1.16 and 1.17 doesn't have the necessary NBT info
+ return null;
+ #else
+
+ CombinedChunkLightStorage combinedStorage = new CombinedChunkLightStorage(ChunkWrapper.getMinBuildHeight(chunk), ChunkWrapper.getMaxBuildHeight(chunk));
+ ChunkLightStorage blockLightStorage = combinedStorage.blockLightStorage;
+ ChunkLightStorage skyLightStorage = combinedStorage.skyLightStorage;
+
+ boolean foundSkyLight = false;
+
+
+
+ //===================//
+ // get NBT tags info //
+ //===================//
+
+ Tag chunkSectionTags = chunkData.get("sections");
+ if (chunkSectionTags == null)
+ {
+ if (!lightingSectionErrorLogged)
+ {
+ lightingSectionErrorLogged = true;
+ LOGGER.error("No sections found for chunk at pos ["+chunk.getPos()+"] chunk data may be out of date.");
+ }
+ return null;
+ }
+ else if (!(chunkSectionTags instanceof ListTag))
+ {
+ if (!lightingSectionErrorLogged)
+ {
+ lightingSectionErrorLogged = true;
+ LOGGER.error("Chunk section tag list have unexpected type ["+chunkSectionTags.getClass().getName()+"], expected ["+ListTag.class.getName()+"].");
+ }
+ return null;
+ }
+ ListTag chunkSectionListTag = (ListTag) chunkSectionTags;
+
+
+
+ //===================//
+ // get lighting info //
+ //===================//
+
+ for (int sectionIndex = 0; sectionIndex < chunkSectionListTag.size(); sectionIndex++)
+ {
+ Tag chunkSectionTag = chunkSectionListTag.get(sectionIndex);
+ if (!(chunkSectionTag instanceof CompoundTag))
+ {
+ if (!lightingSectionErrorLogged)
+ {
+ lightingSectionErrorLogged = true;
+ LOGGER.error("Chunk section tag has an unexpected type ["+chunkSectionTag.getClass().getName()+"], expected ["+CompoundTag.class.getName()+"].");
+ }
+ return null;
+ }
+ CompoundTag chunkSectionCompoundTag = (CompoundTag) chunkSectionTag;
+
+
+ // if null all lights = 0
+ byte[] blockLightNibbleArray = chunkSectionCompoundTag.getByteArray("BlockLight");
+ byte[] skyLightNibbleArray = chunkSectionCompoundTag.getByteArray("SkyLight");
+
+ // if any sky light was found then all lights above will be max brightness
+ if (skyLightNibbleArray.length != 0)
+ {
+ foundSkyLight = true;
+ }
+
+ for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++)
+ {
+ for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
+ {
+ // chunk sections are also 16 blocks tall
+ for (int relY = 0; relY < LodUtil.CHUNK_WIDTH; relY++)
+ {
+ int blockPosIndex = relY*16*16 + relZ*16 + relX;
+ byte blockLight = (blockLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(blockLightNibbleArray, blockPosIndex);
+ byte skyLight = (skyLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(skyLightNibbleArray, blockPosIndex);
+ if (skyLightNibbleArray.length == 0 && foundSkyLight)
+ {
+ skyLight = LodUtil.MAX_MC_LIGHT;
+ }
+
+ int y = relY + (sectionIndex * LodUtil.CHUNK_WIDTH) + ChunkWrapper.getMinBuildHeight(chunk);
+ blockLightStorage.set(relX, y, relZ, blockLight);
+ skyLightStorage.set(relX, y, relZ, skyLight);
+ }
+ }
+ }
+ }
+
+ return combinedStorage;
+ #endif
+ }
+ /** source: https://minecraft.wiki/w/Chunk_format#Block_Format */
+ private static byte getNibbleAtIndex(byte[] arr, int index)
+ {
+ if (index % 2 == 0)
+ {
+ return (byte)(arr[index/2] & 0x0F);
+ }
+ else
+ {
+ return (byte)((arr[index/2]>>4) & 0x0F);
+ }
+ }
private static void logErrors(ChunkPos chunkPos, int i, String string)
{
LOGGER.error("Distant Horizons: Recoverable errors when loading section [" + chunkPos.x + ", " + i + ", " + chunkPos.z + "]: " + string);
}
+
+
+ //================//
+ // helper classes //
+ //================//
+
+ public static class CombinedChunkLightStorage
+ {
+ public ChunkLightStorage blockLightStorage;
+ public ChunkLightStorage skyLightStorage;
+
+ public CombinedChunkLightStorage(int minY, int maxY)
+ {
+ this.blockLightStorage = ChunkLightStorage.createBlockLightStorage(minY, maxY);
+ this.skyLightStorage = ChunkLightStorage.createSkyLightStorage(minY, maxY);
+ }
+ }
+
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DhGenerationChunkHolder.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DhGenerationChunkHolder.java
new file mode 100644
index 000000000..519938ce8
--- /dev/null
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DhGenerationChunkHolder.java
@@ -0,0 +1,23 @@
+package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
+
+#if MC_VER >= MC_1_21
+
+import net.minecraft.server.level.GenerationChunkHolder;
+import net.minecraft.world.level.ChunkPos;
+
+public class DhGenerationChunkHolder extends GenerationChunkHolder
+{
+
+ public DhGenerationChunkHolder(ChunkPos pos)
+ {
+ super(pos);
+ }
+
+ @Override
+ public int getTicketLevel() { return 0; }
+ @Override
+ public int getQueueLevel() { return 0; }
+
+}
+
+#endif
\ No newline at end of file
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DhLitWorldGenRegion.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DhLitWorldGenRegion.java
index 34a27482d..30632bef1 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DhLitWorldGenRegion.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DhLitWorldGenRegion.java
@@ -20,14 +20,17 @@
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
import java.lang.invoke.MethodHandles;
+import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
-
+import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
+import com.seibel.distanthorizons.core.util.LodUtil;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.SpawnerBlock;
import org.apache.logging.log4j.Logger;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
@@ -41,7 +44,7 @@ import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.ColorResolver;
-#if POST_MC_1_17_1
+#if MC_VER >= MC_1_17_1
import net.minecraft.world.level.LevelHeightAccessor;
#endif
import net.minecraft.world.level.LightLayer;
@@ -50,34 +53,50 @@ import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
-import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ImposterProtoChunk;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.lighting.LevelLightEngine;
+#if MC_VER <= MC_1_20_4
+import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.*;
+#endif
+
+#if MC_VER == MC_1_21
+import net.minecraft.util.StaticCache2D;
+import com.google.common.collect.ImmutableList;
+import net.minecraft.server.level.GenerationChunkHolder;
+#endif
+
+
public class DhLitWorldGenRegion extends WorldGenRegion
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
+ private static ChunkStatus debugTriggeredForStatus = null;
+
+
public final DummyLightEngine lightEngine;
- public final BatchGenerationEnvironment.EmptyChunkGenerator generator;
+ public final BatchGenerationEnvironment.IEmptyChunkGeneratorFunc generator;
public final int writeRadius;
public final int size;
+
private final ChunkPos firstPos;
private final List cache;
- Long2ObjectOpenHashMap chunkMap = new Long2ObjectOpenHashMap();
+ private final Long2ObjectOpenHashMap chunkMap = new Long2ObjectOpenHashMap();
/**
* Present to reduce the chance that we accidentally break underlying MC code that isn't thread safe,
* specifically: "it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap.getAndMoveToFirst()"
*/
- ReentrantLock getChunkLock = new ReentrantLock();
+ private final ReentrantLock getChunkLock = new ReentrantLock();
- #if PRE_MC_1_18_2
+ #if MC_VER < MC_1_18_2
private ChunkPos overrideCenterPos = null;
public void setOverrideCenter(ChunkPos pos) { overrideCenterPos = pos; }
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
@Override
public int getCenterX()
{
@@ -100,11 +119,29 @@ public class DhLitWorldGenRegion extends WorldGenRegion
public DhLitWorldGenRegion(
+ int centerChunkX, int centerChunkZ,
+ ChunkAccess centerChunk,
ServerLevel serverLevel, DummyLightEngine lightEngine,
List chunkList, ChunkStatus chunkStatus, int writeRadius,
- BatchGenerationEnvironment.EmptyChunkGenerator generator)
+ BatchGenerationEnvironment.IEmptyChunkGeneratorFunc generator)
{
- super(serverLevel, chunkList #if POST_MC_1_17_1 , chunkStatus, writeRadius #endif );
+ #if MC_VER == MC_1_16_5
+ super(serverLevel, chunkList);
+ #elif MC_VER < MC_1_21
+ super(serverLevel, chunkList, chunkStatus, writeRadius);
+ #else
+ super(serverLevel,
+ StaticCache2D.create(
+ centerChunkX, centerChunkZ,
+ writeRadius * 2, (x,z) -> new DhGenerationChunkHolder(new ChunkPos(x, z))),
+ new ChunkStep(chunkStatus,
+ // reverse is needed because MC uses the index of the chunkStatus to determine how many items are in the list instead of the actual list count
+ new ChunkDependencies(ImmutableList.copyOf(ChunkStatus.getStatusList()).reverse()),
+ new ChunkDependencies(ImmutableList.copyOf(ChunkStatus.getStatusList()).reverse()),
+ writeRadius, (WorldGenContext var1, ChunkStep var2, StaticCache2D var3, ChunkAccess var4) -> null),
+ centerChunk);
+
+ #endif
this.firstPos = chunkList.get(0).getPos();
this.generator = generator;
this.lightEngine = lightEngine;
@@ -115,7 +152,7 @@ public class DhLitWorldGenRegion extends WorldGenRegion
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
// Bypass BCLib mixin overrides.
@Override
public boolean ensureCanWrite(BlockPos blockPos)
@@ -130,7 +167,7 @@ public class DhLitWorldGenRegion extends WorldGenRegion
{
return false;
}
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
if (center.isUpgrading())
{
LevelHeightAccessor levelHeightAccessor = center.getHeightAccessorForGeneration();
@@ -185,7 +222,7 @@ public class DhLitWorldGenRegion extends WorldGenRegion
BlockState blockState = this.getBlockState(blockPos);
// This is a bypass for the spawner block since MC complains about not having it
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
if (blockState.getBlock() instanceof SpawnerBlock)
{
return ((EntityBlock) blockState.getBlock()).newBlockEntity(blockPos, blockState);
@@ -198,12 +235,9 @@ public class DhLitWorldGenRegion extends WorldGenRegion
#endif
}
- // Skip BlockEntity stuff. It aren't really needed
+ /** Skip BlockEntity stuff. They aren't needed for our use case. */
@Override
- public boolean addFreshEntity(Entity entity)
- {
- return true;
- }
+ public boolean addFreshEntity(@NotNull Entity entity) { return true; }
// Allays have empty chunks even if it's outside the worldGenRegion
// @Override
@@ -214,13 +248,13 @@ public class DhLitWorldGenRegion extends WorldGenRegion
// Override to ensure no other mod mixins cause skipping the overrided
// getChunk(...)
@Override
- public ChunkAccess getChunk(int i, int j)
+ public @NotNull ChunkAccess getChunk(int chunkX, int chunkZ)
{
try
{
// lock is to prevent issues with underlying MC code that doesn't support multithreading
this.getChunkLock.lock();
- return this.getChunk(i, j, ChunkStatus.EMPTY);
+ return this.getChunk(chunkX, chunkZ, ChunkStatus.EMPTY);
}
finally
{
@@ -231,13 +265,19 @@ public class DhLitWorldGenRegion extends WorldGenRegion
// Override to ensure no other mod mixins cause skipping the overrided
// getChunk(...)
@Override
- public ChunkAccess getChunk(int i, int j, ChunkStatus chunkStatus)
+ public @NotNull ChunkAccess getChunk(int chunkX, int chunkZ, @NotNull ChunkStatus chunkStatus)
{
try
{
// lock is to prevent issues with underlying MC code that doesn't support multithreading
this.getChunkLock.lock();
- return this.getChunk(i, j, chunkStatus, true);
+
+ ChunkAccess chunk = this.getChunk(chunkX, chunkZ, chunkStatus, true);
+ if (chunk == null)
+ {
+ LodUtil.assertNotReach("getChunk shouldn't return null values");
+ }
+ return chunk;
}
finally
{
@@ -245,102 +285,117 @@ public class DhLitWorldGenRegion extends WorldGenRegion
}
}
- // Use this instead of super.getChunk() to bypass C2ME concurrency checks
- private ChunkAccess superGetChunk(int x, int z, ChunkStatus cs)
- {
- int k = x - firstPos.x;
- int l = z - firstPos.z;
- return cache.get(k + l * size);
- }
-
- // Use this instead of super.hasChunk() to bypass C2ME concurrency checks
- public boolean superHasChunk(int x, int z)
- {
- int k = x - firstPos.x;
- int l = z - firstPos.z;
- return l >= 0 && l < size && k >= 0 && k < size;
- }
-
- // Allow creating empty chunks even if it's outside the worldGenRegion
+ /** Allows creating empty chunks even if they're outside the worldGenRegion */
@Override
@Nullable
- public ChunkAccess getChunk(int i, int j, ChunkStatus chunkStatus, boolean bl)
+ public ChunkAccess getChunk(int chunkX, int chunkZ, @NotNull ChunkStatus chunkStatus, boolean returnNonNull)
{
- ChunkAccess chunk = getChunkAccess(i, j, chunkStatus, bl);
+ ChunkAccess chunk = this.getChunkAccess(chunkX, chunkZ, chunkStatus, returnNonNull);
if (chunk instanceof LevelChunk)
{
- chunk = new ImposterProtoChunk((LevelChunk) chunk #if POST_MC_1_18_2 , true #endif );
+ chunk = new ImposterProtoChunk((LevelChunk) chunk #if MC_VER >= MC_1_18_2 , true #endif );
}
return chunk;
}
- private static ChunkStatus debugTriggeredForStatus = null;
-
- private ChunkAccess getChunkAccess(int i, int j, ChunkStatus chunkStatus, boolean bl)
+ /**
+ * @param returnNonNull if true this method will always return a non-null chunk,
+ * if false it will return null if no chunk exists at the given position with the given status
+ */
+ private ChunkAccess getChunkAccess(int chunkX, int chunkZ, ChunkStatus chunkStatus, boolean returnNonNull)
{
- ChunkAccess chunk = superHasChunk(i, j) ? superGetChunk(i, j, ChunkStatus.EMPTY) : null;
- if (chunk != null && chunk.getStatus().isOrAfter(chunkStatus))
+ ChunkAccess chunk = this.superHasChunk(chunkX, chunkZ) ? this.superGetChunk(chunkX, chunkZ) : null;
+ if (chunk != null && ChunkWrapper.getStatus(chunk).isOrAfter(chunkStatus))
{
return chunk;
}
- if (!bl)
+ else if (!returnNonNull)
+ {
+ // no chunk found with the necessary status and null return values are allowed
return null;
+ }
+
+
+ // we need a non-null chunk
if (chunk == null)
{
- chunk = chunkMap.get(ChunkPos.asLong(i, j));
+ // check memory
+ chunk = this.chunkMap.get(ChunkPos.asLong(chunkX, chunkZ));
if (chunk == null)
{
- chunk = generator.generate(i, j);
+ // chunk isn't in memory, generate a new one
+ chunk = this.generator.generate(chunkX, chunkZ);
if (chunk == null)
+ {
throw new NullPointerException("The provided generator should not return null!");
- chunkMap.put(ChunkPos.asLong(i, j), chunk);
+ }
+ this.chunkMap.put(ChunkPos.asLong(chunkX, chunkZ), chunk);
}
}
+
if (chunkStatus != ChunkStatus.EMPTY && chunkStatus != debugTriggeredForStatus)
{
LOGGER.info("WorldGen requiring " + chunkStatus
+ " outside expected range detected. Force passing EMPTY chunk and seeing if it works.");
debugTriggeredForStatus = chunkStatus;
}
+
return chunk;
}
- /** Overriding allows us to use our own lighting engine */
- @Override
- public LevelLightEngine getLightEngine() { return this.lightEngine; }
-
- /** Overriding allows us to use our own lighting engine */
- @Override
- public int getBrightness(LightLayer lightLayer, BlockPos blockPos) { return 0; }
-
- /** Overriding allows us to use our own lighting engine */
- @Override
- public int getRawBrightness(BlockPos blockPos, int i) { return 0; }
-
- /** Overriding allows us to use our own lighting engine */
- @Override
- public boolean canSeeSky(BlockPos blockPos)
+ /** Use this instead of super.hasChunk() to bypass C2ME concurrency checks */
+ public boolean superHasChunk(int x, int z)
{
- return (getBrightness(LightLayer.SKY, blockPos) >= getMaxLightLevel());
+ int k = x - this.firstPos.x;
+ int l = z - this.firstPos.z;
+ return l >= 0 && l < this.size && k >= 0 && k < this.size;
}
- public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
+ /** Use this instead of super.getChunk() to bypass C2ME concurrency checks */
+ private ChunkAccess superGetChunk(int x, int z)
{
- return calculateBlockTint(blockPos, colorResolver);
+ int k = x - this.firstPos.x;
+ int l = z - this.firstPos.z;
+ return this.cache.get(k + l * this.size);
+ }
+
+
+ /** Overriding allows us to use our own lighting engine */
+ @Override
+ public @NotNull LevelLightEngine getLightEngine() { return this.lightEngine; }
+
+ /** Overriding allows us to use our own lighting engine */
+ @Override
+ public int getBrightness(@NotNull LightLayer lightLayer, @NotNull BlockPos blockPos) { return 0; }
+
+ /** Overriding allows us to use our own lighting engine */
+ @Override
+ public int getRawBrightness(@NotNull BlockPos blockPos, int i) { return 0; }
+
+ /** Overriding allows us to use our own lighting engine */
+ @Override
+ public boolean canSeeSky(@NotNull BlockPos blockPos)
+ {
+ return (this.getBrightness(LightLayer.SKY, blockPos) >= this.getMaxLightLevel());
+ }
+
+ public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver)
+ {
+ return this.calculateBlockTint(blockPos, colorResolver);
}
private Biome _getBiome(BlockPos pos)
{
- #if POST_MC_1_18_2
- return getBiome(pos).value();
+ #if MC_VER >= MC_1_18_2
+ return this.getBiome(pos).value();
#else
- return getBiome(pos);
+ return this.getBiome(pos);
#endif
}
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
{
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
int i = (Minecraft.getInstance()).options.biomeBlendRadius;
#else
int i = (Minecraft.getInstance()).options.biomeBlendRadius().get();
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DummyLightEngine.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DummyLightEngine.java
index 106af9f4a..f46b77131 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DummyLightEngine.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DummyLightEngine.java
@@ -39,7 +39,7 @@ public class DummyLightEngine extends LevelLightEngine
}
- #if PRE_MC_1_20_1
+ #if MC_VER < MC_1_20_1
@Override
public void onBlockEmissionIncrease(BlockPos blockPos, int i) { }
@@ -63,7 +63,7 @@ public class DummyLightEngine extends LevelLightEngine
#endif
@Override
- public void queueSectionData(LightLayer lightLayer, SectionPos sectionPos, @Nullable DataLayer dataLayer #if PRE_MC_1_20_1 , boolean bl #endif ) { }
+ public void queueSectionData(LightLayer lightLayer, SectionPos sectionPos, @Nullable DataLayer dataLayer #if MC_VER < MC_1_20_1 , boolean bl #endif ) { }
@Override
public void checkBlock(BlockPos blockPos) { }
@@ -87,7 +87,7 @@ public class DummyLightEngine extends LevelLightEngine
@Override
public void retainData(ChunkPos chunkPos, boolean bl) { }
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
@Override
public int getLightSectionCount() { throw new UnsupportedOperationException("This should never be used!"); }
@Override
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/LightGetterAdaptor.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/LightGetterAdaptor.java
index b18b8f41b..8e6c71586 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/LightGetterAdaptor.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/LightGetterAdaptor.java
@@ -23,15 +23,24 @@ import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
import net.minecraft.world.level.BlockGetter;
-#if POST_MC_1_17_1
+import net.minecraft.world.level.chunk.LightChunkGetter;
+
+#if MC_VER >= MC_1_17_1
import net.minecraft.world.level.LevelHeightAccessor;
#endif
-import net.minecraft.world.level.chunk.ChunkStatus;
-import net.minecraft.world.level.chunk.LightChunkGetter;
-#if POST_MC_1_20_1
+
+#if MC_VER >= MC_1_20_1
import net.minecraft.world.level.chunk.LightChunk;
#endif
+#if MC_VER <= MC_1_20_4
+import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+#endif
+
+
+
public class LightGetterAdaptor implements LightChunkGetter
{
private final BlockGetter heightGetter;
@@ -50,7 +59,7 @@ public class LightGetterAdaptor implements LightChunkGetter
}
@Override
- public #if PRE_MC_1_20_1 BlockGetter #else LightChunk #endif getChunkForLighting(int chunkX, int chunkZ)
+ public #if MC_VER < MC_1_20_1 BlockGetter #else LightChunk #endif getChunkForLighting(int chunkX, int chunkZ)
{
if (genRegion == null)
throw new IllegalStateException("World Gen region has not been set!");
@@ -64,7 +73,7 @@ public class LightGetterAdaptor implements LightChunkGetter
return shouldReturnNull ? null : (genRegion != null ? genRegion : heightGetter);
}
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
public LevelHeightAccessor getLevelHeightAccessor()
{
return heightGetter;
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/RegionFileStorageExternalCache.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/RegionFileStorageExternalCache.java
index d5c346c70..ff6283b64 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/RegionFileStorageExternalCache.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/RegionFileStorageExternalCache.java
@@ -1,13 +1,15 @@
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
+import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.storage.RegionFile;
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
+import org.apache.logging.log4j.Logger;
-import javax.annotation.Nullable;
+import org.jetbrains.annotations.Nullable;
import java.io.DataInputStream;
import java.io.IOException;
import java.nio.file.Files;
@@ -15,11 +17,27 @@ import java.nio.file.Path;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.ReentrantLock;
+#if MC_VER >= MC_1_20_6
+import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
+#endif
+
+/**
+ * @deprecated should be replaced with net.minecraft.world.level.chunk.storage.IOWorker to
+ * prevent potential file corruption and issues with the C2ME mod.
+ * Generally this would be done via (MC ServerLevel) level.getChunkSource().chunkMap.worker#loadAsync()
+ */
+@Deprecated
public class RegionFileStorageExternalCache implements AutoCloseable
{
+ private static final Logger LOGGER = DhLoggerBuilder.getLogger();
+
+ /** Can be null due to the C2ME mod */
+ @Nullable
public final RegionFileStorage storage;
public static final int MAX_CACHE_SIZE = 16;
+ public static boolean regionCacheNullPointerWarningSent = false;
+
/**
* Present to reduce the chance that we accidentally break underlying MC code that isn't thread safe,
* specifically: "it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap.getAndMoveToFirst()"
@@ -50,6 +68,19 @@ public class RegionFileStorageExternalCache implements AutoCloseable
@Nullable
public RegionFile getRegionFile(ChunkPos pos) throws IOException
{
+ if (this.storage == null)
+ {
+ if (!regionCacheNullPointerWarningSent)
+ {
+ regionCacheNullPointerWarningSent = true;
+ LOGGER.warn("Unable to access Minecraft's chunk cache. This may be due to another mod changing said cache. DH will be unable to access any Minecraft chunk data until said mod is removed.");
+ }
+
+ return null;
+ }
+
+
+
long posLong = ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ());
RegionFile rFile = null;
@@ -64,7 +95,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable
{
this.getRegionFileLock.lock();
- #if MC_1_16_5 || MC_1_17_1
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
rFile = this.storage.getRegionFile(pos);
// keeping the region cache size low helps prevent concurrency issues
@@ -84,7 +115,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable
}
catch (ArrayIndexOutOfBoundsException e)
{
- #if MC_1_16_5 || MC_1_17_1
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
// the file just wasn't cached
break;
#else
@@ -98,6 +129,19 @@ public class RegionFileStorageExternalCache implements AutoCloseable
}
#endif
}
+ catch (NullPointerException e)
+ {
+ // Can sometimes happen when other mods modify the region cache system (IE C2ME)
+ // instead of blowing up, just use DH's cache instead
+
+ if (!regionCacheNullPointerWarningSent)
+ {
+ regionCacheNullPointerWarningSent = true;
+ LOGGER.warn("Unable to access Minecraft's chunk cache. This may be due to another mod changing said cache. Falling back to DH's internal cache.");
+ }
+
+ break;
+ }
finally
{
this.getRegionFileLock.unlock();
@@ -126,7 +170,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable
// Otherwise, check if file exist, and if so, add it to the cache
Path storageFolderPath;
- #if MC_1_16_5 || MC_1_17_1
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
storageFolderPath = this.storage.folder.toPath();
#else
storageFolderPath = this.storage.folder;
@@ -138,10 +182,12 @@ public class RegionFileStorageExternalCache implements AutoCloseable
}
Path regionFilePath = storageFolderPath.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca");
- #if MC_1_16_5 || MC_1_17_1
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
rFile = new RegionFile(regionFilePath.toFile(), storageFolderPath.toFile(), false);
- #else
+ #elif MC_VER <= MC_1_20_4
rFile = new RegionFile(regionFilePath, storageFolderPath, false);
+ #else
+ rFile = new RegionFile(new RegionStorageInfo("level", null, "level type"), regionFilePath, storageFolderPath, false);
#endif
this.regionFileCache.add(new RegionFileCache(ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ()), rFile));
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/WorldGenStructFeatManager.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/WorldGenStructFeatManager.java
index 79259fd36..fcdc779b3 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/WorldGenStructFeatManager.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/WorldGenStructFeatManager.java
@@ -35,51 +35,56 @@ import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
-import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.levelgen.WorldGenSettings;
-#if PRE_MC_1_19_2
+#if MC_VER < MC_1_19_2
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
import net.minecraft.world.level.StructureFeatureManager;
#else
-#if POST_MC_1_19_4
+#if MC_VER >= MC_1_19_4
import net.minecraft.world.level.levelgen.WorldOptions;
#endif
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.StructureManager;
#endif
-#if POST_MC_1_18_2
+#if MC_VER >= MC_1_18_2
import net.minecraft.world.level.levelgen.structure.StructureCheck;
#endif
import net.minecraft.world.level.levelgen.structure.StructureStart;
-#if PRE_MC_1_18_2
+#if MC_VER < MC_1_18_2
import net.minecraft.world.level.levelgen.feature.StructureFeature;
#endif
+#if MC_VER <= MC_1_20_4
+import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+#endif
+
-public class WorldGenStructFeatManager extends #if PRE_MC_1_19_2 StructureFeatureManager #else StructureManager #endif
+public class WorldGenStructFeatManager extends #if MC_VER < MC_1_19_2 StructureFeatureManager #else StructureManager #endif
{
final WorldGenLevel genLevel;
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
WorldGenSettings worldGenSettings;
#else
WorldOptions worldOptions;
#endif
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
StructureCheck structureCheck;
#endif
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
public WorldGenStructFeatManager(
WorldGenSettings worldGenSettings,
- WorldGenLevel genLevel #if POST_MC_1_18_2 , StructureCheck structureCheck #endif )
+ WorldGenLevel genLevel #if MC_VER >= MC_1_18_2 , StructureCheck structureCheck #endif )
{
- super(genLevel, worldGenSettings #if POST_MC_1_18_2 , structureCheck #endif );
+ super(genLevel, worldGenSettings #if MC_VER >= MC_1_18_2 , structureCheck #endif );
this.genLevel = genLevel;
this.worldGenSettings = worldGenSettings;
}
@@ -100,8 +105,8 @@ public class WorldGenStructFeatManager extends #if PRE_MC_1_19_2 StructureFeatur
{
if (worldGenRegion == genLevel)
return this;
- #if PRE_MC_1_19_4
- return new WorldGenStructFeatManager(worldGenSettings, worldGenRegion #if POST_MC_1_18_2 , structureCheck #endif );
+ #if MC_VER < MC_1_19_4
+ return new WorldGenStructFeatManager(worldGenSettings, worldGenRegion #if MC_VER >= MC_1_18_2 , structureCheck #endif );
#else
return new WorldGenStructFeatManager(worldOptions, worldGenRegion, structureCheck);
#endif
@@ -113,7 +118,7 @@ public class WorldGenStructFeatManager extends #if PRE_MC_1_19_2 StructureFeatur
return genLevel.getChunk(x, z, status, false);
}
- #if PRE_MC_1_18_2
+ #if MC_VER < MC_1_18_2
@Override
public Stream extends StructureStart>> startsForFeature(
SectionPos sectionPos2,
@@ -140,7 +145,7 @@ public class WorldGenStructFeatManager extends #if PRE_MC_1_19_2 StructureFeatur
return chunk.hasAnyStructureReferences();
}
- #if MC_1_18_1
+ #if MC_VER == MC_1_18_1
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public List extends StructureStart>> startsForFeature(SectionPos sectionPos,
@@ -165,7 +170,7 @@ public class WorldGenStructFeatManager extends #if PRE_MC_1_19_2 StructureFeatur
return builder.build();
}
#else
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
@Override
public List startsForFeature(SectionPos sectionPos, Predicate> predicate)
{
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java
index 0ea6286a2..7fdce78f0 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java
@@ -27,15 +27,19 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGeneratio
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
import net.minecraft.server.level.WorldGenRegion;
-#if PRE_MC_1_19_2
-#endif
import net.minecraft.world.level.chunk.ChunkAccess;
-import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk;
-#if POST_MC_1_18_2
+
+#if MC_VER >= MC_1_18_2
import net.minecraft.world.level.levelgen.blending.Blender;
#endif
+#if MC_VER <= MC_1_20_4
+import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+#endif
+
public final class StepBiomes
{
public static final ChunkStatus STATUS = ChunkStatus.BIOMES;
@@ -52,29 +56,39 @@ public final class StepBiomes
List chunkWrappers)
{
- ArrayList chunksToDo = new ArrayList();
+ ArrayList chunksToDo = new ArrayList<>();
for (ChunkWrapper chunkWrapper : chunkWrappers)
{
ChunkAccess chunk = chunkWrapper.getChunk();
- if (chunk.getStatus().isOrAfter(STATUS)) continue;
- ((ProtoChunk) chunk).setStatus(STATUS);
- chunksToDo.add(chunk);
+ if (!chunkWrapper.getStatus().isOrAfter(STATUS))
+ {
+ #if MC_VER < MC_1_21
+ ((ProtoChunk) chunk).setStatus(STATUS);
+ #else
+ ((ProtoChunk) chunk).setPersistedStatus(STATUS);
+ #endif
+
+ chunksToDo.add(chunk);
+ }
}
for (ChunkAccess chunk : chunksToDo)
{
// System.out.println("StepBiomes: "+chunk.getPos());
- #if PRE_MC_1_18_2
- environment.params.generator.createBiomes(environment.params.biomes, chunk);
- #elif PRE_MC_1_19_2
- chunk = environment.joinSync(environment.params.generator.createBiomes(environment.params.biomes, Runnable::run, Blender.of(worldGenRegion),
+ #if MC_VER < MC_1_18_2
+ this.environment.params.generator.createBiomes(this.environment.params.biomes, chunk);
+ #elif MC_VER < MC_1_19_2
+ chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.biomes, Runnable::run, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
- #elif PRE_MC_1_19_4
- chunk = environment.joinSync(environment.params.generator.createBiomes(environment.params.biomes, Runnable::run, environment.params.randomState, Blender.of(worldGenRegion),
+ #elif MC_VER < MC_1_19_4
+ chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.biomes, Runnable::run, this.environment.params.randomState, Blender.of(worldGenRegion),
+ tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
+ #elif MC_VER < MC_1_21
+ chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(Runnable::run, this.environment.params.randomState, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#else
- chunk = environment.joinSync(environment.params.generator.createBiomes(Runnable::run, environment.params.randomState, Blender.of(worldGenRegion),
+ chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.randomState, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#endif
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java
index 8f2b94fb8..5ae538825 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java
@@ -19,24 +19,29 @@
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
-import java.util.ArrayList;
-
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
+import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
-import net.minecraft.ReportedException;
import net.minecraft.world.level.chunk.ChunkAccess;
-import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.levelgen.Heightmap;
-#if POST_MC_1_18_2
+import org.apache.logging.log4j.Logger;
+
+#if MC_VER <= MC_1_20_4
+import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif
+
public final class StepFeatures
{
+ private static final Logger LOGGER = DhLoggerBuilder.getLogger();
+
public static final ChunkStatus STATUS = ChunkStatus.FEATURES;
private final BatchGenerationEnvironment environment;
@@ -51,36 +56,44 @@ public final class StepFeatures
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
ArrayGridList chunkWrappers)
{
- ArrayList chunksToDo = new ArrayList();
-
for (ChunkWrapper chunkWrapper : chunkWrappers)
{
ChunkAccess chunk = chunkWrapper.getChunk();
- if (chunk.getStatus().isOrAfter(STATUS)) continue;
- ((ProtoChunk) chunk).setStatus(STATUS);
- chunksToDo.add(chunk);
- }
-
- for (ChunkAccess chunk : chunksToDo)
- {
+ if (!chunkWrapper.getStatus().isOrAfter(STATUS)
+ && chunk instanceof ProtoChunk)
+ {
+ #if MC_VER < MC_1_21
+ ((ProtoChunk) chunk).setStatus(STATUS);
+ #else
+ ((ProtoChunk) chunk).setPersistedStatus(STATUS);
+ #endif
+ }
+
+
try
{
- #if PRE_MC_1_18_2
+ #if MC_VER < MC_1_18_2
worldGenRegion.setOverrideCenter(chunk.getPos());
environment.params.generator.applyBiomeDecoration(worldGenRegion, tParams.structFeat);
#else
- environment.params.generator.applyBiomeDecoration(worldGenRegion, chunk,
- tParams.structFeat.forWorldGenRegion(worldGenRegion));
+ if (worldGenRegion.hasChunk(chunkWrapper.getChunkPos().x, chunkWrapper.getChunkPos().z))
+ {
+ this.environment.params.generator.applyBiomeDecoration(worldGenRegion, chunk, tParams.structFeat.forWorldGenRegion(worldGenRegion));
+ }
+ else
+ {
+ LOGGER.warn("Unable to generate features for chunk at pos ["+chunkWrapper.getChunkPos()+"], world gen region doesn't contain the chunk.");
+ }
#endif
Heightmap.primeHeightmaps(chunk, STATUS.heightmapsAfter());
BatchGenerationEnvironment.clearDistantGenerationMixinData();
}
- catch (ReportedException e)
+ catch (Exception e)
{
- e.printStackTrace();
+ LOGGER.warn("Unexpected issue when generating features for chunk at pos ["+chunkWrapper.getChunkPos()+"], error: ["+e.getMessage()+"].", e);
// FIXME: Features concurrent modification issue. Something about cocobeans might just
- // error out. For now just retry.
+ // error out. For now just retry.
}
}
}
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java
index f2670d97a..47b524cd5 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java
@@ -28,17 +28,19 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParame
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
import net.minecraft.server.level.WorldGenRegion;
-#if POST_MC_1_17_1
-#endif
-#if PRE_MC_1_19_2
-#endif
import net.minecraft.world.level.chunk.ChunkAccess;
-import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk;
-#if POST_MC_1_18_2
+
+#if MC_VER >= MC_1_18_2
import net.minecraft.world.level.levelgen.blending.Blender;
#endif
+#if MC_VER <= MC_1_20_4
+import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+#endif
+
public final class StepNoise
{
private static final ChunkStatus STATUS = ChunkStatus.NOISE;
@@ -56,29 +58,40 @@ public final class StepNoise
List chunkWrappers)
{
- ArrayList chunksToDo = new ArrayList();
+ ArrayList chunksToDo = new ArrayList<>();
for (ChunkWrapper chunkWrapper : chunkWrappers)
{
ChunkAccess chunk = chunkWrapper.getChunk();
- if (chunk.getStatus().isOrAfter(STATUS)) continue;
+ if (chunkWrapper.getStatus().isOrAfter(STATUS))
+ {
+ continue;
+ }
+
+ #if MC_VER < MC_1_21
((ProtoChunk) chunk).setStatus(STATUS);
+ #else
+ ((ProtoChunk) chunk).setPersistedStatus(STATUS);
+ #endif
chunksToDo.add(chunk);
}
for (ChunkAccess chunk : chunksToDo)
{
// System.out.println("StepNoise: "+chunk.getPos());
- #if PRE_MC_1_17_1
- environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk);
- #elif PRE_MC_1_18_2
- chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run,
+ #if MC_VER < MC_1_17_1
+ this.environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk);
+ #elif MC_VER < MC_1_18_2
+ chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run,
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
- #elif PRE_MC_1_19_2
- chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion),
+ #elif MC_VER < MC_1_19_2
+ chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion),
+ tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
+ #elif MC_VER < MC_1_21
+ chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), this.environment.params.randomState,
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#else
- chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), environment.params.randomState,
+ chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Blender.of(worldGenRegion), this.environment.params.randomState,
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#endif
UncheckedInterruptedException.throwIfInterrupted();
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java
index e9bc14cfb..e90819967 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java
@@ -27,12 +27,16 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGeneratio
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
import net.minecraft.server.level.WorldGenRegion;
-#if PRE_MC_1_19_2
-#endif
import net.minecraft.world.level.chunk.ChunkAccess;
-import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk;
+#if MC_VER <= MC_1_20_4
+import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+#endif
+
+
public final class StepStructureReference
{
private static final ChunkStatus STATUS = ChunkStatus.STRUCTURE_REFERENCES;
@@ -55,9 +59,15 @@ public final class StepStructureReference
for (ChunkWrapper chunkWrapper : chunkWrappers)
{
ChunkAccess chunk = chunkWrapper.getChunk();
- if (chunk.getStatus().isOrAfter(STATUS)) continue;
- ((ProtoChunk) chunk).setStatus(STATUS);
- chunksToDo.add(chunk);
+ if (!chunkWrapper.getStatus().isOrAfter(STATUS))
+ {
+ #if MC_VER < MC_1_21
+ ((ProtoChunk) chunk).setStatus(STATUS);
+ #else
+ ((ProtoChunk) chunk).setPersistedStatus(STATUS);
+ #endif
+ chunksToDo.add(chunk);
+ }
}
for (ChunkAccess chunk : chunksToDo)
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java
index b4d76c08d..8c53a0c12 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java
@@ -30,10 +30,16 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParame
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.chunk.ChunkAccess;
-import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk;
import org.apache.logging.log4j.Logger;
+#if MC_VER <= MC_1_20_4
+import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+#endif
+
+
public final class StepStructureStart
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
@@ -70,17 +76,21 @@ public final class StepStructureStart
for (ChunkWrapper chunkWrapper : chunkWrappers)
{
ChunkAccess chunk = chunkWrapper.getChunk();
- if (!chunk.getStatus().isOrAfter(STATUS))
+ if (!chunkWrapper.getStatus().isOrAfter(STATUS))
{
+ #if MC_VER < MC_1_21
((ProtoChunk) chunk).setStatus(STATUS);
+ #else
+ ((ProtoChunk) chunk).setPersistedStatus(STATUS);
+ #endif
chunksToDo.add(chunk);
}
}
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
if (environment.params.worldGenSettings.generateFeatures())
{
- #elif PRE_MC_1_19_4
+ #elif MC_VER < MC_1_19_4
if (environment.params.worldGenSettings.generateStructures()) {
#else
if (environment.params.worldOptions.generateStructures())
@@ -98,10 +108,10 @@ public final class StepStructureStart
// and should prevent some concurrency issues
STRUCTURE_PLACEMENT_LOCK.lock();
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
environment.params.generator.createStructures(environment.params.registry, tParams.structFeat, chunk, environment.params.structures,
environment.params.worldSeed);
- #elif PRE_MC_1_19_4
+ #elif MC_VER < MC_1_19_4
environment.params.generator.createStructures(environment.params.registry, environment.params.randomState, tParams.structFeat, chunk, environment.params.structures,
environment.params.worldSeed);
#else
@@ -110,7 +120,7 @@ public final class StepStructureStart
tParams.structFeat, chunk, environment.params.structures);
#endif
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
try
{
tParams.structCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts());
diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java
index 39c4a6e8d..0e61d70a2 100644
--- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java
+++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java
@@ -28,9 +28,14 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParame
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.chunk.ChunkAccess;
-import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk;
-import net.minecraft.world.level.levelgen.Heightmap;
+
+#if MC_VER <= MC_1_20_4
+import net.minecraft.world.level.chunk.ChunkStatus;
+#else
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+#endif
+
public final class StepSurface
{
@@ -53,17 +58,24 @@ public final class StepSurface
for (ChunkWrapper chunkWrapper : chunkWrappers)
{
ChunkAccess chunk = chunkWrapper.getChunk();
- if (chunk.getStatus().isOrAfter(STATUS)) continue;
- ((ProtoChunk) chunk).setStatus(STATUS);
- chunksToDo.add(chunk);
+ if (!chunkWrapper.getStatus().isOrAfter(STATUS))
+ {
+ #if MC_VER < MC_1_21
+ ((ProtoChunk) chunk).setStatus(STATUS);
+ #else
+ ((ProtoChunk) chunk).setPersistedStatus(STATUS);
+ #endif
+
+ chunksToDo.add(chunk);
+ }
}
for (ChunkAccess chunk : chunksToDo)
{
// System.out.println("StepSurface: "+chunk.getPos());
- #if PRE_MC_1_18_2
+ #if MC_VER < MC_1_18_2
environment.params.generator.buildSurfaceAndBedrock(worldGenRegion, chunk);
- #elif PRE_MC_1_19_2
+ #elif MC_VER < MC_1_19_2
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk);
#else
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), environment.params.randomState, chunk);
diff --git a/common/src/main/resources/1_20_6.distanthorizons.accesswidener b/common/src/main/resources/1_20_6.distanthorizons.accesswidener
new file mode 100644
index 000000000..427617544
--- /dev/null
+++ b/common/src/main/resources/1_20_6.distanthorizons.accesswidener
@@ -0,0 +1,46 @@
+accessWidener v1 named
+
+# used when determining where to save files to
+accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
+
+# used when rendering
+accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
+
+# used for grabbing vanilla rendered chunks
+accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
+
+#accessible method net/minecraft/client/renderer/LevelRenderer renderSectionLayer (Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V
+
+# world generation
+# accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
+accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
+accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
+accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
+
+# lod generation from save file
+accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
+accessible field net/minecraft/world/level/chunk/storage/IOWorker storage Lnet/minecraft/world/level/chunk/storage/RegionFileStorage;
+accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage regionCache Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
+accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage folder Ljava/nio/file/Path;
+
+# grabbing textures
+accessible class net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture
+accessible method net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture getFrameX (I)I
+accessible method net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture getFrameY (I)I
+accessible field net/minecraft/client/renderer/texture/SpriteContents animatedTexture Lnet/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture;
+accessible field net/minecraft/client/renderer/texture/SpriteContents originalImage Lcom/mojang/blaze3d/platform/NativeImage;
+
+# UI stuff
+accessible field net/minecraft/client/gui/components/AbstractButton SPRITES Lnet/minecraft/client/gui/components/WidgetSprites;
+# Handles inserting the config button
+accessible field net/minecraft/client/gui/layouts/HeaderAndFooterLayout headerFrame Lnet/minecraft/client/gui/layouts/FrameLayout;
+accessible field net/minecraft/client/gui/layouts/FrameLayout children Ljava/util/List;
+accessible class net/minecraft/client/gui/layouts/FrameLayout$ChildContainer
+accessible field net/minecraft/client/gui/layouts/LinearLayout wrapped Lnet/minecraft/client/gui/layouts/GridLayout;
+
+# hacky stuff
+accessible field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
+mutable field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
+accessible field net/minecraft/client/gui/components/AbstractSelectionList scrollAmount D # Hack to bypass vanilla's setScrollAmount's clamp
+
+
diff --git a/coreSubProjects b/coreSubProjects
index f32e25f52..28e1eaae7 160000
--- a/coreSubProjects
+++ b/coreSubProjects
@@ -1 +1 @@
-Subproject commit f32e25f52fac692a85ff36e423f7617ae8940370
+Subproject commit 28e1eaae77547a47efb33b809ec022c9b7640eb0
diff --git a/fabric/build.gradle b/fabric/build.gradle
index ccf5e7b7e..accf863fc 100644
--- a/fabric/build.gradle
+++ b/fabric/build.gradle
@@ -1,10 +1,10 @@
plugins {
- id "fabric-loom" version "1.1.+"
+ id "fabric-loom" version "1.6-SNAPSHOT"
}
loom {
accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
-
+
// "runs" isn't required, but when we do need it then it can be useful
runs {
client {
@@ -27,12 +27,15 @@ remapJar {
dependsOn shadowJar
}
+
configurations {
// The addModJar basically embeds the mod to the built jar
addModJar
include.extendsFrom addModJar
modImplementation.extendsFrom addModJar
}
+
+
def addMod(path, enabled) {
if (enabled == "2")
@@ -42,7 +45,7 @@ def addMod(path, enabled) {
}
dependencies {
- minecraft "com.mojang:minecraft:${minecraft_version}"
+ minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
mappings loom.layered() {
// Mojmap mappings
officialMojangMappings()
@@ -52,6 +55,13 @@ dependencies {
// Fabric loader
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
+
+// annotationProcessor "javax.annotation:javax.annotation-api:1.3.2"
+// implementation("javax.annotation:javax.annotation-api:1.3.2")
+// runtimeOnly "javax.annotation:javax.annotation-api:1.3.2"
+// compileOnly "javax.annotation:javax.annotation-api:1.3.2"
+// modImplementation "javax.annotation:javax.annotation-api:1.3.2"
+
// Fabric API
addModJar(fabricApi.module("fabric-api-base", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-lifecycle-events-v1", rootProject.fabric_api_version))
@@ -59,12 +69,15 @@ dependencies {
addModJar(fabricApi.module("fabric-events-interaction-v0", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-rendering-v1", rootProject.fabric_api_version)) // TODO: Remove this as it is only needed in 1 line (FabricClientProxy)
addModJar(fabricApi.module("fabric-networking-api-v1", rootProject.fabric_api_version))
+
+ // used by mod menu in MC 1.20.6+
+ addModJar(fabricApi.module("fabric-screen-api-v1", rootProject.fabric_api_version))
+ addModJar(fabricApi.module("fabric-key-binding-api-v1", rootProject.fabric_api_version))
+
// Mod Menu
modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}")
-
-
// Starlight
addMod("curse.maven:starlight-521783:${rootProject.starlight_version_fabric}", rootProject.enable_starlight)
@@ -78,22 +91,23 @@ dependencies {
modImplementation(fabricApi.module("fabric-rendering-data-attachment-v1", rootProject.fabric_api_version))
modImplementation(fabricApi.module("fabric-rendering-fluids-v1", rootProject.fabric_api_version))
}
-
+
// Lithium
addMod("maven.modrinth:lithium:${rootProject.lithium_version}", rootProject.enable_lithium)
-
+
// Iris
addMod("maven.modrinth:iris:${rootProject.iris_version}", rootProject.enable_iris)
-
+
// BCLib
addMod("com.github.quiqueck:BCLib:${rootProject.bclib_version}", rootProject.enable_bclib)
-
+
// Canvas
addMod("io.vram:canvas-fabric-${project.canvas_version}", rootProject.enable_canvas)
-
+
// Immersive Portals
- if (rootProject.enable_immersive_portals == "1")
- modCompileOnly ("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${project.immersive_portals_version}")
+ if (rootProject.enable_immersive_portals == "1") {
+ modCompileOnly("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${project.immersive_portals_version}")
+ }
else if (rootProject.enable_immersive_portals == "2") {
modImplementation ("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${project.immersive_portals_version}") {
exclude(group: "net.fabricmc.fabric-api")
@@ -126,26 +140,13 @@ processResources {
runClient {
dependsOn(copyCoreResources)
dependsOn(copyCommonLoaderResources)
- jvmArgs([ "-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg ])
+// jvmArgs([ "-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg ])
finalizedBy(deleteResources)
}
-//jar {
-// classifier "dev"
-//}
sourcesJar {
def commonSources = project(":common").sourcesJar
dependsOn commonSources
from commonSources.archiveFile.map { zipTree(it) }
-
-// def fabricLikeSources = project(":fabricLike").sourcesJar
-// dependsOn fabricLikeSources
-// from fabricLikeSources.archiveFile.map { zipTree(it) }
}
-
-//components.java {
-// withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
-// skip()
-// }
-//}
\ No newline at end of file
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientMain.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientMain.java
deleted file mode 100644
index 2990b3ffd..000000000
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientMain.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.seibel.distanthorizons.fabric;
-
-import com.seibel.distanthorizons.common.LodCommonMain;
-import com.seibel.distanthorizons.common.wrappers.DependencySetup;
-import net.fabricmc.api.ClientModInitializer;
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
-import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
-
-@Environment(EnvType.CLIENT)
-public class FabricClientMain implements ClientModInitializer
-{
- public static FabricClientProxy client_proxy;
- public static FabricServerProxy server_proxy;
-
-
- // Do if implements ClientModInitializer
- // This loads the mod before minecraft loads which causes a lot of issues
- @Override
- public void onInitializeClient()
- {
- DependencySetup.createClientBindings();
- FabricMain.init();
- LodCommonMain.initConfig();
-
- server_proxy = new FabricServerProxy(false);
- server_proxy.registerEvents();
-
- client_proxy = new FabricClientProxy();
- client_proxy.registerEvents();
-
- ClientLifecycleEvents.CLIENT_STARTED.register((mc) -> FabricMain.postInit());
- }
-
-}
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java
index 6eb5f15e4..71e35cd76 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java
@@ -19,7 +19,9 @@
package com.seibel.distanthorizons.fabric;
-import com.seibel.distanthorizons.common.rendering.SeamlessOverdraw;
+import com.mojang.blaze3d.systems.RenderSystem;
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
@@ -31,37 +33,36 @@ import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
+import com.seibel.distanthorizons.core.pos.DhBlockPos;
+import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
-import com.seibel.distanthorizons.coreapi.ModInfo;
+import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import com.seibel.distanthorizons.fabric.wrappers.modAccessor.SodiumAccessor;
//import io.netty.buffer.ByteBuf;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
-import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
-import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen;
+#if MC_VER < MC_1_19_4
import java.nio.FloatBuffer;
+#endif
import java.util.HashSet;
import net.minecraft.client.multiplayer.ClientLevel;
-import net.minecraft.client.multiplayer.ClientPacketListener;
-import net.minecraft.network.FriendlyByteBuf;
-import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.phys.HitResult;
import org.apache.logging.log4j.Logger;
+import org.joml.Matrix4f;
import org.lwjgl.glfw.GLFW;
-import org.lwjgl.opengl.GL15;
/**
* This handles all events sent to the client,
@@ -72,7 +73,7 @@ import org.lwjgl.opengl.GL15;
* @version 2023-7-27
*/
@Environment(EnvType.CLIENT)
-public class FabricClientProxy
+public class FabricClientProxy implements AbstractModInitializer.IEventProxy
{
private final ClientApi clientApi = ClientApi.INSTANCE;
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
@@ -127,17 +128,20 @@ public class FabricClientProxy
// if we have access to the server, use the chunk save event instead
if (MC.clientConnectedToDedicatedServer())
{
- // Since fabric doesn't have a client-side break-block API event, this is the next best thing
- ChunkAccess chunk = level.getChunk(blockPos);
- if (chunk != null)
+ if (SharedApi.isChunkAtBlockPosAlreadyUpdating(blockPos.getX(), blockPos.getZ()))
{
- LOGGER.trace("attack block at blockPos: " + blockPos);
-
- IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
- SharedApi.INSTANCE.chunkBlockChangedEvent(
- new ChunkWrapper(chunk, level, wrappedLevel),
- wrappedLevel
- );
+ // Since fabric doesn't have a client-side break-block API event, this is the next best thing
+ ChunkAccess chunk = level.getChunk(blockPos);
+ if (chunk != null)
+ {
+ //LOGGER.trace("attack block at blockPos: " + blockPos);
+
+ IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
+ SharedApi.INSTANCE.chunkBlockChangedEvent(
+ new ChunkWrapper(chunk, level, wrappedLevel),
+ wrappedLevel
+ );
+ }
}
}
@@ -151,20 +155,23 @@ public class FabricClientProxy
// if we have access to the server, use the chunk save event instead
if (MC.clientConnectedToDedicatedServer())
{
- // Since fabric doesn't have a client-side place-block API event, this is the next best thing
- if (hitResult.getType() == HitResult.Type.BLOCK
- && !hitResult.isInside())
+ if (SharedApi.isChunkAtBlockPosAlreadyUpdating(hitResult.getBlockPos().getX(), hitResult.getBlockPos().getZ()))
{
- ChunkAccess chunk = level.getChunk(hitResult.getBlockPos());
- if (chunk != null)
+ // Since fabric doesn't have a client-side place-block API event, this is the next best thing
+ if (hitResult.getType() == HitResult.Type.BLOCK
+ && !hitResult.isInside())
{
- LOGGER.trace("use block at blockPos: " + hitResult.getBlockPos());
-
- IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
- SharedApi.INSTANCE.chunkBlockChangedEvent(
- new ChunkWrapper(chunk, level, wrappedLevel),
- wrappedLevel
- );
+ ChunkAccess chunk = level.getChunk(hitResult.getBlockPos());
+ if (chunk != null)
+ {
+ //LOGGER.trace("use block at blockPos: " + hitResult.getBlockPos());
+
+ IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level);
+ SharedApi.INSTANCE.chunkBlockChangedEvent(
+ new ChunkWrapper(chunk, level, wrappedLevel),
+ wrappedLevel
+ );
+ }
}
}
}
@@ -187,30 +194,26 @@ public class FabricClientProxy
// render event //
//==============//
- //Define this in the MixinLevelRenderer so that it works with sodium without any changes to the code
- // TODO: If all else is fine, can we remove these commented code
- // Client Render Level
WorldRenderEvents.AFTER_SETUP.register((renderContext) ->
{
+ Mat4f projectionMatrix = McObjectConverter.Convert(renderContext.projectionMatrix());
+
+ Mat4f modelViewMatrix;
+ #if MC_VER < MC_1_20_6
+ modelViewMatrix = McObjectConverter.Convert(renderContext.matrixStack().last().pose());
+ #else
+ modelViewMatrix = McObjectConverter.Convert(renderContext.positionMatrix());
+ #endif
+
this.clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()),
- McObjectConverter.Convert(renderContext.matrixStack().last().pose()),
- McObjectConverter.Convert(renderContext.projectionMatrix()),
- renderContext.tickDelta());
-
-
- // experimental proof-of-concept option
- if (Config.Client.Advanced.Graphics.AdvancedGraphics.seamlessOverdraw.get())
- {
- float[] matrixFloatArray = SeamlessOverdraw.overwriteMinecraftNearFarClipPlanes(renderContext.projectionMatrix(), renderContext.tickDelta());
-
- #if MC_1_16_5
- SeamlessOverdraw.applyLegacyProjectionMatrix(matrixFloatArray);
- #elif PRE_MC_1_19_4
- renderContext.projectionMatrix().load(FloatBuffer.wrap(matrixFloatArray));
- #else
- renderContext.projectionMatrix().set(matrixFloatArray);
- #endif
- }
+ modelViewMatrix,
+ projectionMatrix,
+ #if MC_VER < MC_1_21
+ renderContext.tickDelta()
+ #else
+ renderContext.tickCounter().getGameTimeDeltaTicks()
+ #endif
+ );
});
// Debug keyboard event
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricDedicatedServerMain.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricDedicatedServerMain.java
deleted file mode 100644
index 88c4bfc59..000000000
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricDedicatedServerMain.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.seibel.distanthorizons.fabric;
-
-import com.seibel.distanthorizons.common.LodCommonMain;
-import com.seibel.distanthorizons.common.wrappers.DependencySetup;
-import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
-import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
-import com.seibel.distanthorizons.core.util.LodUtil;
-import net.fabricmc.api.DedicatedServerModInitializer;
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
-import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
-import net.minecraft.server.dedicated.DedicatedServer;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-@Environment(EnvType.SERVER)
-public class FabricDedicatedServerMain implements DedicatedServerModInitializer
-{
- private static final Logger LOGGER = LogManager.getLogger(FabricDedicatedServerMain.class.getSimpleName());
-
- public static FabricServerProxy server_proxy;
- public boolean hasPostSetupDone = false;
-
- @Override
- public void onInitializeServer()
- {
- DependencySetup.createServerBindings();
- FabricMain.init();
-
- // FIXME this prevents returning uninitialized Config values
- // resulting from a circular reference mid-initialization in a static class
- // ThreadPresetConfigEventHandler <-> Config
- ThreadPresetConfigEventHandler.INSTANCE.toString();
-
- server_proxy = new FabricServerProxy(true);
- server_proxy.registerEvents();
-
- ServerLifecycleEvents.SERVER_STARTING.register((server) ->
- {
- if (this.hasPostSetupDone)
- {
- return;
- }
-
- this.hasPostSetupDone = true;
- LodUtil.assertTrue(server instanceof DedicatedServer);
-
- MinecraftDedicatedServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer) server;
- LodCommonMain.initConfig();
- FabricMain.postInit();
-
- LOGGER.info("Dedicated server initialized at " + server.getServerDirectory());
- });
- }
-
-}
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java
index 5941f54c9..6f96d189b 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java
@@ -19,73 +19,56 @@
package com.seibel.distanthorizons.fabric;
-import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
-import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
-import com.seibel.distanthorizons.core.config.ConfigBase;
-import com.seibel.distanthorizons.core.jar.ModJarInfo;
-import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
-import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.*;
-import com.seibel.distanthorizons.common.LodCommonMain;
-import com.seibel.distanthorizons.coreapi.ModInfo;
+import com.mojang.brigadier.CommandDispatcher;
+import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.core.config.Config;
-import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
+import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
-import com.seibel.distanthorizons.fabric.wrappers.FabricDependencySetup;
+import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.*;
+import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.fabric.wrappers.modAccessor.*;
-
+import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.api.DedicatedServerModInitializer;
+import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
+import net.fabricmc.fabric.api.event.Event;
+import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.MinecraftServer;
import org.apache.logging.log4j.Logger;
import javax.swing.*;
+import java.awt.*;
+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.
- *
- * @author coolGi
- * @author Ran
- * @version 9-2-2022
*/
-public class FabricMain
+public class FabricMain extends AbstractModInitializer implements ClientModInitializer, DedicatedServerModInitializer
{
+ private static final ResourceLocation INITIAL_PHASE = ResourceLocation.tryParse("distanthorizons:dedicated_server_initial");
+
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
- public static void postInit()
- {
- LOGGER.info("Post-Initializing Mod");
- FabricDependencySetup.runDelayedSetup();
-
- if (Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get() && SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("bclib"))
- ModAccessorInjector.INSTANCE.get(IBCLibAccessor.class).setRenderCustomFog(false); // Remove BCLib's fog
- #if POST_MC_1_20_1
- if (SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("sodium"))
- ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class).setFogOcclusion(false); // FIXME: This is a tmp fix for sodium 0.5.0, and 0.5.1. This is fixed in sodium 0.5.2
- #endif
-
- if (ConfigBase.INSTANCE == null)
- throw new IllegalStateException("Config was not initialized. Make sure to call LodCommonMain.initConfig() before calling this method.");
-
- LOGGER.info("Mod Post-Initialized");
- }
- // This loads the mod after minecraft loads which doesn't causes a lot of issues
- public static void init()
+ @Override
+ protected void createInitialBindings() { SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); }
+
+ @Override
+ protected IEventProxy createClientProxy() { return new FabricClientProxy(); }
+
+ @Override
+ protected IEventProxy createServerProxy(boolean isDedicated) { return new FabricServerProxy(isDedicated); }
+
+ @Override
+ protected void initializeModCompat()
{
- ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
-
- LOGGER.info("Initializing Mod");
- LodCommonMain.startup(null);
- FabricDependencySetup.createInitialBindings();
- LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
-
- // Print git info (Useful for dev builds)
- LOGGER.info("DH Branch: " + ModJarInfo.Git_Branch);
- LOGGER.info("DH Commit: " + ModJarInfo.Git_Commit);
- LOGGER.info("DH Jar Build Source: " + ModJarInfo.Build_Source);
-
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
if (modChecker.isModLoaded("sodium"))
{
@@ -94,10 +77,13 @@ public class FabricMain
// If sodium is installed Indium is also necessary in order to use the Fabric rendering API
if (!modChecker.isModLoaded("indium"))
{
- // People don't read the crash logs!!!
- // So, just put a notification, so they hopefully realise what's the problem (and dont just open issues)
- System.setProperty("java.awt.headless", "false"); // Required to make it work
- JOptionPane.showMessageDialog(null, ModInfo.READABLE_NAME + " now relies on Indium to work with Sodium.\nPlease download Indium from https://modrinth.com/mod/indium", ModInfo.READABLE_NAME, JOptionPane.INFORMATION_MESSAGE);
+ String indiumMissingMessage = ModInfo.READABLE_NAME + " needs Indium to work with Sodium.\nPlease download Indium from https://modrinth.com/mod/indium";
+ LOGGER.fatal(indiumMissingMessage);
+
+ if (!GraphicsEnvironment.isHeadless())
+ {
+ JOptionPane.showMessageDialog(null, indiumMissingMessage, ModInfo.READABLE_NAME, JOptionPane.INFORMATION_MESSAGE);
+ }
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
String errorMessage = "loading Distant Horizons. Distant Horizons requires Indium in order to run with Sodium.";
@@ -105,30 +91,44 @@ public class FabricMain
mc.crashMinecraft(errorMessage, new Exception(exceptionError));
}
}
- if (modChecker.isModLoaded("starlight"))
- {
- ModAccessorInjector.INSTANCE.bind(IStarlightAccessor.class, new StarlightAccessor());
- }
- if (modChecker.isModLoaded("optifine"))
- {
- ModAccessorInjector.INSTANCE.bind(IOptifineAccessor.class, new OptifineAccessor());
- }
- if (modChecker.isModLoaded("bclib"))
- {
- ModAccessorInjector.INSTANCE.bind(IBCLibAccessor.class, new BCLibAccessor());
- }
- #if MC_1_16_5 || MC_1_18_2 || MC_1_19_2 || MC_1_19_4 || MC_1_20_1
- // 1.17.1 won't support this since there isn't a matching Iris version
- if (modChecker.isModLoaded("iris"))
- {
- ModAccessorInjector.INSTANCE.bind(IIrisAccessor.class, new IrisAccessor());
- }
+ this.tryCreateModCompatAccessor("starlight", IStarlightAccessor.class, StarlightAccessor::new);
+ this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
+ this.tryCreateModCompatAccessor("bclib", IBCLibAccessor.class, BCLibAccessor::new);
+ #if MC_VER >= MC_1_19_4
+ // 1.19.4 is the lowest version Iris supports DH
+ this.tryCreateModCompatAccessor("iris", IIrisAccessor.class, IrisAccessor::new);
+ #endif
+ }
+
+ @Override
+ protected void subscribeRegisterCommandsEvent(Consumer> eventHandler) { }
+
+ @Override
+ protected void subscribeClientStartedEvent(Runnable eventHandler) { ClientLifecycleEvents.CLIENT_STARTED.register((mc) -> eventHandler.run()); }
+
+ @Override
+ protected void subscribeServerStartingEvent(Consumer eventHandler)
+ {
+ ServerLifecycleEvents.SERVER_STARTING.addPhaseOrdering(INITIAL_PHASE, Event.DEFAULT_PHASE);
+ ServerLifecycleEvents.SERVER_STARTING.register(INITIAL_PHASE, eventHandler::accept);
+ }
+
+ @Override
+ protected void runDelayedSetup()
+ {
+ SingletonInjector.INSTANCE.runDelayedSetup();
+
+ if (Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get() && SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("bclib"))
+ ModAccessorInjector.INSTANCE.get(IBCLibAccessor.class).setRenderCustomFog(false); // Remove BCLib's fog
+
+ #if MC_VER >= MC_1_20_1
+ if (SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("sodium"))
+ ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class).setFogOcclusion(false); // FIXME: This is a tmp fix for sodium 0.5.0, and 0.5.1. This is fixed in sodium 0.5.2
#endif
- LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
-
- ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
+ if (ConfigBase.INSTANCE == null)
+ throw new IllegalStateException("Config was not initialized. Make sure to call LodCommonMain.initConfig() before calling this method.");
}
}
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricServerProxy.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricServerProxy.java
index 98f780d7b..71a0d8af7 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricServerProxy.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricServerProxy.java
@@ -1,11 +1,11 @@
package com.seibel.distanthorizons.fabric;
+import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
-import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
@@ -32,7 +32,7 @@ import java.util.function.Supplier;
* @author Tomlee
* @version 5-11-2022
*/
-public class FabricServerProxy
+public class FabricServerProxy implements AbstractModInitializer.IEventProxy
{
private static final ServerApi SERVER_API = ServerApi.INSTANCE;
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientLevel.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientLevel.java
index 4343c34a7..59c290576 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientLevel.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientLevel.java
@@ -24,7 +24,7 @@ import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import net.minecraft.client.multiplayer.ClientLevel;
-#if POST_MC_1_18_2
+#if MC_VER >= MC_1_18_2
#endif
import net.minecraft.world.level.chunk.LevelChunk;
import org.spongepowered.asm.mixin.Mixin;
@@ -44,14 +44,14 @@ public class MixinClientLevel
// //Moved to MixinClientPacketListener
// @Inject(method = "", at = @At("TAIL"))
// private void loadWorldEvent(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData, ResourceKey resourceKey,
-// #if POST_MC_1_18_2 Holder holder, #else DimensionType dimensionType, #endif int i,
-// #if POST_MC_1_18_2 int j, #endif Supplier supplier, LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci)
+// #if MC_VER >= MC_1_18_2 Holder holder, #else DimensionType dimensionType, #endif int i,
+// #if MC_VER >= MC_1_18_2 int j, #endif Supplier supplier, LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci)
// {
// ClientApi.INSTANCE.clientLevelLoadEvent(WorldWrapper.getWorldWrapper((ClientLevel)(Object)this));
// }
// Moved to overriding the enableChunkLight(...) method over at ClientPacketListener for 1.20+
- #if POST_MC_1_18_2 && PRE_MC_1_20_1 // Only the setLightReady is only available after 1.18. This ensures the light data is ready.
+ #if MC_VER >= MC_1_18_2 && MC_VER < MC_1_20_1 // Only the setLightReady is only available after 1.18. This ensures the light data is ready.
@Inject(method = "setLightReady", at = @At("HEAD"))
private void onChunkLightReady(int x, int z, CallbackInfo ci)
{
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientPacketListener.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientPacketListener.java
index b290d6aad..2430745bb 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientPacketListener.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientPacketListener.java
@@ -7,11 +7,12 @@ import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener;
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;
-#if POST_MC_1_20_1
+#if MC_VER >= MC_1_20_1
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.world.level.chunk.LevelChunk;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
@@ -23,15 +24,31 @@ public class MixinClientPacketListener
@Shadow
private ClientLevel level;
+ @Unique
+ private ClientLevel previousLevel;
+
+
@Inject(method = "handleLogin", at = @At("RETURN"))
void onHandleLoginEnd(CallbackInfo ci) { ClientApi.INSTANCE.onClientOnlyConnected(); }
@Inject(method = "handleRespawn", at = @At("HEAD"))
- void onHandleRespawnStart(CallbackInfo ci) { ClientApi.INSTANCE.clientLevelUnloadEvent(ClientLevelWrapper.getWrapper(this.level)); }
+ void onHandleRespawnStart(CallbackInfo ci) { this.previousLevel = this.level; }
@Inject(method = "handleRespawn", at = @At("RETURN"))
- void onHandleRespawnEnd(CallbackInfo ci) { ClientApi.INSTANCE.clientLevelLoadEvent(ClientLevelWrapper.getWrapper(this.level)); }
+ void onHandleRespawnEnd(CallbackInfo ci)
+ {
+ // If the player changes dimensions the "this.level" will be changed halfway through the respawn method.
+ // By checking if the object references are the same, we can see if the previous level should be unloaded
+ // or if the player just respawned in the same level.
+ if (this.previousLevel != this.level)
+ {
+ ClientApi.INSTANCE.clientLevelUnloadEvent(ClientLevelWrapper.getWrapper(this.previousLevel));
+ ClientApi.INSTANCE.clientLevelLoadEvent(ClientLevelWrapper.getWrapper(this.level));
+ }
+
+ this.previousLevel = null;
+ }
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
@Inject(method = "cleanup", at = @At("HEAD"))
#else
@Inject(method = "close", at = @At("HEAD"))
@@ -45,7 +62,7 @@ public class MixinClientPacketListener
ClientApi.INSTANCE.onClientOnlyDisconnected();
}
- #if POST_MC_1_20_1
+ #if MC_VER >= MC_1_20_1
@Inject(method = "enableChunkLight", at = @At("TAIL"))
void onEnableChunkLight(LevelChunk chunk, int x, int z, CallbackInfo ci)
{
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinDynamicTexture.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinDynamicTexture.java
deleted file mode 100644
index 881da29c2..000000000
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinDynamicTexture.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * This file is part of the Distant Horizons mod
- * licensed under the GNU LGPL v3 License.
- *
- * Copyright (C) 2020-2023 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.fabric.mixins.client;
-
-
-import com.mojang.blaze3d.platform.NativeImage;
-import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
-import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
-import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
-import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
-import com.seibel.distanthorizons.common.util.ILightTextureMarker;
-import net.minecraft.client.renderer.texture.DynamicTexture;
-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;
-
-@Mixin(DynamicTexture.class)
-public class MixinDynamicTexture implements ILightTextureMarker
-{
- /** Used to prevent accidentally using other dynamic textures as a lightmap */
- @Unique
- private boolean isLightTexture = false;
-
- @Shadow
- @Final
- private NativeImage pixels;
-
- @Inject(method = "upload()V", at = @At("HEAD"))
- public void updateLightTexture(CallbackInfo ci)
- {
- // since the light map is always updated on the client render thread we should be able to access the client level at the same time
- IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
- if (!this.isLightTexture
- || mc == null
- || mc.getWrappedClientLevel() == null
- )
- {
- return;
- }
-
- //ApiShared.LOGGER.info("Lightmap update");
- IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
- MinecraftRenderWrapper.INSTANCE.updateLightmap(this.pixels, clientLevel);
- }
-
- public void markLightTexture() { this.isLightTexture = true; }
-
-}
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinFogRenderer.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinFogRenderer.java
index ead892c02..3f24f1865 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinFogRenderer.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinFogRenderer.java
@@ -35,7 +35,7 @@ import net.minecraft.client.renderer.FogRenderer.FogMode;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
-#if PRE_MC_1_17_1
+#if MC_VER < MC_1_17_1
import net.minecraft.world.level.material.FluidState;
#else
import net.minecraft.world.level.material.FogType;
@@ -50,14 +50,14 @@ public class MixinFogRenderer
private static final float A_EVEN_LARGER_VALUE = 42069420694206942069.F;
@Inject(at = @At("RETURN"), method = "setupFog")
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, CallbackInfo callback)
{
#else
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, float g, CallbackInfo callback)
{
#endif
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
FluidState fluidState = camera.getFluidInCamera();
boolean cameraNotInFluid = fluidState.isEmpty();
#else
@@ -71,7 +71,7 @@ public class MixinFogRenderer
&& !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial()
&& Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get())
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
RenderSystem.fogStart(A_REALLY_REALLY_BIG_VALUE);
RenderSystem.fogEnd(A_EVEN_LARGER_VALUE);
#else
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinGameRenderer.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinGameRenderer.java
index 27b97fe65..4cc9c68c2 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinGameRenderer.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinGameRenderer.java
@@ -16,7 +16,7 @@ public class MixinGameRenderer
private static final Logger LOGGER = LogManager.getLogger(MixinGameRenderer.class.getSimpleName());
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
// FIXME: This I think will dup multiple renderStartupEvent calls...
@Inject(method = {"reloadShaders", "preloadUiShader"}, at = @At("TAIL"))
public void onStartupShaders(CallbackInfo ci)
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLevelRenderer.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLevelRenderer.java
index 5c687cd4e..12bbb0421 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLevelRenderer.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLevelRenderer.java
@@ -20,15 +20,20 @@
package com.seibel.distanthorizons.fabric.mixins.client;
import com.mojang.blaze3d.vertex.PoseStack;
-#if PRE_MC_1_19_4
+#if MC_VER < MC_1_19_4
import com.mojang.math.Matrix4f;
#else
-import net.minecraft.client.Camera;
-import net.minecraft.client.renderer.GameRenderer;
-import net.minecraft.client.renderer.LightTexture;
import org.joml.Matrix4f;
#endif
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
+import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
+import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
+import com.seibel.distanthorizons.core.api.internal.ClientApi;
+import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
+import net.minecraft.client.Camera;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.GameRenderer;
+import net.minecraft.client.renderer.LightTexture;
import com.seibel.distanthorizons.core.config.Config;
import net.minecraft.client.Camera;
import net.minecraft.client.multiplayer.ClientLevel;
@@ -37,6 +42,7 @@ import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.world.level.lighting.LevelLightEngine;
+import org.lwjgl.opengl.GL15;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
@@ -62,50 +68,66 @@ public class MixinLevelRenderer
{
@Shadow
private ClientLevel level;
- @Unique
- private static float previousPartialTicks = 0;
- // Inject rendering at first call to renderChunkLayer
- // HEAD or RETURN
- #if PRE_MC_1_17_1
- @Inject(at = @At("RETURN"), method = "renderSky(Lcom/mojang/blaze3d/vertex/PoseStack;F)V")
- private void renderSky(PoseStack matrixStackIn, float partialTicks, CallbackInfo callback)
- {
- // get the partial ticks since renderBlockLayer doesn't
- // have access to them
- previousPartialTicks = partialTicks;
- }
- #else
- @Inject(method = "renderClouds", at = @At("HEAD"), cancellable = true)
- public void renderClouds(PoseStack poseStack, Matrix4f projectionMatrix, float tickDelta, double cameraX, double cameraY, double cameraZ, CallbackInfo ci) {
- // get the partial ticks since renderChunkLayer doesn't
- // have access to them
- previousPartialTicks = tickDelta;
- }
- #endif
-
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDD)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack matrixStackIn, double xIn, double yIn, double zIn, CallbackInfo callback)
- #elif PRE_MC_1_19_4
+ #elif MC_VER < MC_1_19_4
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLcom/mojang/math/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
- #elif PRE_MC_1_20_2
+ #elif MC_VER < MC_1_20_2
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
- #else
+ #elif MC_VER < MC_1_20_6
@Inject(at = @At("HEAD"),
method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double camX, double camY, double camZ, Matrix4f projectionMatrix, CallbackInfo callback)
+ #else
+ @Inject(at = @At("HEAD"),
+ method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;DDDLorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V",
+ cancellable = true)
+ private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f projectionMatrix, Matrix4f frustumMatrix, CallbackInfo callback)
#endif
{
+ #if MC_VER == MC_1_16_5
+ // get the matrices from the OpenGL fixed pipeline
+ float[] mcProjMatrixRaw = new float[16];
+ GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
+ Mat4f mcProjectionMatrix = new Mat4f(mcProjMatrixRaw);
+ mcProjectionMatrix.transpose();
+
+ Mat4f mcModelViewMatrix = McObjectConverter.Convert(matrixStackIn.last().pose());
+
+ #elif MC_VER <= MC_1_20_4
+ // get the matrices directly from MC
+ Mat4f mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose());
+ Mat4f mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
+ #else
+ // get the matrices directly from MC
+ Mat4f mcModelViewMatrix = McObjectConverter.Convert(projectionMatrix);
+ Mat4f mcProjectionMatrix = new Mat4f();
+ mcProjectionMatrix.setIdentity();
+ #endif
+
+ if (renderType.equals(RenderType.translucent())) {
+ ClientApi.INSTANCE.renderDeferredLods(ClientLevelWrapper.getWrapper(this.level),
+ mcModelViewMatrix,
+ mcProjectionMatrix,
+ #if MC_VER < MC_1_21
+ Minecraft.getInstance().getFrameTime()
+ #else
+ Minecraft.getInstance().getTimer().getRealtimeDeltaTicks()
+ #endif
+ );
+ }
+
// FIXME completely disables rendering when sodium is installed
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
{
@@ -113,15 +135,18 @@ public class MixinLevelRenderer
}
}
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
@Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runUpdates(IZZ)I"), method = "renderLevel")
public void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
- #elif PRE_MC_1_20_1
+ #elif MC_VER < MC_1_20_1
@Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runUpdates(IZZ)I"), method = "renderLevel")
public void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
+ #elif MC_VER < MC_1_20_6
+ @Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I"), method = "renderLevel")
+ private void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
#else
@Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I"), method = "renderLevel")
- private void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
+ private void callAfterRunUpdates(CallbackInfo ci)
#endif
{
ChunkWrapper.syncedUpdateClientLightStatus();
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLightTexture.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLightTexture.java
index db9c56535..f09edc1f5 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLightTexture.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLightTexture.java
@@ -20,9 +20,14 @@
package com.seibel.distanthorizons.fabric.mixins.client;
-import com.seibel.distanthorizons.common.util.ILightTextureMarker;
+import com.mojang.blaze3d.platform.NativeImage;
+
+import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.renderer.LightTexture;
-import net.minecraft.client.renderer.texture.DynamicTexture;
+
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -35,13 +40,20 @@ public class MixinLightTexture
{
@Shadow
@Final
- private DynamicTexture lightTexture;
+ private NativeImage lightPixels;
- @Inject(method = "", at = @At("RETURN"))
- public void markLightTexture(CallbackInfo ci)
+
+ @Inject(method = "updateLightTexture(F)V", at = @At("RETURN"))
+ public void updateLightTexture(float partialTicks, CallbackInfo ci)
{
- //
- ((ILightTextureMarker) this.lightTexture).markLightTexture();
+ IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
+ if (mc == null || mc.getWrappedClientLevel() == null)
+ {
+ return;
+ }
+
+ IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
+ MinecraftRenderWrapper.INSTANCE.updateLightmap(this.lightPixels, clientLevel);
}
}
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinMinecraft.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinMinecraft.java
index 92d79850a..f6b4b112a 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinMinecraft.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinMinecraft.java
@@ -1,6 +1,6 @@
package com.seibel.distanthorizons.fabric.mixins.client;
-import com.seibel.distanthorizons.api.enums.config.EUpdateBranch;
+import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
@@ -8,10 +8,12 @@ import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
-import net.minecraft.client.Minecraft;
+import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen;
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.Redirect;
@@ -25,8 +27,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Minecraft.class)
public class MixinMinecraft
{
- #if PRE_MC_1_20_2
- #if MC_1_20_1
+ /**
+ * Can be enabled for testing the auto updater UI.
+ * will always show the auto updater if set to true.
+ */
+ @Unique
+ private static final boolean DEBUG_ALWAYS_SHOW_UPDATER = false;
+
+
+
+ #if MC_VER < MC_1_20_2
+ #if MC_VER == MC_1_20_1
@Redirect(
method = "Lnet/minecraft/client/Minecraft;setInitialScreen(Lcom/mojang/realmsclient/client/RealmsClient;Lnet/minecraft/server/packs/resources/ReloadInstance;Lnet/minecraft/client/main/GameConfig$QuickPlayData;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V")
@@ -41,17 +52,17 @@ public class MixinMinecraft
public void onOpenScreen(Minecraft instance, Screen guiScreen)
{
#endif
- if (!Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get()) // Don't do anything if the user doesn't want it
+ if (!Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() && !DEBUG_ALWAYS_SHOW_UPDATER) // Don't do anything if the user doesn't want it
{
instance.setScreen(guiScreen); // Sets the screen back to the vanilla screen as if nothing ever happened
return;
}
- if (SelfUpdater.onStart())
+ if (SelfUpdater.onStart() || DEBUG_ALWAYS_SHOW_UPDATER)
{
instance.setScreen(new UpdateModScreen(
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
- (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()): GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
+ (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()): GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
));
}
else
@@ -61,7 +72,7 @@ public class MixinMinecraft
}
#endif
- #if POST_MC_1_20_2
+ #if MC_VER >= MC_1_20_2
@Redirect(
method = "Lnet/minecraft/client/Minecraft;onGameLoadFinished(Lnet/minecraft/client/Minecraft$GameLoadCookie;)V",
at = @At(value = "INVOKE", target = "Ljava/lang/Runnable;run()V")
@@ -69,15 +80,31 @@ public class MixinMinecraft
private void buildInitialScreens(Runnable runnable)
{
if (
- Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() // Don't do anything if the user doesn't want it
- && SelfUpdater.onStart()
- )
+ DEBUG_ALWAYS_SHOW_UPDATER ||
+ (
+ // Don't do anything if the user doesn't want it
+ Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get()
+ && SelfUpdater.onStart()
+ )
+ )
{
- runnable = () -> {
+ runnable = () ->
+ {
+ String versionId;
+ EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
+ if (updateBranch == EDhApiUpdateBranch.STABLE)
+ {
+ versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
+ }
+ else
+ {
+ versionId = GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha");
+ }
+
Minecraft.getInstance().setScreen(new UpdateModScreen(
// TODO: Change to runnable, instead of tittle screen
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
- (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()) : GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
+ versionId
));
};
}
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinOptionsScreen.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinOptionsScreen.java
index 7fbb823a1..d638536f7 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinOptionsScreen.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinOptionsScreen.java
@@ -23,59 +23,134 @@ import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.config.Config;
-import net.minecraft.client.gui.screens.OptionsScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
-#if PRE_MC_1_19_2
+#if MC_VER < MC_1_19_2
import net.minecraft.network.chat.TranslatableComponent;
#endif
import net.minecraft.resources.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;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+
+#if MC_VER >= MC_1_20_6
+import net.minecraft.client.gui.layouts.LinearLayout;
+import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Shadow;
+#endif
+
+#if MC_VER < MC_1_21
+import net.minecraft.client.gui.screens.OptionsScreen;
+#else
+import net.minecraft.client.gui.screens.options.OptionsScreen;
+#endif
+
/**
* Adds a button to the menu to goto the config
*
* @author coolGi
- * @version 12-02-2021
+ * @version 2024-5-20
*/
@Mixin(OptionsScreen.class)
public class MixinOptionsScreen extends Screen
{
- // Get the texture for the button
- private static final ResourceLocation ICON_TEXTURE = new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
- protected MixinOptionsScreen(Component title)
- {
- super(title);
- }
+ /** Texture used for the config opening button */
+ @Unique
+ private static final ResourceLocation ICON_TEXTURE =
+ #if MC_VER < MC_1_21
+ new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
+ #else
+ ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
+ #endif
- @Inject(at = @At("HEAD"), method = "init")
+
+ @Unique
+ private TexturedButtonWidget optionsButton = null;
+
+ #if MC_VER >= MC_1_20_6
+ @Shadow
+ @Final
+ protected HeaderAndFooterLayout layout;
+ #endif
+
+
+
+ //==============//
+ // constructors //
+ //==============//
+
+ protected MixinOptionsScreen(Component title) { super(title); }
+
+ @Inject(at = @At("RETURN"), method = "init")
private void lodconfig$init(CallbackInfo ci)
{
if (Config.Client.optionsButton.get())
- this. #if PRE_MC_1_17_1 addButton #else addRenderableWidget #endif
- (new TexturedButtonWidget(
- // 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
- (buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(GetConfigScreen.getScreen(this)),
- // Add a title to the utton
- #if PRE_MC_1_19_2
- new TranslatableComponent(ModInfo.ID + ".title")));
- #else
- Component.translatable(ModInfo.ID + ".title")));
- #endif
+ {
+ #if MC_VER < MC_1_17_1
+ this.addButton(this.getOptionsButton());
+ #elif MC_VER < MC_1_20_6
+ this.addRenderableWidget(this.getOptionsButton());
+ #else
+
+ // add the button so it's rendered
+ this.addRenderableWidget(this.getOptionsButton());
+
+ // add the button to the correct location in the UI
+ // TODO is there a better way to do this instead of using access transformers to inject into the exact UI elements?
+ LinearLayout layout = (LinearLayout) this.layout.headerFrame.children.get(0).child;
+
+ // determine how wide the other option buttons are so we can put our botton to the left of them all
+ AtomicInteger width = new AtomicInteger(0);
+ layout.visitChildren(x -> { width.addAndGet(x.getWidth()); });
+ width.addAndGet(-10); // padding between the DH button and the FOV slider
+
+ layout.wrapped.addChild(this.getOptionsButton(), 1, 2, (settings) -> { settings.paddingLeft(width.get() * -1); });
+ layout.arrangeElements();
+
+ #endif
+ }
+ }
+
+
+
+ //================//
+ // helper methods //
+ //================//
+
+ @Unique
+ public TexturedButtonWidget getOptionsButton()
+ {
+ if (this.optionsButton == null)
+ {
+ this.optionsButton
+ = new TexturedButtonWidget(
+ // Where the button is on the screen
+ this.width / 2 - 180, this.height / 6 - 12,
+ // Width and height of the button
+ 20, 20,
+ // texture UV 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
+ (buttonWidget) -> Objects.requireNonNull(this.minecraft).setScreen(GetConfigScreen.getScreen(this)),
+ // Add a title to the button
+ #if MC_VER < MC_1_19_2
+ new TranslatableComponent(ModInfo.ID + ".title"));
+ #else
+ Component.translatable(ModInfo.ID + ".title"));
+ #endif
+ }
+
+ return this.optionsButton;
}
}
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinTextureUtil.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinTextureUtil.java
index 91e27661c..597d5a609 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinTextureUtil.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinTextureUtil.java
@@ -16,7 +16,7 @@ import org.spongepowered.asm.mixin.injection.Redirect;
public class MixinTextureUtil
{
@Redirect(method = "Lcom/mojang/blaze3d/platform/TextureUtil;prepareImage(Lcom/mojang/blaze3d/platform/NativeImage$InternalGlFormat;IIII)V",
- at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;_texParameter(IIF)V", #if MC_1_16_5 remap = true #else remap = false #endif))
+ at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;_texParameter(IIF)V", #if MC_VER == MC_1_16_5 remap = true #else remap = false #endif))
private static void setLodBias(int target, int pname, float param)
{
float biasValue = Config.Client.Advanced.Graphics.AdvancedGraphics.lodBias.get().floatValue();
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/events/MixinServerLevel.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/events/MixinServerLevel.java
index a475b61a6..9d02eb99d 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/events/MixinServerLevel.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/events/MixinServerLevel.java
@@ -31,7 +31,7 @@ import org.spongepowered.asm.mixin.Mixin;
@Deprecated // TODO: Not sure if this is needed anymore
public class MixinServerLevel
{
-// #if PRE_MC_1_17_1
+// #if MC_VER < MC_1_17_1
// @Inject(method = "save", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;save(Z)V", shift = At.Shift.AFTER))
// private void saveWorldEvent(ProgressListener progressListener, boolean bl, boolean bl2, CallbackInfo ci) {
// Main.client_proxy.worldSaveEvent();
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/mods/sodium/MixinSodiumRenderer.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/mods/sodium/MixinSodiumRenderer.java
index bb9741d58..498fdf8c9 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/mods/sodium/MixinSodiumRenderer.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/mods/sodium/MixinSodiumRenderer.java
@@ -2,7 +2,7 @@ package com.seibel.distanthorizons.fabric.mixins.mods.sodium;
/* Removed since DH now uses Indium so we can use the Fabric rendering API instead
-#if POST_MC_1_20_1
+#if MC_VER >= MC_1_20_1
// Sodium 0.5
import com.mojang.blaze3d.vertex.PoseStack;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
@@ -55,7 +55,7 @@ public class MixinSodiumRenderer
}
-#elif POST_MC_1_17_1
+#elif MC_VER >= MC_1_17_1
// Sodium 0.3 to 0.4
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinChunkGenerator.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinChunkGenerator.java
index e0d28ec86..14be488cd 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinChunkGenerator.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinChunkGenerator.java
@@ -22,7 +22,7 @@ package com.seibel.distanthorizons.fabric.mixins.server;
import org.spongepowered.asm.mixin.Mixin;
import net.minecraft.world.level.chunk.ChunkGenerator;
-#if PRE_MC_1_18_2
+#if MC_VER < MC_1_18_2
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinChunkMap.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinChunkMap.java
index 90033b89a..ffef0238c 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinChunkMap.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinChunkMap.java
@@ -28,56 +28,66 @@ public class MixinChunkMap
@Final
ServerLevel level;
- @Inject(method = "save", at = @At(value = "INVOKE", target = CHUNK_SERIALIZER_WRITE))
+ // firing at INVOKE causes issues with C2ME and is probably unnecessary since we
+ // don't need the chunk(s) before MC has finished saving them
+ @Inject(method = "save", at = @At(value = "RETURN", target = CHUNK_SERIALIZER_WRITE))
private void onChunkSave(ChunkAccess chunk, CallbackInfoReturnable ci)
{
- //=====================================//
- // corrupt/incomplete chunk validation //
- //=====================================//
-
- // 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_1_16_5 || MC_1_17_1
- if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
+ // true means a chunk was saved to disk
+ if (ci.getReturnValue())
{
- return;
+ // TODO is this validation necessary since we are checking above if
+ // the callback return value should state if the chunk was actually saved or not?
+ // Do we trust it to always be correct?
+
+ //=====================================//
+ // corrupt/incomplete chunk validation //
+ //=====================================//
+
+ // 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_16_5 || MC_VER == MC_1_17_1
+ if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
+ {
+ return;
+ }
+ #else
+ if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect())
+ {
+ return;
+ }
+ #endif
+
+
+ //==================//
+ // biome validation //
+ //==================//
+
+ // some chunks may be missing their biomes, which cause issues when attempting to save them
+ #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
+ if (chunk.getBiomes() == null)
+ {
+ return;
+ }
+ #else
+ try
+ {
+ // this will throw an exception if the biomes aren't set up
+ chunk.getNoiseBiome(0,0,0);
+ }
+ catch (Exception e)
+ {
+ return;
+ }
+ #endif
+
+
+
+ ServerApi.INSTANCE.serverChunkSaveEvent(
+ new ChunkWrapper(chunk, this.level, ServerLevelWrapper.getWrapper(this.level)),
+ ServerLevelWrapper.getWrapper(this.level)
+ );
}
- #else
- if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect())
- {
- return;
- }
- #endif
-
-
- //==================//
- // biome validation //
- //==================//
-
- // some chunks may be missing their biomes, which cause issues when attempting to save them
- #if MC_1_16_5 || MC_1_17_1
- if (chunk.getBiomes() == null)
- {
- return;
- }
- #else
- try
- {
- // this will throw an exception if the biomes aren't set up
- chunk.getNoiseBiome(0,0,0);
- }
- catch (Exception e)
- {
- return;
- }
- #endif
-
-
-
- ServerApi.INSTANCE.serverChunkSaveEvent(
- new ChunkWrapper(chunk, this.level, ServerLevelWrapper.getWrapper(this.level)),
- ServerLevelWrapper.getWrapper(this.level)
- );
}
}
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinUtilBackgroundThread.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinUtilBackgroundThread.java
index 6e58f36af..8bfd986df 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinUtilBackgroundThread.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinUtilBackgroundThread.java
@@ -50,7 +50,7 @@ public class MixinUtilBackgroundThread
}
}
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
@Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/lang/Runnable;)Ljava/lang/Runnable;",
at = @At("HEAD"), cancellable = true)
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable ci)
@@ -62,7 +62,7 @@ public class MixinUtilBackgroundThread
}
}
#endif
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
@Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/util/function/Supplier;)Ljava/util/function/Supplier;",
at = @At("HEAD"), cancellable = true)
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier> r, CallbackInfoReturnable> ci)
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/unsafe/MixinThreadingDetector.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/unsafe/MixinThreadingDetector.java
deleted file mode 100644
index b6027388f..000000000
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/unsafe/MixinThreadingDetector.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * This file is part of the Distant Horizons mod
- * licensed under the GNU LGPL v3 License.
- *
- * Copyright (C) 2020-2023 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.fabric.mixins.server.unsafe;
-
-import org.spongepowered.asm.mixin.Mixin;
-
-//FIXME: Is this still needed?
-#if POST_MC_1_18_2
-
-import net.minecraft.util.ThreadingDetector;
-import org.spongepowered.asm.mixin.Mutable;
-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;
-
-import java.util.concurrent.Semaphore;
-
-/**
- * Why does this exist? But okay! (Will be probably removed when the experimental generator is done)
- * FIXME: Recheck this
- */
-@Mixin(ThreadingDetector.class)
-public class MixinThreadingDetector
-{
- @Mutable
- @Shadow
- private Semaphore lock;
-
- @Inject(method = "", at = @At("RETURN"))
- private void setSemaphore(CallbackInfo ci)
- {
- this.lock = new Semaphore(2);
- }
-
-}
-#else
-
-import net.minecraft.server.level.ServerLevel;
-
-@Mixin(ServerLevel.class)
-public class MixinThreadingDetector { } //FIXME: Is there some way to make this file just not be added?
-#endif
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/BCLibAccessor.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/BCLibAccessor.java
index a12f1f0a4..06efa7741 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/BCLibAccessor.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/BCLibAccessor.java
@@ -1,11 +1,11 @@
package com.seibel.distanthorizons.fabric.wrappers.modAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IBCLibAccessor;
-#if MC_1_16_5 || MC_1_17_1 || MC_1_20_4 // These versions either don't have BCLib, or the implementation is different
-#elif MC_1_18_2
+#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 || MC_VER == MC_1_20_4 || MC_VER == MC_1_20_6 // These versions either don't have BCLib, or the implementation is different
+#elif MC_VER == MC_1_18_2
import ru.bclib.config.ClientConfig;
import ru.bclib.config.Configs;
-#else
+#elif MC_VER < MC_1_21
import org.betterx.bclib.config.ClientConfig;
import org.betterx.bclib.config.Configs;
#endif
@@ -17,7 +17,8 @@ public class BCLibAccessor implements IBCLibAccessor
public void setRenderCustomFog(boolean newValue)
{
- #if !(MC_1_16_5 || MC_1_17_1 || MC_1_20_4) // These versions either don't have BCLib, or the implementation is different
+ // only some MC versions have BCLib and require this fix
+ #if (MC_VER > MC_1_17_1 && MC_VER < MC_1_20_4)
// Change the value of CUSTOM_FOG_RENDERING in the bclib client config
// This disabled fog from rendering within bclib
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/IrisAccessor.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/IrisAccessor.java
index 37fe1b2a0..90753eee3 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/IrisAccessor.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/IrisAccessor.java
@@ -19,10 +19,14 @@
package com.seibel.distanthorizons.fabric.wrappers.modAccessor;
-#if MC_1_16_5 || MC_1_18_2 || MC_1_19_2 || MC_1_19_4 || MC_1_20_1
+#if MC_VER >= MC_1_19_4
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
+#if MC_VER <= MC_1_20_4
import net.coderbot.iris.Iris;
+#else
+import net.irisshaders.iris.Iris;
+#endif
import net.irisshaders.iris.api.v0.IrisApi;
public class IrisAccessor implements IIrisAccessor
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/ModChecker.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/ModChecker.java
index 1e4d15622..dcd7d7fd7 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/ModChecker.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/ModChecker.java
@@ -22,6 +22,8 @@ package com.seibel.distanthorizons.fabric.wrappers.modAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import net.fabricmc.loader.api.FabricLoader;
+import java.io.File;
+
public class ModChecker implements IModChecker
{
public static final ModChecker INSTANCE = new ModChecker();
@@ -32,4 +34,10 @@ public class ModChecker implements IModChecker
return FabricLoader.getInstance().isModLoaded(modid);
}
+ @Override
+ public File modLocation(String modid)
+ {
+ return new File(FabricLoader.getInstance().getModContainer(modid).get().getOrigin().getPaths().get(0).toUri());
+ }
+
}
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/SodiumAccessor.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/SodiumAccessor.java
index 72289277a..7145d673a 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/SodiumAccessor.java
+++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/SodiumAccessor.java
@@ -33,7 +33,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAcce
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer;
import net.minecraft.client.Minecraft;
-#if PRE_MC_1_17_1
+#if MC_VER < MC_1_17_1
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.world.entity.Entity;
@@ -60,21 +60,21 @@ public class SodiumAccessor implements ISodiumAccessor
return "Sodium-Fabric";
}
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
@Override
public HashSet getNormalRenderedChunks()
{
SodiumWorldRenderer renderer = SodiumWorldRenderer.instance();
LevelHeightAccessor height = Minecraft.getInstance().level;
- #if POST_MC_1_20_1
+ #if MC_VER >= MC_1_20_1
// TODO: This is just a tmp solution, use a proper solution later
return MC_RENDER.getMaximumRenderedChunks().stream().filter((DhChunkPos chunk) -> {
return (renderer.isBoxVisible(
chunk.getMinBlockX() + 1, height.getMinBuildHeight() + 1, chunk.getMinBlockZ() + 1,
chunk.getMinBlockX() + 15, height.getMaxBuildHeight() - 1, chunk.getMinBlockZ() + 15));
}).collect(Collectors.toCollection(HashSet::new));
- #elif POST_MC_1_18_2
+ #elif MC_VER >= MC_1_18_2
// 0b11 = Lighted chunk & loaded chunk
return renderer.getChunkTracker().getChunks(0b00).filter(
(long l) -> {
@@ -134,7 +134,7 @@ public class SodiumAccessor implements ISodiumAccessor
@Override
public void setFogOcclusion(boolean b)
{
- #if POST_MC_1_20_1
+ #if MC_VER >= MC_1_20_1
me.jellysquid.mods.sodium.client.SodiumClientMod.options().performance.useFogOcclusion = b;
#endif
}
diff --git a/fabric/src/main/resources/DistantHorizons.fabric.mixins.json b/fabric/src/main/resources/DistantHorizons.fabric.mixins.json
index ffde1f7c4..38fab22fe 100644
--- a/fabric/src/main/resources/DistantHorizons.fabric.mixins.json
+++ b/fabric/src/main/resources/DistantHorizons.fabric.mixins.json
@@ -3,7 +3,6 @@
"minVersion": "0.8",
"package": "com.seibel.distanthorizons.fabric.mixins",
"mixins": [
- "server.unsafe.MixinThreadingDetector",
"server.MixinChunkGenerator",
"server.MixinChunkMap",
"server.MixinUtilBackgroundThread"
@@ -15,7 +14,6 @@
"client.MixinFogRenderer",
"client.MixinGameRenderer",
"client.MixinLevelRenderer",
- "client.MixinDynamicTexture",
"client.MixinLightTexture",
"client.MixinOptionsScreen",
"client.MixinMinecraft",
diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json
index 2ffe2d3cc..db15ae4bf 100644
--- a/fabric/src/main/resources/fabric.mod.json
+++ b/fabric/src/main/resources/fabric.mod.json
@@ -17,17 +17,17 @@
},
"license": "LGPL-3",
- "icon": "icon.png",
+ "icon": "assets/distanthorizons/icon.png",
"accessWidener": "distanthorizons.accesswidener",
"environment": "*",
"entrypoints": {
"client": [
- "com.seibel.distanthorizons.fabric.FabricClientMain"
+ "com.seibel.distanthorizons.fabric.FabricMain"
],
"server": [
- "com.seibel.distanthorizons.fabric.FabricDedicatedServerMain"
+ "com.seibel.distanthorizons.fabric.FabricMain"
],
"modmenu": [
"com.seibel.distanthorizons.fabric.wrappers.config.ModMenuIntegration"
@@ -56,7 +56,6 @@
},
"suggests": {
- "blendium": "*"
},
"breaks": $fabric_incompatibility_list,
diff --git a/forge/build.gradle b/forge/build.gradle
index ec9aca1e3..790890245 100644
--- a/forge/build.gradle
+++ b/forge/build.gradle
@@ -1,8 +1,10 @@
plugins {
+ // Note: This is only needed for multi-loader projects
+ // The main architectury loom version is set at the start of the root build.gradle
id "architectury-plugin" version "3.4-SNAPSHOT"
}
-sourceCompatibility = targetCompatibility = JavaVersion.VERSION_17
+sourceCompatibility = targetCompatibility = JavaVersion.VERSION_21
architectury {
platformSetupLoomIde()
@@ -18,6 +20,7 @@ architectury {
//}
loom {
+ silentMojangMappingsLicense() // Shut the licencing warning
accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
forge {
@@ -25,7 +28,7 @@ loom {
extraAccessWideners.add loom.accessWidenerPath.get().asFile.name
mixinConfigs = [
- "DistantHorizons.mixins.json"
+ "DistantHorizons.forge.mixins.json"
]
}
@@ -36,7 +39,7 @@ loom {
setConfigName("Forge Client")
ideConfigGenerated(true)
runDir("../run")
- vmArgs("-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg)
+// vmArgs("-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg)
}
server {
server()
@@ -52,13 +55,13 @@ remapJar {
dependsOn shadowJar
}
-
def addMod(path, enabled) {
if (enabled == "2")
dependencies { implementation(path) }
else if (enabled == "1")
dependencies { modCompileOnly(path) }
}
+
dependencies {
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
mappings loom.layered() {
@@ -71,24 +74,22 @@ dependencies {
// Forge
forge "net.minecraftforge:forge:${rootProject.minecraft_version}-${rootProject.forge_version}"
- // Architectury API
-// if (minecraft_version == "1.16.5") {
-// implementation("me.shedaniel:architectury-forge:${rootProject.architectury_version}")
-// } else {
-// implementation("dev.architectury:architectury-forge:${rootProject.architectury_version}")
-// }
-
- // Starlight
- addMod("curse.maven:starlight-forge-526854:${rootProject.starlight_version_forge}", rootProject.enable_starlight_forge)
-// annotationProcessor "org.spongepowered:mixin:0.8.4:processor"
-
addMod("curse.maven:TerraForged-363820:${rootProject.terraforged_version}", rootProject.enable_terraforged)
addMod("curse.maven:TerraFirmaCraft-302973:4616004", rootProject.enable_terrafirmacraft)
-// if (System.getProperty("idea.sync.active") != "true") {
-// annotationProcessor "org.spongepowered:mixin:0.8.4:processor"
-// }
+
+ if ( // Only run on MC 1.20.6 or later
+ // FIXME: Add an environment variable for the Major, Minor, and Patch version number of Minecraft
+ minecraft_version.split("\\.")[1].toInteger() >= 20 &&
+ (
+ minecraft_version.split("\\.").length > 1 && // Incase there isn't a minor version
+ minecraft_version.split("\\.")[2].toInteger() >= 6
+ )
+ ) {
+ // (potential) hack fix, force jopt-simple to be exactly 5.0.4 because Mojang ships that version, but some transitive dependencies request 6.0+
+ implementation('net.sf.jopt-simple:jopt-simple:5.0.4') //{ version { strictly '5.0.4' } }
+ }
}
task deleteResources(type: Delete) {
@@ -109,15 +110,3 @@ tasks.named('runClient') {
finalizedBy(deleteResources)
}
-
-sourcesJar {
- def commonSources = project(":common").sourcesJar
- dependsOn commonSources
- from commonSources.archiveFile.map { zipTree(it) }
-}
-
-//components.java {
-// withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
-// skip()
-// }
-//}
\ No newline at end of file
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java
index c96b8ce10..036bc979b 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java
@@ -19,6 +19,7 @@
package com.seibel.distanthorizons.forge;
+import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.util.ProxyUtil;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
@@ -36,7 +37,7 @@ import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.client.multiplayer.ClientLevel;
-#if PRE_MC_1_19_2
+#if MC_VER < MC_1_19_2
import net.minecraftforge.event.world.ChunkEvent;
import net.minecraftforge.event.world.WorldEvent;
#else
@@ -44,13 +45,13 @@ import net.minecraftforge.event.level.ChunkEvent;
import net.minecraftforge.event.level.LevelEvent;
#endif
-#if POST_MC_1_18_2
+#if MC_VER >= MC_1_18_2
import net.minecraftforge.client.event.RenderLevelStageEvent;
#endif
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraft.world.level.chunk.ChunkAccess;
-import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
+import net.minecraftforge.common.MinecraftForge;
//import net.minecraftforge.network.NetworkRegistry;
//import net.minecraftforge.network.simple.SimpleChannel;
import org.apache.logging.log4j.Logger;
@@ -71,7 +72,7 @@ import org.lwjgl.opengl.GL32;
* @author James_Seibel
* @version 2023-7-27
*/
-public class ForgeClientProxy
+public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
{
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
@@ -79,7 +80,7 @@ public class ForgeClientProxy
// private static SimpleChannel multiversePluginChannel;
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
private static LevelAccessor GetEventLevel(WorldEvent e) { return e.getWorld(); }
#else
private static LevelAccessor GetEventLevel(LevelEvent e) { return e.getLevel(); }
@@ -87,6 +88,15 @@ public class ForgeClientProxy
+ @Override
+ public void registerEvents()
+ {
+ MinecraftForge.EVENT_BUS.register(this);
+ this.setupNetworkingListeners();
+ }
+
+
+
//=============//
// tick events //
//=============//
@@ -107,7 +117,7 @@ public class ForgeClientProxy
//==============//
@SubscribeEvent
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
public void clientLevelLoadEvent(WorldEvent.Load event)
#else
public void clientLevelLoadEvent(LevelEvent.Load event)
@@ -115,7 +125,7 @@ public class ForgeClientProxy
{
LOGGER.info("level load");
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
LevelAccessor level = event.getWorld();
#else
LevelAccessor level = event.getLevel();
@@ -131,15 +141,15 @@ public class ForgeClientProxy
ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper);
}
@SubscribeEvent
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
public void clientLevelUnloadEvent(WorldEvent.Unload event)
#else
- public void clientLevelUnloadEvent(LevelEvent.Load event)
+ public void clientLevelUnloadEvent(LevelEvent.Unload event)
#endif
{
LOGGER.info("level unload");
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
LevelAccessor level = event.getWorld();
#else
LevelAccessor level = event.getLevel();
@@ -163,9 +173,14 @@ public class ForgeClientProxy
@SubscribeEvent
public void rightClickBlockEvent(PlayerInteractEvent.RightClickBlock event)
{
- LOGGER.trace("interact or block place event at blockPos: " + event.getPos());
+ if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
+ {
+ return;
+ }
- #if PRE_MC_1_19_2
+ //LOGGER.trace("interact or block place event at blockPos: " + event.getPos());
+
+ #if MC_VER < MC_1_19_2
LevelAccessor level = event.getWorld();
#else
LevelAccessor level = event.getLevel();
@@ -177,9 +192,14 @@ public class ForgeClientProxy
@SubscribeEvent
public void leftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event)
{
- LOGGER.trace("break or block attack at blockPos: " + event.getPos());
+ if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
+ {
+ return;
+ }
- #if PRE_MC_1_19_2
+ //LOGGER.trace("break or block attack at blockPos: " + event.getPos());
+
+ #if MC_VER < MC_1_19_2
LevelAccessor level = event.getWorld();
#else
LevelAccessor level = event.getLevel();
@@ -217,7 +237,7 @@ public class ForgeClientProxy
//==============//
@SubscribeEvent
- public void registerKeyBindings(#if PRE_MC_1_19_2 InputEvent.KeyInputEvent #else InputEvent.Key #endif event)
+ public void registerKeyBindings(#if MC_VER < MC_1_19_2 InputEvent.KeyInputEvent #else InputEvent.Key #endif event)
{
if (Minecraft.getInstance().player == null)
{
@@ -237,8 +257,7 @@ public class ForgeClientProxy
// networking //
//============//
- /** @param event this is just to ensure the event is called at the right time, if it is called outside the {@link FMLClientSetupEvent} event, the binding may fail */
- public static void setupNetworkingListeners(FMLClientSetupEvent event)
+ public void setupNetworkingListeners()
{
// multiversePluginChannel = NetworkRegistry.newSimpleChannel(
// new ResourceLocation(ModInfo.NETWORKING_RESOURCE_NAMESPACE, ModInfo.MULTIVERSE_PLUGIN_NAMESPACE),
@@ -298,20 +317,18 @@ public class ForgeClientProxy
//===========//
@SubscribeEvent
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
public void afterLevelRenderEvent(RenderLevelStageEvent event)
#else
public void afterLevelRenderEvent(TickEvent.RenderTickEvent event)
#endif
{
- #if POST_MC_1_20_1
+ #if MC_VER >= MC_1_20_1
if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_LEVEL)
- #elif POST_MC_1_18_2
+ #elif MC_VER >= MC_1_18_2
if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_SOLID_BLOCKS)
#else
- // FIXME: Is this the correct location for 1.16 & 1.17???
- // I couldnt find anything for rendering after the level, so is rendering after overlays ok?
- if (event.type.equals(TickEvent.RenderTickEvent.Type.WORLD))
+ if (event.type.equals(TickEvent.RenderTickEvent.Type.RENDER))
#endif
{
try
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeMain.java b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeMain.java
index 6ee80e4de..3a853f08e 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeMain.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeMain.java
@@ -19,184 +19,115 @@
package com.seibel.distanthorizons.forge;
-import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
-import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
-import com.seibel.distanthorizons.common.LodCommonMain;
-import com.seibel.distanthorizons.common.forge.LodForgeMethodCaller;
-import com.seibel.distanthorizons.common.wrappers.DependencySetup;
+import com.mojang.brigadier.CommandDispatcher;
+import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
-import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
-import com.seibel.distanthorizons.core.jar.ModJarInfo;
-import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor;
-import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.coreapi.ModInfo;
-import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
-import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
-import com.seibel.distanthorizons.forge.wrappers.ForgeDependencySetup;
+import com.seibel.distanthorizons.forge.wrappers.modAccessor.ModChecker;
import com.seibel.distanthorizons.forge.wrappers.modAccessor.OptifineAccessor;
-import net.minecraft.client.renderer.block.model.BakedQuad;
-import net.minecraft.core.Direction;
-#if POST_MC_1_19_2
-import net.minecraft.util.RandomSource;
-#endif
-import net.minecraft.world.level.ColorResolver;
-import net.minecraft.world.level.biome.Biome;
-import net.minecraft.world.level.block.Block;
-import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.server.MinecraftServer;
import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.*;
+#if MC_VER == MC_1_16_5
+import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
+#elif MC_VER == MC_1_17_1
+import net.minecraftforge.fmlserverevents.FMLServerStartingEvent;
+#else
+import net.minecraftforge.event.server.ServerStartingEvent;
+#endif
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
-#if PRE_MC_1_17_1
+#if MC_VER < MC_1_17_1
import net.minecraftforge.fml.ExtensionPoint;
-#elif MC_1_17_1
+#elif MC_VER == MC_1_17_1
import net.minecraftforge.fmlclient.ConfigGuiHandler;
-#elif POST_MC_1_18_2 && PRE_MC_1_19_2
+#elif MC_VER >= MC_1_18_2 && MC_VER < MC_1_19_2
import net.minecraftforge.client.ConfigGuiHandler;
#else
import net.minecraftforge.client.ConfigScreenHandler;
#endif
-import org.apache.logging.log4j.Logger;
-
// these imports change due to forge refactoring classes in 1.19
-#if PRE_MC_1_19_2
+#if MC_VER < MC_1_19_2
import net.minecraftforge.client.model.data.ModelDataMap;
import java.util.Random;
#else
-import net.minecraft.client.renderer.RenderType;
-import net.minecraftforge.client.model.data.ModelData;
#endif
-import java.lang.invoke.MethodHandles;
-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.
- *
- * @author coolGi
- * @author Ran
- * @author James Seibel
- * @version 8-15-2022
*/
@Mod(ModInfo.ID)
-public class ForgeMain implements LodForgeMethodCaller
+public class ForgeMain extends AbstractModInitializer
{
- private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
- public static ForgeClientProxy client_proxy = null;
- public static ForgeServerProxy server_proxy = null;
-
public ForgeMain()
{
- DependencySetup.createClientBindings();
-
-// initDedicated(null);
-// initDedicated(null);
// Register the mod initializer (Actual event registration is done in the different proxies)
- FMLJavaModLoadingContext.get().getModEventBus().addListener(this::initClient);
- FMLJavaModLoadingContext.get().getModEventBus().addListener(this::initDedicated);
+ FMLJavaModLoadingContext.get().getModEventBus().addListener((FMLClientSetupEvent e) -> this.onInitializeClient());
+ FMLJavaModLoadingContext.get().getModEventBus().addListener((FMLDedicatedServerSetupEvent e) -> this.onInitializeServer());
}
- private void initClient(final FMLClientSetupEvent event)
+ @Override
+ protected void createInitialBindings() { SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); }
+
+ @Override
+ protected IEventProxy createClientProxy() { return new ForgeClientProxy(); }
+
+ @Override
+ protected IEventProxy createServerProxy(boolean isDedicated) { return new ForgeServerProxy(isDedicated); }
+
+ @Override
+ protected void initializeModCompat()
{
- ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
+ this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
- LOGGER.info("Initializing Mod");
- LodCommonMain.startup(this);
- ForgeDependencySetup.createInitialBindings();
- LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
-
- // Print git info (Useful for dev builds)
- LOGGER.info("DH Branch: " + ModJarInfo.Git_Branch);
- LOGGER.info("DH Commit: " + ModJarInfo.Git_Commit);
- LOGGER.info("DH Jar Build Source: " + ModJarInfo.Build_Source);
-
- client_proxy = new ForgeClientProxy();
- MinecraftForge.EVENT_BUS.register(client_proxy);
- server_proxy = new ForgeServerProxy(false);
- MinecraftForge.EVENT_BUS.register(server_proxy);
-
- if (AbstractOptifineAccessor.optifinePresent())
- {
- ModAccessorInjector.INSTANCE.bind(IOptifineAccessor.class, new OptifineAccessor());
- }
-
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY,
() -> (client, parent) -> GetConfigScreen.getScreen(parent));
- #elif MC_1_17_1 || MC_1_18_2 || PRE_MC_1_19_2
+ #elif MC_VER >= MC_1_17_1 && MC_VER < MC_1_19_2
ModLoadingContext.get().registerExtensionPoint(ConfigGuiHandler.ConfigGuiFactory.class,
() -> new ConfigGuiHandler.ConfigGuiFactory((client, parent) -> GetConfigScreen.getScreen(parent)));
#else
ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class,
() -> new ConfigScreenHandler.ConfigScreenFactory((client, parent) -> GetConfigScreen.getScreen(parent)));
#endif
-
- ForgeClientProxy.setupNetworkingListeners(event);
-
- LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
-
- ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
-
- // Init config
- // The reason im initialising in this rather than the post init process is cus im using this for the auto updater
- LodCommonMain.initConfig();
}
- private void initDedicated(final FMLDedicatedServerSetupEvent event)
- {
-// DependencySetup.createServerBindings();
-// initCommon();
-
-// server_proxy = new ForgeServerProxy(true);
-// MinecraftForge.EVENT_BUS.register(server_proxy);
-//
- postInitCommon();
- }
-
- private void postInitCommon()
- {
- LOGGER.info("Post-Initializing Mod");
- ForgeDependencySetup.runDelayedSetup();
-
- LOGGER.info("Mod Post-Initialized");
- }
-
- #if PRE_MC_1_19_2
- private final ModelDataMap modelData = new ModelDataMap.Builder().build();
- #else
- private final ModelData modelData = ModelData.EMPTY;
- #endif
-
@Override
- #if PRE_MC_1_19_2
- public List getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, Random random)
+ protected void subscribeRegisterCommandsEvent(Consumer> eventHandler)
{
- return mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random, modelData);
+ MinecraftForge.EVENT_BUS.addListener((RegisterCommandsEvent e) -> { eventHandler.accept(e.getDispatcher()); });
}
- #else
- public List getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, RandomSource random)
- {
- return mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random, modelData #if POST_MC_1_19_2 , RenderType.solid() #endif );
- }
- #endif
- @Override //TODO: Check this if its still needed
- public int colorResolverGetColor(ColorResolver resolver, Biome biome, double x, double z)
+ @Override
+ protected void subscribeClientStartedEvent(Runnable eventHandler)
{
- #if MC_1_17_1______Still_needed
- return resolver.m_130045_(biome, x, z);
- #else
- return resolver.getColor(biome, x, z);
- #endif
-
+ // FIXME What event is this?
}
+ @Override
+ protected void subscribeServerStartingEvent(Consumer eventHandler)
+ {
+ MinecraftForge.EVENT_BUS.addListener((#if MC_VER >= MC_1_18_2 ServerStartingEvent #else FMLServerStartingEvent #endif e) ->
+ {
+ eventHandler.accept(e.getServer());
+ });
+ }
+
+ @Override
+ protected void runDelayedSetup() { SingletonInjector.INSTANCE.runDelayedSetup(); }
+
}
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeServerProxy.java b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeServerProxy.java
index 46d2f5c6a..0c9521e0c 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeServerProxy.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeServerProxy.java
@@ -1,20 +1,19 @@
package com.seibel.distanthorizons.forge;
+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.world.ClientLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
-import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.server.level.ServerLevel;
-import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
+import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.TickEvent;
-#if PRE_MC_1_19_2
+#if MC_VER < MC_1_19_2
import net.minecraftforge.event.world.ChunkEvent;
import net.minecraftforge.event.world.WorldEvent;
#else
@@ -23,10 +22,10 @@ import net.minecraftforge.event.level.LevelEvent;
#endif
import net.minecraftforge.eventbus.api.SubscribeEvent;
-#if MC_1_16_5
+#if MC_VER == MC_1_16_5
import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
-#elif MC_1_17_1
+#elif MC_VER == MC_1_17_1
import net.minecraftforge.fmlserverevents.FMLServerAboutToStartEvent;
import net.minecraftforge.fmlserverevents.FMLServerStoppingEvent;
#else
@@ -39,9 +38,9 @@ import org.apache.logging.log4j.Logger;
import java.util.function.Supplier;
-public class ForgeServerProxy
+public class ForgeServerProxy implements AbstractModInitializer.IEventProxy
{
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
private static LevelAccessor GetEventLevel(WorldEvent e) { return e.getWorld(); }
#else
private static LevelAccessor GetEventLevel(LevelEvent e) { return e.getLevel(); }
@@ -53,6 +52,15 @@ public class ForgeServerProxy
public static Supplier isGenerationThreadChecker = null;
+
+ @Override
+ public void registerEvents()
+ {
+ MinecraftForge.EVENT_BUS.register(this);
+ }
+
+
+
//=============//
// constructor //
//=============//
@@ -81,21 +89,21 @@ public class ForgeServerProxy
// ServerWorldLoadEvent
@SubscribeEvent
- public void dedicatedWorldLoadEvent(#if MC_1_16_5 || MC_1_17_1 FMLServerAboutToStartEvent #else ServerAboutToStartEvent #endif event)
+ public void dedicatedWorldLoadEvent(#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 FMLServerAboutToStartEvent #else ServerAboutToStartEvent #endif event)
{
this.serverApi.serverLoadEvent(this.isDedicated);
}
// ServerWorldUnloadEvent
@SubscribeEvent
- public void serverWorldUnloadEvent(#if MC_1_16_5 || MC_1_17_1 FMLServerStoppingEvent #else ServerStoppingEvent #endif event)
+ public void serverWorldUnloadEvent(#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 FMLServerStoppingEvent #else ServerStoppingEvent #endif event)
{
this.serverApi.serverUnloadEvent();
}
// ServerLevelLoadEvent
@SubscribeEvent
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
public void serverLevelLoadEvent(WorldEvent.Load event)
#else
public void serverLevelLoadEvent(LevelEvent.Load event)
@@ -109,7 +117,7 @@ public class ForgeServerProxy
// ServerLevelUnloadEvent
@SubscribeEvent
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
public void serverLevelUnloadEvent(WorldEvent.Unload event)
#else
public void serverLevelUnloadEvent(LevelEvent.Unload event)
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/ForgeMixinPlugin.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/ForgeMixinPlugin.java
index 78f4fd7e5..78481bf26 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/ForgeMixinPlugin.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/ForgeMixinPlugin.java
@@ -14,10 +14,24 @@ import java.util.Set;
*/
public class ForgeMixinPlugin implements IMixinConfigPlugin
{
+ private boolean firstRun = false;
+ private boolean isForgeMixinFile;
+
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName)
{
+ if (!this.firstRun) {
+ try {
+ Class> cls = Class.forName("net.neoforged.fml.common.Mod"); // Check if a NeoForge exclusive class exists
+ this.isForgeMixinFile = false;
+ } catch (ClassNotFoundException e) {
+ this.isForgeMixinFile = true;
+ }
+ }
+ if (!this.isForgeMixinFile)
+ return false;
+
if (mixinClassName.contains(".mods."))
{ // If the mixin wants to go into a mod then we check if that mod is loaded or not
return ModList.get().isLoaded(
@@ -28,44 +42,27 @@ public class ForgeMixinPlugin implements IMixinConfigPlugin
.replaceAll("\\..*$", "") // Replaces everything after the mod name
);
}
+
return true;
}
@Override
- public void onLoad(String mixinPackage)
- {
-
- }
+ public void onLoad(String mixinPackage) { }
@Override
- public String getRefMapperConfig()
- {
- return null;
- }
+ public String getRefMapperConfig() { return null; }
@Override
- public void acceptTargets(Set myTargets, Set otherTargets)
- {
-
- }
+ public void acceptTargets(Set myTargets, Set otherTargets) { }
@Override
- public List getMixins()
- {
- return null;
- }
+ public List getMixins() { return null; }
@Override
- public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo)
- {
-
- }
+ public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { }
@Override
- public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo)
- {
-
- }
+ public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { }
}
\ No newline at end of file
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinClientPacketListener.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinClientPacketListener.java
index 1bb20e3fa..2726de266 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinClientPacketListener.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinClientPacketListener.java
@@ -16,7 +16,7 @@ public class MixinClientPacketListener
@Inject(method = "handleLogin", at = @At("RETURN"))
void onHandleLoginEnd(CallbackInfo ci) { ClientApi.INSTANCE.onClientOnlyConnected(); }
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
@Inject(method = "cleanup", at = @At("HEAD"))
#else
@Inject(method = "close", at = @At("HEAD"))
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinFogRenderer.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinFogRenderer.java
index 597a9850b..db0ed1a9f 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinFogRenderer.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinFogRenderer.java
@@ -35,7 +35,7 @@ import net.minecraft.client.renderer.FogRenderer.FogMode;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
-#if PRE_MC_1_17_1
+#if MC_VER < MC_1_17_1
import net.minecraft.world.level.material.FluidState;
#else
import net.minecraft.world.level.material.FogType;
@@ -53,10 +53,10 @@ public class MixinFogRenderer
@Inject(at = @At("RETURN"),
method = "setupFog(Lnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/FogRenderer$FogMode;FZF)V",
- remap = #if MC_1_17_1 || MC_1_18_2 false #else true #endif ) // Remap messiness due to this being weird in forge
+ remap = #if MC_VER == MC_1_17_1 || MC_VER == MC_1_18_2 false #else true #endif ) // Remap messiness due to this being weird in forge
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, float partTick, CallbackInfo callback)
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
FluidState fluidState = camera.getFluidInCamera();
boolean cameraNotInFluid = fluidState.isEmpty();
#else
@@ -71,7 +71,7 @@ public class MixinFogRenderer
&& !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial()
&& Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get())
{
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
RenderSystem.fogStart(A_REALLY_REALLY_BIG_VALUE);
RenderSystem.fogEnd(A_EVEN_LARGER_VALUE);
#else
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinGameRenderer.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinGameRenderer.java
index 316e89d59..614054ee2 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinGameRenderer.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinGameRenderer.java
@@ -16,7 +16,7 @@ public class MixinGameRenderer
{
private static final Logger LOGGER = LogManager.getLogger(MixinGameRenderer.class.getSimpleName());
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
// FIXME: This I think will dup multiple renderStartupEvent calls...
@Inject(method = {"reloadShaders", "preloadUiShader"}, at = @At("TAIL"))
public void onStartupShaders(CallbackInfo ci)
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinLevelRenderer.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinLevelRenderer.java
index 2239adb4f..9eb2d9394 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinLevelRenderer.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinLevelRenderer.java
@@ -20,15 +20,15 @@
package com.seibel.distanthorizons.forge.mixins.client;
import com.mojang.blaze3d.vertex.PoseStack;
-#if PRE_MC_1_19_4
+#if MC_VER < MC_1_19_4
import com.mojang.math.Matrix4f;
#else
import net.minecraft.client.Camera;
+import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LightTexture;
import org.joml.Matrix4f;
#endif
-import com.seibel.distanthorizons.common.rendering.SeamlessOverdraw;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
@@ -36,44 +36,41 @@ import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import net.minecraft.client.Camera;
+import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderType;
-import net.minecraft.world.level.lighting.LevelLightEngine;
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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import javax.annotation.Nullable;
import java.nio.FloatBuffer;
-#if PRE_MC_1_17_1
+#if MC_VER < MC_1_17_1
import org.lwjgl.opengl.GL15;
#endif
/**
- * This class is used to mix in my rendering code
+ * This class is used to mix in DH's rendering code
* before Minecraft starts rendering blocks.
* If this wasn't done, and we used Forge's
* render last event, the LODs would render on top
* of the normal terrain.
*
* This is also the mixin for rendering the clouds
- *
- * @author coolGi
- * @author James Seibel
- * @version 12-31-2021
*/
@Mixin(LevelRenderer.class)
public class MixinLevelRenderer
{
- @Shadow
+ @Nullable
+ @Shadow //# if MC_VER >= MC_1_20_4 (remap = false) # endif
private ClientLevel level;
@Unique
private static float previousPartialTicks = 0;
@@ -84,7 +81,7 @@ public class MixinLevelRenderer
throw new NullPointerException("Null cannot be cast to non-null type.");
}
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
@Inject(at = @At("RETURN"), method = "renderSky(Lcom/mojang/blaze3d/vertex/PoseStack;F)V")
private void renderSky(PoseStack matrixStackIn, float partialTicks, CallbackInfo callback)
#else
@@ -92,37 +89,44 @@ public class MixinLevelRenderer
public void renderClouds(PoseStack poseStack, Matrix4f projectionMatrix, float partialTicks, double cameraX, double cameraY, double cameraZ, CallbackInfo ci)
#endif
{
+ // FIXME this is only called when clouds are enabled and vanilla render distance is far enough
+ // not having the parital ticks doesn't appear to be critical currently, but might cause weird issues down the line
+
// get the partial ticks since renderBlockLayer doesn't
// have access to them
previousPartialTicks = partialTicks;
}
- // TODO: Can we move this to forge's client proxy similarly to how fabric does it
- #if PRE_MC_1_17_1
+ #if MC_VER < MC_1_17_1
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDD)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack matrixStackIn, double xIn, double yIn, double zIn, CallbackInfo callback)
- #elif PRE_MC_1_19_4
+ #elif MC_VER < MC_1_19_4
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLcom/mojang/math/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
- #elif PRE_MC_1_20_2
+ #elif MC_VER < MC_1_20_2
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
- #else
+ #elif MC_VER < MC_1_20_4
@Inject(at = @At("HEAD"),
method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double camX, double camY, double camZ, Matrix4f projectionMatrix, CallbackInfo callback)
+ #else
+ @Inject(at = @At("HEAD"),
+ method = "renderSectionLayer",
+ cancellable = true)
+ private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double camX, double camY, double camZ, Matrix4f projectionMatrix, CallbackInfo callback)
#endif
{
// get MC's model view and projection matrices
- #if MC_1_16_5
+ #if MC_VER == MC_1_16_5
// get the matrices from the OpenGL fixed pipeline
float[] mcProjMatrixRaw = new float[16];
GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
@@ -142,21 +146,11 @@ public class MixinLevelRenderer
// only render before solid blocks
if (renderType.equals(RenderType.solid()))
{
- ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(level), mcModelViewMatrix, mcProjectionMatrix, previousPartialTicks);
-
- // experimental proof-of-concept option
- if (Config.Client.Advanced.Graphics.AdvancedGraphics.seamlessOverdraw.get())
- {
- float[] matrixFloatArray = SeamlessOverdraw.overwriteMinecraftNearFarClipPlanes(mcProjectionMatrix, previousPartialTicks);
-
- #if MC_1_16_5
- SeamlessOverdraw.applyLegacyProjectionMatrix(matrixFloatArray);
- #elif PRE_MC_1_19_4
- projectionMatrix.load(FloatBuffer.wrap(matrixFloatArray));
- #else
- projectionMatrix.set(matrixFloatArray);
- #endif
- }
+ ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, Minecraft.getInstance().getFrameTime());
+ }
+ else if (renderType.equals(RenderType.translucent()))
+ {
+ ClientApi.INSTANCE.renderDeferredLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, Minecraft.getInstance().getFrameTime());
}
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
@@ -165,10 +159,10 @@ public class MixinLevelRenderer
}
}
- #if PRE_MC_1_19_4
+ #if MC_VER < MC_1_19_4
@Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runUpdates(IZZ)I"), method = "renderLevel")
public void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
- #elif PRE_MC_1_20_1
+ #elif MC_VER < MC_1_20_1
@Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runUpdates(IZZ)I"), method = "renderLevel")
public void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
#else
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinLightTexture.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinLightTexture.java
index f350a1754..319c449a5 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinLightTexture.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinLightTexture.java
@@ -20,10 +20,13 @@
package com.seibel.distanthorizons.forge.mixins.client;
-import com.seibel.distanthorizons.common.util.ILightTextureMarker;
+import com.mojang.blaze3d.platform.NativeImage;
+import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.renderer.LightTexture;
-import net.minecraft.client.renderer.texture.DynamicTexture;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -35,11 +38,22 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(LightTexture.class)
public class MixinLightTexture
{
- @Shadow
- @Final
- private DynamicTexture lightTexture;
+ @Shadow //# if MC_VER >= MC_1_20_4 (remap = false) # endif
+ @Final
+ private NativeImage lightPixels;
- @Inject(method = "", at = @At("RETURN"))
- public void markLightTexture(CallbackInfo ci) { ((ILightTextureMarker) this.lightTexture).markLightTexture(); }
+
+ @Inject(method = "updateLightTexture(F)V", at = @At("RETURN"))
+ public void updateLightTexture(float partialTicks, CallbackInfo ci)
+ {
+ IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
+ if (mc == null || mc.getWrappedClientLevel() == null)
+ {
+ return;
+ }
+
+ IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
+ MinecraftRenderWrapper.INSTANCE.updateLightmap(this.lightPixels, clientLevel);
+ }
}
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinMinecraft.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinMinecraft.java
index 1aaa81bf7..ca7a417d5 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinMinecraft.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinMinecraft.java
@@ -1,6 +1,6 @@
package com.seibel.distanthorizons.forge.mixins.client;
-import com.seibel.distanthorizons.api.enums.config.EUpdateBranch;
+import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
@@ -25,8 +25,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Minecraft.class)
public class MixinMinecraft
{
- #if PRE_MC_1_20_2
- #if MC_1_20_1
+ #if MC_VER < MC_1_20_2
+ #if MC_VER == MC_1_20_1
@Redirect(
method = "Lnet/minecraft/client/Minecraft;setInitialScreen(Lcom/mojang/realmsclient/client/RealmsClient;Lnet/minecraft/server/packs/resources/ReloadInstance;Lnet/minecraft/client/main/GameConfig$QuickPlayData;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V")
@@ -51,7 +51,7 @@ public class MixinMinecraft
{
instance.setScreen(new UpdateModScreen(
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
- (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()): GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
+ (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()): GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
));
}
else
@@ -61,7 +61,7 @@ public class MixinMinecraft
}
#endif
- #if POST_MC_1_20_2
+ #if MC_VER >= MC_1_20_2
@Redirect(
method = "Lnet/minecraft/client/Minecraft;onGameLoadFinished(Lnet/minecraft/client/Minecraft$GameLoadCookie;)V",
at = @At(value = "INVOKE", target = "Ljava/lang/Runnable;run()V")
@@ -73,11 +73,23 @@ public class MixinMinecraft
&& SelfUpdater.onStart()
)
{
- runnable = () -> {
+ runnable = () ->
+ {
+ String versionId;
+ EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
+ if (updateBranch == EDhApiUpdateBranch.STABLE)
+ {
+ versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
+ }
+ else
+ {
+ versionId = GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha");
+ }
+
Minecraft.getInstance().setScreen(new UpdateModScreen(
// TODO: Change to runnable, instead of tittle screen
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
- (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()) : GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
+ versionId
));
};
}
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinOptionsScreen.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinOptionsScreen.java
index af33b5db0..e3af8c9e8 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinOptionsScreen.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinOptionsScreen.java
@@ -26,7 +26,7 @@ import com.seibel.distanthorizons.core.config.Config;
import net.minecraft.client.gui.screens.OptionsScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
-#if PRE_MC_1_19_2
+#if MC_VER < MC_1_19_2
import net.minecraft.network.chat.TranslatableComponent;
#endif
import net.minecraft.resources.ResourceLocation;
@@ -57,7 +57,7 @@ public class MixinOptionsScreen extends Screen
private void lodconfig$init(CallbackInfo ci)
{
if (Config.Client.optionsButton.get())
- this. #if PRE_MC_1_17_1 addButton #else addRenderableWidget #endif
+ this. #if MC_VER < MC_1_17_1 addButton #else addRenderableWidget #endif
(new TexturedButtonWidget(
// Where the button is on the screen
this.width / 2 - 180, this.height / 6 - 12,
@@ -71,7 +71,7 @@ public class MixinOptionsScreen extends Screen
// For now it goes to the client option by default
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(GetConfigScreen.getScreen(this)),
// Add a title to the button
- #if PRE_MC_1_19_2
+ #if MC_VER < MC_1_19_2
new TranslatableComponent(ModInfo.ID + ".title")));
#else
Component.translatable(ModInfo.ID + ".title")));
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinWorldUpgrader.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinWorldUpgrader.java
deleted file mode 100644
index 9e2f76cda..000000000
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinWorldUpgrader.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package com.seibel.distanthorizons.forge.mixins.client;
-
-import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
-import com.seibel.distanthorizons.api.interfaces.world.IDhApiDimensionTypeWrapper;
-import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
-import com.seibel.distanthorizons.common.wrappers.world.DimensionTypeWrapper;
-import com.seibel.distanthorizons.core.file.structure.LocalSaveStructure;
-import com.seibel.distanthorizons.core.level.DhServerLevel;
-import com.seibel.distanthorizons.core.pos.DhBlockPos;
-import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
-import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
-import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
-import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
-import net.minecraft.resources.ResourceKey;
-import net.minecraft.util.worldupdate.WorldUpgrader;
-import net.minecraft.world.level.Level;
-import net.minecraft.world.level.dimension.DimensionType;
-import net.minecraft.world.level.dimension.LevelStem;
-import net.minecraft.world.level.levelgen.WorldGenSettings;
-import net.minecraft.world.level.storage.DimensionDataStorage;
-import net.minecraft.world.level.storage.LevelStorageSource;
-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.LocalCapture;
-
-import java.io.File;
-import java.nio.file.Path;
-
-#if FALSE
-@Mixin(WorldUpgrader.class)
-public class MixinWorldUpgrader {
- static class FakeLevelWrapper implements IServerLevelWrapper {
- private Path saveFolder;
- private LevelStem stem;
- private DimensionType dimension;
- private DimensionTypeWrapper dimensionTypeWrapper;
-
- public FakeLevelWrapper(LevelStorageSource.LevelStorageAccess storage, WorldGenSettings gen, ResourceKey dim) {
- saveFolder = storage.getDimensionPath(dim);
- stem = gen.dimensions().getOrThrow(WorldGenSettings.levelToLevelStem(dim));
- dimension = stem.typeHolder().value();
- dimensionTypeWrapper = DimensionTypeWrapper.getDimensionTypeWrapper(dimension);
- }
-
- @Override
- public EDhApiLevelType getLevelType() {
- return EDhApiLevelType.SERVER_LEVEL;
- }
-
- @Override
- public IDhApiDimensionTypeWrapper getDimensionType() {
- return dimensionTypeWrapper;
- }
-
- @Override
- public int getBlockLight(int x, int y, int z) {
- return 0;
- }
-
- @Override
- public int getSkyLight(int x, int y, int z) {
- return 0;
- }
-
- @Override
- public boolean hasCeiling() {
- return dimension.hasCeiling();
- }
-
- @Override
- public boolean hasSkyLight() {
- return dimension.hasSkyLight();
- }
-
- @Override
- public int getHeight() {
- return dimension.height();
- }
-
- @Override
- public int getMinHeight() {
- return dimension.minY();
- }
-
- @Override
- public boolean hasChunkLoaded(int chunkX, int chunkZ) {
- return false;
- }
-
- @Override
- public IBlockStateWrapper getBlockState(DhBlockPos pos) {
- return BlockStateWrapper.AIR;
- }
-
- @Override
- public IBiomeWrapper getBiome(DhBlockPos pos) {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- @Override
- public Object getWrappedMcObject() {
- return null;
- }
-
- @Nullable
- @Override
- public IClientLevelWrapper tryGetClientLevelWrapper() {
- return null;
- }
-
- @Override
- public File getSaveFolder() {
- return saveFolder.toFile();
- }
- }
-
- @Unique
- private DhServerLevel dhServerLevel;
- @Unique
- private FakeLevelWrapper fakeLevelWrapper;
- @Unique
- public LocalSaveStructure saveStructure;
-
- @Shadow @Final
- private DimensionDataStorage overworldDataStorage;
- @Shadow @Final
- private LevelStorageSource.LevelStorageAccess levelStorage;
- @Shadow @Final
- private WorldGenSettings worldGenSettings;
-
- @Inject(method = "Lnet/minecraft/util/worldupdate/WorldUpgrader;work()V",
- at = @At(value = "INVOKE")
- )
- private void initWorldUpgrade() {
- saveStructure = new LocalSaveStructure();
- }
-
- @Inject(method = "Lnet/minecraft/util/worldupdate/WorldUpgrader;work()V",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/util/worldupdate/WorldUpgrader;getAllChunkPos(Lnet/minecraft/resources/ResourceKey;)Ljava/util/List;", shift = At.Shift.AFTER),
- locals = LocalCapture.CAPTURE_FAILSOFT
- )
- private void startWorldUpgrade(CallbackInfo info, ResourceKey resourceKey) {
- ResourceKey key = resourceKey;
- fakeLevelWrapper = new FakeLevelWrapper(levelStorage, worldGenSettings, key);
- dhServerLevel = new DhServerLevel(saveStructure, fakeLevelWrapper);
- }
-
-
-}
-#endif
\ No newline at end of file
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinChunkGenerator.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinChunkGenerator.java
index 5b15692ce..3541cf2fb 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinChunkGenerator.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinChunkGenerator.java
@@ -22,7 +22,7 @@ package com.seibel.distanthorizons.forge.mixins.server;
import org.spongepowered.asm.mixin.Mixin;
import net.minecraft.world.level.chunk.ChunkGenerator;
-#if PRE_MC_1_18_2
+#if MC_VER < MC_1_18_2
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinTFChunkGenerator.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinTFChunkGenerator.java
index 537592d1b..ab203d244 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinTFChunkGenerator.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinTFChunkGenerator.java
@@ -3,13 +3,13 @@ package com.seibel.distanthorizons.forge.mixins.server;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.spongepowered.asm.mixin.Mixin;
-#if MC_1_16_5
+#if MC_VER == MC_1_16_5
@Mixin(ChunkGenerator.class)
class MixinTFChunkGenerator
{
// not currently implemented, attempting to run with the mod enabled in the IDE causes the game to lock up
}
-#elif PRE_MC_1_17_1
+#elif MC_VER < MC_1_17_1
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinUtilBackgroundThread.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinUtilBackgroundThread.java
index 59904ca04..dee12f792 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinUtilBackgroundThread.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinUtilBackgroundThread.java
@@ -50,7 +50,7 @@ public class MixinUtilBackgroundThread
}
}
- #if POST_MC_1_17_1
+ #if MC_VER >= MC_1_17_1
@Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/lang/Runnable;)Ljava/lang/Runnable;",
at = @At("HEAD"), cancellable = true)
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable ci)
@@ -62,7 +62,7 @@ public class MixinUtilBackgroundThread
}
}
#endif
- #if POST_MC_1_18_2
+ #if MC_VER >= MC_1_18_2
@Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/util/function/Supplier;)Ljava/util/function/Supplier;",
at = @At("HEAD"), cancellable = true)
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier> r, CallbackInfoReturnable> ci)
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/unsafe/MixinThreadingDetector.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/unsafe/MixinThreadingDetector.java
deleted file mode 100644
index d692a4c49..000000000
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/unsafe/MixinThreadingDetector.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * This file is part of the Distant Horizons mod
- * licensed under the GNU LGPL v3 License.
- *
- * Copyright (C) 2020-2023 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.forge.mixins.server.unsafe;
-
-import org.spongepowered.asm.mixin.Mixin;
-#if POST_MC_1_18_2
-
-import net.minecraft.util.ThreadingDetector;
-import org.spongepowered.asm.mixin.Mutable;
-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;
-
-import java.util.concurrent.Semaphore;
-
-/**
- * Why does this exist? But okay! (Will be probably removed when the experimental generator is done)
- * FIXME: Recheck this // STILL check this
- */
-@Mixin(ThreadingDetector.class)
-public class MixinThreadingDetector
-{
- @Mutable
- @Shadow
- private Semaphore lock;
-
- @Inject(method = "", at = @At("RETURN"))
- private void setSemaphore(CallbackInfo ci)
- {
- this.lock = new Semaphore(2);
- }
-
-}
-
-#else
-
-import net.minecraft.world.level.chunk.ChunkGenerator;
-
-@Mixin(ChunkGenerator.class)
-public class MixinThreadingDetector { }
-#endif
\ No newline at end of file
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/wrappers/modAccessor/ModChecker.java b/forge/src/main/java/com/seibel/distanthorizons/forge/wrappers/modAccessor/ModChecker.java
index 4475c6900..1125b4240 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/wrappers/modAccessor/ModChecker.java
+++ b/forge/src/main/java/com/seibel/distanthorizons/forge/wrappers/modAccessor/ModChecker.java
@@ -22,6 +22,8 @@ package com.seibel.distanthorizons.forge.wrappers.modAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import net.minecraftforge.fml.ModList;
+import java.io.File;
+
public class ModChecker implements IModChecker
{
public static final ModChecker INSTANCE = new ModChecker();
@@ -32,4 +34,10 @@ public class ModChecker implements IModChecker
return ModList.get().isLoaded(modid);
}
+ @Override
+ public File modLocation(String modid)
+ {
+ return ModList.get().getModFileById(modid).getFile().getFilePath().toFile();
+ }
+
}
diff --git a/forge/src/main/resources/DistantHorizons.mixins.json b/forge/src/main/resources/DistantHorizons.forge.mixins.json
similarity index 76%
rename from forge/src/main/resources/DistantHorizons.mixins.json
rename to forge/src/main/resources/DistantHorizons.forge.mixins.json
index b30ef91ed..c7b69cbaf 100644
--- a/forge/src/main/resources/DistantHorizons.mixins.json
+++ b/forge/src/main/resources/DistantHorizons.forge.mixins.json
@@ -3,7 +3,6 @@
"minVersion": "0.8",
"package": "com.seibel.distanthorizons.forge.mixins",
"mixins": [
- "server.unsafe.MixinThreadingDetector",
"server.MixinUtilBackgroundThread",
"server.MixinChunkGenerator",
"server.MixinTFChunkGenerator"
@@ -14,11 +13,9 @@
"client.MixinFogRenderer",
"client.MixinGameRenderer",
"client.MixinLevelRenderer",
- "client.MixinDynamicTexture",
"client.MixinLightTexture",
"client.MixinOptionsScreen",
"client.MixinTextureUtil"
],
- "server": [],
- "plugin": "com.seibel.distanthorizons.forge.mixins.ForgeMixinPlugin"
+ "server": []
}
diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml
index 43a8eb78d..0f86a948e 100644
--- a/forge/src/main/resources/META-INF/mods.toml
+++ b/forge/src/main/resources/META-INF/mods.toml
@@ -12,8 +12,8 @@ issueTrackerURL = "${issues}"
#//updateJSONURL="https://change.me.example.invalid/updates.json" # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/
displayURL = "${homepage}"
description = "${description}" #//mandatory. The description text for the mod
- logoFile = "logo.png"
- catalogueImageIcon = "icon.png"
+ logoFile = "assets/distanthorizons/logo.png"
+ catalogueImageIcon = "assets/distanthorizons/icon.png"
credits = "Massive thanks to: Leonardo, Cola, Ran, CoolGi, and Leetom. For their hard work to bring Distant Horizons to where it is today. - James"
#// if not set defaults to "false"
clientSideOnly = "true"
@@ -23,10 +23,16 @@ issueTrackerURL = "${issues}"
#// Allow any version to be present (or not) on the server
acceptableRemoteVersions = "*"
+[[dependencies.distanthorizons]]
+ modId="forge" #mandatory
+ mandatory = true # Forge syntax
+ versionRange="[0,)" #mandatory
+ ordering="NONE"
+ side="BOTH"
[[dependencies.distanthorizons]]
modId = "minecraft"
- mandatory = true
+ mandatory = true # Forge syntax
versionRange = "${compatible_forgemc_versions}" # Where we set what version of mc it is avalible for
- ordering = "NONE"
+ ordering = "AFTER"
side = "BOTH"
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 6592d9c1d..43c0bb48c 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -5,12 +5,12 @@ org.gradle.caching=true
# Mod Info
mod_name=DistantHorizons
-mod_version=2.0.1-a
-api_version=1.0.0
+mod_version=2.1.2-a
+api_version=2.1.0
maven_group=com.seibel.distanthorizons
mod_readable_name=Distant Horizons
mod_description=This mod generates and renders simplified terrain beyond the normal view distance at a low performance cost. Allowing you to see much farther without turning your game into a slideshow.
-# Note: In forge's mods.toml this is hard coded because Architectury throws an error with setting it as a varuable
+# Note: In forge's mods.toml this is hard coded because Architectury throws an error with setting it as a variable
mod_authors=["James Seibel", "Leonardo Amato", "Cola", "coolGi", "Ran", "Leetom"]
mod_homepage=https://modrinth.com/mod/distanthorizons
mod_source=https://gitlab.com/jeseibel/distant-horizons
@@ -18,14 +18,19 @@ mod_issues=https://gitlab.com/jeseibel/distant-horizons/-/issues
mod_discord=https://discord.gg/xAB8G4cENx
# Global Plugin Versions
-manifold_version=2023.1.31
+manifold_version=2023.1.17
+# 2023.1.17 can be used if there are mystery Java compiler issues
nightconfig_version=3.6.6
lz4_version=1.8.0
+xz_version=1.9
sqlite_jdbc_version=3.43.0.0
+# 8.2.1 is the newest version we can use since that's the version MC 1.16.5 uses
+# (at least until we can fix the gradle script so core and main can use/shade different fastutil versions)
+fastutil_version=8.2.1
#svgSalamander_version=1.1.3
-# Minecraft related libaries (included in MC's jar)
-log4j_version=2.20.0
+# Minecraft related libraries (included in MC's jar)
+log4j_version=2.23.1
netty_version=4.1.94.Final
lwjgl_version=3.3.1
joml_version=1.10.2
@@ -44,7 +49,7 @@ versionStr=
# This defines what MC version Intellij will use for the preprocessor
# and what version is used automatically by build and run commands
-mcVer=1.20.2
+mcVer=1.21
-# Defines the maximum amount of memory Minecraft is allowed when run in a developement environment
-minecraftMemoryJavaArg="-Xmx4G"
+# Defines the maximum amount of memory Minecraft is allowed when run in a development environment
+#minecraftMemoryJavaArg="-Xmx4G"
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index e708b1c02..d64cd4917 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index fdb79863a..b82aa23a4 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-# TODO: Wait for forge to fix gradle 8 support, once it did change gradle to a newer version
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 1b6c78733..1aa94a426 100755
--- a/gradlew
+++ b/gradlew
@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +80,11 @@ do
esac
done
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-APP_NAME="Gradle"
+# This is normally unused
+# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,22 +131,29 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then
done
fi
-# Collect all arguments for the java command;
-# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-# shell script including quotes and variable substitutions, so put them in
-# double quotes to make sure that they get re-expanded; and
-# * put everything else in single quotes, so that it's not re-expanded.
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
@@ -205,6 +214,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
diff --git a/gradlew.bat b/gradlew.bat
index 107acd32c..93e3f59f1 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/neoforge/build.gradle b/neoforge/build.gradle
new file mode 100644
index 000000000..04da288d0
--- /dev/null
+++ b/neoforge/build.gradle
@@ -0,0 +1,100 @@
+plugins {
+ // Note: This is only needed for multi-loader projects
+ // The main architectury loom version is set at the start of the root build.gradle
+ id "architectury-plugin" version "3.4-SNAPSHOT"
+}
+
+sourceCompatibility = targetCompatibility = JavaVersion.VERSION_17
+
+architectury {
+ platformSetupLoomIde()
+ neoForge()
+}
+
+loom {
+ silentMojangMappingsLicense() // Shut the licencing warning
+ accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
+
+ neoForge {
+ // Access wideners are defined in the `remapJar.atAccessWideners`
+
+ // Mixins are defined in the `mods.toml`
+ }
+ mixin {
+ // Mixins are defined in the `mods.toml`
+ }
+
+ // "runs" isn't required, but when we do need it then it can be useful
+ runs {
+ client {
+ client()
+ setConfigName("NeoForge Client")
+ ideConfigGenerated(true)
+ runDir("../run")
+ //vmArgs("-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg)
+ }
+ server {
+ server()
+ setConfigName("NeoForge Server")
+ ideConfigGenerated(true)
+ runDir("../run")
+ }
+ }
+}
+
+
+
+def addMod(path, enabled) {
+ if (enabled == "2")
+ dependencies { implementation(path) }
+ else if (enabled == "1")
+ dependencies { modCompileOnly(path) }
+}
+dependencies {
+ minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
+ mappings loom.layered()
+ {
+ // Mojmap mappings
+ officialMojangMappings()
+ // Parchment mappings (it adds parameter mappings & javadoc)
+ parchment("org.parchmentmc.data:parchment-${rootProject.parchment_version}@zip")
+ }
+
+
+ // Neoforge
+ neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
+ addMod("curse.maven:TerraFirmaCraft-302973:4616004", rootProject.enable_terrafirmacraft)
+}
+
+
+
+task deleteResources(type: Delete) {
+ delete file("build/resources/main")
+}
+
+tasks.register('copyAllResources') {
+ dependsOn(copyCoreResources)
+ dependsOn(copyCommonLoaderResources)
+}
+
+processResources {
+ dependsOn(tasks.named('copyAllResources'))
+}
+
+tasks.named('runClient') {
+ dependsOn(tasks.named('copyAllResources'))
+ finalizedBy(deleteResources)
+}
+
+remapJar {
+ inputFile = shadowJar.archiveFile
+ dependsOn shadowJar
+
+ atAccessWideners.add("distanthorizons.accesswidener")
+}
+
+sourcesJar {
+ def commonSources = project(":common").sourcesJar
+ dependsOn commonSources
+ from commonSources.archiveFile.map { zipTree(it) }
+}
diff --git a/neoforge/gradle.properties b/neoforge/gradle.properties
new file mode 100644
index 000000000..85e1db4b7
--- /dev/null
+++ b/neoforge/gradle.properties
@@ -0,0 +1 @@
+loom.platform=neoForge
\ No newline at end of file
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeClientProxy.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeClientProxy.java
new file mode 100644
index 000000000..cc53ba527
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeClientProxy.java
@@ -0,0 +1,340 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020-2023 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.neoforge;
+
+import com.seibel.distanthorizons.common.AbstractModInitializer;
+import com.seibel.distanthorizons.common.util.ProxyUtil;
+import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
+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.SharedApi;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
+import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
+
+import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
+import com.seibel.distanthorizons.coreapi.ModInfo;
+//import io.netty.buffer.ByteBuf;
+import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
+import net.minecraft.world.level.LevelAccessor;
+
+import net.minecraft.client.multiplayer.ClientLevel;
+import net.neoforged.neoforge.client.event.RenderLevelStageEvent;
+import net.neoforged.neoforge.common.NeoForge;
+import net.neoforged.neoforge.event.level.ChunkEvent;
+import net.neoforged.neoforge.event.level.LevelEvent;
+
+import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;
+import net.minecraft.world.level.chunk.ChunkAccess;
+
+//import net.neoforged.network.NetworkRegistry;
+//import net.neoforged.network.simple.SimpleChannel;
+import org.apache.logging.log4j.Logger;
+import org.lwjgl.glfw.GLFW;
+
+import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
+
+import net.minecraft.client.Minecraft;
+import net.neoforged.neoforge.client.event.InputEvent;
+import net.neoforged.bus.api.SubscribeEvent;
+import org.lwjgl.opengl.GL32;
+
+#if MC_VER < MC_1_20_6
+import net.neoforged.neoforge.event.TickEvent;
+#else
+import net.neoforged.neoforge.client.event.ClientTickEvent;
+#endif
+
+
+/**
+ * This handles all events sent to the client,
+ * and is the starting point for most of the mod.
+ *
+ * @author James_Seibel
+ * @version 2023-7-27
+ */
+public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
+{
+ private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
+ private static final Logger LOGGER = DhLoggerBuilder.getLogger();
+
+// private static SimpleChannel multiversePluginChannel;
+
+ // Not the cleanest way of passing this to the LOD renderer, but it'll have to do for now
+ public static Mat4f currentModelViewMatrix = new Mat4f();
+ public static Mat4f currentProjectionMatrix = new Mat4f();
+
+
+
+
+ @Override
+ public void registerEvents()
+ {
+ NeoForge.EVENT_BUS.register(this);
+ setupNetworkingListeners();
+ }
+
+
+
+ //=============//
+ // tick events //
+ //=============//
+
+ #if MC_VER < MC_1_20_6
+ @SubscribeEvent
+ public void clientTickEvent(TickEvent.ClientTickEvent event)
+ {
+ if (event.phase == TickEvent.Phase.START)
+ {
+ ClientApi.INSTANCE.clientTickEvent();
+ }
+ }
+ #else
+ @SubscribeEvent
+ public void clientTickEvent(ClientTickEvent.Pre event)
+ {
+ ClientApi.INSTANCE.clientTickEvent();
+ }
+ #endif
+
+
+
+ //==============//
+ // world events //
+ //==============//
+
+ @SubscribeEvent
+ public void clientLevelLoadEvent(LevelEvent.Load event)
+ {
+ LOGGER.info("level load");
+
+ LevelAccessor level = event.getLevel();
+ if (!(level instanceof ClientLevel))
+ {
+ return;
+ }
+
+ ClientLevel clientLevel = (ClientLevel) level;
+ IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel);
+ // TODO this causes a crash due to level being set to null somewhere
+ ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper);
+ }
+ @SubscribeEvent
+ public void clientLevelUnloadEvent(LevelEvent.Unload event)
+ {
+ LOGGER.info("level unload");
+
+ LevelAccessor level = event.getLevel();
+ if (!(level instanceof ClientLevel))
+ {
+ return;
+ }
+
+ ClientLevel clientLevel = (ClientLevel) level;
+ IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel);
+ ClientApi.INSTANCE.clientLevelUnloadEvent(clientLevelWrapper);
+ }
+
+
+
+ //==============//
+ // chunk events //
+ //==============//
+
+ @SubscribeEvent
+ public void rightClickBlockEvent(PlayerInteractEvent.RightClickBlock event)
+ {
+ if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
+ {
+ return;
+ }
+
+ //LOGGER.trace("interact or block place event at blockPos: " + event.getPos());
+
+ LevelAccessor level = event.getLevel();
+
+ ChunkAccess chunk = level.getChunk(event.getPos());
+ this.onBlockChangeEvent(level, chunk);
+ }
+ @SubscribeEvent
+ public void leftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event)
+ {
+ if (SharedApi.isChunkAtBlockPosAlreadyUpdating(event.getPos().getX(), event.getPos().getZ()))
+ {
+ return;
+ }
+
+ //LOGGER.trace("break or block attack at blockPos: " + event.getPos());
+
+ LevelAccessor level = event.getLevel();
+
+ ChunkAccess chunk = level.getChunk(event.getPos());
+ this.onBlockChangeEvent(level, chunk);
+ }
+ private void onBlockChangeEvent(LevelAccessor level, ChunkAccess chunk)
+ {
+ ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(level);
+ SharedApi.INSTANCE.chunkBlockChangedEvent(new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel);
+ }
+
+
+ @SubscribeEvent
+ public void clientChunkLoadEvent(ChunkEvent.Load event)
+ {
+ ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
+ IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), wrappedLevel);
+ SharedApi.INSTANCE.chunkLoadEvent(chunk, wrappedLevel);
+ }
+ @SubscribeEvent
+ public void clientChunkUnloadEvent(ChunkEvent.Unload event)
+ {
+ ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
+ IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), wrappedLevel);
+ SharedApi.INSTANCE.chunkUnloadEvent(chunk, wrappedLevel);
+ }
+
+
+
+ //==============//
+ // key bindings //
+ //==============//
+
+ @SubscribeEvent
+ public void registerKeyBindings(InputEvent.Key event)
+ {
+ if (Minecraft.getInstance().player == null)
+ {
+ return;
+ }
+ if (event.getAction() != GLFW.GLFW_PRESS)
+ {
+ return;
+ }
+
+ ClientApi.INSTANCE.keyPressedEvent(event.getKey());
+ }
+
+
+
+ //============//
+ // networking //
+ //============//
+
+ public static void setupNetworkingListeners()
+ {
+// multiversePluginChannel = NetworkRegistry.newSimpleChannel(
+// new ResourceLocation(ModInfo.NETWORKING_RESOURCE_NAMESPACE, ModInfo.MULTIVERSE_PLUGIN_NAMESPACE),
+// // network protocol version
+// () -> ModInfo.MULTIVERSE_PLUGIN_PROTOCOL_VERSION +"",
+// // client accepted versions
+// ForgeClientProxy::isReceivedProtocolVersionAcceptable,
+// // server accepted versions
+// ForgeClientProxy::isReceivedProtocolVersionAcceptable
+// );
+//
+// multiversePluginChannel.registerMessage(0/*should be incremented for each simple channel we listen to*/, ByteBuf.class,
+// // encoder
+// (pack, friendlyByteBuf) -> { },
+// // decoder
+// (friendlyByteBuf) -> friendlyByteBuf.asByteBuf(),
+// // message consumer
+// (nettyByteBuf, contextRef) ->
+// {
+// ClientApi.INSTANCE.serverMessageReceived(nettyByteBuf);
+// contextRef.get().setPacketHandled(true);
+// }
+// );
+ }
+
+ public static boolean isReceivedProtocolVersionAcceptable(String versionString)
+ {
+ if (versionString.toLowerCase().contains("allowvanilla"))
+ {
+ // allow using networking on vanilla servers
+ return true;
+ }
+ else if (versionString.toLowerCase().contains("absent"))
+ {
+ // allow using networking even if DH isn't installed on the server
+ return true;
+ }
+ else
+ {
+ // DH is installed on the server, check if the version is valid to use
+ try
+ {
+ int version = Integer.parseInt(versionString);
+ return ModInfo.MULTIVERSE_PLUGIN_PROTOCOL_VERSION == version;
+ }
+ catch (NumberFormatException ignored)
+ {
+ return false;
+ }
+ }
+ }
+
+
+
+ //===========//
+ // rendering //
+ //===========//
+
+ @SubscribeEvent
+ public void beforeLevelRenderEvent(RenderLevelStageEvent event)
+ {
+ if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_SKY)
+ {
+ currentModelViewMatrix = McObjectConverter.Convert(event.getModelViewMatrix());
+ currentProjectionMatrix = McObjectConverter.Convert(event.getProjectionMatrix());
+ }
+ }
+
+ @SubscribeEvent
+ public void afterLevelRenderEvent(RenderLevelStageEvent event)
+ {
+ if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_LEVEL)
+ {
+ 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);
+ }
+ }
+ }
+
+
+
+ //================//
+ // helper methods //
+ //================//
+
+ private static LevelAccessor GetEventLevel(LevelEvent e) { return e.getLevel(); }
+
+
+}
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java
new file mode 100644
index 000000000..8dd61f085
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020-2023 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.neoforge;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.seibel.distanthorizons.common.AbstractModInitializer;
+import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
+import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
+import com.seibel.distanthorizons.coreapi.ModInfo;
+import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.ModChecker;
+import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.OptifineAccessor;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.server.MinecraftServer;
+import net.neoforged.bus.api.IEventBus;
+import net.neoforged.fml.ModLoadingContext;
+import net.neoforged.fml.common.Mod;
+import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
+import net.neoforged.fml.event.lifecycle.FMLDedicatedServerSetupEvent;
+import net.neoforged.neoforge.common.NeoForge;
+import net.neoforged.neoforge.event.RegisterCommandsEvent;
+import net.neoforged.neoforge.event.server.ServerStartingEvent;
+
+import java.util.function.Consumer;
+
+#if MC_VER < MC_1_20_6
+import net.neoforged.neoforge.client.ConfigScreenHandler;
+#else
+import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
+#endif
+
+/**
+ * Initialize and setup the Mod.
+ * If you are looking for the real start of the mod
+ * check out the ClientProxy.
+ */
+@Mod(ModInfo.ID)
+public class NeoforgeMain extends AbstractModInitializer
+{
+ public NeoforgeMain(IEventBus eventBus)
+ {
+ eventBus.addListener((FMLClientSetupEvent e) -> this.onInitializeClient());
+ eventBus.addListener((FMLDedicatedServerSetupEvent e) -> this.onInitializeServer());
+ }
+
+ @Override
+ protected IEventProxy createServerProxy(boolean isDedicated) { return new NeoforgeServerProxy(isDedicated); }
+
+ @Override
+ protected void createInitialBindings() { SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); }
+
+ @Override
+ protected IEventProxy createClientProxy() { return new NeoforgeClientProxy(); }
+
+ @Override
+ protected void initializeModCompat()
+ {
+ this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
+
+ #if MC_VER < MC_1_20_6
+ ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class,
+ () -> new ConfigScreenHandler.ConfigScreenFactory((client, parent) -> GetConfigScreen.getScreen(parent)));
+ #else
+ ModLoadingContext.get().registerExtensionPoint(IConfigScreenFactory.class,
+ // TODO fix potential null pointer
+ () -> (client, parent) -> GetConfigScreen.getScreen(parent));
+ #endif
+ }
+
+ @Override
+ protected void subscribeRegisterCommandsEvent(Consumer> eventHandler)
+ {
+ NeoForge.EVENT_BUS.addListener((RegisterCommandsEvent e) -> { eventHandler.accept(e.getDispatcher()); });
+ }
+
+ @Override
+ protected void subscribeClientStartedEvent(Runnable eventHandler)
+ {
+ // FIXME What event is this?
+ }
+
+ @Override
+ protected void subscribeServerStartingEvent(Consumer eventHandler)
+ {
+ NeoForge.EVENT_BUS.addListener((ServerStartingEvent e) -> { eventHandler.accept(e.getServer()); });
+ }
+
+ @Override
+ protected void runDelayedSetup() { SingletonInjector.INSTANCE.runDelayedSetup(); }
+
+}
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeServerProxy.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeServerProxy.java
new file mode 100644
index 000000000..f7e7e366b
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeServerProxy.java
@@ -0,0 +1,143 @@
+package com.seibel.distanthorizons.neoforge;
+
+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.world.ServerLevelWrapper;
+import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
+import com.seibel.distanthorizons.core.api.internal.ServerApi;
+import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
+import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.level.LevelAccessor;
+import net.neoforged.neoforge.common.NeoForge;
+import net.neoforged.neoforge.event.level.ChunkEvent;
+import net.neoforged.neoforge.event.level.LevelEvent;
+import net.neoforged.bus.api.SubscribeEvent;
+
+import net.neoforged.neoforge.event.server.ServerAboutToStartEvent;
+import net.neoforged.neoforge.event.server.ServerStoppingEvent;
+
+import org.apache.logging.log4j.Logger;
+
+import java.util.function.Supplier;
+
+#if MC_VER < MC_1_20_6
+import net.neoforged.neoforge.event.TickEvent;
+#else
+import net.neoforged.neoforge.event.tick.ServerTickEvent;
+#endif
+
+
+public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy
+{
+ private static LevelAccessor GetEventLevel(LevelEvent e) { return e.getLevel(); }
+
+ private final ServerApi serverApi = ServerApi.INSTANCE;
+ private static final Logger LOGGER = DhLoggerBuilder.getLogger();
+ private final boolean isDedicated;
+ public static Supplier isGenerationThreadChecker = null;
+
+
+ //=============//
+ // constructor //
+ //=============//
+
+ public NeoforgeServerProxy(boolean isDedicated)
+ {
+ this.isDedicated = isDedicated;
+ isGenerationThreadChecker = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread;
+ }
+
+ @Override
+ public void registerEvents()
+ {
+ NeoForge.EVENT_BUS.register(this);
+ }
+
+
+
+
+ //========//
+ // events //
+ //========//
+
+ #if MC_VER < MC_1_20_6
+ @SubscribeEvent
+ public void serverTickEvent(TickEvent.ServerTickEvent event)
+ {
+ if (event.phase == TickEvent.Phase.END)
+ {
+ this.serverApi.serverTickEvent();
+ }
+ }
+ #else
+ @SubscribeEvent
+ public void serverTickEvent(ServerTickEvent.Post event)
+ {
+ this.serverApi.serverTickEvent();
+ }
+ #endif
+
+ // ServerWorldLoadEvent
+ @SubscribeEvent
+ public void dedicatedWorldLoadEvent(ServerAboutToStartEvent event)
+ {
+ this.serverApi.serverLoadEvent(this.isDedicated);
+ }
+
+ // ServerWorldUnloadEvent
+ @SubscribeEvent
+ public void serverWorldUnloadEvent(ServerStoppingEvent event)
+ {
+ this.serverApi.serverUnloadEvent();
+ }
+
+ // ServerLevelLoadEvent
+ @SubscribeEvent
+ public void serverLevelLoadEvent(LevelEvent.Load event)
+ {
+ if (GetEventLevel(event) instanceof ServerLevel)
+ {
+ this.serverApi.serverLevelLoadEvent(this.getServerLevelWrapper((ServerLevel) GetEventLevel(event)));
+ }
+ }
+
+ // ServerLevelUnloadEvent
+ @SubscribeEvent
+ public void serverLevelUnloadEvent(LevelEvent.Unload event)
+ {
+ if (GetEventLevel(event) instanceof ServerLevel)
+ {
+ this.serverApi.serverLevelUnloadEvent(this.getServerLevelWrapper((ServerLevel) GetEventLevel(event)));
+ }
+ }
+
+ @SubscribeEvent
+ public void serverChunkLoadEvent(ChunkEvent.Load event)
+ {
+ ILevelWrapper levelWrapper = ProxyUtil.getLevelWrapper(GetEventLevel(event));
+
+ IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
+ this.serverApi.serverChunkLoadEvent(chunk, levelWrapper);
+ }
+ @SubscribeEvent
+ public void serverChunkSaveEvent(ChunkEvent.Unload event)
+ {
+ ILevelWrapper levelWrapper = ProxyUtil.getLevelWrapper(GetEventLevel(event));
+
+ IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetEventLevel(event), levelWrapper);
+ this.serverApi.serverChunkSaveEvent(chunk, levelWrapper);
+ }
+
+
+
+ //================//
+ // helper methods //
+ //================//
+
+ private static ServerLevelWrapper getServerLevelWrapper(ServerLevel level) { return ServerLevelWrapper.getWrapper(level); }
+
+
+}
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/NeoforgeMixinPlugin.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/NeoforgeMixinPlugin.java
new file mode 100644
index 000000000..ba48ebaea
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/NeoforgeMixinPlugin.java
@@ -0,0 +1,68 @@
+package com.seibel.distanthorizons.neoforge.mixins;
+
+import net.neoforged.fml.ModList;
+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;
+
+/**
+ * @author coolGi
+ * @author cortex
+ */
+public class NeoforgeMixinPlugin implements IMixinConfigPlugin
+{
+ private boolean firstRun = false;
+ private boolean isNeoforgeMixinFile;
+
+
+ @Override
+ public boolean shouldApplyMixin(String targetClassName, String mixinClassName)
+ {
+ if (!this.firstRun) {
+ try {
+ Class> cls = Class.forName("net.neoforged.fml.common.Mod"); // Check if a NeoForge exclusive class exists
+ this.isNeoforgeMixinFile = true;
+ } catch (ClassNotFoundException e) {
+ this.isNeoforgeMixinFile = false;
+ }
+ }
+ if (!this.isNeoforgeMixinFile)
+ return false;
+
+ if (mixinClassName.contains(".mods."))
+ { // If the mixin wants to go into a mod then we check if that mod is loaded or not
+ return ModList.get().isLoaded(
+ mixinClassName
+ // What these 2 regex's do is get the mod name that we are checking out of the mixinClassName
+ // Eg. "com.seibel.distanthorizons.mixins.mods.sodium.MixinSodiumChunkRenderer" turns into "sodium"
+ .replaceAll("^.*mods.", "") // Replaces everything before the mods
+ .replaceAll("\\..*$", "") // Replaces everything after the mod name
+ );
+ }
+
+ return true;
+ }
+
+
+ @Override
+ public void onLoad(String mixinPackage) { }
+
+ @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 targetClass, String mixinClassName, IMixinInfo mixinInfo) { }
+
+ @Override
+ public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { }
+
+}
\ No newline at end of file
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinClientPacketListener.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinClientPacketListener.java
new file mode 100644
index 000000000..2439e0233
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinClientPacketListener.java
@@ -0,0 +1,28 @@
+package com.seibel.distanthorizons.neoforge.mixins.client;
+
+import com.seibel.distanthorizons.core.api.internal.ClientApi;
+import net.minecraft.client.multiplayer.ClientPacketListener;
+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(ClientPacketListener.class)
+public class MixinClientPacketListener
+{
+ // TODO update fabric version as well
+
+ @Inject(method = "handleLogin", at = @At("RETURN"))
+ void onHandleLoginEnd(CallbackInfo ci) { ClientApi.INSTANCE.onClientOnlyConnected(); }
+
+ #if MC_VER < MC_1_19_4
+ @Inject(method = "cleanup", at = @At("HEAD"))
+ #else
+ @Inject(method = "close", at = @At("HEAD"))
+ #endif
+ void onCleanupStart(CallbackInfo ci)
+ {
+ ClientApi.INSTANCE.onClientOnlyDisconnected();
+ }
+
+}
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinDebugScreenOverlay.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinDebugScreenOverlay.java
new file mode 100644
index 000000000..2b8cddded
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinDebugScreenOverlay.java
@@ -0,0 +1,23 @@
+package com.seibel.distanthorizons.neoforge.mixins.client;
+
+import com.seibel.distanthorizons.core.logging.f3.F3Screen;
+import net.minecraft.client.gui.components.DebugScreenOverlay;
+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.CallbackInfoReturnable;
+
+import java.util.List;
+
+@Mixin(DebugScreenOverlay.class)
+public class MixinDebugScreenOverlay
+{
+
+ @Inject(method = "getSystemInformation", at = @At("RETURN"))
+ private void addCustomF3(CallbackInfoReturnable> cir)
+ {
+ List messages = cir.getReturnValue();
+ F3Screen.addStringToDisplay(messages);
+ }
+
+}
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinFogRenderer.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinFogRenderer.java
new file mode 100644
index 000000000..0468a72da
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinFogRenderer.java
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020-2023 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.neoforge.mixins.client;
+
+import com.seibel.distanthorizons.core.config.Config;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
+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;
+
+import com.mojang.blaze3d.systems.RenderSystem;
+
+import net.minecraft.client.Camera;
+import net.minecraft.client.renderer.FogRenderer;
+import net.minecraft.client.renderer.FogRenderer.FogMode;
+import net.minecraft.world.effect.MobEffects;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.LivingEntity;
+#if MC_VER < MC_1_17_1
+import net.minecraft.world.level.material.FluidState;
+#else
+import net.minecraft.world.level.material.FogType;
+#endif
+
+
+
+@Mixin(FogRenderer.class)
+public class MixinFogRenderer
+{
+
+ // Using this instead of Float.MAX_VALUE because Sodium don't like it.
+ private static final float A_REALLY_REALLY_BIG_VALUE = 420694206942069.F;
+ private static final float A_EVEN_LARGER_VALUE = 42069420694206942069.F;
+
+ @Inject(at = @At("RETURN"),
+ method = "setupFog(Lnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/FogRenderer$FogMode;FZF)V",
+ remap = #if MC_VER == MC_1_17_1 || MC_VER == MC_1_18_2 false #else true #endif ) // Remap messiness due to this being weird in forge
+ private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, float partTick, CallbackInfo callback)
+ {
+ #if MC_VER < MC_1_17_1
+ FluidState fluidState = camera.getFluidInCamera();
+ boolean cameraNotInFluid = fluidState.isEmpty();
+ #else
+ FogType fogTypes = camera.getFluidInCamera();
+ boolean cameraNotInFluid = fogTypes == FogType.NONE;
+ #endif
+
+
+ Entity entity = camera.getEntity();
+ boolean isSpecialFog = (entity instanceof LivingEntity) && ((LivingEntity) entity).hasEffect(MobEffects.BLINDNESS);
+ if (!isSpecialFog && cameraNotInFluid && fogMode == FogMode.FOG_TERRAIN
+ && !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial()
+ && Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get())
+ {
+ #if MC_VER < MC_1_17_1
+ RenderSystem.fogStart(A_REALLY_REALLY_BIG_VALUE);
+ RenderSystem.fogEnd(A_EVEN_LARGER_VALUE);
+ #else
+ RenderSystem.setShaderFogStart(A_REALLY_REALLY_BIG_VALUE);
+ RenderSystem.setShaderFogEnd(A_EVEN_LARGER_VALUE);
+ #endif
+ }
+ }
+
+}
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinGameRenderer.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinGameRenderer.java
new file mode 100644
index 000000000..071983ab9
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinGameRenderer.java
@@ -0,0 +1,58 @@
+package com.seibel.distanthorizons.neoforge.mixins.client;
+
+import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
+import com.seibel.distanthorizons.core.api.internal.ClientApi;
+import net.minecraft.client.renderer.GameRenderer;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+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;
+
+// TODO: Check if this port from fabric works
+@Mixin(GameRenderer.class)
+public class MixinGameRenderer
+{
+ private static final Logger LOGGER = LogManager.getLogger(MixinGameRenderer.class.getSimpleName());
+
+ #if MC_VER >= MC_1_17_1
+ // FIXME: This I think will dup multiple renderStartupEvent calls...
+ @Inject(method = {"reloadShaders", "preloadUiShader"}, at = @At("TAIL"))
+ public void onStartupShaders(CallbackInfo ci)
+ {
+ LOGGER.info("Starting up renderer (forge)");
+ if (!DependencySetupDoneCheck.isDone)
+ {
+ LOGGER.warn("Dependency setup is not done yet, skipping renderer this startup event!");
+ return;
+ }
+ ClientApi.INSTANCE.rendererStartupEvent();
+ }
+
+ @Inject(method = "shutdownShaders", at = @At("HEAD"))
+ public void onShutdownShaders(CallbackInfo ci)
+ {
+ LOGGER.info("Shutting down renderer (forge)");
+ if (!DependencySetupDoneCheck.isDone)
+ {
+ LOGGER.warn("Dependency setup is not done yet, skipping renderer this shutdown event!");
+ return;
+ }
+ ClientApi.INSTANCE.rendererShutdownEvent();
+ }
+ #else
+
+
+ @Inject(method = {"loadEffect"}, at = @At("TAIL"))
+ public void onStartupShaders(CallbackInfo ci) {
+ ClientApi.INSTANCE.rendererStartupEvent();
+ }
+
+ @Inject(method = "shutdownEffect", at = @At("HEAD"))
+ public void onShutdownShaders(CallbackInfo ci) {
+ ClientApi.INSTANCE.rendererShutdownEvent();
+ }
+ #endif
+
+}
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinLevelRenderer.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinLevelRenderer.java
new file mode 100644
index 000000000..8c3c0506c
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinLevelRenderer.java
@@ -0,0 +1,163 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020-2023 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.neoforge.mixins.client;
+
+import com.mojang.blaze3d.systems.RenderSystem;
+import com.mojang.blaze3d.vertex.PoseStack;
+#if MC_VER < MC_1_19_4
+import com.mojang.math.Matrix4f;
+#else
+import com.seibel.distanthorizons.neoforge.NeoforgeClientProxy;
+import net.minecraft.client.Camera;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.GameRenderer;
+import net.minecraft.client.renderer.LightTexture;
+import org.joml.Matrix4f;
+#endif
+import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
+import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
+import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
+import com.seibel.distanthorizons.core.config.Config;
+import com.seibel.distanthorizons.core.api.internal.ClientApi;
+import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
+import net.minecraft.client.multiplayer.ClientLevel;
+import net.minecraft.client.renderer.LevelRenderer;
+import net.minecraft.client.renderer.RenderType;
+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;
+
+#if MC_VER < MC_1_17_1
+import org.lwjgl.opengl.GL15;
+#endif
+
+
+/**
+ * This class is used to mix in DH's rendering code
+ * before Minecraft starts rendering blocks.
+ * If this wasn't done, and we used Forge's
+ * render last event, the LODs would render on top
+ * of the normal terrain.
+ *
+ * This is also the mixin for rendering the clouds
+ */
+@Mixin(LevelRenderer.class)
+public class MixinLevelRenderer
+{
+ @Shadow
+ #if MC_VER >= MC_1_20_4
+ (remap = false)
+ #endif
+ private ClientLevel level;
+
+
+ #if MC_VER < MC_1_17_1
+ @Inject(at = @At("HEAD"),
+ method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDD)V",
+ cancellable = true)
+ private void renderChunkLayer(RenderType renderType, PoseStack matrixStackIn, double xIn, double yIn, double zIn, CallbackInfo callback)
+ #elif MC_VER < MC_1_19_4
+ @Inject(at = @At("HEAD"),
+ method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLcom/mojang/math/Matrix4f;)V",
+ cancellable = true)
+ private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
+ #elif MC_VER < MC_1_20_2
+ @Inject(at = @At("HEAD"),
+ method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
+ cancellable = true)
+ private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
+ #elif MC_VER < MC_1_20_6
+ @Inject(at = @At("HEAD"),
+ method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V",
+ cancellable = true)
+ private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double camX, double camY, double camZ, Matrix4f projectionMatrix, CallbackInfo callback)
+ #else
+ @Inject(at = @At("HEAD"),
+ method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;DDDLorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V",
+ cancellable = true)
+ private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f projectionMatrix, Matrix4f frustumMatrix, CallbackInfo callback)
+ #endif
+ {
+ #if MC_VER == MC_1_16_5
+ // get the matrices from the OpenGL fixed pipeline
+ float[] mcProjMatrixRaw = new float[16];
+ GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
+ Mat4f mcProjectionMatrix = new Mat4f(mcProjMatrixRaw);
+ mcProjectionMatrix.transpose();
+
+ Mat4f mcModelViewMatrix = McObjectConverter.Convert(matrixStackIn.last().pose());
+
+ #elif MC_VER <= MC_1_20_4
+ // get the matrices directly from MC
+ Mat4f mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose());
+ Mat4f mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
+ #else
+ // get the matrices from neoForge's render event.
+ // We can't call the renderer there because we don't have access to the level that's being rendered
+ Mat4f mcModelViewMatrix = NeoforgeClientProxy.currentModelViewMatrix;
+ Mat4f mcProjectionMatrix = NeoforgeClientProxy.currentProjectionMatrix;
+ #endif
+
+
+ float frameTime;
+ #if MC_VER < MC_1_21
+ frameTime = Minecraft.getInstance().getFrameTime();
+ #else
+ frameTime = Minecraft.getInstance().getTimer().getRealtimeDeltaTicks();
+ #endif
+
+ // only render before solid blocks
+ if (renderType.equals(RenderType.solid()))
+ {
+ ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, frameTime);
+ }
+ else if (renderType.equals(RenderType.translucent()))
+ {
+ ClientApi.INSTANCE.renderDeferredLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, frameTime);
+ }
+
+ if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
+ {
+ callback.cancel();
+ }
+ }
+
+ #if MC_VER < MC_1_19_4
+ @Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runUpdates(IZZ)I"), method = "renderLevel")
+ public void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
+ #elif MC_VER < MC_1_20_1
+ @Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runUpdates(IZZ)I"), method = "renderLevel")
+ public void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
+ #elif MC_VER < MC_1_20_6
+ @Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I"), method = "renderLevel")
+ private void callAfterRunUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci)
+ #else
+ @Inject(at = @At(value = "TAIL", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I"), method = "renderLevel")
+ private void callAfterRunUpdates(CallbackInfo ci)
+ #endif
+ {
+ ChunkWrapper.syncedUpdateClientLightStatus();
+ }
+
+
+}
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinDynamicTexture.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinLightTexture.java
similarity index 63%
rename from forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinDynamicTexture.java
rename to neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinLightTexture.java
index 3f02eb37d..5ae06aec8 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/client/MixinDynamicTexture.java
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinLightTexture.java
@@ -17,7 +17,7 @@
* along with this program. If not, see .
*/
-package com.seibel.distanthorizons.forge.mixins.client;
+package com.seibel.distanthorizons.neoforge.mixins.client;
import com.mojang.blaze3d.platform.NativeImage;
@@ -26,47 +26,34 @@ import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapp
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
-import com.seibel.distanthorizons.common.util.ILightTextureMarker;
-
-import net.minecraft.client.renderer.texture.DynamicTexture;
+import net.minecraft.client.renderer.LightTexture;
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;
-@Mixin(DynamicTexture.class)
-public class MixinDynamicTexture implements ILightTextureMarker
+@Mixin(LightTexture.class)
+public class MixinLightTexture
{
- /** Used to prevent accidentally using other dynamic textures as a lightmap */
- @Unique
- private boolean isLightTexture = false;
-
@Shadow
@Final
- private NativeImage pixels;
+ private NativeImage lightPixels;
- @Inject(method = "upload()V", at = @At("HEAD"))
- public void updateLightTexture(CallbackInfo ci)
+
+ @Inject(method = "updateLightTexture(F)V", at = @At("RETURN"))
+ public void updateLightTexture(float partialTicks, CallbackInfo ci)
{
- // since the light map is always updated on the client render thread we should be able to access the client level at the same time
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
- if (!this.isLightTexture
- || mc == null
- || mc.getWrappedClientLevel() == null
- )
+ if (mc == null || mc.getWrappedClientLevel() == null)
{
return;
}
- //ApiShared.LOGGER.info("Lightmap update");
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
- MinecraftRenderWrapper.INSTANCE.updateLightmap(this.pixels, clientLevel);
+ MinecraftRenderWrapper.INSTANCE.updateLightmap(this.lightPixels, clientLevel);
}
- public void markLightTexture() { this.isLightTexture = true; }
-
}
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinMinecraft.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinMinecraft.java
new file mode 100644
index 000000000..a202069a0
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinMinecraft.java
@@ -0,0 +1,110 @@
+package com.seibel.distanthorizons.neoforge.mixins.client;
+
+import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
+import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
+import com.seibel.distanthorizons.core.config.Config;
+import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
+import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
+import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
+import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
+import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
+import com.seibel.distanthorizons.coreapi.ModInfo;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.screens.TitleScreen;
+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.Redirect;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+/**
+ * At the moment this is only used for the auto updater
+ *
+ * @author coolGi
+ */
+@Mixin(Minecraft.class)
+public class MixinMinecraft
+{
+ // commented out due to a bug with Manifold and having nested preprocessors
+ // and since neoforge doesn't work for anything before MC 1.20.6 anyway it doesn't need to be included
+
+ //#if MC_VER < MC_1_20_2
+ //#if MC_VER == MC_1_20_1
+ //@Redirect(
+ // method = "Lnet/minecraft/client/Minecraft;setInitialScreen(Lcom/mojang/realmsclient/client/RealmsClient;Lnet/minecraft/server/packs/resources/ReloadInstance;Lnet/minecraft/client/main/GameConfig$QuickPlayData;)V",
+ // at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V")
+ //)
+ //public void onOpenScreen(Minecraft instance, Screen guiScreen)
+ //{
+ //#else
+ //@Redirect(
+ // method = "(Lnet/minecraft/client/main/GameConfig;)V",
+ // at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V")
+ //)
+ //public void onOpenScreen(Minecraft instance, Screen guiScreen)
+ //{
+ //#endif
+ // if (!Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get()) // Don't do anything if the user doesn't want it
+ // {
+ // instance.setScreen(guiScreen); // Sets the screen back to the vanilla screen as if nothing ever happened
+ // return;
+ // }
+ //
+ // if (SelfUpdater.onStart())
+ // {
+ // instance.setScreen(new UpdateModScreen(
+ // new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
+ // (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()): GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
+ // ));
+ // }
+ // else
+ // {
+ // instance.setScreen(guiScreen); // Sets the screen back to the vanilla screen as if nothing ever happened
+ // }
+ //}
+ //#endif
+
+ #if MC_VER >= MC_1_20_2
+ @Redirect(
+ method = "Lnet/minecraft/client/Minecraft;onGameLoadFinished(Lnet/minecraft/client/Minecraft$GameLoadCookie;)V",
+ at = @At(value = "INVOKE", target = "Ljava/lang/Runnable;run()V")
+ )
+ private void buildInitialScreens(Runnable runnable)
+ {
+ if (
+ Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() // Don't do anything if the user doesn't want it
+ && SelfUpdater.onStart()
+ )
+ {
+ runnable = () ->
+ {
+ String versionId;
+ EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
+ if (updateBranch == EDhApiUpdateBranch.STABLE)
+ {
+ versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
+ }
+ else
+ {
+ versionId = GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha");
+ }
+
+ Minecraft.getInstance().setScreen(new UpdateModScreen(
+ // TODO: Change to runnable, instead of tittle screen
+ new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
+ versionId
+ ));
+ };
+ }
+
+ runnable.run();
+ }
+ #endif
+
+ @Inject(at = @At("HEAD"), method = "close()V", remap = false)
+ public void close(CallbackInfo ci)
+ {
+ SelfUpdater.onClose();
+ }
+
+}
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinOptionsScreen.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinOptionsScreen.java
new file mode 100644
index 000000000..b1a661e78
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinOptionsScreen.java
@@ -0,0 +1,156 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020-2023 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.neoforge.mixins.client;
+
+import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
+import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
+import com.seibel.distanthorizons.coreapi.ModInfo;
+import com.seibel.distanthorizons.core.config.Config;
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.network.chat.Component;
+#if MC_VER < MC_1_19_2
+import net.minecraft.network.chat.TranslatableComponent;
+#endif
+import net.minecraft.resources.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;
+
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+
+#if MC_VER >= MC_1_20_6
+import net.minecraft.client.gui.layouts.LinearLayout;
+import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Shadow;
+#endif
+
+#if MC_VER < MC_1_21
+import net.minecraft.client.gui.screens.OptionsScreen;
+#else
+import net.minecraft.client.gui.screens.options.OptionsScreen;
+#endif
+
+
+/**
+ * Adds a button to the menu to goto the config
+ *
+ * @author coolGi
+ * @version 2024-5-20
+ */
+@Mixin(OptionsScreen.class)
+public class MixinOptionsScreen extends Screen
+{
+ /** Texture used for the config opening button */
+ @Unique
+ private static final ResourceLocation ICON_TEXTURE =
+ #if MC_VER < MC_1_21
+ new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
+ #else
+ ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
+ #endif
+
+
+ @Unique
+ private TexturedButtonWidget optionsButton = null;
+
+ #if MC_VER >= MC_1_20_6
+ @Shadow
+ @Final
+ protected HeaderAndFooterLayout layout;
+ #endif
+
+
+
+ //==============//
+ // constructors //
+ //==============//
+
+ protected MixinOptionsScreen(Component title) { super(title); }
+
+ @Inject(at = @At("RETURN"), method = "init")
+ private void lodconfig$init(CallbackInfo ci)
+ {
+ if (Config.Client.optionsButton.get())
+ {
+ #if MC_VER < MC_1_17_1
+ this.addButton(this.getOptionsButton());
+ #elif MC_VER < MC_1_20_6
+ this.addRenderableWidget(this.getOptionsButton());
+ #else
+
+ // add the button so it's rendered
+ this.addRenderableWidget(this.getOptionsButton());
+
+ // add the button to the correct location in the UI
+ // TODO is there a better way to do this instead of using access transformers to inject into the exact UI elements?
+ LinearLayout layout = (LinearLayout) this.layout.headerFrame.children.get(0).child;
+
+ // determine how wide the other option buttons are so we can put our botton to the left of them all
+ AtomicInteger width = new AtomicInteger(0);
+ layout.visitChildren(x -> { width.addAndGet(x.getWidth()); });
+ width.addAndGet(-10); // padding between the DH button and the FOV slider
+
+ layout.wrapped.addChild(this.getOptionsButton(), 1, 2, (settings) -> { settings.paddingLeft(width.get() * -1); });
+ layout.arrangeElements();
+
+ #endif
+ }
+ }
+
+
+
+ //================//
+ // helper methods //
+ //================//
+
+ @Unique
+ public TexturedButtonWidget getOptionsButton()
+ {
+ if (this.optionsButton == null)
+ {
+ this.optionsButton
+ = new TexturedButtonWidget(
+ // Where the button is on the screen
+ this.width / 2 - 180, this.height / 6 - 12,
+ // Width and height of the button
+ 20, 20,
+ // texture UV 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
+ (buttonWidget) -> Objects.requireNonNull(this.minecraft).setScreen(GetConfigScreen.getScreen(this)),
+ // Add a title to the button
+ #if MC_VER < MC_1_19_2
+ new TranslatableComponent(ModInfo.ID + ".title"));
+ #else
+ Component.translatable(ModInfo.ID + ".title"));
+ #endif
+ }
+
+ return this.optionsButton;
+ }
+
+}
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinTextureUtil.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinTextureUtil.java
new file mode 100644
index 000000000..57b40bc72
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinTextureUtil.java
@@ -0,0 +1,31 @@
+package com.seibel.distanthorizons.neoforge.mixins.client;
+
+import com.mojang.blaze3d.platform.GlStateManager;
+import com.mojang.blaze3d.platform.TextureUtil;
+import com.seibel.distanthorizons.core.config.Config;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+/**
+ * Sets Minecraft's LOD Bias (looks similar to mipmaps)
+ *
+ * @author coolGi
+ */
+@Mixin(TextureUtil.class)
+public class MixinTextureUtil
+{
+ @Redirect(method = "prepareImage(Lcom/mojang/blaze3d/platform/NativeImage$InternalGlFormat;IIII)V",
+ at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;_texParameter(IIF)V"), remap = false)
+ private static void setLodBias(int target, int pname, float param)
+ {
+ float biasValue = Config.Client.Advanced.Graphics.AdvancedGraphics.lodBias.get().floatValue();
+ if (biasValue != 0)
+ {
+ // The target is GL11.GL_TEXTURE_2D
+ // And the pname is GL14.GL_TEXTURE_LOD_BIAS
+ GlStateManager._texParameter(target, pname, biasValue);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinChunkGenerator.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinChunkGenerator.java
new file mode 100644
index 000000000..5d70347c3
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinChunkGenerator.java
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020-2023 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.neoforge.mixins.server;
+
+import org.spongepowered.asm.mixin.Mixin;
+import net.minecraft.world.level.chunk.ChunkGenerator;
+
+#if MC_VER < MC_1_18_2
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.server.level.WorldGenRegion;
+import net.minecraft.world.level.StructureFeatureManager;
+import net.minecraft.world.level.biome.Biome;
+import net.minecraft.world.level.levelgen.WorldgenRandom;
+
+@Mixin(ChunkGenerator.class)
+public class MixinChunkGenerator
+{
+ @Redirect(method = "applyBiomeDecoration", at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/world/level/biome/Biome;generate(Lnet/minecraft/world/level/StructureFeatureManager;"
+ + "Lnet/minecraft/world/level/chunk/ChunkGenerator;Lnet/minecraft/server/level/WorldGenRegion;J"
+ + "Lnet/minecraft/world/level/levelgen/WorldgenRandom;Lnet/minecraft/core/BlockPos;)V"
+
+ ))
+ private void wrapBiomeGenerateCall(
+ Biome biome, StructureFeatureManager structFeatManager, ChunkGenerator generator,
+ WorldGenRegion genRegion, long l, WorldgenRandom random, BlockPos pos)
+ {
+ synchronized (ChunkGenerator.class)
+ {
+ //ApiShared.LOGGER.info("Generating Biome {} and acquired lock.", biome.getRegistryName());
+ biome.generate(structFeatManager, (ChunkGenerator) (Object) this, genRegion, l, random, pos);
+ }
+ //ApiShared.LOGGER.info("Released lock. Biome {} generated.", biome.getRegistryName());
+ }
+
+}
+
+#else
+@Mixin(ChunkGenerator.class)
+public class MixinChunkGenerator { }
+#endif
\ No newline at end of file
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinTFChunkGenerator.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinTFChunkGenerator.java
new file mode 100644
index 000000000..42f0ec9f2
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinTFChunkGenerator.java
@@ -0,0 +1,61 @@
+package com.seibel.distanthorizons.neoforge.mixins.server;
+
+import net.minecraft.world.level.chunk.ChunkGenerator;
+import org.spongepowered.asm.mixin.Mixin;
+
+#if MC_VER == MC_1_16_5
+@Mixin(ChunkGenerator.class)
+class MixinTFChunkGenerator
+{
+ // not currently implemented, attempting to run with the mod enabled in the IDE causes the game to lock up
+}
+#elif MC_VER < MC_1_17_1
+
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+import com.terraforged.mod.chunk.generator.FeatureGenerator;
+
+import java.util.Random;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.WorldGenLevel;
+import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
+
+@Mixin(FeatureGenerator.class)
+public class MixinTFChunkGenerator
+{
+
+ @Redirect(method = "decorate("
+ + "Lnet/minecraft/world/level/StructureFeatureManager;"
+ + "Lnet/minecraft/world/level/WorldGenLevel;"
+ + "Lnet/minecraft/world/level/chunk/ChunkAccess;"
+ + "Lnet/minecraft/world/level/biome/Biome;"
+ + "Lnet/minecraft/core/BlockPos;"
+ + "Lcom/terraforged/mod/profiler/watchdog/WatchdogContext;)V",
+ at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/world/level/levelgen/feature/ConfiguredFeature;place("
+ + "Lnet/minecraft/world/level/WorldGenLevel;"
+ + "Lnet/minecraft/world/level/chunk/ChunkGenerator;"
+ + "Ljava/util/Random;Lnet/minecraft/core/BlockPos;)Z"
+ ))
+ private boolean wrapDecorate$FeaturePlace(ConfiguredFeature, ?> feature, WorldGenLevel arg,
+ ChunkGenerator arg2, Random random, BlockPos arg3) {
+ synchronized(FeatureGenerator.class) {
+ //ClientApi.LOGGER.info("wrapDecorate FeaturePlace triggered");
+ return feature.place(arg, arg2, random, arg3);
+ }
+ }
+
+ //METHOD: com.terraforged.mod.chunk.generator.FeatureGenerator.decorate(StructureFeatureManager manager,
+ // WorldGenLevel region, ChunkAccess chunk, Biome biome, BlockPos pos, WatchdogContext context)
+
+ //TARGET: boolean net.minecraft.world.level.levelgen.feature.ConfiguredFeature.place
+ // (WorldGenLevel arg, ChunkGenerator arg2, Random random, BlockPos arg3)
+}
+
+#else
+@Mixin(ChunkGenerator.class)
+class MixinTFChunkGenerator { }
+#endif
\ No newline at end of file
diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java
new file mode 100644
index 000000000..cbe606d49
--- /dev/null
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java
@@ -0,0 +1,78 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020-2023 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.neoforge.mixins.server;
+
+import java.util.concurrent.ExecutorService;
+import java.util.function.Supplier;
+
+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.CallbackInfoReturnable;
+
+import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
+import com.seibel.distanthorizons.core.util.objects.DummyRunExecutorService;
+
+import net.minecraft.Util;
+
+@Mixin(Util.class)
+public class MixinUtilBackgroundThread
+{
+ private static boolean shouldApplyOverride()
+ {
+ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get();
+ }
+
+ @Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
+ private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable ci)
+ {
+ if (shouldApplyOverride())
+ {
+ //ApiShared.LOGGER.info("util backgroundExecutor triggered");
+ ci.setReturnValue(new DummyRunExecutorService());
+ }
+ }
+
+ #if MC_VER >= MC_1_17_1
+ @Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/lang/Runnable;)Ljava/lang/Runnable;",
+ at = @At("HEAD"), cancellable = true)
+ private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable ci)
+ {
+ if (shouldApplyOverride())
+ {
+ //ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
+ ci.setReturnValue(r);
+ }
+ }
+ #endif
+ #if MC_VER >= MC_1_18_2
+ @Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/util/function/Supplier;)Ljava/util/function/Supplier;",
+ at = @At("HEAD"), cancellable = true)
+ private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier> r, CallbackInfoReturnable> ci)
+ {
+ if (shouldApplyOverride())
+ {
+ //ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
+ ci.setReturnValue(r);
+ }
+ }
+ #endif
+
+}
diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/wrappers/ForgeDependencySetup.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/ModChecker.java
similarity index 57%
rename from forge/src/main/java/com/seibel/distanthorizons/forge/wrappers/ForgeDependencySetup.java
rename to neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/ModChecker.java
index 5008ee6c0..6494d6edf 100644
--- a/forge/src/main/java/com/seibel/distanthorizons/forge/wrappers/ForgeDependencySetup.java
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/ModChecker.java
@@ -17,32 +17,27 @@
* along with this program. If not, see .
*/
-package com.seibel.distanthorizons.forge.wrappers;
+package com.seibel.distanthorizons.neoforge.wrappers.modAccessor;
-import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
-import com.seibel.distanthorizons.forge.wrappers.modAccessor.ModChecker;
+import net.neoforged.fml.ModList;
-/**
- * Binds all necessary dependencies so we
- * can access them in Core.
- * This needs to be called before any Core classes
- * are loaded.
- *
- * @author James Seibel
- * @author Ran
- * @version 12-1-2021
- */
-public class ForgeDependencySetup
+import java.io.File;
+
+public class ModChecker implements IModChecker
{
- public static void createInitialBindings()
+ public static final ModChecker INSTANCE = new ModChecker();
+
+ @Override
+ public boolean isModLoaded(String modid)
{
- SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
+ return ModList.get().isLoaded(modid);
}
- public static void runDelayedSetup()
+ @Override
+ public File modLocation(String modid)
{
- SingletonInjector.INSTANCE.runDelayedSetup();
+ return ModList.get().getModFileById(modid).getFile().getFilePath().toFile();
}
}
diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/FabricDependencySetup.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/OptifineAccessor.java
similarity index 56%
rename from fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/FabricDependencySetup.java
rename to neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/OptifineAccessor.java
index 13eb0b7eb..ceb05847c 100644
--- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/FabricDependencySetup.java
+++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/OptifineAccessor.java
@@ -17,32 +17,27 @@
* along with this program. If not, see .
*/
-package com.seibel.distanthorizons.fabric.wrappers;
+package com.seibel.distanthorizons.neoforge.wrappers.modAccessor;
-import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
-import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
-import com.seibel.distanthorizons.fabric.wrappers.modAccessor.ModChecker;
+import java.util.HashSet;
-/**
- * Binds all necessary dependencies, so we
- * can access them in Core.
- * This needs to be called before any Core classes
- * are loaded.
- *
- * @author James Seibel
- * @author Ran
- * @version 3-5-2022
- */
-public class FabricDependencySetup
+import com.seibel.distanthorizons.core.pos.DhChunkPos;
+import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor;
+
+public class OptifineAccessor extends AbstractOptifineAccessor
{
- public static void createInitialBindings()
+
+ @Override
+ public String getModName()
{
- SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
+ return "Optifine-Forge-1.18.X";
}
- public static void runDelayedSetup()
+ @Override
+ public HashSet getNormalRenderedChunks()
{
- SingletonInjector.INSTANCE.runDelayedSetup();
+ // TODO: Impl proper methods here
+ return null;
}
}
diff --git a/neoforge/src/main/resources/DistantHorizons.neoforge.mixins.json b/neoforge/src/main/resources/DistantHorizons.neoforge.mixins.json
new file mode 100644
index 000000000..5efe0dba6
--- /dev/null
+++ b/neoforge/src/main/resources/DistantHorizons.neoforge.mixins.json
@@ -0,0 +1,22 @@
+{
+ "required": true,
+ "minVersion": "0.8",
+ "package": "com.seibel.distanthorizons.neoforge.mixins",
+ "mixins": [
+ "server.MixinUtilBackgroundThread",
+ "server.MixinChunkGenerator",
+ "server.MixinTFChunkGenerator"
+ ],
+ "client": [
+ "client.MixinClientPacketListener",
+ "client.MixinDebugScreenOverlay",
+ "client.MixinFogRenderer",
+ "client.MixinGameRenderer",
+ "client.MixinLevelRenderer",
+ "client.MixinLightTexture",
+ "client.MixinOptionsScreen",
+ "client.MixinTextureUtil"
+ ],
+ "server": [],
+ "plugin": "com.seibel.distanthorizons.neoforge.mixins.NeoforgeMixinPlugin"
+}
diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml
new file mode 100644
index 000000000..be75d32f9
--- /dev/null
+++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml
@@ -0,0 +1,35 @@
+modLoader = "javafml" #//mandatory
+loaderVersion = "*" # // mandatory. Allow all forge versions as we are definding what Minecraft versions we requre later on
+license = "LGPL"
+issueTrackerURL = "${issues}"
+
+
+[[mods]] #//mandatory
+ modId = "distanthorizons" #//mandatory
+ version = "${version}" #//mandatory, gets the version number from jar populated by the build.gradle script
+ displayName = "${mod_name}" #//mandatory
+ authors = ["James Seibel", "Leonardo Amato", "Cola", "coolGi", "Ran", "Leetom"] # Should be done with `$authors`, but architectury complains
+ #//updateJSONURL="https://change.me.example.invalid/updates.json" # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/
+ displayURL = "${homepage}"
+ description = "${description}" #//mandatory. The description text for the mod
+ logoFile = "assets/distanthorizons/logo.png"
+ catalogueImageIcon = "assets/distanthorizons/icon.png"
+ credits = "Massive thanks to: Leonardo, Cola, Ran, CoolGi, and Leetom. For their hard work to bring Distant Horizons to where it is today. - James"
+ #// if not set defaults to "false"
+ clientSideOnly = "true"
+ #// if not set side defaults to "BOTH"
+ #// TODO change to "BOTH" when we add server support
+ side = "CLIENT"
+ #// Allow any version to be present (or not) on the server
+ acceptableRemoteVersions = "*"
+
+# We may need this to make forge (lexforge) & neoforge work together
+[[mixins]]
+ config = "DistantHorizons.neoforge.mixins.json"
+
+[[dependencies.distanthorizons]]
+ modId = "minecraft"
+ type = "required"
+ versionRange = "${compatible_forgemc_versions}" # Where we set what version of mc it is avalible for
+ ordering = "NONE"
+ side = "BOTH"
\ No newline at end of file
diff --git a/neoforge/src/main/resources/pack.mcmeta b/neoforge/src/main/resources/pack.mcmeta
new file mode 100644
index 000000000..37621f6f9
--- /dev/null
+++ b/neoforge/src/main/resources/pack.mcmeta
@@ -0,0 +1,10 @@
+{
+ "pack": {
+ "pack_format": 7,
+ "supported_formats": {
+ "min_inclusive": 16,
+ "max_inclusive": 90000
+ },
+ "description": "Distant Horizons"
+ }
+}
diff --git a/settings.gradle b/settings.gradle
index b1e6b43cb..fb99f9435 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -4,11 +4,19 @@ pluginManagement {
name "Fabric"
url "https://maven.fabricmc.net/"
}
- // TODO: Stop using Forge for versions with NeoForge
+ // TODO: Stop using Forge for versions with NeoForged
maven {
name "Forge"
url "https://maven.minecraftforge.net/"
}
+ maven {
+ name "NeoForge Releases"
+ url "https://maven.neoforged.net/releases/"
+ }
+ maven {
+ name "NeoForge Snapshot"
+ url "https://maven.neoforged.net/snapshots/"
+ }
maven {
name "Architectury (Better Forge because regular Forge is annoying)" // TODO: Once we switch to NeoForge, would it's gradle work better? or will it have Forge's problems in it
url "https://maven.architectury.dev/"
@@ -21,14 +29,36 @@ pluginManagement {
name "Sponge"
url "https://repo.spongepowered.org/repository/maven-public/"
}
+ maven {
+ name "ParchmentMC"
+ url "https://maven.parchmentmc.org"
+ }
mavenCentral()
gradlePluginPortal()
+
+ // Not needed, but useful for debugging gradle plugins
+ mavenLocal()
}
}
-// Loads the version.properties
+// Throw an error and a little help message if the user forgot to clone the core sub-project
+if (!file("./coreSubProjects/LICENSE.txt").exists()) { // the LICENCE.txt file should always, and only exist if the core-sub-project was cloned
+ println('''
+It seems that the core sub project was not included...
+ please make sure that when you were cloning the repo, you were using the `--recurse-submodules` flag on git.
+ and if its too late now to re-clone the project, please grab the core sub project in whatever way you can from https://gitlab.com/jeseibel/distant-horizons-core.git
+
+If you still need help with compiling, please read the Readme.md
+ ''')
+ throw new GradleException("coreSubProject not found")
+}
+
+
+
+
+/** Loads the VersionProperties fiel for the currently selected Minecraft version. */
def loadProperties() {
def defaultMcVersion = "1.20.1" // 1.20.1 is our current most stable version so we use that if no version was defined
@@ -65,7 +95,6 @@ def loadProperties() {
gradle.ext.mcVers = mcVers
gradle.ext.mcIndex = mcIndex
}
-
loadProperties()
@@ -81,7 +110,9 @@ project(":api").projectDir = file('coreSubProjects/api')
include("common")
// Enables or disables the subprojects depending on whats in the versionProperties/mcVer.properties
for (loader in ((String) gradle.builds_for).split(",")) {
- include(loader.strip()) // Strip it in case a space is added before or after the comma
+ def loaderName = loader.strip() // Strip it in case a space is added before or after the comma
+ println "Adding loader " + loaderName
+ include(loaderName)
}
//if (gradle.builds_for.contains("fabric") || gradle.builds_for.contains("quilt"))
// include("fabricLike")
diff --git a/versionProperties/1.16.5.properties b/versionProperties/1.16.5.properties
index dc8d54645..b43755a1a 100644
--- a/versionProperties/1.16.5.properties
+++ b/versionProperties/1.16.5.properties
@@ -5,6 +5,7 @@ parchment_version=1.16.5:2022.03.06
compatible_minecraft_versions=["1.16.4", "1.16.5"]
accessWidenerVersion=1_16
builds_for=fabric,forge
+embed_joml=true
# Fabric loader
fabric_loader_version=0.14.24
@@ -20,8 +21,8 @@ fabric_api_version=0.42.0+1.16
immersive_portals_version=
canvas_version=
- fabric_incompatibility_list={ }
- fabric_recommend_list={ "indium": "*" }
+ fabric_incompatibility_list={ "iris": "*" }
+ fabric_recommend_list={}
# Fabric mod run
# 0 = Don't enable and don't run
diff --git a/versionProperties/1.17.1.properties b/versionProperties/1.17.1.properties
index 8a8531d51..9b059c06d 100644
--- a/versionProperties/1.17.1.properties
+++ b/versionProperties/1.17.1.properties
@@ -5,6 +5,7 @@ parchment_version=1.17.1:2021.12.12
compatible_minecraft_versions=["1.17", "1.17.1"]
accessWidenerVersion=1_17
builds_for=fabric,forge
+embed_joml=true
# Fabric loader
fabric_loader_version=0.14.24
@@ -16,12 +17,12 @@ fabric_api_version=0.46.1+1.17
lithium_version=
sodium_version=mc1.17.1-0.3.4
iris_version=1.17.x-v1.2.7
- bclib_version=0.5.6
+ bclib_version=0.5.5
immersive_portals_version=
canvas_version=
- fabric_incompatibility_list={ }
- fabric_recommend_list={ "indium": "*" }
+ fabric_incompatibility_list={ "iris": "*" }
+ fabric_recommend_list={}
# Fabric mod run
# 0 = Don't enable and don't run
diff --git a/versionProperties/1.18.2.properties b/versionProperties/1.18.2.properties
index e987c439f..e4b01723e 100644
--- a/versionProperties/1.18.2.properties
+++ b/versionProperties/1.18.2.properties
@@ -5,6 +5,7 @@ parchment_version=1.18.2:2022.11.06
compatible_minecraft_versions=["1.18.2"]
accessWidenerVersion=1_18
builds_for=fabric,forge
+embed_joml=true
# Fabric loader
fabric_loader_version=0.14.24
@@ -21,8 +22,8 @@ fabric_api_version=0.76.0+1.18.2
immersive_portals_version=v1.4.11-1.18
canvas_version=mc118:1.0.2616
- fabric_incompatibility_list={ }
- fabric_recommend_list={ "indium": "*" }
+ fabric_incompatibility_list={ "iris": "*" }
+ fabric_recommend_list={}
# Fabric mod run
# 0 = Don't enable and don't run
diff --git a/versionProperties/1.19.2.properties b/versionProperties/1.19.2.properties
index c4fe3195f..cc8479a27 100644
--- a/versionProperties/1.19.2.properties
+++ b/versionProperties/1.19.2.properties
@@ -5,6 +5,7 @@ parchment_version=1.19.2:2022.11.27
compatible_minecraft_versions=["1.19.2"]
accessWidenerVersion=1_19_2
builds_for=fabric,forge
+embed_joml=true
# Fabric loader
fabric_loader_version=0.14.24
@@ -20,8 +21,8 @@ fabric_api_version=0.76.1+1.19.2
immersive_portals_version=
canvas_version=mc119-1.0.2480
- fabric_incompatibility_list={ }
- fabric_recommend_list={ "indium": "*" }
+ fabric_incompatibility_list={ "iris": "*" }
+ fabric_recommend_list={}
# Fabric mod run
# 0 = Don't enable and don't run
diff --git a/versionProperties/1.19.4.properties b/versionProperties/1.19.4.properties
index c3a91dfda..7ba9a7565 100644
--- a/versionProperties/1.19.4.properties
+++ b/versionProperties/1.19.4.properties
@@ -20,8 +20,8 @@ fabric_api_version=0.87.1+1.19.4
immersive_portals_version=
canvas_version=
- fabric_incompatibility_list={ }
- fabric_recommend_list={ "indium": "*" }
+ fabric_incompatibility_list={ "iris": "*" }
+ fabric_recommend_list={}
# Fabric mod run
# 0 = Don't enable and don't run
diff --git a/versionProperties/1.20.1.properties b/versionProperties/1.20.1.properties
index 5eb7c4c78..69cede1c0 100644
--- a/versionProperties/1.20.1.properties
+++ b/versionProperties/1.20.1.properties
@@ -7,7 +7,7 @@ accessWidenerVersion=1_20
builds_for=fabric,forge
# Fabric loader
-fabric_loader_version=0.14.24
+fabric_loader_version=0.15.6
fabric_api_version=0.90.4+1.20.1
# Fabric mod versions
modmenu_version=7.2.2
@@ -16,12 +16,12 @@ fabric_api_version=0.90.4+1.20.1
lithium_version=
sodium_version=mc1.20.1-0.5.3
iris_version=1.6.10+1.20.1
- bclib_version=3.0.12
+ bclib_version=3.0.13
immersive_portals_version=
canvas_version=
- fabric_incompatibility_list={ }
- fabric_recommend_list={ "indium": "*" }
+ fabric_incompatibility_list={ "iris": "<=1.6.20" }
+ fabric_recommend_list={}
# Fabric mod run
# 0 = Don't enable and don't run
diff --git a/versionProperties/1.20.2.properties b/versionProperties/1.20.2.properties
index 1f15abab5..62f394c8a 100644
--- a/versionProperties/1.20.2.properties
+++ b/versionProperties/1.20.2.properties
@@ -7,7 +7,7 @@ accessWidenerVersion=1_20_2
builds_for=fabric,forge
# Fabric loader
-fabric_loader_version=0.14.24
+fabric_loader_version=0.15.6
fabric_api_version=0.90.4+1.20.2
# Fabric mod versions
modmenu_version=8.0.0
@@ -20,8 +20,8 @@ fabric_api_version=0.90.4+1.20.2
immersive_portals_version=
canvas_version=
- fabric_incompatibility_list={ }
- fabric_recommend_list={ "indium": "*" }
+ fabric_incompatibility_list={ "iris": "<=1.6.20" }
+ fabric_recommend_list={}
# Fabric mod run
# 0 = Don't enable and don't run
diff --git a/versionProperties/1.20.4.properties b/versionProperties/1.20.4.properties
index 31c0b6c76..380a3fd7c 100644
--- a/versionProperties/1.20.4.properties
+++ b/versionProperties/1.20.4.properties
@@ -1,13 +1,14 @@
# 1.20.4 version
java_version=17
minecraft_version=1.20.4
-parchment_version=1.20.1:2023.09.03
+parchment_version=1.20.2:2023.12.10
compatible_minecraft_versions=["1.20.3", "1.20.4"]
accessWidenerVersion=1_20_2
builds_for=fabric,forge
+# neoforge can be added once the issue with mixins has been resolved
# Fabric loader
-fabric_loader_version=0.15.1
+fabric_loader_version=0.15.6
fabric_api_version=0.91.2+1.20.4
# Fabric mod versions
modmenu_version=9.0.0-pre.1
@@ -20,8 +21,8 @@ fabric_api_version=0.91.2+1.20.4
immersive_portals_version=
canvas_version=
- fabric_incompatibility_list={ }
- fabric_recommend_list={ "indium": "*" }
+ fabric_incompatibility_list={ "iris": "<=1.6.20" }
+ fabric_recommend_list={}
# Fabric mod run
# 0 = Don't enable and don't run
@@ -36,13 +37,14 @@ fabric_api_version=0.91.2+1.20.4
enable_immersive_portals=0
enable_canvas=0
-# Forge loader
-forge_version=49.0.14
- # Forge mod versions
+# (Neo)Forge loader
+forge_version=49.0.30
+neoforge_version=20.4.233
+ # (Neo)Forge mod versions
starlight_version_forge=
terraforged_version=
- # Forge mod run
+ # (Neo)Forge mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
diff --git a/versionProperties/1.20.6.properties b/versionProperties/1.20.6.properties
new file mode 100644
index 000000000..273c66923
--- /dev/null
+++ b/versionProperties/1.20.6.properties
@@ -0,0 +1,53 @@
+# 1.20.6 version
+java_version=21
+minecraft_version=1.20.6
+parchment_version=1.20.6:2024.05.01
+compatible_minecraft_versions=["1.20.6"]
+accessWidenerVersion=1_20_6
+builds_for=fabric,neoforge
+# forge is broken due to gradle/build script issues
+
+# Fabric loader
+fabric_loader_version=0.15.10
+fabric_api_version=0.97.8+1.20.6
+ # Fabric mod versions
+ modmenu_version=10.0.0-beta.1
+ starlight_version_fabric=
+ phosphor_version_fabric=
+ lithium_version=
+ sodium_version=mc1.20.6-0.5.8
+ iris_version=1.7.0+1.20.6
+ bclib_version=
+ immersive_portals_version=
+ canvas_version=
+
+ fabric_incompatibility_list={ "iris": "<=1.6.20" }
+ fabric_recommend_list={}
+
+ # Fabric mod run
+ # 0 = Don't enable and don't run
+ # 1 = Can be referenced in code but doesn't run
+ # 2 = Can be referenced in code and runs in client
+ enable_starlight=0
+ enable_phosphor=0
+ enable_sodium=1
+ enable_lithium=0
+ enable_iris=1
+ enable_bclib=0
+ enable_immersive_portals=0
+ enable_canvas=0
+
+# (Neo)Forge loader
+forge_version=50.0.19
+neoforge_version=20.6.70-beta
+ # (Neo)Forge mod versions
+ starlight_version_forge=
+ terraforged_version=
+
+ # (Neo)Forge mod run
+ # 0 = Don't enable and don't run
+ # 1 = Can be referenced in code but doesn't run
+ # 2 = Can be referenced in code and runs in client
+ enable_starlight_forge=0
+ enable_terraforged=0
+ enable_terrafirmacraft=0
diff --git a/versionProperties/1.21.properties b/versionProperties/1.21.properties
new file mode 100644
index 000000000..4e9ded570
--- /dev/null
+++ b/versionProperties/1.21.properties
@@ -0,0 +1,53 @@
+# 1.21 version
+java_version=21
+minecraft_version=1.21
+parchment_version=1.20.6:2024.05.01
+compatible_minecraft_versions=["1.21.0"]
+accessWidenerVersion=1_20_6
+builds_for=fabric,neoforge
+# forge is broken due to gradle/build script issues
+
+# Fabric loader
+fabric_loader_version=0.15.11
+fabric_api_version=0.100.1+1.21
+ # Fabric mod versions
+ modmenu_version=11.0.0-beta.1
+ starlight_version_fabric=
+ phosphor_version_fabric=
+ lithium_version=
+ sodium_version=mc1.21-0.5.9
+ iris_version=1.7.1+1.21
+ bclib_version=
+ immersive_portals_version=
+ canvas_version=
+
+ fabric_incompatibility_list={ "iris": "<=1.6.20" }
+ fabric_recommend_list={}
+
+ # Fabric mod run
+ # 0 = Don't enable and don't run
+ # 1 = Can be referenced in code but doesn't run
+ # 2 = Can be referenced in code and runs in client
+ enable_starlight=0
+ enable_phosphor=0
+ enable_sodium=1
+ enable_lithium=0
+ enable_iris=1
+ enable_bclib=0
+ enable_immersive_portals=0
+ enable_canvas=0
+
+# (Neo)Forge loader
+forge_version=50.0.19
+neoforge_version=21.0.4-beta
+ # (Neo)Forge mod versions
+ starlight_version_forge=
+ terraforged_version=
+
+ # (Neo)Forge mod run
+ # 0 = Don't enable and don't run
+ # 1 = Can be referenced in code but doesn't run
+ # 2 = Can be referenced in code and runs in client
+ enable_starlight_forge=0
+ enable_terraforged=0
+ enable_terrafirmacraft=0