Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ad8d824bd | |||
| 53ee2123c1 | |||
| fe3ace7d35 | |||
| 4d4dff2373 | |||
| f388911468 | |||
| 9704ad80f1 | |||
| 026d9a425e | |||
| 85bff28758 | |||
| 213060d473 | |||
| ca400ccf59 | |||
| 9dc6d17d7b | |||
| 15d3af3c66 | |||
| d9d1c4dfaf | |||
| 1c2974cf6a | |||
| c353335968 | |||
| 2ee76a413f | |||
| 7b074fc155 | |||
| 28220f62ad | |||
| cc7e4359ec | |||
| 72a292aeb6 | |||
| ca8f63cf7d | |||
| 4f518a0701 | |||
| b81253af67 | |||
| fd3d4e92af | |||
| 7418a196a9 |
@@ -0,0 +1 @@
|
|||||||
|
<factorypath />
|
||||||
+2
-1
@@ -23,4 +23,5 @@ eclipse
|
|||||||
# minecraft run folder,
|
# minecraft run folder,
|
||||||
# ignore everything but the mods folder
|
# ignore everything but the mods folder
|
||||||
run/*
|
run/*
|
||||||
!run/mods
|
!run/mods
|
||||||
|
/Users/
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
[submodule "ASMHelper"]
|
|
||||||
path = ASMHelper
|
|
||||||
url = https://github.com/squeek502/ASMHelper.git
|
|
||||||
branch = 1.12.x
|
|
||||||
Binary file not shown.
+16
-6
@@ -1,7 +1,17 @@
|
|||||||
This program is an attempt to create Level Of Details (LODs) in Minecraft.
|
This program is an attempt to implement a Level Of Detail system for Minecraft.
|
||||||
The purpose is to increase the maximum view distance in game
|
With the purpose of increasing the maximum view distance in game without harming performance.
|
||||||
|
|
||||||
Used in congunction with:
|
Forge version: 1.12.2-14.23.5.2854
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
This version will run in eclipse perfectly fine, but will crash retail Minecraft.
|
||||||
|
(However this appears to be because of an incompatible update to the core mod.)
|
||||||
|
This version also doesn't work with Optifine at all.
|
||||||
|
(Attempting to run with Optifine in either eclipse or retail Minecraft
|
||||||
|
will either prevent the game from launching at all or crash during loading.)
|
||||||
|
|
||||||
|
|
||||||
|
Used in conjunction with:
|
||||||
https://gitlab.com/jeseibel/minecraft-lod-core-mod
|
https://gitlab.com/jeseibel/minecraft-lod-core-mod
|
||||||
|
|
||||||
|
|
||||||
@@ -14,18 +24,18 @@ http://mcforge.readthedocs.io/en/latest/gettingstarted/
|
|||||||
|
|
||||||
Step 1: open a command line in the project folder
|
Step 1: open a command line in the project folder
|
||||||
|
|
||||||
Step 2: run the command: "./gradlew setupDecompWorkspace"
|
Step 2: run the command: "./gradlew genEclipseRuns"
|
||||||
|
|
||||||
Step 3: run the command: "./gradlew eclipse"
|
Step 3: run the command: "./gradlew eclipse"
|
||||||
|
|
||||||
Step 4: Import project
|
Step 4: Import project
|
||||||
|
|
||||||
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)
|
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.
|
And make sure it is used in the gradle.bat file.
|
||||||
|
|
||||||
Step 6: Import the lodcore and lodcore_source jar files into the referenced libraries.
|
Step 6: Import the lodcore and lodcore_source jar files into the referenced libraries.
|
||||||
|
|
||||||
Step 6: Make sure the eclipse has the JDK 1.8.0_251 installed. (This is needed so that eclipse can run minecraft)
|
Step 7: Make sure the eclipse has the JDK 1.8.0_251 installed. (This is needed so that eclipse can run minecraft)
|
||||||
|
|
||||||
|
|
||||||
Other commands:
|
Other commands:
|
||||||
|
|||||||
+52
-42
@@ -1,77 +1,87 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
|
maven { url = 'https://files.minecraftforge.net/maven' }
|
||||||
jcenter()
|
jcenter()
|
||||||
maven { url = "https://files.minecraftforge.net/maven" }
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
|
classpath 'net.minecraftforge.gradle:ForgeGradle:3.+'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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'
|
||||||
|
// 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 = "1.0"
|
version = "1.0"
|
||||||
group = "com.backsun.lod" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
group = "com.backsun.lod" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||||
archivesBaseName = "lod"
|
archivesBaseName = "lod"
|
||||||
|
|
||||||
sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
|
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
|
||||||
compileJava {
|
|
||||||
sourceCompatibility = targetCompatibility = '1.8'
|
|
||||||
}
|
|
||||||
|
|
||||||
minecraft {
|
minecraft {
|
||||||
version = "1.12.2-14.23.5.2847"
|
// The mappings can be changed at any time, and must be in the following format.
|
||||||
runDir = "run"
|
// 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.
|
// 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.
|
// Simply re-run your setup task after changing the mappings to update your workspace.
|
||||||
mappings = "snapshot_20171003"
|
//mappings channel: 'snapshot', version: '20171003-1.12'
|
||||||
|
mappings channel: 'snapshot', version: '20171003-1.12'
|
||||||
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
|
// 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')
|
||||||
|
|
||||||
|
// 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'
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
|
||||||
|
// 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'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// you may put jars on which you depend on in ./libs
|
// Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed
|
||||||
// or you may define them like so..
|
// 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.12.2-14.23.5.2854'
|
||||||
|
|
||||||
|
compile fileTree(dir: 'libs', include: '*.jar')
|
||||||
|
|
||||||
|
// 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:classifier"
|
||||||
//compile "some.group:artifact:version"
|
//compile "some.group:artifact:version"
|
||||||
|
|
||||||
// real examples
|
// Real examples
|
||||||
//compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
|
//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
|
//compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
|
||||||
|
|
||||||
// the 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
|
// 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'
|
//provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
||||||
|
|
||||||
// the deobf configurations: 'deobfCompile' and 'deobfProvided' are the same as the normal compile and provided,
|
// These dependencies get remapped to your current MCP mappings
|
||||||
// except that these dependencies get remapped to your current MCP mappings
|
// deobf 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
||||||
//deobfCompile 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
|
||||||
//deobfProvided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
//deobfProvided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
||||||
|
|
||||||
// for more info...
|
// For more info...
|
||||||
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
|
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
|
||||||
// http://www.gradle.org/docs/current/userguide/dependency_management.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'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
|
# 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.
|
# This is required to provide enough memory for the Minecraft decompilation process.
|
||||||
org.gradle.jvmargs=-Xmx3G
|
org.gradle.jvmargs=-Xmx3G
|
||||||
|
org.gradle.daemon=false
|
||||||
Vendored
BIN
Binary file not shown.
+1
-2
@@ -1,6 +1,5 @@
|
|||||||
#Mon Sep 14 12:28:28 PDT 2015
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
|
||||||
|
|||||||
@@ -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
|
# Attempt to set APP_HOME
|
||||||
# Resolve links: $0 may be a link
|
# Resolve links: $0 may be a link
|
||||||
PRG="$0"
|
PRG="$0"
|
||||||
@@ -61,9 +20,49 @@ while [ -h "$PRG" ] ; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
SAVED="`pwd`"
|
SAVED="`pwd`"
|
||||||
cd "`dirname \"$PRG\"`/" >&-
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
APP_HOME="`pwd -P`"
|
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
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
@@ -90,7 +89,7 @@ location of your Java installation."
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# 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`
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
if [ $? -eq 0 ] ; then
|
if [ $? -eq 0 ] ; then
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
@@ -114,6 +113,7 @@ fi
|
|||||||
if $cygwin ; then
|
if $cygwin ; then
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
@@ -154,11 +154,19 @@ if $cygwin ; then
|
|||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
# Escape application args
|
||||||
function splitJvmOpts() {
|
save () {
|
||||||
JVM_OPTS=("$@")
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
}
|
}
|
||||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
APP_ARGS=$(save "$@")
|
||||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
|
||||||
|
|
||||||
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
@@ -8,14 +8,14 @@
|
|||||||
@rem Set local scope for the variables with windows NT shell
|
@rem Set local scope for the variables with windows NT shell
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
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
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
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
|
@rem Find java.exe
|
||||||
if defined JAVA_MC_HOME goto findJavaFromJavaHome
|
if defined JAVA_MC_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
@@ -46,10 +46,9 @@ echo location of your Java installation.
|
|||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:init
|
: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 not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
|
||||||
|
|
||||||
:win9xME_args
|
:win9xME_args
|
||||||
@rem Slurp the command line arguments.
|
@rem Slurp the command line arguments.
|
||||||
@@ -60,11 +59,6 @@ set _SKIP=2
|
|||||||
if "x%~1" == "x" goto execute
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
set CMD_LINE_ARGS=%*
|
||||||
goto execute
|
|
||||||
|
|
||||||
:4NT_args
|
|
||||||
@rem Get arguments from the 4NT Shell from JP Software
|
|
||||||
set CMD_LINE_ARGS=%$
|
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
include ":ASMHelper"
|
|
||||||
@@ -16,6 +16,10 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
|||||||
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
|
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Initialize and setup the Mod.
|
||||||
|
* <br>
|
||||||
|
* If you are looking for the real start of the mod
|
||||||
|
* check out the ClientProxy.
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 02-07-2021
|
* @version 02-07-2021
|
||||||
|
|||||||
@@ -0,0 +1,223 @@
|
|||||||
|
package com.backsun.lod.builders;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
import com.backsun.lod.objects.NearFarBuffer;
|
||||||
|
import com.backsun.lod.util.enums.FogDistance;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.BufferBuilder;
|
||||||
|
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||||
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is used to create NearFarBuffer objects
|
||||||
|
* in a thread independent way, so multiple of these objects can be
|
||||||
|
* created and executed in parallel to populate BufferBuilders.
|
||||||
|
*
|
||||||
|
* @author James Seibel
|
||||||
|
* @version 02-23-2021
|
||||||
|
*/
|
||||||
|
public class BuildBufferThread implements Callable<NearFarBuffer>
|
||||||
|
{
|
||||||
|
public BufferBuilder nearBuffer;
|
||||||
|
public BufferBuilder farBuffer;
|
||||||
|
public FogDistance distanceMode;
|
||||||
|
public AxisAlignedBB[][] lods;
|
||||||
|
public Color[][] colors;
|
||||||
|
|
||||||
|
private int startLodIndex = 0;
|
||||||
|
private int endLodIndex = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public BuildBufferThread()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public BuildBufferThread(BufferBuilder newNearBufferBuilder,
|
||||||
|
BufferBuilder newFarBufferBuilder, AxisAlignedBB[][] newLods,
|
||||||
|
Color[][] newColors, FogDistance newDistanceMode, int newStartingIndex,
|
||||||
|
int numberOfRowsToGenerate)
|
||||||
|
{
|
||||||
|
setNewData(newNearBufferBuilder, newFarBufferBuilder, distanceMode,
|
||||||
|
newLods, newColors, newStartingIndex, numberOfRowsToGenerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNewData(BufferBuilder newNearBufferBuilder,
|
||||||
|
BufferBuilder newFarBufferBuilder, FogDistance newDistanceMode,
|
||||||
|
AxisAlignedBB[][] newLods, Color[][] newColors,
|
||||||
|
int newStartingIndex, int numberOfRowsToGenerate)
|
||||||
|
{
|
||||||
|
nearBuffer = newNearBufferBuilder;
|
||||||
|
farBuffer = newFarBufferBuilder;
|
||||||
|
distanceMode = newDistanceMode;
|
||||||
|
lods = newLods;
|
||||||
|
colors = newColors;
|
||||||
|
|
||||||
|
startLodIndex = newStartingIndex;
|
||||||
|
endLodIndex = newStartingIndex + numberOfRowsToGenerate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NearFarBuffer call()
|
||||||
|
{
|
||||||
|
nearBuffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
|
||||||
|
farBuffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
|
||||||
|
|
||||||
|
int numbChunksWide = lods.length;
|
||||||
|
|
||||||
|
BufferBuilder currentBuffer;
|
||||||
|
AxisAlignedBB bb;
|
||||||
|
int red;
|
||||||
|
int green;
|
||||||
|
int blue;
|
||||||
|
int alpha;
|
||||||
|
|
||||||
|
// this is done if the FogDistance is either
|
||||||
|
// NEAR or FAR, if it is NEAR_AND_FAR
|
||||||
|
// the buffer is determined for each LOD
|
||||||
|
if (distanceMode == FogDistance.NEAR)
|
||||||
|
{
|
||||||
|
currentBuffer = nearBuffer;
|
||||||
|
}
|
||||||
|
else // if (distanceMode == FogDistance.FAR)
|
||||||
|
{
|
||||||
|
currentBuffer = farBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// x axis
|
||||||
|
for (int i = startLodIndex; i < endLodIndex; 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 (distanceMode == FogDistance.NEAR_AND_FAR)
|
||||||
|
{
|
||||||
|
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,133 @@
|
|||||||
|
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 net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.world.DimensionType;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.chunk.Chunk;
|
||||||
|
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
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 lodWorld;
|
||||||
|
|
||||||
|
int dimId = chunk.getWorld().provider.getDimension();
|
||||||
|
World world = mc.getIntegratedServer().getWorld(dimId);
|
||||||
|
|
||||||
|
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.getWorldName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if we have a lodWorld make sure
|
||||||
|
// it is for this minecraft world
|
||||||
|
if (!lodWorld.worldName.equals(LodDimensionFileHandler.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 lodWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the given chunk
|
||||||
|
* has any data in it.
|
||||||
|
*/
|
||||||
|
public boolean isValidChunk(Chunk chunk)
|
||||||
|
{
|
||||||
|
ExtendedBlockStorage[] blockStorage = chunk.getBlockStorageArray();
|
||||||
|
|
||||||
|
for(ExtendedBlockStorage e : blockStorage)
|
||||||
|
{
|
||||||
|
if(e != null && !e.isEmpty())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
-58
@@ -1,4 +1,4 @@
|
|||||||
package com.backsun.lod.util;
|
package com.backsun.lod.handlers;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -23,9 +23,9 @@ import net.minecraft.world.storage.ISaveHandler;
|
|||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 01-30-2021
|
* @version 01-30-2021
|
||||||
*/
|
*/
|
||||||
public class LodFileHandler
|
public class LodDimensionFileHandler
|
||||||
{
|
{
|
||||||
private LodDimension loadedRegion = null;
|
private LodDimension loadedDimension = null;
|
||||||
public long regionLastWriteTime[][];
|
public long regionLastWriteTime[][];
|
||||||
|
|
||||||
// String s = Minecraft.getMinecraftDir().getCanonicalPath() + "/saves/" + world.getSaveHandler().getSaveDirectoryName() + "/data/AA/World" + world.provider.dimensionId + ".dat";
|
// String s = Minecraft.getMinecraftDir().getCanonicalPath() + "/saves/" + world.getSaveHandler().getSaveDirectoryName() + "/data/AA/World" + world.provider.dimensionId + ".dat";
|
||||||
@@ -36,19 +36,17 @@ public class LodFileHandler
|
|||||||
private final String FILE_EXTENSION = ".txt";
|
private final String FILE_EXTENSION = ".txt";
|
||||||
|
|
||||||
private ExecutorService fileWritingThreadPool = Executors.newFixedThreadPool(1);
|
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(ISaveHandler newSaveHandler, LodDimension newLoadedDimension)
|
||||||
{
|
{
|
||||||
saveHandler = newSaveHandler;
|
saveHandler = newSaveHandler;
|
||||||
|
|
||||||
loadedRegion = newLoadedRegion;
|
loadedDimension = newLoadedDimension;
|
||||||
// these two variable are used in sync with the LodDimension
|
// these two variable are used in sync with the LodDimension
|
||||||
regionLastWriteTime = new long[loadedRegion.getWidth()][loadedRegion.getWidth()];
|
regionLastWriteTime = new long[loadedDimension.getWidth()][loadedDimension.getWidth()];
|
||||||
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++)
|
||||||
regionLastWriteTime[i][j] = -1;
|
regionLastWriteTime[i][j] = -1;
|
||||||
|
|
||||||
if (saveHandler != null && saveHandler.getWorldDirectory() != null)
|
if (saveHandler != null && saveHandler.getWorldDirectory() != null)
|
||||||
@@ -141,8 +139,10 @@ public class LodFileHandler
|
|||||||
// Save to File //
|
// 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
|
// we don't currently support reading or writing
|
||||||
// files when connected to a server
|
// files when connected to a server
|
||||||
@@ -150,64 +150,31 @@ public class LodFileHandler
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!readyToReadAndWrite())
|
if (!readyToReadAndWrite())
|
||||||
{
|
|
||||||
// we aren't ready to read and write yet
|
// 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;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
fileWritingThreadPool.execute(saveDirtyRegionsThread);
|
fileWritingThreadPool.execute(saveDirtyRegionsThread);
|
||||||
}
|
}
|
||||||
private Thread saveDirtyRegionsThread = new Thread(() ->
|
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]);
|
saveRegionToDisk(loadedDimension.regions[i][j]);
|
||||||
loadedRegion.isRegionDirty[i][j] = false;
|
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)
|
private void saveRegionToDisk(LodRegion region)
|
||||||
{
|
{
|
||||||
if (!readyToReadAndWrite() || region == null)
|
if (!readyToReadAndWrite() || region == null)
|
||||||
@@ -258,15 +225,13 @@ public class LodFileHandler
|
|||||||
* Return the name of the file that should contain the
|
* Return the name of the file that should contain the
|
||||||
* region at the given x and z. <br>
|
* region at the given x and z. <br>
|
||||||
* Returns null if this object isn't ready to read and write.
|
* Returns null if this object isn't ready to read and write.
|
||||||
* @param regionX
|
|
||||||
* @param regionZ
|
|
||||||
*/
|
*/
|
||||||
private String getFileNameForRegion(int regionX, int regionZ)
|
private String getFileNameForRegion(int regionX, int regionZ)
|
||||||
{
|
{
|
||||||
if (!readyToReadAndWrite())
|
if (!readyToReadAndWrite())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return save_dir + "\\lod_data\\DIM" + loadedRegion.dimension.getId() + "\\" +
|
return save_dir + "\\lod_data\\DIM" + loadedDimension.dimension.getId() + "\\" +
|
||||||
FILE_NAME_PREFIX + "." + regionX + "." + regionZ + FILE_EXTENSION;
|
FILE_NAME_PREFIX + "." + regionX + "." + regionZ + FILE_EXTENSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,6 +239,8 @@ public class LodFileHandler
|
|||||||
/**
|
/**
|
||||||
* Returns if this FileHandler is ready to read
|
* Returns if this FileHandler is ready to read
|
||||||
* and write files.
|
* and write files.
|
||||||
|
* <br>
|
||||||
|
* This returns true when the world save directory is known.
|
||||||
*/
|
*/
|
||||||
public boolean readyToReadAndWrite()
|
public boolean readyToReadAndWrite()
|
||||||
{
|
{
|
||||||
@@ -306,6 +273,8 @@ public class LodFileHandler
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Gets the canonical path to the world save folder.
|
||||||
|
* <br>
|
||||||
* Returns null if there was an IO Exception
|
* Returns null if there was an IO Exception
|
||||||
*/
|
*/
|
||||||
private String getWorldSaveDirectory()
|
private String getWorldSaveDirectory()
|
||||||
+4
-3
@@ -1,4 +1,4 @@
|
|||||||
package com.backsun.lod.util;
|
package com.backsun.lod.handlers;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@@ -11,7 +11,8 @@ import net.minecraft.client.Minecraft;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This object is used to get variables from methods
|
* This object is used to get variables from methods
|
||||||
* where they are private.
|
* where they are private. Specifically the fog setting
|
||||||
|
* in Optifine.
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 09-21-2020
|
* @version 09-21-2020
|
||||||
@@ -136,7 +137,7 @@ public class ReflectionHandler
|
|||||||
// either optifine isn't installed,
|
// either optifine isn't installed,
|
||||||
// the variable name was changed, or
|
// the variable name was changed, or
|
||||||
// the setup method wasn't called yet.
|
// the setup method wasn't called yet.
|
||||||
return FogQuality.OFF;
|
return FogQuality.FANCY;
|
||||||
}
|
}
|
||||||
|
|
||||||
int returnNum = 0;
|
int returnNum = 0;
|
||||||
@@ -3,7 +3,7 @@ package com.backsun.lod.objects;
|
|||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
|
||||||
import com.backsun.lod.util.enums.ColorDirection;
|
import com.backsun.lod.util.enums.ColorDirection;
|
||||||
import com.backsun.lod.util.enums.LodLocation;
|
import com.backsun.lod.util.enums.LodCorner;
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
@@ -73,7 +73,7 @@ public class LodChunk
|
|||||||
//==============//
|
//==============//
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an empty LodChunk
|
* Create an empty invisible LodChunk at (0,0)
|
||||||
*/
|
*/
|
||||||
public LodChunk()
|
public LodChunk()
|
||||||
{
|
{
|
||||||
@@ -145,7 +145,7 @@ public class LodChunk
|
|||||||
|
|
||||||
// top
|
// top
|
||||||
top = new short[4];
|
top = new short[4];
|
||||||
for(LodLocation loc : LodLocation.values())
|
for(LodCorner loc : LodCorner.values())
|
||||||
{
|
{
|
||||||
lastIndex = index;
|
lastIndex = index;
|
||||||
index = data.indexOf(DATA_DELIMITER, lastIndex + 1);
|
index = data.indexOf(DATA_DELIMITER, lastIndex + 1);
|
||||||
@@ -156,7 +156,7 @@ public class LodChunk
|
|||||||
|
|
||||||
// bottom
|
// bottom
|
||||||
bottom = new short[4];
|
bottom = new short[4];
|
||||||
for(LodLocation loc : LodLocation.values())
|
for(LodCorner loc : LodCorner.values())
|
||||||
{
|
{
|
||||||
lastIndex = index;
|
lastIndex = index;
|
||||||
index = data.indexOf(DATA_DELIMITER, lastIndex + 1);
|
index = data.indexOf(DATA_DELIMITER, lastIndex + 1);
|
||||||
@@ -202,11 +202,11 @@ public class LodChunk
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Illegal argument is thrown if either the
|
* Creates a LodChunk for a chunk in the given world. <br>
|
||||||
* chunk or world is null. The reason the world
|
* Note: The world is required to determine each block's color
|
||||||
* can't be null is because it's required to determine
|
*
|
||||||
* a block's color.
|
* @throws IllegalArgumentException
|
||||||
* @throws IllegalArgumentException
|
* thrown if either the chunk or world is null.
|
||||||
*/
|
*/
|
||||||
public LodChunk(Chunk chunk, World world) throws IllegalArgumentException
|
public LodChunk(Chunk chunk, World world) throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
@@ -228,16 +228,16 @@ public class LodChunk
|
|||||||
colors = new Color[6];
|
colors = new Color[6];
|
||||||
|
|
||||||
// generate the top and bottom points of this LOD
|
// generate the top and bottom points of this LOD
|
||||||
for(LodLocation loc : LodLocation.values())
|
for(LodCorner loc : LodCorner.values())
|
||||||
{
|
{
|
||||||
top[loc.value] = generateLodSection(chunk, true, loc);
|
top[loc.value] = generateLodCorner(chunk, SectionGenerationMode.GENERATE_TOP, loc);
|
||||||
bottom[loc.value] = generateLodSection(chunk, false, loc);
|
bottom[loc.value] = generateLodCorner(chunk, SectionGenerationMode.GENERATE_BOTTOM, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine the average color for each direction
|
// determine the average color for each direction
|
||||||
for(ColorDirection dir : ColorDirection.values())
|
for(ColorDirection dir : ColorDirection.values())
|
||||||
{
|
{
|
||||||
colors[dir.value] = generateLodColorSection(chunk, world, dir);
|
colors[dir.value] = generateLodColor(chunk, world, dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,15 +253,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
|
* If invalid/null/empty chunks are given
|
||||||
* crashes may occur.
|
* crashes may occur.
|
||||||
*/
|
*/
|
||||||
public short generateLodSection(Chunk chunk, boolean getTopSection, LodLocation lodLoc)
|
private short generateLodCorner(Chunk chunk, SectionGenerationMode generationMode, LodCorner lodLoc)
|
||||||
{
|
{
|
||||||
// should have a length of 16
|
// should have a length of 16
|
||||||
// (each storage is 16x16x16 and the
|
// (each storage is 16x16x16 and the
|
||||||
// world height is 256)
|
// world height is 256)
|
||||||
ExtendedBlockStorage[] data = chunk.getBlockStorageArray();
|
ExtendedBlockStorage[] blockStorage = chunk.getBlockStorageArray();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -313,21 +315,29 @@ public class LodChunk
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(getTopSection)
|
if(generationMode == SectionGenerationMode.GENERATE_TOP)
|
||||||
return determineTopPoint(data, startX, endX, startZ, endZ);
|
return determineTopPoint(blockStorage, startX, endX, startZ, endZ);
|
||||||
else
|
else
|
||||||
return determineBottomPoint(data, startX, endX, startZ, endZ);
|
return determineBottomPoint(blockStorage, 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(ExtendedBlockStorage[] blockStorage, int startX, int endX, int startZ, int endZ)
|
||||||
{
|
{
|
||||||
// search from the bottom up
|
// search from the bottom up
|
||||||
for(int i = 0; i < data.length; i++)
|
for(int i = 0; i < blockStorage.length; i++)
|
||||||
{
|
{
|
||||||
for(int y = 0; y < CHUNK_DATA_HEIGHT; y++)
|
for(int y = 0; y < CHUNK_DATA_HEIGHT; y++)
|
||||||
{
|
{
|
||||||
|
if(isLayerValidLodPoint(blockStorage, startX, endX, startZ, endZ, i, y))
|
||||||
if(isLayerValidLodPoint(data, startX, endX, startZ, endZ, i, y))
|
|
||||||
{
|
{
|
||||||
// we found
|
// we found
|
||||||
// enough blocks in this
|
// enough blocks in this
|
||||||
@@ -335,23 +345,24 @@ public class LodChunk
|
|||||||
// LOD point
|
// LOD point
|
||||||
return (short) (y + (i * CHUNK_DATA_HEIGHT));
|
return (short) (y + (i * CHUNK_DATA_HEIGHT));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} // y
|
}
|
||||||
} // data
|
|
||||||
|
|
||||||
|
|
||||||
// we never found a valid LOD point
|
// we never found a valid LOD point
|
||||||
return -1;
|
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(ExtendedBlockStorage[] blockStorage, int startX, int endX, int startZ, int endZ)
|
||||||
{
|
{
|
||||||
// search from the top down
|
// search from the top down
|
||||||
for(int i = data.length - 1; i >= 0; i--)
|
for(int i = blockStorage.length - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
for(int y = CHUNK_DATA_WIDTH - 1; y >= 0; y--)
|
for(int y = CHUNK_DATA_WIDTH - 1; y >= 0; y--)
|
||||||
{
|
{
|
||||||
if(isLayerValidLodPoint(data, startX, endX, startZ, endZ, i, y))
|
if(isLayerValidLodPoint(blockStorage, startX, endX, startZ, endZ, i, y))
|
||||||
{
|
{
|
||||||
// we found
|
// we found
|
||||||
// enough blocks in this
|
// enough blocks in this
|
||||||
@@ -359,10 +370,8 @@ public class LodChunk
|
|||||||
// LOD point
|
// LOD point
|
||||||
return (short) (y + (i * CHUNK_DATA_HEIGHT));
|
return (short) (y + (i * CHUNK_DATA_HEIGHT));
|
||||||
}
|
}
|
||||||
} // y
|
}
|
||||||
} // data
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// we never found a valid LOD point
|
// we never found a valid LOD point
|
||||||
return -1;
|
return -1;
|
||||||
@@ -373,7 +382,7 @@ public class LodChunk
|
|||||||
* values a valid LOD point?
|
* values a valid LOD point?
|
||||||
*/
|
*/
|
||||||
private boolean isLayerValidLodPoint(
|
private boolean isLayerValidLodPoint(
|
||||||
ExtendedBlockStorage[] data,
|
ExtendedBlockStorage[] blockStorage,
|
||||||
int startX, int endX,
|
int startX, int endX,
|
||||||
int startZ, int endZ,
|
int startZ, int endZ,
|
||||||
int dataIndex, int y)
|
int dataIndex, int y)
|
||||||
@@ -385,7 +394,7 @@ public class LodChunk
|
|||||||
{
|
{
|
||||||
for(int z = startZ; z < endZ; z++)
|
for(int z = startZ; z < endZ; z++)
|
||||||
{
|
{
|
||||||
if(data[dataIndex] == null)
|
if(blockStorage[dataIndex] == null)
|
||||||
{
|
{
|
||||||
// this section doesn't have any blocks,
|
// this section doesn't have any blocks,
|
||||||
// it is not a valid section
|
// it is not a valid section
|
||||||
@@ -393,7 +402,7 @@ public class LodChunk
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(data[dataIndex].get(x, y, z) != null && Block.getIdFromBlock(data[dataIndex].get(x, y, z).getBlock()) != airBlockId)
|
if(blockStorage[dataIndex].get(x, y, z) != null && Block.getIdFromBlock(blockStorage[dataIndex].get(x, y, z).getBlock()) != airBlockId)
|
||||||
{
|
{
|
||||||
// we found a valid block in
|
// we found a valid block in
|
||||||
// in this layer
|
// in this layer
|
||||||
@@ -412,9 +421,11 @@ public class LodChunk
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the color of the given ColorDirection at the given chunk
|
||||||
private Color generateLodColorSection(Chunk chunk, World world, ColorDirection colorDir)
|
* in the given world.
|
||||||
|
*/
|
||||||
|
private Color generateLodColor(Chunk chunk, World world, ColorDirection colorDir)
|
||||||
{
|
{
|
||||||
Minecraft mc = Minecraft.getMinecraft();
|
Minecraft mc = Minecraft.getMinecraft();
|
||||||
BlockColors bc = mc.getBlockColors();
|
BlockColors bc = mc.getBlockColors();
|
||||||
@@ -441,11 +452,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)
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtendedBlockStorage[] blockStorage = chunk.getBlockStorageArray();
|
||||||
|
|
||||||
int numbOfBlocks = 0;
|
int numbOfBlocks = 0;
|
||||||
int red = 0;
|
int red = 0;
|
||||||
@@ -456,8 +474,8 @@ public class LodChunk
|
|||||||
|
|
||||||
|
|
||||||
// either go top down or bottom up
|
// either go top down or bottom up
|
||||||
int dataStart = goTopDown? data.length - 1 : 0;
|
int dataStart = goTopDown? blockStorage.length - 1 : 0;
|
||||||
int dataMax = data.length;
|
int dataMax = blockStorage.length;
|
||||||
int dataMin = 0;
|
int dataMin = 0;
|
||||||
int dataIncrement = goTopDown? -1 : 1;
|
int dataIncrement = goTopDown? -1 : 1;
|
||||||
|
|
||||||
@@ -474,16 +492,16 @@ public class LodChunk
|
|||||||
|
|
||||||
for(int di = dataStart; !foundBlock && di >= dataMin && di < dataMax; di += dataIncrement)
|
for(int di = dataStart; !foundBlock && di >= dataMin && di < dataMax; di += dataIncrement)
|
||||||
{
|
{
|
||||||
if(!foundBlock && data[di] != null)
|
if(!foundBlock && blockStorage[di] != null)
|
||||||
{
|
{
|
||||||
for(int y = topStart; !foundBlock && y >= topMin && y < topMax; y += topIncrement)
|
for(int y = topStart; !foundBlock && y >= topMin && y < topMax; y += topIncrement)
|
||||||
{
|
{
|
||||||
int ci;
|
int ci;
|
||||||
if(Block.getIdFromBlock(data[di].get(x, y, z).getBlock()) == waterBlockId)
|
if(Block.getIdFromBlock(blockStorage[di].get(x, y, z).getBlock()) == waterBlockId)
|
||||||
// this is a special case since getColor on water generally returns white
|
// this is a special case since getColor on water generally returns white
|
||||||
ci = waterColor;
|
ci = waterColor;
|
||||||
else
|
else
|
||||||
ci = bc.getColor(data[di].get(x, y, z), world, new BlockPos(x,y,z));
|
ci = bc.getColor(blockStorage[di].get(x, y, z), world, new BlockPos(x,y,z));
|
||||||
|
|
||||||
if(ci == 0)
|
if(ci == 0)
|
||||||
{
|
{
|
||||||
@@ -519,10 +537,20 @@ public class LodChunk
|
|||||||
|
|
||||||
return new Color(red, green, blue);
|
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)
|
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)");
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtendedBlockStorage[] blockStorage = chunk.getBlockStorageArray();
|
||||||
|
|
||||||
int numbOfBlocks = 0;
|
int numbOfBlocks = 0;
|
||||||
int red = 0;
|
int red = 0;
|
||||||
@@ -563,9 +591,9 @@ public class LodChunk
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (int di = 0; di < data.length; di++)
|
for (int di = 0; di < blockStorage.length; di++)
|
||||||
{
|
{
|
||||||
if (data[di] != null)
|
if (blockStorage[di] != null)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < CHUNK_DATA_HEIGHT; y++)
|
for (int y = 0; y < CHUNK_DATA_HEIGHT; y++)
|
||||||
{
|
{
|
||||||
@@ -607,11 +635,11 @@ public class LodChunk
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ci;
|
int ci;
|
||||||
if(Block.getIdFromBlock(data[di].get(x, y, z).getBlock()) == waterBlockId)
|
if(Block.getIdFromBlock(blockStorage[di].get(x, y, z).getBlock()) == waterBlockId)
|
||||||
// this is a special case since getColor on water generally returns white
|
// this is a special case since getColor on water generally returns white
|
||||||
ci = waterColor;
|
ci = waterColor;
|
||||||
else
|
else
|
||||||
ci = bc.getColor(data[di].get(x, y, z), world, new BlockPos(x,y,z));
|
ci = bc.getColor(blockStorage[di].get(x, y, z), world, new BlockPos(x,y,z));
|
||||||
|
|
||||||
if (ci == 0) {
|
if (ci == 0) {
|
||||||
// skip air or invisible blocks
|
// skip air or invisible blocks
|
||||||
@@ -671,6 +699,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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -681,7 +733,6 @@ public class LodChunk
|
|||||||
//========//
|
//========//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Outputs all data in csv format
|
* Outputs all data in csv format
|
||||||
* with the given delimiter.
|
* with the given delimiter.
|
||||||
@@ -727,28 +778,7 @@ public class LodChunk
|
|||||||
|
|
||||||
s += "x: " + x + " z: " + z + "\t";
|
s += "x: " + x + " z: " + z + "\t";
|
||||||
|
|
||||||
// s += "top: ";
|
s += "(" + colors[ColorDirection.TOP.value].getRed() + ", " + colors[ColorDirection.TOP.value].getGreen() + ", " + colors[ColorDirection.TOP.value].getBlue() + ")";
|
||||||
// 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() + "), ";
|
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.backsun.lod.objects;
|
package com.backsun.lod.objects;
|
||||||
|
|
||||||
import com.backsun.lod.util.LodFileHandler;
|
import com.backsun.lod.handlers.LodDimensionFileHandler;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.world.DimensionType;
|
import net.minecraft.world.DimensionType;
|
||||||
@@ -10,13 +10,13 @@ import net.minecraft.world.DimensionType;
|
|||||||
* for a given dimension.
|
* for a given dimension.
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 01-31-2021
|
* @version 02-23-2021
|
||||||
*/
|
*/
|
||||||
public class LodDimension
|
public class LodDimension
|
||||||
{
|
{
|
||||||
public final DimensionType dimension;
|
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;
|
private volatile int halfWidth;
|
||||||
|
|
||||||
public LodRegion regions[][];
|
public LodRegion regions[][];
|
||||||
@@ -25,7 +25,8 @@ public class LodDimension
|
|||||||
private int centerX;
|
private int centerX;
|
||||||
private int centerZ;
|
private int centerZ;
|
||||||
|
|
||||||
private LodFileHandler rfHandler;
|
private LodDimensionFileHandler fileHandler;
|
||||||
|
|
||||||
|
|
||||||
public LodDimension(DimensionType newDimension, int newMaxWidth)
|
public LodDimension(DimensionType newDimension, int newMaxWidth)
|
||||||
{
|
{
|
||||||
@@ -33,7 +34,7 @@ public class LodDimension
|
|||||||
width = newMaxWidth;
|
width = newMaxWidth;
|
||||||
|
|
||||||
// dimension 0 works here since we are just looking for the save handler anyway
|
// dimension 0 works here since we are just looking for the save handler anyway
|
||||||
rfHandler = new LodFileHandler(Minecraft.getMinecraft().getIntegratedServer().getWorld(0).getSaveHandler(), this);
|
fileHandler = new LodDimensionFileHandler(Minecraft.getMinecraft().getIntegratedServer().getWorld(0).getSaveHandler(), this);
|
||||||
|
|
||||||
regions = new LodRegion[width][width];
|
regions = new LodRegion[width][width];
|
||||||
isRegionDirty = new boolean[width][width];
|
isRegionDirty = new boolean[width][width];
|
||||||
@@ -50,7 +51,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)
|
public void move(int xOffset, int zOffset)
|
||||||
{
|
{
|
||||||
// if the x or z offset is equal to or greater than
|
// if the x or z offset is equal to or greater than
|
||||||
@@ -144,22 +148,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)
|
public LodRegion getRegion(int regionX, int regionZ)
|
||||||
{
|
{
|
||||||
int xIndex = (regionX - centerX) + halfWidth;
|
int xIndex = (regionX - centerX) + halfWidth;
|
||||||
@@ -201,11 +199,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)
|
public void addLod(LodChunk lod)
|
||||||
{
|
{
|
||||||
int regionX = (lod.x + centerX) / LodRegion.SIZE;
|
int regionX = lod.x / LodRegion.SIZE;
|
||||||
int regionZ = (lod.z + centerZ) / LodRegion.SIZE;
|
int regionZ = lod.z / LodRegion.SIZE;
|
||||||
|
|
||||||
// prevent issues if X/Z is negative and less than 16
|
// prevent issues if X/Z is negative and less than 16
|
||||||
if (lod.x < 0)
|
if (lod.x < 0)
|
||||||
@@ -236,20 +238,20 @@ public class LodDimension
|
|||||||
int xIndex = (regionX - centerX) + halfWidth;
|
int xIndex = (regionX - centerX) + halfWidth;
|
||||||
int zIndex = (regionZ - centerZ) + halfWidth;
|
int zIndex = (regionZ - centerZ) + halfWidth;
|
||||||
isRegionDirty[xIndex][zIndex] = true;
|
isRegionDirty[xIndex][zIndex] = true;
|
||||||
|
fileHandler.saveDirtyRegionsToFileAsync();
|
||||||
|
|
||||||
|
|
||||||
rfHandler.saveDirtyRegionsToFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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)
|
public LodChunk getLodFromCoordinates(int chunkX, int chunkZ)
|
||||||
{
|
{
|
||||||
// (chunkX + centerX) % width
|
int regionX = chunkX / LodRegion.SIZE;
|
||||||
int regionX = (chunkX + centerX) / LodRegion.SIZE;
|
int regionZ = chunkZ / LodRegion.SIZE;
|
||||||
int regionZ = (chunkZ + centerZ) / LodRegion.SIZE;
|
|
||||||
|
|
||||||
// prevent issues if chunkX/Z is negative and less than width
|
// prevent issues if chunkX/Z is negative and less than width
|
||||||
if (chunkX < 0)
|
if (chunkX < 0)
|
||||||
@@ -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)
|
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()
|
public int getWidth()
|
||||||
{
|
{
|
||||||
return width;
|
return width;
|
||||||
@@ -311,6 +331,18 @@ public class LodDimension
|
|||||||
for(int j = 0; j < width; j++)
|
for(int j = 0; j < width; j++)
|
||||||
isRegionDirty[i][j] = false;
|
isRegionDirty[i][j] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String s = "";
|
||||||
|
|
||||||
|
s += "dim: " + dimension.getName() + "\t";
|
||||||
|
s += "(" + centerX + "," + centerZ + ")";
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ package com.backsun.lod.objects;
|
|||||||
* one file in the file system.
|
* one file in the file system.
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 1-20-2021
|
* @version 1-22-2021
|
||||||
*/
|
*/
|
||||||
public class LodRegion
|
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)
|
public void addLod(LodChunk lod)
|
||||||
{
|
{
|
||||||
// we use ABS since LODs can be negative, but if they are
|
// we use ABS since LODs can be negative, but if they are
|
||||||
@@ -43,6 +48,13 @@ public class LodRegion
|
|||||||
chunks[xIndex][zIndex] = lod;
|
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)
|
public LodChunk getLod(int chunkX, int chunkZ)
|
||||||
{
|
{
|
||||||
// since we add LOD's with ABS, we get them the same way
|
// 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()
|
public LodChunk[][] getAllLods()
|
||||||
{
|
{
|
||||||
return chunks;
|
return chunks;
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package com.backsun.lod.objects;
|
package com.backsun.lod.objects;
|
||||||
|
|
||||||
import java.util.Dictionary;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This stores all LODs for a given world.
|
* This stores all LODs for a given world.
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 01-31-2021
|
* @version 02-22-2021
|
||||||
*/
|
*/
|
||||||
public class LodWorld
|
public class LodWorld
|
||||||
{
|
{
|
||||||
@@ -17,7 +16,7 @@ public class LodWorld
|
|||||||
/**
|
/**
|
||||||
* Key = Dimension id (as an int)
|
* Key = Dimension id (as an int)
|
||||||
*/
|
*/
|
||||||
private Dictionary<Integer, LodDimension> lodDimensions;
|
private Map<Integer, LodDimension> lodDimensions;
|
||||||
|
|
||||||
|
|
||||||
public LodWorld(String newWorldName)
|
public LodWorld(String newWorldName)
|
||||||
@@ -38,12 +37,27 @@ public class LodWorld
|
|||||||
return lodDimensions.get(dimensionId);
|
return lodDimensions.get(dimensionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resizes the max width in regions that each LodDimension
|
||||||
|
* should use.
|
||||||
|
*/
|
||||||
public void resizeDimensionRegionWidth(int newWidth)
|
public void resizeDimensionRegionWidth(int newWidth)
|
||||||
{
|
{
|
||||||
Enumeration<Integer> keys = lodDimensions.keys();
|
for(Integer key : lodDimensions.keySet())
|
||||||
|
lodDimensions.get(key).setRegionWidth(newWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String s = "";
|
||||||
|
|
||||||
while(keys.hasMoreElements())
|
s += worldName + "\t - dimensions: ";
|
||||||
lodDimensions.get(keys.nextElement()).setRegionWidth(newWidth);
|
for(Integer key : lodDimensions.keySet())
|
||||||
|
s += lodDimensions.get(key).dimension.getName() + ", ";
|
||||||
|
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -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
|
* This object is just a replacement for an array
|
||||||
@@ -8,16 +8,16 @@ import java.nio.ByteBuffer;
|
|||||||
* and BuildBufferThread.
|
* and BuildBufferThread.
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 02-13-2021
|
* @version 02-21-2021
|
||||||
*/
|
*/
|
||||||
public class NearFarBuffer
|
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;
|
nearBuffer = newNearBuffer;
|
||||||
farBuffer = newFarBuffer;
|
farBuffer = newFarBuffer;
|
||||||
@@ -1,25 +1,18 @@
|
|||||||
package com.backsun.lod.proxy;
|
package com.backsun.lod.proxy;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
import com.backsun.lod.builders.LodBuilder;
|
||||||
import com.backsun.lod.objects.LodChunk;
|
import com.backsun.lod.objects.LodChunk;
|
||||||
import com.backsun.lod.objects.LodDimension;
|
import com.backsun.lod.objects.LodDimension;
|
||||||
import com.backsun.lod.objects.LodRegion;
|
import com.backsun.lod.objects.LodRegion;
|
||||||
import com.backsun.lod.objects.LodWorld;
|
import com.backsun.lod.objects.LodWorld;
|
||||||
import com.backsun.lod.renderer.LodRenderer;
|
import com.backsun.lod.renderer.LodRenderer;
|
||||||
import com.backsun.lod.util.LodConfig;
|
import com.backsun.lod.util.LodConfig;
|
||||||
import com.backsun.lod.util.LodFileHandler;
|
import com.backsun.lodcore.util.RenderGlobalHook;
|
||||||
import com.backsun.lodCore.util.RenderGlobalHook;
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.multiplayer.WorldClient;
|
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.client.event.RenderWorldLastEvent;
|
||||||
import net.minecraftforge.event.terraingen.PopulateChunkEvent;
|
import net.minecraftforge.event.terraingen.PopulateChunkEvent;
|
||||||
import net.minecraftforge.event.world.ChunkEvent;
|
import net.minecraftforge.event.world.ChunkEvent;
|
||||||
@@ -29,23 +22,21 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
|||||||
// Minecraft.getMinecraft().getIntegratedServer()
|
// 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
|
* @author James_Seibel
|
||||||
* @version 01-31-2021
|
* @version 02-23-2021
|
||||||
*/
|
*/
|
||||||
public class ClientProxy extends CommonProxy
|
public class ClientProxy extends CommonProxy
|
||||||
{
|
{
|
||||||
private LodRenderer renderer;
|
private LodRenderer renderer;
|
||||||
private LodWorld lodWorld;
|
private LodWorld lodWorld;
|
||||||
private ExecutorService lodGenThreadPool = Executors.newFixedThreadPool(1);
|
private LodBuilder lodBuilder;
|
||||||
|
|
||||||
/** Default size of any LOD regions we use */
|
|
||||||
private int regionWidth = 5;
|
|
||||||
|
|
||||||
public ClientProxy()
|
public ClientProxy()
|
||||||
{
|
{
|
||||||
|
lodBuilder = new LodBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -67,13 +58,17 @@ public class ClientProxy extends CommonProxy
|
|||||||
GL11.glDisable(GL11.GL_STENCIL_TEST);
|
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)
|
public void renderLods(float partialTicks)
|
||||||
{
|
{
|
||||||
int newWidth = Math.max(4, (Minecraft.getMinecraft().gameSettings.renderDistanceChunks * LodChunk.WIDTH * 2) / LodRegion.SIZE);
|
int newWidth = Math.max(4, (Minecraft.getMinecraft().gameSettings.renderDistanceChunks * LodChunk.WIDTH * 2) / LodRegion.SIZE);
|
||||||
if (lodWorld != null && regionWidth != newWidth)
|
if (lodWorld != null && lodBuilder.regionWidth != newWidth)
|
||||||
{
|
{
|
||||||
lodWorld.resizeDimensionRegionWidth(newWidth);
|
lodWorld.resizeDimensionRegionWidth(newWidth);
|
||||||
regionWidth = newWidth;
|
lodBuilder.regionWidth = newWidth;
|
||||||
|
|
||||||
// skip this frame, hopefully the lodWorld
|
// skip this frame, hopefully the lodWorld
|
||||||
// should have everything set up by then
|
// should have everything set up by then
|
||||||
@@ -101,7 +96,6 @@ public class ClientProxy extends CommonProxy
|
|||||||
lodDim.move(xOffset, zOffset);
|
lodDim.move(xOffset, zOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// we wait to create the renderer until the first frame
|
// we wait to create the renderer until the first frame
|
||||||
// to make sure that the EntityRenderer has
|
// to make sure that the EntityRenderer has
|
||||||
// been created, that way we can get the fovModifer
|
// been created, that way we can get the fovModifer
|
||||||
@@ -120,9 +114,6 @@ public class ClientProxy extends CommonProxy
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===============//
|
//===============//
|
||||||
// update events //
|
// update events //
|
||||||
//===============//
|
//===============//
|
||||||
@@ -130,7 +121,7 @@ public class ClientProxy extends CommonProxy
|
|||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void chunkLoadEvent(ChunkEvent event)
|
public void chunkLoadEvent(ChunkEvent event)
|
||||||
{
|
{
|
||||||
generateLodChunk(event.getChunk());
|
lodWorld = lodBuilder.generateLodChunkAsync(event.getChunk());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,111 +137,12 @@ public class ClientProxy extends CommonProxy
|
|||||||
|
|
||||||
if(world != null)
|
if(world != null)
|
||||||
{
|
{
|
||||||
generateLodChunk(world.getChunkFromChunkCoords(event.getChunkX(), event.getChunkZ()));
|
lodWorld = lodBuilder.generateLodChunkAsync(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.backsun.lod.proxy;
|
package com.backsun.lod.proxy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is used by the server.
|
* This handles any events sent to the server.
|
||||||
*
|
*
|
||||||
* @author James_Seibel
|
* @author James_Seibel
|
||||||
* @version 08-31-2020
|
* @version 08-31-2020
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -15,30 +15,36 @@ import java.util.concurrent.Future;
|
|||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
import org.lwjgl.util.glu.Project;
|
import org.lwjgl.util.glu.Project;
|
||||||
|
|
||||||
|
import com.backsun.lod.builders.BuildBufferThread;
|
||||||
|
import com.backsun.lod.handlers.ReflectionHandler;
|
||||||
import com.backsun.lod.objects.LodChunk;
|
import com.backsun.lod.objects.LodChunk;
|
||||||
import com.backsun.lod.objects.LodDimension;
|
import com.backsun.lod.objects.LodDimension;
|
||||||
|
import com.backsun.lod.objects.NearFarBuffer;
|
||||||
import com.backsun.lod.util.LodConfig;
|
import com.backsun.lod.util.LodConfig;
|
||||||
import com.backsun.lod.util.ReflectionHandler;
|
|
||||||
import com.backsun.lod.util.enums.ColorDirection;
|
import com.backsun.lod.util.enums.ColorDirection;
|
||||||
import com.backsun.lod.util.enums.FogDistance;
|
import com.backsun.lod.util.enums.FogDistance;
|
||||||
import com.backsun.lod.util.enums.FogQuality;
|
import com.backsun.lod.util.enums.FogQuality;
|
||||||
import com.backsun.lod.util.enums.LodLocation;
|
import com.backsun.lod.util.enums.LodCorner;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.entity.EntityPlayerSP;
|
||||||
import net.minecraft.client.renderer.BufferBuilder;
|
import net.minecraft.client.renderer.BufferBuilder;
|
||||||
import net.minecraft.client.renderer.GlStateManager;
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
import net.minecraft.client.renderer.Tessellator;
|
import net.minecraft.client.renderer.Tessellator;
|
||||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 2-13-2021
|
* @version 2-24-2021
|
||||||
*/
|
*/
|
||||||
public class LodRenderer
|
public class LodRenderer
|
||||||
{
|
{
|
||||||
|
/** this is the light used when rendering the LODs,
|
||||||
|
* it should be something different than what is used by Minecraft */
|
||||||
|
private static final int LOD_GL_LIGHT_NUMBER = GL11.GL_LIGHT2;
|
||||||
|
|
||||||
/** If true the LODs colors will be replaced with
|
/** If true the LODs colors will be replaced with
|
||||||
* a checkerboard, this can be used for debugging. */
|
* a checkerboard, this can be used for debugging. */
|
||||||
public boolean debugging = false;
|
public boolean debugging = false;
|
||||||
@@ -52,31 +58,35 @@ public class LodRenderer
|
|||||||
private Tessellator tessellator;
|
private Tessellator tessellator;
|
||||||
private BufferBuilder bufferBuilder;
|
private BufferBuilder bufferBuilder;
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an array of 0's used to clear old
|
|
||||||
* ByteBuffers when they need to be rebuilt.
|
|
||||||
*/
|
|
||||||
byte[] clearBytes;
|
|
||||||
|
|
||||||
private ReflectionHandler reflectionHandler;
|
private ReflectionHandler reflectionHandler;
|
||||||
|
|
||||||
public LodDimension lodDimension = null;
|
public LodDimension lodDimension = null;
|
||||||
|
|
||||||
|
|
||||||
|
/** Total number of CPU cores available to the Java VM */
|
||||||
private int maxNumbThreads = Runtime.getRuntime().availableProcessors();
|
private int maxNumbThreads = Runtime.getRuntime().availableProcessors();
|
||||||
/** How many threads should be used for building the render buffer. */
|
/** How many threads should be used for building render buffers */
|
||||||
private int numbBufferThreads = maxNumbThreads;
|
private int numbBufferThreads = maxNumbThreads;
|
||||||
|
/** This stores all the BuildBufferThread objects for each CPU core */
|
||||||
private ArrayList<BuildBufferThread> bufferThreads = new ArrayList<BuildBufferThread>();
|
private ArrayList<BuildBufferThread> bufferThreads = new ArrayList<BuildBufferThread>();
|
||||||
private volatile ByteBuffer[] nearBuffers = new ByteBuffer[maxNumbThreads];
|
/** The buffers that are used to draw LODs using near fog */
|
||||||
private volatile ByteBuffer[] farBuffers = new ByteBuffer[maxNumbThreads];
|
private volatile BufferBuilder[] drawableNearBuffers = null;
|
||||||
|
/** The buffers that are used to draw LODs using far fog */
|
||||||
|
private volatile BufferBuilder[] drawableFarBuffers = null;
|
||||||
|
|
||||||
|
/** The buffers that are used to create LODs using near fog */
|
||||||
|
private volatile BufferBuilder[] buildableNearBuffers = null;
|
||||||
|
/** The buffers that are used to create LODs using far fog */
|
||||||
|
private volatile BufferBuilder[] buildableFarBuffers = null;
|
||||||
|
|
||||||
|
/** If we have more CPU cores than LOD rows to draw this tells
|
||||||
|
* which drawable buffers will and won't be used. */
|
||||||
|
private boolean[] shouldDrawBuffer = new boolean[maxNumbThreads];
|
||||||
|
|
||||||
|
/** This holds the threads used to generate the LOD buffers */
|
||||||
private ExecutorService bufferThreadPool = Executors.newFixedThreadPool(maxNumbThreads);
|
private ExecutorService bufferThreadPool = Executors.newFixedThreadPool(maxNumbThreads);
|
||||||
/*
|
/** This holds the thread used to generate new LODs off the main thread. */
|
||||||
* this is the maximum number of bytes a buffer
|
private ExecutorService genThread = Executors.newSingleThreadExecutor();
|
||||||
* would ever have to hold at once (this prevents the buffer
|
|
||||||
* from having to resize and thus save performance)
|
|
||||||
*/
|
|
||||||
private int bufferMaxCapacity = 0;
|
|
||||||
|
|
||||||
/** This is used to determine if the LODs should be regenerated */
|
/** This is used to determine if the LODs should be regenerated */
|
||||||
private int previousChunkRenderDistance = 0;
|
private int previousChunkRenderDistance = 0;
|
||||||
@@ -87,8 +97,17 @@ public class LodRenderer
|
|||||||
/** This is used to determine if the LODs should be regenerated */
|
/** This is used to determine if the LODs should be regenerated */
|
||||||
private FogDistance prevFogDistance = FogDistance.NEAR_AND_FAR;
|
private FogDistance prevFogDistance = FogDistance.NEAR_AND_FAR;
|
||||||
|
|
||||||
/** if this is true the LODs should be regenerated */
|
/** if this is true the LOD buffers should be regenerated,
|
||||||
|
* provided they aren't already being regenerated. */
|
||||||
private boolean regen = false;
|
private boolean regen = false;
|
||||||
|
/** if this is true the LOD buffers are currently being
|
||||||
|
* regenerated. */
|
||||||
|
private volatile boolean regenerating = false;
|
||||||
|
/** if this is true new LOD buffers have been generated
|
||||||
|
* and are waiting to be swapped with the drawable buffers*/
|
||||||
|
private volatile boolean switchBuffers = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -98,23 +117,22 @@ public class LodRenderer
|
|||||||
mc = Minecraft.getMinecraft();
|
mc = Minecraft.getMinecraft();
|
||||||
|
|
||||||
// for some reason "Tessellator.getInstance()" won't work here, we have to create a new one
|
// for some reason "Tessellator.getInstance()" won't work here, we have to create a new one
|
||||||
tessellator = new Tessellator(2097152);
|
tessellator = new Tessellator(2097152); // the number here is what is used by the default Tessellator
|
||||||
bufferBuilder = tessellator.getBuffer();
|
bufferBuilder = tessellator.getBuffer();
|
||||||
|
|
||||||
reflectionHandler = new ReflectionHandler();
|
reflectionHandler = new ReflectionHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Besides drawing the LODs this method also starts
|
||||||
|
* the async process of generating the Buffers that hold those LODs.
|
||||||
|
*
|
||||||
|
* @param newDimension The dimension to draw, if null doesn't replace the current dimension.
|
||||||
|
* @param partialTicks how far into the current tick this method was called.
|
||||||
|
*/
|
||||||
public void drawLODs(LodDimension newDimension, float partialTicks)
|
public void drawLODs(LodDimension newDimension, float partialTicks)
|
||||||
{
|
{
|
||||||
if (reflectionHandler.fovMethod == null)
|
|
||||||
{
|
|
||||||
// don't continue if we can't get the
|
|
||||||
// user's FOV
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reflectionHandler.fovMethod == null)
|
if (reflectionHandler.fovMethod == null)
|
||||||
{
|
{
|
||||||
// we aren't able to get the user's
|
// we aren't able to get the user's
|
||||||
@@ -122,29 +140,7 @@ public class LodRenderer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// should the LODs be regenerated?
|
if (lodDimension == null && newDimension == null)
|
||||||
if ((int)Minecraft.getMinecraft().player.posX / LodChunk.WIDTH != prevChunkX ||
|
|
||||||
(int)Minecraft.getMinecraft().player.posZ / LodChunk.WIDTH != prevChunkZ ||
|
|
||||||
previousChunkRenderDistance != mc.gameSettings.renderDistanceChunks ||
|
|
||||||
prevFogDistance != LodConfig.fogDistance ||
|
|
||||||
lodDimension != newDimension)
|
|
||||||
{
|
|
||||||
regen = true;
|
|
||||||
|
|
||||||
prevChunkX = (int)Minecraft.getMinecraft().player.posX / LodChunk.WIDTH;
|
|
||||||
prevChunkZ = (int)Minecraft.getMinecraft().player.posZ / LodChunk.WIDTH;
|
|
||||||
prevFogDistance = LodConfig.fogDistance;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// nope, the player hasn't moved, the
|
|
||||||
// render distance hasn't changed, and
|
|
||||||
// the dimension is the same
|
|
||||||
regen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
lodDimension = newDimension;
|
|
||||||
if (lodDimension == null)
|
|
||||||
{
|
{
|
||||||
// if there aren't any loaded LodChunks
|
// if there aren't any loaded LodChunks
|
||||||
// don't try drawing anything
|
// don't try drawing anything
|
||||||
@@ -155,13 +151,43 @@ public class LodRenderer
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===============//
|
||||||
|
// initial setup //
|
||||||
|
//===============//
|
||||||
|
|
||||||
|
|
||||||
// used for debugging and viewing how long different processes take
|
// used for debugging and viewing how long different processes take
|
||||||
mc.mcProfiler.endSection();
|
mc.mcProfiler.endSection();
|
||||||
mc.mcProfiler.startSection("LOD");
|
mc.mcProfiler.startSection("LOD");
|
||||||
mc.mcProfiler.startSection("LOD setup");
|
mc.mcProfiler.startSection("LOD setup");
|
||||||
@SuppressWarnings("unused")
|
|
||||||
long startTime = System.nanoTime();
|
EntityPlayerSP player = mc.player;
|
||||||
|
|
||||||
|
// should LODs be regenerated?
|
||||||
|
if ((int)player.posX / LodChunk.WIDTH != prevChunkX ||
|
||||||
|
(int)player.posZ / LodChunk.WIDTH != prevChunkZ ||
|
||||||
|
previousChunkRenderDistance != mc.gameSettings.renderDistanceChunks ||
|
||||||
|
prevFogDistance != LodConfig.fogDistance ||
|
||||||
|
lodDimension != newDimension)
|
||||||
|
{
|
||||||
|
// yes
|
||||||
|
regen = true;
|
||||||
|
|
||||||
|
prevChunkX = (int)player.posX / LodChunk.WIDTH;
|
||||||
|
prevChunkZ = (int)player.posZ / LodChunk.WIDTH;
|
||||||
|
prevFogDistance = LodConfig.fogDistance;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// nope, the player hasn't moved, the
|
||||||
|
// render distance hasn't changed, and
|
||||||
|
// the dimension is the same
|
||||||
|
regen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newDimension != null)
|
||||||
|
lodDimension = newDimension;
|
||||||
|
|
||||||
if (LodConfig.drawCheckerBoard)
|
if (LodConfig.drawCheckerBoard)
|
||||||
{
|
{
|
||||||
if (debugging != LodConfig.drawCheckerBoard)
|
if (debugging != LodConfig.drawCheckerBoard)
|
||||||
@@ -176,27 +202,11 @@ public class LodRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// color setup
|
|
||||||
int alpha = 255; // 0 - 255
|
|
||||||
|
|
||||||
Color red = new Color(255, 0, 0, alpha);
|
|
||||||
Color black = new Color(0, 0, 0, alpha);
|
|
||||||
Color white = new Color(255, 255, 255, alpha);
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
Color invisible = new Color(0,0,0,0);
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
Color error = new Color(255, 0, 225, alpha); // bright pink
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// get the camera location
|
// get the camera location
|
||||||
Entity player = mc.player;
|
|
||||||
double cameraX = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks;
|
double cameraX = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks;
|
||||||
double cameraY = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks;
|
double cameraY = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks;
|
||||||
double cameraZ = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks;
|
double cameraZ = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// determine how far the game's render distance is currently set
|
// determine how far the game's render distance is currently set
|
||||||
int renderDistWidth = mc.gameSettings.renderDistanceChunks;
|
int renderDistWidth = mc.gameSettings.renderDistanceChunks;
|
||||||
@@ -206,20 +216,6 @@ public class LodRenderer
|
|||||||
int totalLength = (int) farPlaneDistance * LOD_CHUNK_DISTANCE_RADIUS * 2;
|
int totalLength = (int) farPlaneDistance * LOD_CHUNK_DISTANCE_RADIUS * 2;
|
||||||
int numbChunksWide = (totalLength / LodChunk.WIDTH);
|
int numbChunksWide = (totalLength / LodChunk.WIDTH);
|
||||||
|
|
||||||
// this seemingly useless math is required,
|
|
||||||
// just using (int) camera doesn't work
|
|
||||||
int playerXChunkOffset = ((int) cameraX / LodChunk.WIDTH) * LodChunk.WIDTH;
|
|
||||||
int playerZChunkOffset = ((int) cameraZ / LodChunk.WIDTH) * LodChunk.WIDTH;
|
|
||||||
// this where we will start drawing squares
|
|
||||||
// (exactly half the total width)
|
|
||||||
int startX = (-LodChunk.WIDTH * (numbChunksWide / 2)) + playerXChunkOffset;
|
|
||||||
int startZ = (-LodChunk.WIDTH * (numbChunksWide / 2)) + playerZChunkOffset;
|
|
||||||
|
|
||||||
|
|
||||||
// this is where we store the LOD objects
|
|
||||||
AxisAlignedBB lodArray[][] = new AxisAlignedBB[numbChunksWide][numbChunksWide];
|
|
||||||
// this is where we store the color for each LOD object
|
|
||||||
Color colorArray[][] = new Color[numbChunksWide][numbChunksWide];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -229,89 +225,39 @@ public class LodRenderer
|
|||||||
// create the LODs //
|
// create the LODs //
|
||||||
//=================//
|
//=================//
|
||||||
|
|
||||||
if (regen)
|
// only regenerate the LODs if:
|
||||||
|
// 1. we want to regenerate LODs
|
||||||
|
// 2. we aren't already regenerating the LODs
|
||||||
|
// 3. we aren't waiting for the build and draw buffers to swap
|
||||||
|
// (this is to prevent thread conflicts)
|
||||||
|
if (regen && !regenerating && !switchBuffers)
|
||||||
{
|
{
|
||||||
mc.mcProfiler.endStartSection("LOD generation");
|
mc.mcProfiler.endStartSection("LOD generation");
|
||||||
|
regenerating = true;
|
||||||
|
|
||||||
// x axis
|
// this will only be called once, unless the numbBufferThreads changes
|
||||||
for (int i = 0; i < numbChunksWide; i++)
|
if (numbBufferThreads != bufferThreads.size())
|
||||||
{
|
setupBufferThreads();
|
||||||
// z axis
|
|
||||||
for (int j = 0; j < numbChunksWide; j++)
|
// this will mainly happen when the view distance is changed
|
||||||
{
|
if (drawableNearBuffers == null || drawableFarBuffers == null ||
|
||||||
// skip the middle
|
previousChunkRenderDistance != mc.gameSettings.renderDistanceChunks)
|
||||||
// (As the player moves some chunks will overlap or be missing,
|
setupBuffers(numbChunksWide);
|
||||||
// this is just how chunk loading/unloading works. This can hopefully
|
|
||||||
// be hidden with careful use of fog)
|
// generate the LODs on a separate thread to prevent stuttering or freezing
|
||||||
int middle = (numbChunksWide / 2);
|
genThread.execute(createLodBufferGenerationThread(player.posX, player.posZ, numbChunksWide));
|
||||||
if (RenderUtil.isCoordinateInLoadedArea(i, j, middle))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// set where this square will be drawn in the world
|
|
||||||
double xOffset = (LodChunk.WIDTH * i) + // offset by the number of LOD blocks
|
|
||||||
startX; // offset so the center LOD block is centered underneath the player
|
|
||||||
double yOffset = 0;
|
|
||||||
double zOffset = (LodChunk.WIDTH * j) + startZ;
|
|
||||||
|
|
||||||
int chunkX = i + (startX / LodChunk.WIDTH);
|
|
||||||
int chunkZ = j + (startZ / LodChunk.WIDTH);
|
|
||||||
|
|
||||||
LodChunk lod = lodDimension.getLodFromCoordinates(chunkX, chunkZ); // new LodChunk(); //
|
|
||||||
if (lod == null)
|
|
||||||
{
|
|
||||||
// note: for some reason if any color or lod object are set here
|
|
||||||
// it causes the game to use 100% gpu, all of it undefined in the debug menu
|
|
||||||
// and drop to ~6 fps.
|
|
||||||
// colorArray[i][j] = null;
|
|
||||||
// lodArray[i][j] = null;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Color c = new Color(
|
|
||||||
(lod.colors[ColorDirection.TOP.value].getRed()),
|
|
||||||
(lod.colors[ColorDirection.TOP.value].getGreen()),
|
|
||||||
(lod.colors[ColorDirection.TOP.value].getBlue()),
|
|
||||||
lod.colors[ColorDirection.TOP.value].getAlpha());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!debugging)
|
|
||||||
{
|
|
||||||
// add the color to the array
|
|
||||||
colorArray[i][j] = c;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if debugging draw the squares as a black and white checker board
|
|
||||||
if ((chunkX + chunkZ) % 2 == 0)
|
|
||||||
c = white;
|
|
||||||
else
|
|
||||||
c = black;
|
|
||||||
// draw the first square as red
|
|
||||||
if (i == 0 && j == 0)
|
|
||||||
c = red;
|
|
||||||
|
|
||||||
colorArray[i][j] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// add the new box to the array
|
|
||||||
int topPoint = getLodHeightPoint(lod.top);
|
|
||||||
int bottomPoint = getLodHeightPoint(lod.bottom);
|
|
||||||
|
|
||||||
// don't draw an LOD if it is empty
|
|
||||||
if (topPoint == -1 && bottomPoint == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
lodArray[i][j] = new AxisAlignedBB(0, bottomPoint, 0, LodChunk.WIDTH, topPoint, LodChunk.WIDTH).offset(xOffset, yOffset, zOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// replace the buffers used to draw and build,
|
||||||
|
// this is only done when the createLodBufferGenerationThread
|
||||||
|
// has finished executing on a parallel thread.
|
||||||
|
if (switchBuffers)
|
||||||
|
{
|
||||||
|
swapBuffers();
|
||||||
|
switchBuffers = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -320,18 +266,17 @@ public class LodRenderer
|
|||||||
//===========================//
|
//===========================//
|
||||||
|
|
||||||
// set the required open GL settings
|
// set the required open GL settings
|
||||||
|
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
|
||||||
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||||
GL11.glLineWidth(2.0f);
|
GL11.glLineWidth(2.0f);
|
||||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||||
GL11.glEnable(GL11.GL_CULL_FACE);
|
GL11.glEnable(GL11.GL_CULL_FACE);
|
||||||
|
|
||||||
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
|
// move the LODs so they are in the correct place relative to the camera
|
||||||
|
|
||||||
GlStateManager.translate(-cameraX, -cameraY, -cameraZ);
|
GlStateManager.translate(-cameraX, -cameraY, -cameraZ);
|
||||||
|
|
||||||
setProjectionMatrix(partialTicks);
|
setProjectionMatrix(partialTicks);
|
||||||
setupLighting(partialTicks);
|
setupLighting(partialTicks);
|
||||||
setupBufferThreads(lodArray);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -342,30 +287,31 @@ public class LodRenderer
|
|||||||
// rendering //
|
// rendering //
|
||||||
//===========//
|
//===========//
|
||||||
|
|
||||||
mc.mcProfiler.endStartSection("LOD build buffer");
|
|
||||||
if (regen)
|
|
||||||
generateLodBuffers(lodArray, colorArray, LodConfig.fogDistance);
|
|
||||||
|
|
||||||
switch(LodConfig.fogDistance)
|
switch(LodConfig.fogDistance)
|
||||||
{
|
{
|
||||||
case NEAR_AND_FAR:
|
case NEAR_AND_FAR:
|
||||||
mc.mcProfiler.endStartSection("LOD draw setup");
|
// when drawing NEAR_AND_FAR fog we need 2 draw
|
||||||
setupFog(FogDistance.NEAR, reflectionHandler.getFogQuality());
|
// calls since fog can only go in one direction at a time
|
||||||
sendLodsToGpuAndDraw(nearBuffers);
|
|
||||||
|
|
||||||
mc.mcProfiler.endStartSection("LOD draw setup");
|
mc.mcProfiler.endStartSection("LOD draw");
|
||||||
setupFog(FogDistance.FAR, reflectionHandler.getFogQuality());
|
|
||||||
sendLodsToGpuAndDraw(farBuffers);
|
|
||||||
break;
|
|
||||||
case NEAR:
|
|
||||||
mc.mcProfiler.endStartSection("LOD draw setup");
|
|
||||||
setupFog(FogDistance.NEAR, reflectionHandler.getFogQuality());
|
setupFog(FogDistance.NEAR, reflectionHandler.getFogQuality());
|
||||||
sendLodsToGpuAndDraw(nearBuffers);
|
sendLodsToGpuAndDraw(drawableNearBuffers);
|
||||||
break;
|
|
||||||
case FAR:
|
mc.mcProfiler.endStartSection("LOD draw");
|
||||||
mc.mcProfiler.endStartSection("LOD draw setup");
|
|
||||||
setupFog(FogDistance.FAR, reflectionHandler.getFogQuality());
|
setupFog(FogDistance.FAR, reflectionHandler.getFogQuality());
|
||||||
sendLodsToGpuAndDraw(farBuffers);
|
sendLodsToGpuAndDraw(drawableFarBuffers);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NEAR:
|
||||||
|
mc.mcProfiler.endStartSection("LOD draw");
|
||||||
|
setupFog(FogDistance.NEAR, reflectionHandler.getFogQuality());
|
||||||
|
sendLodsToGpuAndDraw(drawableNearBuffers);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FAR:
|
||||||
|
mc.mcProfiler.endStartSection("LOD draw");
|
||||||
|
setupFog(FogDistance.FAR, reflectionHandler.getFogQuality());
|
||||||
|
sendLodsToGpuAndDraw(drawableFarBuffers);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,14 +325,13 @@ public class LodRenderer
|
|||||||
|
|
||||||
mc.mcProfiler.endStartSection("LOD cleanup");
|
mc.mcProfiler.endStartSection("LOD cleanup");
|
||||||
|
|
||||||
|
|
||||||
// this must be done otherwise other parts of the screen may be drawn with a fog effect
|
// this must be done otherwise other parts of the screen may be drawn with a fog effect
|
||||||
// IE the GUI
|
// IE the GUI
|
||||||
GlStateManager.disableFog();
|
GlStateManager.disableFog();
|
||||||
|
|
||||||
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
|
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
|
||||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||||
GL11.glDisable(GL11.GL_LIGHT1);
|
GL11.glDisable(LOD_GL_LIGHT_NUMBER);
|
||||||
GL11.glDisable(GL11.GL_COLOR_MATERIAL);
|
GL11.glDisable(GL11.GL_COLOR_MATERIAL);
|
||||||
|
|
||||||
// change the perspective matrix back to prevent incompatibilities
|
// change the perspective matrix back to prevent incompatibilities
|
||||||
@@ -398,112 +343,34 @@ public class LodRenderer
|
|||||||
previousChunkRenderDistance = mc.gameSettings.renderDistanceChunks;
|
previousChunkRenderDistance = mc.gameSettings.renderDistanceChunks;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// This is about how long this whole process should take
|
|
||||||
// 16 ms = 60 hz
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
long endTime = System.nanoTime();
|
|
||||||
|
|
||||||
// end of profiler tracking
|
// end of profiler tracking
|
||||||
mc.mcProfiler.endSection();
|
mc.mcProfiler.endSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* draw an array of cubes (or squares) with the given colors.
|
* This is where the actual drawing happens.
|
||||||
* @param lods bounding boxes to draw
|
*
|
||||||
* @param colors color of each box to draw
|
* @param buffers the buffers sent to the GPU to draw
|
||||||
*/
|
*/
|
||||||
private void generateLodBuffers(AxisAlignedBB[][] lods, Color[][] colors, FogDistance fogDistance)
|
private void sendLodsToGpuAndDraw(BufferBuilder[] buffers)
|
||||||
{
|
|
||||||
List<Future<NearFarBuffer>> bufferFutures = new ArrayList<>();
|
|
||||||
// TODO this should change based on whether we are using near/far or both fog settings
|
|
||||||
bufferMaxCapacity = (lods.length * lods.length * (6 * 4 * ((3 * 4) + (4 * 4)))) / numbBufferThreads;
|
|
||||||
|
|
||||||
for(int i = 0; i < numbBufferThreads; i++)
|
|
||||||
{
|
|
||||||
if (nearBuffers[i] == null || previousChunkRenderDistance != mc.gameSettings.renderDistanceChunks)
|
|
||||||
{
|
|
||||||
nearBuffers[i] = ByteBuffer.allocateDirect(bufferMaxCapacity);
|
|
||||||
nearBuffers[i].order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
|
|
||||||
farBuffers[i] = ByteBuffer.allocateDirect(bufferMaxCapacity);
|
|
||||||
farBuffers[i].order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
|
|
||||||
clearBytes = new byte[bufferMaxCapacity];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (regen)
|
|
||||||
{
|
|
||||||
// this is the best way I could find to
|
|
||||||
// overwrite the old data
|
|
||||||
// (which needs to be done otherwise old
|
|
||||||
// LODs may be drawn)
|
|
||||||
nearBuffers[i].clear();
|
|
||||||
nearBuffers[i].put(clearBytes);
|
|
||||||
nearBuffers[i].clear();
|
|
||||||
|
|
||||||
farBuffers[i].clear();
|
|
||||||
farBuffers[i].put(clearBytes);
|
|
||||||
farBuffers[i].clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
int pos = bufferBuilder.getByteBuffer().position();
|
|
||||||
nearBuffers[i].position(pos);
|
|
||||||
farBuffers[i].position(pos);
|
|
||||||
|
|
||||||
bufferThreads.get(i).setNewData(nearBuffers[i], farBuffers[i], fogDistance, lods, colors, i, numbBufferThreads);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bufferFutures = bufferThreadPool.invokeAll(bufferThreads);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e)
|
|
||||||
{
|
|
||||||
// this should never happen, but just in case
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < numbBufferThreads; i++)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
nearBuffers[i] = bufferFutures.get(i).get().nearBuffer;
|
|
||||||
farBuffers[i] = bufferFutures.get(i).get().farBuffer;
|
|
||||||
}
|
|
||||||
catch(CancellationException | ExecutionException| InterruptedException e)
|
|
||||||
{
|
|
||||||
// this should never happen, but just in case
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendLodsToGpuAndDraw(ByteBuffer[] buffers)
|
|
||||||
{
|
{
|
||||||
for(int i = 0; i < numbBufferThreads; i++)
|
for(int i = 0; i < numbBufferThreads; i++)
|
||||||
{
|
{
|
||||||
int pos = bufferBuilder.getByteBuffer().position();
|
if (shouldDrawBuffer[i])
|
||||||
buffers[i].position(pos);
|
{
|
||||||
|
int pos = bufferBuilder.getByteBuffer().position();
|
||||||
bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
|
buffers[i].getByteBuffer().position(pos);
|
||||||
bufferBuilder.getByteBuffer().clear();
|
|
||||||
bufferBuilder.putBulkData(buffers[i]);
|
bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
|
||||||
|
bufferBuilder.getByteBuffer().clear();
|
||||||
mc.mcProfiler.endStartSection("LOD draw");
|
// replace the data in bufferBuilder with the data from the given buffer
|
||||||
tessellator.draw();
|
bufferBuilder.putBulkData(buffers[i].getByteBuffer());
|
||||||
mc.mcProfiler.endStartSection("LOD draw setup");
|
|
||||||
|
tessellator.draw();
|
||||||
bufferBuilder.getByteBuffer().clear(); // this is required otherwise nothing is drawn
|
|
||||||
|
bufferBuilder.getByteBuffer().clear(); // this is required otherwise nothing is drawn
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,7 +394,7 @@ public class LodRenderer
|
|||||||
|
|
||||||
if(fogDistance == FogDistance.NEAR_AND_FAR)
|
if(fogDistance == FogDistance.NEAR_AND_FAR)
|
||||||
{
|
{
|
||||||
throw new IllegalArgumentException("setupFog only accepts NEAR or FAR fog distances.");
|
throw new IllegalArgumentException("setupFog doesn't accept the NEAR_AND_FAR fog distance.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// the multipliers are percentages
|
// the multipliers are percentages
|
||||||
@@ -577,7 +444,6 @@ public class LodRenderer
|
|||||||
/**
|
/**
|
||||||
* create a new projection matrix and send it over to the GPU
|
* create a new projection matrix and send it over to the GPU
|
||||||
* @param partialTicks how many ticks into the frame we are
|
* @param partialTicks how many ticks into the frame we are
|
||||||
* @return true if the matrix was successfully created and sent to the GPU, false otherwise
|
|
||||||
*/
|
*/
|
||||||
private void setProjectionMatrix(float partialTicks)
|
private void setProjectionMatrix(float partialTicks)
|
||||||
{
|
{
|
||||||
@@ -609,36 +475,62 @@ public class LodRenderer
|
|||||||
float gammaMultiplyer = (mc.gameSettings.gammaSetting * 0.5f + 0.5f);
|
float gammaMultiplyer = (mc.gameSettings.gammaSetting * 0.5f + 0.5f);
|
||||||
float lightStrength = sunBrightness * skyHasLight * gammaMultiplyer;
|
float lightStrength = sunBrightness * skyHasLight * gammaMultiplyer;
|
||||||
float lightAmbient[] = {lightStrength, lightStrength, lightStrength, 1.0f};
|
float lightAmbient[] = {lightStrength, lightStrength, lightStrength, 1.0f};
|
||||||
|
|
||||||
ByteBuffer temp = ByteBuffer.allocateDirect(16);
|
ByteBuffer temp = ByteBuffer.allocateDirect(16);
|
||||||
temp.order(ByteOrder.nativeOrder());
|
temp.order(ByteOrder.nativeOrder());
|
||||||
GL11.glLight(GL11.GL_LIGHT1, GL11.GL_AMBIENT, (FloatBuffer) temp.asFloatBuffer().put(lightAmbient).flip());
|
GL11.glLight(LOD_GL_LIGHT_NUMBER, GL11.GL_AMBIENT, (FloatBuffer) temp.asFloatBuffer().put(lightAmbient).flip());
|
||||||
GL11.glEnable(GL11.GL_LIGHT1); // Enable the above lighting
|
GL11.glEnable(LOD_GL_LIGHT_NUMBER); // Enable the above lighting
|
||||||
|
|
||||||
GlStateManager.enableLighting();
|
GlStateManager.enableLighting();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
private void setupBufferThreads(AxisAlignedBB[][] lods)
|
* create the BuildBufferThreads
|
||||||
|
*/
|
||||||
|
private void setupBufferThreads()
|
||||||
{
|
{
|
||||||
if (numbBufferThreads != bufferThreads.size())
|
bufferThreads.clear();
|
||||||
|
for(int i = 0; i < numbBufferThreads; i++)
|
||||||
|
bufferThreads.add(new BuildBufferThread());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create all buffers that will be used.
|
||||||
|
*/
|
||||||
|
private void setupBuffers(int numbChunksWide)
|
||||||
|
{
|
||||||
|
drawableNearBuffers = new BufferBuilder[numbBufferThreads];
|
||||||
|
drawableFarBuffers = new BufferBuilder[numbBufferThreads];
|
||||||
|
|
||||||
|
buildableNearBuffers = new BufferBuilder[numbBufferThreads];
|
||||||
|
buildableFarBuffers = new BufferBuilder[numbBufferThreads];
|
||||||
|
|
||||||
|
|
||||||
|
// calculate how many chunks wide, at most
|
||||||
|
// any thread will have to generate
|
||||||
|
int biggestWidth = -1;
|
||||||
|
int[] loads = calculateCpuLoadBalance(numbChunksWide, numbBufferThreads);
|
||||||
|
for(int i : loads)
|
||||||
|
if (i > biggestWidth)
|
||||||
|
biggestWidth = i;
|
||||||
|
|
||||||
|
|
||||||
|
// calculate the max amount of storage needed (in bytes)
|
||||||
|
// by any singular buffer
|
||||||
|
// NOTE: most buffers won't use the full amount, but this should prevent
|
||||||
|
// them from needing to allocate more memory (which is a slow progress)
|
||||||
|
int bufferMaxCapacity = (numbChunksWide * biggestWidth * (6 * 4 * ((3 * 4) + (4 * 4))));
|
||||||
|
|
||||||
|
for(int i = 0; i < numbBufferThreads; i++)
|
||||||
{
|
{
|
||||||
bufferMaxCapacity = (lods.length * lods.length * (6 * 4 * ((3 * 4) + (4 * 4)))) / numbBufferThreads;
|
// TODO complain or do something when memory is too low
|
||||||
clearBytes = new byte[bufferMaxCapacity];
|
// currently the VM will just crash and complain there is no more memory
|
||||||
|
// issue #4
|
||||||
|
drawableNearBuffers[i] = new BufferBuilder(bufferMaxCapacity);
|
||||||
|
drawableFarBuffers[i] = new BufferBuilder(bufferMaxCapacity);
|
||||||
|
|
||||||
bufferThreads.clear();
|
buildableNearBuffers[i] = new BufferBuilder(bufferMaxCapacity);
|
||||||
for(int i = 0; i < numbBufferThreads; i++)
|
buildableFarBuffers[i] = new BufferBuilder(bufferMaxCapacity);
|
||||||
bufferThreads.add(new BuildBufferThread());
|
|
||||||
regen = true;
|
|
||||||
|
|
||||||
for(int i = 0; i < maxNumbThreads; i++)
|
|
||||||
{
|
|
||||||
nearBuffers[i] = ByteBuffer.allocateDirect(bufferMaxCapacity);
|
|
||||||
nearBuffers[i].order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
|
|
||||||
farBuffers[i] = ByteBuffer.allocateDirect(bufferMaxCapacity);
|
|
||||||
farBuffers[i].order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,22 +538,275 @@ public class LodRenderer
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//======================//
|
||||||
|
// Other Misc Functions //
|
||||||
|
//======================//
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns -1 if there are no valid points
|
* @Returns -1 if there are no valid points
|
||||||
*/
|
*/
|
||||||
private int getLodHeightPoint(short[] heightPoints)
|
private int getValidHeightPoint(short[] heightPoints)
|
||||||
{
|
{
|
||||||
if (heightPoints[LodLocation.NE.value] != -1)
|
if (heightPoints[LodCorner.NE.value] != -1)
|
||||||
return heightPoints[LodLocation.NE.value];
|
return heightPoints[LodCorner.NE.value];
|
||||||
if (heightPoints[LodLocation.NW.value] != -1)
|
if (heightPoints[LodCorner.NW.value] != -1)
|
||||||
return heightPoints[LodLocation.NW.value];
|
return heightPoints[LodCorner.NW.value];
|
||||||
if (heightPoints[LodLocation.SE.value] != -1)
|
if (heightPoints[LodCorner.SE.value] != -1)
|
||||||
return heightPoints[LodLocation.NE.value];
|
return heightPoints[LodCorner.NE.value];
|
||||||
return heightPoints[LodLocation.NE.value];
|
return heightPoints[LodCorner.NE.value];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a thread to asynchronously generate LOD buffers
|
||||||
|
* centered around the given camera X and Z.
|
||||||
|
* <br>
|
||||||
|
* This thread will write to the drawableNearBuffers and drawableFarBuffers.
|
||||||
|
* <br>
|
||||||
|
* After the buildable buffers have been generated they must be
|
||||||
|
* swapped with the drawable buffers to be drawn.
|
||||||
|
*/
|
||||||
|
private Thread createLodBufferGenerationThread(double playerX, double playerZ,
|
||||||
|
int numbChunksWide)
|
||||||
|
{
|
||||||
|
// this is where we store the points for each LOD object
|
||||||
|
AxisAlignedBB lodArray[][] = new AxisAlignedBB[numbChunksWide][numbChunksWide];
|
||||||
|
// this is where we store the color for each LOD object
|
||||||
|
Color colorArray[][] = new Color[numbChunksWide][numbChunksWide];
|
||||||
|
|
||||||
|
int alpha = 255; // 0 - 255
|
||||||
|
Color red = new Color(255, 0, 0, alpha);
|
||||||
|
Color black = new Color(0, 0, 0, alpha);
|
||||||
|
Color white = new Color(255, 255, 255, alpha);
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
Color invisible = new Color(0,0,0,0);
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
Color error = new Color(255, 0, 225, alpha); // bright pink
|
||||||
|
|
||||||
|
// this seemingly useless math is required,
|
||||||
|
// just using (int) camera doesn't work
|
||||||
|
int playerXChunkOffset = ((int) playerX / LodChunk.WIDTH) * LodChunk.WIDTH;
|
||||||
|
int playerZChunkOffset = ((int) playerZ / LodChunk.WIDTH) * LodChunk.WIDTH;
|
||||||
|
// this is where we will start drawing squares
|
||||||
|
// (exactly half the total width)
|
||||||
|
int startX = (-LodChunk.WIDTH * (numbChunksWide / 2)) + playerXChunkOffset;
|
||||||
|
int startZ = (-LodChunk.WIDTH * (numbChunksWide / 2)) + playerZChunkOffset;
|
||||||
|
|
||||||
|
Thread t = new Thread(()->
|
||||||
|
{
|
||||||
|
// x axis
|
||||||
|
for (int i = 0; i < numbChunksWide; i++)
|
||||||
|
{
|
||||||
|
// z axis
|
||||||
|
for (int j = 0; j < numbChunksWide; j++)
|
||||||
|
{
|
||||||
|
// skip the middle
|
||||||
|
// (As the player moves some chunks will overlap or be missing,
|
||||||
|
// this is just how chunk loading/unloading works. This can hopefully
|
||||||
|
// be hidden with careful use of fog)
|
||||||
|
int middle = (numbChunksWide / 2);
|
||||||
|
if (isCoordInCenterArea(i, j, middle))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// set where this square will be drawn in the world
|
||||||
|
double xOffset = (LodChunk.WIDTH * i) + // offset by the number of LOD blocks
|
||||||
|
startX; // offset so the center LOD block is centered underneath the player
|
||||||
|
double yOffset = 0;
|
||||||
|
double zOffset = (LodChunk.WIDTH * j) + startZ;
|
||||||
|
|
||||||
|
int chunkX = i + (startX / LodChunk.WIDTH);
|
||||||
|
int chunkZ = j + (startZ / LodChunk.WIDTH);
|
||||||
|
|
||||||
|
LodChunk lod = lodDimension.getLodFromCoordinates(chunkX, chunkZ);
|
||||||
|
if (lod == null)
|
||||||
|
{
|
||||||
|
// note: for some reason if any color or lod objects are set here
|
||||||
|
// it causes the game to use 100% gpu;
|
||||||
|
// undefined in the debug menu
|
||||||
|
// and drop to ~6 fps.
|
||||||
|
colorArray[i][j] = null;
|
||||||
|
lodArray[i][j] = null;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color c = new Color(
|
||||||
|
(lod.colors[ColorDirection.TOP.value].getRed()),
|
||||||
|
(lod.colors[ColorDirection.TOP.value].getGreen()),
|
||||||
|
(lod.colors[ColorDirection.TOP.value].getBlue()),
|
||||||
|
lod.colors[ColorDirection.TOP.value].getAlpha());
|
||||||
|
|
||||||
|
if (!debugging)
|
||||||
|
{
|
||||||
|
// add the color to the array
|
||||||
|
colorArray[i][j] = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if debugging draw the squares as a black and white checker board
|
||||||
|
if ((chunkX + chunkZ) % 2 == 0)
|
||||||
|
c = white;
|
||||||
|
else
|
||||||
|
c = black;
|
||||||
|
// draw the first square as red
|
||||||
|
if (i == 0 && j == 0)
|
||||||
|
c = red;
|
||||||
|
|
||||||
|
colorArray[i][j] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// add the new box to the array
|
||||||
|
int topPoint = getValidHeightPoint(lod.top);
|
||||||
|
int bottomPoint = getValidHeightPoint(lod.bottom);
|
||||||
|
|
||||||
|
// don't draw an LOD if it is empty
|
||||||
|
if (topPoint == -1 && bottomPoint == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
lodArray[i][j] = new AxisAlignedBB(0, bottomPoint, 0, LodChunk.WIDTH, topPoint, LodChunk.WIDTH).offset(xOffset, yOffset, zOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generateLodBuffers(lodArray, colorArray, LodConfig.fogDistance);
|
||||||
|
|
||||||
|
regenerating = false;
|
||||||
|
switchBuffers = true;
|
||||||
|
});
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* draw an array of boxes with the given colors.
|
||||||
|
* <br><br>
|
||||||
|
* Currently only one color per box is supported.
|
||||||
|
*
|
||||||
|
* @param lods bounding boxes to draw
|
||||||
|
* @param colors color of each box to draw
|
||||||
|
*/
|
||||||
|
private void generateLodBuffers(AxisAlignedBB[][] lods, Color[][] colors, FogDistance fogDistance)
|
||||||
|
{
|
||||||
|
List<Future<NearFarBuffer>> bufferFutures = new ArrayList<>();
|
||||||
|
ArrayList<BuildBufferThread> threadsToRun = new ArrayList<>();
|
||||||
|
|
||||||
|
int indexToStart = 0;
|
||||||
|
int[] threadLoads = calculateCpuLoadBalance(lods.length, numbBufferThreads);
|
||||||
|
|
||||||
|
// update the information that the bufferThreads are using
|
||||||
|
for(int i = 0; i < numbBufferThreads; i++)
|
||||||
|
{
|
||||||
|
// if we have more threads than LOD rows to generate
|
||||||
|
// don't send the threads to the CPU
|
||||||
|
if (threadLoads[i] != 0)
|
||||||
|
{
|
||||||
|
// update this thread with the latest information
|
||||||
|
bufferThreads.get(i).
|
||||||
|
setNewData(buildableNearBuffers[i], buildableFarBuffers[i],
|
||||||
|
fogDistance, lods, colors, indexToStart, threadLoads[i]);
|
||||||
|
indexToStart += threadLoads[i];
|
||||||
|
|
||||||
|
// add this thread to the list of threads we are going to run
|
||||||
|
threadsToRun.add(bufferThreads.get(i));
|
||||||
|
|
||||||
|
shouldDrawBuffer[i] = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shouldDrawBuffer[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// run all the bufferThreads and get their results
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bufferFutures = bufferThreadPool.invokeAll(threadsToRun);
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
// this should never happen, but just in case
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// update our buildable buffers
|
||||||
|
for(int i = 0; i < numbBufferThreads; i++)
|
||||||
|
{
|
||||||
|
// only replace buffers that actually generated something
|
||||||
|
if (threadLoads[i] != 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
buildableNearBuffers[i] = bufferFutures.get(i).get().nearBuffer;
|
||||||
|
buildableFarBuffers[i] = bufferFutures.get(i).get().farBuffer;
|
||||||
|
}
|
||||||
|
catch(CancellationException | ExecutionException| InterruptedException e)
|
||||||
|
{
|
||||||
|
// this should never happen, but just in case
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap buildable and drawable buffers.
|
||||||
|
*/
|
||||||
|
private void swapBuffers()
|
||||||
|
{
|
||||||
|
for(int i = 0; i < buildableNearBuffers.length; i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BufferBuilder tmp = buildableNearBuffers[i];
|
||||||
|
buildableNearBuffers[i] = drawableNearBuffers[i];
|
||||||
|
drawableNearBuffers[i] = tmp;
|
||||||
|
|
||||||
|
tmp = buildableFarBuffers[i];
|
||||||
|
buildableFarBuffers[i] = drawableFarBuffers[i];
|
||||||
|
drawableFarBuffers[i] = tmp;
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the given coordinate is in the loaded area of the world.
|
||||||
|
* @param centerCoordinate the center of the loaded world
|
||||||
|
*/
|
||||||
|
private boolean isCoordInCenterArea(int i, int j, int centerCoordinate)
|
||||||
|
{
|
||||||
|
return (i >= centerCoordinate - mc.gameSettings.renderDistanceChunks
|
||||||
|
&& i <= centerCoordinate + mc.gameSettings.renderDistanceChunks)
|
||||||
|
&&
|
||||||
|
(j >= centerCoordinate - mc.gameSettings.renderDistanceChunks
|
||||||
|
&& j <= centerCoordinate + mc.gameSettings.renderDistanceChunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a simple implementation of the pigeon hole
|
||||||
|
* principle to try and give each BuildBufferThread a balanced load.
|
||||||
|
*
|
||||||
|
* @returns an array of ints where each int is how many rows
|
||||||
|
* that BuildBufferThread should generate
|
||||||
|
*/
|
||||||
|
private int[] calculateCpuLoadBalance(int numbOfItems, int numbOfThreads)
|
||||||
|
{
|
||||||
|
int[] cpuLoad = new int[numbOfThreads];
|
||||||
|
|
||||||
|
for(int i = 0; i < numbOfItems; i++)
|
||||||
|
cpuLoad[i % numbOfThreads]++;
|
||||||
|
|
||||||
|
return cpuLoad;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package com.backsun.lod.renderer;
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This holds miscellaneous helper code
|
|
||||||
* to be used in the rendering process.
|
|
||||||
*
|
|
||||||
* @author James Seibel
|
|
||||||
* @version 2-13-2021
|
|
||||||
*/
|
|
||||||
public class RenderUtil
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns if the given coordinate is in the loaded area of the world.
|
|
||||||
* @param centerCoordinate the center of the loaded world
|
|
||||||
*/
|
|
||||||
public static boolean isCoordinateInLoadedArea(int i, int j, int centerCoordinate)
|
|
||||||
{
|
|
||||||
Minecraft mc = Minecraft.getMinecraft();
|
|
||||||
|
|
||||||
return (i >= centerCoordinate - mc.gameSettings.renderDistanceChunks
|
|
||||||
&& i <= centerCoordinate + mc.gameSettings.renderDistanceChunks)
|
|
||||||
&&
|
|
||||||
(j >= centerCoordinate - mc.gameSettings.renderDistanceChunks
|
|
||||||
&& j <= centerCoordinate + mc.gameSettings.renderDistanceChunks);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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).
|
|
||||||
*/
|
|
||||||
public static boolean isCoordinateInNearFogArea(int i, int j, int lodRadius)
|
|
||||||
{
|
|
||||||
int halfRadius = lodRadius / 2;
|
|
||||||
|
|
||||||
return (i >= lodRadius - halfRadius
|
|
||||||
&& i <= lodRadius + halfRadius)
|
|
||||||
&&
|
|
||||||
(j >= lodRadius - halfRadius
|
|
||||||
&& j <= lodRadius + halfRadius);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -9,6 +9,7 @@ import net.minecraftforge.fml.common.Mod;
|
|||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* This is linked to Forge's mod config GUI.
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 02-14-2021
|
* @version 02-14-2021
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.backsun.lod.util;
|
package com.backsun.lod.util;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* This holds meta information about the mod.
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 04-16-2020
|
* @version 04-16-2020
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.backsun.lod.util.enums;
|
package com.backsun.lod.util.enums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* TOP, N, S, E, W, BOTTOM
|
||||||
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 10-17-2020
|
* @version 10-17-2020
|
||||||
*
|
|
||||||
* TOP, N, S, E, W, BOTTOM
|
|
||||||
*/
|
*/
|
||||||
public enum ColorDirection
|
public enum ColorDirection
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
package com.backsun.lod.util.enums;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author James Seibel
|
|
||||||
* @version 1-23-2021
|
|
||||||
*/
|
|
||||||
public enum DrawMode
|
|
||||||
{
|
|
||||||
/** Draw the LOD objects in groups.
|
|
||||||
* <br>
|
|
||||||
* <br>
|
|
||||||
* Fancy fog: render the center and outside LOD
|
|
||||||
* objects in 2 different groups.
|
|
||||||
* <br>
|
|
||||||
* Fast fog: render all LOD objects at one time.
|
|
||||||
*/
|
|
||||||
BATCH(0),
|
|
||||||
|
|
||||||
/** Draw each LOD objects separately.
|
|
||||||
* <br>
|
|
||||||
* <br>
|
|
||||||
* Not suggested normally since draw calls are GPU expensive.
|
|
||||||
*/
|
|
||||||
INDIVIDUAL(5);
|
|
||||||
|
|
||||||
public final int value;
|
|
||||||
|
|
||||||
private DrawMode(int newValue)
|
|
||||||
{
|
|
||||||
value = newValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,9 +8,9 @@ package com.backsun.lod.util.enums;
|
|||||||
*/
|
*/
|
||||||
public enum FogDistance
|
public enum FogDistance
|
||||||
{
|
{
|
||||||
/** valid for both fast and fancy fog qualities. */
|
/** good for fast or fancy fog qualities. */
|
||||||
NEAR,
|
NEAR,
|
||||||
/** valid for both fast and fancy fog qualities. */
|
/** good for fast or fancy fog qualities. */
|
||||||
FAR,
|
FAR,
|
||||||
/** only looks good if the fog quality is set to Fancy. */
|
/** only looks good if the fog quality is set to Fancy. */
|
||||||
NEAR_AND_FAR;
|
NEAR_AND_FAR;
|
||||||
|
|||||||
+3
-4
@@ -1,13 +1,12 @@
|
|||||||
package com.backsun.lod.util.enums;
|
package com.backsun.lod.util.enums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* NE, SE, SW, NW
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 1-20-2020
|
* @version 1-20-2020
|
||||||
*
|
|
||||||
* NE, SE, SW, NW
|
|
||||||
*/
|
*/
|
||||||
public enum LodLocation
|
public enum LodCorner
|
||||||
{
|
{
|
||||||
// used for position
|
// used for position
|
||||||
|
|
||||||
@@ -22,7 +21,7 @@ public enum LodLocation
|
|||||||
|
|
||||||
public final int value;
|
public final int value;
|
||||||
|
|
||||||
private LodLocation(int newValue)
|
private LodCorner(int newValue)
|
||||||
{
|
{
|
||||||
value = newValue;
|
value = newValue;
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"modid": "lod",
|
"modid": "lod",
|
||||||
"name": "Level Of Details",
|
"name": "Level Of Details",
|
||||||
"description": "Generates and renders simplified chunks beyond the normal view distance, at a low performance cost.",
|
"description": "Generates and renders simplified chunks beyond the normal view distance, at a low performance cost.",
|
||||||
"version": "0.1",
|
"version": "1.0",
|
||||||
"mcversion": "1.12.2",
|
"mcversion": "1.12.2",
|
||||||
"url": "",
|
"url": "",
|
||||||
"updateUrl": "",
|
"updateUrl": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user