Compare commits

...

44 Commits

Author SHA1 Message Date
James Seibel e1e63d4981 Add compile instructions and further improve the readme 2021-03-01 10:08:20 -06:00
James Seibel 12f4a2d159 Fix a readme typo 2021-03-01 09:57:43 -06:00
James Seibel fa2f12e4e0 Change the version number to alpha 1 2021-03-01 09:37:01 -06:00
James Seibel 520e2e99d9 Add the state of multiplayer to the readme 2021-03-01 09:24:09 -06:00
James Seibel 759d6a0a94 Add the MC version to the build archive name 2021-03-01 09:23:44 -06:00
James Seibel 7983f59ff1 Improve the mod description in the readme 2021-03-01 09:10:18 -06:00
James Seibel cd33b4c33e Update the readme to reflect the state of this branch 2021-02-28 22:46:37 -06:00
James Seibel 49bbc56941 Update the build.gradle 2021-02-28 18:42:06 -06:00
James Seibel bf6813b6a5 Improve magic number comments 2021-02-28 17:17:03 -06:00
James Seibel f96a6dcecd Improve how block color is determined 2021-02-28 16:35:46 -06:00
James Seibel 306f575edd Fix not regening the LODs when changing dimensions 2021-02-28 16:15:40 -06:00
James Seibel 8babc5aa65 Fix a bug related to disabling depth testing 2021-02-28 16:03:38 -06:00
James Seibel 6abbf328fb Remove issue #6, partially fixed in 6bedfa5 2021-02-28 16:01:51 -06:00
James Seibel 6bedfa5136 Partially implement screen swirling effects
It isn't great, but it works well enough
2021-02-28 16:00:18 -06:00
James Seibel e02156b1a4 Add LOD lighting 2021-02-28 15:07:09 -06:00
James Seibel 673474cd64 Re-implement config files 2021-02-27 21:45:37 -06:00
James Seibel 807818e078 Fix a few meta info files 2021-02-27 21:45:12 -06:00
James Seibel 22840bd4e3 Small refactor to ClientProxy 2021-02-27 21:03:00 -06:00
James Seibel 4c71c9aad5 Add small refactors and improvements to LodRenderer 2021-02-27 20:39:47 -06:00
James Seibel cc1683f573 Remove an unneeded variable decleration 2021-02-27 19:44:49 -06:00
James Seibel 62dc86d64e Update LodRenderer class comment 2021-02-27 19:44:37 -06:00
James Seibel ef65f87777 Improve how different fog levels are rendered 2021-02-27 19:41:45 -06:00
James Seibel 055f64e7c6 Improve the world changing logic 2021-02-27 19:09:52 -06:00
James Seibel a0fc9835b6 rename getWorldIdentifier to getCurrentWorldID 2021-02-27 19:08:11 -06:00
James Seibel b127ad0538 prevent a potential null pointer 2021-02-27 19:04:42 -06:00
James Seibel e1cf190a7f Replace getWorldName with getWorldIdentifier 2021-02-27 19:04:17 -06:00
James Seibel 27caab932c re-add depth testing
It was disabled by default previously
2021-02-27 19:02:36 -06:00
James Seibel d06415bd3e Remove the unneeded common proxy 2021-02-27 18:59:50 -06:00
James Seibel 14e0fca1ed Update and improve meta info files 2021-02-27 17:23:17 -06:00
James Seibel 3d6ba0fad9 Remove a test mixin file 2021-02-27 17:22:48 -06:00
James Seibel 84bdd3dd90 Fix fog not rendering 2021-02-27 17:07:44 -06:00
James Seibel e81cd17ecf Fix the FOV being incorrect 2021-02-27 11:38:00 -06:00
James Seibel 58b0eafe29 Replace the old render logic with VBO rendering 2021-02-27 11:31:53 -06:00
James Seibel 336cfb0749 Remove duplicate files 2021-02-26 22:46:10 -06:00
James Seibel 0f5990e2f8 Remove an unneeded variable 2021-02-26 17:45:00 -06:00
James Seibel 7acad77eda Fix LOD color generation 2021-02-26 17:40:53 -06:00
James Seibel fb0ff2a00c Improve naming of methods in LodChunk 2021-02-26 13:39:08 -06:00
James Seibel ab7157476b Fix a potential null pointer exception 2021-02-26 13:38:54 -06:00
James Seibel 40bc930d34 Add missing info to a comment 2021-02-26 13:21:32 -06:00
James Seibel 9500805243 Fix lod file reading and writing 2021-02-26 13:19:52 -06:00
James Seibel f637e5fd44 Fix a possible casting error 2021-02-26 13:18:37 -06:00
James Seibel cfda8c9655 Bring over improvements and changes from the master branch 2021-02-26 10:31:34 -06:00
James Seibel cb04b2df09 Update Readme.txt 2021-02-21 08:33:46 -06:00
James Seibel f754467450 Initial work to update to 1.16.4 2021-02-21 08:31:03 -06:00
65 changed files with 3650 additions and 1956 deletions
+5
View File
@@ -0,0 +1,5 @@
# Disable autocrlf on generated files, they always generate with LF
# Add any extra files or paths here to make git stop saying they
# are changed when only line endings change.
src/generated/**/.cache/cache text eol=lf
src/generated/**/*.json text eol=lf
+3 -4
View File
@@ -19,8 +19,7 @@ build
# other
eclipse
run
# minecraft run folder,
# ignore everything but the mods folder
run/*
!run/mods
# Files from Forge MDK
forge*changelog.txt
-4
View File
@@ -1,4 +0,0 @@
[submodule "ASMHelper"]
path = ASMHelper
url = https://github.com/squeek502/ASMHelper.git
branch = 1.12.x
+1 -1
View File
@@ -10,7 +10,7 @@ alpha. Eloraam of RedPower, and SpaceToad of Buildcraft, without their acceptian
of me taking over the project, who knows what Minecraft modding would be today.
Secondly, someone who has worked with me, and developed some of the core features
that allow modding to he as functional, and as simple as it is, cpw. For developing
that allow modding to be as functional, and as simple as it is, cpw. For developing
FML, which stabelized the client and server modding ecosystem. As well as the base
loading system that allows us to modify Minecraft's code as elegently as possible.
-10
View File
@@ -1,10 +0,0 @@
IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD License.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of mumart nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -1,40 +0,0 @@
SoundSystem CodecIBXM Class License:
You are free to use this class for any purpose, commercial or otherwise.
You may modify this class or source code, and distribute it any way you
like, provided the following conditions are met:
1) You may not falsely claim to be the author of this class or any
unmodified portion of it.
2) You may not copyright this class or a modified version of it and then
sue me for copyright infringement.
3) If you modify the source code, you must clearly document the changes
made before redistributing the modified source code, so other users know
it is not the original code.
4) You are not required to give me credit for this class in any derived
work, but if you do, you must also mention my website:
http://www.paulscode.com
5) I the author will not be responsible for any damages (physical,
financial, or otherwise) caused by the use if this class or any
portion of it.
6) I the author do not guarantee, warrant, or make any representations,
either expressed or implied, regarding the use of this class or any
portion of it.
Author: Paul Lamb
http://www.paulscode.com
This software is based on or using the IBXM library available from
http://www.geocities.com/sunet2000/
IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD License.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of mumart nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+2 -8
View File
@@ -3,8 +3,8 @@ parts herein are licensed under the terms of the LGPL 2.1 found
here http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt and
copied below.
Homepage: http://MinecraftForge.net/
http://github.com/MinecraftForge/MinecraftForge
Homepage: http://minecraftforge.net/
https://github.com/MinecraftForge/MinecraftForge
A note on authorship:
@@ -57,12 +57,6 @@ This software contains a partial repackaging of javaxdelta, a BSD licensed progr
binary differences and applying them, sourced from the subversion at http://sourceforge.net/projects/javaxdelta/
authored by genman, heikok, pivot.
The only changes are to replace some Trove collection types with standard Java collections, and repackaged.
This software contains potions of Paulscodee IBXM library, a BSD liceensed library for
loading and playing IBXM formated auto. No modifications havee beeen made. The associated
licenses can be found along side this one, or at
https://github.com/MinecraftForge/MinecraftForge/blob/1.12.x/LICENSE-Paulscode%20IBXM%20Library.txt
https://github.com/MinecraftForge/MinecraftForge/blob/1.12.x/LICENSE-Paulscode%20SoundSystem%20CodecIBXM.txt
=========================================================================
Binary file not shown.
+44 -20
View File
@@ -1,8 +1,16 @@
This program is an attempt to create Level Of Details (LODs) in Minecraft.
The purpose is to increase the maximum view distance in game
This mod adds a Level Of Detail (LOD) system to Minecraft.
This implementation renders simplified chunks outside the normal render distance
allowing for an increased view distance without harming performance.
Used in congunction with:
https://gitlab.com/jeseibel/minecraft-lod-core-mod
Forge version: 1.16.4-35.1.4
Notes:
This version has been confirmed to work in Eclipse and retail Minecraft.
(retail running forge 1.16.4-35.1.37)
That being said only singleplayer is currently supported; connecting
to servers (local or otherwise) will cause no LODs to be drawn and
may cause instibility.
========================
@@ -12,30 +20,46 @@ source code installation
See the Forge Documentation online for more detailed instructions:
http://mcforge.readthedocs.io/en/latest/gettingstarted/
Step 1: open a command line in the project folder
Step 1: Create a system variable called "JAVA_MC_HOME" with the location of the JDK 1.8.0_251 (This is needed for gradle to work correctly)
Step 2: run the command: "./gradlew setupDecompWorkspace"
Step 2: replace JAVA_HOME with JAVA_MC_HOME in gradle.bat
Step 3: run the command: "./gradlew eclipse"
Step 3: open a command line in the project folder
Step 4: Import project
Step 4: run the command: "./gradlew geneclipseruns"
Step 5: Create a system variable called "JAVA_MC_HOME" with the location of the JDK 1.8.0_251 (This is needed for gradle to work correctly)
And make sure it is used in the build.gradle file.
Step 6: Import the lodcore and lodcore_source jar files into the referenced libraries.
Step 5: run the command: "./gradlew eclipse"
Step 6: Make sure the eclipse has the JDK 1.8.0_251 installed. (This is needed so that eclipse can run minecraft)
Other commands:
"gradlew --refresh-dependencies" to refresh local dependencies.
"gradlew clean" to reset everything (this does not affect your code) and then start the process again.
Step 7: Import the project into eclipse
Tip:
The Minecraft source code is NOT added to your workspace in a editable way. Minecraft is treated like a normal Library. Sources are there for documentation and research purposes only.
=========
compiling
=========
Step 1: open a command line in the project folder
Step 2: run the command: "./gradlew build"
Step 3: the compiled jar file will be in the folder "build\libs"
==============
Other commands
==============
"./gradlew --refresh-dependencies" to refresh local dependencies.
"./gradlew clean" to reset everything (this does not affect your code) and then start the process again.
============
Note to self
============
The Minecraft source code is NOT added to your workspace in a editable way. Minecraft is treated like a normal Library. Sources are there for documentation and research purposes only.
Current location of mcp-srg.srg:
"C:/Users/James Seibel/.gradle/caches/minecraft/de/oceanlabs/mcp/mcp_snapshot/20171003/1.12.2/srgs/"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.
Binary file not shown.
-1
View File
@@ -1 +0,0 @@
these are tools needed for looking at obfuscated minecraft code.
Binary file not shown.
Binary file not shown.
-1
View File
@@ -1 +0,0 @@
these are tools needed for deobfuscating and looking at the code of optifine.
-3
View File
@@ -1,3 +0,0 @@
java -jar ./simpledeobf-0.6.jar --input ./OptiFine_1.12.2_HD_U_F5.jar --output ./OptiFine_1.12.2_HD_U_F5_dev.jar --mapFile C:/Users/James_Seibel/.gradle/caches/minecraft/de/oceanlabs/mcp/mcp_snapshot/20171003/1.12.2/srgs/notch-mcp.srg --ref C:/Users/James_Seibel/.gradle/caches/minecraft/net/minecraft/minecraft/1.12.2/minecraft-1.12.2.jar
pause
Binary file not shown.
-1
View File
@@ -1 +0,0 @@
./gradlew build
+134 -51
View File
@@ -1,77 +1,160 @@
buildscript {
repositories {
maven { url = 'https://files.minecraftforge.net/maven' }
jcenter()
maven { url = "https://files.minecraftforge.net/maven" }
mavenCentral()
maven { url='https://dist.creeper.host/Sponge/maven' }
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true
classpath group: 'org.spongepowered', name: 'mixingradle', version: '0.7-SNAPSHOT'
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'org.spongepowered.mixin'
// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
version = 'a1'
group = 'com.backsun.lod'
archivesBaseName = 'lod_1.16.4'
version = "1.0"
group = "com.backsun.lod" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "lod"
sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
compileJava {
sourceCompatibility = targetCompatibility = '1.8'
}
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
minecraft {
version = "1.12.2-14.23.5.2847"
runDir = "run"
// the mappings can be changed at any time, and must be in the following format.
// snapshot_YYYYMMDD snapshot are built nightly.
// stable_# stables are built at the discretion of the MCP team.
// The mappings can be changed at any time, and must be in the following format.
// snapshot_YYYYMMDD Snapshot are built nightly.
// stable_# Stables are built at the discretion of the MCP team.
// Use non-default mappings at your own risk. they may not always work.
// simply re-run your setup task after changing the mappings to update your workspace.
mappings = "snapshot_20171003"
// Simply re-run your setup task after changing the mappings to update your workspace.
mappings channel: 'snapshot', version: '20201028-1.16.3'
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
// Default run configurations.
// These can be tweaked, removed, or duplicated as needed.
runs {
client {
workingDirectory project.file('run')
arg "-mixin.config=lod.mixins.json"
// Recommended logging data for a userdev environment
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
// Recommended logging level for the console
property 'forge.logging.console.level', 'debug'
mods {
examplemod {
source sourceSets.main
}
}
}
server {
workingDirectory project.file('run')
arg "-mixin.config=lod.mixins.json"
// Recommended logging data for a userdev environment
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
// Recommended logging level for the console
property 'forge.logging.console.level', 'debug'
mods {
examplemod {
source sourceSets.main
}
}
}
data {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
// Recommended logging level for the console
property 'forge.logging.console.level', 'debug'
// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
args '--mod', 'lod', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
mods {
examplemod {
source sourceSets.main
}
}
}
}
}
// Include resources generated by data generators.
sourceSets.main.resources { srcDir 'src/generated/resources' }
dependencies {
// you may put jars on which you depend on in ./libs
// or you may define them like so..
//compile "some.group:artifact:version:classifier"
//compile "some.group:artifact:version"
// real examples
//compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
//compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
// Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed
// that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied.
// The userdev artifact is a special name and will get all sorts of transformations applied to it.
minecraft 'net.minecraftforge:forge:1.16.4-35.1.4'
// the 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
//provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// You may put jars on which you depend on in ./libs or you may define them like so..
// compile "some.group:artifact:version:classifier"
// compile "some.group:artifact:version"
// the deobf configurations: 'deobfCompile' and 'deobfProvided' are the same as the normal compile and provided,
// except that these dependencies get remapped to your current MCP mappings
//deobfCompile 'com.mod-buildcraft:buildcraft:6.0.8:dev'
//deobfProvided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// Real examples
// compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
// compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
// for more info...
// The 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
// provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// These dependencies get remapped to your current MCP mappings
// deobf 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// For more info...
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
// http://www.gradle.org/docs/current/userguide/dependency_management.html
}
processResources {
// this will ensure that this task is redone when the versions change.
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
// replace stuff in mcmod.info, nothing else
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
// replace version and mcversion
expand 'version':project.version, 'mcversion':project.minecraft.version
}
// copy everything else except the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
// Example for how to get properties into the manifest for reading by the runtime..
jar {
manifest {
attributes([
"Specification-Title": "Levels of Detail",
"Specification-Version": "1", // We are version 1 of ourselves
"Implementation-Title": project.name,
"Implementation-Version": "1.0",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
"MixinConfigs": "lod.mixins.json",
])
}
}
// Example configuration to allow publishing using the maven-publish task
// This is the preferred method to reobfuscate your jar file
jar.finalizedBy('reobfJar')
// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
//publish.dependsOn('reobfJar')
publishing {
publications {
mavenJava(MavenPublication) {
artifact jar
}
}
repositories {
maven {
url "file:///${project.projectDir}/mcmodsrepo"
}
}
}
mixin {
add sourceSets.main, "lod.refmap.json"
}
+1563 -366
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -1,3 +1,4 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false
Binary file not shown.
+1 -2
View File
@@ -1,6 +1,5 @@
#Mon Sep 14 12:28:28 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip
Vendored
+59 -51
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
##############################################################################
##
@@ -6,47 +6,6 @@
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@@ -61,9 +20,49 @@ while [ -h "$PRG" ] ; do
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$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=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -90,7 +89,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -114,6 +113,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -154,11 +154,19 @@ if $cygwin ; then
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
APP_ARGS=$(save "$@")
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
Vendored
+4 -10
View File
@@ -8,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_MC_HOME goto findJavaFromJavaHome
@@ -46,10 +46,9 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
Binary file not shown.
Binary file not shown.
View File
View File
Binary file not shown.
-1
View File
@@ -1 +0,0 @@
include ":ASMHelper"
+41 -29
View File
@@ -1,53 +1,65 @@
package com.backsun.lod;
import com.backsun.lod.proxy.ClientProxy;
import com.backsun.lod.proxy.CommonProxy;
import com.backsun.lod.util.Reference;
import com.backsun.lod.util.LodConfig;
import net.minecraft.client.Minecraft;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.Mod.Instance;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
/**
* Initialize and setup the Mod.
* <br>
* If you are looking for the real start of the mod
* check out the ClientProxy.
*
* @author James Seibel
* @version 02-07-2021
*/
@IFMLLoadingPlugin.MCVersion("1.12.2")
@IFMLLoadingPlugin.TransformerExclusions({"com.backsun.lod.asm"})
@Mod(modid = Reference.MOD_ID, name = Reference.NAME, version = Reference.VERSION, dependencies = "required-after:lodcore@[1.0,)")
@Mod(ModInfo.MODID)
public class LodMain
{
@Instance
public static LodMain instance;
@SidedProxy(clientSide = Reference.CLIENT_PROXY_CLASS, serverSide = Reference.COMMON_PROXY_CLASS)
public static CommonProxy common_proxy;
public static ClientProxy client_proxy;
@EventHandler
public static void PreInit(FMLPreInitializationEvent event)
private void init(final FMLCommonSetupEvent event)
{
Minecraft.getMinecraft().getFramebuffer().enableStencil();
Minecraft.getInstance().getFramebuffer().enableStencil();
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, LodConfig.clientSpec);
}
@EventHandler
public static void Init(FMLInitializationEvent event)
{
MinecraftForge.EVENT_BUS.register(common_proxy);
client_proxy = new ClientProxy();
}
@EventHandler
public static void PostInit(FMLPostInitializationEvent event)
{
}
public LodMain()
{
// Register the methods
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::init);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientStart);
// Register ourselves for server and other game events we are interested in
MinecraftForge.EVENT_BUS.register(this);
}
private void onClientStart(final FMLClientSetupEvent event)
{
client_proxy = new ClientProxy();
MinecraftForge.EVENT_BUS.register(client_proxy);
}
@SubscribeEvent
public void onServerStarting(FMLServerStartingEvent event)
{
// this is called when the server starts
}
}
@@ -0,0 +1,15 @@
package com.backsun.lod;
/**
* This file is similar to mcmod.info
*
* @author James Seibel
* @version 02-17-2021
*/
public final class ModInfo
{
public static final String MODID = "lod";
public static final String MODNAME = "Levels of Detail";
public static final String MODAPI = "LodAPI";
public static final String VERSION = "1.0";
}
@@ -0,0 +1,189 @@
package com.backsun.lod.builders;
import java.awt.Color;
import org.lwjgl.opengl.GL11;
import com.backsun.lod.objects.NearFarBuffer;
import com.backsun.lod.renderer.LodRenderer;
import com.backsun.lod.util.enums.FogDistance;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.util.math.AxisAlignedBB;
/**
* This object is used to create NearFarBuffer objects.
*
* @author James Seibel
* @version 02-27-2021
*/
public class LodBufferBuilder
{
public BufferBuilder nearBuffer;
public BufferBuilder farBuffer;
public FogDistance distanceMode;
public AxisAlignedBB[][] lods;
public Color[][] colors;
public LodBufferBuilder()
{
}
public NearFarBuffer createBuffers(
BufferBuilder newNearBufferBuilder, BufferBuilder newFarBufferBuilder,
FogDistance newDistanceMode,
AxisAlignedBB[][] newLods, Color[][] newColors)
{
nearBuffer = newNearBufferBuilder;
farBuffer = newFarBufferBuilder;
distanceMode = newDistanceMode;
lods = newLods;
colors = newColors;
nearBuffer.begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT);
farBuffer.begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT);
int numbChunksWide = lods.length;
BufferBuilder currentBuffer;
AxisAlignedBB bb;
int red;
int green;
int blue;
int alpha;
// x axis
for (int i = 0; i < numbChunksWide; i++)
{
// z axis
for (int j = 0; j < numbChunksWide; j++)
{
if (lods[i][j] == null || colors[i][j] == null)
continue;
bb = lods[i][j];
// get the color of this LOD object
red = colors[i][j].getRed();
green = colors[i][j].getGreen();
blue = colors[i][j].getBlue();
alpha = colors[i][j].getAlpha();
if (isCoordinateInNearFogArea(i, j, numbChunksWide / 2))
currentBuffer = nearBuffer;
else
currentBuffer = farBuffer;
if (bb.minY != bb.maxY)
{
// top (facing up)
addPosAndColor(currentBuffer, bb.minX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.maxY, bb.minZ, red, green, blue, alpha);
// bottom (facing down)
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
// south (facing -Z)
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
// north (facing +Z)
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
// west (facing -X)
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.maxY, bb.minZ, red, green, blue, alpha);
// east (facing +X)
addPosAndColor(currentBuffer, bb.maxX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
}
else
{
// render this LOD as one block thick
// top (facing up)
addPosAndColor(currentBuffer, bb.minX, bb.minY+1, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY+1, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY+1, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY+1, bb.minZ, red, green, blue, alpha);
// bottom (facing down)
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
// south (facing -Z)
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY+1, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY+1, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
// north (facing +Z)
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY+1, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY+1, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
// west (facing -X)
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY+1, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY+1, bb.minZ, red, green, blue, alpha);
// east (facing +X)
addPosAndColor(currentBuffer, bb.maxX, bb.minY+1, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY+1, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
}
} // z axis
} // x axis
nearBuffer.finishDrawing();
farBuffer.finishDrawing();
return new NearFarBuffer(nearBuffer, farBuffer);
}
private void addPosAndColor(BufferBuilder buffer, double x, double y, double z, int red, int green, int blue, int alpha)
{
buffer.pos(x, y, z).color(red, green, blue, alpha).endVertex();
}
/**
* Find the coordinates that are in the center half of the given
* 2D matrix, starting at (0,0) and going to (2 * lodRadius, 2 * lodRadius).
*/
private static boolean isCoordinateInNearFogArea(int chunkX, int chunkZ, int lodRadius)
{
int halfRadius = lodRadius / 2;
return (chunkX >= lodRadius - halfRadius
&& chunkX <= lodRadius + halfRadius)
&&
(chunkZ >= lodRadius - halfRadius
&& chunkZ <= lodRadius + halfRadius);
}
}
@@ -0,0 +1,124 @@
package com.backsun.lod.builders;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.backsun.lod.handlers.LodDimensionFileHandler;
import com.backsun.lod.objects.LodChunk;
import com.backsun.lod.objects.LodDimension;
import com.backsun.lod.objects.LodWorld;
import com.backsun.lod.util.LodUtils;
import net.minecraft.world.DimensionType;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkSection;
import net.minecraft.world.server.ServerWorld;
/**
* This object is in charge of creating Lod
* related objects.
* (specifically: Lod World, Dimension, Region, and Chunk objects)
*
* @author James Seibel
* @version 2-22-2021
*/
public class LodBuilder
{
private ExecutorService lodGenThreadPool = Executors.newSingleThreadExecutor();
public volatile LodWorld lodWorld;
/** Default size of any LOD regions we use */
public int regionWidth = 5;
public LodBuilder()
{
}
/**
* Returns LodWorld so that it can be passed
* to the LodRenderer.
*/
public LodWorld generateLodChunkAsync(Chunk chunk)
{
if (lodWorld != null)
// is this chunk from the same world as the lodWorld?
if (!lodWorld.worldName.equals(LodDimensionFileHandler.getCurrentWorldID()))
// we are not in the same world anymore,
// remove the old world so it can be recreated later
lodWorld = null;
// don't try to create an LOD object
// if for some reason we aren't
// given a valid chunk object
// (Minecraft often gives back empty
// or null chunks in this method)
if (chunk == null || !isValidChunk(chunk))
return lodWorld;
DimensionType dim = chunk.getWorld().getDimensionType();
ServerWorld world = LodUtils.getServerWorldFromDimension(dim);
if (world == null)
return lodWorld;
Thread thread = new Thread(() ->
{
try
{
LodChunk lod = new LodChunk(chunk, world);
LodDimension lodDim;
if (lodWorld == null)
{
lodWorld = new LodWorld(LodDimensionFileHandler.getCurrentWorldID());
}
if (lodWorld.getLodDimension(dim) == null)
{
lodDim = new LodDimension(dim, regionWidth);
lodWorld.addLodDimension(lodDim);
}
else
{
lodDim = lodWorld.getLodDimension(dim);
}
lodDim.addLod(lod);
}
catch(IllegalArgumentException | NullPointerException e)
{
// if the world changes while LODs are being generated
// they will throw errors as they try to access things that no longer
// exist.
}
});
lodGenThreadPool.execute(thread);
return lodWorld;
}
/**
* Return whether the given chunk
* has any data in it.
*/
public boolean isValidChunk(Chunk chunk)
{
ChunkSection[] blockStorage = chunk.getSections();
for(ChunkSection section : blockStorage)
{
if(section != null && !section.isEmpty())
{
return true;
}
}
return false;
}
}
@@ -1,4 +1,4 @@
package com.backsun.lod.util;
package com.backsun.lod.handlers;
import java.io.BufferedReader;
import java.io.File;
@@ -11,9 +11,11 @@ import java.util.concurrent.Executors;
import com.backsun.lod.objects.LodChunk;
import com.backsun.lod.objects.LodDimension;
import com.backsun.lod.objects.LodRegion;
import com.backsun.lod.util.LodUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.server.ServerChunkProvider;
import net.minecraft.world.server.ServerWorld;
/**
* This object handles creating LodRegions
@@ -23,36 +25,29 @@ import net.minecraft.world.storage.ISaveHandler;
* @author James Seibel
* @version 01-30-2021
*/
public class LodFileHandler
public class LodDimensionFileHandler
{
private LodDimension loadedRegion = null;
private LodDimension loadedDimension = null;
public long regionLastWriteTime[][];
// String s = Minecraft.getMinecraftDir().getCanonicalPath() + "/saves/" + world.getSaveHandler().getSaveDirectoryName() + "/data/AA/World" + world.provider.dimensionId + ".dat";
private String save_dir;
public ISaveHandler saveHandler;
private File dimensionDataSaveFolder;
private final String FILE_NAME_PREFIX = "lod";
private final String FILE_EXTENSION = ".txt";
private ExecutorService fileWritingThreadPool = Executors.newFixedThreadPool(1);
/** Is true if the readyToReadAndWrite is false */
private boolean waitingToSaveRegions = false;
public LodFileHandler(ISaveHandler newSaveHandler, LodDimension newLoadedRegion)
public LodDimensionFileHandler(File newSaveFolder, LodDimension newLoadedDimension)
{
saveHandler = newSaveHandler;
dimensionDataSaveFolder = newSaveFolder;
loadedRegion = newLoadedRegion;
loadedDimension = newLoadedDimension;
// these two variable are used in sync with the LodDimension
regionLastWriteTime = new long[loadedRegion.getWidth()][loadedRegion.getWidth()];
for(int i = 0; i < loadedRegion.getWidth(); i++)
for(int j = 0; j < loadedRegion.getWidth(); j++)
regionLastWriteTime = new long[loadedDimension.getWidth()][loadedDimension.getWidth()];
for(int i = 0; i < loadedDimension.getWidth(); i++)
for(int j = 0; j < loadedDimension.getWidth(); j++)
regionLastWriteTime[i][j] = -1;
if (saveHandler != null && saveHandler.getWorldDirectory() != null)
save_dir = getWorldSaveDirectory();
}
@@ -73,7 +68,7 @@ public class LodFileHandler
{
// we don't currently support reading or writing
// files when connected to a server
if (!Minecraft.getMinecraft().isIntegratedServerRunning())
if (!Minecraft.getInstance().isIntegratedServerRunning())
return null;
if (!readyToReadAndWrite())
@@ -141,73 +136,42 @@ public class LodFileHandler
// Save to File //
//==============//
public synchronized void saveDirtyRegionsToFile()
/**
* Save all dirty regions in this LodDimension to file.
*/
public synchronized void saveDirtyRegionsToFileAsync()
{
// we don't currently support reading or writing
// files when connected to a server
if (!Minecraft.getMinecraft().isIntegratedServerRunning())
if (!Minecraft.getInstance().isIntegratedServerRunning())
return;
if (!readyToReadAndWrite())
{
// we aren't ready to read and write yet
if(!waitingToSaveRegions)
{
waitingToSaveRegions = true;
// retry until we are able to read and write
// then wake up the fileWritingThreadPool
Thread retryReady = new Thread(() ->
{
try
{
// check once every so often so see
// if anything has changed so we can
// start reading and writing files
while(!readyToReadAndWrite())
{
this.wait(1000);
// get the save handler again, if for some
// reason the original handler was null
saveHandler = Minecraft.getMinecraft().getIntegratedServer().getWorld(0).getSaveHandler();
save_dir = getWorldSaveDirectory();
}
// we can start writing files now
fileWritingThreadPool.execute(saveDirtyRegionsThread);
waitingToSaveRegions = false;
}
catch (InterruptedException e)
{ /* should never be called */}
});
retryReady.run();
}
return;
}
fileWritingThreadPool.execute(saveDirtyRegionsThread);
}
private Thread saveDirtyRegionsThread = new Thread(() ->
{
for(int i = 0; i < loadedRegion.getWidth(); i++)
for(int i = 0; i < loadedDimension.getWidth(); i++)
{
for(int j = 0; j < loadedRegion.getWidth(); j++)
for(int j = 0; j < loadedDimension.getWidth(); j++)
{
if(loadedRegion.isRegionDirty[i][j])
if(loadedDimension.isRegionDirty[i][j])
{
saveRegionToDisk(loadedRegion.regions[i][j]);
loadedRegion.isRegionDirty[i][j] = false;
saveRegionToDisk(loadedDimension.regions[i][j]);
loadedDimension.isRegionDirty[i][j] = false;
}
}
}
waitingToSaveRegions = false;
});
/**
* Save a specific region to disk.<br>
* Note: it will save to the LodDimension that this
* handler is associated with.
*/
private void saveRegionToDisk(LodRegion region)
{
if (!readyToReadAndWrite() || region == null)
@@ -258,27 +222,37 @@ public class LodFileHandler
* Return the name of the file that should contain the
* region at the given x and z. <br>
* Returns null if this object isn't ready to read and write.
* @param regionX
* @param regionZ
*/
private String getFileNameForRegion(int regionX, int regionZ)
{
if (!readyToReadAndWrite())
return null;
return save_dir + "\\lod_data\\DIM" + loadedRegion.dimension.getId() + "\\" +
FILE_NAME_PREFIX + "." + regionX + "." + regionZ + FILE_EXTENSION;
try
{
// saveFolder is something like
// ".\Super Flat\DIM-1\data"
// or
// ".\Super Flat\data"
return dimensionDataSaveFolder.getCanonicalPath() + "\\lod\\" +
FILE_NAME_PREFIX + "." + regionX + "." + regionZ + FILE_EXTENSION;
}
catch(IOException e)
{
return null;
}
}
/**
* Returns if this FileHandler is ready to read
* and write files.
* <br>
* This returns true when the world save directory is known.
*/
public boolean readyToReadAndWrite()
{
return saveHandler != null && saveHandler.getWorldDirectory() != null &&
save_dir != null && !save_dir.isEmpty();
return dimensionDataSaveFolder != null;
}
@@ -289,13 +263,21 @@ public class LodFileHandler
* world, if in multiplayer it will return the server name
* and game version.
*/
public static String getWorldName()
public static String getCurrentWorldID()
{
Minecraft mc = Minecraft.getMinecraft();
Minecraft mc = Minecraft.getInstance();
if(mc.isIntegratedServerRunning())
{
return mc.getIntegratedServer().getWorldName();
ServerWorld serverWorld = LodUtils.getFirstValidServerWorld();
if (serverWorld == null)
return "";
ServerChunkProvider provider = serverWorld.getChunkProvider();
if(provider != null)
return provider.getSavedData().folder.toString();
return "";
}
else
{
@@ -304,19 +286,4 @@ public class LodFileHandler
}
/**
* Returns null if there was an IO Exception
*/
private String getWorldSaveDirectory()
{
try
{
return saveHandler.getWorldDirectory().getCanonicalPath();
}
catch (IOException e)
{
return null;
}
}
}
@@ -0,0 +1,99 @@
package com.backsun.lod.handlers;
import java.lang.reflect.Field;
import com.backsun.lod.util.enums.FogQuality;
import net.minecraft.client.Minecraft;
/**
* This object is used to get variables from methods
* where they are private. Specifically the fog setting
* in Optifine.
*
* @author James Seibel
* @version 09-21-2020
*/
public class ReflectionHandler
{
private Minecraft mc = Minecraft.getInstance();
public Field ofFogField = null;
public ReflectionHandler()
{
setupFogField();
}
/**
* Similar to setupFovMethod.
*/
private void setupFogField()
{
// get every variable from the entity renderer
Field[] vars = mc.gameSettings.getClass().getDeclaredFields();
// try and find the ofFogType variable in gameSettings
for(Field f : vars)
{
if(f.getName().equals("ofFogType"))
{
ofFogField = f;
return;
}
}
// we didn't find the field,
// either optifine isn't installed, or
// optifine changed the name of the variable
ofFogField = null;
}
/**
* Get what type of fog optifine is currently set to render.
*/
public FogQuality getFogQuality()
{
if (ofFogField == null)
{
// either optifine isn't installed,
// the variable name was changed, or
// the setup method wasn't called yet.
return FogQuality.FANCY;
}
int returnNum = 0;
try
{
returnNum = (int)ofFogField.get(mc.gameSettings);
}
catch (IllegalArgumentException | IllegalAccessException e)
{
e.printStackTrace();
}
switch (returnNum)
{
case 0:
return FogQuality.FAST;
case 1:
return FogQuality.FAST;
case 2:
return FogQuality.FANCY;
case 3:
return FogQuality.OFF;
default:
return FogQuality.FAST;
}
}
}
@@ -0,0 +1,22 @@
package com.backsun.lod.mixin;
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.backsun.lod.renderer.RenderGlobalHook;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.WorldRenderer;
@Mixin(WorldRenderer.class)
public class MixinWorldRenderer
{
@Inject(at = @At("HEAD"), method = "renderBlockLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/matrix/MatrixStack;DDD)V", cancellable = false)
private void renderBlockLayer(RenderType blockLayerIn, MatrixStack matrixStackIn, double xIn, double yIn, double zIn, CallbackInfo callback)
{
RenderGlobalHook.startRenderingStencil(blockLayerIn);
}
}
@@ -3,15 +3,15 @@ package com.backsun.lod.objects;
import java.awt.Color;
import com.backsun.lod.util.enums.ColorDirection;
import com.backsun.lod.util.enums.LodCorner;
import com.backsun.lod.util.enums.LodLocation;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.color.BlockColors;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.chunk.ChunkSection;
/**
* This object contains position
@@ -33,10 +33,6 @@ public class LodChunk
private static final int CHUNK_DATA_WIDTH = WIDTH;
private static final int CHUNK_DATA_HEIGHT = WIDTH;
private final int airBlockId = Block.getIdFromBlock(Block.getBlockFromName("air"));
private final int waterBlockId = Block.getIdFromBlock(Block.getBlockFromName("water"));
private final int waterColor = colorToInt(new Color(36, 50, 171));
/**
* This is how many blocks are
* required at a specific y-value
@@ -73,7 +69,7 @@ public class LodChunk
//==============//
/**
* Create an empty LodChunk
* Create an empty invisible LodChunk at (0,0)
*/
public LodChunk()
{
@@ -202,11 +198,11 @@ public class LodChunk
}
/**
* Illegal argument is thrown if either the
* chunk or world is null. The reason the world
* can't be null is because it's required to determine
* a block's color.
* @throws IllegalArgumentException
* Creates a LodChunk for a chunk in the given world. <br>
* Note: The world is required to determine each block's color
*
* @throws IllegalArgumentException
* thrown if either the chunk or world is null.
*/
public LodChunk(Chunk chunk, World world) throws IllegalArgumentException
{
@@ -220,8 +216,8 @@ public class LodChunk
}
x = chunk.x;
z = chunk.z;
x = chunk.getPos().x;
z = chunk.getPos().z;
top = new short[4];
bottom = new short[4];
@@ -230,14 +226,14 @@ public class LodChunk
// generate the top and bottom points of this LOD
for(LodLocation loc : LodLocation.values())
{
top[loc.value] = generateLodSection(chunk, true, loc);
bottom[loc.value] = generateLodSection(chunk, false, loc);
top[loc.value] = generateLodCorner(chunk, SectionGenerationMode.GENERATE_TOP, loc);
bottom[loc.value] = generateLodCorner(chunk, SectionGenerationMode.GENERATE_BOTTOM, loc);
}
// determine the average color for each direction
for(ColorDirection dir : ColorDirection.values())
{
colors[dir.value] = generateLodColorSection(chunk, world, dir);
colors[dir.value] = generateLodColorForDirection(chunk, world, dir);
}
}
@@ -253,15 +249,17 @@ public class LodChunk
/**
* Generate the height for the given LodLocation, either the top or bottom.
* <br><br>
* If invalid/null/empty chunks are given
* crashes may occur.
*/
public short generateLodSection(Chunk chunk, boolean getTopSection, LodLocation lodLoc)
public short generateLodCorner(Chunk chunk, SectionGenerationMode generationMode, LodLocation lodLoc)
{
// should have a length of 16
// (each storage is 16x16x16 and the
// world height is 256)
ExtendedBlockStorage[] data = chunk.getBlockStorageArray();
ChunkSection[] chunkSections = chunk.getSections();
@@ -313,21 +311,30 @@ public class LodChunk
}
if(getTopSection)
return determineTopPoint(data, startX, endX, startZ, endZ);
if(generationMode == SectionGenerationMode.GENERATE_TOP)
return determineTopPoint(chunkSections, startX, endX, startZ, endZ);
else
return determineBottomPoint(data, startX, endX, startZ, endZ);
return determineBottomPoint(chunkSections, startX, endX, startZ, endZ);
}
/** GENERATE_TOP, GENERATE_BOTTOM */
private enum SectionGenerationMode
{
GENERATE_TOP,
GENERATE_BOTTOM;
}
private short determineBottomPoint(ExtendedBlockStorage[] data, int startX, int endX, int startZ, int endZ)
/**
* Find the lowest valid point from the bottom.
*/
private short determineBottomPoint(ChunkSection[] chunkSections, int startX, int endX, int startZ, int endZ)
{
// search from the bottom up
for(int i = 0; i < data.length; i++)
for(int i = 0; i < chunkSections.length; i++)
{
for(int y = 0; y < CHUNK_DATA_HEIGHT; y++)
{
if(isLayerValidLodPoint(data, startX, endX, startZ, endZ, i, y))
if(isLayerValidLodPoint(chunkSections, startX, endX, startZ, endZ, i, y))
{
// we found
// enough blocks in this
@@ -335,23 +342,24 @@ public class LodChunk
// LOD point
return (short) (y + (i * CHUNK_DATA_HEIGHT));
}
} // y
} // data
}
}
// we never found a valid LOD point
return -1;
}
private short determineTopPoint(ExtendedBlockStorage[] data, int startX, int endX, int startZ, int endZ)
/**
* Find the highest valid point from the Top
*/
private short determineTopPoint(ChunkSection[] chunkSections, int startX, int endX, int startZ, int endZ)
{
// search from the top down
for(int i = data.length - 1; i >= 0; i--)
for(int i = chunkSections.length - 1; i >= 0; i--)
{
for(int y = CHUNK_DATA_WIDTH - 1; y >= 0; y--)
{
if(isLayerValidLodPoint(data, startX, endX, startZ, endZ, i, y))
if(isLayerValidLodPoint(chunkSections, startX, endX, startZ, endZ, i, y))
{
// we found
// enough blocks in this
@@ -359,10 +367,8 @@ public class LodChunk
// LOD point
return (short) (y + (i * CHUNK_DATA_HEIGHT));
}
} // y
} // data
}
}
// we never found a valid LOD point
return -1;
@@ -373,10 +379,10 @@ public class LodChunk
* values a valid LOD point?
*/
private boolean isLayerValidLodPoint(
ExtendedBlockStorage[] data,
ChunkSection[] chunkSections,
int startX, int endX,
int startZ, int endZ,
int dataIndex, int y)
int sectionIndex, int y)
{
// search through this layer
int layerBlocks = 0;
@@ -385,7 +391,7 @@ public class LodChunk
{
for(int z = startZ; z < endZ; z++)
{
if(data[dataIndex] == null)
if(chunkSections[sectionIndex] == null)
{
// this section doesn't have any blocks,
// it is not a valid section
@@ -393,7 +399,7 @@ public class LodChunk
}
else
{
if(data[dataIndex].get(x, y, z) != null && Block.getIdFromBlock(data[dataIndex].get(x, y, z).getBlock()) != airBlockId)
if(chunkSections[sectionIndex].getBlockState(x, y, z) != null && chunkSections[sectionIndex].getBlockState(x, y, z).getBlock() != Blocks.AIR)
{
// we found a valid block in
// in this layer
@@ -412,11 +418,13 @@ public class LodChunk
return false;
}
private Color generateLodColorSection(Chunk chunk, World world, ColorDirection colorDir)
/**
* Generate the color of the given ColorDirection at the given chunk
* in the given world.
*/
private Color generateLodColorForDirection(Chunk chunk, World world, ColorDirection colorDir)
{
Minecraft mc = Minecraft.getMinecraft();
Minecraft mc = Minecraft.getInstance();
BlockColors bc = mc.getBlockColors();
switch (colorDir)
@@ -441,11 +449,18 @@ public class LodChunk
}
/**
* Only accepts TOP and BOTTOM as ColorPositions
* Generates the color of the top or bottom of a given chunk in the given world.
*
* @throws IllegalArgumentException if given a ColorDirection other than TOP or BOTTOM
*/
private Color generateLodColorVertical(Chunk chunk, ColorDirection colorDir, World world, BlockColors bc)
{
ExtendedBlockStorage[] data = chunk.getBlockStorageArray();
if(colorDir != ColorDirection.TOP && colorDir != ColorDirection.BOTTOM)
{
throw new IllegalArgumentException("generateLodColorVertical only accepts the ColorDirection TOP or BOTTOM");
}
ChunkSection[] chunkSections = chunk.getSections();
int numbOfBlocks = 0;
int red = 0;
@@ -456,8 +471,8 @@ public class LodChunk
// either go top down or bottom up
int dataStart = goTopDown? data.length - 1 : 0;
int dataMax = data.length;
int dataStart = goTopDown? chunkSections.length - 1 : 0;
int dataMax = chunkSections.length;
int dataMin = 0;
int dataIncrement = goTopDown? -1 : 1;
@@ -472,18 +487,14 @@ public class LodChunk
{
boolean foundBlock = false;
for(int di = dataStart; !foundBlock && di >= dataMin && di < dataMax; di += dataIncrement)
for(int i = dataStart; !foundBlock && i >= dataMin && i < dataMax; i += dataIncrement)
{
if(!foundBlock && data[di] != null)
if(!foundBlock && chunkSections[i] != null)
{
for(int y = topStart; !foundBlock && y >= topMin && y < topMax; y += topIncrement)
{
int ci;
if(Block.getIdFromBlock(data[di].get(x, y, z).getBlock()) == waterBlockId)
// this is a special case since getColor on water generally returns white
ci = waterColor;
else
ci = bc.getColor(data[di].get(x, y, z), world, new BlockPos(x,y,z));
ci = chunkSections[i].getBlockState(x, y, z).materialColor.colorValue;
if(ci == 0)
{
@@ -519,10 +530,20 @@ public class LodChunk
return new Color(red, green, blue);
}
/**
* Generates the color of the side of a given chunk in the given world for the given ColorDirection.
*
* @throws IllegalArgumentException if given a ColorDirection other than N, S, W, E (North, South, East, West)
*/
private Color generateLodColorHorizontal(Chunk chunk, ColorDirection colorDir, World world, BlockColors bc)
{
ExtendedBlockStorage[] data = chunk.getBlockStorageArray();
if(colorDir != ColorDirection.N && colorDir != ColorDirection.S && colorDir != ColorDirection.E && colorDir != ColorDirection.W)
{
throw new IllegalArgumentException("generateLodColorHorizontal only accepts the ColorDirection N (North), S (South), E (East), or W (West)");
}
ChunkSection[] chunkSections = chunk.getSections();
int numbOfBlocks = 0;
int red = 0;
@@ -563,9 +584,9 @@ public class LodChunk
}
for (int di = 0; di < data.length; di++)
for (int i = 0; i < chunkSections.length; i++)
{
if (data[di] != null)
if (chunkSections[i] != null)
{
for (int y = 0; y < CHUNK_DATA_HEIGHT; y++)
{
@@ -607,11 +628,7 @@ public class LodChunk
}
int ci;
if(Block.getIdFromBlock(data[di].get(x, y, z).getBlock()) == waterBlockId)
// this is a special case since getColor on water generally returns white
ci = waterColor;
else
ci = bc.getColor(data[di].get(x, y, z), world, new BlockPos(x,y,z));
ci = chunkSections[i].getBlockState(x, y, z).getMaterial().getColor().colorValue;
if (ci == 0) {
// skip air or invisible blocks
@@ -663,6 +680,7 @@ public class LodChunk
/**
* Convert a Color into a BlockColors object.
*/
@SuppressWarnings("unused")
private int colorToInt(Color color)
{
return color.getRGB();
@@ -671,6 +689,30 @@ public class LodChunk
//================//
// misc functions //
//================//
/**
* If this LOD is either invisible from every
* direction or doesn't have a valid height
* it is empty.
*/
public boolean isLodEmpty()
{
for(LodCorner corner : LodCorner.values())
if(top[corner.value] != -1 || bottom[corner.value] != -1)
// at least one corner is valid
return false;
Color invisible = new Color(0,0,0,0);
for(ColorDirection dir : ColorDirection.values())
if(!colors[dir.value].equals(invisible))
// at least one direction has a non-invisible color
return false;
return true;
}
@@ -727,28 +769,7 @@ public class LodChunk
s += "x: " + x + " z: " + z + "\t";
// s += "top: ";
// for(int i = 0; i < top.length; i++)
// {
// s += top[i] + " ";
// }
// s += "\t";
// s += "bottom: ";
// for(int i = 0; i < bottom.length; i++)
// {
// s += bottom[i] + " ";
// }
// s += "\t";
// s += "colors ";
// for(int i = 0; i < colors.length; i++)
// {
// if(colors[i] != null)
// s += "(" + colors[i].getRed() + ", " + colors[i].getGreen() + ", " + colors[i].getBlue() + "), ";
// }
s += "(" + colors[ColorDirection.TOP.value].getRed() + ", " + colors[ColorDirection.TOP.value].getGreen() + ", " + colors[ColorDirection.TOP.value].getBlue() + "), ";
s += "(" + colors[ColorDirection.TOP.value].getRed() + ", " + colors[ColorDirection.TOP.value].getGreen() + ", " + colors[ColorDirection.TOP.value].getBlue() + ")";
return s;
}
@@ -1,22 +1,23 @@
package com.backsun.lod.objects;
import com.backsun.lod.util.LodFileHandler;
import com.backsun.lod.handlers.LodDimensionFileHandler;
import com.backsun.lod.util.LodUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.world.DimensionType;
import net.minecraft.world.server.ServerChunkProvider;
/**
* This object holds all loaded LOD regions
* for a given dimension.
*
* @author James Seibel
* @version 01-31-2021
* @version 02-23-2021
*/
public class LodDimension
{
public final DimensionType dimension;
private volatile int width; // if this ever changes make sure to update the halfWidth too
private volatile int width;
private volatile int halfWidth;
public LodRegion regions[][];
@@ -25,15 +26,16 @@ public class LodDimension
private int centerX;
private int centerZ;
private LodFileHandler rfHandler;
private LodDimensionFileHandler fileHandler;
public LodDimension(DimensionType newDimension, int newMaxWidth)
{
dimension = newDimension;
width = newMaxWidth;
// dimension 0 works here since we are just looking for the save handler anyway
rfHandler = new LodFileHandler(Minecraft.getMinecraft().getIntegratedServer().getWorld(0).getSaveHandler(), this);
ServerChunkProvider provider = LodUtils.getServerWorldFromDimension(newDimension).getChunkProvider();
fileHandler = new LodDimensionFileHandler(provider.getSavedData().folder, this);
regions = new LodRegion[width][width];
isRegionDirty = new boolean[width][width];
@@ -50,7 +52,10 @@ public class LodDimension
}
/**
* Move the center of this LodDimension and move all owned
* regions over by the given x and z offset.
*/
public void move(int xOffset, int zOffset)
{
// if the x or z offset is equal to or greater than
@@ -144,22 +149,16 @@ public class LodDimension
}
public int getCenterX()
{
return centerX;
}
public int getCenterZ()
{
return centerZ;
}
/**
* Gets the region at the given X and Z
* <br>
* Returns null if the region doesn't exist
* or is outside the loaded area.
*/
public LodRegion getRegion(int regionX, int regionZ)
{
int xIndex = (regionX - centerX) + halfWidth;
@@ -201,11 +200,15 @@ public class LodDimension
/**
* Add the given LOD to this dimension at the coordinate
* stored in the LOD. If an LOD already exists at the given
* coordinates it will be overwritten.
*/
public void addLod(LodChunk lod)
{
int regionX = (lod.x + centerX) / LodRegion.SIZE;
int regionZ = (lod.z + centerZ) / LodRegion.SIZE;
int regionX = lod.x / LodRegion.SIZE;
int regionZ = lod.z / LodRegion.SIZE;
// prevent issues if X/Z is negative and less than 16
if (lod.x < 0)
@@ -236,20 +239,20 @@ public class LodDimension
int xIndex = (regionX - centerX) + halfWidth;
int zIndex = (regionZ - centerZ) + halfWidth;
isRegionDirty[xIndex][zIndex] = true;
rfHandler.saveDirtyRegionsToFile();
fileHandler.saveDirtyRegionsToFileAsync();
}
/**
* Returns null if the LodChunk isn't loaded
* Get the LodChunk at the given X and Z coordinates
* in this dimension.
* <br>
* Returns null if the LodChunk doesn't exist or
* is outside the loaded area.
*/
public LodChunk getLodFromCoordinates(int chunkX, int chunkZ)
{
// (chunkX + centerX) % width
int regionX = (chunkX + centerX) / LodRegion.SIZE;
int regionZ = (chunkZ + centerZ) / LodRegion.SIZE;
int regionX = chunkX / LodRegion.SIZE;
int regionZ = chunkZ / LodRegion.SIZE;
// prevent issues if chunkX/Z is negative and less than width
if (chunkX < 0)
@@ -263,7 +266,6 @@ public class LodDimension
LodRegion region = getRegion(regionX, regionZ);
// TODO fix small render distances sometimes not having all regions loaded
if(region == null)
return null;
@@ -271,11 +273,13 @@ public class LodDimension
}
/**
* Get the region at the given X and Z coordinates from the
* RegionFileHandler.
*/
public LodRegion getRegionFromFile(int regionX, int regionZ)
{
return rfHandler.loadRegionFromFile(regionX, regionZ);
return fileHandler.loadRegionFromFile(regionX, regionZ);
}
@@ -293,6 +297,22 @@ public class LodDimension
public int getCenterX()
{
return centerX;
}
public int getCenterZ()
{
return centerZ;
}
public int getWidth()
{
return width;
@@ -311,6 +331,18 @@ public class LodDimension
for(int j = 0; j < width; j++)
isRegionDirty[i][j] = false;
}
@Override
public String toString()
{
String s = "";
s += "dim: " + dimension.toString() + "\t";
s += "(" + centerX + "," + centerZ + ")";
return s;
}
}
@@ -7,7 +7,7 @@ package com.backsun.lod.objects;
* one file in the file system.
*
* @author James Seibel
* @version 1-20-2021
* @version 1-22-2021
*/
public class LodRegion
{
@@ -31,6 +31,11 @@ public class LodRegion
}
/**
* Add the given LOD to this region at the coordinate
* stored in the LOD. If an LOD already exists at the given
* coordinates it will be overwritten.
*/
public void addLod(LodChunk lod)
{
// we use ABS since LODs can be negative, but if they are
@@ -43,6 +48,13 @@ public class LodRegion
chunks[xIndex][zIndex] = lod;
}
/**
* Get the LodChunk at the given X and Z coordinates
* in this region.
* <br>
* Returns null if the LodChunk doesn't exist or
* is outside the loaded area.
*/
public LodChunk getLod(int chunkX, int chunkZ)
{
// since we add LOD's with ABS, we get them the same way
@@ -56,7 +68,9 @@ public class LodRegion
}
/**
* Returns all LodChunks in this region
*/
public LodChunk[][] getAllLods()
{
return chunks;
@@ -1,14 +1,15 @@
package com.backsun.lod.objects;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Map;
import net.minecraft.world.DimensionType;
/**
* This stores all LODs for a given world.
*
* @author James Seibel
* @version 01-31-2021
* @version 02-22-2021
*/
public class LodWorld
{
@@ -17,33 +18,48 @@ public class LodWorld
/**
* Key = Dimension id (as an int)
*/
private Dictionary<Integer, LodDimension> lodDimensions;
private Map<DimensionType, LodDimension> lodDimensions;
public LodWorld(String newWorldName)
{
worldName = newWorldName;
lodDimensions = new Hashtable<Integer, LodDimension>();
lodDimensions = new Hashtable<DimensionType, LodDimension>();
}
public void addLodDimension(LodDimension newStorage)
{
lodDimensions.put(newStorage.dimension.getId(), newStorage);
lodDimensions.put(newStorage.dimension, newStorage);
}
public LodDimension getLodDimension(int dimensionId)
public LodDimension getLodDimension(DimensionType dimension)
{
return lodDimensions.get(dimensionId);
return lodDimensions.get(dimension);
}
/**
* Resizes the max width in regions that each LodDimension
* should use.
*/
public void resizeDimensionRegionWidth(int newWidth)
{
Enumeration<Integer> keys = lodDimensions.keys();
for(DimensionType key : lodDimensions.keySet())
lodDimensions.get(key).setRegionWidth(newWidth);
}
@Override
public String toString()
{
String s = "";
while(keys.hasMoreElements())
lodDimensions.get(keys.nextElement()).setRegionWidth(newWidth);
s += worldName + "\t - dimensions: ";
for(DimensionType key : lodDimensions.keySet())
s += lodDimensions.get(key).dimension.toString() + ", ";
return s;
}
}
@@ -1,6 +1,6 @@
package com.backsun.lod.renderer;
package com.backsun.lod.objects;
import java.nio.ByteBuffer;
import net.minecraft.client.renderer.BufferBuilder;
/**
* This object is just a replacement for an array
@@ -8,16 +8,16 @@ import java.nio.ByteBuffer;
* and BuildBufferThread.
*
* @author James Seibel
* @version 02-13-2021
* @version 02-21-2021
*/
public class NearFarBuffer
{
public ByteBuffer nearBuffer;
public BufferBuilder nearBuffer;
public ByteBuffer farBuffer;
public BufferBuilder farBuffer;
NearFarBuffer(ByteBuffer newNearBuffer, ByteBuffer newFarBuffer)
public NearFarBuffer(BufferBuilder newNearBuffer, BufferBuilder newFarBuffer)
{
nearBuffer = newNearBuffer;
farBuffer = newFarBuffer;
@@ -0,0 +1,28 @@
package com.backsun.lod.objects;
import com.backsun.lod.util.enums.FogDistance;
/**
* This object is just a replacement for an array
* to make things easier to understand in the LodRenderer.
*
* @author James Seibel
* @version 02-27-2021
*/
public class NearFarFogSetting
{
public FogDistance nearFogSetting = FogDistance.NEAR;
public FogDistance farFogSetting = FogDistance.FAR;
public NearFarFogSetting()
{
}
public NearFarFogSetting(FogDistance newNearFogSetting, FogDistance newFarFogSetting)
{
nearFogSetting = newNearFogSetting;
farFogSetting = newFarFogSetting;
}
}
@@ -1,51 +1,44 @@
package com.backsun.lod.proxy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.lwjgl.opengl.GL11;
import com.backsun.lod.builders.LodBuilder;
import com.backsun.lod.handlers.LodDimensionFileHandler;
import com.backsun.lod.objects.LodChunk;
import com.backsun.lod.objects.LodDimension;
import com.backsun.lod.objects.LodRegion;
import com.backsun.lod.objects.LodWorld;
import com.backsun.lod.renderer.LodRenderer;
import com.backsun.lod.renderer.RenderGlobalHook;
import com.backsun.lod.util.LodConfig;
import com.backsun.lod.util.LodFileHandler;
import com.backsun.lodCore.util.RenderGlobalHook;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.world.DimensionType;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.event.terraingen.PopulateChunkEvent;
import net.minecraftforge.event.world.ChunkEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
//TODO Find a way to replace getIntegratedServer so this mod could be used on non-local worlds.
// Minecraft.getMinecraft().getIntegratedServer()
/**
* This is used by the client.
* This handles all events sent to the client,
* and is the starting point for most of this program.
*
* @author James_Seibel
* @version 01-31-2021
* @version 02-23-2021
*/
public class ClientProxy extends CommonProxy
public class ClientProxy
{
private LodRenderer renderer;
private LodWorld lodWorld;
private ExecutorService lodGenThreadPool = Executors.newFixedThreadPool(1);
/** Default size of any LOD regions we use */
private int regionWidth = 5;
private LodBuilder lodBuilder;
Minecraft mc = Minecraft.getInstance();
public ClientProxy()
{
lodBuilder = new LodBuilder();
renderer = new LodRenderer();
}
@@ -61,37 +54,48 @@ public class ClientProxy extends CommonProxy
RenderGlobalHook.endRenderingStencil();
GL11.glStencilFunc(GL11.GL_EQUAL, 0, 0xFF);
if (LodConfig.drawLODs)
if (LodConfig.CLIENT.drawLODs.get())
renderLods(event.getPartialTicks());
GL11.glDisable(GL11.GL_STENCIL_TEST);
}
/**
* Do any setup that is required to draw LODs
* and then tell the LodRenderer to draw.
*/
public void renderLods(float partialTicks)
{
int newWidth = Math.max(4, (Minecraft.getMinecraft().gameSettings.renderDistanceChunks * LodChunk.WIDTH * 2) / LodRegion.SIZE);
if (lodWorld != null && regionWidth != newWidth)
// update the
int newWidth = Math.max(4, (mc.gameSettings.renderDistanceChunks * LodChunk.WIDTH * 2) / LodRegion.SIZE);
if (lodWorld != null && lodBuilder.regionWidth != newWidth)
{
lodWorld.resizeDimensionRegionWidth(newWidth);
regionWidth = newWidth;
lodBuilder.regionWidth = newWidth;
// skip this frame, hopefully the lodWorld
// should have everything set up by then
return;
}
Minecraft mc = Minecraft.getMinecraft();
// are we still in the same world?
if (!lodWorld.worldName.equals(LodDimensionFileHandler.getCurrentWorldID()))
// no, don't render the wrong world
return;
if (mc == null || mc.player == null || lodWorld == null)
return;
int dimId = mc.player.dimension;
LodDimension lodDim = lodWorld.getLodDimension(dimId);
LodDimension lodDim = lodWorld.getLodDimension(mc.player.world.getDimensionType());
if (lodDim == null)
return;
double playerX = mc.player.posX;
double playerZ = mc.player.posZ;
// offset the regions
double playerX = mc.player.getPosX();
double playerZ = mc.player.getPosZ();
int xOffset = ((int)playerX / (LodChunk.WIDTH * LodRegion.SIZE)) - lodDim.getCenterX();
int zOffset = ((int)playerZ / (LodChunk.WIDTH * LodRegion.SIZE)) - lodDim.getCenterZ();
@@ -102,154 +106,23 @@ public class ClientProxy extends CommonProxy
}
// we wait to create the renderer until the first frame
// to make sure that the EntityRenderer has
// been created, that way we can get the fovModifer
// method from it through reflection.
if (renderer == null)
{
renderer = new LodRenderer();
}
else
{
renderer.drawLODs(lodDim, partialTicks);
}
renderer.drawLODs(lodDim, partialTicks, mc.getProfiler());
}
//===============//
// update events //
//===============//
//=====================//
// lod creation events //
//=====================//
@SubscribeEvent
public void chunkLoadEvent(ChunkEvent event)
public void chunkLoadEvent(ChunkEvent.Load event)
{
generateLodChunk(event.getChunk());
}
/**
* this event is called whenever a chunk is created for the first time.
*/
@SubscribeEvent
public void onChunkPopulate(PopulateChunkEvent event)
{
Minecraft mc = Minecraft.getMinecraft();
if (mc != null && event != null)
{
WorldClient world = mc.world;
if(world != null)
{
generateLodChunk(world.getChunkFromChunkCoords(event.getChunkX(), event.getChunkZ()));
}
}
}
/*
*
Use this for generating chunks and maybe determining if they are loaded at all?
Could I create my own chunk generator and multithread it? It wouldn't save to the world, but could I save it for LODs?
chunk = Minecraft.getMinecraft().getIntegratedServer().getWorld(0).getChunkProvider().chunkGenerator.generateChunk(chunk.x, chunk.z);
System.out.println(chunk.x + " " + chunk.z + "\tloaded: " + chunk.isLoaded() + "\tpop: " + chunk.isPopulated() + "\tter pop: " + chunk.isTerrainPopulated());
*/
private void generateLodChunk(Chunk chunk)
{
Minecraft mc = Minecraft.getMinecraft();
// don't try to create an LOD object
// if for some reason we aren't
// given a valid chunk object
// (Minecraft often gives back empty
// or null chunks in this method)
if (chunk == null || !isValidChunk(chunk))
return;
int dimId = chunk.getWorld().provider.getDimension();
World world = mc.getIntegratedServer().getWorld(dimId);
if (world == null)
return;
Thread thread = new Thread(() ->
{
try
{
LodChunk lod = new LodChunk(chunk, world);
LodDimension lodDim;
if (lodWorld == null)
{
lodWorld = new LodWorld(LodFileHandler.getWorldName());
}
else
{
// if we have a lodWorld make sure
// it is for this minecraft world
if (!lodWorld.worldName.equals(LodFileHandler.getWorldName()))
{
// this lodWorld isn't for this minecraft world
// delete it so we can get a new one
lodWorld = null;
// skip this frame
// we'll get this set up next time
return;
}
}
if (lodWorld.getLodDimension(dimId) == null)
{
DimensionType dim = DimensionType.getById(dimId);
lodDim = new LodDimension(dim, regionWidth);
lodWorld.addLodDimension(lodDim);
}
else
{
lodDim = lodWorld.getLodDimension(dimId);
}
lodDim.addLod(lod);
}
catch(IllegalArgumentException | NullPointerException e)
{
// if the world changes while LODs are being generated
// they will throw errors as they try to access things that no longer
// exist.
}
});
lodGenThreadPool.execute(thread);
}
/**
* Return whether the given chunk
* has any data in it.
*/
private boolean isValidChunk(Chunk chunk)
{
ExtendedBlockStorage[] data = chunk.getBlockStorageArray();
for(ExtendedBlockStorage e : data)
{
if(e != null && !e.isEmpty())
{
return true;
}
}
return false;
if (event.getChunk().getClass() == Chunk.class)
lodWorld = lodBuilder.generateLodChunkAsync((Chunk) event.getChunk());
}
@@ -1,12 +0,0 @@
package com.backsun.lod.proxy;
/**
* This is used by the server.
*
* @author James_Seibel
* @version 08-31-2020
*/
public class CommonProxy
{
}
@@ -1,333 +0,0 @@
package com.backsun.lod.renderer;
import java.awt.Color;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.concurrent.Callable;
import com.backsun.lod.util.enums.FogDistance;
import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.MathHelper;
/**
*
*
* @author James Seibel
* @version 02-13-2021
*/
public class BuildBufferThread implements Callable<NearFarBuffer>
{
public ByteBuffer nearBuffer;
public ByteBuffer farBuffer;
public FogDistance distanceMode;
public AxisAlignedBB[][] lods;
public Color[][] colors;
private int start = 0;
private int end = -1;
private int vertexCount = 0;
private VertexFormat vertexFormat = null;
private int vertexFormatIndex = 0;
private VertexFormatElement vertexFormatElement = null;
BuildBufferThread()
{
vertexCount = 0;
vertexFormat = DefaultVertexFormats.POSITION_COLOR;
vertexFormatIndex = 0;
vertexFormatElement = vertexFormat.getElement(vertexFormatIndex);
}
BuildBufferThread(ByteBuffer newNearByteBuffer, ByteBuffer newFarByteBuffer, AxisAlignedBB[][] newLods, Color[][] newColors, FogDistance newDistanceMode, int threadNumber, int totalThreads)
{
setNewData(newNearByteBuffer, newFarByteBuffer, distanceMode, newLods, newColors, threadNumber, totalThreads);
vertexCount = 0;
vertexFormat = DefaultVertexFormats.POSITION_COLOR;
vertexFormatIndex = 0;
vertexFormatElement = vertexFormat.getElement(vertexFormatIndex);
}
public void setNewData(ByteBuffer newNearByteBuffer, ByteBuffer newFarByteBuffer, FogDistance newDistanceMode, AxisAlignedBB[][] newLods, Color[][] newColors, int threadNumber, int totalThreads)
{
vertexCount = 0;
vertexFormatIndex = 0;
nearBuffer = newNearByteBuffer;
farBuffer = newFarByteBuffer;
distanceMode = newDistanceMode;
lods = newLods;
colors = newColors;
int numbChunksWide = lods.length;
int rowsToRender = numbChunksWide / totalThreads;
start = threadNumber * rowsToRender;
end = (threadNumber + 1) * rowsToRender;
}
@Override
public NearFarBuffer call()
{
int numbChunksWide = lods.length;
ByteBuffer currentBuffer;
AxisAlignedBB bb;
int red;
int green;
int blue;
int alpha;
if (distanceMode == FogDistance.NEAR)
{
currentBuffer = nearBuffer;
}
else // if (distanceMode == FogDistance.FAR)
{
currentBuffer = farBuffer;
}
// x axis
for (int i = start; i < end; i++)
{
// z axis
for (int j = 0; j < numbChunksWide; j++)
{
if (lods[i][j] == null || colors[i][j] == null)
continue;
bb = lods[i][j];
// get the color of this LOD object
red = colors[i][j].getRed();
green = colors[i][j].getGreen();
blue = colors[i][j].getBlue();
alpha = colors[i][j].getAlpha();
// choose which buffer to add these LODs too
if (distanceMode == FogDistance.NEAR_AND_FAR)
{
if (RenderUtil.isCoordinateInNearFogArea(i, j, numbChunksWide / 2))
currentBuffer = nearBuffer;
else
currentBuffer = farBuffer;
}
if (bb.minY != bb.maxY)
{
// top (facing up)
addPosAndColor(currentBuffer, bb.minX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.maxY, bb.minZ, red, green, blue, alpha);
// bottom (facing down)
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
// south (facing -Z)
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
// north (facing +Z)
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
// west (facing -X)
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.maxY, bb.minZ, red, green, blue, alpha);
// east (facing +X)
addPosAndColor(currentBuffer, bb.maxX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
}
else
{
// render this LOD as one block thick
// top (facing up)
addPosAndColor(currentBuffer, bb.minX, bb.minY+1, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY+1, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY+1, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY+1, bb.minZ, red, green, blue, alpha);
// bottom (facing down)
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
// south (facing -Z)
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY+1, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY+1, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
// north (facing +Z)
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY+1, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY+1, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
// west (facing -X)
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY+1, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.minX, bb.minY+1, bb.minZ, red, green, blue, alpha);
// east (facing +X)
addPosAndColor(currentBuffer, bb.maxX, bb.minY+1, bb.minZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY+1, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(currentBuffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
}
} // z axis
} // x axis
return new NearFarBuffer(nearBuffer, farBuffer);
}
private void addPosAndColor(ByteBuffer buffer, double x, double y, double z, int red, int green, int blue, int alpha)
{
addPos(buffer, x, y, z);
addColor(buffer, red, green, blue, alpha);
endVertex();
}
private void addPos(ByteBuffer byteBuffer, double x, double y, double z)
{
int i = this.vertexCount * this.vertexFormat.getNextOffset() + this.vertexFormat.getOffset(this.vertexFormatIndex);
switch (this.vertexFormatElement.getType())
{
case FLOAT: // This is the one currently used
byteBuffer.putFloat(i, (float)(x));
byteBuffer.putFloat(i + 4, (float)(y));
byteBuffer.putFloat(i + 8, (float)(z));
break;
case UINT:
case INT:
byteBuffer.putInt(i, Float.floatToRawIntBits((float)(x)));
byteBuffer.putInt(i + 4, Float.floatToRawIntBits((float)(y)));
byteBuffer.putInt(i + 8, Float.floatToRawIntBits((float)(z)));
break;
case USHORT:
case SHORT:
byteBuffer.putShort(i, (short)((int)(x)));
byteBuffer.putShort(i + 2, (short)((int)(y)));
byteBuffer.putShort(i + 4, (short)((int)(z)));
break;
case UBYTE:
case BYTE:
byteBuffer.put(i, (byte)((int)(x)));
byteBuffer.put(i + 1, (byte)((int)(y)));
byteBuffer.put(i + 2, (byte)((int)(z)));
}
nextVertexFormatIndex();
}
private void addColor(ByteBuffer byteBuffer, int red, int green, int blue, int alpha)
{
int i = this.vertexCount * this.vertexFormat.getNextOffset() + this.vertexFormat.getOffset(this.vertexFormatIndex);
switch (this.vertexFormatElement.getType())
{
case FLOAT:
byteBuffer.putFloat(i, red / 255.0F);
byteBuffer.putFloat(i + 4, green / 255.0F);
byteBuffer.putFloat(i + 8, blue / 255.0F);
byteBuffer.putFloat(i + 12, alpha / 255.0F);
break;
case UINT:
case INT:
byteBuffer.putFloat(i, red);
byteBuffer.putFloat(i + 4, green);
byteBuffer.putFloat(i + 8, blue);
byteBuffer.putFloat(i + 12, alpha);
break;
case USHORT:
case SHORT:
byteBuffer.putShort(i, (short)red);
byteBuffer.putShort(i + 2, (short)green);
byteBuffer.putShort(i + 4, (short)blue);
byteBuffer.putShort(i + 6, (short)alpha);
break;
case UBYTE:
case BYTE:
if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN)
{
// this is the one used currently
byteBuffer.put(i, (byte)red);
byteBuffer.put(i + 1, (byte)green);
byteBuffer.put(i + 2, (byte)blue);
byteBuffer.put(i + 3, (byte)alpha);
}
else
{
byteBuffer.put(i, (byte)alpha);
byteBuffer.put(i + 1, (byte)blue);
byteBuffer.put(i + 2, (byte)green);
byteBuffer.put(i + 3, (byte)red);
}
}
nextVertexFormatIndex();
}
private void nextVertexFormatIndex()
{
++this.vertexFormatIndex;
this.vertexFormatIndex %= this.vertexFormat.getElementCount();
this.vertexFormatElement = this.vertexFormat.getElement(this.vertexFormatIndex);
if (this.vertexFormatElement.getUsage() == VertexFormatElement.EnumUsage.PADDING)
{
this.nextVertexFormatIndex();
}
}
private void endVertex()
{
++this.vertexCount;
growBuffer(this.vertexFormat.getNextOffset());
}
private void growBuffer(int p_181670_1_)
{
//if (MathHelper.roundUp(p_181670_1_, 4) / 4 > this.rawIntBuffer.remaining() || this.vertexCount * this.vertexFormat.getNextOffset() + p_181670_1_ > this.byteBuffer.capacity())
if (this.vertexCount * this.vertexFormat.getNextOffset() + p_181670_1_ > nearBuffer.capacity())
{
int i = nearBuffer.capacity();
int j = i + MathHelper.roundUp(p_181670_1_, 2097152);
// int k = this.rawIntBuffer.position();
ByteBuffer directBytebuffer = GLAllocation.createDirectByteBuffer(j);
nearBuffer.position(0);
directBytebuffer.put(nearBuffer);
directBytebuffer.rewind();
nearBuffer = directBytebuffer;
// this.rawFloatBuffer = buffer.asFloatBuffer().asReadOnlyBuffer();
// this.rawIntBuffer = buffer.asIntBuffer();
// this.rawIntBuffer.position(k);
// this.rawShortBuffer = buffer.asShortBuffer();
// this.rawShortBuffer.position(k << 1);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,82 @@
package com.backsun.lod.renderer;
import org.lwjgl.opengl.GL11;
import net.minecraft.client.renderer.RenderType;
/**
* This code is used for drawing
* to the stencil buffer.
*
* @author James Seibel
* @version 02-17-2021
*/
public class RenderGlobalHook
{
/**
* this variable should be the same as the method name below.
* It is used when transforming the RenderGlobal class'
* renderBlockLayer method.
*/
public static final String START_STENCIL_METHOD_NAME = "startRenderingStencil";
/**
* This method tells OpenGL to start drawing everything to the stencil.
* This is done to prevent LODs from being rendered on top of the world.
* <br><br>
* Called in the order (as of minecraft 1.16.4): <br>
* RenderType.getSolid() <br>
* RenderType.getCutoutMipped() <br>
* RenderType.getCutout() <br>
* RenderType.getTranslucent() <br>
* RenderType.getTripwire() <br>
*/
public static void startRenderingStencil(RenderType blockLayerIn)
{
// we only enable drawing to the stencil once since
// we want to skip the rendering of the out of world fog
// but catch everything else
if (blockLayerIn == RenderType.getSolid())
{
// solid is the first layer rendered
// clear the buffer so we can start fresh.
// if this isn't cleared first we will have overlap with the fog
// outside the world
GL11.glClearStencil(0);
GL11.glStencilMask(0x11111111);
GL11.glClear(GL11.GL_STENCIL_BUFFER_BIT);
GL11.glEnable(GL11.GL_STENCIL_TEST);
GL11.glStencilFunc(GL11.GL_ALWAYS, 1, 0x11111111);
GL11.glStencilMask(0b11111111);
GL11.glStencilOp(GL11.GL_KEEP, // this doesn't mater since GL_ALWAYS is being used
GL11.GL_KEEP, // stencil test passes
GL11.GL_REPLACE); // stencil + depth pass
}
}
/**
* this variable should be the same as the method name below.
* It is used when transforming the RenderGlobal class'
* renderBlockLayer method.
*/
public static final String END_STENCIL_METHOD_NAME = "endRenderingStencil";
/**
* Currently this method isn't used in any transformations since we end
* the stencil drawing in the ClientProxy right before we draw the LODs.
*/
public static void endRenderingStencil(RenderType blockLayerIn)
{
GL11.glStencilOp(GL11.GL_KEEP, // this doesn't mater since GL_ALWAYS is being used
GL11.GL_KEEP, // stencil test passes
GL11.GL_KEEP); // stencil + depth pass
}
public static void endRenderingStencil()
{
endRenderingStencil(null);
}
}
@@ -17,7 +17,7 @@ public class RenderUtil
*/
public static boolean isCoordinateInLoadedArea(int i, int j, int centerCoordinate)
{
Minecraft mc = Minecraft.getMinecraft();
Minecraft mc = Minecraft.getInstance();
return (i >= centerCoordinate - mc.gameSettings.renderDistanceChunks
&& i <= centerCoordinate + mc.gameSettings.renderDistanceChunks)
@@ -1,55 +1,105 @@
package com.backsun.lod.util;
import com.backsun.lod.util.enums.FogDistance;
import java.nio.file.Path;
import java.nio.file.Paths;
import net.minecraftforge.common.config.Config;
import net.minecraftforge.common.config.ConfigManager;
import net.minecraftforge.fml.client.event.ConfigChangedEvent;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import com.backsun.lod.ModInfo;
import com.backsun.lod.util.enums.FogDistance;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.electronwill.nightconfig.core.io.WritingMode;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.config.ModConfig;
/**
*
* @author James Seibel
* @version 02-14-2021
* @version 02-27-2021
*/
@Config(modid = Reference.MOD_ID)
@Mod.EventBusSubscriber
public class LodConfig
{
// save the config file when it is changed
@Mod.EventBusSubscriber(modid = Reference.MOD_ID)
private static class EventHandler
public static class Client
{
@SubscribeEvent
public static void onConfigChanged(final ConfigChangedEvent.OnConfigChangedEvent event)
public ForgeConfigSpec.BooleanValue drawLODs;
public ForgeConfigSpec.EnumValue<FogDistance> fogDistance;
public ForgeConfigSpec.BooleanValue drawCheckerBoard;
Client(ForgeConfigSpec.Builder builder)
{
if (event.getModID().equals(Reference.MOD_ID))
{
ConfigManager.sync(Reference.MOD_ID, Config.Type.INSTANCE);
}
}
builder.comment(ModInfo.MODNAME + " configuration settings").push("client");
drawLODs = builder
.comment("If false LODs will not be drawn, \n"
+ "however they will still be generated \n"
+ "and saved to file for later use.")
.define("drawLODs", true);
fogDistance = builder
.comment("\n"
+ "At what distance should Fog be drawn on the LODs? \n"
+ "If fog cuts off ubruptly or you are using Optifine's \"fast\" \n"
+ "fog option set this to " + FogDistance.NEAR.toString() + " or " + FogDistance.FAR.toString() + ".")
.defineEnum("fogDistance", FogDistance.NEAR_AND_FAR);
drawCheckerBoard = builder
.comment("\n"
+ "If false the LODs will draw with their normal world colors. \n"
+ "If true they will draw as a black and white checkerboard. \n"
+ "This can be used for debugging or imagining you are playing a \n"
+ "giant game of chess ;)")
.define("drawCheckerBoard", false);
builder.pop();
}
}
@Config.Comment(
{"Enable LODs",
"If true LODs will be drawn, if false LODs will "
+ "not be rendered. However they will "
+ "still be generated and stored in your world's save folder."})
public static boolean drawLODs = true;
@Config.Comment(
{"Fog Distance",
"What distance should Fog be drawn on the LODs?"})
public static FogDistance fogDistance = FogDistance.NEAR_AND_FAR;
@Config.Comment(
{"Draw Debugging Checkerboard",
"If false the LODs will draw with their normal world colors."
+ "If true they will draw as a black and white checkerboard."
+ "This can be used for debugging or imagining you are playing a "
+ "giant game of chess ;)"})
public static boolean drawCheckerBoard = false;
/**
* {@link Path} to the configuration file of this mod
*/
private static final Path CONFIG_PATH =
Paths.get("config", ModInfo.MODID + ".toml");
public static final ForgeConfigSpec clientSpec;
public static final Client CLIENT;
static {
final Pair<Client, ForgeConfigSpec> specPair = new ForgeConfigSpec.Builder().configure(Client::new);
clientSpec = specPair.getRight();
CLIENT = specPair.getLeft();
// setup the config file
CommentedFileConfig config = CommentedFileConfig.builder(CONFIG_PATH)
.writingMode(WritingMode.REPLACE)
.build();
config.load();
config.save();
clientSpec.setConfig(config);
}
@SubscribeEvent
public static void onLoad(final ModConfig.Loading configEvent)
{
LogManager.getLogger().debug(ModInfo.MODNAME, "Loaded forge config file {}", configEvent.getConfig().getFileName());
}
@SubscribeEvent
public static void onFileChange(final ModConfig.Reloading configEvent)
{
LogManager.getLogger().debug(ModInfo.MODNAME, "Forge config just got changed on the file system!");
}
}
@@ -0,0 +1,63 @@
package com.backsun.lod.util;
import net.minecraft.client.Minecraft;
import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.world.DimensionType;
import net.minecraft.world.server.ServerWorld;
/**
* This class holds methods that may be used in multiple places.
*
* @author James Seibel
* @version 02-26-2021
*/
public class LodUtils
{
private static Minecraft mc = Minecraft.getInstance();
/**
* Gets the first valid ServerWorld.
*
* @return null if there are no ServerWorlds
*/
public static ServerWorld getFirstValidServerWorld()
{
if (mc.getIntegratedServer() == null)
return null;
Iterable<ServerWorld> worlds = mc.getIntegratedServer().getWorlds();
for (ServerWorld world : worlds)
return world;
return null;
}
/**
* Gets the ServerWorld for the relevant dimension.
*
* @return null if there is no ServerWorld for the given dimension
*/
public static ServerWorld getServerWorldFromDimension(DimensionType dimension)
{
IntegratedServer server = mc.getIntegratedServer();
if (server == null)
return null;
Iterable<ServerWorld> worlds = server.getWorlds();
ServerWorld returnWorld = null;
for (ServerWorld world : worlds)
{
if(world.getDimensionType() == dimension)
{
returnWorld = world;
break;
}
}
return returnWorld;
}
}
@@ -1,6 +1,7 @@
package com.backsun.lod.util;
/**
* This holds meta information about the mod.
*
* @author James Seibel
* @version 04-16-2020
@@ -14,7 +15,7 @@ public class Reference
/** the mod's version */
public static final String VERSION = "1.0";
/** the version of minecraft this mod is built for */
public static final String ACCEPTED_VERSIONS = "[1.12.2]";
public static final String ACCEPTED_VERSIONS = "[1.16.4]";
/** where the client proxy class is */
public static final String CLIENT_PROXY_CLASS = "com.backsun.lod.proxy.ClientProxy";
@@ -1,9 +1,6 @@
package com.backsun.lod.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import com.backsun.lod.util.enums.FogQuality;
@@ -14,97 +11,27 @@ import net.minecraft.client.Minecraft;
* where they are private.
*
* @author James Seibel
* @version 09-21-2020
* @version 02-18-2021
*/
public class ReflectionHandler
{
public Method fovMethod = null;
private Minecraft mc = Minecraft.getInstance();
public Field ofFogField = null;
public ReflectionHandler()
{
setupFovMethod();
setupFogField();
}
/**
* This sets the "getFOVModifier" method from the
* minecraft "EntityRenderer" class, so that we can get
* the FOV of the player at any time.
*
* This is required since Minecraft is obfuscated so
* we can't just look for 'getFOVModifier'
* we have to search for it based on its parameters and
* return type; which luckily are unique in the EntityRenderer
* class.
*/
private void setupFovMethod()
{
// get every method from the entity renderer
Method[] methods = Minecraft.getMinecraft().entityRenderer.getClass().getDeclaredMethods();
Class<?> returnType;
Parameter[] params;
Method returnMethod = null;
for(Method m : methods)
{
returnType = m.getReturnType();
params = m.getParameters();
// see if this method has the same return type
// and parameters as the 'getFOVModifier' method.
if (returnType.equals(float.class) &&
params.length == 2 &&
params[0].getType().equals(float.class) &&
params[1].getType().equals(boolean.class))
{
// only accept the first method that we find
if (returnMethod == null)
{
returnMethod = m;
}
else
{
// we found a second method that matches the
// outline we were looking for,
// to prevent unexpected behavior
// dont't set fovMethod.
// Since we aren't sure that
// this method is the right
// one, we may accidently mess
// up the entityRender by invoking
// it and we probably wouldn't get
// the FOV from it anyway.
System.err.println("Error: a second method that matches the parameters and return typ of 'getFOVModifier' was found, LODs won't be rendered.");
return;
}
}
}
// only set the method once we have gone through
// the whole array of methods, just to
// make sure we have the right one.
fovMethod = returnMethod;
// set up the method so we can invoke it later
fovMethod.setAccessible(true);
}
/**
* Similar to setupFovMethod.
*/
private void setupFogField()
{
// get every variable from the entity renderer
Field[] vars = Minecraft.getMinecraft().gameSettings.getClass().getDeclaredFields();
Field[] vars = mc.gameSettings.getClass().getDeclaredFields();
// try and find the ofFogType variable in gameSettings
for(Field f : vars)
@@ -143,7 +70,7 @@ public class ReflectionHandler
try
{
returnNum = (int)ofFogField.get(Minecraft.getMinecraft().gameSettings);
returnNum = (int)ofFogField.get(mc.gameSettings);
}
catch (IllegalArgumentException | IllegalAccessException e)
{
@@ -166,22 +93,4 @@ public class ReflectionHandler
}
}
/**
* Gets the FOV used by the EntityRender.
*/
public float getFov(Minecraft mc, float partialTicks, boolean useFovSetting)
{
try
{
return (float)fovMethod.invoke(mc.entityRenderer, new Object[]{partialTicks, useFovSetting});
}
catch(InvocationTargetException | IllegalAccessException | IllegalArgumentException e)
{
e.printStackTrace();
}
return 0.0f;
}
}
@@ -1,10 +1,10 @@
package com.backsun.lod.util.enums;
/**
* TOP, N, S, E, W, BOTTOM
*
* @author James Seibel
* @version 10-17-2020
*
* TOP, N, S, E, W, BOTTOM
*/
public enum ColorDirection
{
@@ -8,9 +8,9 @@ package com.backsun.lod.util.enums;
*/
public enum FogDistance
{
/** valid for both fast and fancy fog qualities. */
/** good for fast or fancy fog qualities. */
NEAR,
/** valid for both fast and fancy fog qualities. */
/** good for fast or fancy fog qualities. */
FAR,
/** only looks good if the fog quality is set to Fancy. */
NEAR_AND_FAR;
@@ -0,0 +1,28 @@
package com.backsun.lod.util.enums;
/**
* NE, SE, SW, NW
*
* @author James Seibel
* @version 1-20-2020
*/
public enum LodCorner
{
// used for position
/** -Z, +X */
NE(0),
/** +Z, +X */
SE(1),
/** +Z, -X */
SW(2),
/** -Z, -X */
NW(3);
public final int value;
private LodCorner(int newValue)
{
value = newValue;
}
}
@@ -0,0 +1,48 @@
# Note: to update code in eclipse run the "eclipse" command in graldew
# make public the method getFOVModifier
public net.minecraft.client.renderer.GameRenderer func_215311_a(Lnet/minecraft/client/renderer/ActiveRenderInfo;FZ)D # getFOVModifier
# make public the byteBuffer in BufferBuilder
public net.minecraft.client.renderer.BufferBuilder field_179001_a # byteBuffer
# make public the cameraZoom in the GameRenderer
public net.minecraft.client.renderer.GameRenderer field_78503_V # cameraZoom
# make public the cameraYaw in the GameRenderer
public net.minecraft.client.renderer.GameRenderer field_228376_w_ # cameraYaw
# make public the cameraPitch in the GameRenderer
public net.minecraft.client.renderer.GameRenderer field_228377_x_ # cameraPitch
# make public the folder in the DimensionSavedDataManager
public net.minecraft.world.storage.DimensionSavedDataManager field_215759_d # folder
# make public the ambiantLight field in DimensionType
public net.minecraft.world.DimensionType field_236017_x_ # ambientLight
# make public the renderUpdateCount in GameRenderer
public net.minecraft.client.renderer.GameRenderer field_78529_t # rendererUpdateCount
# make public the materialColor in AbstractBlockState
public net.minecraft.block.AbstractBlock$AbstractBlockState field_235704_h_ # materialColor
#=====================#
# Examples from Forge #
#=====================#
# Makes public the IScreenFactory class in ScreenManager
public net.minecraft.client.gui.ScreenManager$IScreenFactory
# Makes protected and removes the final modifier from 'random' in MinecraftServer
protected-f net.minecraft.server.MinecraftServer field_147146_q #random
# Makes public the 'createNamedService' method in Util,
# accepting a String and returns an ExecutorService
public net.minecraft.util.Util func_240979_a_(Ljava/lang/String;)Ljava/util/concurrent/ExecutorService; #createNamedService
# Makes public the 'func_239776_a_' method in UUIDCodec,
# accepting two longs and returning an int[]
public net.minecraft.util.UUIDCodec func_239776_a_(JJ)[I #func_239776_a_
+50
View File
@@ -0,0 +1,50 @@
#// This is an example mods.toml file. It contains the data relating to the loading mods.
#// There are several mandatory fields (#mandatory), and many more that are optional (#optional).
#// The overall format is standard TOML format, v0.5.0.
#// Note that there are a couple of TOML lists in this file.
#// Find more information on toml format here: https://github.com/toml-lang/toml
#// The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
modLoader="javafml" #mandatory
#// A version range to match for said mod loader - for regular FML @Mod it will be the forge version
loaderVersion="[35,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions.
#// The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties.
#// Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here.
license="All rights reserved"
#// A URL to refer people to when problems occur with this mod
#//issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional
#// A list of mods - how many allowed here is determined by the individual mod loader
[[mods]] #mandatory
#// The modid of the mod
modId="lod" #mandatory
#// The version number of the mod - there's a few well known ${} variables useable here or just hardcode it
#//${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata
#// see the associated build.gradle script for how to populate this completely automatically during a build
version="a1" #mandatory
#// A display name for the mod
displayName="Levels of Detail" #mandatory
#// A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/
#//updateJSONURL="https://change.me.example.invalid/updates.json" #optional
#// A URL for the "homepage" for this mod, displayed in the mod UI
#//displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional
#// A file name (in the root of the mod JAR) containing a logo for display
#//logoFile="examplemod.png" #optional
#// A text field displayed in the mod UI
credits="TechnoVision, Vike, and Darkhax for their modding tutorials." #optional
#// A text field displayed in the mod UI
authors="James Seibel" #optional
#// The description text for the mod (multi line!) (#mandatory)
description='''
This mod generates and renders simplified chunks beyond the normal view distance, at a low performance cost.
'''
+10
View File
@@ -0,0 +1,10 @@
{
"required": true,
"package": "com.backsun.lod.mixin",
"compatibilityLevel": "JAVA_8",
"refmap": "lod.refmap.json",
"mixins": [
"MixinWorldRenderer"
],
"minVersion": "0.8"
}
+4 -4
View File
@@ -3,14 +3,14 @@
"modid": "lod",
"name": "Level Of Details",
"description": "Generates and renders simplified chunks beyond the normal view distance, at a low performance cost.",
"version": "0.1",
"mcversion": "1.12.2",
"version": "a1",
"mcversion": "1.16.4",
"url": "",
"updateUrl": "",
"authorList": ["James Seibel"],
"credits": "TechnoVision and Vike for their modding tutorials.",
"credits": "TechnoVision, Vike, and Darkhax for their modding tutorials.",
"logoFile": "",
"screenshots": [],
"dependencies": ["lodcore"]
"dependencies": []
}
]
+2 -2
View File
@@ -1,7 +1,7 @@
{
"pack": {
"description": "examplemod resources",
"pack_format": 3,
"_comment": "A pack_format of 3 should be used starting with Minecraft 1.11. All resources, including language files, should be lowercase (eg: en_us.lang). A pack_format of 2 will load your mod resources with LegacyV2Adapter, which requires language files to have uppercase letters (eg: en_US.lang)."
"pack_format": 6,
"_comment": "A pack_format of 6 requires json lang files and some texture changes from 1.16.2. Note: we require v6 pack meta for all mods."
}
}