Compare commits
103 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 17e375bc61 | |||
| a2c8c90a5e | |||
| b376014df8 | |||
| b9ee54f6ad | |||
| 6c7e1900a3 | |||
| 6f929f40f9 | |||
| b6a8930855 | |||
| 7a91b258de | |||
| 35bef76aeb | |||
| 780d0ad9fb | |||
| c0d5dd6dee | |||
| 3e87e625ba | |||
| 56f9403859 | |||
| 8259c79e9c | |||
| be1e2fe7e6 | |||
| 609ee5c70d | |||
| 207cab9a0f | |||
| c80b025ac1 | |||
| 8610917b86 | |||
| fae4bee871 | |||
| b9608498a2 | |||
| fe59c6b0c9 | |||
| b082b048d6 | |||
| 91712cee2a | |||
| 5adfbb2dee | |||
| ec32d09468 | |||
| 919990820e | |||
| 5cc31efa12 | |||
| 5f48b41693 | |||
| 9530eea287 | |||
| ebbf304c94 | |||
| 7c8ac0c2ff | |||
| eefad5e052 | |||
| 9a1e6e29d4 | |||
| 62ab450d98 | |||
| b4a5da4a74 | |||
| ed82480c89 | |||
| 82449c5edc | |||
| b165726bc9 | |||
| 11910d0f28 | |||
| f66e27b077 | |||
| 835beb607d | |||
| c4e2d3fb0f | |||
| eb3d8d9da5 | |||
| 151d548099 | |||
| c5cdc2760f | |||
| a663bf9f19 | |||
| 7ddd48d132 | |||
| ce10a43cc6 | |||
| 5476af5bb3 | |||
| 25d2cfd7b8 | |||
| 1b754387e0 | |||
| bcad40069f | |||
| 5aa9061006 | |||
| 873e8cec57 | |||
| f6f96c3aea | |||
| aeed672295 | |||
| 832fbe6d15 | |||
| 03deddf666 | |||
| d06413d1b4 | |||
| 8afa50d585 | |||
| 9f28f1f812 | |||
| 985388fd90 | |||
| e27e10082a | |||
| 4e510d96fc | |||
| c0ec02f062 | |||
| bd27a96bde | |||
| d6aeaf8e9d | |||
| 2b9bba4aa7 | |||
| 58b0991891 | |||
| 59cbbef327 | |||
| 7047c81a2b | |||
| 6e2ab47359 | |||
| f879332e1d | |||
| 6fcafecc61 | |||
| a5af93aef1 | |||
| 4b84fd2a67 | |||
| 924efc0cbd | |||
| 288457b5bd | |||
| d29fa86de6 | |||
| 97be227e3d | |||
| 909d6a54c3 | |||
| 228b6a80dc | |||
| 6936a5f96f | |||
| 740560a50a | |||
| 47c28f0f37 | |||
| 1c859cd7da | |||
| e4a97dd76d | |||
| 4fd1e5ea06 | |||
| 6039aeabde | |||
| 17a384f074 | |||
| 25e8f5ec6a | |||
| eac8cacd42 | |||
| 75193d76a3 | |||
| aa24fd341e | |||
| 81adade05b | |||
| e3808dc986 | |||
| d669b2a1fe | |||
| 2bd8dab240 | |||
| 2b423c2edd | |||
| 1a4faf4bdd | |||
| b70829aceb | |||
| bba771d376 |
+39
-71
@@ -3,16 +3,13 @@ image: gradle:eclipse-temurin
|
|||||||
|
|
||||||
# all stages need to be defined here
|
# all stages need to be defined here
|
||||||
stages:
|
stages:
|
||||||
- gradleSetup
|
- build_18-1
|
||||||
- build
|
- build_18-2
|
||||||
- merge
|
# - zip_artifacts
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
# Disable the Gradle daemon for Continuous Integration servers as correctness
|
# If we have correctness issues when compiling this can be set to false
|
||||||
# is usually a priority over speed in CI environments. Using a fresh
|
GRADLE_OPTS: "-Dorg.gradle.daemon=true"
|
||||||
# runtime for each build is more reliable since the runtime is completely
|
|
||||||
# isolated from any previous builds.
|
|
||||||
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
|
|
||||||
# Pull core when building
|
# Pull core when building
|
||||||
GIT_SUBMODULE_STRATEGY: recursive
|
GIT_SUBMODULE_STRATEGY: recursive
|
||||||
|
|
||||||
@@ -23,91 +20,62 @@ before_script:
|
|||||||
- echo GE_JOB_ID=$CI_JOB_ID >> generate_jars.env
|
- echo GE_JOB_ID=$CI_JOB_ID >> generate_jars.env
|
||||||
|
|
||||||
|
|
||||||
|
# 1.18.1 build
|
||||||
|
build_18-1:
|
||||||
# first stage
|
stage: build_18-1
|
||||||
# This prevents us from re-downloading Gradle every stage
|
script: ./gradlew build -PmcVer=1.18.1 --gradle-user-home cache/; ./gradlew merge --gradle-user-home cache/
|
||||||
gradleSetup:
|
|
||||||
stage: gradleSetup
|
|
||||||
script: ./gradlew --build-cache --gradle-user-home cache/ check
|
|
||||||
# build using Java 17
|
# build using Java 17
|
||||||
image: eclipse-temurin:17
|
image: eclipse-temurin:17
|
||||||
cache:
|
cache:
|
||||||
key:
|
key: "$CI_COMMIT_REF_NAME_18-1"
|
||||||
files:
|
|
||||||
- gradle/wrapper/gradle-wrapper.properties
|
|
||||||
policy: push
|
|
||||||
paths:
|
|
||||||
- cache/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# second stage
|
|
||||||
build:
|
|
||||||
stage: build
|
|
||||||
script: ./gradlew build --gradle-user-home cache/
|
|
||||||
# build using Java 17
|
|
||||||
image: eclipse-temurin:17
|
|
||||||
cache:
|
|
||||||
key: "$CI_COMMIT_REF_NAME"
|
|
||||||
policy: pull-push
|
policy: pull-push
|
||||||
paths:
|
paths:
|
||||||
- .architectury-transformer
|
|
||||||
- .gradle
|
|
||||||
- build
|
|
||||||
- common/.gradle
|
|
||||||
- common/build
|
|
||||||
- core/.gradle
|
|
||||||
- core/build
|
|
||||||
- fabric/.gradle
|
|
||||||
- fabric/src/generated
|
|
||||||
- forge/.gradle
|
|
||||||
- forge/src/generated
|
|
||||||
- build
|
|
||||||
- .gradle
|
- .gradle
|
||||||
- cache/
|
- cache/
|
||||||
artifacts:
|
|
||||||
name: "NightlyBuild-$CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
|
||||||
paths:
|
|
||||||
# relative to the root directory
|
|
||||||
- fabric/build/libs
|
|
||||||
- forge/build/libs
|
|
||||||
exclude:
|
|
||||||
- fabric/build/libs/*-dev.jar
|
|
||||||
- fabric/build/libs/*-dev-shadow.jar
|
|
||||||
- fabric/build/libs/*-sources-dev.jar
|
|
||||||
- fabric/build/libs/*-sources.jar
|
|
||||||
- forge/build/libs/*-dev.jar
|
|
||||||
- forge/build/libs/*-dev-shadow.jar
|
|
||||||
- forge/build/libs/*-sources-dev.jar
|
|
||||||
- forge/build/libs/*-sources.jar
|
|
||||||
reports:
|
|
||||||
# To ensure we've access to these files in the next stage
|
|
||||||
dotenv: generate_jars.env
|
|
||||||
expire_in: 1 day
|
|
||||||
|
|
||||||
# third stage
|
|
||||||
merge:
|
# 1.18.2 build
|
||||||
stage: merge
|
build_18-2:
|
||||||
script: ./gradlew merge --gradle-user-home cache/
|
stage: build_18-2
|
||||||
|
script: ./gradlew build -PmcVer=1.18.2 --gradle-user-home cache/; ./gradlew merge --gradle-user-home cache/
|
||||||
# build using Java 17
|
# build using Java 17
|
||||||
image: eclipse-temurin:17
|
image: eclipse-temurin:17
|
||||||
cache:
|
cache:
|
||||||
key: "$CI_COMMIT_REF_NAME"
|
key: "$CI_COMMIT_REF_NAME_18-2"
|
||||||
policy: pull-push
|
policy: pull-push
|
||||||
paths:
|
paths:
|
||||||
- build
|
|
||||||
- .gradle
|
- .gradle
|
||||||
- cache/
|
- cache/
|
||||||
|
|
||||||
|
# TEMPORARY, there should be a way of either generating artifacts per build or in a separate stage
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "Merged_NightlyBuild-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
# This should only be done after the last build, otherwise there will be duplicate jars
|
||||||
|
name: "Merged_NightlyBuild-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||||
paths:
|
paths:
|
||||||
# relative to the root directory
|
# relative to the root directory
|
||||||
- Merged
|
- Merged
|
||||||
expire_in: 1 day
|
expire_in: 1 day
|
||||||
|
|
||||||
|
|
||||||
## forth stage
|
# # put artifacts in a zip
|
||||||
|
# # This should only be done after all the builds have been completed
|
||||||
|
# zip_artifacts:
|
||||||
|
# stage: zip_artifacts
|
||||||
|
# # The complier complains if we don't do something with the script line
|
||||||
|
# script: echo 'Building complete. Creating artifact Zip.'
|
||||||
|
# # build using Java 17
|
||||||
|
# image: eclipse-temurin:17
|
||||||
|
# artifacts:
|
||||||
|
# # This should only be done after the last build, otherwise there will be duplicate jars
|
||||||
|
# name: "Merged_NightlyBuild-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||||
|
# paths:
|
||||||
|
# # relative to the root directory
|
||||||
|
# - Merged
|
||||||
|
# expire_in: 1 day
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# unused deployment stage
|
||||||
#deploy:
|
#deploy:
|
||||||
# stage: deploy
|
# stage: deploy
|
||||||
# image: registry.gitlab.com/gitlab-org/release-cli:latest
|
# image: registry.gitlab.com/gitlab-org/release-cli:latest
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
[submodule "core"]
|
[submodule "core"]
|
||||||
path = core
|
path = core
|
||||||
url = https://gitlab.com/jeseibel/distant-horizons-core.git
|
url = https://gitlab.com/jeseibel/distant-horizons-core.git
|
||||||
|
branch = main
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# 1.18.1 version based stuff
|
||||||
|
|
||||||
|
minecraft_version=1.18.1
|
||||||
|
java_version = 17
|
||||||
|
|
||||||
|
# Fabric loader
|
||||||
|
fabric_loader_version=0.13.3
|
||||||
|
fabric_api_version=0.46.6+1.18
|
||||||
|
# Fabric mod versions
|
||||||
|
modmenu_version=3.0.1
|
||||||
|
starlight_version_fabric=3554912
|
||||||
|
lithium_version=mc1.18.1-0.7.7
|
||||||
|
sodium_version=3605309
|
||||||
|
iris_version=1.18.x-v1.1.4
|
||||||
|
bclib_version=1.2.5
|
||||||
|
immersive_portals_version = v1.0.4-1.18
|
||||||
|
|
||||||
|
# Fabric mod run
|
||||||
|
# 0 = Don't enable and don't run
|
||||||
|
# 1 = Can be referenced in code but doesn't run
|
||||||
|
# 2 = Can be referenced in code and runs in client
|
||||||
|
enable_starlight=0
|
||||||
|
enable_sodium=1
|
||||||
|
enable_lithium=0
|
||||||
|
enable_iris=0
|
||||||
|
enable_bclib=0
|
||||||
|
|
||||||
|
# Forge loader
|
||||||
|
forge_version=39.1.2
|
||||||
|
# Forge mod versions
|
||||||
|
starlight_version_forge=3559934
|
||||||
|
|
||||||
|
# Forge mod run
|
||||||
|
# 0 = Dont enable and don't run
|
||||||
|
# 1 = Can be referenced in code but doesn't run
|
||||||
|
# 2 = Can be referenced in code and runs in client
|
||||||
|
enable_starlight_forge=0
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# 1.18.2 version based stuff
|
||||||
|
# architectury_plugin_version = 3.4-SNAPSHOT
|
||||||
|
# dev_architectury_loom_version = 0.10.0-SNAPSHOT
|
||||||
|
minecraft_version=1.18.2
|
||||||
|
java_version = 17
|
||||||
|
|
||||||
|
# Fabric loader
|
||||||
|
fabric_loader_version=0.13.3
|
||||||
|
fabric_api_version=0.48.0+1.18.2
|
||||||
|
# Fabric mod versions
|
||||||
|
modmenu_version=3.1.0
|
||||||
|
starlight_version_fabric=3667443
|
||||||
|
lithium_version=mc1.18.2-0.7.9
|
||||||
|
sodium_version=3669187
|
||||||
|
iris_version=1.18.x-v1.2.2
|
||||||
|
immersive_portals_version = v1.0.4-1.18
|
||||||
|
bclib_version=0
|
||||||
|
|
||||||
|
# Fabric mod run
|
||||||
|
# 0 = Don't enable and don't run
|
||||||
|
# 1 = Can be referenced in code but doesn't run
|
||||||
|
# 2 = Can be referenced in code and runs in client
|
||||||
|
enable_starlight=0
|
||||||
|
enable_sodium=1
|
||||||
|
enable_lithium=0
|
||||||
|
enable_iris=0
|
||||||
|
enable_bclib=0
|
||||||
|
|
||||||
|
# Forge loader
|
||||||
|
forge_version=40.0.18
|
||||||
|
# Forge mod versions
|
||||||
|
starlight_version_forge=0
|
||||||
|
|
||||||
|
# Forge mod run
|
||||||
|
# 0 = Dont enable and don't run
|
||||||
|
# 1 = Can be referenced in code but doesn't run
|
||||||
|
# 2 = Can be referenced in code and runs in client
|
||||||
|
enable_starlight_forge=0
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
# Distant Horizons
|
# <img src="https://gitlab.com/jeseibel/distant-horizons-core/-/raw/main/_logo%20files/LOD%20logo%20flat%20-%20with%20boarder.png" width="32"> Distant Horizons
|
||||||
|
|
||||||
|
> A mod that adds a Level of Detail System to Minecraft
|
||||||
|
|
||||||
|
|
||||||
|
# What is Distant Horizons?
|
||||||
|
|
||||||
This mod adds a Level Of Detail (LOD) system to Minecraft.\
|
This mod adds a Level Of Detail (LOD) system to Minecraft.\
|
||||||
This implementation renders simplified chunks outside the normal render distance\
|
This implementation renders simplified chunks outside the normal render distance\
|
||||||
@@ -9,20 +14,30 @@ If you want to see a quick demo, check out a video covering the mod here:
|
|||||||
|
|
||||||
<a href="https://www.youtube.com/watch?v=H2tnvEVbO1c" target="_blank"></a>
|
<a href="https://www.youtube.com/watch?v=H2tnvEVbO1c" target="_blank"></a>
|
||||||
|
|
||||||
Architectury version: 3.4-SNAPSHOT\
|
### Versions
|
||||||
Forge version: 39.0.5 and 38.0.14\
|
|
||||||
Fabric version: 0.12.12\
|
Architectury version: 3.4-SNAPSHOT\
|
||||||
Fabric API version: 0.44.0+1.18
|
Java Compiler plugin: Manifold Preprocessor
|
||||||
|
|
||||||
|
#### 1.18.2 mods
|
||||||
|
Forge version: 40.0.18\
|
||||||
|
Fabric version: 0.13.3\
|
||||||
|
Fabric API version: 0.48.0+1.18.2\
|
||||||
|
Modmenu version: 3.1.0
|
||||||
|
|
||||||
|
#### 1.18.1 mods
|
||||||
|
Forge version: 39.1.2\
|
||||||
|
Fabric version: 0.13.3\
|
||||||
|
Fabric API version: 0.46.6+1.18\
|
||||||
|
Modmenu version: 3.0.1
|
||||||
|
|
||||||
Modmenu version: 3.0.0\
|
|
||||||
Sodium version: mc1.18-0.4.0-alpha5
|
|
||||||
|
|
||||||
Notes:\
|
Notes:\
|
||||||
This version has been confirmed to work in Eclipse and Retail Minecraft.\
|
This version has been confirmed to work in IDE and Retail Minecraft.\
|
||||||
(Retail running forge version 1.18.1-39.0.5 and fabric version 1.18-0.12.12 and 1.18.1-0.12.12)
|
(Retail running forge version 1.18.1-39.0.5 and fabric version 1.18-0.12.12 and 1.18.1-0.13.2)
|
||||||
|
|
||||||
|
|
||||||
## source code installation
|
## Source Code Installation
|
||||||
|
|
||||||
See the Fabric Documentation online for more detailed instructions:\
|
See the Fabric Documentation online for more detailed instructions:\
|
||||||
https://fabricmc.net/wiki/tutorial:setup
|
https://fabricmc.net/wiki/tutorial:setup
|
||||||
@@ -31,31 +46,46 @@ https://fabricmc.net/wiki/tutorial:setup
|
|||||||
|
|
||||||
* A Java Development Kit (JDK) for Java 17 (recommended) or newer. Visit https://www.oracle.com/java/technologies/downloads/ for installers.
|
* A Java Development Kit (JDK) for Java 17 (recommended) or newer. Visit https://www.oracle.com/java/technologies/downloads/ for installers.
|
||||||
* Git or someway to clone git projects. Visit https://git-scm.com/ for installers.
|
* Git or someway to clone git projects. Visit https://git-scm.com/ for installers.
|
||||||
* (Not required) Any Java IDE, for example Intellij IDEA and Eclipse. You may also use any other code editors, such as Visual Studio Code. (Optional)
|
* (Not required) Any Java IDE with plugins that support Manifold, for example Intellij IDEA.
|
||||||
It's better to use IntelliJ IDEA since Eclipse is not supported by Architectury, but it still works.
|
|
||||||
|
|
||||||
**If using IntelliJ:**
|
**If using IntelliJ:**
|
||||||
|
0. Install Manifold plugin
|
||||||
1. open IDEA and import the build.gradle
|
1. open IDEA and import the build.gradle
|
||||||
2. refresh the Gradle project in IDEA if required
|
2. refresh the Gradle project in IDEA if required
|
||||||
|
|
||||||
**If using Ecplise:**
|
**If using Ecplise: (Note that Eclispe currently doesn't support Manifold's preprocessor!)**
|
||||||
1. run the command: `./gradlew geneclipseruns`
|
1. run the command: `./gradlew geneclipseruns`
|
||||||
2. run the command: `./gradlew eclipse`
|
2. run the command: `./gradlew eclipse`
|
||||||
3. Make sure eclipse has the JDK 17 installed. (This is needed so that eclipse can run minecraft)
|
3. Make sure eclipse has the JDK 17 installed. (This is needed so that eclipse can run minecraft)
|
||||||
4. Import the project into eclipse
|
4. Import the project into eclipse
|
||||||
|
|
||||||
|
## Switching Versions
|
||||||
|
This branch support 2 built versions:
|
||||||
|
- 1.18.2
|
||||||
|
- 1.18.1 (which also runs on 1.18)
|
||||||
|
|
||||||
|
To switch between active versions, change `mcVer=1.18.?` in `gradle.properties` file.
|
||||||
|
|
||||||
|
If running on IDE, to ensure IDE pickup the changed versions, you will need to run a gradle command again to allow gradle to update all the libs. (In IntellJ you will also need to do a gradle sync again if it didn't start it automatically.)
|
||||||
|
>Note: There may be a `java.nio.file.FileSystemException` thrown on running the command after switching versions. To fix it, either restart your IDE (as your IDE is locking up a file) or use tools like LockHunter to unlock the linked file. (Often a lib file under `common\build\lib` or `forge\build\lib` or `fabric\build\lib`). If anyone knows how to solve this issue please comment to this issue: https://gitlab.com/jeseibel/minecraft-lod-mod/-/issues/233
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
|
|
||||||
**Using GUI**
|
**Using GUI**
|
||||||
1. Open a command line in the project folder
|
1. Download the zip of the project and extract it
|
||||||
2. Run the command: `./gradlew build`
|
2. Download the core from https://gitlab.com/jeseibel/distant-horizons-core and extract into a folder called `core`
|
||||||
3. The compiled jar file will be in the folder `fabric/build/libs/` and `forge/build/libs/`
|
3. Open a command line in the project folder
|
||||||
|
4. Run the command: `./gradlew assemble`
|
||||||
|
5. Then run command: `./gradlew mergeJars`
|
||||||
|
6. The compiled jar file will be in the folder `Merged`
|
||||||
|
|
||||||
**If in terminal:**
|
**If in terminal:**
|
||||||
1. `git clone -b 1.18.X --recurse-submodules https://gitlab.com/jeseibel/minecraft-lod-mod.git`
|
1. `git clone -b preprocessor_test --recurse-submodules https://gitlab.com/jeseibel/minecraft-lod-mod.git`
|
||||||
2. `cd minecraft-lod-mod`
|
2. `cd minecraft-lod-mod`
|
||||||
3. `./gradlew assemble` or `./gradlew build`
|
3. `./gradlew assemble`
|
||||||
4. The build should be in `fabric/build/libs/` and `forge/build/libs/`
|
4. `./gradlew mergeJars`
|
||||||
|
5. The compiled jar file will be in the folder `Merged`
|
||||||
|
>Note: You can add the arg: `-PmcVer=1.18.?` to tell gradle to build a selected MC version instead of having to manually modify the `gradle.properties` file.
|
||||||
|
|
||||||
|
|
||||||
## Other commands
|
## Other commands
|
||||||
@@ -84,4 +114,4 @@ XZ for Java (data compression)\
|
|||||||
https://tukaani.org/xz/java.html
|
https://tukaani.org/xz/java.html
|
||||||
|
|
||||||
DHJarMerger (To merge multiple mod versions into one jar)\
|
DHJarMerger (To merge multiple mod versions into one jar)\
|
||||||
https://github.com/Ran-helo/DHJarMerger
|
https://github.com/Ran-helo/DHJarMerger
|
||||||
|
|||||||
+52
-4
@@ -1,5 +1,6 @@
|
|||||||
import io.github.ran.jarmerger.JarMergerPlugin
|
import io.github.ran.jarmerger.JarMergerPlugin
|
||||||
|
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
dependencies{
|
dependencies{
|
||||||
classpath files('plugins/DHJarMerger-1.0.jar')
|
classpath files('plugins/DHJarMerger-1.0.jar')
|
||||||
@@ -11,6 +12,31 @@ plugins {
|
|||||||
id "dev.architectury.loom" version "0.10.0-SNAPSHOT" apply false
|
id "dev.architectury.loom" version "0.10.0-SNAPSHOT" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def writeBuildGradlePredefine() {
|
||||||
|
def excapedMCVersion = rootProject.minecraft_version.replace(".", "_")
|
||||||
|
new File(projectDir, "build.properties").text = "MC_VERSION_${excapedMCVersion}=\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
def loadProperties() {
|
||||||
|
def defaultMcVersion = '1.18.2'
|
||||||
|
if (!project.hasProperty("mcVer")) {
|
||||||
|
println "No mcVer set! Defaulting to ${defaultMcVersion}."
|
||||||
|
println "Tip: Use -PmcVer='${defaultMcVersion}' in cmd arg to set mcVer."
|
||||||
|
}
|
||||||
|
def mcVersion = project.hasProperty("mcVer") ? mcVer : defaultMcVersion
|
||||||
|
|
||||||
|
println "Loading properties file at " + mcVersion + ".properties"
|
||||||
|
def props = new Properties()
|
||||||
|
props.load(new FileInputStream("$rootProject.rootDir/"+"$mcVersion"+".properties"))
|
||||||
|
|
||||||
|
props.each { prop ->
|
||||||
|
rootProject.ext.set(prop.key, prop.value)
|
||||||
|
// println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
|
||||||
|
}
|
||||||
|
writeBuildGradlePredefine()
|
||||||
|
}
|
||||||
|
loadProperties()
|
||||||
|
|
||||||
apply plugin: JarMergerPlugin
|
apply plugin: JarMergerPlugin
|
||||||
|
|
||||||
architectury {
|
architectury {
|
||||||
@@ -34,6 +60,9 @@ subprojects { p ->
|
|||||||
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||||
// The following line declares the mojmap mappings
|
// The following line declares the mojmap mappings
|
||||||
mappings loom.officialMojangMappings()
|
mappings loom.officialMojangMappings()
|
||||||
|
|
||||||
|
//Manifold
|
||||||
|
annotationProcessor "systems.manifold:manifold-preprocessor:${rootProject.manifold_version}"
|
||||||
|
|
||||||
// Toml
|
// Toml
|
||||||
implementation("com.electronwill.night-config:toml:${rootProject.toml_version}")
|
implementation("com.electronwill.night-config:toml:${rootProject.toml_version}")
|
||||||
@@ -44,12 +73,19 @@ subprojects { p ->
|
|||||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (p != project(":core")) {
|
if (p != project(":core")) {
|
||||||
common(project(":core")) { transitive false }
|
common(project(":core")) { transitive false }
|
||||||
shadowMe(project(":core")) { transitive false }
|
shadowMe(project(":core")) { transitive false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes 'Implementation-Title': rootProject.archives_base_name,
|
||||||
|
'Implementation-Version': rootProject.mod_version,
|
||||||
|
'Main-Class': 'com.seibel.lod.core.JarMain'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects { p ->
|
allprojects { p ->
|
||||||
@@ -65,6 +101,9 @@ allprojects { p ->
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
// used to download and compile dependencies from git repos
|
// used to download and compile dependencies from git repos
|
||||||
maven { url 'https://jitpack.io' }
|
maven { url 'https://jitpack.io' }
|
||||||
|
|
||||||
|
// For Manifold Preprocessor
|
||||||
|
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
|
||||||
|
|
||||||
// Required for importing Modrinth mods
|
// Required for importing Modrinth mods
|
||||||
maven {
|
maven {
|
||||||
@@ -110,8 +149,11 @@ allprojects { p ->
|
|||||||
description: mod_description,
|
description: mod_description,
|
||||||
homepage: mod_homepage,
|
homepage: mod_homepage,
|
||||||
source: mod_source,
|
source: mod_source,
|
||||||
issues: mod_issues
|
issues: mod_issues,
|
||||||
|
minecraft_version: minecraft_version,
|
||||||
|
java_version: java_version
|
||||||
] // The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties
|
] // The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties
|
||||||
|
//TODO: Make Forge loader version also be relaced with non hardcoded value instead of "[36,41)"
|
||||||
|
|
||||||
inputs.properties replaceProperties
|
inputs.properties replaceProperties
|
||||||
replaceProperties.put 'project', project
|
replaceProperties.put 'project', project
|
||||||
@@ -134,9 +176,15 @@ allprojects { p ->
|
|||||||
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
|
// Add Manifold Preprocessor
|
||||||
|
// def excapedMCVersion = rootProject.minecraft_version.replace(".", "_")
|
||||||
|
// options.compilerArgs += ['-Xplugin:Manifold', "-AMC_VERSION_${excapedMCVersion}"]
|
||||||
|
//
|
||||||
|
options.compilerArgs += ['-Xplugin:Manifold']
|
||||||
|
|
||||||
|
// println options.compilerArgs
|
||||||
if (p != project(":core")) {
|
if (p != project(":core")) {
|
||||||
// Minecraft 1.18 (1.18-pre2) upwards uses Java 17.
|
options.release = rootProject.java_version as Integer
|
||||||
options.release = 17
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
MC_VERSION_1_18_2=
|
||||||
+172
-46
@@ -19,21 +19,25 @@
|
|||||||
|
|
||||||
package com.seibel.lod.common;
|
package com.seibel.lod.common;
|
||||||
|
|
||||||
import com.seibel.lod.common.wrappers.config.ConfigGui;
|
|
||||||
import com.seibel.lod.core.config.*;
|
import com.seibel.lod.core.config.*;
|
||||||
import com.seibel.lod.core.enums.config.*;
|
import com.seibel.lod.core.enums.config.*;
|
||||||
import com.seibel.lod.core.enums.rendering.*;
|
import com.seibel.lod.core.enums.rendering.*;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IAdvanced.*;
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IAdvanced.*;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IGraphics.*;
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IGraphics.*;
|
||||||
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IGraphics.IFogQuality.IAdvancedFog;
|
||||||
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IGraphics.IFogQuality.IAdvancedFog.IHeightFog;
|
||||||
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IMultiplayer;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IWorldGenerator;
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.IClient.IWorldGenerator;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This handles any configuration the user has access to.
|
* This handles any configuration the user has access to.
|
||||||
* @author coolGi2007
|
* @author coolGi2007
|
||||||
* @version 12-12-2021
|
* @version 12-12-2021
|
||||||
*/
|
*/
|
||||||
public class OldConfig
|
|
||||||
|
public class Config
|
||||||
//public class Config extends TinyConfig
|
//public class Config extends TinyConfig
|
||||||
{
|
{
|
||||||
// CONFIG STRUCTURE
|
// CONFIG STRUCTURE
|
||||||
@@ -50,12 +54,12 @@ public class OldConfig
|
|||||||
// |-> Threads
|
// |-> Threads
|
||||||
// |-> Buffers
|
// |-> Buffers
|
||||||
// |-> Debugging
|
// |-> Debugging
|
||||||
|
|
||||||
// Since the original config system uses forge stuff, that means we have to rewrite the whole config system
|
// Since the original config system uses forge stuff, that means we have to rewrite the whole config system
|
||||||
|
|
||||||
@ConfigAnnotations.ScreenEntry
|
@ConfigAnnotations.ScreenEntry
|
||||||
public static Client client;
|
public static Client client;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _optionsButton = ILodConfigWrapperSingleton.IClient.OPTIONS_BUTTON_DESC;
|
public static String _optionsButton = ILodConfigWrapperSingleton.IClient.OPTIONS_BUTTON_DESC;
|
||||||
// I know this option should be in Client
|
// I know this option should be in Client
|
||||||
@@ -63,88 +67,184 @@ public class OldConfig
|
|||||||
// Tough it is in client in the wrapper singleton
|
// Tough it is in client in the wrapper singleton
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static boolean optionsButton = true;
|
public static boolean optionsButton = true;
|
||||||
|
|
||||||
public static class Client
|
public static class Client
|
||||||
{
|
{
|
||||||
@ConfigAnnotations.ScreenEntry
|
@ConfigAnnotations.ScreenEntry
|
||||||
public static Graphics graphics;
|
public static Graphics graphics;
|
||||||
|
|
||||||
@ConfigAnnotations.ScreenEntry
|
@ConfigAnnotations.ScreenEntry
|
||||||
public static WorldGenerator worldGenerator;
|
public static WorldGenerator worldGenerator;
|
||||||
|
|
||||||
|
@ConfigAnnotations.ScreenEntry
|
||||||
|
public static Multiplayer multiplayer;
|
||||||
|
|
||||||
@ConfigAnnotations.ScreenEntry
|
@ConfigAnnotations.ScreenEntry
|
||||||
public static Advanced advanced;
|
public static Advanced advanced;
|
||||||
|
|
||||||
|
|
||||||
public static class Graphics
|
public static class Graphics
|
||||||
{
|
{
|
||||||
@ConfigAnnotations.ScreenEntry
|
@ConfigAnnotations.ScreenEntry
|
||||||
public static Quality quality;
|
public static Quality quality;
|
||||||
|
|
||||||
@ConfigAnnotations.ScreenEntry
|
@ConfigAnnotations.ScreenEntry
|
||||||
public static FogQuality fogQuality;
|
public static FogQuality fogQuality;
|
||||||
|
|
||||||
@ConfigAnnotations.ScreenEntry
|
@ConfigAnnotations.ScreenEntry
|
||||||
public static AdvancedGraphics advancedGraphics;
|
public static AdvancedGraphics advancedGraphics;
|
||||||
|
|
||||||
|
|
||||||
public static class Quality
|
public static class Quality
|
||||||
{
|
{
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _drawResolution = IQuality.DRAW_RESOLUTION_DESC;
|
public static String _drawResolution = IQuality.DRAW_RESOLUTION_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static HorizontalResolution drawResolution = IQuality.DRAW_RESOLUTION_DEFAULT;
|
public static HorizontalResolution drawResolution = IQuality.DRAW_RESOLUTION_DEFAULT;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _lodChunkRenderDistance = IQuality.LOD_CHUNK_RENDER_DISTANCE_DESC;
|
public static String _lodChunkRenderDistance = IQuality.LOD_CHUNK_RENDER_DISTANCE_DESC;
|
||||||
@ConfigAnnotations.Entry(minValue = 16, maxValue = 2048)
|
@ConfigAnnotations.Entry(minValue = 16, maxValue = 2048)
|
||||||
public static int lodChunkRenderDistance = IQuality.LOD_CHUNK_RENDER_DISTANCE_MIN_DEFAULT_MAX.defaultValue;
|
public static int lodChunkRenderDistance = IQuality.LOD_CHUNK_RENDER_DISTANCE_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _verticalQuality = IQuality.VERTICAL_QUALITY_DESC;
|
public static String _verticalQuality = IQuality.VERTICAL_QUALITY_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static VerticalQuality verticalQuality = IQuality.VERTICAL_QUALITY_DEFAULT;
|
public static VerticalQuality verticalQuality = IQuality.VERTICAL_QUALITY_DEFAULT;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _horizontalScale = IQuality.HORIZONTAL_SCALE_DESC;
|
public static String _horizontalScale = IQuality.HORIZONTAL_SCALE_DESC;
|
||||||
@ConfigAnnotations.Entry(minValue = 2, maxValue = 32)
|
@ConfigAnnotations.Entry(minValue = 2, maxValue = 32)
|
||||||
public static int horizontalScale = IQuality.HORIZONTAL_SCALE_MIN_DEFAULT_MAX.defaultValue;
|
public static int horizontalScale = IQuality.HORIZONTAL_SCALE_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _horizontalQuality = IQuality.HORIZONTAL_SCALE_DESC;
|
public static String _horizontalQuality = IQuality.HORIZONTAL_SCALE_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static HorizontalQuality horizontalQuality = IQuality.HORIZONTAL_QUALITY_DEFAULT;
|
public static HorizontalQuality horizontalQuality = IQuality.HORIZONTAL_QUALITY_DEFAULT;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _dropoffQuality = IQuality.DROPOFF_QUALITY_DESC;
|
public static String _dropoffQuality = IQuality.DROPOFF_QUALITY_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static DropoffQuality dropoffQuality = IQuality.DROPOFF_QUALITY_DEFAULT;
|
public static DropoffQuality dropoffQuality = IQuality.DROPOFF_QUALITY_DEFAULT;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _lodBiomeBlending = IQuality.LOD_BIOME_BLENDING_DESC;
|
||||||
|
@ConfigAnnotations.Entry(minValue = 0, maxValue = 7)
|
||||||
|
public static int lodBiomeBlending = IQuality.LOD_BIOME_BLENDING_MIN_DEFAULT_MAX.defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class FogQuality
|
public static class FogQuality
|
||||||
{
|
{
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _fogDistance = IFogQuality.FOG_DISTANCE_DESC;
|
public static String _fogDistance = IFogQuality.FOG_DISTANCE_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static FogDistance fogDistance = IFogQuality.FOG_DISTANCE_DEFAULT;
|
public static FogDistance fogDistance = IFogQuality.FOG_DISTANCE_DEFAULT;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _fogDrawMode = IFogQuality.FOG_DRAW_MODE_DESC;
|
public static String _fogDrawMode = IFogQuality.FOG_DRAW_MODE_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static FogDrawMode fogDrawMode = IFogQuality.FOG_DRAW_MODE_DEFAULT;
|
public static FogDrawMode fogDrawMode = IFogQuality.FOG_DRAW_MODE_DEFAULT;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _fogColorMode = IFogQuality.FOG_COLOR_MODE_DESC;
|
public static String _fogColorMode = IFogQuality.FOG_COLOR_MODE_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static FogColorMode fogColorMode = IFogQuality.FOG_COLOR_MODE_DEFAULT;
|
public static FogColorMode fogColorMode = IFogQuality.FOG_COLOR_MODE_DEFAULT;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _disableVanillaFog = IFogQuality.DISABLE_VANILLA_FOG_DESC;
|
public static String _disableVanillaFog = IFogQuality.DISABLE_VANILLA_FOG_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static boolean disableVanillaFog = IFogQuality.DISABLE_VANILLA_FOG_DEFAULT;
|
public static boolean disableVanillaFog = IFogQuality.DISABLE_VANILLA_FOG_DEFAULT;
|
||||||
|
|
||||||
|
@ConfigAnnotations.ScreenEntry
|
||||||
|
public static AdvancedFog advancedFog;
|
||||||
|
|
||||||
|
public static class AdvancedFog {
|
||||||
|
static final double SQRT2 = 1.4142135623730951;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _farFogStart = IAdvancedFog.FAR_FOG_START_DESC;
|
||||||
|
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = SQRT2)
|
||||||
|
public static double farFogStart = IAdvancedFog.FAR_FOG_START_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _farFogEnd = IAdvancedFog.FAR_FOG_END_DESC;
|
||||||
|
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = SQRT2)
|
||||||
|
public static double farFogEnd = IAdvancedFog.FAR_FOG_END_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _farFogMin = IAdvancedFog.FAR_FOG_MIN_DESC;
|
||||||
|
@ConfigAnnotations.Entry(minValue = -5.0, maxValue = SQRT2)
|
||||||
|
public static double farFogMin = IAdvancedFog.FAR_FOG_MIN_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _farFogMax = IAdvancedFog.FAR_FOG_MAX_DESC;
|
||||||
|
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = 5.0)
|
||||||
|
public static double farFogMax = IAdvancedFog.FAR_FOG_MAX_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _farFogType = IAdvancedFog.FAR_FOG_TYPE_DESC;
|
||||||
|
@ConfigAnnotations.Entry
|
||||||
|
public static FogSetting.FogType farFogType = IAdvancedFog.FAR_FOG_TYPE_DEFAULT;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _farFogDensity = IAdvancedFog.FAR_FOG_DENSITY_DESC;
|
||||||
|
@ConfigAnnotations.Entry(minValue = 0.01, maxValue = 50.0)
|
||||||
|
public static double farFogDensity = IAdvancedFog.FAR_FOG_DENSITY_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
|
@ConfigAnnotations.ScreenEntry
|
||||||
|
public static HeightFog heightFog;
|
||||||
|
|
||||||
|
public static class HeightFog {
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _heightFogMixMode = IHeightFog.HEIGHT_FOG_MIX_MODE_DESC;
|
||||||
|
@ConfigAnnotations.Entry
|
||||||
|
public static HeightFogMixMode heightFogMixMode = IHeightFog.HEIGHT_FOG_MIX_MODE_DEFAULT;
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _heightFogMode = IHeightFog.HEIGHT_FOG_MODE_DESC;
|
||||||
|
@ConfigAnnotations.Entry
|
||||||
|
public static HeightFogMode heightFogMode = IHeightFog.HEIGHT_FOG_MODE_DEFAULT;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _heightFogHeight = IHeightFog.HEIGHT_FOG_HEIGHT_DESC;
|
||||||
|
@ConfigAnnotations.Entry(minValue = -4096.0, maxValue = 4096.0)
|
||||||
|
public static double heightFogHeight = IHeightFog.HEIGHT_FOG_HEIGHT_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _heightFogStart = IHeightFog.HEIGHT_FOG_START_DESC;
|
||||||
|
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = SQRT2)
|
||||||
|
public static double heightFogStart = IHeightFog.HEIGHT_FOG_START_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _heightFogEnd = IHeightFog.HEIGHT_FOG_END_DESC;
|
||||||
|
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = SQRT2)
|
||||||
|
public static double heightFogEnd = IHeightFog.HEIGHT_FOG_END_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _heightFogMin = IHeightFog.HEIGHT_FOG_MIN_DESC;
|
||||||
|
@ConfigAnnotations.Entry(minValue = -5.0, maxValue = SQRT2)
|
||||||
|
public static double heightFogMin = IHeightFog.HEIGHT_FOG_MIN_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _heightFogMax = IHeightFog.HEIGHT_FOG_MAX_DESC;
|
||||||
|
@ConfigAnnotations.Entry(minValue = 0.0, maxValue = 5.0)
|
||||||
|
public static double heightFogMax = IHeightFog.HEIGHT_FOG_MAX_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _heightFogType = IHeightFog.HEIGHT_FOG_TYPE_DESC;
|
||||||
|
@ConfigAnnotations.Entry
|
||||||
|
public static FogSetting.FogType heightFogType = IHeightFog.HEIGHT_FOG_TYPE_DEFAULT;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _heightFogDensity = IHeightFog.HEIGHT_FOG_DENSITY_DESC;
|
||||||
|
@ConfigAnnotations.Entry(minValue = 0.01, maxValue = 50.0)
|
||||||
|
public static double heightFogDensity = IHeightFog.HEIGHT_FOG_DENSITY_MIN_DEFAULT_MAX.defaultValue;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class AdvancedGraphics
|
public static class AdvancedGraphics
|
||||||
{
|
{
|
||||||
@@ -152,17 +252,27 @@ public class OldConfig
|
|||||||
public static String _disableDirectionalCulling = IAdvancedGraphics.DISABLE_DIRECTIONAL_CULLING_DESC;
|
public static String _disableDirectionalCulling = IAdvancedGraphics.DISABLE_DIRECTIONAL_CULLING_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static boolean disableDirectionalCulling = IAdvancedGraphics.DISABLE_DIRECTIONAL_CULLING_DEFAULT;
|
public static boolean disableDirectionalCulling = IAdvancedGraphics.DISABLE_DIRECTIONAL_CULLING_DEFAULT;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _vanillaOverdraw = IAdvancedGraphics.VANILLA_OVERDRAW_DESC;
|
public static String _vanillaOverdraw = IAdvancedGraphics.VANILLA_OVERDRAW_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static VanillaOverdraw vanillaOverdraw = IAdvancedGraphics.VANILLA_OVERDRAW_DEFAULT;
|
public static VanillaOverdraw vanillaOverdraw = IAdvancedGraphics.VANILLA_OVERDRAW_DEFAULT;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _useExtendedNearClipPlane = IAdvancedGraphics.USE_EXTENDED_NEAR_CLIP_PLANE_DESC;
|
public static String _useExtendedNearClipPlane = IAdvancedGraphics.USE_EXTENDED_NEAR_CLIP_PLANE_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static boolean useExtendedNearClipPlane = IAdvancedGraphics.USE_EXTENDED_NEAR_CLIP_PLANE_DEFAULT;
|
public static boolean useExtendedNearClipPlane = IAdvancedGraphics.USE_EXTENDED_NEAR_CLIP_PLANE_DEFAULT;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _brightnessMultiplier = IAdvancedGraphics.BRIGHTNESS_MULTIPLIER_DESC;
|
||||||
|
@ConfigAnnotations.Entry
|
||||||
|
public static double brightnessMultiplier = IAdvancedGraphics.BRIGHTNESS_MULTIPLIER_DEFAULT;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _saturationMultiplier = IAdvancedGraphics.SATURATION_MULTIPLIER_DESC;
|
||||||
|
@ConfigAnnotations.Entry
|
||||||
|
public static double saturationMultiplier = IAdvancedGraphics.SATURATION_MULTIPLIER_DEFAULT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _backsideCullingRange = IAdvancedGraphics.VANILLA_CULLING_RANGE_DESC;
|
public static String _backsideCullingRange = IAdvancedGraphics.VANILLA_CULLING_RANGE_DESC;
|
||||||
@@ -171,16 +281,16 @@ public class OldConfig
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class WorldGenerator
|
public static class WorldGenerator
|
||||||
{
|
{
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _enableDistantGeneration = IWorldGenerator.ENABLE_DISTANT_GENERATION_DESC;
|
public static String _enableDistantGeneration = IWorldGenerator.ENABLE_DISTANT_GENERATION_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static boolean enableDistantGeneration = IWorldGenerator.ENABLE_DISTANT_GENERATION_DEFAULT;
|
public static boolean enableDistantGeneration = IWorldGenerator.ENABLE_DISTANT_GENERATION_DEFAULT;
|
||||||
|
|
||||||
// @ConfigAnnotations.FileComment
|
// @ConfigAnnotations.FileComment
|
||||||
// public static String _distanceGenerationMode = IWorldGenerator.getDistanceGenerationModeDesc();
|
// public static String _distanceGenerationMode = IWorldGenerator.getDistanceGenerationModeDesc();
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static DistanceGenerationMode distanceGenerationMode = IWorldGenerator.DISTANCE_GENERATION_MODE_DEFAULT;
|
public static DistanceGenerationMode distanceGenerationMode = IWorldGenerator.DISTANCE_GENERATION_MODE_DEFAULT;
|
||||||
@@ -208,64 +318,80 @@ public class OldConfig
|
|||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static BlocksToAvoid blocksToAvoid = IWorldGenerator.BLOCKS_TO_AVOID_DEFAULT;
|
public static BlocksToAvoid blocksToAvoid = IWorldGenerator.BLOCKS_TO_AVOID_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Multiplayer
|
||||||
|
{
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _serverFolderNameMode = IMultiplayer.SERVER_FOLDER_NAME_MODE_DESC;
|
||||||
|
@ConfigAnnotations.Entry
|
||||||
|
public static ServerFolderNameMode serverFolderNameMode = IMultiplayer.SERVER_FOLDER_NAME_MODE_DEFAULT;
|
||||||
|
|
||||||
|
@ConfigAnnotations.FileComment
|
||||||
|
public static String _multiDimensionRequiredSimilarity = IMultiplayer.MULTI_DIMENSION_REQUIRED_SIMILARITY_DESC;
|
||||||
|
@ConfigAnnotations.Entry
|
||||||
|
public static double multiDimensionRequiredSimilarity = IMultiplayer.MULTI_DIMENSION_REQUIRED_SIMILARITY_DEFAULT;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class Advanced
|
public static class Advanced
|
||||||
{
|
{
|
||||||
@ConfigAnnotations.ScreenEntry
|
@ConfigAnnotations.ScreenEntry
|
||||||
public static Threading threading;
|
public static Threading threading;
|
||||||
|
|
||||||
@ConfigAnnotations.ScreenEntry
|
@ConfigAnnotations.ScreenEntry
|
||||||
public static Debugging debugging;
|
public static Debugging debugging;
|
||||||
|
|
||||||
@ConfigAnnotations.ScreenEntry
|
@ConfigAnnotations.ScreenEntry
|
||||||
public static Buffers buffers;
|
public static Buffers buffers;
|
||||||
|
|
||||||
|
|
||||||
public static class Threading
|
public static class Threading
|
||||||
{
|
{
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _numberOfWorldGenerationThreads = IThreading.NUMBER_OF_WORLD_GENERATION_THREADS_DESC;
|
public static String _numberOfWorldGenerationThreads = IThreading.NUMBER_OF_WORLD_GENERATION_THREADS_DESC;
|
||||||
@ConfigAnnotations.Entry(minValue = 1, maxValue = 50)
|
@ConfigAnnotations.Entry(minValue = 1, maxValue = 50)
|
||||||
public static int numberOfWorldGenerationThreads = IThreading.NUMBER_OF_WORLD_GENERATION_THREADS_DEFAULT.defaultValue;
|
public static int numberOfWorldGenerationThreads = IThreading.NUMBER_OF_WORLD_GENERATION_THREADS_DEFAULT.defaultValue;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _numberOfBufferBuilderThreads = IThreading.NUMBER_OF_BUFFER_BUILDER_THREADS_DESC;
|
public static String _numberOfBufferBuilderThreads = IThreading.NUMBER_OF_BUFFER_BUILDER_THREADS_DESC;
|
||||||
@ConfigAnnotations.Entry(minValue = 1, maxValue = 50)
|
@ConfigAnnotations.Entry(minValue = 1, maxValue = 50)
|
||||||
public static int numberOfBufferBuilderThreads = IThreading.NUMBER_OF_BUFFER_BUILDER_THREADS_MIN_DEFAULT_MAX.defaultValue;
|
public static int numberOfBufferBuilderThreads = IThreading.NUMBER_OF_BUFFER_BUILDER_THREADS_MIN_DEFAULT_MAX.defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class Debugging
|
public static class Debugging
|
||||||
{
|
{
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _drawLods = IDebugging.DRAW_LODS_DESC;
|
public static String _drawLods = IDebugging.DRAW_LODS_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static boolean drawLods = IDebugging.DRAW_LODS_DEFAULT;
|
public static boolean drawLods = IDebugging.DRAW_LODS_DEFAULT;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _debugMode = IDebugging.DEBUG_MODE_DESC;
|
public static String _debugMode = IDebugging.DEBUG_MODE_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static DebugMode debugMode = IDebugging.DEBUG_MODE_DEFAULT;
|
public static DebugMode debugMode = IDebugging.DEBUG_MODE_DEFAULT;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _enableDebugKeybindings = IDebugging.DEBUG_KEYBINDINGS_ENABLED_DESC;
|
public static String _enableDebugKeybindings = IDebugging.DEBUG_KEYBINDINGS_ENABLED_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static boolean enableDebugKeybindings = IDebugging.DEBUG_KEYBINDINGS_ENABLED_DEFAULT;
|
public static boolean enableDebugKeybindings = IDebugging.DEBUG_KEYBINDINGS_ENABLED_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class Buffers
|
public static class Buffers
|
||||||
{
|
{
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _gpuUploadMethod = IBuffers.GPU_UPLOAD_METHOD_DESC;
|
public static String _gpuUploadMethod = IBuffers.GPU_UPLOAD_METHOD_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
public static GpuUploadMethod gpuUploadMethod = IBuffers.GPU_UPLOAD_METHOD_DEFAULT;
|
public static GpuUploadMethod gpuUploadMethod = IBuffers.GPU_UPLOAD_METHOD_DEFAULT;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _gpuUploadPerMegabyteInMilliseconds = IBuffers.GPU_UPLOAD_PER_MEGABYTE_IN_MILLISECONDS_DESC;
|
public static String _gpuUploadPerMegabyteInMilliseconds = IBuffers.GPU_UPLOAD_PER_MEGABYTE_IN_MILLISECONDS_DESC;
|
||||||
@ConfigAnnotations.Entry(minValue = 0, maxValue = 50)
|
@ConfigAnnotations.Entry(minValue = 0, maxValue = 50)
|
||||||
public static int gpuUploadPerMegabyteInMilliseconds = IBuffers.GPU_UPLOAD_PER_MEGABYTE_IN_MILLISECONDS_DEFAULT.defaultValue;
|
public static int gpuUploadPerMegabyteInMilliseconds = IBuffers.GPU_UPLOAD_PER_MEGABYTE_IN_MILLISECONDS_DEFAULT.defaultValue;
|
||||||
|
|
||||||
@ConfigAnnotations.FileComment
|
@ConfigAnnotations.FileComment
|
||||||
public static String _rebuildTimes = IBuffers.REBUILD_TIMES_DESC;
|
public static String _rebuildTimes = IBuffers.REBUILD_TIMES_DESC;
|
||||||
@ConfigAnnotations.Entry
|
@ConfigAnnotations.Entry
|
||||||
@@ -4,8 +4,6 @@ import com.seibel.lod.common.forge.LodForgeMethodCaller;
|
|||||||
import com.seibel.lod.common.networking.NetworkInterface;
|
import com.seibel.lod.common.networking.NetworkInterface;
|
||||||
import com.seibel.lod.common.wrappers.DependencySetup;
|
import com.seibel.lod.common.wrappers.DependencySetup;
|
||||||
import com.seibel.lod.common.wrappers.config.ConfigGui;
|
import com.seibel.lod.common.wrappers.config.ConfigGui;
|
||||||
import com.seibel.lod.core.Config;
|
|
||||||
import com.seibel.lod.core.config.ConfigBase;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the common main class
|
* This is the common main class
|
||||||
@@ -17,9 +15,7 @@ public class LodCommonMain {
|
|||||||
public static LodForgeMethodCaller forgeMethodCaller;
|
public static LodForgeMethodCaller forgeMethodCaller;
|
||||||
public static NetworkInterface networkInterface;
|
public static NetworkInterface networkInterface;
|
||||||
|
|
||||||
public static final boolean IsNewConfig = false;
|
public static void startup(LodForgeMethodCaller caller, boolean serverSided, NetworkInterface networkInterface) {
|
||||||
|
|
||||||
public static void startup(LodForgeMethodCaller caller, boolean serverSided) {
|
|
||||||
LodCommonMain.serverSided = serverSided;
|
LodCommonMain.serverSided = serverSided;
|
||||||
if (caller != null) {
|
if (caller != null) {
|
||||||
LodCommonMain.forge = true;
|
LodCommonMain.forge = true;
|
||||||
@@ -27,15 +23,17 @@ public class LodCommonMain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DependencySetup.createInitialBindings();
|
DependencySetup.createInitialBindings();
|
||||||
|
|
||||||
|
LodCommonMain.networkInterface = networkInterface;
|
||||||
|
if (!serverSided) {
|
||||||
|
networkInterface.register_Client();
|
||||||
|
} else {
|
||||||
|
networkInterface.register_Server();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void initConfig() {
|
public static void initConfig() {
|
||||||
if (!IsNewConfig)
|
ConfigGui.init(Config.class);
|
||||||
ConfigGui.init(OldConfig.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void registerNetworking(NetworkInterface networkInterface) {
|
|
||||||
LodCommonMain.networkInterface = networkInterface;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.seibel.lod.common.forge;
|
package com.seibel.lod.common.forge;
|
||||||
|
|
||||||
import com.seibel.lod.common.wrappers.minecraft.MinecraftWrapper;
|
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
|
||||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
@@ -15,5 +15,5 @@ import java.util.Random;
|
|||||||
* @author Ran
|
* @author Ran
|
||||||
*/
|
*/
|
||||||
public interface LodForgeMethodCaller {
|
public interface LodForgeMethodCaller {
|
||||||
List<BakedQuad> getQuads(MinecraftWrapper mc, Block block, BlockState blockState, Direction direction, Random random);
|
List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, Random random);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.seibel.lod.common.networking;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is packet handler for our mod
|
||||||
|
* It basically handles the packets sent from the server & client
|
||||||
|
*
|
||||||
|
* @author Ran
|
||||||
|
*/
|
||||||
|
public class NetworkHandler {
|
||||||
|
// If you need the response sender then tell me
|
||||||
|
// I'll add extra code to get the response sender
|
||||||
|
public static void receivePacketClient(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf) {
|
||||||
|
// TODO: Server sided stuff here
|
||||||
|
// You can make client execute something by using client.execute(Runnable)
|
||||||
|
// In the fabric docs it says that client.execute is ran on the render thread?
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you need the response sender then tell me
|
||||||
|
// I'll add extra code to get the response sender
|
||||||
|
public static void receivePacketServer(MinecraftServer server, ServerPlayer client, ServerGamePacketListenerImpl handler, FriendlyByteBuf buf) {
|
||||||
|
// TODO: Server sided stuff here
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
package com.seibel.lod.common.networking;
|
package com.seibel.lod.common.networking;
|
||||||
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ran
|
* @author Ran
|
||||||
*/
|
*/
|
||||||
public interface NetworkInterface {
|
public interface NetworkInterface {
|
||||||
void send(FriendlyByteBuf packetByteBuf);
|
void register_Client();
|
||||||
|
void register_Server();
|
||||||
FriendlyByteBuf receive();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,100 @@
|
|||||||
package com.seibel.lod.common.networking;
|
package com.seibel.lod.common.networking;
|
||||||
|
|
||||||
|
import com.seibel.lod.core.ModInfo;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
|
||||||
|
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class holds most of the networking code for the mod.
|
* This class holds most of the networking code for the mod.
|
||||||
* @author Ran
|
* @author Ran
|
||||||
*/
|
*/
|
||||||
public class Networking {
|
public class Networking {
|
||||||
// public void example(int packetId) {
|
public static final ResourceLocation resourceLocation_meow = new ResourceLocation("lod", "meow");
|
||||||
// FriendlyByteBuf packetByteBuf = Networking.createNew();
|
|
||||||
// packetByteBuf.writeInt(packetId);
|
|
||||||
// LodCommonMain.networkInterface.send(packetByteBuf);
|
|
||||||
// }
|
|
||||||
|
|
||||||
public static FriendlyByteBuf createNew() {
|
public static FriendlyByteBuf createNew() {
|
||||||
return new FriendlyByteBuf(Unpooled.buffer());
|
// TODO: Probably replace the Unpooled.buffer()
|
||||||
|
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||||
|
buf.writeInt(ModInfo.PROTOCOL_VERSION);
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All code below is from the fabric api and might have been modified to work with Distant Horizons
|
||||||
|
* Which is licensed under the Apache License 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a packet to a player.
|
||||||
|
*
|
||||||
|
* @param player the player to send the packet to
|
||||||
|
* @param buf the payload of the packet.
|
||||||
|
*/
|
||||||
|
public static void send(ServerPlayer player, FriendlyByteBuf buf) {
|
||||||
|
Objects.requireNonNull(player, "Server player entity cannot be null");
|
||||||
|
Objects.requireNonNull(resourceLocation_meow, "Channel name cannot be null");
|
||||||
|
Objects.requireNonNull(buf, "Packet byte buf cannot be null");
|
||||||
|
|
||||||
|
player.connection.send(createS2CPacket(resourceLocation_meow, buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a packet to the connected server.
|
||||||
|
*
|
||||||
|
* @param buf the payload of the packet
|
||||||
|
* @throws IllegalStateException if the client is not connected to a server
|
||||||
|
*/
|
||||||
|
public static void send(FriendlyByteBuf buf) throws IllegalStateException {
|
||||||
|
// You cant send without a client player, so this is fine
|
||||||
|
if (Minecraft.getInstance().getConnection() != null) {
|
||||||
|
Minecraft.getInstance().getConnection().send(createC2SPacket(resourceLocation_meow, buf));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Cannot send packets when not in game!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a packet which may be sent to the connected client.
|
||||||
|
*
|
||||||
|
* @param channelName the channel name
|
||||||
|
* @param buf the packet byte buf which represents the payload of the packet
|
||||||
|
* @return a new packet
|
||||||
|
*/
|
||||||
|
public static Packet<?> createS2CPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
|
||||||
|
Objects.requireNonNull(channelName, "Channel cannot be null");
|
||||||
|
Objects.requireNonNull(buf, "Buf cannot be null");
|
||||||
|
|
||||||
|
return createPlayS2CPacket(channelName, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Packet<?> createPlayS2CPacket(ResourceLocation channel, FriendlyByteBuf buf) {
|
||||||
|
return new ClientboundCustomPayloadPacket(channel, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a packet which may be sent to a the connected server.
|
||||||
|
*
|
||||||
|
* @param channelName the channel name
|
||||||
|
* @param buf the packet byte buf which represents the payload of the packet
|
||||||
|
* @return a new packet
|
||||||
|
*/
|
||||||
|
public static Packet<?> createC2SPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
|
||||||
|
Objects.requireNonNull(channelName, "Channel name cannot be null");
|
||||||
|
Objects.requireNonNull(buf, "Buf cannot be null");
|
||||||
|
|
||||||
|
return createPlayC2SPacket(channelName, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Packet<?> createPlayC2SPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
|
||||||
|
return new ServerboundCustomPayloadPacket(channelName, buf);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
package com.seibel.lod.common.wrappers;
|
package com.seibel.lod.common.wrappers;
|
||||||
|
|
||||||
import com.seibel.lod.common.LodCommonMain;
|
import com.seibel.lod.common.LodCommonMain;
|
||||||
import com.seibel.lod.common.wrappers.block.BlockColorSingletonWrapper;
|
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
|
||||||
import com.seibel.lod.common.wrappers.minecraft.MinecraftRenderWrapper;
|
import com.seibel.lod.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||||
import com.seibel.lod.common.wrappers.minecraft.MinecraftWrapper;
|
|
||||||
import com.seibel.lod.core.handlers.IReflectionHandler;
|
import com.seibel.lod.core.handlers.IReflectionHandler;
|
||||||
import com.seibel.lod.core.handlers.ReflectionHandler;
|
import com.seibel.lod.core.handlers.ReflectionHandler;
|
||||||
import com.seibel.lod.core.util.SingletonHandler;
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
|
import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorSingletonWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds all necessary dependencies, so we
|
* Binds all necessary dependencies, so we
|
||||||
@@ -24,14 +22,15 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
|
|||||||
* @version 12-1-2021
|
* @version 12-1-2021
|
||||||
*/
|
*/
|
||||||
public class DependencySetup {
|
public class DependencySetup {
|
||||||
public static void createInitialBindings() {
|
public static void createInitialBindings()
|
||||||
SingletonHandler.bind(IBlockColorSingletonWrapper.class, BlockColorSingletonWrapper.INSTANCE);
|
{
|
||||||
if (!LodCommonMain.serverSided) {
|
|
||||||
SingletonHandler.bind(IMinecraftWrapper.class, MinecraftWrapper.INSTANCE);
|
|
||||||
SingletonHandler.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
|
|
||||||
SingletonHandler.bind(IReflectionHandler.class, ReflectionHandler.createSingleton(MinecraftWrapper.INSTANCE.getOptions().getClass().getDeclaredFields(), MinecraftWrapper.INSTANCE.getOptions()));
|
|
||||||
}
|
|
||||||
SingletonHandler.bind(IVersionConstants.class, VersionConstants.INSTANCE);
|
SingletonHandler.bind(IVersionConstants.class, VersionConstants.INSTANCE);
|
||||||
|
if (!LodCommonMain.serverSided)
|
||||||
|
{
|
||||||
|
SingletonHandler.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE);
|
||||||
|
SingletonHandler.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
|
||||||
|
SingletonHandler.bind(IReflectionHandler.class, ReflectionHandler.createSingleton(MinecraftClientWrapper.INSTANCE.getOptions().getClass().getDeclaredFields(), MinecraftClientWrapper.INSTANCE.getOptions()));
|
||||||
|
}
|
||||||
|
|
||||||
SingletonHandler.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
|
SingletonHandler.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
|
||||||
DependencySetupDoneCheck.isDone = true;
|
DependencySetupDoneCheck.isDone = true;
|
||||||
|
|||||||
@@ -22,9 +22,12 @@ package com.seibel.lod.common.wrappers;
|
|||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
import com.mojang.math.Matrix4f;
|
import com.mojang.math.Matrix4f;
|
||||||
|
import com.seibel.lod.common.wrappers.block.BlockPosWrapper;
|
||||||
import com.seibel.lod.core.enums.LodDirection;
|
import com.seibel.lod.core.enums.LodDirection;
|
||||||
import com.seibel.lod.core.objects.math.Mat4f;
|
import com.seibel.lod.core.objects.math.Mat4f;
|
||||||
|
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,8 +50,30 @@ public class McObjectConverter
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static final Direction[] directions;
|
||||||
|
static final LodDirection[] lodDirections;
|
||||||
|
static {
|
||||||
|
LodDirection[] lodDirs = LodDirection.values();
|
||||||
|
directions = new Direction[lodDirs.length];
|
||||||
|
lodDirections = new LodDirection[lodDirs.length];
|
||||||
|
for (LodDirection lodDir : lodDirs) {
|
||||||
|
Direction dir = Direction.byName(lodDir.name());
|
||||||
|
directions[lodDir.ordinal()] = dir;
|
||||||
|
lodDirections[dir.ordinal()] = lodDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockPos Convert(AbstractBlockPosWrapper wrappedPos) {
|
||||||
|
return new BlockPos(wrappedPos.getX(),wrappedPos.getY(), wrappedPos.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Direction Convert(LodDirection lodDirection)
|
public static Direction Convert(LodDirection lodDirection)
|
||||||
{
|
{
|
||||||
return Direction.byName(lodDirection.name());
|
return directions[lodDirection.ordinal()];
|
||||||
|
}
|
||||||
|
public static LodDirection Convert(Direction direction)
|
||||||
|
{
|
||||||
|
return lodDirections[direction.ordinal()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,38 +24,16 @@ public class VersionConstants implements IVersionConstants
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isWorldGeneratorSingleThreaded(DistanceGenerationMode distanceGenerationMode)
|
|
||||||
{
|
|
||||||
// We are always asking the server to generate the chunk,
|
|
||||||
// so no use running this stuff multithreaded.
|
|
||||||
return true;
|
|
||||||
/*
|
|
||||||
switch (distanceGenerationMode) {
|
|
||||||
default:
|
|
||||||
case NONE:
|
|
||||||
case BIOME_ONLY:
|
|
||||||
case BIOME_ONLY_SIMULATE_HEIGHT:
|
|
||||||
case SURFACE:
|
|
||||||
case FEATURES:
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case FULL:
|
|
||||||
return true;
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getWorldGenerationCountPerThread()
|
public int getWorldGenerationCountPerThread()
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasBatchGenerationImplementation()
|
public boolean isVanillaRenderedChunkSquare()
|
||||||
{
|
{
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,11 +26,9 @@ import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
|
|||||||
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractWorldGeneratorWrapper;
|
|
||||||
import com.seibel.lod.common.wrappers.block.BlockPosWrapper;
|
import com.seibel.lod.common.wrappers.block.BlockPosWrapper;
|
||||||
import com.seibel.lod.common.wrappers.chunk.ChunkPosWrapper;
|
import com.seibel.lod.common.wrappers.chunk.ChunkPosWrapper;
|
||||||
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.lod.common.wrappers.worldGeneration.WorldGeneratorWrapper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This handles creating abstract wrapper objects.
|
* This handles creating abstract wrapper objects.
|
||||||
@@ -88,14 +86,6 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
return new ChunkPosWrapper(blockPos);
|
return new ChunkPosWrapper(blockPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AbstractWorldGeneratorWrapper createWorldGenerator(LodBuilder newLodBuilder, LodDimension newLodDimension, IWorldWrapper worldWrapper)
|
|
||||||
{
|
|
||||||
return new WorldGeneratorWrapper(newLodBuilder, newLodDimension, worldWrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AbstractBatchGenerationEnvionmentWrapper createBatchGenerator(LodBuilder newLodBuilder,
|
public AbstractBatchGenerationEnvionmentWrapper createBatchGenerator(LodBuilder newLodBuilder,
|
||||||
LodDimension newLodDimension, IWorldWrapper worldWrapper)
|
LodDimension newLodDimension, IWorldWrapper worldWrapper)
|
||||||
{
|
{
|
||||||
|
|||||||
-46
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
|
|
||||||
* licensed under the GNU GPL v3 License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 James Seibel
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.seibel.lod.common.wrappers.block;
|
|
||||||
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorSingletonWrapper;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorWrapper;
|
|
||||||
|
|
||||||
import net.minecraft.world.level.block.Blocks;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains methods that would have been static in BlockColorWrapper.
|
|
||||||
* Since interfaces can't create/implement static methods we have
|
|
||||||
* to split the object up in two.
|
|
||||||
*
|
|
||||||
* @author James Seibel
|
|
||||||
* @version 11-17-2021
|
|
||||||
*/
|
|
||||||
public class BlockColorSingletonWrapper implements IBlockColorSingletonWrapper
|
|
||||||
{
|
|
||||||
public static final BlockColorSingletonWrapper INSTANCE = new BlockColorSingletonWrapper();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBlockColorWrapper getWaterColor()
|
|
||||||
{
|
|
||||||
return BlockColorWrapper.getBlockColorWrapper(Blocks.WATER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,323 +0,0 @@
|
|||||||
package com.seibel.lod.common.wrappers.block;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
|
|
||||||
import com.seibel.lod.common.wrappers.minecraft.MinecraftWrapper;
|
|
||||||
import com.seibel.lod.core.util.ColorUtil;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorWrapper;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.Blocks;
|
|
||||||
import net.minecraft.world.level.block.BushBlock;
|
|
||||||
import net.minecraft.world.level.block.FlowerBlock;
|
|
||||||
import net.minecraft.world.level.block.GrassBlock;
|
|
||||||
import net.minecraft.world.level.block.LeavesBlock;
|
|
||||||
import net.minecraft.world.level.block.TallGrassBlock;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author James Seibel
|
|
||||||
* @version 11-21-2021
|
|
||||||
*/
|
|
||||||
public class BlockColorWrapper implements IBlockColorWrapper
|
|
||||||
{
|
|
||||||
//set of block which require tint
|
|
||||||
public static final ConcurrentMap<Block, BlockColorWrapper> blockColorWrapperMap = new ConcurrentHashMap<>();
|
|
||||||
// public static final ModelDataMap dataMap = new ModelDataMap.Builder().build();
|
|
||||||
public static final AbstractBlockPosWrapper blockPos = new BlockPosWrapper(0, 0, 0);
|
|
||||||
public static final Random random = new Random(0);
|
|
||||||
//public static BlockColourWrapper WATER_COLOR = getBlockColorWrapper(Blocks.WATER);
|
|
||||||
public static final Direction[] directions = new Direction[] { Direction.UP, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH, Direction.DOWN };
|
|
||||||
|
|
||||||
private final Block block;
|
|
||||||
private int color;
|
|
||||||
private boolean isColored;
|
|
||||||
private boolean toTint;
|
|
||||||
private boolean foliageTint;
|
|
||||||
private boolean grassTint;
|
|
||||||
private boolean waterTint;
|
|
||||||
|
|
||||||
|
|
||||||
/**Constructor only require for the block instance we are wrapping**/
|
|
||||||
public BlockColorWrapper(Block block)
|
|
||||||
{
|
|
||||||
this.block = block;
|
|
||||||
this.color = 0;
|
|
||||||
this.isColored = true;
|
|
||||||
this.toTint = false;
|
|
||||||
this.foliageTint = false;
|
|
||||||
this.grassTint = false;
|
|
||||||
this.waterTint = false;
|
|
||||||
setupColorAndTint();
|
|
||||||
/*StringBuilder s = new StringBuilder();
|
|
||||||
s.append(block + "\n"
|
|
||||||
+ Integer.toHexString(
|
|
||||||
Minecraft.getInstance().getBlockColors().createDefault().getColor(
|
|
||||||
block.defaultBlockState(),
|
|
||||||
(World) MinecraftWrapper.INSTANCE.getWrappedServerLevel().getLevel(),
|
|
||||||
blockPosWrapper.getBlockPos())) + "\n"
|
|
||||||
);
|
|
||||||
for(Property x : Minecraft.getInstance().getBlockColors().getColoringProperties(block))
|
|
||||||
s.append(x.getName() + " " + x.getPossibleValues() + '\n');
|
|
||||||
System.out.println(s);*/
|
|
||||||
//System.out.println(block + " color " + Integer.toHexString(color) + " to tint " + toTint + " folliageTint " + folliageTint + " grassTint " + grassTint + " waterTint " + waterTint);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this return a wrapper of the block in input
|
|
||||||
* @param block object of the block to wrap
|
|
||||||
*/
|
|
||||||
public static IBlockColorWrapper getBlockColorWrapper(Block block)
|
|
||||||
{
|
|
||||||
//first we check if the block has already been wrapped
|
|
||||||
BlockColorWrapper colorWrapper = blockColorWrapperMap.get(block);
|
|
||||||
if (colorWrapper != null)
|
|
||||||
return colorWrapper;
|
|
||||||
|
|
||||||
//if it hasn't been created yet, we create it and save it in the map
|
|
||||||
colorWrapper = new BlockColorWrapper(block);
|
|
||||||
BlockColorWrapper colorWrapperCAS = blockColorWrapperMap.putIfAbsent(block, colorWrapper);
|
|
||||||
//we return the newly created wrapper
|
|
||||||
return colorWrapperCAS==null ? colorWrapper : colorWrapperCAS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate the color of the given block from its texture
|
|
||||||
* and store it for later use.
|
|
||||||
*/
|
|
||||||
private void setupColorAndTint()
|
|
||||||
{
|
|
||||||
BlockState blockState = block.defaultBlockState();
|
|
||||||
//BlockPosWrapper blockPosWrapper = new BlockPosWrapper();
|
|
||||||
MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
|
|
||||||
TextureAtlasSprite texture;
|
|
||||||
List<BakedQuad> quads = null;
|
|
||||||
|
|
||||||
//boolean isTinted = false;
|
|
||||||
//int listSize = 0;
|
|
||||||
|
|
||||||
// first step is to check if this block has a tinted face
|
|
||||||
//for (Direction direction : directions)
|
|
||||||
//{
|
|
||||||
// quads = mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random);
|
|
||||||
// listSize = Math.max(listSize, quads.size());
|
|
||||||
// for (BakedQuad bakedQuad : quads)
|
|
||||||
// {
|
|
||||||
// isTinted |= bakedQuad.isTinted();
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//if it contains a tinted face then we store this block in the toTint set
|
|
||||||
//if (isTinted)
|
|
||||||
// this.toTint = true;
|
|
||||||
|
|
||||||
//now we get the first non-empty face
|
|
||||||
for (Direction direction : directions)
|
|
||||||
{
|
|
||||||
quads = mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random);
|
|
||||||
if (!quads.isEmpty())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//the quads list is not empty we extract the first one
|
|
||||||
if (!quads.isEmpty())
|
|
||||||
{
|
|
||||||
isColored = true;
|
|
||||||
texture = quads.get(0).getSprite();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
isColored = true;
|
|
||||||
texture = mc.getModelManager().getBlockModelShaper().getParticleIcon(block.defaultBlockState());
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
int alpha = 0;
|
|
||||||
int red = 0;
|
|
||||||
int green = 0;
|
|
||||||
int blue = 0;
|
|
||||||
int numberOfGreyPixel = 0;
|
|
||||||
int tempColor;
|
|
||||||
int colorMultiplier;
|
|
||||||
|
|
||||||
// generate the block's color
|
|
||||||
// for (int frameIndex = 0; frameIndex < texture.getFrameCount(); frameIndex++)
|
|
||||||
boolean lookForTint = grassInstance() || leavesInstance() || waterIstance();
|
|
||||||
|
|
||||||
int frameIndex = 0; // TODO
|
|
||||||
{
|
|
||||||
// textures normally use u and v instead of x and y
|
|
||||||
for (int u = 0; u < texture.getWidth(); u++)
|
|
||||||
{
|
|
||||||
for (int v = 0; v < texture.getHeight(); v++)
|
|
||||||
{
|
|
||||||
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, frameIndex, u, v);
|
|
||||||
|
|
||||||
if (ColorUtil.getAlpha(TextureAtlasSpriteWrapper.getPixelRGBA(texture, frameIndex, u, v)) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (lookForTint)
|
|
||||||
{
|
|
||||||
// determine if this pixel is gray
|
|
||||||
int colorMax = Math.max(Math.max(ColorUtil.getBlue(tempColor), ColorUtil.getGreen(tempColor)), ColorUtil.getRed(tempColor));
|
|
||||||
int colorMin = 4 + Math.min(Math.min(ColorUtil.getBlue(tempColor), ColorUtil.getGreen(tempColor)), ColorUtil.getRed(tempColor));
|
|
||||||
boolean isGray = colorMax < colorMin;
|
|
||||||
if (isGray)
|
|
||||||
numberOfGreyPixel++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// for flowers, weight their non-green color higher
|
|
||||||
if (block instanceof FlowerBlock && (!(ColorUtil.getGreen(tempColor) > (ColorUtil.getBlue(tempColor) + 30)) || !(ColorUtil.getGreen(tempColor) > (ColorUtil.getRed(tempColor) + 30))))
|
|
||||||
colorMultiplier = 5;
|
|
||||||
else
|
|
||||||
colorMultiplier = 1;
|
|
||||||
|
|
||||||
|
|
||||||
// add to the running averages
|
|
||||||
count += colorMultiplier;
|
|
||||||
alpha += ColorUtil.getAlpha(tempColor) * colorMultiplier;
|
|
||||||
red += ColorUtil.getBlue(tempColor) * colorMultiplier;
|
|
||||||
green += ColorUtil.getGreen(tempColor) * colorMultiplier;
|
|
||||||
blue += ColorUtil.getRed(tempColor) * colorMultiplier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (count == 0)
|
|
||||||
// this block is entirely transparent
|
|
||||||
tempColor = 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// determine the average color
|
|
||||||
alpha /= count;
|
|
||||||
red /= count;
|
|
||||||
green /= count;
|
|
||||||
blue /= count;
|
|
||||||
tempColor = ColorUtil.rgbToInt(alpha, red, green, blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine if this block should use the biome color tint
|
|
||||||
if (lookForTint && (float) numberOfGreyPixel / count > 0.75f)
|
|
||||||
this.toTint = true;
|
|
||||||
|
|
||||||
// we check which kind of tint we need to apply
|
|
||||||
this.grassTint = grassInstance() && toTint;
|
|
||||||
|
|
||||||
this.foliageTint = leavesInstance() && toTint;
|
|
||||||
|
|
||||||
this.waterTint = waterIstance() && toTint;
|
|
||||||
|
|
||||||
//hardcoded leaves
|
|
||||||
if (block == Blocks.SPRUCE_LEAVES)
|
|
||||||
color = ColorUtil.multiplyRGBcolors(tempColor, 0xFF619961);
|
|
||||||
else if (block == Blocks.BIRCH_LEAVES)
|
|
||||||
color = ColorUtil.multiplyRGBcolors(tempColor, 0xFF80A755);
|
|
||||||
else
|
|
||||||
color = tempColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** determine if the given block should use the biome's grass color */
|
|
||||||
private boolean grassInstance()
|
|
||||||
{
|
|
||||||
return block instanceof GrassBlock
|
|
||||||
|| block instanceof BushBlock
|
|
||||||
// || block instanceof IGrowable
|
|
||||||
// || block instanceof AbstractPlantBlock
|
|
||||||
// || block instanceof AbstractTopPlantBlock
|
|
||||||
|| block instanceof TallGrassBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** determine if the given block should use the biome's foliage color */
|
|
||||||
private boolean leavesInstance()
|
|
||||||
{
|
|
||||||
return (block instanceof LeavesBlock && block != Blocks.SPRUCE_LEAVES && block != Blocks.BIRCH_LEAVES/* && block != Blocks.AZALEA_LEAVES && block != Blocks.FLOWERING_AZALEA_LEAVES*/)
|
|
||||||
|| block == Blocks.VINE
|
|
||||||
|| block == Blocks.SUGAR_CANE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** determine if the given block should use the biome's foliage color */
|
|
||||||
private boolean waterIstance()
|
|
||||||
{
|
|
||||||
return block == Blocks.WATER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName(){
|
|
||||||
return block.getName().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------//
|
|
||||||
//Colors getters//
|
|
||||||
//--------------//
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasColor()
|
|
||||||
{
|
|
||||||
return isColored;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getColor()
|
|
||||||
{
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------//
|
|
||||||
//Tint getters//
|
|
||||||
//------------//
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasTint()
|
|
||||||
{
|
|
||||||
return toTint;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasGrassTint()
|
|
||||||
{
|
|
||||||
return grassTint;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasFolliageTint()
|
|
||||||
{
|
|
||||||
return foliageTint;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasWaterTint()
|
|
||||||
{
|
|
||||||
return waterTint;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override public boolean equals(Object o)
|
|
||||||
{
|
|
||||||
if (this == o)
|
|
||||||
return true;
|
|
||||||
if (!(o instanceof BlockColorWrapper))
|
|
||||||
return false;
|
|
||||||
BlockColorWrapper that = (BlockColorWrapper) o;
|
|
||||||
return Objects.equals(block, that.block);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int hashCode()
|
|
||||||
{
|
|
||||||
return Objects.hash(block);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.seibel.lod.common.wrappers.block;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
public class BlockDetailMap
|
||||||
|
{
|
||||||
|
|
||||||
|
private static ConcurrentHashMap<BlockState, BlockDetailWrapper> map = new ConcurrentHashMap<BlockState, BlockDetailWrapper>();
|
||||||
|
|
||||||
|
private BlockDetailMap() {}
|
||||||
|
|
||||||
|
public static BlockDetailWrapper getOrMakeBlockDetailCache(BlockState bs, BlockPos pos, LevelReader getter) {
|
||||||
|
BlockDetailWrapper cache = map.get(bs);
|
||||||
|
if (cache != null) return cache;
|
||||||
|
if (bs.getFluidState().isEmpty()) {
|
||||||
|
cache = BlockDetailWrapper.make(bs, pos, getter);
|
||||||
|
} else {
|
||||||
|
cache = BlockDetailWrapper.make(bs.getFluidState().createLegacyBlock(), pos, getter);
|
||||||
|
}
|
||||||
|
BlockDetailWrapper cacheCAS = map.putIfAbsent(bs, cache);
|
||||||
|
return cacheCAS==null ? cache : cacheCAS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,315 @@
|
|||||||
|
package com.seibel.lod.common.wrappers.block;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import com.seibel.lod.common.Config;
|
||||||
|
import com.seibel.lod.common.wrappers.McObjectConverter;
|
||||||
|
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
|
||||||
|
import com.seibel.lod.core.api.ApiShared;
|
||||||
|
import com.seibel.lod.core.enums.LodDirection;
|
||||||
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
|
import com.seibel.lod.core.util.ColorUtil;
|
||||||
|
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
|
||||||
|
import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper;
|
||||||
|
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
|
|
||||||
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||||
|
import net.minecraft.Util;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.color.block.BlockTintCache;
|
||||||
|
import net.minecraft.client.renderer.BiomeColors;
|
||||||
|
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||||
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Cursor3D;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.level.*;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.FlowerBlock;
|
||||||
|
import net.minecraft.world.level.block.LeavesBlock;
|
||||||
|
import net.minecraft.world.level.block.RenderShape;
|
||||||
|
import net.minecraft.world.level.block.RotatedPillarBlock;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class BlockDetailWrapper extends IBlockDetailWrapper
|
||||||
|
{
|
||||||
|
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
|
||||||
|
|
||||||
|
public static final int FLOWER_COLOR_SCALE = 5;
|
||||||
|
|
||||||
|
public static final Random random = new Random(0);
|
||||||
|
|
||||||
|
enum ColorMode {
|
||||||
|
Default,
|
||||||
|
Flower,
|
||||||
|
Leaves;
|
||||||
|
static ColorMode getColorMode(Block b) {
|
||||||
|
if (b instanceof LeavesBlock) return Leaves;
|
||||||
|
if (b instanceof FlowerBlock) return Flower;
|
||||||
|
return Default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO: Perhaps make this not just use the first frame?
|
||||||
|
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode) {
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
double alpha = 0;
|
||||||
|
double red = 0;
|
||||||
|
double green = 0;
|
||||||
|
double blue = 0;
|
||||||
|
int tempColor;
|
||||||
|
|
||||||
|
{
|
||||||
|
// textures normally use u and v instead of x and y
|
||||||
|
for (int u = 0; u < texture.getWidth(); u++)
|
||||||
|
{
|
||||||
|
for (int v = 0; v < texture.getHeight(); v++)
|
||||||
|
{
|
||||||
|
//note: Minecraft color format is: 0xAA BB GG RR
|
||||||
|
//________ DH mod color format is: 0xAA RR GG BB
|
||||||
|
//OpenGL RGBA format native order: 0xRR GG BB AA
|
||||||
|
//_ OpenGL RGBA format Java Order: 0xAA BB GG RR
|
||||||
|
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
|
||||||
|
|
||||||
|
double r = ((tempColor & 0x000000FF) )/255.;
|
||||||
|
double g = ((tempColor & 0x0000FF00) >>> 8)/255.;
|
||||||
|
double b = ((tempColor & 0x00FF0000) >>> 16)/255.;
|
||||||
|
double a = ((tempColor & 0xFF000000) >>> 24)/255.;
|
||||||
|
int scale = 1;
|
||||||
|
|
||||||
|
if (colorMode == ColorMode.Leaves) {
|
||||||
|
r *= a;
|
||||||
|
g *= a;
|
||||||
|
b *= a;
|
||||||
|
a = 1.;
|
||||||
|
} else if (a==0.) {
|
||||||
|
continue;
|
||||||
|
} else if (colorMode == ColorMode.Flower && (g+0.1<b || g+0.1<r)) {
|
||||||
|
scale = FLOWER_COLOR_SCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
count += scale;
|
||||||
|
alpha += a*a*scale;
|
||||||
|
red += r*r*scale;
|
||||||
|
green += g*g*scale;
|
||||||
|
blue += b*b*scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
// this block is entirely transparent
|
||||||
|
tempColor = ColorUtil.rgbToInt(255,255,0,255);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// determine the average color
|
||||||
|
tempColor = ColorUtil.rgbToInt(
|
||||||
|
(int) (Math.sqrt(alpha/count)*255.),
|
||||||
|
(int) (Math.sqrt(red / count)*255.),
|
||||||
|
(int) (Math.sqrt(green / count)*255.),
|
||||||
|
(int) (Math.sqrt(blue / count)*255.));
|
||||||
|
}
|
||||||
|
// TODO: Remove this when transparency is added!
|
||||||
|
double colorAlpha = ColorUtil.getAlpha(tempColor)/255.;
|
||||||
|
tempColor = ColorUtil.rgbToInt(
|
||||||
|
ColorUtil.getAlpha(tempColor),
|
||||||
|
(int)(ColorUtil.getRed(tempColor) * colorAlpha),
|
||||||
|
(int)(ColorUtil.getGreen(tempColor) * colorAlpha),
|
||||||
|
(int)(ColorUtil.getBlue(tempColor) * colorAlpha)
|
||||||
|
);
|
||||||
|
return tempColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static final Block[] BLOCK_TO_AVOID = {Blocks.AIR, Blocks.CAVE_AIR, Blocks.BARRIER};
|
||||||
|
|
||||||
|
private static final Direction[] DIRECTION_ORDER = {Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN};
|
||||||
|
|
||||||
|
private static boolean isBlockToBeAvoid(Block b) {
|
||||||
|
for (Block bta : BLOCK_TO_AVOID)
|
||||||
|
if (bta==b) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final BlockState state;
|
||||||
|
final BlockPos samplePos;
|
||||||
|
final LevelReader sampleGetter;
|
||||||
|
|
||||||
|
boolean isShapeResolved = false;
|
||||||
|
boolean[] dontOccludeFaces = null;
|
||||||
|
boolean noCollision = false;
|
||||||
|
boolean noFullFace = false;
|
||||||
|
|
||||||
|
boolean isColorResolved = false;
|
||||||
|
int baseColor = 0; //TODO: Impl per-face color
|
||||||
|
boolean needShade = true;
|
||||||
|
boolean needPostTinting = false;
|
||||||
|
int tintIndex = 0;
|
||||||
|
|
||||||
|
public static BlockDetailWrapper NULL_BLOCK_DETAIL = new BlockDetailWrapper();
|
||||||
|
|
||||||
|
public BlockDetailWrapper(BlockState state, BlockPos pos, LevelReader getter) {
|
||||||
|
this.state = state;
|
||||||
|
this.samplePos = pos;
|
||||||
|
this.sampleGetter = getter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockDetailWrapper() {
|
||||||
|
this.state = null;
|
||||||
|
this.samplePos = null;
|
||||||
|
this.sampleGetter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BlockDetailWrapper make(BlockState bs, BlockPos pos, LevelReader getter) {
|
||||||
|
if(!bs.getFluidState().isEmpty()) { // Is a fluidBlock
|
||||||
|
if (isBlockToBeAvoid(bs.getBlock())) return NULL_BLOCK_DETAIL;
|
||||||
|
if (bs.isAir()) return NULL_BLOCK_DETAIL;
|
||||||
|
return new BlockDetailWrapper(bs, pos, getter);
|
||||||
|
} else {
|
||||||
|
if (bs.getRenderShape() != RenderShape.MODEL) return NULL_BLOCK_DETAIL;
|
||||||
|
if (isBlockToBeAvoid(bs.getBlock())) return NULL_BLOCK_DETAIL;
|
||||||
|
return new BlockDetailWrapper(bs, pos, getter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resolveShapes() {
|
||||||
|
if (isShapeResolved) return;
|
||||||
|
if (state.getFluidState().isEmpty()) {
|
||||||
|
noCollision = state.getCollisionShape(sampleGetter, samplePos).isEmpty();
|
||||||
|
dontOccludeFaces = new boolean[6];
|
||||||
|
if (state.canOcclude()) {
|
||||||
|
/* FIXME: Figure out how or if needed to impl per-face culling?
|
||||||
|
for (Direction dir : Direction.values()) {
|
||||||
|
dontOccludeFaces[McObjectConverter.Convert(dir).ordinal()]
|
||||||
|
= state.getFaceOcclusionShape(sampleGetter, samplePos, dir).isEmpty();
|
||||||
|
}*/
|
||||||
|
} else {
|
||||||
|
Arrays.fill(dontOccludeFaces, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
VoxelShape voxelShape = state.getShape(sampleGetter, samplePos);
|
||||||
|
if (voxelShape.isEmpty()) {
|
||||||
|
noFullFace = true;
|
||||||
|
} else {
|
||||||
|
AABB bbox = voxelShape.bounds();
|
||||||
|
double xWidth = (bbox.maxX - bbox.minX);
|
||||||
|
double yWidth = (bbox.maxY - bbox.minY);
|
||||||
|
double zWidth = (bbox.maxZ - bbox.minZ);
|
||||||
|
noFullFace = xWidth < 1 && zWidth < 1 && yWidth < 1;
|
||||||
|
}
|
||||||
|
} else { // Liquid Block
|
||||||
|
dontOccludeFaces = new boolean[6];
|
||||||
|
}
|
||||||
|
isShapeResolved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resolveColors() {
|
||||||
|
if (isColorResolved) return;
|
||||||
|
if (state.getFluidState().isEmpty()) {
|
||||||
|
List<BakedQuad> quads = null;
|
||||||
|
for (Direction direction : DIRECTION_ORDER)
|
||||||
|
{
|
||||||
|
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
||||||
|
getBlockModel(state).getQuads(state, direction, random);
|
||||||
|
if (!quads.isEmpty() &&
|
||||||
|
!(state.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP))
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if (quads != null && !quads.isEmpty()) {
|
||||||
|
needPostTinting = quads.get(0).isTinted();
|
||||||
|
needShade = quads.get(0).isShade();
|
||||||
|
tintIndex = quads.get(0).getTintIndex();
|
||||||
|
baseColor = calculateColorFromTexture(quads.get(0).getSprite(),
|
||||||
|
ColorMode.getColorMode(state.getBlock()));
|
||||||
|
}
|
||||||
|
} else { // Liquid Block
|
||||||
|
|
||||||
|
needPostTinting = true;
|
||||||
|
needShade = false;
|
||||||
|
tintIndex = 0;
|
||||||
|
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(state),
|
||||||
|
ColorMode.getColorMode(state.getBlock()));
|
||||||
|
|
||||||
|
}
|
||||||
|
isColorResolved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockAndTintGetter wrapColorResolver(LevelReader level) {
|
||||||
|
int blendDistance = CONFIG.client().graphics().quality().getLodBiomeBlending();
|
||||||
|
if (blendDistance == 0) {
|
||||||
|
return new TintGetterOverrideFast(level);
|
||||||
|
} else {
|
||||||
|
return new TintGetterOverrideSmooth(level, blendDistance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAndResolveFaceColor(LodDirection dir, IChunkWrapper chunk, AbstractBlockPosWrapper blockPos)
|
||||||
|
{
|
||||||
|
// FIXME: impl per-face colors
|
||||||
|
resolveColors();
|
||||||
|
if (!needPostTinting) return baseColor;
|
||||||
|
int tintColor = Minecraft.getInstance().getBlockColors()
|
||||||
|
.getColor(state, wrapColorResolver(((ChunkWrapper)chunk).getColorResolver()),
|
||||||
|
McObjectConverter.Convert(blockPos), tintIndex);
|
||||||
|
if (tintColor == -1) return baseColor;
|
||||||
|
return ColorUtil.multiplyARGBwithRGB(baseColor, tintColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasFaceCullingFor(LodDirection dir)
|
||||||
|
{
|
||||||
|
resolveShapes();
|
||||||
|
return !dontOccludeFaces[dir.ordinal()];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNoCollision()
|
||||||
|
{
|
||||||
|
resolveShapes();
|
||||||
|
return noCollision;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean noFaceIsFullFace()
|
||||||
|
{
|
||||||
|
resolveShapes();
|
||||||
|
return noFullFace;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String serialize()
|
||||||
|
{
|
||||||
|
// FIXME: Impl this for the blockState Storage stuff
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isSame(IBlockDetailWrapper iBlockDetail)
|
||||||
|
{
|
||||||
|
return ((BlockDetailWrapper)iBlockDetail).state.getBlock().equals(state.getBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
|
|
||||||
package com.seibel.lod.common.wrappers.block;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockShapeWrapper;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
|
||||||
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
|
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.Blocks;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
|
||||||
import net.minecraft.world.phys.AABB;
|
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author James Seibel
|
|
||||||
* @version 11-21-2021
|
|
||||||
*/
|
|
||||||
public class BlockShapeWrapper implements IBlockShapeWrapper
|
|
||||||
{
|
|
||||||
//set of block which require tint
|
|
||||||
public static final ConcurrentMap<Block, BlockShapeWrapper> blockShapeWrapperMap = new ConcurrentHashMap<>();
|
|
||||||
public static BlockShapeWrapper WATER_SHAPE = new BlockShapeWrapper();
|
|
||||||
|
|
||||||
private final Block block;
|
|
||||||
private final boolean toAvoid;
|
|
||||||
private boolean nonFull;
|
|
||||||
private boolean noCollision;
|
|
||||||
|
|
||||||
/**Constructor only require for the block instance we are wrapping**/
|
|
||||||
public BlockShapeWrapper(Block block, IChunkWrapper chunkWrapper, int x, int y, int z)
|
|
||||||
{
|
|
||||||
this.block = block;
|
|
||||||
this.nonFull = false;
|
|
||||||
this.noCollision = false;
|
|
||||||
this.toAvoid = ofBlockToAvoid();
|
|
||||||
setupShapes(chunkWrapper, x, y, z);
|
|
||||||
//System.out.println(block + " non full " + nonFull + " no collision " + noCollision + " to avoid " + toAvoid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private BlockShapeWrapper()
|
|
||||||
{
|
|
||||||
this.block = Blocks.WATER;
|
|
||||||
this.nonFull = false;
|
|
||||||
this.noCollision = false;
|
|
||||||
this.toAvoid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this return a wrapper of the block in input
|
|
||||||
* @param block Block object to wrap
|
|
||||||
*/
|
|
||||||
static public BlockShapeWrapper getBlockShapeWrapper(Block block, ChunkWrapper chunkWrapper, int x, int y, int z)
|
|
||||||
{
|
|
||||||
//first we check if the block has already been wrapped
|
|
||||||
BlockShapeWrapper blockWrapper = blockShapeWrapperMap.get(block);
|
|
||||||
if (blockWrapper != null)
|
|
||||||
return blockWrapper;
|
|
||||||
|
|
||||||
//if it hasn't been created yet, we create it and save it in the map
|
|
||||||
blockWrapper = new BlockShapeWrapper(block, chunkWrapper, x, y, z);
|
|
||||||
BlockShapeWrapper blockWrapperCAS = blockShapeWrapperMap.putIfAbsent(block, blockWrapper);
|
|
||||||
//we return the newly created wrapper
|
|
||||||
return blockWrapperCAS==null ? blockWrapper : blockWrapperCAS;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupShapes(IChunkWrapper chunkWrapper, int x, int y, int z)
|
|
||||||
{
|
|
||||||
ChunkAccess chunk = ((ChunkWrapper) chunkWrapper).getChunk();
|
|
||||||
BlockPos blockPos = new BlockPos(x, y, z);
|
|
||||||
boolean noCollisionSetted = false;
|
|
||||||
boolean nonFullSetted = false;
|
|
||||||
if (!block.defaultBlockState().getFluidState().isEmpty())// || block instanceof SixWayBlock)
|
|
||||||
{
|
|
||||||
noCollisionSetted = true;
|
|
||||||
nonFullSetted = true;
|
|
||||||
noCollision = false;
|
|
||||||
nonFull = false;
|
|
||||||
}
|
|
||||||
if (!nonFullSetted)
|
|
||||||
{
|
|
||||||
VoxelShape voxelShape = block.defaultBlockState().getShape(chunk, blockPos);
|
|
||||||
|
|
||||||
if (!voxelShape.isEmpty())
|
|
||||||
{
|
|
||||||
AABB bbox = voxelShape.bounds();
|
|
||||||
double xWidth = (bbox.maxX - bbox.minX);
|
|
||||||
double yWidth = (bbox.maxY - bbox.minY);
|
|
||||||
double zWidth = (bbox.maxZ - bbox.minZ);
|
|
||||||
nonFull = xWidth < 1 && zWidth < 1 && yWidth < 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nonFull = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!noCollisionSetted)
|
|
||||||
{
|
|
||||||
VoxelShape collisionShape = block.defaultBlockState().getCollisionShape(chunk, blockPos);
|
|
||||||
noCollision = collisionShape.isEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean ofBlockToAvoid()
|
|
||||||
{
|
|
||||||
return block.equals(Blocks.AIR)
|
|
||||||
|| block.equals(Blocks.CAVE_AIR)
|
|
||||||
|| block.equals(Blocks.BARRIER);
|
|
||||||
}
|
|
||||||
//-----------------//
|
|
||||||
//Avoidance getters//
|
|
||||||
//-----------------//
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isNonFull()
|
|
||||||
{
|
|
||||||
return nonFull;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNoCollision()
|
|
||||||
{
|
|
||||||
return noCollision;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isToAvoid()
|
|
||||||
{
|
|
||||||
return toAvoid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override public boolean equals(Object o)
|
|
||||||
{
|
|
||||||
if (this == o)
|
|
||||||
return true;
|
|
||||||
if (!(o instanceof BlockShapeWrapper))
|
|
||||||
return false;
|
|
||||||
BlockShapeWrapper that = (BlockShapeWrapper) o;
|
|
||||||
return Objects.equals(block, that.block);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int hashCode()
|
|
||||||
{
|
|
||||||
return Objects.hash(block);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+196
@@ -0,0 +1,196 @@
|
|||||||
|
package com.seibel.lod.common.wrappers.block;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||||
|
import net.minecraft.Util;
|
||||||
|
import net.minecraft.client.color.block.BlockTintCache;
|
||||||
|
import net.minecraft.client.renderer.BiomeColors;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Cursor3D;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.level.*;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class TintGetterOverrideFast implements BlockAndTintGetter {
|
||||||
|
LevelReader parent;
|
||||||
|
private final Object2ObjectArrayMap<ColorResolver, ConcurrentHashMap<Biome, Integer>> tintCaches;
|
||||||
|
|
||||||
|
public TintGetterOverrideFast(LevelReader parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.tintCaches = Util.make(new Object2ObjectArrayMap(3), object2ObjectArrayMap -> {
|
||||||
|
object2ObjectArrayMap.put(BiomeColors.GRASS_COLOR_RESOLVER, new ConcurrentHashMap<Biome, Integer>());
|
||||||
|
object2ObjectArrayMap.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new ConcurrentHashMap<Biome, Integer>());
|
||||||
|
object2ObjectArrayMap.put(BiomeColors.WATER_COLOR_RESOLVER, new ConcurrentHashMap<Biome, Integer>());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Biome _getBiome(BlockPos pos) {
|
||||||
|
#if MC_VERSION_1_18_2
|
||||||
|
return parent.getBiome(pos).value();
|
||||||
|
#elif MC_VERSION_1_18_1
|
||||||
|
return parent.getBiome(pos);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) {
|
||||||
|
Biome b = _getBiome(blockPos);
|
||||||
|
return tintCaches.get(colorResolver).computeIfAbsent(b, (key) -> colorResolver.getColor(b, blockPos.getX(), blockPos.getZ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getShade(Direction direction, boolean bl) {
|
||||||
|
return parent.getShade(direction, bl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LevelLightEngine getLightEngine() {
|
||||||
|
return parent.getLightEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBrightness(LightLayer lightLayer, BlockPos blockPos) {
|
||||||
|
return parent.getBrightness(lightLayer, blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRawBrightness(BlockPos blockPos, int i) {
|
||||||
|
return parent.getRawBrightness(blockPos, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSeeSky(BlockPos blockPos) {
|
||||||
|
return parent.canSeeSky(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public BlockEntity getBlockEntity(BlockPos blockPos) {
|
||||||
|
return parent.getBlockEntity(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) {
|
||||||
|
return parent.getBlockEntity(blockPos, blockEntityType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getBlockState(BlockPos blockPos) {
|
||||||
|
return parent.getBlockState(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidState getFluidState(BlockPos blockPos) {
|
||||||
|
return parent.getFluidState(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLightEmission(BlockPos blockPos) {
|
||||||
|
return parent.getLightEmission(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxLightLevel() {
|
||||||
|
return parent.getMaxLightLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<BlockState> getBlockStates(AABB aABB) {
|
||||||
|
return parent.getBlockStates(aABB);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) {
|
||||||
|
return parent.isBlockInLine(clipBlockStateContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockHitResult clip(ClipContext clipContext) {
|
||||||
|
return parent.clip(clipContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState) {
|
||||||
|
return parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier) {
|
||||||
|
return parent.getBlockFloorHeight(voxelShape, supplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBlockFloorHeight(BlockPos blockPos) {
|
||||||
|
return parent.getBlockFloorHeight(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return parent.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMinBuildHeight() {
|
||||||
|
return parent.getMinBuildHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxBuildHeight() {
|
||||||
|
return parent.getMaxBuildHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionsCount() {
|
||||||
|
return parent.getSectionsCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMinSection() {
|
||||||
|
return parent.getMinSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxSection() {
|
||||||
|
return parent.getMaxSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOutsideBuildHeight(BlockPos blockPos) {
|
||||||
|
return parent.isOutsideBuildHeight(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOutsideBuildHeight(int i) {
|
||||||
|
return parent.isOutsideBuildHeight(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionIndex(int i) {
|
||||||
|
return parent.getSectionIndex(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionIndexFromSectionY(int i) {
|
||||||
|
return parent.getSectionIndexFromSectionY(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionYFromSectionIndex(int i) {
|
||||||
|
return parent.getSectionYFromSectionIndex(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
+219
@@ -0,0 +1,219 @@
|
|||||||
|
package com.seibel.lod.common.wrappers.block;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||||
|
import net.minecraft.Util;
|
||||||
|
import net.minecraft.client.color.block.BlockTintCache;
|
||||||
|
import net.minecraft.client.renderer.BiomeColors;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Cursor3D;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.level.*;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class TintGetterOverrideSmooth implements BlockAndTintGetter {
|
||||||
|
LevelReader parent;
|
||||||
|
private final Object2ObjectArrayMap<ColorResolver, BlockTintCache> tintCaches;
|
||||||
|
public int smoothingRange;
|
||||||
|
|
||||||
|
public TintGetterOverrideSmooth(LevelReader parent, int smoothingRange) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.smoothingRange = smoothingRange;
|
||||||
|
this.tintCaches = Util.make(new Object2ObjectArrayMap(3), object2ObjectArrayMap -> {
|
||||||
|
object2ObjectArrayMap.put(BiomeColors.GRASS_COLOR_RESOLVER, new BlockTintCache((pos) -> calculateBlockTint(pos, BiomeColors.GRASS_COLOR_RESOLVER)));
|
||||||
|
object2ObjectArrayMap.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new BlockTintCache((pos) -> calculateBlockTint(pos, BiomeColors.FOLIAGE_COLOR_RESOLVER)));
|
||||||
|
object2ObjectArrayMap.put(BiomeColors.WATER_COLOR_RESOLVER, new BlockTintCache((pos) -> calculateBlockTint(pos, BiomeColors.WATER_COLOR_RESOLVER)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Biome _getBiome(BlockPos pos) {
|
||||||
|
#if MC_VERSION_1_18_2
|
||||||
|
return parent.getBiome(pos).value();
|
||||||
|
#elif MC_VERSION_1_18_1
|
||||||
|
return parent.getBiome(pos);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
||||||
|
{
|
||||||
|
int i = smoothingRange;
|
||||||
|
if (i == 0)
|
||||||
|
return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ());
|
||||||
|
int j = (i * 2 + 1) * (i * 2 + 1);
|
||||||
|
int k = 0;
|
||||||
|
int l = 0;
|
||||||
|
int m = 0;
|
||||||
|
Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i);
|
||||||
|
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||||
|
while (cursor3D.advance())
|
||||||
|
{
|
||||||
|
mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
|
||||||
|
int n = colorResolver.getColor(_getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
|
||||||
|
k += (n & 0xFF0000) >> 16;
|
||||||
|
l += (n & 0xFF00) >> 8;
|
||||||
|
m += n & 0xFF;
|
||||||
|
}
|
||||||
|
return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) {
|
||||||
|
BlockTintCache blockTintCache = this.tintCaches.get(colorResolver);
|
||||||
|
return blockTintCache.getColor(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getShade(Direction direction, boolean bl) {
|
||||||
|
return parent.getShade(direction, bl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LevelLightEngine getLightEngine() {
|
||||||
|
return parent.getLightEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBrightness(LightLayer lightLayer, BlockPos blockPos) {
|
||||||
|
return parent.getBrightness(lightLayer, blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRawBrightness(BlockPos blockPos, int i) {
|
||||||
|
return parent.getRawBrightness(blockPos, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSeeSky(BlockPos blockPos) {
|
||||||
|
return parent.canSeeSky(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public BlockEntity getBlockEntity(BlockPos blockPos) {
|
||||||
|
return parent.getBlockEntity(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) {
|
||||||
|
return parent.getBlockEntity(blockPos, blockEntityType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getBlockState(BlockPos blockPos) {
|
||||||
|
return parent.getBlockState(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidState getFluidState(BlockPos blockPos) {
|
||||||
|
return parent.getFluidState(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLightEmission(BlockPos blockPos) {
|
||||||
|
return parent.getLightEmission(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxLightLevel() {
|
||||||
|
return parent.getMaxLightLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<BlockState> getBlockStates(AABB aABB) {
|
||||||
|
return parent.getBlockStates(aABB);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) {
|
||||||
|
return parent.isBlockInLine(clipBlockStateContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockHitResult clip(ClipContext clipContext) {
|
||||||
|
return parent.clip(clipContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState) {
|
||||||
|
return parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier) {
|
||||||
|
return parent.getBlockFloorHeight(voxelShape, supplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBlockFloorHeight(BlockPos blockPos) {
|
||||||
|
return parent.getBlockFloorHeight(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return parent.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMinBuildHeight() {
|
||||||
|
return parent.getMinBuildHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxBuildHeight() {
|
||||||
|
return parent.getMaxBuildHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionsCount() {
|
||||||
|
return parent.getSectionsCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMinSection() {
|
||||||
|
return parent.getMinSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxSection() {
|
||||||
|
return parent.getMaxSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOutsideBuildHeight(BlockPos blockPos) {
|
||||||
|
return parent.isOutsideBuildHeight(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOutsideBuildHeight(int i) {
|
||||||
|
return parent.isOutsideBuildHeight(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionIndex(int i) {
|
||||||
|
return parent.getSectionIndex(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionIndexFromSectionY(int i) {
|
||||||
|
return parent.getSectionIndexFromSectionY(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionYFromSectionIndex(int i) {
|
||||||
|
return parent.getSectionYFromSectionIndex(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,47 +1,53 @@
|
|||||||
package com.seibel.lod.common.wrappers.chunk;
|
package com.seibel.lod.common.wrappers.chunk;
|
||||||
|
|
||||||
|
import com.seibel.lod.common.wrappers.block.BlockDetailWrapper;
|
||||||
|
import com.seibel.lod.core.enums.LodDirection;
|
||||||
import com.seibel.lod.core.util.LevelPosUtil;
|
import com.seibel.lod.core.util.LevelPosUtil;
|
||||||
import com.seibel.lod.core.util.LodUtil;
|
import com.seibel.lod.core.util.LodUtil;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockShapeWrapper;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
|
|
||||||
import com.seibel.lod.common.wrappers.WrapperUtil;
|
import com.seibel.lod.common.wrappers.WrapperUtil;
|
||||||
import com.seibel.lod.common.wrappers.block.BlockColorWrapper;
|
import com.seibel.lod.common.wrappers.block.BlockDetailMap;
|
||||||
import com.seibel.lod.common.wrappers.block.BlockShapeWrapper;
|
|
||||||
import com.seibel.lod.common.wrappers.world.BiomeWrapper;
|
import com.seibel.lod.common.wrappers.world.BiomeWrapper;
|
||||||
|
import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.LightedWorldGenRegion;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.QuartPos;
|
import net.minecraft.core.QuartPos;
|
||||||
import net.minecraft.world.level.BlockAndTintGetter;
|
import net.minecraft.world.level.LevelReader;
|
||||||
import net.minecraft.world.level.LightLayer;
|
import net.minecraft.world.level.LightLayer;
|
||||||
import net.minecraft.world.level.block.AirBlock;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.LiquidBlock;
|
|
||||||
import net.minecraft.world.level.block.LiquidBlockContainer;
|
import net.minecraft.world.level.block.LiquidBlockContainer;
|
||||||
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
|
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 11-21-2021
|
* @version 3-5-2022
|
||||||
*/
|
*/
|
||||||
public class ChunkWrapper implements IChunkWrapper
|
public class ChunkWrapper implements IChunkWrapper
|
||||||
{
|
{
|
||||||
private final ChunkAccess chunk;
|
private final ChunkAccess chunk;
|
||||||
private final BlockAndTintGetter lightSource;
|
private final LevelReader lightSource;
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight(){
|
public ChunkWrapper(ChunkAccess chunk, LevelReader lightSource)
|
||||||
return chunk.getHeight();
|
{
|
||||||
}
|
this.chunk = chunk;
|
||||||
|
this.lightSource = lightSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight(){
|
||||||
|
return chunk.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMinBuildHeight()
|
public int getMinBuildHeight()
|
||||||
{
|
{
|
||||||
@@ -52,133 +58,151 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
{
|
{
|
||||||
return chunk.getMaxBuildHeight();
|
return chunk.getMaxBuildHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getHeightMapValue(int xRel, int zRel)
|
public int getHeightMapValue(int xRel, int zRel)
|
||||||
{
|
{
|
||||||
return chunk.getOrCreateHeightmapUnprimed(WrapperUtil.DEFAULT_HEIGHTMAP).getFirstAvailable(xRel, zRel);
|
return chunk.getOrCreateHeightmapUnprimed(WrapperUtil.DEFAULT_HEIGHTMAP).getFirstAvailable(xRel, zRel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBiomeWrapper getBiome(int x, int y, int z)
|
public IBiomeWrapper getBiome(int x, int y, int z)
|
||||||
{
|
{
|
||||||
|
#if MC_VERSION_1_18_2
|
||||||
|
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
|
||||||
|
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)).value());
|
||||||
|
#elif MC_VERSION_1_18_1
|
||||||
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
|
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
|
||||||
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
|
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
|
||||||
}
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBlockDetailWrapper getBlockDetail(int x, int y, int z) {
|
||||||
|
BlockPos pos = new BlockPos(x,y,z);
|
||||||
|
BlockState blockState = chunk.getBlockState(pos);
|
||||||
|
IBlockDetailWrapper blockDetail = BlockDetailMap.getOrMakeBlockDetailCache(blockState, pos, lightSource);
|
||||||
|
return blockDetail == BlockDetailWrapper.NULL_BLOCK_DETAIL ? null : blockDetail;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBlockColorWrapper getBlockColorWrapper(int x, int y, int z)
|
public IBlockDetailWrapper getBlockDetailAtFace(int x, int y, int z, LodDirection dir) {
|
||||||
{
|
int fy = y+dir.getNormal().y;
|
||||||
BlockState blockState = chunk.getBlockState(new BlockPos(x,y,z));
|
if (fy < getMinBuildHeight() || fy > getMaxBuildHeight()) return null;
|
||||||
Block block = blockState.getBlock();
|
BlockPos pos = new BlockPos(x+dir.getNormal().x,fy,z+dir.getNormal().z);
|
||||||
return BlockColorWrapper.getBlockColorWrapper(block);
|
BlockState blockState;
|
||||||
|
if (blockPosInsideChunk(x,y,z))
|
||||||
|
blockState = chunk.getBlockState(pos);
|
||||||
|
else {
|
||||||
|
blockState = lightSource.getBlockState(pos);
|
||||||
|
}
|
||||||
|
if (blockState == null || blockState.isAir()) return null;
|
||||||
|
IBlockDetailWrapper blockDetail = BlockDetailMap.getOrMakeBlockDetailCache(blockState, pos, lightSource);
|
||||||
|
return blockDetail == BlockDetailWrapper.NULL_BLOCK_DETAIL ? null : blockDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public ChunkAccess getChunk() {
|
||||||
public IBlockShapeWrapper getBlockShapeWrapper(int x, int y, int z)
|
return chunk;
|
||||||
{
|
}
|
||||||
BlockState blockState = chunk.getBlockState(new BlockPos(x,y,z));
|
|
||||||
Block block = blockState.getBlock();
|
@Override
|
||||||
return BlockShapeWrapper.getBlockShapeWrapper(block, this, x, y, z);
|
public int getChunkPosX(){
|
||||||
}
|
return chunk.getPos().x;
|
||||||
|
}
|
||||||
@Deprecated
|
|
||||||
public ChunkWrapper(ChunkAccess chunk)
|
@Override
|
||||||
{
|
public int getChunkPosZ(){
|
||||||
this.chunk = chunk;
|
return chunk.getPos().z;
|
||||||
this.lightSource = null;
|
}
|
||||||
}
|
|
||||||
public ChunkWrapper(ChunkAccess chunk, BlockAndTintGetter lightSource)
|
@Override
|
||||||
{
|
public int getRegionPosX(){
|
||||||
this.chunk = chunk;
|
return LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, LodUtil.REGION_DETAIL_LEVEL);
|
||||||
this.lightSource = lightSource;
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
public ChunkAccess getChunk() {
|
public int getRegionPosZ(){
|
||||||
return chunk;
|
return LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().z, LodUtil.REGION_DETAIL_LEVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getChunkPosX(){
|
public int getMaxY(int x, int z) {
|
||||||
return chunk.getPos().x;
|
return chunk.getHeight(Heightmap.Types.MOTION_BLOCKING, Math.floorMod(x, 16), Math.floorMod(z, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getChunkPosZ(){
|
public int getMaxX(){
|
||||||
return chunk.getPos().z;
|
return chunk.getPos().getMaxBlockX();
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
@Override
|
public int getMaxZ(){
|
||||||
public int getRegionPosX(){
|
return chunk.getPos().getMaxBlockZ();
|
||||||
return LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, LodUtil.REGION_DETAIL_LEVEL);
|
}
|
||||||
}
|
@Override
|
||||||
|
public int getMinX(){
|
||||||
@Override
|
return chunk.getPos().getMinBlockX();
|
||||||
public int getRegionPosZ(){
|
}
|
||||||
return LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().z, LodUtil.REGION_DETAIL_LEVEL);
|
@Override
|
||||||
}
|
public int getMinZ() {
|
||||||
|
return chunk.getPos().getMinBlockZ();
|
||||||
@Override
|
}
|
||||||
public int getMaxY(int x, int z) {
|
|
||||||
return chunk.getHeight(Heightmap.Types.MOTION_BLOCKING, Math.floorMod(x, 16), Math.floorMod(z, 16));
|
@Override
|
||||||
}
|
public long getLongChunkPos() {
|
||||||
|
return chunk.getPos().toLong();
|
||||||
@Override
|
}
|
||||||
public int getMaxX(){
|
|
||||||
return chunk.getPos().getMaxBlockX();
|
@Override
|
||||||
}
|
public boolean isLightCorrect(){
|
||||||
@Override
|
//return true;
|
||||||
public int getMaxZ(){
|
if (chunk instanceof LevelChunk) {
|
||||||
return chunk.getPos().getMaxBlockZ();
|
return ((LevelChunk) chunk).isClientLightReady();
|
||||||
}
|
}
|
||||||
@Override
|
return chunk.isLightCorrect();
|
||||||
public int getMinX(){
|
}
|
||||||
return chunk.getPos().getMinBlockX();
|
|
||||||
}
|
public boolean isWaterLogged(int x, int y, int z)
|
||||||
@Override
|
{
|
||||||
public int getMinZ() {
|
BlockState blockState = chunk.getBlockState(new BlockPos(x,y,z));
|
||||||
return chunk.getPos().getMinBlockZ();
|
|
||||||
}
|
//This type of block is always in water
|
||||||
|
return (!(blockState.getBlock() instanceof LiquidBlockContainer) && (blockState.getBlock() instanceof SimpleWaterloggedBlock))
|
||||||
@Override
|
&& (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED));
|
||||||
public long getLongChunkPos() {
|
}
|
||||||
return chunk.getPos().toLong();
|
|
||||||
}
|
@Override
|
||||||
|
public int getEmittedBrightness(int x, int y, int z)
|
||||||
@Override
|
{
|
||||||
public boolean isLightCorrect(){
|
return chunk.getLightEmission(new BlockPos(x,y,z));
|
||||||
//return true;
|
}
|
||||||
if (chunk instanceof LevelChunk) {
|
|
||||||
return ((LevelChunk) chunk).isClientLightReady();
|
|
||||||
}
|
|
||||||
return chunk.isLightCorrect();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isWaterLogged(int x, int y, int z)
|
|
||||||
{
|
|
||||||
BlockState blockState = chunk.getBlockState(new BlockPos(x,y,z));
|
|
||||||
|
|
||||||
//This type of block is always in water
|
|
||||||
return (!(blockState.getBlock() instanceof LiquidBlockContainer) && (blockState.getBlock() instanceof SimpleWaterloggedBlock))
|
|
||||||
&& (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getEmittedBrightness(int x, int y, int z)
|
|
||||||
{
|
|
||||||
return chunk.getLightEmission(new BlockPos(x,y,z));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBlockLight(int x, int y, int z) {
|
public int getBlockLight(int x, int y, int z) {
|
||||||
if (lightSource == null) return -1;
|
if (lightSource == null) return -1;
|
||||||
return lightSource.getBrightness(LightLayer.BLOCK, new BlockPos(x,y,z));
|
return lightSource.getBrightness(LightLayer.BLOCK, new BlockPos(x,y,z));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSkyLight(int x, int y, int z) {
|
public int getSkyLight(int x, int y, int z) {
|
||||||
if (lightSource == null) return -1;
|
if (lightSource == null) return -1;
|
||||||
return lightSource.getBrightness(LightLayer.SKY, new BlockPos(x,y,z));
|
return lightSource.getBrightness(LightLayer.SKY, new BlockPos(x,y,z));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean doesNearbyChunksExist() {
|
||||||
|
if (lightSource instanceof LightedWorldGenRegion) return true;
|
||||||
|
for (int dx = -1; dx <= 1; dx++) {
|
||||||
|
for (int dz = -1; dz <= 1; dz++) {
|
||||||
|
if (dx==0 && dz==0) continue;
|
||||||
|
if (lightSource.getChunk(dx+getChunkPosX(), dz+getChunkPosZ(), ChunkStatus.BIOMES, false) == null) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LevelReader getColorResolver()
|
||||||
|
{
|
||||||
|
return lightSource;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ public abstract class ConfigGui
|
|||||||
// Change these to your own mod
|
// Change these to your own mod
|
||||||
private static final String MOD_NAME = ModInfo.NAME; // For file saving and identifying
|
private static final String MOD_NAME = ModInfo.NAME; // For file saving and identifying
|
||||||
private static final String MOD_NAME_READABLE = ModInfo.READABLE_NAME; // For logs
|
private static final String MOD_NAME_READABLE = ModInfo.READABLE_NAME; // For logs
|
||||||
// private static final Logger LOGGER = ClientApi.LOGGER; // For logs
|
// private static final Logger LOGGER = ApiShared.LOGGER; // For logs
|
||||||
private static final Logger LOGGER = LogManager.getLogger(ModInfo.NAME); // For logs (this inits before ClientAPI so this is a temp fix)
|
private static final Logger LOGGER = LogManager.getLogger(ModInfo.NAME); // For logs (this inits before ClientAPI so this is a temp fix)
|
||||||
|
|
||||||
|
|
||||||
@@ -607,6 +607,7 @@ public abstract class ConfigGui
|
|||||||
else if (info.screenButton)
|
else if (info.screenButton)
|
||||||
{
|
{
|
||||||
Button widget = new Button(this.width / 2 - info.width, this.height - 28, info.width * 2, 20, name, (button -> {
|
Button widget = new Button(this.width / 2 - info.width, this.height - 28, info.width * 2, 20, name, (button -> {
|
||||||
|
saveToFile();
|
||||||
Objects.requireNonNull(minecraft).setScreen(ConfigGui.getScreen(this, info.gotoScreen));
|
Objects.requireNonNull(minecraft).setScreen(ConfigGui.getScreen(this, info.gotoScreen));
|
||||||
}));
|
}));
|
||||||
this.list.addButton(widget, null, null, null);
|
this.list.addButton(widget, null, null, null);
|
||||||
|
|||||||
+350
-108
@@ -3,7 +3,7 @@ package com.seibel.lod.common.wrappers.config;
|
|||||||
import com.seibel.lod.core.enums.config.*;
|
import com.seibel.lod.core.enums.config.*;
|
||||||
import com.seibel.lod.core.enums.rendering.*;
|
import com.seibel.lod.core.enums.rendering.*;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||||
import com.seibel.lod.common.OldConfig;
|
import com.seibel.lod.common.Config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This holds the config defaults and setters/getters
|
* This holds the config defaults and setters/getters
|
||||||
@@ -15,45 +15,51 @@ import com.seibel.lod.common.OldConfig;
|
|||||||
public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
||||||
{
|
{
|
||||||
public static final LodConfigWrapperSingleton INSTANCE = new LodConfigWrapperSingleton();
|
public static final LodConfigWrapperSingleton INSTANCE = new LodConfigWrapperSingleton();
|
||||||
|
|
||||||
|
|
||||||
private static final Client client = new Client();
|
private static final Client client = new Client();
|
||||||
@Override
|
@Override
|
||||||
public IClient client()
|
public IClient client()
|
||||||
{
|
{
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Client implements IClient
|
public static class Client implements IClient
|
||||||
{
|
{
|
||||||
public final IGraphics graphics;
|
public final IGraphics graphics;
|
||||||
public final IWorldGenerator worldGenerator;
|
public final IWorldGenerator worldGenerator;
|
||||||
|
public final IMultiplayer multiplayer;
|
||||||
public final IAdvanced advanced;
|
public final IAdvanced advanced;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IGraphics graphics()
|
public IGraphics graphics()
|
||||||
{
|
{
|
||||||
return graphics;
|
return graphics;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IWorldGenerator worldGenerator()
|
public IWorldGenerator worldGenerator()
|
||||||
{
|
{
|
||||||
return worldGenerator;
|
return worldGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IMultiplayer multiplayer() {
|
||||||
|
return multiplayer;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAdvanced advanced()
|
public IAdvanced advanced()
|
||||||
{
|
{
|
||||||
return advanced;
|
return advanced;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getOptionsButton()
|
public boolean getOptionsButton()
|
||||||
{
|
{
|
||||||
return OldConfig.optionsButton;
|
return Config.optionsButton;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setOptionsButton(boolean newOptionsButton)
|
public void setOptionsButton(boolean newOptionsButton)
|
||||||
@@ -61,8 +67,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("optionsButton").value = newOptionsButton;
|
ConfigGui.editSingleOption.getEntry("optionsButton").value = newOptionsButton;
|
||||||
ConfigGui.editSingleOption.saveOption("optionsButton");
|
ConfigGui.editSingleOption.saveOption("optionsButton");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//================//
|
//================//
|
||||||
// Client Configs //
|
// Client Configs //
|
||||||
//================//
|
//================//
|
||||||
@@ -70,10 +76,11 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
{
|
{
|
||||||
graphics = new Graphics();
|
graphics = new Graphics();
|
||||||
worldGenerator = new WorldGenerator();
|
worldGenerator = new WorldGenerator();
|
||||||
|
multiplayer = new Multiplayer();
|
||||||
advanced = new Advanced();
|
advanced = new Advanced();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//==================//
|
//==================//
|
||||||
// Graphics Configs //
|
// Graphics Configs //
|
||||||
//==================//
|
//==================//
|
||||||
@@ -82,42 +89,42 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
public final IQuality quality;
|
public final IQuality quality;
|
||||||
public final IFogQuality fogQuality;
|
public final IFogQuality fogQuality;
|
||||||
public final IAdvancedGraphics advancedGraphics;
|
public final IAdvancedGraphics advancedGraphics;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IQuality quality()
|
public IQuality quality()
|
||||||
{
|
{
|
||||||
return quality;
|
return quality;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IFogQuality fogQuality()
|
public IFogQuality fogQuality()
|
||||||
{
|
{
|
||||||
return fogQuality;
|
return fogQuality;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAdvancedGraphics advancedGraphics()
|
public IAdvancedGraphics advancedGraphics()
|
||||||
{
|
{
|
||||||
return advancedGraphics;
|
return advancedGraphics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Graphics()
|
Graphics()
|
||||||
{
|
{
|
||||||
quality = new Quality();
|
quality = new Quality();
|
||||||
fogQuality = new FogQuality();
|
fogQuality = new FogQuality();
|
||||||
advancedGraphics = new AdvancedGraphics();
|
advancedGraphics = new AdvancedGraphics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class Quality implements IQuality
|
public static class Quality implements IQuality
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public HorizontalResolution getDrawResolution()
|
public HorizontalResolution getDrawResolution()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.Quality.drawResolution;
|
return Config.Client.Graphics.Quality.drawResolution;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setDrawResolution(HorizontalResolution newHorizontalResolution)
|
public void setDrawResolution(HorizontalResolution newHorizontalResolution)
|
||||||
@@ -125,12 +132,12 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.graphics.quality.drawResolution").value = newHorizontalResolution;
|
ConfigGui.editSingleOption.getEntry("client.graphics.quality.drawResolution").value = newHorizontalResolution;
|
||||||
ConfigGui.editSingleOption.saveOption("client.graphics.quality.drawResolution");
|
ConfigGui.editSingleOption.saveOption("client.graphics.quality.drawResolution");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLodChunkRenderDistance()
|
public int getLodChunkRenderDistance()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.Quality.lodChunkRenderDistance;
|
return Config.Client.Graphics.Quality.lodChunkRenderDistance;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setLodChunkRenderDistance(int newLodChunkRenderDistance)
|
public void setLodChunkRenderDistance(int newLodChunkRenderDistance)
|
||||||
@@ -138,12 +145,12 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.graphics.quality.lodChunkRenderDistance").value = newLodChunkRenderDistance;
|
ConfigGui.editSingleOption.getEntry("client.graphics.quality.lodChunkRenderDistance").value = newLodChunkRenderDistance;
|
||||||
ConfigGui.editSingleOption.saveOption("client.graphics.quality.lodChunkRenderDistance");
|
ConfigGui.editSingleOption.saveOption("client.graphics.quality.lodChunkRenderDistance");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VerticalQuality getVerticalQuality()
|
public VerticalQuality getVerticalQuality()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.Quality.verticalQuality;
|
return Config.Client.Graphics.Quality.verticalQuality;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setVerticalQuality(VerticalQuality newVerticalQuality)
|
public void setVerticalQuality(VerticalQuality newVerticalQuality)
|
||||||
@@ -151,12 +158,12 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.graphics.quality.verticalQuality").value = newVerticalQuality;
|
ConfigGui.editSingleOption.getEntry("client.graphics.quality.verticalQuality").value = newVerticalQuality;
|
||||||
ConfigGui.editSingleOption.saveOption("client.graphics.quality.verticalQuality");
|
ConfigGui.editSingleOption.saveOption("client.graphics.quality.verticalQuality");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getHorizontalScale()
|
public int getHorizontalScale()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.Quality.horizontalScale;
|
return Config.Client.Graphics.Quality.horizontalScale;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setHorizontalScale(int newHorizontalScale)
|
public void setHorizontalScale(int newHorizontalScale)
|
||||||
@@ -164,12 +171,12 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.graphics.quality.horizontalScale").value = newHorizontalScale;
|
ConfigGui.editSingleOption.getEntry("client.graphics.quality.horizontalScale").value = newHorizontalScale;
|
||||||
ConfigGui.editSingleOption.saveOption("client.graphics.quality.horizontalScale");
|
ConfigGui.editSingleOption.saveOption("client.graphics.quality.horizontalScale");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HorizontalQuality getHorizontalQuality()
|
public HorizontalQuality getHorizontalQuality()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.Quality.horizontalQuality;
|
return Config.Client.Graphics.Quality.horizontalQuality;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setHorizontalQuality(HorizontalQuality newHorizontalQuality)
|
public void setHorizontalQuality(HorizontalQuality newHorizontalQuality)
|
||||||
@@ -180,22 +187,40 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DropoffQuality getDropoffQuality() {
|
public DropoffQuality getDropoffQuality() {
|
||||||
return OldConfig.Client.Graphics.Quality.dropoffQuality;
|
return Config.Client.Graphics.Quality.dropoffQuality;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setDropoffQuality(DropoffQuality newDropoffQuality) {
|
public void setDropoffQuality(DropoffQuality newDropoffQuality) {
|
||||||
ConfigGui.editSingleOption.getEntry("client.graphics.quality.dropoffQuality").value = newDropoffQuality;
|
ConfigGui.editSingleOption.getEntry("client.graphics.quality.dropoffQuality").value = newDropoffQuality;
|
||||||
ConfigGui.editSingleOption.saveOption("client.graphics.quality.dropoffQuality");
|
ConfigGui.editSingleOption.saveOption("client.graphics.quality.dropoffQuality");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLodBiomeBlending() {
|
||||||
|
return Config.Client.Graphics.Quality.lodBiomeBlending;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLodBiomeBlending(int newLodBiomeBlending) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.quality.lodBiomeBlending").value = newLodBiomeBlending;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.quality.lodBiomeBlending");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class FogQuality implements IFogQuality
|
public static class FogQuality implements IFogQuality
|
||||||
{
|
{
|
||||||
|
public final IAdvancedFog advancedFog;
|
||||||
|
|
||||||
|
FogQuality()
|
||||||
|
{
|
||||||
|
advancedFog = new AdvancedFog();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FogDistance getFogDistance()
|
public FogDistance getFogDistance()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.FogQuality.fogDistance;
|
return Config.Client.Graphics.FogQuality.fogDistance;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setFogDistance(FogDistance newFogDistance)
|
public void setFogDistance(FogDistance newFogDistance)
|
||||||
@@ -203,40 +228,40 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.fogDistance").value = newFogDistance;
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.fogDistance").value = newFogDistance;
|
||||||
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.fogDistance");
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.fogDistance");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FogDrawMode getFogDrawMode()
|
public FogDrawMode getFogDrawMode()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.FogQuality.fogDrawMode;
|
return Config.Client.Graphics.FogQuality.fogDrawMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFogDrawMode(FogDrawMode setFogDrawMode)
|
public void setFogDrawMode(FogDrawMode setFogDrawMode)
|
||||||
{
|
{
|
||||||
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.fogDrawMode").value = setFogDrawMode;
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.fogDrawMode").value = setFogDrawMode;
|
||||||
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.fogDrawMode");
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.fogDrawMode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FogColorMode getFogColorMode()
|
public FogColorMode getFogColorMode()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.FogQuality.fogColorMode;
|
return Config.Client.Graphics.FogQuality.fogColorMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFogColorMode(FogColorMode newFogColorMode)
|
public void setFogColorMode(FogColorMode newFogColorMode)
|
||||||
{
|
{
|
||||||
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.fogColorMode").value = newFogColorMode;
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.fogColorMode").value = newFogColorMode;
|
||||||
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.fogColorMode");
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.fogColorMode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getDisableVanillaFog()
|
public boolean getDisableVanillaFog()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.FogQuality.disableVanillaFog;
|
return Config.Client.Graphics.FogQuality.disableVanillaFog;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setDisableVanillaFog(boolean newDisableVanillaFog)
|
public void setDisableVanillaFog(boolean newDisableVanillaFog)
|
||||||
@@ -244,15 +269,176 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.disableVanillaFog").value = newDisableVanillaFog;
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.disableVanillaFog").value = newDisableVanillaFog;
|
||||||
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.disableVanillaFog");
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.disableVanillaFog");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IAdvancedFog advancedFog() {
|
||||||
|
return advancedFog;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AdvancedFog implements IAdvancedFog {
|
||||||
|
public final IHeightFog heightFog;
|
||||||
|
|
||||||
|
public AdvancedFog() {
|
||||||
|
heightFog = new HeightFog();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getFarFogStart() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.farFogStart;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public double getFarFogEnd() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.farFogEnd;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public double getFarFogMin() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.farFogMin;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public double getFarFogMax() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.farFogMax;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public FogSetting.FogType getFarFogType() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.farFogType;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public double getFarFogDensity() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.farFogDensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFarFogStart(double newFarFogStart) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.farFogStart").value = newFarFogStart;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.farFogStart");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setFarFogEnd(double newFarFogEnd) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.farFogEnd").value = newFarFogEnd;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.farFogEnd");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setFarFogMin(double newFarFogMin) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.farFogMin").value = newFarFogMin;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.farFogMin");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setFarFogMax(double newFarFogMax) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.farFogMax").value = newFarFogMax;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.farFogMax");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setFarFogType(FogSetting.FogType newFarFogType) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.farFogType").value = newFarFogType;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.farFogType");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setFarFogDensity(double newFarFogDensity) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.farFogDensity").value = newFarFogDensity;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.farFogDensity");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IHeightFog heightFog() {
|
||||||
|
return heightFog;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HeightFog implements IHeightFog {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HeightFogMixMode getHeightFogMixMode() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogMixMode;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public HeightFogMode getHeightFogMode() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogMode;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public double getHeightFogHeight() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogHeight;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public double getHeightFogStart() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogStart;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public double getHeightFogEnd() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogEnd;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public double getHeightFogMin() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogMin;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public double getHeightFogMax() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogMax;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public FogSetting.FogType getHeightFogType() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogType;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public double getHeightFogDensity() {
|
||||||
|
return Config.Client.Graphics.FogQuality.AdvancedFog.heightFog.heightFogDensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHeightFogMixMode(HeightFogMixMode newHeightFogMixMode) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogMixMode").value = newHeightFogMixMode;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogMixMode");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setHeightFogMode(HeightFogMode newHeightFogMode) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogMode").value = newHeightFogMode;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogMode");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setHeightFogHeight(double newHeightFogHeight) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogHeight").value = newHeightFogHeight;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogHeight");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setHeightFogStart(double newHeightFogStart) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogStart").value = newHeightFogStart;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogStart");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setHeightFogEnd(double newHeightFogEnd) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogEnd").value = newHeightFogEnd;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogEnd");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setHeightFogMin(double newHeightFogMin) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogMin").value = newHeightFogMin;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogMin");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setHeightFogMax(double newHeightFogMax) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogMax").value = newHeightFogMax;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogMax");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setHeightFogType(FogSetting.FogType newHeightFogType) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogType").value = newHeightFogType;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogType");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setHeightFogDensity(double newHeightFogDensity) {
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.fogQuality.advancedFog.heightFog.heightFogDensity").value = newHeightFogDensity;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.fogQuality.advancedFog.heightFog.heightFogDensity");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class AdvancedGraphics implements IAdvancedGraphics
|
public static class AdvancedGraphics implements IAdvancedGraphics
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public boolean getDisableDirectionalCulling()
|
public boolean getDisableDirectionalCulling()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.AdvancedGraphics.disableDirectionalCulling;
|
return Config.Client.Graphics.AdvancedGraphics.disableDirectionalCulling;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setDisableDirectionalCulling(boolean newDisableDirectionalCulling)
|
public void setDisableDirectionalCulling(boolean newDisableDirectionalCulling)
|
||||||
@@ -260,12 +446,12 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.disableDirectionalCulling").value = newDisableDirectionalCulling;
|
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.disableDirectionalCulling").value = newDisableDirectionalCulling;
|
||||||
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.disableDirectionalCulling");
|
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.disableDirectionalCulling");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VanillaOverdraw getVanillaOverdraw()
|
public VanillaOverdraw getVanillaOverdraw()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.AdvancedGraphics.vanillaOverdraw;
|
return Config.Client.Graphics.AdvancedGraphics.vanillaOverdraw;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setVanillaOverdraw(VanillaOverdraw newVanillaOverdraw)
|
public void setVanillaOverdraw(VanillaOverdraw newVanillaOverdraw)
|
||||||
@@ -277,7 +463,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
@Override
|
@Override
|
||||||
public int getBacksideCullingRange()
|
public int getBacksideCullingRange()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.AdvancedGraphics.backsideCullingRange;
|
return Config.Client.Graphics.AdvancedGraphics.backsideCullingRange;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setBacksideCullingRange(int newBacksideCullingRange)
|
public void setBacksideCullingRange(int newBacksideCullingRange)
|
||||||
@@ -289,7 +475,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
@Override
|
@Override
|
||||||
public boolean getUseExtendedNearClipPlane()
|
public boolean getUseExtendedNearClipPlane()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Graphics.AdvancedGraphics.useExtendedNearClipPlane;
|
return Config.Client.Graphics.AdvancedGraphics.useExtendedNearClipPlane;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setUseExtendedNearClipPlane(boolean newUseExtendedNearClipPlane)
|
public void setUseExtendedNearClipPlane(boolean newUseExtendedNearClipPlane)
|
||||||
@@ -297,12 +483,36 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.useExtendedNearClipPlane").value = newUseExtendedNearClipPlane;
|
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.useExtendedNearClipPlane").value = newUseExtendedNearClipPlane;
|
||||||
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.useExtendedNearClipPlane");
|
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.useExtendedNearClipPlane");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBrightnessMultiplier()
|
||||||
|
{
|
||||||
|
return Config.Client.Graphics.AdvancedGraphics.brightnessMultiplier;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setBrightnessMultiplier(double newBrightnessMultiplier)
|
||||||
|
{
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.brightnessMultiplier").value = newBrightnessMultiplier;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.brightnessMultiplier");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getSaturationMultiplier()
|
||||||
|
{
|
||||||
|
return Config.Client.Graphics.AdvancedGraphics.saturationMultiplier;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setSaturationMultiplier(double newSaturationMultiplier)
|
||||||
|
{
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.saturationMultiplier").value = newSaturationMultiplier;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.saturationMultiplier");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//========================//
|
//========================//
|
||||||
// WorldGenerator Configs //
|
// WorldGenerator Configs //
|
||||||
//========================//
|
//========================//
|
||||||
@@ -311,7 +521,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
@Override
|
@Override
|
||||||
public GenerationPriority getGenerationPriority()
|
public GenerationPriority getGenerationPriority()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.WorldGenerator.generationPriority;
|
return Config.Client.WorldGenerator.generationPriority;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setGenerationPriority(GenerationPriority newGenerationPriority)
|
public void setGenerationPriority(GenerationPriority newGenerationPriority)
|
||||||
@@ -319,12 +529,12 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.worldGenerator.generationPriority").value = newGenerationPriority;
|
ConfigGui.editSingleOption.getEntry("client.worldGenerator.generationPriority").value = newGenerationPriority;
|
||||||
ConfigGui.editSingleOption.saveOption("client.worldGenerator.generationPriority");
|
ConfigGui.editSingleOption.saveOption("client.worldGenerator.generationPriority");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DistanceGenerationMode getDistanceGenerationMode()
|
public DistanceGenerationMode getDistanceGenerationMode()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.WorldGenerator.distanceGenerationMode;
|
return Config.Client.WorldGenerator.distanceGenerationMode;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setDistanceGenerationMode(DistanceGenerationMode newDistanceGenerationMode)
|
public void setDistanceGenerationMode(DistanceGenerationMode newDistanceGenerationMode)
|
||||||
@@ -337,7 +547,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
@Override
|
@Override
|
||||||
public boolean getAllowUnstableFeatureGeneration()
|
public boolean getAllowUnstableFeatureGeneration()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.WorldGenerator.allowUnstableFeatureGeneration;
|
return Config.Client.WorldGenerator.allowUnstableFeatureGeneration;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setAllowUnstableFeatureGeneration(boolean newAllowUnstableFeatureGeneration)
|
public void setAllowUnstableFeatureGeneration(boolean newAllowUnstableFeatureGeneration)
|
||||||
@@ -345,12 +555,12 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.worldGenerator.allowUnstableFeatureGeneration").value = newAllowUnstableFeatureGeneration;
|
ConfigGui.editSingleOption.getEntry("client.worldGenerator.allowUnstableFeatureGeneration").value = newAllowUnstableFeatureGeneration;
|
||||||
ConfigGui.editSingleOption.saveOption("client.worldGenerator.allowUnstableFeatureGeneration");
|
ConfigGui.editSingleOption.saveOption("client.worldGenerator.allowUnstableFeatureGeneration");
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlocksToAvoid getBlocksToAvoid()
|
public BlocksToAvoid getBlocksToAvoid()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.WorldGenerator.blocksToAvoid;
|
return Config.Client.WorldGenerator.blocksToAvoid;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setBlockToAvoid(BlocksToAvoid newBlockToAvoid)
|
public void setBlockToAvoid(BlocksToAvoid newBlockToAvoid)
|
||||||
@@ -372,7 +582,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
@Override
|
@Override
|
||||||
public LightGenerationMode getLightGenerationMode()
|
public LightGenerationMode getLightGenerationMode()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.WorldGenerator.lightGenerationMode;
|
return Config.Client.WorldGenerator.lightGenerationMode;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setLightGenerationMode(LightGenerationMode newLightGenerationMode)
|
public void setLightGenerationMode(LightGenerationMode newLightGenerationMode)
|
||||||
@@ -381,10 +591,42 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.saveOption("client.worldGenerator.lightGenerationMode");
|
ConfigGui.editSingleOption.saveOption("client.worldGenerator.lightGenerationMode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=====================//
|
||||||
|
// Multiplayer Configs //
|
||||||
|
//=====================//
|
||||||
|
public static class Multiplayer implements IMultiplayer
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public ServerFolderNameMode getServerFolderNameMode()
|
||||||
|
{
|
||||||
|
return Config.Client.Multiplayer.serverFolderNameMode;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setServerFolderNameMode(ServerFolderNameMode newServerFolderNameMode)
|
||||||
|
{
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.multiplayer.serverFolderNameMode").value = newServerFolderNameMode;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.multiplayer.serverFolderNameMode");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getMultiDimensionRequiredSimilarity()
|
||||||
|
{
|
||||||
|
return Config.Client.Multiplayer.multiDimensionRequiredSimilarity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMultiDimensionRequiredSimilarity(double newMultiDimensionMinimumSimilarityPercent)
|
||||||
|
{
|
||||||
|
ConfigGui.editSingleOption.getEntry("client.multiplayer.multiDimensionMinimumSimilarityPercent").value = newMultiDimensionMinimumSimilarityPercent;
|
||||||
|
ConfigGui.editSingleOption.saveOption("client.multiplayer.multiDimensionMinimumSimilarityPercent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============================//
|
//============================//
|
||||||
// AdvancedModOptions Configs //
|
// AdvancedModOptions Configs //
|
||||||
//============================//
|
//============================//
|
||||||
@@ -393,42 +635,42 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
public final IThreading threading;
|
public final IThreading threading;
|
||||||
public final IDebugging debugging;
|
public final IDebugging debugging;
|
||||||
public final IBuffers buffers;
|
public final IBuffers buffers;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IThreading threading()
|
public IThreading threading()
|
||||||
{
|
{
|
||||||
return threading;
|
return threading;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IDebugging debugging()
|
public IDebugging debugging()
|
||||||
{
|
{
|
||||||
return debugging;
|
return debugging;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBuffers buffers()
|
public IBuffers buffers()
|
||||||
{
|
{
|
||||||
return buffers;
|
return buffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Advanced()
|
public Advanced()
|
||||||
{
|
{
|
||||||
threading = new Threading();
|
threading = new Threading();
|
||||||
debugging = new Debugging();
|
debugging = new Debugging();
|
||||||
buffers = new Buffers();
|
buffers = new Buffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Threading implements IThreading
|
public static class Threading implements IThreading
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public int getNumberOfWorldGenerationThreads()
|
public int getNumberOfWorldGenerationThreads()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Advanced.Threading.numberOfWorldGenerationThreads;
|
return Config.Client.Advanced.Threading.numberOfWorldGenerationThreads;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setNumberOfWorldGenerationThreads(int newNumberOfWorldGenerationThreads)
|
public void setNumberOfWorldGenerationThreads(int newNumberOfWorldGenerationThreads)
|
||||||
@@ -436,12 +678,12 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.advanced.threading.numberOfWorldGenerationThreads").value = newNumberOfWorldGenerationThreads;
|
ConfigGui.editSingleOption.getEntry("client.advanced.threading.numberOfWorldGenerationThreads").value = newNumberOfWorldGenerationThreads;
|
||||||
ConfigGui.editSingleOption.saveOption("client.advanced.threading.numberOfWorldGenerationThreads");
|
ConfigGui.editSingleOption.saveOption("client.advanced.threading.numberOfWorldGenerationThreads");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNumberOfBufferBuilderThreads()
|
public int getNumberOfBufferBuilderThreads()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Advanced.Threading.numberOfBufferBuilderThreads;
|
return Config.Client.Advanced.Threading.numberOfBufferBuilderThreads;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setNumberOfBufferBuilderThreads(int newNumberOfWorldBuilderThreads)
|
public void setNumberOfBufferBuilderThreads(int newNumberOfWorldBuilderThreads)
|
||||||
@@ -450,10 +692,10 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.saveOption("client.advanced.threading.numberOfBufferBuilderThreads");
|
ConfigGui.editSingleOption.saveOption("client.advanced.threading.numberOfBufferBuilderThreads");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===============//
|
//===============//
|
||||||
// Debug Options //
|
// Debug Options //
|
||||||
//===============//
|
//===============//
|
||||||
@@ -470,8 +712,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.drawLods").value = newDrawLods;
|
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.drawLods").value = newDrawLods;
|
||||||
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.drawLods");
|
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.drawLods");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DebugMode getDebugMode()
|
public DebugMode getDebugMode()
|
||||||
{
|
{
|
||||||
@@ -483,8 +725,8 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugMode").value = newDebugMode;
|
ConfigGui.editSingleOption.getEntry("client.advanced.debugging.debugMode").value = newDebugMode;
|
||||||
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugMode");
|
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.debugMode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getDebugKeybindingsEnabled()
|
public boolean getDebugKeybindingsEnabled()
|
||||||
{
|
{
|
||||||
@@ -497,15 +739,15 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.enableDebugKeybindings");
|
ConfigGui.editSingleOption.saveOption("client.advanced.debugging.enableDebugKeybindings");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class Buffers implements IBuffers
|
public static class Buffers implements IBuffers
|
||||||
{
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GpuUploadMethod getGpuUploadMethod()
|
public GpuUploadMethod getGpuUploadMethod()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Advanced.Buffers.gpuUploadMethod;
|
return Config.Client.Advanced.Buffers.gpuUploadMethod;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setGpuUploadMethod(GpuUploadMethod newDisableVanillaFog)
|
public void setGpuUploadMethod(GpuUploadMethod newDisableVanillaFog)
|
||||||
@@ -513,24 +755,24 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|||||||
ConfigGui.editSingleOption.getEntry("client.advanced.buffers.gpuUploadMethod").value = newDisableVanillaFog;
|
ConfigGui.editSingleOption.getEntry("client.advanced.buffers.gpuUploadMethod").value = newDisableVanillaFog;
|
||||||
ConfigGui.editSingleOption.saveOption("client.advanced.buffers.gpuUploadMethod");
|
ConfigGui.editSingleOption.saveOption("client.advanced.buffers.gpuUploadMethod");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getGpuUploadPerMegabyteInMilliseconds()
|
public int getGpuUploadPerMegabyteInMilliseconds()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Advanced.Buffers.gpuUploadPerMegabyteInMilliseconds;
|
return Config.Client.Advanced.Buffers.gpuUploadPerMegabyteInMilliseconds;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setGpuUploadPerMegabyteInMilliseconds(int newMilliseconds) {
|
public void setGpuUploadPerMegabyteInMilliseconds(int newMilliseconds) {
|
||||||
ConfigGui.editSingleOption.getEntry("client.advanced.buffers.gpuUploadPerMegabyteInMilliseconds").value = newMilliseconds;
|
ConfigGui.editSingleOption.getEntry("client.advanced.buffers.gpuUploadPerMegabyteInMilliseconds").value = newMilliseconds;
|
||||||
ConfigGui.editSingleOption.saveOption("client.advanced.buffers.gpuUploadPerMegabyteInMilliseconds");
|
ConfigGui.editSingleOption.saveOption("client.advanced.buffers.gpuUploadPerMegabyteInMilliseconds");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BufferRebuildTimes getRebuildTimes()
|
public BufferRebuildTimes getRebuildTimes()
|
||||||
{
|
{
|
||||||
return OldConfig.Client.Advanced.Buffers.rebuildTimes;
|
return Config.Client.Advanced.Buffers.rebuildTimes;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setRebuildTimes(BufferRebuildTimes newBufferRebuildTimes)
|
public void setRebuildTimes(BufferRebuildTimes newBufferRebuildTimes)
|
||||||
|
|||||||
-505
@@ -1,505 +0,0 @@
|
|||||||
package com.seibel.lod.common.wrappers.config;
|
|
||||||
|
|
||||||
import com.seibel.lod.core.enums.config.*;
|
|
||||||
import com.seibel.lod.core.enums.rendering.*;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
|
||||||
import com.seibel.lod.core.Config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is temporary for testing the new config
|
|
||||||
*
|
|
||||||
* @author coolGi2007
|
|
||||||
* @version 02-13-2022
|
|
||||||
*/
|
|
||||||
public class NewLodConfigWrapperSingleton implements ILodConfigWrapperSingleton
|
|
||||||
{
|
|
||||||
public static final NewLodConfigWrapperSingleton INSTANCE = new NewLodConfigWrapperSingleton();
|
|
||||||
|
|
||||||
|
|
||||||
private static final Client client = new Client();
|
|
||||||
@Override
|
|
||||||
public IClient client()
|
|
||||||
{
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Client implements IClient
|
|
||||||
{
|
|
||||||
public final IGraphics graphics;
|
|
||||||
public final IWorldGenerator worldGenerator;
|
|
||||||
public final IAdvanced advanced;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IGraphics graphics()
|
|
||||||
{
|
|
||||||
return graphics;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IWorldGenerator worldGenerator()
|
|
||||||
{
|
|
||||||
return worldGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IAdvanced advanced()
|
|
||||||
{
|
|
||||||
return advanced;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getOptionsButton()
|
|
||||||
{
|
|
||||||
return Config.client.optionsButton.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setOptionsButton(boolean newOptionsButton)
|
|
||||||
{
|
|
||||||
Config.client.optionsButton.set(newOptionsButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
|
||||||
// Client Configs //
|
|
||||||
//================//
|
|
||||||
public Client()
|
|
||||||
{
|
|
||||||
graphics = new Graphics();
|
|
||||||
worldGenerator = new WorldGenerator();
|
|
||||||
advanced = new Advanced();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//==================//
|
|
||||||
// Graphics Configs //
|
|
||||||
//==================//
|
|
||||||
public static class Graphics implements IGraphics
|
|
||||||
{
|
|
||||||
public final IQuality quality;
|
|
||||||
public final IFogQuality fogQuality;
|
|
||||||
public final IAdvancedGraphics advancedGraphics;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IQuality quality()
|
|
||||||
{
|
|
||||||
return quality;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IFogQuality fogQuality()
|
|
||||||
{
|
|
||||||
return fogQuality;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IAdvancedGraphics advancedGraphics()
|
|
||||||
{
|
|
||||||
return advancedGraphics;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Graphics()
|
|
||||||
{
|
|
||||||
quality = new Quality();
|
|
||||||
fogQuality = new FogQuality();
|
|
||||||
advancedGraphics = new AdvancedGraphics();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class Quality implements IQuality
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public HorizontalResolution getDrawResolution()
|
|
||||||
{
|
|
||||||
return Config.Client.Graphics.Quality.drawResolution.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setDrawResolution(HorizontalResolution newHorizontalResolution)
|
|
||||||
{
|
|
||||||
Config.Client.Graphics.Quality.drawResolution.set(newHorizontalResolution);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLodChunkRenderDistance()
|
|
||||||
{
|
|
||||||
return Config.Client.Graphics.Quality.lodChunkRenderDistance.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setLodChunkRenderDistance(int newLodChunkRenderDistance)
|
|
||||||
{
|
|
||||||
Config.Client.Graphics.Quality.lodChunkRenderDistance.set(newLodChunkRenderDistance);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VerticalQuality getVerticalQuality()
|
|
||||||
{
|
|
||||||
return Config.Client.Graphics.Quality.verticalQuality.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setVerticalQuality(VerticalQuality newVerticalQuality)
|
|
||||||
{
|
|
||||||
Config.Client.Graphics.Quality.verticalQuality.set(newVerticalQuality);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHorizontalScale()
|
|
||||||
{
|
|
||||||
return Config.Client.Graphics.Quality.horizontalScale.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setHorizontalScale(int newHorizontalScale)
|
|
||||||
{
|
|
||||||
Config.Client.Graphics.Quality.horizontalScale.set(newHorizontalScale);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HorizontalQuality getHorizontalQuality()
|
|
||||||
{
|
|
||||||
return Config.Client.Graphics.Quality.horizontalQuality.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setHorizontalQuality(HorizontalQuality newHorizontalQuality)
|
|
||||||
{
|
|
||||||
Config.Client.Graphics.Quality.horizontalQuality.set(newHorizontalQuality);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DropoffQuality getDropoffQuality() {
|
|
||||||
return Config.Client.Graphics.Quality.dropoffQuality.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setDropoffQuality(DropoffQuality newDropoffQuality) {
|
|
||||||
Config.Client.Graphics.Quality.dropoffQuality.set(newDropoffQuality);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class FogQuality implements IFogQuality
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public FogDistance getFogDistance()
|
|
||||||
{
|
|
||||||
return Config.Client.Graphics.FogQuality.fogDistance.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setFogDistance(FogDistance newFogDistance)
|
|
||||||
{
|
|
||||||
Config.Client.Graphics.FogQuality.fogDistance.set(newFogDistance);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FogDrawMode getFogDrawMode()
|
|
||||||
{
|
|
||||||
return Config.Client.Graphics.FogQuality.fogDrawMode.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFogDrawMode(FogDrawMode setFogDrawMode)
|
|
||||||
{
|
|
||||||
Config.Client.Graphics.FogQuality.fogDrawMode.set(setFogDrawMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FogColorMode getFogColorMode()
|
|
||||||
{
|
|
||||||
return Config.Client.Graphics.FogQuality.fogColorMode.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFogColorMode(FogColorMode newFogColorMode)
|
|
||||||
{
|
|
||||||
Config.Client.Graphics.FogQuality.fogColorMode.set(newFogColorMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getDisableVanillaFog()
|
|
||||||
{
|
|
||||||
return Config.Client.Graphics.FogQuality.disableVanillaFog.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setDisableVanillaFog(boolean newDisableVanillaFog)
|
|
||||||
{
|
|
||||||
Config.Client.Graphics.FogQuality.disableVanillaFog.set(newDisableVanillaFog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class AdvancedGraphics implements IAdvancedGraphics
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public boolean getDisableDirectionalCulling()
|
|
||||||
{
|
|
||||||
return Config.Client.Graphics.AdvancedGraphics.disableDirectionalCulling.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setDisableDirectionalCulling(boolean newDisableDirectionalCulling)
|
|
||||||
{
|
|
||||||
Config.Client.Graphics.AdvancedGraphics.disableDirectionalCulling.set(newDisableDirectionalCulling);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VanillaOverdraw getVanillaOverdraw()
|
|
||||||
{
|
|
||||||
return Config.Client.Graphics.AdvancedGraphics.vanillaOverdraw.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setVanillaOverdraw(VanillaOverdraw newVanillaOverdraw)
|
|
||||||
{
|
|
||||||
Config.Client.Graphics.AdvancedGraphics.vanillaOverdraw.set(newVanillaOverdraw);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getUseExtendedNearClipPlane()
|
|
||||||
{
|
|
||||||
return Config.Client.Graphics.AdvancedGraphics.useExtendedNearClipPlane.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setUseExtendedNearClipPlane(boolean newUseExtendedNearClipPlane)
|
|
||||||
{
|
|
||||||
Config.Client.Graphics.AdvancedGraphics.useExtendedNearClipPlane.set(newUseExtendedNearClipPlane);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//========================//
|
|
||||||
// WorldGenerator Configs //
|
|
||||||
//========================//
|
|
||||||
public static class WorldGenerator implements IWorldGenerator
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public GenerationPriority getGenerationPriority()
|
|
||||||
{
|
|
||||||
return Config.Client.WorldGenerator.generationPriority.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setGenerationPriority(GenerationPriority newGenerationPriority)
|
|
||||||
{
|
|
||||||
Config.Client.WorldGenerator.generationPriority.set(newGenerationPriority);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DistanceGenerationMode getDistanceGenerationMode()
|
|
||||||
{
|
|
||||||
return Config.Client.WorldGenerator.distanceGenerationMode.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setDistanceGenerationMode(DistanceGenerationMode newDistanceGenerationMode)
|
|
||||||
{
|
|
||||||
Config.Client.WorldGenerator.distanceGenerationMode.set(newDistanceGenerationMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@Override
|
|
||||||
public boolean getAllowUnstableFeatureGeneration()
|
|
||||||
{
|
|
||||||
return Config.Client.WorldGenerator.allowUnstableFeatureGeneration;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setAllowUnstableFeatureGeneration(boolean newAllowUnstableFeatureGeneration)
|
|
||||||
{
|
|
||||||
ConfigGui.editSingleOption.getEntry("client.worldGenerator.allowUnstableFeatureGeneration").value = newAllowUnstableFeatureGeneration;
|
|
||||||
ConfigGui.editSingleOption.saveOption("client.worldGenerator.allowUnstableFeatureGeneration");
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlocksToAvoid getBlocksToAvoid()
|
|
||||||
{
|
|
||||||
return Config.Client.WorldGenerator.blocksToAvoid.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setBlockToAvoid(BlocksToAvoid newBlockToAvoid)
|
|
||||||
{
|
|
||||||
Config.Client.WorldGenerator.blocksToAvoid.set(newBlockToAvoid);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public boolean getEnableDistantGeneration()
|
|
||||||
{
|
|
||||||
return Config.Client.WorldGenerator.enableDistantGeneration.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setEnableDistantGeneration(boolean newEnableDistantGeneration)
|
|
||||||
{
|
|
||||||
Config.Client.WorldGenerator.enableDistantGeneration.set(newEnableDistantGeneration);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public LightGenerationMode getLightGenerationMode()
|
|
||||||
{
|
|
||||||
return Config.Client.WorldGenerator.lightGenerationMode.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setLightGenerationMode(LightGenerationMode newLightGenerationMode)
|
|
||||||
{
|
|
||||||
Config.Client.WorldGenerator.lightGenerationMode.set(newLightGenerationMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============================//
|
|
||||||
// AdvancedModOptions Configs //
|
|
||||||
//============================//
|
|
||||||
public static class Advanced implements IAdvanced
|
|
||||||
{
|
|
||||||
public final IThreading threading;
|
|
||||||
public final IDebugging debugging;
|
|
||||||
public final IBuffers buffers;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IThreading threading()
|
|
||||||
{
|
|
||||||
return threading;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IDebugging debugging()
|
|
||||||
{
|
|
||||||
return debugging;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBuffers buffers()
|
|
||||||
{
|
|
||||||
return buffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Advanced()
|
|
||||||
{
|
|
||||||
threading = new Threading();
|
|
||||||
debugging = new Debugging();
|
|
||||||
buffers = new Buffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Threading implements IThreading
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public int getNumberOfWorldGenerationThreads()
|
|
||||||
{
|
|
||||||
return Config.Client.Advanced.Threading.numberOfWorldGenerationThreads.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setNumberOfWorldGenerationThreads(int newNumberOfWorldGenerationThreads)
|
|
||||||
{
|
|
||||||
Config.Client.Advanced.Threading.numberOfWorldGenerationThreads.set(newNumberOfWorldGenerationThreads);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getNumberOfBufferBuilderThreads()
|
|
||||||
{
|
|
||||||
return Config.Client.Advanced.Threading.numberOfBufferBuilderThreads.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setNumberOfBufferBuilderThreads(int newNumberOfWorldBuilderThreads)
|
|
||||||
{
|
|
||||||
Config.Client.Advanced.Threading.numberOfBufferBuilderThreads.set(newNumberOfWorldBuilderThreads);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===============//
|
|
||||||
// Debug Options //
|
|
||||||
//===============//
|
|
||||||
public static class Debugging implements IDebugging
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public boolean getDrawLods()
|
|
||||||
{
|
|
||||||
return Config.Client.Advanced.Debugging.drawLods.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setDrawLods(boolean newDrawLods)
|
|
||||||
{
|
|
||||||
Config.Client.Advanced.Debugging.drawLods.set(newDrawLods);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DebugMode getDebugMode()
|
|
||||||
{
|
|
||||||
return Config.Client.Advanced.Debugging.debugMode.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setDebugMode(DebugMode newDebugMode)
|
|
||||||
{
|
|
||||||
Config.Client.Advanced.Debugging.debugMode.set(newDebugMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getDebugKeybindingsEnabled()
|
|
||||||
{
|
|
||||||
return Config.Client.Advanced.Debugging.enableDebugKeybindings.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setDebugKeybindingsEnabled(boolean newEnableDebugKeybindings)
|
|
||||||
{
|
|
||||||
Config.Client.Advanced.Debugging.enableDebugKeybindings.set(newEnableDebugKeybindings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class Buffers implements IBuffers
|
|
||||||
{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GpuUploadMethod getGpuUploadMethod()
|
|
||||||
{
|
|
||||||
return Config.Client.Advanced.Buffers.gpuUploadMethod.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setGpuUploadMethod(GpuUploadMethod newDisableVanillaFog)
|
|
||||||
{
|
|
||||||
Config.Client.Advanced.Buffers.gpuUploadMethod.set(newDisableVanillaFog);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getGpuUploadPerMegabyteInMilliseconds()
|
|
||||||
{
|
|
||||||
return Config.Client.Advanced.Buffers.gpuUploadPerMegabyteInMilliseconds.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setGpuUploadPerMegabyteInMilliseconds(int newMilliseconds) {
|
|
||||||
Config.Client.Advanced.Buffers.gpuUploadPerMegabyteInMilliseconds.set(newMilliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BufferRebuildTimes getRebuildTimes()
|
|
||||||
{
|
|
||||||
return Config.Client.Advanced.Buffers.rebuildTimes.get();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void setRebuildTimes(BufferRebuildTimes newBufferRebuildTimes)
|
|
||||||
{
|
|
||||||
Config.Client.Advanced.Buffers.rebuildTimes.set(newBufferRebuildTimes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+7
-7
@@ -26,10 +26,10 @@ import java.util.ArrayList;
|
|||||||
import com.mojang.blaze3d.platform.NativeImage;
|
import com.mojang.blaze3d.platform.NativeImage;
|
||||||
import com.mojang.blaze3d.platform.Window;
|
import com.mojang.blaze3d.platform.Window;
|
||||||
import com.seibel.lod.core.ModInfo;
|
import com.seibel.lod.core.ModInfo;
|
||||||
import com.seibel.lod.core.api.ClientApi;
|
import com.seibel.lod.core.api.ApiShared;
|
||||||
import com.seibel.lod.core.enums.LodDirection;
|
import com.seibel.lod.core.enums.LodDirection;
|
||||||
import com.seibel.lod.core.util.LodUtil;
|
import com.seibel.lod.core.util.LodUtil;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.misc.ILightMapWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.misc.ILightMapWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
|
||||||
@@ -67,11 +67,11 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
* to allow for easier movement between Minecraft versions.
|
* to allow for easier movement between Minecraft versions.
|
||||||
*
|
*
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 9-16-2021
|
* @version 3-5-2022
|
||||||
*/
|
*/
|
||||||
public class MinecraftWrapper implements IMinecraftWrapper
|
public class MinecraftClientWrapper implements IMinecraftClientWrapper
|
||||||
{
|
{
|
||||||
public static final MinecraftWrapper INSTANCE = new MinecraftWrapper();
|
public static final MinecraftClientWrapper INSTANCE = new MinecraftClientWrapper();
|
||||||
|
|
||||||
public final Minecraft mc = Minecraft.getInstance();
|
public final Minecraft mc = Minecraft.getInstance();
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ public class MinecraftWrapper implements IMinecraftWrapper
|
|||||||
private ProfilerWrapper profilerWrapper;
|
private ProfilerWrapper profilerWrapper;
|
||||||
|
|
||||||
|
|
||||||
private MinecraftWrapper()
|
private MinecraftClientWrapper()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -418,7 +418,7 @@ public class MinecraftWrapper implements IMinecraftWrapper
|
|||||||
@Override
|
@Override
|
||||||
public void crashMinecraft(String errorMessage, Throwable exception)
|
public void crashMinecraft(String errorMessage, Throwable exception)
|
||||||
{
|
{
|
||||||
ClientApi.LOGGER.error(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft...");
|
ApiShared.LOGGER.error(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft...");
|
||||||
CrashReport report = new CrashReport(errorMessage, exception);
|
CrashReport report = new CrashReport(errorMessage, exception);
|
||||||
Minecraft.crash(report);
|
Minecraft.crash(report);
|
||||||
}
|
}
|
||||||
+226
-229
@@ -5,13 +5,15 @@ import java.util.HashSet;
|
|||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderTarget;
|
||||||
import com.mojang.blaze3d.platform.NativeImage;
|
import com.mojang.blaze3d.platform.NativeImage;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import com.seibel.lod.common.wrappers.misc.LightMapWrapper;
|
import com.seibel.lod.common.wrappers.misc.LightMapWrapper;
|
||||||
|
import com.seibel.lod.core.api.ApiShared;
|
||||||
import com.seibel.lod.core.api.ClientApi;
|
import com.seibel.lod.core.api.ClientApi;
|
||||||
import com.seibel.lod.core.api.ModAccessorApi;
|
import com.seibel.lod.core.handlers.dependencyInjection.ModAccessorHandler;
|
||||||
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
import com.seibel.lod.core.util.LodUtil;
|
import com.seibel.lod.core.util.LodUtil;
|
||||||
import com.seibel.lod.core.util.SingletonHandler;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
|
|
||||||
@@ -23,7 +25,6 @@ import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
|||||||
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
||||||
import com.seibel.lod.common.wrappers.McObjectConverter;
|
import com.seibel.lod.common.wrappers.McObjectConverter;
|
||||||
@@ -53,112 +54,132 @@ import net.minecraft.world.phys.Vec3;
|
|||||||
*/
|
*/
|
||||||
public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||||
{
|
{
|
||||||
public static final MinecraftRenderWrapper INSTANCE = new MinecraftRenderWrapper();
|
public static final MinecraftRenderWrapper INSTANCE = new MinecraftRenderWrapper();
|
||||||
|
|
||||||
private static final Minecraft MC = Minecraft.getInstance();
|
private static final Minecraft MC = Minecraft.getInstance();
|
||||||
private static final GameRenderer GAME_RENDERER = MC.gameRenderer;
|
private static final GameRenderer GAME_RENDERER = MC.gameRenderer;
|
||||||
private static final WrapperFactory FACTORY = WrapperFactory.INSTANCE;
|
private static final IWrapperFactory FACTORY = WrapperFactory.INSTANCE;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Vec3f getLookAtVector()
|
public Vec3f getLookAtVector()
|
||||||
{
|
{
|
||||||
Camera camera = GAME_RENDERER.getMainCamera();
|
Camera camera = GAME_RENDERER.getMainCamera();
|
||||||
Vector3f cameraDir = camera.getLookVector();
|
Vector3f cameraDir = camera.getLookVector();
|
||||||
return new Vec3f(cameraDir.x(), cameraDir.y(), cameraDir.z());
|
return new Vec3f(cameraDir.x(), cameraDir.y(), cameraDir.z());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractBlockPosWrapper getCameraBlockPosition()
|
||||||
|
{
|
||||||
|
Camera camera = GAME_RENDERER.getMainCamera();
|
||||||
|
BlockPos blockPos = camera.getBlockPosition();
|
||||||
|
return new BlockPosWrapper(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean playerHasBlindnessEffect()
|
||||||
|
{
|
||||||
|
return MC.player.getActiveEffectsMap().get(MobEffects.BLINDNESS) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vec3d getCameraExactPosition()
|
||||||
|
{
|
||||||
|
Camera camera = GAME_RENDERER.getMainCamera();
|
||||||
|
Vec3 projectedView = camera.getPosition();
|
||||||
|
|
||||||
|
return new Vec3d(projectedView.x, projectedView.y, projectedView.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mat4f getDefaultProjectionMatrix(float partialTicks)
|
||||||
|
{
|
||||||
|
return McObjectConverter.Convert(GAME_RENDERER.getProjectionMatrix(GAME_RENDERER.getFov(GAME_RENDERER.getMainCamera(), partialTicks, true)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getGamma()
|
||||||
|
{
|
||||||
|
return MC.options.gamma;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Color getFogColor(float partialTicks) {
|
||||||
|
FogRenderer.setupColor(GAME_RENDERER.getMainCamera(), partialTicks, MC.level, 1, GAME_RENDERER.getDarkenWorldAmount(partialTicks));
|
||||||
|
float[] colorValues = RenderSystem.getShaderFogColor();
|
||||||
|
return new Color(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
|
||||||
|
}
|
||||||
|
// getSpecialFogColor() is the same as getFogColor()
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Color getSkyColor() {
|
||||||
|
if (MC.level.dimensionType().hasSkyLight()) {
|
||||||
|
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), MC.getFrameTime());
|
||||||
|
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
|
||||||
|
} else
|
||||||
|
return new Color(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getFov(float partialTicks)
|
||||||
|
{
|
||||||
|
return GAME_RENDERER.getFov(GAME_RENDERER.getMainCamera(), partialTicks, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Measured in chunks */
|
||||||
|
@Override
|
||||||
|
public int getRenderDistance()
|
||||||
|
{
|
||||||
|
return MC.options.getEffectiveRenderDistance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getScreenWidth()
|
||||||
|
{
|
||||||
|
return MC.getWindow().getWidth();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getScreenHeight()
|
||||||
|
{
|
||||||
|
return MC.getWindow().getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
private RenderTarget getRenderTarget() {
|
||||||
|
RenderTarget r = null; //MC.levelRenderer.getCloudsTarget();
|
||||||
|
return r!=null ? r : MC.getMainRenderTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractBlockPosWrapper getCameraBlockPosition()
|
public int getTargetFrameBuffer() {
|
||||||
{
|
return getRenderTarget().frameBufferId;
|
||||||
Camera camera = GAME_RENDERER.getMainCamera();
|
|
||||||
BlockPos blockPos = camera.getBlockPosition();
|
|
||||||
return new BlockPosWrapper(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean playerHasBlindnessEffect()
|
public int getTargetFrameBufferViewportWidth() {
|
||||||
{
|
return getRenderTarget().viewWidth;
|
||||||
return MC.player.getActiveEffectsMap().get(MobEffects.BLINDNESS) != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Vec3d getCameraExactPosition()
|
public int getTargetFrameBufferViewportHeight() {
|
||||||
{
|
return getRenderTarget().viewHeight;
|
||||||
Camera camera = GAME_RENDERER.getMainCamera();
|
|
||||||
Vec3 projectedView = camera.getPosition();
|
|
||||||
|
|
||||||
return new Vec3d(projectedView.x, projectedView.y, projectedView.z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public Mat4f getDefaultProjectionMatrix(float partialTicks)
|
* This method returns the ChunkPos of all chunks that Minecraft
|
||||||
{
|
* is going to render this frame. <br><br>
|
||||||
return McObjectConverter.Convert(GAME_RENDERER.getProjectionMatrix(GAME_RENDERER.getFov(GAME_RENDERER.getMainCamera(), partialTicks, true)));
|
* <p>
|
||||||
}
|
*/
|
||||||
|
|
||||||
@Override
|
public boolean usingBackupGetVanillaRenderedChunks = true;
|
||||||
public double getGamma()
|
|
||||||
{
|
|
||||||
return MC.options.gamma;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Color getFogColor(float partialTicks) {
|
|
||||||
FogRenderer.setupColor(GAME_RENDERER.getMainCamera(), partialTicks, MC.level, 1, GAME_RENDERER.getDarkenWorldAmount(partialTicks));
|
|
||||||
float[] colorValues = RenderSystem.getShaderFogColor();
|
|
||||||
return new Color(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
|
|
||||||
}
|
|
||||||
// getSpecialFogColor() is the same as getFogColor()
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Color getSkyColor() {
|
|
||||||
if (MC.level.dimensionType().hasSkyLight()) {
|
|
||||||
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), MC.getFrameTime());
|
|
||||||
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
|
|
||||||
} else
|
|
||||||
return new Color(0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getFov(float partialTicks)
|
|
||||||
{
|
|
||||||
return GAME_RENDERER.getFov(GAME_RENDERER.getMainCamera(), partialTicks, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Measured in chunks */
|
|
||||||
@Override
|
|
||||||
public int getRenderDistance()
|
|
||||||
{
|
|
||||||
return MC.options.renderDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getScreenWidth()
|
|
||||||
{
|
|
||||||
return MC.getWindow().getWidth();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public int getScreenHeight()
|
|
||||||
{
|
|
||||||
return MC.getWindow().getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the ChunkPos of all chunks that Minecraft
|
|
||||||
* is going to render this frame. <br><br>
|
|
||||||
* <p>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean usingBackupGetVanillaRenderedChunks = false;
|
|
||||||
@Override
|
@Override
|
||||||
public HashSet<AbstractChunkPosWrapper> getVanillaRenderedChunks()
|
public HashSet<AbstractChunkPosWrapper> getVanillaRenderedChunks()
|
||||||
{
|
{
|
||||||
ISodiumAccessor sodium = ModAccessorApi.get(ISodiumAccessor.class);
|
ISodiumAccessor sodium = ModAccessorHandler.get(ISodiumAccessor.class);
|
||||||
if (sodium != null)
|
if (sodium != null)
|
||||||
{
|
{
|
||||||
return sodium.getNormalRenderedChunks();
|
return sodium.getNormalRenderedChunks();
|
||||||
}
|
}
|
||||||
IOptifineAccessor optifine = ModAccessorApi.get(IOptifineAccessor.class);
|
IOptifineAccessor optifine = ModAccessorHandler.get(IOptifineAccessor.class);
|
||||||
if (optifine != null)
|
if (optifine != null)
|
||||||
{
|
{
|
||||||
HashSet<AbstractChunkPosWrapper> pos = optifine.getNormalRenderedChunks();
|
HashSet<AbstractChunkPosWrapper> pos = optifine.getNormalRenderedChunks();
|
||||||
@@ -168,79 +189,55 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
|||||||
}
|
}
|
||||||
if (!usingBackupGetVanillaRenderedChunks) {
|
if (!usingBackupGetVanillaRenderedChunks) {
|
||||||
try {
|
try {
|
||||||
LevelRenderer levelRenderer = MC.levelRenderer;
|
LevelRenderer levelRenderer = MC.levelRenderer;
|
||||||
LinkedHashSet<LevelRenderer.RenderChunkInfo> chunks = levelRenderer.renderChunkStorage.get().renderChunks;
|
LinkedHashSet<LevelRenderer.RenderChunkInfo> chunks = levelRenderer.renderChunkStorage.get().renderChunks;
|
||||||
return (chunks.stream().map((chunk) -> {
|
return (chunks.stream().map((chunk) -> {
|
||||||
|
#if MC_VERSION_1_18_2
|
||||||
|
AABB chunkBoundingBox = chunk.chunk.getBoundingBox();
|
||||||
|
#elif MC_VERSION_1_18_1
|
||||||
AABB chunkBoundingBox = chunk.chunk.bb;
|
AABB chunkBoundingBox = chunk.chunk.bb;
|
||||||
return FACTORY.createChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
|
#endif
|
||||||
Math.floorDiv((int) chunkBoundingBox.minZ, 16));
|
return FACTORY.createChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16),
|
||||||
}).collect(Collectors.toCollection(HashSet::new)));
|
Math.floorDiv((int) chunkBoundingBox.minZ, 16));
|
||||||
|
}).collect(Collectors.toCollection(HashSet::new)));
|
||||||
} catch (LinkageError e) {
|
} catch (LinkageError e) {
|
||||||
try {
|
try {
|
||||||
MinecraftWrapper.INSTANCE.sendChatMessage(
|
MinecraftClientWrapper.INSTANCE.sendChatMessage(
|
||||||
"\u00A7e\u00A7l\u00A7uWRANING: Distant Horizons: getVanillaRenderedChunks method failed."
|
"\u00A7e\u00A7l\u00A7uWARNING: Distant Horizons: getVanillaRenderedChunks method failed."
|
||||||
+ " Using Backup Method.");
|
+ " Using Backup Method.");
|
||||||
MinecraftWrapper.INSTANCE.sendChatMessage(
|
MinecraftClientWrapper.INSTANCE.sendChatMessage(
|
||||||
"\u00A7eOverdraw prevention will be worse than normal.");
|
"\u00A7eOverdraw prevention will be worse than normal.");
|
||||||
} catch (Exception e2) {}
|
} catch (Exception e2) {}
|
||||||
ClientApi.LOGGER.error("getVanillaRenderedChunks Error: {}", e);
|
ApiShared.LOGGER.error("getVanillaRenderedChunks Error: ", e);
|
||||||
usingBackupGetVanillaRenderedChunks = true;
|
usingBackupGetVanillaRenderedChunks = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getMaximumRenderedChunks();
|
return getMaximumRenderedChunks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public HashSet<AbstractChunkPosWrapper> getMaximumRenderedChunks()
|
|
||||||
{
|
|
||||||
//TODO: Make this a circle
|
|
||||||
IMinecraftWrapper mcWrapper = SingletonHandler.get(IMinecraftWrapper.class);
|
|
||||||
IWrapperFactory factory = SingletonHandler.get(IWrapperFactory.class);
|
|
||||||
|
|
||||||
int chunkRenderDist = this.getRenderDistance();
|
|
||||||
|
|
||||||
AbstractChunkPosWrapper centerChunkPos = mcWrapper.getPlayerChunkPos();
|
|
||||||
int startChunkX = centerChunkPos.getX() - chunkRenderDist;
|
|
||||||
int startChunkZ = centerChunkPos.getZ() - chunkRenderDist;
|
|
||||||
|
|
||||||
// add every position within render distance
|
|
||||||
HashSet<AbstractChunkPosWrapper> renderedPos = new HashSet<AbstractChunkPosWrapper>();
|
|
||||||
for (int chunkX = 0; chunkX < (chunkRenderDist * 2+1); chunkX++)
|
|
||||||
{
|
|
||||||
for(int chunkZ = 0; chunkZ < (chunkRenderDist * 2+1); chunkZ++)
|
|
||||||
{
|
|
||||||
renderedPos.add(factory.createChunkPos(startChunkX + chunkX, startChunkZ + chunkZ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return renderedPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getLightmapPixels()
|
||||||
@Override
|
{
|
||||||
public int[] getLightmapPixels()
|
LightTexture tex = GAME_RENDERER.lightTexture();
|
||||||
{
|
tex.tick(); // This call makes no sense, but it fixes pause menu flicker bug
|
||||||
LightTexture tex = GAME_RENDERER.lightTexture();
|
NativeImage lightMapPixels = tex.lightPixels;
|
||||||
tex.tick(); // This call makes no sense, but it fixes pause menu flicker bug
|
LightMapWrapper lightMap = new LightMapWrapper(lightMapPixels);
|
||||||
NativeImage lightMapPixels = tex.lightPixels;
|
|
||||||
LightMapWrapper lightMap = new LightMapWrapper(lightMapPixels);
|
|
||||||
|
int lightMapHeight = getLightmapTextureHeight();
|
||||||
|
int lightMapWidth = getLightmapTextureWidth();
|
||||||
int lightMapHeight = getLightmapTextureHeight();
|
|
||||||
int lightMapWidth = getLightmapTextureWidth();
|
int[] pixels = new int[lightMapWidth * lightMapHeight];
|
||||||
|
for (int u = 0; u < lightMapWidth; u++)
|
||||||
int[] pixels = new int[lightMapWidth * lightMapHeight];
|
{
|
||||||
for (int u = 0; u < lightMapWidth; u++)
|
for (int v = 0; v < lightMapWidth; v++)
|
||||||
{
|
{
|
||||||
for (int v = 0; v < lightMapWidth; v++)
|
// this could probably be kept as a int, but
|
||||||
{
|
// it is easier to test and see the colors when debugging this way.
|
||||||
// this could probably be kept as a int, but
|
// When creating a new release this should be changed to the int version.
|
||||||
// it is easier to test and see the colors when debugging this way.
|
Color c = LodUtil.intToColor(lightMap.getLightValue(u, v));
|
||||||
// When creating a new release this should be changed to the int version.
|
|
||||||
Color c = LodUtil.intToColor(lightMap.getLightValue(u, v));
|
// these should both create a totally white image
|
||||||
|
|
||||||
// these should both create a totally white image
|
|
||||||
// int col =
|
// int col =
|
||||||
// Integer.MAX_VALUE;
|
// Integer.MAX_VALUE;
|
||||||
// int col =
|
// int col =
|
||||||
@@ -248,82 +245,82 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
|||||||
// (0b11111111 << 8) + // green
|
// (0b11111111 << 8) + // green
|
||||||
// (0b11111111 << 16) + // blue
|
// (0b11111111 << 16) + // blue
|
||||||
// (0b11111111 << 24); // blue
|
// (0b11111111 << 24); // blue
|
||||||
|
|
||||||
int col =
|
int col =
|
||||||
((c.getRed() & 0xFF) << 16) | // blue
|
((c.getRed() & 0xFF) << 16) | // blue
|
||||||
((c.getGreen() & 0xFF) << 8) | // green
|
((c.getGreen() & 0xFF) << 8) | // green
|
||||||
((c.getBlue() & 0xFF)) | // red
|
((c.getBlue() & 0xFF)) | // red
|
||||||
((c.getAlpha() & 0xFF) << 24); // alpha
|
((c.getAlpha() & 0xFF) << 24); // alpha
|
||||||
|
|
||||||
// 2D array stored in a 1D array.
|
// 2D array stored in a 1D array.
|
||||||
// Thank you Tim from College ;)
|
// Thank you Tim from College ;)
|
||||||
pixels[u * lightMapWidth + v] = col;
|
pixels[u * lightMapWidth + v] = col;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pixels;
|
return pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLightmapTextureHeight()
|
public int getLightmapTextureHeight()
|
||||||
{
|
{
|
||||||
int height = -1;
|
int height = -1;
|
||||||
|
|
||||||
LightTexture lightTexture = GAME_RENDERER.lightTexture();
|
LightTexture lightTexture = GAME_RENDERER.lightTexture();
|
||||||
if (lightTexture != null)
|
if (lightTexture != null)
|
||||||
{
|
{
|
||||||
NativeImage tex = lightTexture.lightPixels;
|
NativeImage tex = lightTexture.lightPixels;
|
||||||
if (tex != null)
|
if (tex != null)
|
||||||
{
|
{
|
||||||
height = tex.getHeight();
|
height = tex.getHeight();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLightmapTextureWidth()
|
public int getLightmapTextureWidth()
|
||||||
{
|
{
|
||||||
int width = -1;
|
int width = -1;
|
||||||
|
|
||||||
LightTexture lightTexture = GAME_RENDERER.lightTexture();
|
LightTexture lightTexture = GAME_RENDERER.lightTexture();
|
||||||
if (lightTexture != null)
|
if (lightTexture != null)
|
||||||
{
|
{
|
||||||
NativeImage tex = lightTexture.lightPixels;
|
NativeImage tex = lightTexture.lightPixels;
|
||||||
if (tex != null)
|
if (tex != null)
|
||||||
{
|
{
|
||||||
width = tex.getWidth();
|
width = tex.getWidth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLightmapGLFormat() {
|
public int getLightmapGLFormat() {
|
||||||
int glFormat = -1;
|
int glFormat = -1;
|
||||||
|
|
||||||
LightTexture lightTexture = GAME_RENDERER.lightTexture();
|
LightTexture lightTexture = GAME_RENDERER.lightTexture();
|
||||||
if (lightTexture != null) {
|
if (lightTexture != null) {
|
||||||
NativeImage tex = lightTexture.lightPixels;
|
NativeImage tex = lightTexture.lightPixels;
|
||||||
if (tex != null) {
|
if (tex != null) {
|
||||||
glFormat = tex.format().glFormat();
|
glFormat = tex.format().glFormat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return glFormat;
|
return glFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFogStateSpecial() {
|
public boolean isFogStateSpecial() {
|
||||||
Entity entity = GAME_RENDERER.getMainCamera().getEntity();
|
Entity entity = GAME_RENDERER.getMainCamera().getEntity();
|
||||||
boolean isBlind = (entity instanceof LivingEntity) && ((LivingEntity)entity).hasEffect(MobEffects.BLINDNESS);
|
boolean isBlind = (entity instanceof LivingEntity) && ((LivingEntity)entity).hasEffect(MobEffects.BLINDNESS);
|
||||||
return GAME_RENDERER.getMainCamera().getFluidInCamera() != FogType.NONE || isBlind;
|
return GAME_RENDERER.getMainCamera().getFluidInCamera() != FogType.NONE || isBlind;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean tryDisableVanillaFog() {
|
public boolean tryDisableVanillaFog() {
|
||||||
return true; // Handled via MixinFogRenderer in both forge and fabric
|
return true; // Handled via MixinFogRenderer in both forge and fabric
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
{
|
{
|
||||||
int colorInt;
|
int colorInt;
|
||||||
|
|
||||||
switch (biome.getBiomeCategory())
|
switch (biome.biomeCategory)
|
||||||
{
|
{
|
||||||
|
|
||||||
case NETHER:
|
case NETHER:
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import net.minecraft.server.level.ServerLevel;
|
|||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.LightLayer;
|
import net.minecraft.world.level.LightLayer;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkSource;
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -50,12 +51,12 @@ public class WorldWrapper implements IWorldWrapper
|
|||||||
private static final ConcurrentMap<LevelAccessor, WorldWrapper> worldWrapperMap = new ConcurrentHashMap<>();
|
private static final ConcurrentMap<LevelAccessor, WorldWrapper> worldWrapperMap = new ConcurrentHashMap<>();
|
||||||
private final LevelAccessor world;
|
private final LevelAccessor world;
|
||||||
public final WorldType worldType;
|
public final WorldType worldType;
|
||||||
|
|
||||||
|
|
||||||
public WorldWrapper(LevelAccessor newWorld)
|
public WorldWrapper(LevelAccessor newWorld)
|
||||||
{
|
{
|
||||||
world = newWorld;
|
world = newWorld;
|
||||||
|
|
||||||
if (world.getClass() == ServerLevel.class)
|
if (world.getClass() == ServerLevel.class)
|
||||||
worldType = WorldType.ServerWorld;
|
worldType = WorldType.ServerWorld;
|
||||||
else if (world.getClass() == ClientLevel.class)
|
else if (world.getClass() == ClientLevel.class)
|
||||||
@@ -63,8 +64,8 @@ public class WorldWrapper implements IWorldWrapper
|
|||||||
else
|
else
|
||||||
worldType = WorldType.Unknown;
|
worldType = WorldType.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static WorldWrapper getWorldWrapper(LevelAccessor world)
|
public static WorldWrapper getWorldWrapper(LevelAccessor world)
|
||||||
{
|
{
|
||||||
@@ -72,74 +73,68 @@ public class WorldWrapper implements IWorldWrapper
|
|||||||
//first we check if the biome has already been wrapped
|
//first we check if the biome has already been wrapped
|
||||||
if(worldWrapperMap.containsKey(world) && worldWrapperMap.get(world) != null)
|
if(worldWrapperMap.containsKey(world) && worldWrapperMap.get(world) != null)
|
||||||
return worldWrapperMap.get(world);
|
return worldWrapperMap.get(world);
|
||||||
|
|
||||||
|
|
||||||
//if it hasn't been created yet, we create it and save it in the map
|
//if it hasn't been created yet, we create it and save it in the map
|
||||||
WorldWrapper worldWrapper = new WorldWrapper(world);
|
WorldWrapper worldWrapper = new WorldWrapper(world);
|
||||||
worldWrapperMap.put(world, worldWrapper);
|
worldWrapperMap.put(world, worldWrapper);
|
||||||
|
|
||||||
//we return the newly created wrapper
|
//we return the newly created wrapper
|
||||||
return worldWrapper;
|
return worldWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void clearMap()
|
public static void clearMap()
|
||||||
{
|
{
|
||||||
worldWrapperMap.clear();
|
worldWrapperMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorldType getWorldType()
|
public WorldType getWorldType()
|
||||||
{
|
{
|
||||||
return worldType;
|
return worldType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DimensionTypeWrapper getDimensionType()
|
public DimensionTypeWrapper getDimensionType()
|
||||||
{
|
{
|
||||||
return DimensionTypeWrapper.getDimensionTypeWrapper(world.dimensionType());
|
return DimensionTypeWrapper.getDimensionTypeWrapper(world.dimensionType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBlockLight(int x, int y, int z)
|
public int getBlockLight(int x, int y, int z)
|
||||||
{
|
{
|
||||||
return world.getBrightness(LightLayer.BLOCK, new BlockPos(x,y,z));
|
return world.getBrightness(LightLayer.BLOCK, new BlockPos(x,y,z));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSkyLight(int x, int y, int z)
|
public int getSkyLight(int x, int y, int z)
|
||||||
{
|
{
|
||||||
return world.getBrightness(LightLayer.SKY, new BlockPos(x,y,z));
|
return world.getBrightness(LightLayer.SKY, new BlockPos(x,y,z));
|
||||||
}
|
}
|
||||||
|
|
||||||
public LevelAccessor getWorld()
|
public LevelAccessor getWorld()
|
||||||
{
|
{
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasCeiling()
|
public boolean hasCeiling()
|
||||||
{
|
{
|
||||||
return world.dimensionType().hasCeiling();
|
return world.dimensionType().hasCeiling();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasSkyLight()
|
public boolean hasSkyLight()
|
||||||
{
|
{
|
||||||
return world.dimensionType().hasSkyLight();
|
return world.dimensionType().hasSkyLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty()
|
|
||||||
{
|
|
||||||
return world == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getHeight()
|
public int getHeight()
|
||||||
{
|
{
|
||||||
return world.getHeight();
|
return world.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short getMinHeight()
|
public short getMinHeight()
|
||||||
{
|
{
|
||||||
@@ -152,21 +147,21 @@ public class WorldWrapper implements IWorldWrapper
|
|||||||
{
|
{
|
||||||
if (worldType != WorldType.ServerWorld)
|
if (worldType != WorldType.ServerWorld)
|
||||||
throw new UnsupportedOperationException("getSaveFolder can only be called for ServerWorlds.");
|
throw new UnsupportedOperationException("getSaveFolder can only be called for ServerWorlds.");
|
||||||
|
|
||||||
ServerChunkCache chunkSource = ((ServerLevel) world).getChunkSource();
|
ServerChunkCache chunkSource = ((ServerLevel) world).getChunkSource();
|
||||||
return chunkSource.getDataStorage().dataFolder;
|
return chunkSource.getDataStorage().dataFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** @throws UnsupportedOperationException if the WorldWrapper isn't for a ServerWorld */
|
/** @throws UnsupportedOperationException if the WorldWrapper isn't for a ServerWorld */
|
||||||
public ServerLevel getServerWorld() throws UnsupportedOperationException
|
public ServerLevel getServerWorld() throws UnsupportedOperationException
|
||||||
{
|
{
|
||||||
if (worldType != WorldType.ServerWorld)
|
if (worldType != WorldType.ServerWorld)
|
||||||
throw new UnsupportedOperationException("getSaveFolder can only be called for ServerWorlds.");
|
throw new UnsupportedOperationException("getSaveFolder can only be called for ServerWorlds.");
|
||||||
|
|
||||||
return (ServerLevel) world;
|
return (ServerLevel) world;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSeaLevel()
|
public int getSeaLevel()
|
||||||
{
|
{
|
||||||
@@ -175,11 +170,18 @@ public class WorldWrapper implements IWorldWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IChunkWrapper tryGetChunk(AbstractChunkPosWrapper pos) {
|
public IChunkWrapper tryGetChunk(AbstractChunkPosWrapper pos) {
|
||||||
ChunkAccess chunk = world.getChunk(pos.getX(), pos.getZ(), ChunkStatus.EMPTY, false);
|
ChunkAccess chunk = world.getChunk(pos.getX(), pos.getZ(), ChunkStatus.EMPTY, false);
|
||||||
if (chunk == null) return null;
|
if (chunk == null) return null;
|
||||||
return new ChunkWrapper(chunk, world);
|
return new ChunkWrapper(chunk, world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasChunkLoaded(int chunkX, int chunkZ) {
|
||||||
|
// world.hasChunk(chunkX, chunkZ); THIS DOES NOT WORK FOR CLIENT LEVEL CAUSE MOJANG ALWAYS RETURN TRUE FOR THAT!
|
||||||
|
ChunkSource source = world.getChunkSource();
|
||||||
|
return source.hasChunk(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-62
@@ -19,17 +19,17 @@
|
|||||||
|
|
||||||
package com.seibel.lod.common.wrappers.worldGeneration;
|
package com.seibel.lod.common.wrappers.worldGeneration;
|
||||||
|
|
||||||
import com.seibel.lod.core.api.ClientApi;
|
import com.seibel.lod.core.api.ApiShared;
|
||||||
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
|
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
|
||||||
import com.seibel.lod.core.builders.lodBuilding.LodBuilderConfig;
|
import com.seibel.lod.core.builders.lodBuilding.LodBuilderConfig;
|
||||||
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
|
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
|
||||||
import com.seibel.lod.core.enums.config.LightGenerationMode;
|
import com.seibel.lod.core.enums.config.LightGenerationMode;
|
||||||
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
import com.seibel.lod.core.objects.lod.LodDimension;
|
import com.seibel.lod.core.objects.lod.LodDimension;
|
||||||
import com.seibel.lod.core.util.GridList;
|
import com.seibel.lod.core.util.gridList.ArrayGridList;
|
||||||
import com.seibel.lod.core.util.LodThreadFactory;
|
import com.seibel.lod.core.util.LodThreadFactory;
|
||||||
import com.seibel.lod.core.util.SingletonHandler;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper;
|
||||||
|
|
||||||
@@ -190,7 +190,6 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
if (e.endNano != 0)
|
if (e.endNano != 0)
|
||||||
{
|
{
|
||||||
lodTime.add(e.endNano - preTime);
|
lodTime.add(e.endNano - preTime);
|
||||||
preTime = e.endNano;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +213,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
|
|
||||||
//=================Generation Step===================
|
//=================Generation Step===================
|
||||||
|
|
||||||
public final LinkedList<GenerationEvent> events = new LinkedList<GenerationEvent>();
|
public final LinkedList<GenerationEvent> events = new LinkedList<>();
|
||||||
public final GlobalParameters params;
|
public final GlobalParameters params;
|
||||||
public final StepStructureStart stepStructureStart = new StepStructureStart(this);
|
public final StepStructureStart stepStructureStart = new StepStructureStart(this);
|
||||||
public final StepStructureReference stepStructureReference = new StepStructureReference(this);
|
public final StepStructureReference stepStructureReference = new StepStructureReference(this);
|
||||||
@@ -226,15 +225,16 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
public boolean unsafeThreadingRecorded = false;
|
public boolean unsafeThreadingRecorded = false;
|
||||||
//public boolean safeMode = false;
|
//public boolean safeMode = false;
|
||||||
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
|
private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class);
|
||||||
private static final IMinecraftWrapper MC = SingletonHandler.get(IMinecraftWrapper.class);
|
private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
|
||||||
public static final long EXCEPTION_TIMER_RESET_TIME = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS);
|
public static final long EXCEPTION_TIMER_RESET_TIME = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS);
|
||||||
public static final int EXCEPTION_COUNTER_TRIGGER = 20;
|
public static final int EXCEPTION_COUNTER_TRIGGER = 20;
|
||||||
|
public static final int RANGE_TO_RANGE_EMPTY_EXTENSION = 1;
|
||||||
public int unknownExceptionCount = 0;
|
public int unknownExceptionCount = 0;
|
||||||
public long lastExceptionTriggerTime = 0;
|
public long lastExceptionTriggerTime = 0;
|
||||||
|
|
||||||
public static final LodThreadFactory threadFactory = new LodThreadFactory("Gen-Worker-Thread", Thread.MIN_PRIORITY);
|
public static final LodThreadFactory threadFactory = new LodThreadFactory("Gen-Worker-Thread", Thread.MIN_PRIORITY);
|
||||||
|
|
||||||
public static ThreadLocal<Boolean> isDistantGeneratorThread = new ThreadLocal<Boolean>();
|
public static ThreadLocal<Boolean> isDistantGeneratorThread = new ThreadLocal<>();
|
||||||
|
|
||||||
public static boolean isCurrentThreadDistantGeneratorThread() {
|
public static boolean isCurrentThreadDistantGeneratorThread() {
|
||||||
return (isDistantGeneratorThread.get() != null);
|
return (isDistantGeneratorThread.get() != null);
|
||||||
@@ -251,7 +251,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
if (!unsafeThreadingRecorded && !f.isDone()) {
|
if (!unsafeThreadingRecorded && !f.isDone()) {
|
||||||
MC.sendChatMessage("\u00A74\u00A7l\u00A7uERROR: Distant Horizons: Unsafe Threading in Chunk Generator Detected!");
|
MC.sendChatMessage("\u00A74\u00A7l\u00A7uERROR: Distant Horizons: Unsafe Threading in Chunk Generator Detected!");
|
||||||
MC.sendChatMessage("\u00A7eTo increase stability, it is recommended to set world generation threads count to 1.");
|
MC.sendChatMessage("\u00A7eTo increase stability, it is recommended to set world generation threads count to 1.");
|
||||||
ClientApi.LOGGER.error("Unsafe Threading in Chunk Generator: ", new RuntimeException("Concurrent future"));
|
ApiShared.LOGGER.error("Unsafe Threading in Chunk Generator: ", new RuntimeException("Concurrent future"));
|
||||||
unsafeThreadingRecorded = true;
|
unsafeThreadingRecorded = true;
|
||||||
}
|
}
|
||||||
return f.join();
|
return f.join();
|
||||||
@@ -300,8 +300,8 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
}
|
}
|
||||||
catch (Throwable e)
|
catch (Throwable e)
|
||||||
{
|
{
|
||||||
ClientApi.LOGGER.error("Batching World Generator: Event {} gotten an exception", event);
|
ApiShared.LOGGER.error("Batching World Generator: Event {} gotten an exception", event);
|
||||||
ClientApi.LOGGER.error("Exception: ", e);
|
ApiShared.LOGGER.error("Exception: ", e);
|
||||||
unknownExceptionCount++;
|
unknownExceptionCount++;
|
||||||
lastExceptionTriggerTime = System.nanoTime();
|
lastExceptionTriggerTime = System.nanoTime();
|
||||||
}
|
}
|
||||||
@@ -312,12 +312,12 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
}
|
}
|
||||||
else if (event.hasTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS))
|
else if (event.hasTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS))
|
||||||
{
|
{
|
||||||
ClientApi.LOGGER.error("Batching World Generator: " + event + " timed out and terminated!");
|
ApiShared.LOGGER.error("Batching World Generator: " + event + " timed out and terminated!");
|
||||||
ClientApi.LOGGER.info("Dump PrefEvent: " + event.pEvent);
|
ApiShared.LOGGER.info("Dump PrefEvent: " + event.pEvent);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!event.terminate())
|
if (!event.terminate())
|
||||||
ClientApi.LOGGER.error("Failed to terminate the stuck generation event!");
|
ApiShared.LOGGER.error("Failed to terminate the stuck generation event!");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -329,7 +329,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
try {
|
try {
|
||||||
MC.sendChatMessage("\u00A74\u00A7l\u00A7uERROR: Distant Horizons: Too many exceptions in Batching World Generator! Disabling the generator.");
|
MC.sendChatMessage("\u00A74\u00A7l\u00A7uERROR: Distant Horizons: Too many exceptions in Batching World Generator! Disabling the generator.");
|
||||||
} catch (Exception e) {}
|
} catch (Exception e) {}
|
||||||
ClientApi.LOGGER.error("Too many exceptions in Batching World Generator! Now disabling.");
|
ApiShared.LOGGER.error("Too many exceptions in Batching World Generator! Now disabling.");
|
||||||
unknownExceptionCount = 0;
|
unknownExceptionCount = 0;
|
||||||
CONFIG.client().worldGenerator().setEnableDistantGeneration(false);
|
CONFIG.client().worldGenerator().setEnableDistantGeneration(false);
|
||||||
}
|
}
|
||||||
@@ -338,14 +338,14 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
public BatchGenerationEnvironment(IWorldWrapper serverlevel, LodBuilder lodBuilder, LodDimension lodDim)
|
public BatchGenerationEnvironment(IWorldWrapper serverlevel, LodBuilder lodBuilder, LodDimension lodDim)
|
||||||
{
|
{
|
||||||
super(serverlevel, lodBuilder, lodDim);
|
super(serverlevel, lodBuilder, lodDim);
|
||||||
ClientApi.LOGGER.info("================WORLD_GEN_STEP_INITING=============");
|
ApiShared.LOGGER.info("================WORLD_GEN_STEP_INITING=============");
|
||||||
ChunkGenerator generator = ((WorldWrapper) serverlevel).getServerWorld().getChunkSource().getGenerator();
|
ChunkGenerator generator = ((WorldWrapper) serverlevel).getServerWorld().getChunkSource().getGenerator();
|
||||||
if (!(generator instanceof NoiseBasedChunkGenerator ||
|
if (!(generator instanceof NoiseBasedChunkGenerator ||
|
||||||
generator instanceof DebugLevelSource ||
|
generator instanceof DebugLevelSource ||
|
||||||
generator instanceof FlatLevelSource)) {
|
generator instanceof FlatLevelSource)) {
|
||||||
MC.sendChatMessage("\u00A74\u00A7l\u00A7uWARNING: Distant Horizons: Unknown Chunk Generator Detected! Distant Generation May Fail!");
|
MC.sendChatMessage("\u00A74\u00A7l\u00A7uWARNING: Distant Horizons: Unknown Chunk Generator Detected! Distant Generation May Fail!");
|
||||||
MC.sendChatMessage("\u00A7eIf it does crash, set Distant Generation to OFF or Generation Mode to None.");
|
MC.sendChatMessage("\u00A7eIf it does crash, set Distant Generation to OFF or Generation Mode to None.");
|
||||||
ClientApi.LOGGER.warn("Unknown Chunk Generator detected: {}", generator.getClass());
|
ApiShared.LOGGER.warn("Unknown Chunk Generator detected: {}", generator.getClass());
|
||||||
}
|
}
|
||||||
params = new GlobalParameters((ServerLevel) ((WorldWrapper) serverlevel).getWorld(), lodBuilder, lodDim);
|
params = new GlobalParameters((ServerLevel) ((WorldWrapper) serverlevel).getWorld(), lodBuilder, lodDim);
|
||||||
}
|
}
|
||||||
@@ -360,7 +360,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ClientApi.LOGGER.error("DistantHorizons: Couldn't load chunk {}", chunkPos, e);
|
ApiShared.LOGGER.error("DistantHorizons: Couldn't load chunk {}", chunkPos, e);
|
||||||
}
|
}
|
||||||
if (chunkData == null)
|
if (chunkData == null)
|
||||||
{
|
{
|
||||||
@@ -371,7 +371,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
try {
|
try {
|
||||||
return ChunkLoader.read(level, lightEngine, chunkPos, chunkData);
|
return ChunkLoader.read(level, lightEngine, chunkPos, chunkData);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ClientApi.LOGGER.error("DistantHorizons: Couldn't load chunk {}", chunkPos, e);
|
ApiShared.LOGGER.error("DistantHorizons: Couldn't load chunk {}", chunkPos, e);
|
||||||
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null);
|
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -381,24 +381,22 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
public void generateLodFromList(GenerationEvent e)
|
public void generateLodFromList(GenerationEvent e)
|
||||||
{
|
{
|
||||||
if (ENABLE_EVENT_LOGGING)
|
if (ENABLE_EVENT_LOGGING)
|
||||||
ClientApi.LOGGER.info("Lod Generate Event: " + e.pos);
|
ApiShared.LOGGER.info("Lod Generate Event: " + e.pos);
|
||||||
e.pEvent.beginNano = System.nanoTime();
|
e.pEvent.beginNano = System.nanoTime();
|
||||||
GridList<ChunkAccess> referencedChunks;
|
ArrayGridList<ChunkAccess> referencedChunks;
|
||||||
|
ArrayGridList<ChunkAccess> genChunks;
|
||||||
DistanceGenerationMode generationMode;
|
DistanceGenerationMode generationMode;
|
||||||
LightedWorldGenRegion region;
|
LightedWorldGenRegion region;
|
||||||
WorldGenLevelLightEngine lightEngine;
|
WorldGenLevelLightEngine lightEngine;
|
||||||
LightGetterAdaptor adaptor;
|
LightGetterAdaptor adaptor;
|
||||||
|
int refRange = e.range + RANGE_TO_RANGE_EMPTY_EXTENSION;
|
||||||
|
int refOffsetX = e.pos.x - refRange;
|
||||||
|
int refOffsetZ = e.pos.z - refRange;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
adaptor = new LightGetterAdaptor(params.level);
|
adaptor = new LightGetterAdaptor(params.level);
|
||||||
lightEngine = new WorldGenLevelLightEngine(adaptor);
|
lightEngine = new WorldGenLevelLightEngine(adaptor);
|
||||||
|
|
||||||
int cx = e.pos.x;
|
|
||||||
int cy = e.pos.z;
|
|
||||||
int rangeEmpty = e.range + 1;
|
|
||||||
GridList<ChunkAccess> chunks = new GridList<ChunkAccess>(rangeEmpty);
|
|
||||||
|
|
||||||
@SuppressWarnings("resource")
|
@SuppressWarnings("resource")
|
||||||
EmptyChunkGenerator generator = (int x, int z) ->
|
EmptyChunkGenerator generator = (int x, int z) ->
|
||||||
{
|
{
|
||||||
@@ -417,23 +415,19 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
params.biomes, null);
|
params.biomes, null);
|
||||||
return target;
|
return target;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int oy = -rangeEmpty; oy <= rangeEmpty; oy++)
|
referencedChunks = new ArrayGridList<>(refRange*2+1,
|
||||||
{
|
(x,z) -> generator.generate(x + refOffsetX,z + refOffsetZ)
|
||||||
for (int ox = -rangeEmpty; ox <= rangeEmpty; ox++)
|
);
|
||||||
{
|
|
||||||
ChunkAccess target = generator.generate(cx + ox, cy + oy);
|
|
||||||
chunks.add(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e.pEvent.emptyNano = System.nanoTime();
|
e.pEvent.emptyNano = System.nanoTime();
|
||||||
e.refreshTimeout();
|
e.refreshTimeout();
|
||||||
region = new LightedWorldGenRegion(params.level, lightEngine, e.tParam.structFeat, chunks, ChunkStatus.STRUCTURE_STARTS, rangeEmpty, e.lightMode, generator);
|
region = new LightedWorldGenRegion(params.level, lightEngine, referencedChunks,
|
||||||
|
ChunkStatus.STRUCTURE_STARTS, refRange, e.lightMode, generator);
|
||||||
adaptor.setRegion(region);
|
adaptor.setRegion(region);
|
||||||
e.tParam.makeStructFeat(region);
|
e.tParam.makeStructFeat(region);
|
||||||
referencedChunks = chunks.subGrid(e.range);
|
genChunks = new ArrayGridList<>(referencedChunks, RANGE_TO_RANGE_EMPTY_EXTENSION,
|
||||||
referencedChunks = generateDirect(e, referencedChunks, e.target, region);
|
referencedChunks.gridSize - RANGE_TO_RANGE_EMPTY_EXTENSION);
|
||||||
|
generateDirect(e, genChunks, e.target, region);
|
||||||
}
|
}
|
||||||
catch (StepStructureStart.StructStartCorruptedException f)
|
catch (StepStructureStart.StructStartCorruptedException f)
|
||||||
{
|
{
|
||||||
@@ -465,14 +459,12 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int centreIndex = referencedChunks.size() / 2;
|
|
||||||
|
|
||||||
for (int oy = -e.range; oy <= e.range; oy++)
|
for (int oy = 0; oy < genChunks.gridSize; oy++)
|
||||||
{
|
{
|
||||||
for (int ox = -e.range; ox <= e.range; ox++)
|
for (int ox = 0; ox < genChunks.gridSize; ox++)
|
||||||
{
|
{
|
||||||
int targetIndex = referencedChunks.offsetOf(centreIndex, ox, oy);
|
ChunkAccess target = genChunks.get(ox, oy);
|
||||||
ChunkAccess target = referencedChunks.get(targetIndex);
|
|
||||||
ChunkWrapper wrappedChunk = new ChunkWrapper(target, region);
|
ChunkWrapper wrappedChunk = new ChunkWrapper(target, region);
|
||||||
if (!wrappedChunk.isLightCorrect()) {
|
if (!wrappedChunk.isLightCorrect()) {
|
||||||
throw new RuntimeException("The generated chunk somehow has isLightCorrect() returning false");
|
throw new RuntimeException("The generated chunk somehow has isLightCorrect() returning false");
|
||||||
@@ -483,14 +475,14 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
if (isFull)
|
if (isFull)
|
||||||
{
|
{
|
||||||
if (ENABLE_LOAD_EVENT_LOGGING)
|
if (ENABLE_LOAD_EVENT_LOGGING)
|
||||||
ClientApi.LOGGER.info("Detected full existing chunk at {}", target.getPos());
|
ApiShared.LOGGER.info("Detected full existing chunk at {}", target.getPos());
|
||||||
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk,
|
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk,
|
||||||
new LodBuilderConfig(DistanceGenerationMode.FULL), true, e.genAllDetails);
|
new LodBuilderConfig(DistanceGenerationMode.FULL), true, e.genAllDetails);
|
||||||
}
|
}
|
||||||
else if (isPartial)
|
else if (isPartial)
|
||||||
{
|
{
|
||||||
if (ENABLE_LOAD_EVENT_LOGGING)
|
if (ENABLE_LOAD_EVENT_LOGGING)
|
||||||
ClientApi.LOGGER.info("Detected old existing chunk at {}", target.getPos());
|
ApiShared.LOGGER.info("Detected old existing chunk at {}", target.getPos());
|
||||||
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk,
|
params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk,
|
||||||
new LodBuilderConfig(generationMode), true, e.genAllDetails);
|
new LodBuilderConfig(generationMode), true, e.genAllDetails);
|
||||||
}
|
}
|
||||||
@@ -516,12 +508,12 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
if (ENABLE_PERF_LOGGING)
|
if (ENABLE_PERF_LOGGING)
|
||||||
{
|
{
|
||||||
e.tParam.perf.recordEvent(e.pEvent);
|
e.tParam.perf.recordEvent(e.pEvent);
|
||||||
ClientApi.LOGGER.info(e.tParam.perf);
|
ApiShared.LOGGER.info(e.tParam.perf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GridList<ChunkAccess> generateDirect(GenerationEvent e, GridList<ChunkAccess> subRange, Steps step,
|
public void generateDirect(GenerationEvent e, ArrayGridList<ChunkAccess> subRange, Steps step,
|
||||||
LightedWorldGenRegion region)
|
LightedWorldGenRegion region)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -534,38 +526,37 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (step == Steps.Empty)
|
if (step == Steps.Empty)
|
||||||
return subRange;
|
return;
|
||||||
stepStructureStart.generateGroup(e.tParam, region, subRange);
|
stepStructureStart.generateGroup(e.tParam, region, subRange);
|
||||||
e.pEvent.structStartNano = System.nanoTime();
|
e.pEvent.structStartNano = System.nanoTime();
|
||||||
e.refreshTimeout();
|
e.refreshTimeout();
|
||||||
if (step == Steps.StructureStart)
|
if (step == Steps.StructureStart)
|
||||||
return subRange;
|
return;
|
||||||
stepStructureReference.generateGroup(e.tParam, region, subRange);
|
stepStructureReference.generateGroup(e.tParam, region, subRange);
|
||||||
e.pEvent.structRefNano = System.nanoTime();
|
e.pEvent.structRefNano = System.nanoTime();
|
||||||
e.refreshTimeout();
|
e.refreshTimeout();
|
||||||
if (step == Steps.StructureReference)
|
if (step == Steps.StructureReference)
|
||||||
return subRange;
|
return;
|
||||||
stepBiomes.generateGroup(e.tParam, region, subRange);
|
stepBiomes.generateGroup(e.tParam, region, subRange);
|
||||||
e.pEvent.biomeNano = System.nanoTime();
|
e.pEvent.biomeNano = System.nanoTime();
|
||||||
e.refreshTimeout();
|
e.refreshTimeout();
|
||||||
if (step == Steps.Biomes)
|
if (step == Steps.Biomes)
|
||||||
return subRange;
|
return;
|
||||||
stepNoise.generateGroup(e.tParam, region, subRange);
|
stepNoise.generateGroup(e.tParam, region, subRange);
|
||||||
e.pEvent.noiseNano = System.nanoTime();
|
e.pEvent.noiseNano = System.nanoTime();
|
||||||
e.refreshTimeout();
|
e.refreshTimeout();
|
||||||
if (step == Steps.Noise)
|
if (step == Steps.Noise)
|
||||||
return subRange;
|
return;
|
||||||
stepSurface.generateGroup(e.tParam, region, subRange);
|
stepSurface.generateGroup(e.tParam, region, subRange);
|
||||||
e.pEvent.surfaceNano = System.nanoTime();
|
e.pEvent.surfaceNano = System.nanoTime();
|
||||||
e.refreshTimeout();
|
e.refreshTimeout();
|
||||||
if (step == Steps.Surface)
|
if (step == Steps.Surface)
|
||||||
return subRange;
|
return;
|
||||||
if (step == Steps.Carvers)
|
if (step == Steps.Carvers)
|
||||||
return subRange;
|
return;
|
||||||
stepFeatures.generateGroup(e.tParam, region, subRange);
|
stepFeatures.generateGroup(e.tParam, region, subRange);
|
||||||
e.pEvent.featureNano = System.nanoTime();
|
e.pEvent.featureNano = System.nanoTime();
|
||||||
e.refreshTimeout();
|
e.refreshTimeout();
|
||||||
return subRange;
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -603,14 +594,14 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop(boolean blocking) {
|
public void stop(boolean blocking) {
|
||||||
ClientApi.LOGGER.info("Batch Chunk Generator shutting down...");
|
ApiShared.LOGGER.info("Batch Chunk Generator shutting down...");
|
||||||
executors.shutdownNow();
|
executors.shutdownNow();
|
||||||
if (blocking) try {
|
if (blocking) try {
|
||||||
if (!executors.awaitTermination(10, TimeUnit.SECONDS)) {
|
if (!executors.awaitTermination(10, TimeUnit.SECONDS)) {
|
||||||
ClientApi.LOGGER.error("Batch Chunk Generator shutdown failed! Ignoring child threads...");
|
ApiShared.LOGGER.error("Batch Chunk Generator shutdown failed! Ignoring child threads...");
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
ClientApi.LOGGER.error("Batch Chunk Generator shutdown failed! Ignoring child threads...", e);
|
ApiShared.LOGGER.error("Batch Chunk Generator shutdown failed! Ignoring child threads...", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+6
-4
@@ -6,9 +6,10 @@ import java.util.concurrent.Future;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment.PrefEvent;
|
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment.PrefEvent;
|
||||||
import com.seibel.lod.core.api.ClientApi;
|
import com.seibel.lod.core.api.ApiShared;
|
||||||
import com.seibel.lod.core.enums.config.LightGenerationMode;
|
import com.seibel.lod.core.enums.config.LightGenerationMode;
|
||||||
import com.seibel.lod.core.util.SingletonHandler;
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
|
import com.seibel.lod.core.util.LodUtil;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper.Steps;
|
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper.Steps;
|
||||||
|
|
||||||
@@ -69,9 +70,9 @@ public final class GenerationEvent
|
|||||||
|
|
||||||
public boolean terminate()
|
public boolean terminate()
|
||||||
{
|
{
|
||||||
future.cancel(true);
|
ApiShared.LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN=======================");
|
||||||
ClientApi.LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN=======================");
|
|
||||||
BatchGenerationEnvironment.threadFactory.dumpAllThreadStacks();
|
BatchGenerationEnvironment.threadFactory.dumpAllThreadStacks();
|
||||||
|
future.cancel(true);
|
||||||
return future.isCancelled();
|
return future.isCancelled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,6 +100,7 @@ public final class GenerationEvent
|
|||||||
public void refreshTimeout()
|
public void refreshTimeout()
|
||||||
{
|
{
|
||||||
nanotime = System.nanoTime();
|
nanotime = System.nanoTime();
|
||||||
|
LodUtil.checkInterruptsUnchecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-2
@@ -3,9 +3,8 @@ package com.seibel.lod.common.wrappers.worldGeneration;
|
|||||||
|
|
||||||
import com.mojang.datafixers.DataFixer;
|
import com.mojang.datafixers.DataFixer;
|
||||||
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
|
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
|
||||||
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
import com.seibel.lod.core.objects.lod.LodDimension;
|
import com.seibel.lod.core.objects.lod.LodDimension;
|
||||||
import com.seibel.lod.core.util.SingletonHandler;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
|
|
||||||
|
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.core.RegistryAccess;
|
||||||
|
|||||||
-153
@@ -1,153 +0,0 @@
|
|||||||
|
|
||||||
package com.seibel.lod.common.wrappers.worldGeneration;
|
|
||||||
|
|
||||||
import com.seibel.lod.core.builders.lodBuilding.LodBuilder;
|
|
||||||
import com.seibel.lod.core.builders.lodBuilding.LodBuilderConfig;
|
|
||||||
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
|
|
||||||
import com.seibel.lod.core.objects.lod.LodDimension;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractWorldGeneratorWrapper;
|
|
||||||
|
|
||||||
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
|
|
||||||
import com.seibel.lod.common.wrappers.world.WorldWrapper;
|
|
||||||
|
|
||||||
import net.minecraft.world.level.chunk.*;
|
|
||||||
/* */
|
|
||||||
/* */ import net.minecraft.server.level.ServerLevel;
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author James Seibel
|
|
||||||
* @version 11-13-2021
|
|
||||||
*/
|
|
||||||
public class WorldGeneratorWrapper extends AbstractWorldGeneratorWrapper
|
|
||||||
{
|
|
||||||
public final ServerLevel serverWorld;
|
|
||||||
public final LodDimension lodDim;
|
|
||||||
public final LodBuilder lodBuilder;
|
|
||||||
|
|
||||||
public WorldGeneratorWrapper(LodBuilder newLodBuilder, LodDimension newLodDimension, IWorldWrapper worldWrapper)
|
|
||||||
{
|
|
||||||
super(newLodBuilder, newLodDimension, worldWrapper);
|
|
||||||
|
|
||||||
lodBuilder = newLodBuilder;
|
|
||||||
lodDim = newLodDimension;
|
|
||||||
serverWorld = ((WorldWrapper) worldWrapper).getServerWorld();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** takes about 2-5 ms */
|
|
||||||
@Override
|
|
||||||
public void generateBiomesOnly(AbstractChunkPosWrapper pos, DistanceGenerationMode generationMode)
|
|
||||||
{
|
|
||||||
generate(pos.getX(), pos.getZ(), generationMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** takes about 10 - 20 ms */
|
|
||||||
@Override
|
|
||||||
public void generateSurface(AbstractChunkPosWrapper pos)
|
|
||||||
{
|
|
||||||
generate(pos.getX(), pos.getZ(), DistanceGenerationMode.SURFACE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* takes about 15 - 20 ms
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void generateFeatures(AbstractChunkPosWrapper pos)
|
|
||||||
{
|
|
||||||
generate(pos.getX(), pos.getZ(), DistanceGenerationMode.FEATURES);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates using MC's ServerWorld.
|
|
||||||
* <p>
|
|
||||||
* on pre generated chunks 0 - 1 ms <br>
|
|
||||||
* on un generated chunks 0 - 50 ms <br>
|
|
||||||
* with the median seeming to hover around 15 - 30 ms <br>
|
|
||||||
* and outliers in the 100 - 200 ms range <br>
|
|
||||||
* <p>
|
|
||||||
* Note this should not be multithreaded and does cause server/simulation lag
|
|
||||||
* (Higher lag for generating than loading)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void generateFull(AbstractChunkPosWrapper pos)
|
|
||||||
{
|
|
||||||
generate(pos.getX(), pos.getZ(), DistanceGenerationMode.FULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generate(int chunkX, int chunkZ, DistanceGenerationMode generationMode)
|
|
||||||
{
|
|
||||||
|
|
||||||
// long t = System.nanoTime();
|
|
||||||
|
|
||||||
ChunkStatus targetStatus;
|
|
||||||
switch (generationMode)
|
|
||||||
{
|
|
||||||
case BIOME_ONLY:
|
|
||||||
targetStatus = ChunkStatus.BIOMES;
|
|
||||||
break;
|
|
||||||
case BIOME_ONLY_SIMULATE_HEIGHT:
|
|
||||||
targetStatus = ChunkStatus.NOISE;
|
|
||||||
break;
|
|
||||||
case SURFACE:
|
|
||||||
targetStatus = ChunkStatus.SURFACE;
|
|
||||||
break;
|
|
||||||
case FEATURES:
|
|
||||||
targetStatus = ChunkStatus.FEATURES;
|
|
||||||
break;
|
|
||||||
case FULL:
|
|
||||||
targetStatus = ChunkStatus.FULL;
|
|
||||||
break;
|
|
||||||
case NONE:
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The bool=true means that we wants to generate chunk, and that the returned ChunkAccess must not be null
|
|
||||||
ChunkAccess ca = serverWorld.getChunkSource().getChunk(chunkX, chunkZ, targetStatus, true);
|
|
||||||
if (ca == null)
|
|
||||||
throw new RuntimeException("This should NEVER be null due to bool being true");
|
|
||||||
lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(ca, serverWorld), new LodBuilderConfig(generationMode), false, true);
|
|
||||||
|
|
||||||
// long duration = System.nanoTime()-t;
|
|
||||||
|
|
||||||
// Debug print the duration
|
|
||||||
// System.out.println("LodChunkGenFull["+chunkX+","+chunkZ+"]: "+(double)(duration)/1000.);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Update this chart
|
|
||||||
* performance/generation tests related to
|
|
||||||
* serverWorld.getChunk(x, z, ChunkStatus. *** )
|
|
||||||
|
|
||||||
true/false is whether they generated blocks or not
|
|
||||||
the time is how long it took to generate
|
|
||||||
|
|
||||||
ChunkStatus.EMPTY 0 - 1 ms false (empty, what did you expect? :P)
|
|
||||||
ChunkStatus.STRUCTURE_REFERENCES 1 - 2 ms false (no height, only generates some chunks)
|
|
||||||
ChunkStatus.BIOMES 1 - 10 ms false (no height)
|
|
||||||
ChunkStatus.NOISE 4 - 15 ms true (all blocks are stone)
|
|
||||||
ChunkStatus.LIQUID_CARVERS 6 - 12 ms true (no snow/trees, just grass)
|
|
||||||
ChunkStatus.SURFACE 5 - 15 ms true (no snow/trees, just grass)
|
|
||||||
ChunkStatus.CARVERS 5 - 30 ms true (no snow/trees, just grass)
|
|
||||||
ChunkStatus.FEATURES 7 - 25 ms true
|
|
||||||
ChunkStatus.HEIGHTMAPS 20 - 40 ms true
|
|
||||||
ChunkStatus.LIGHT 20 - 40 ms true
|
|
||||||
ChunkStatus.FULL 30 - 50 ms true
|
|
||||||
ChunkStatus.SPAWN 50 - 80 ms true
|
|
||||||
|
|
||||||
At this point I would suggest using FEATURES, as it generates snow and trees
|
|
||||||
(and any other object that are needed to make biomes distinct)
|
|
||||||
|
|
||||||
Otherwise, if snow/trees aren't necessary SURFACE is the next fastest (although not by much)
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
+89
-13
@@ -4,6 +4,7 @@ package com.seibel.lod.common.wrappers.worldGeneration.mimicObject;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.Dynamic;
|
import com.mojang.serialization.Dynamic;
|
||||||
|
import com.seibel.lod.core.api.ApiShared;
|
||||||
import com.seibel.lod.core.api.ClientApi;
|
import com.seibel.lod.core.api.ClientApi;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||||
@@ -14,6 +15,12 @@ import java.util.Locale;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
#if MC_VERSION_1_18_2
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.core.RegistryAccess;
|
||||||
|
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
||||||
|
#endif
|
||||||
|
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
@@ -49,7 +56,7 @@ import org.apache.logging.log4j.Logger;
|
|||||||
public class ChunkLoader
|
public class ChunkLoader
|
||||||
{
|
{
|
||||||
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
||||||
private static final Logger LOGGER = ClientApi.LOGGER;
|
private static final Logger LOGGER = ApiShared.LOGGER;
|
||||||
private static final String TAG_UPGRADE_DATA = "UpgradeData";
|
private static final String TAG_UPGRADE_DATA = "UpgradeData";
|
||||||
private static final String BLOCK_TICKS_TAG = "block_ticks";
|
private static final String BLOCK_TICKS_TAG = "block_ticks";
|
||||||
private static final String FLUID_TICKS_TAG = "fluid_ticks";
|
private static final String FLUID_TICKS_TAG = "fluid_ticks";
|
||||||
@@ -69,16 +76,21 @@ public class ChunkLoader
|
|||||||
private static LevelChunkSection[] readSections(LevelAccessor level, LevelLightEngine lightEngine, ChunkPos chunkPos, CompoundTag chunkData)
|
private static LevelChunkSection[] readSections(LevelAccessor level, LevelLightEngine lightEngine, ChunkPos chunkPos, CompoundTag chunkData)
|
||||||
{
|
{
|
||||||
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
|
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
|
||||||
|
#if MC_VERSION_1_18_1
|
||||||
Codec<PalettedContainer<Biome>> biomeCodec = PalettedContainer.codec(
|
Codec<PalettedContainer<Biome>> biomeCodec = PalettedContainer.codec(
|
||||||
biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
|
biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
|
||||||
|
#elif MC_VERSION_1_18_2
|
||||||
|
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codec(
|
||||||
|
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
|
||||||
|
#endif
|
||||||
|
|
||||||
int i = level.getSectionsCount();
|
int i = level.getSectionsCount();
|
||||||
LevelChunkSection[] chunkSections = new LevelChunkSection[i];
|
LevelChunkSection[] chunkSections = new LevelChunkSection[i];
|
||||||
|
|
||||||
boolean isLightOn = chunkData.getBoolean("isLightOn");
|
boolean isLightOn = chunkData.getBoolean("isLightOn");
|
||||||
boolean hasSkyLight = level.dimensionType().hasSkyLight();
|
boolean hasSkyLight = level.dimensionType().hasSkyLight();
|
||||||
ListTag tagSections = chunkData.getList("sections", 10);
|
ListTag tagSections = chunkData.getList("sections", 10);
|
||||||
|
|
||||||
for (int j = 0; j < tagSections.size(); ++j)
|
for (int j = 0; j < tagSections.size(); ++j)
|
||||||
{
|
{
|
||||||
CompoundTag tagSection = tagSections.getCompound(j);
|
CompoundTag tagSection = tagSections.getCompound(j);
|
||||||
@@ -87,22 +99,33 @@ public class ChunkLoader
|
|||||||
if (sectionId >= 0 && sectionId < chunkSections.length)
|
if (sectionId >= 0 && sectionId < chunkSections.length)
|
||||||
{
|
{
|
||||||
PalettedContainer<BlockState> blockStateContainer;
|
PalettedContainer<BlockState> blockStateContainer;
|
||||||
|
#if MC_VERSION_1_18_1
|
||||||
PalettedContainer<Biome> biomeContainer;
|
PalettedContainer<Biome> biomeContainer;
|
||||||
|
#elif MC_VERSION_1_18_2
|
||||||
|
PalettedContainer<Holder<Biome>> biomeContainer;
|
||||||
|
#endif
|
||||||
|
|
||||||
blockStateContainer = tagSection.contains("block_states", 10)
|
blockStateContainer = tagSection.contains("block_states", 10)
|
||||||
? BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagSection.getCompound("block_states")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, LOGGER::error)
|
? BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagSection.getCompound("block_states")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, LOGGER::error)
|
||||||
: new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
: new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
||||||
|
|
||||||
|
#if MC_VERSION_1_18_1
|
||||||
biomeContainer = tagSection.contains("biomes", 10)
|
biomeContainer = tagSection.contains("biomes", 10)
|
||||||
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, LOGGER::error)
|
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, LOGGER::error)
|
||||||
: new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
: new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||||
|
#elif MC_VERSION_1_18_2
|
||||||
|
biomeContainer = tagSection.contains("biomes", 10)
|
||||||
|
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, i, (String) string)).getOrThrow(false, LOGGER::error)
|
||||||
|
: new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(), biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
|
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLightOn)
|
if (!isLightOn)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (tagSection.contains("BlockLight", 7))
|
if (tagSection.contains("BlockLight", 7))
|
||||||
lightEngine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, sectionYPos), new DataLayer(tagSection.getByteArray("BlockLight")), true);
|
lightEngine.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, sectionYPos), new DataLayer(tagSection.getByteArray("BlockLight")), true);
|
||||||
if (hasSkyLight && tagSection.contains("SkyLight", 7))
|
if (hasSkyLight && tagSection.contains("SkyLight", 7))
|
||||||
@@ -122,7 +145,8 @@ public class ChunkLoader
|
|||||||
}
|
}
|
||||||
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
|
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MC_VERSION_1_18_1
|
||||||
private static Map<StructureFeature<?>, StructureStart<?>> unpackStructureStart(StructurePieceSerializationContext structurePieceSerializationContext, CompoundTag compoundTag, long l)
|
private static Map<StructureFeature<?>, StructureStart<?>> unpackStructureStart(StructurePieceSerializationContext structurePieceSerializationContext, CompoundTag compoundTag, long l)
|
||||||
{
|
{
|
||||||
HashMap<StructureFeature<?>, StructureStart<?>> map = Maps.newHashMap();
|
HashMap<StructureFeature<?>, StructureStart<?>> map = Maps.newHashMap();
|
||||||
@@ -143,7 +167,7 @@ public class ChunkLoader
|
|||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<StructureFeature<?>, LongSet> unpackStructureReferences(ChunkPos chunkPos, CompoundTag compoundTag)
|
private static Map<StructureFeature<?>, LongSet> unpackStructureReferences(ChunkPos chunkPos, CompoundTag compoundTag)
|
||||||
{
|
{
|
||||||
HashMap<StructureFeature<?>, LongSet> map = Maps.newHashMap();
|
HashMap<StructureFeature<?>, LongSet> map = Maps.newHashMap();
|
||||||
@@ -170,13 +194,65 @@ public class ChunkLoader
|
|||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
#elif MC_VERSION_1_18_2
|
||||||
|
private static Map<ConfiguredStructureFeature<?, ?>, StructureStart> unpackStructureStart(StructurePieceSerializationContext structurePieceSerializationContext, CompoundTag compoundTag, long l) {
|
||||||
|
Map<ConfiguredStructureFeature<?, ?>, StructureStart> map = Maps.newHashMap();
|
||||||
|
Registry<ConfiguredStructureFeature<?, ?>> structStartRegistry = structurePieceSerializationContext.registryAccess().registryOrThrow(Registry.CONFIGURED_STRUCTURE_FEATURE_REGISTRY);
|
||||||
|
CompoundTag compoundTag2 = compoundTag.getCompound("starts");
|
||||||
|
for (String string : compoundTag2.getAllKeys()) {
|
||||||
|
ResourceLocation resourceLocation = ResourceLocation.tryParse(string);
|
||||||
|
ConfiguredStructureFeature<?, ?> structureFeature = structStartRegistry.get(resourceLocation);
|
||||||
|
// String string2 = string.toLowerCase(Locale.ROOT);
|
||||||
|
// ConfiguredStructureFeature<?, ?> structureFeature = StructureFeature.STRUCTURES_REGISTRY.get(string2);
|
||||||
|
if (structureFeature == null) {
|
||||||
|
LOGGER.error("Unknown structure start: {}", resourceLocation);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
StructureStart structureStart = StructureFeature.loadStaticStart(structurePieceSerializationContext, compoundTag2.getCompound(string), l);
|
||||||
|
if (structureStart == null)
|
||||||
|
continue;
|
||||||
|
map.put(structureFeature, structureStart);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<ConfiguredStructureFeature<?, ?>, LongSet> unpackStructureReferences(RegistryAccess registryAccess, ChunkPos chunkPos, CompoundTag compoundTag)
|
||||||
|
{
|
||||||
|
Map<ConfiguredStructureFeature<?, ?>, LongSet> map = Maps.newHashMap();
|
||||||
|
Registry<ConfiguredStructureFeature<?, ?>> structRegistry = registryAccess.registryOrThrow(Registry.CONFIGURED_STRUCTURE_FEATURE_REGISTRY);
|
||||||
|
CompoundTag compoundTag2 = compoundTag.getCompound("References");
|
||||||
|
for (String string : compoundTag2.getAllKeys())
|
||||||
|
{
|
||||||
|
ResourceLocation resourceLocation = ResourceLocation.tryParse(string);
|
||||||
|
ConfiguredStructureFeature<?, ?> structureFeature = structRegistry.get(resourceLocation);
|
||||||
|
// String string2 = string.toLowerCase(Locale.ROOT);
|
||||||
|
// ConfiguredStructureFeature<?, ?> structureFeature = StructureFeature.STRUCTURES_REGISTRY.get(string2);
|
||||||
|
if (structureFeature == null)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Found reference to unknown structure '{}' in chunk {}, discarding", resourceLocation, chunkPos);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
map.put(structureFeature, new LongOpenHashSet(Arrays.stream(compoundTag2.getLongArray(string)).filter(l ->
|
||||||
|
{
|
||||||
|
ChunkPos chunkPos2 = new ChunkPos(l);
|
||||||
|
if (chunkPos2.getChessboardDistance(chunkPos) > 8)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Found invalid structure reference [ {} @ {} ] for chunk {}.", resourceLocation, chunkPos2, chunkPos);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}).toArray()));
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private static void readStructures(WorldGenLevel level, LevelChunk chunk, CompoundTag chunkData)
|
private static void readStructures(WorldGenLevel level, LevelChunk chunk, CompoundTag chunkData)
|
||||||
{
|
{
|
||||||
CompoundTag tagStructures = chunkData.getCompound("structures");
|
CompoundTag tagStructures = chunkData.getCompound("structures");
|
||||||
chunk.setAllStarts(
|
chunk.setAllStarts(
|
||||||
unpackStructureStart(StructurePieceSerializationContext.fromLevel(level.getLevel()), tagStructures, level.getSeed()));
|
unpackStructureStart(StructurePieceSerializationContext.fromLevel(level.getLevel()), tagStructures, level.getSeed()));
|
||||||
chunk.setAllReferences(unpackStructureReferences(chunk.getPos(), tagStructures));
|
chunk.setAllReferences(unpackStructureReferences(#if MC_VERSION_1_18_2 level.registryAccess() ,#endif chunk.getPos(), tagStructures));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
|
private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
package com.seibel.lod.common.wrappers.worldGeneration.mimicObject;
|
package com.seibel.lod.common.wrappers.worldGeneration.mimicObject;
|
||||||
|
|
||||||
import com.seibel.lod.core.api.ModAccessorApi;
|
import com.seibel.lod.core.handlers.dependencyInjection.ModAccessorHandler;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
|
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
|
||||||
|
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
@@ -15,7 +15,7 @@ public class LightGetterAdaptor implements LightChunkGetter {
|
|||||||
|
|
||||||
public LightGetterAdaptor(BlockGetter heightAccessor) {
|
public LightGetterAdaptor(BlockGetter heightAccessor) {
|
||||||
this.heightGetter = heightAccessor;
|
this.heightGetter = heightAccessor;
|
||||||
shouldReturnNull = ModAccessorApi.get(IStarlightAccessor.class) != null;
|
shouldReturnNull = ModAccessorHandler.get(IStarlightAccessor.class) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRegion(LightedWorldGenRegion region) {
|
public void setRegion(LightedWorldGenRegion region) {
|
||||||
|
|||||||
+64
-10
@@ -2,6 +2,7 @@ package com.seibel.lod.common.wrappers.worldGeneration.mimicObject;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.seibel.lod.core.api.ApiShared;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment.EmptyChunkGenerator;
|
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment.EmptyChunkGenerator;
|
||||||
@@ -9,16 +10,24 @@ import com.seibel.lod.core.api.ClientApi;
|
|||||||
import com.seibel.lod.core.enums.config.LightGenerationMode;
|
import com.seibel.lod.core.enums.config.LightGenerationMode;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||||
|
import net.minecraft.Util;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.color.block.BlockTintCache;
|
||||||
|
import net.minecraft.client.renderer.BiomeColors;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Cursor3D;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
import net.minecraft.server.level.WorldGenRegion;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
import net.minecraft.world.level.ColorResolver;
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
import net.minecraft.world.level.LevelHeightAccessor;
|
||||||
import net.minecraft.world.level.LightLayer;
|
import net.minecraft.world.level.LightLayer;
|
||||||
import net.minecraft.world.level.StructureFeatureManager;
|
import net.minecraft.world.level.StructureFeatureManager;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
@@ -39,21 +48,25 @@ public class LightedWorldGenRegion extends WorldGenRegion {
|
|||||||
public final int size;
|
public final int size;
|
||||||
private final ChunkPos firstPos;
|
private final ChunkPos firstPos;
|
||||||
private final List<ChunkAccess> cache;
|
private final List<ChunkAccess> cache;
|
||||||
private final StructureFeatureManager structFeat;
|
|
||||||
Long2ObjectOpenHashMap<ChunkAccess> chunkMap = new Long2ObjectOpenHashMap<ChunkAccess>();
|
Long2ObjectOpenHashMap<ChunkAccess> chunkMap = new Long2ObjectOpenHashMap<ChunkAccess>();
|
||||||
|
|
||||||
public LightedWorldGenRegion(ServerLevel serverLevel, WorldGenLevelLightEngine lightEngine,
|
public LightedWorldGenRegion(ServerLevel serverLevel, WorldGenLevelLightEngine lightEngine,
|
||||||
StructureFeatureManager structFeat, List<ChunkAccess> list, ChunkStatus chunkStatus, int i,
|
List<ChunkAccess> list, ChunkStatus chunkStatus, int i,
|
||||||
LightGenerationMode lightMode, EmptyChunkGenerator generator) {
|
LightGenerationMode lightMode, EmptyChunkGenerator generator) {
|
||||||
super(serverLevel, list, chunkStatus, i);
|
super(serverLevel, list, chunkStatus, i);
|
||||||
this.lightMode = lightMode;
|
this.lightMode = lightMode;
|
||||||
this.firstPos = list.get(0).getPos();
|
this.firstPos = list.get(0).getPos();
|
||||||
this.generator = generator;
|
this.generator = generator;
|
||||||
this.structFeat = structFeat;
|
|
||||||
light = lightEngine;
|
light = lightEngine;
|
||||||
writeRadius = i;
|
writeRadius = i;
|
||||||
cache = list;
|
cache = list;
|
||||||
size = Mth.floor(Math.sqrt(list.size()));
|
size = Mth.floor(Math.sqrt(list.size()));
|
||||||
|
|
||||||
|
this.tintCaches = Util.make(new Object2ObjectArrayMap(3), object2ObjectArrayMap -> {
|
||||||
|
object2ObjectArrayMap.put(BiomeColors.GRASS_COLOR_RESOLVER, new BlockTintCache((pos) -> {return calculateBlockTint(pos, BiomeColors.GRASS_COLOR_RESOLVER);}));
|
||||||
|
object2ObjectArrayMap.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new BlockTintCache((pos) -> {return calculateBlockTint(pos, BiomeColors.FOLIAGE_COLOR_RESOLVER);}));
|
||||||
|
object2ObjectArrayMap.put(BiomeColors.WATER_COLOR_RESOLVER, new BlockTintCache((pos) -> {return calculateBlockTint(pos, BiomeColors.WATER_COLOR_RESOLVER);}));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bypass BCLib mixin overrides.
|
// Bypass BCLib mixin overrides.
|
||||||
@@ -76,12 +89,13 @@ public class LightedWorldGenRegion extends WorldGenRegion {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// TODO Check this
|
||||||
public List<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos,
|
// @Override
|
||||||
StructureFeature<?> structureFeature) {
|
// public List<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos,
|
||||||
return structFeat.startsForFeature(sectionPos, structureFeature);
|
// StructureFeature<?> structureFeature) {
|
||||||
}
|
// return structFeat.startsForFeature(sectionPos, structureFeature);
|
||||||
|
// }
|
||||||
|
|
||||||
// Skip updating the related tile entities
|
// Skip updating the related tile entities
|
||||||
@Override
|
@Override
|
||||||
@@ -183,7 +197,7 @@ public class LightedWorldGenRegion extends WorldGenRegion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chunkStatus != ChunkStatus.EMPTY && chunkStatus != debugTriggeredForStatus) {
|
if (chunkStatus != ChunkStatus.EMPTY && chunkStatus != debugTriggeredForStatus) {
|
||||||
ClientApi.LOGGER.info("WorldGen requiring " + chunkStatus
|
ApiShared.LOGGER.info("WorldGen requiring " + chunkStatus
|
||||||
+ " outside expected range detected. Force passing EMPTY chunk and seeing if it works.");
|
+ " outside expected range detected. Force passing EMPTY chunk and seeing if it works.");
|
||||||
debugTriggeredForStatus = chunkStatus;
|
debugTriggeredForStatus = chunkStatus;
|
||||||
}
|
}
|
||||||
@@ -224,4 +238,44 @@ public class LightedWorldGenRegion extends WorldGenRegion {
|
|||||||
return (getBrightness(LightLayer.SKY, blockPos) >= getMaxLightLevel());
|
return (getBrightness(LightLayer.SKY, blockPos) >= getMaxLightLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final Object2ObjectArrayMap<ColorResolver, BlockTintCache> tintCaches;
|
||||||
|
|
||||||
|
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
||||||
|
{
|
||||||
|
BlockTintCache blockTintCache = (BlockTintCache) this.tintCaches.get(colorResolver);
|
||||||
|
return blockTintCache.getColor(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Biome _getBiome(BlockPos pos) {
|
||||||
|
#if MC_VERSION_1_18_2
|
||||||
|
return getBiome(pos).value();
|
||||||
|
#elif MC_VERSION_1_18_1
|
||||||
|
return getBiome(pos);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
||||||
|
{
|
||||||
|
int i = (Minecraft.getInstance()).options.biomeBlendRadius;
|
||||||
|
if (i == 0)
|
||||||
|
return colorResolver.getColor((Biome) _getBiome(blockPos), blockPos.getX(), blockPos.getZ());
|
||||||
|
int j = (i * 2 + 1) * (i * 2 + 1);
|
||||||
|
int k = 0;
|
||||||
|
int l = 0;
|
||||||
|
int m = 0;
|
||||||
|
Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i);
|
||||||
|
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||||
|
while (cursor3D.advance())
|
||||||
|
{
|
||||||
|
mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
|
||||||
|
int n = colorResolver.getColor((Biome) _getBiome((BlockPos) mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
|
||||||
|
k += (n & 0xFF0000) >> 16;
|
||||||
|
l += (n & 0xFF00) >> 8;
|
||||||
|
m += n & 0xFF;
|
||||||
|
}
|
||||||
|
return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+4
-1
@@ -51,7 +51,9 @@ public class WorldGenStructFeatManager extends StructureFeatureManager {
|
|||||||
if (chunk == null) return false;
|
if (chunk == null) return false;
|
||||||
return chunk.hasAnyStructureReferences();
|
return chunk.hasAnyStructureReferences();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Check this
|
||||||
|
/*
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
public List<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos,
|
public List<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos,
|
||||||
@@ -76,4 +78,5 @@ public class WorldGenStructFeatManager extends StructureFeatureManager {
|
|||||||
}
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
+2
-2
@@ -4,7 +4,7 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
|
import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
|
||||||
import com.seibel.lod.core.util.GridList;
|
import com.seibel.lod.core.util.gridList.ArrayGridList;
|
||||||
|
|
||||||
import net.minecraft.ReportedException;
|
import net.minecraft.ReportedException;
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
import net.minecraft.server.level.WorldGenRegion;
|
||||||
@@ -30,7 +30,7 @@ public final class StepFeatures {
|
|||||||
public final ChunkStatus STATUS = ChunkStatus.FEATURES;
|
public final ChunkStatus STATUS = ChunkStatus.FEATURES;
|
||||||
|
|
||||||
public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion,
|
public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion,
|
||||||
GridList<ChunkAccess> chunks) {
|
ArrayGridList<ChunkAccess> chunks) {
|
||||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
|
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
|
||||||
|
|
||||||
for (ChunkAccess chunk : chunks) {
|
for (ChunkAccess chunk : chunks) {
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@ package com.seibel.lod.common.wrappers.worldGeneration.step;
|
|||||||
|
|
||||||
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.WorldGenLevelLightEngine;
|
import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.WorldGenLevelLightEngine;
|
||||||
import com.seibel.lod.core.util.GridList;
|
import com.seibel.lod.core.util.gridList.ArrayGridList;
|
||||||
|
|
||||||
import net.minecraft.server.level.ThreadedLevelLightEngine;
|
import net.minecraft.server.level.ThreadedLevelLightEngine;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
@@ -28,7 +28,7 @@ public final class StepLight {
|
|||||||
public final ChunkStatus STATUS = ChunkStatus.LIGHT;
|
public final ChunkStatus STATUS = ChunkStatus.LIGHT;
|
||||||
|
|
||||||
public void generateGroup(LightEventListener lightEngine,
|
public void generateGroup(LightEventListener lightEngine,
|
||||||
GridList<ChunkAccess> chunks) {
|
ArrayGridList<ChunkAccess> chunks) {
|
||||||
//ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
|
//ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
|
||||||
|
|
||||||
for (ChunkAccess chunk : chunks) {
|
for (ChunkAccess chunk : chunks) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
accessWidener v1 named
|
accessWidener v1 named
|
||||||
|
|
||||||
# used when determining where to save files too
|
# used when determining where to save files to
|
||||||
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
|
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
|
||||||
|
|
||||||
# used when rendering
|
# used when rendering
|
||||||
@@ -22,9 +22,10 @@ accessible field net/minecraft/world/level/lighting/LevelLightEngine skyEngine L
|
|||||||
# world generation
|
# world generation
|
||||||
accessible method net/minecraft/world/level/levelgen/Heightmap setHeight (III)V
|
accessible method net/minecraft/world/level/levelgen/Heightmap setHeight (III)V
|
||||||
accessible field net/minecraft/world/level/biome/Biome generationSettings Lnet/minecraft/world/level/biome/BiomeGenerationSettings;
|
accessible field net/minecraft/world/level/biome/Biome generationSettings Lnet/minecraft/world/level/biome/BiomeGenerationSettings;
|
||||||
accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Ljava/util/function/Supplier;
|
accessible field net/minecraft/world/level/biome/Biome biomeCategory Lnet/minecraft/world/level/biome/Biome$BiomeCategory;
|
||||||
|
# accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Lnet/minecraft/core/Holder;
|
||||||
accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doFill (Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;II)Lnet/minecraft/world/level/chunk/ChunkAccess;
|
accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doFill (Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;II)Lnet/minecraft/world/level/chunk/ChunkAccess;
|
||||||
accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doCreateBiomes (Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;)V
|
#accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doCreateBiomes (Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;)V
|
||||||
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
|
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
|
||||||
|
|
||||||
# lod generation from save file
|
# lod generation from save file
|
||||||
|
|||||||
+1
-1
Submodule core updated: 2ba7c6be6e...6cd0281d0e
@@ -19,17 +19,18 @@
|
|||||||
|
|
||||||
package com.seibel.lod.fabric;
|
package com.seibel.lod.fabric;
|
||||||
|
|
||||||
|
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.lod.core.api.ClientApi;
|
import com.seibel.lod.core.api.ClientApi;
|
||||||
import com.seibel.lod.core.api.EventApi;
|
import com.seibel.lod.core.api.EventApi;
|
||||||
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
import com.mojang.blaze3d.platform.InputConstants;
|
import com.mojang.blaze3d.platform.InputConstants;
|
||||||
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.lod.common.wrappers.world.DimensionTypeWrapper;
|
import com.seibel.lod.common.wrappers.world.DimensionTypeWrapper;
|
||||||
import com.seibel.lod.common.wrappers.world.WorldWrapper;
|
import com.seibel.lod.common.wrappers.world.WorldWrapper;
|
||||||
|
|
||||||
import com.seibel.lod.core.util.SingletonHandler;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||||
|
|
||||||
|
import com.seibel.lod.fabric.mixins.MixinUtilBackgroudThread;
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
@@ -44,6 +45,7 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
|||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
@@ -60,14 +62,13 @@ public class ClientProxy
|
|||||||
private final EventApi eventApi = EventApi.INSTANCE;
|
private final EventApi eventApi = EventApi.INSTANCE;
|
||||||
private final ClientApi clientApi = ClientApi.INSTANCE;
|
private final ClientApi clientApi = ClientApi.INSTANCE;
|
||||||
|
|
||||||
|
public static Supplier<Boolean> isGenerationThreadChecker = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers Fabric Events
|
* Registers Fabric Events
|
||||||
* @author Ran
|
* @author Ran
|
||||||
*/
|
*/
|
||||||
public void registerEvents() {
|
public void registerEvents() {
|
||||||
// TODO: Fix this if it's wrong
|
|
||||||
|
|
||||||
/* Registor the mod accessor*/
|
/* Registor the mod accessor*/
|
||||||
|
|
||||||
/* World Events */
|
/* World Events */
|
||||||
@@ -91,6 +92,8 @@ public class ClientProxy
|
|||||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||||
if (client.player != null) onKeyInput();
|
if (client.player != null) onKeyInput();
|
||||||
});
|
});
|
||||||
|
isGenerationThreadChecker = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,18 +21,20 @@ package com.seibel.lod.fabric;
|
|||||||
|
|
||||||
import com.seibel.lod.common.LodCommonMain;
|
import com.seibel.lod.common.LodCommonMain;
|
||||||
import com.seibel.lod.core.ModInfo;
|
import com.seibel.lod.core.ModInfo;
|
||||||
|
import com.seibel.lod.core.api.ApiShared;
|
||||||
import com.seibel.lod.core.api.ClientApi;
|
import com.seibel.lod.core.api.ClientApi;
|
||||||
import com.seibel.lod.core.api.ModAccessorApi;
|
import com.seibel.lod.core.handlers.dependencyInjection.ModAccessorHandler;
|
||||||
import com.seibel.lod.core.util.SingletonHandler;
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IModChecker;
|
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
|
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
|
||||||
|
import com.seibel.lod.fabric.networking.NetworkHandler;
|
||||||
import com.seibel.lod.fabric.wrappers.modAccessor.ModChecker;
|
import com.seibel.lod.fabric.wrappers.modAccessor.ModChecker;
|
||||||
import com.seibel.lod.fabric.wrappers.modAccessor.OptifineAccessor;
|
import com.seibel.lod.fabric.wrappers.modAccessor.OptifineAccessor;
|
||||||
import com.seibel.lod.fabric.wrappers.modAccessor.SodiumAccessor;
|
import com.seibel.lod.fabric.wrappers.modAccessor.SodiumAccessor;
|
||||||
import com.seibel.lod.fabric.wrappers.modAccessor.StarlightAccessor;
|
import com.seibel.lod.fabric.wrappers.modAccessor.StarlightAccessor;
|
||||||
import com.seibel.lod.fabric.wrappers.DependencySetup;
|
import com.seibel.lod.fabric.wrappers.FabricDependencySetup;
|
||||||
|
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
|
|
||||||
@@ -63,29 +65,32 @@ public class Main implements ClientModInitializer
|
|||||||
// This loads the mod after minecraft loads which doesn't causes a lot of issues
|
// This loads the mod after minecraft loads which doesn't causes a lot of issues
|
||||||
public static void init() {
|
public static void init() {
|
||||||
LodCommonMain.initConfig();
|
LodCommonMain.initConfig();
|
||||||
LodCommonMain.startup(null, false);
|
LodCommonMain.startup(null, false, new NetworkHandler());
|
||||||
DependencySetup.createInitialBindings();
|
FabricDependencySetup.createInitialBindings();
|
||||||
SingletonHandler.bind(IModChecker.class, ModChecker.INSTANCE);
|
FabricDependencySetup.finishBinding();
|
||||||
ClientApi.LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
|
ApiShared.LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
|
||||||
|
|
||||||
// Check if this works
|
// Check if this works
|
||||||
client_proxy = new ClientProxy();
|
client_proxy = new ClientProxy();
|
||||||
client_proxy.registerEvents();
|
client_proxy.registerEvents();
|
||||||
if (SingletonHandler.get(IModChecker.class).isModLoaded("sodium")) {
|
if (SingletonHandler.get(IModChecker.class).isModLoaded("sodium")) {
|
||||||
ModAccessorApi.bind(ISodiumAccessor.class, new SodiumAccessor());
|
ModAccessorHandler.bind(ISodiumAccessor.class, new SodiumAccessor());
|
||||||
}
|
}
|
||||||
if (SingletonHandler.get(IModChecker.class).isModLoaded("starlight")) {
|
if (SingletonHandler.get(IModChecker.class).isModLoaded("starlight")) {
|
||||||
ModAccessorApi.bind(IStarlightAccessor.class, new StarlightAccessor());
|
ModAccessorHandler.bind(IStarlightAccessor.class, new StarlightAccessor());
|
||||||
}
|
}
|
||||||
if (SingletonHandler.get(IModChecker.class).isModLoaded("optifine")) {
|
if (SingletonHandler.get(IModChecker.class).isModLoaded("optifine")) {
|
||||||
ModAccessorApi.bind(IOptifineAccessor.class, new OptifineAccessor());
|
ModAccessorHandler.bind(IOptifineAccessor.class, new OptifineAccessor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModAccessorHandler.finishBinding();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void initServer() {
|
public static void initServer() {
|
||||||
LodCommonMain.initConfig();
|
LodCommonMain.initConfig();
|
||||||
LodCommonMain.startup(null, true);
|
LodCommonMain.startup(null, true, new NetworkHandler());
|
||||||
DependencySetup.createInitialBindings();
|
FabricDependencySetup.createInitialBindings();
|
||||||
ClientApi.LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
|
FabricDependencySetup.finishBinding();
|
||||||
|
ApiShared.LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.seibel.lod.fabric.mixins;
|
||||||
|
|
||||||
|
import com.seibel.lod.fabric.Main;
|
||||||
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(DedicatedServer.class)
|
||||||
|
public class MixinDedicatedServer {
|
||||||
|
@Inject(method = "initServer", at = @At("TAIL"))
|
||||||
|
public void initServer(CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
Main.initServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import com.seibel.lod.core.util.SingletonHandler;
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||||
|
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package com.seibel.lod.fabric.mixins;
|
|||||||
import com.seibel.lod.common.wrappers.config.ConfigGui;
|
import com.seibel.lod.common.wrappers.config.ConfigGui;
|
||||||
import com.seibel.lod.common.wrappers.config.TexturedButtonWidget;
|
import com.seibel.lod.common.wrappers.config.TexturedButtonWidget;
|
||||||
import com.seibel.lod.core.ModInfo;
|
import com.seibel.lod.core.ModInfo;
|
||||||
import com.seibel.lod.core.util.SingletonHandler;
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||||
import net.minecraft.client.gui.screens.OptionsScreen;
|
import net.minecraft.client.gui.screens.OptionsScreen;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
|||||||
@@ -3,14 +3,12 @@ package com.seibel.lod.fabric.mixins;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import com.seibel.lod.fabric.ClientProxy;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import com.seibel.lod.common.wrappers.DependencySetupDoneCheck;
|
|
||||||
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
|
||||||
import com.seibel.lod.core.api.ClientApi;
|
|
||||||
import com.seibel.lod.core.util.DummyRunExecutorService;
|
import com.seibel.lod.core.util.DummyRunExecutorService;
|
||||||
|
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
@@ -23,9 +21,9 @@ public class MixinUtilBackgroudThread
|
|||||||
at = @At("HEAD"), cancellable = true)
|
at = @At("HEAD"), cancellable = true)
|
||||||
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable<Runnable> ci)
|
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable<Runnable> ci)
|
||||||
{
|
{
|
||||||
if (DependencySetupDoneCheck.isDone && BatchGenerationEnvironment.isCurrentThreadDistantGeneratorThread())
|
if (ClientProxy.isGenerationThreadChecker != null && ClientProxy.isGenerationThreadChecker.get())
|
||||||
{
|
{
|
||||||
//ClientApi.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
|
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
|
||||||
ci.setReturnValue(r);
|
ci.setReturnValue(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,9 +31,9 @@ public class MixinUtilBackgroudThread
|
|||||||
at = @At("HEAD"), cancellable = true)
|
at = @At("HEAD"), cancellable = true)
|
||||||
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
|
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
|
||||||
{
|
{
|
||||||
if (DependencySetupDoneCheck.isDone && BatchGenerationEnvironment.isCurrentThreadDistantGeneratorThread())
|
if (ClientProxy.isGenerationThreadChecker != null && ClientProxy.isGenerationThreadChecker.get())
|
||||||
{
|
{
|
||||||
//ClientApi.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
|
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
|
||||||
ci.setReturnValue(r);
|
ci.setReturnValue(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,9 +41,9 @@ public class MixinUtilBackgroudThread
|
|||||||
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
|
||||||
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
|
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
|
||||||
{
|
{
|
||||||
if (DependencySetupDoneCheck.isDone && BatchGenerationEnvironment.isCurrentThreadDistantGeneratorThread())
|
if (ClientProxy.isGenerationThreadChecker != null && ClientProxy.isGenerationThreadChecker.get())
|
||||||
{
|
{
|
||||||
//ClientApi.LOGGER.info("util backgroundExecutor triggered");
|
//ApiShared.LOGGER.info("util backgroundExecutor triggered");
|
||||||
ci.setReturnValue(new DummyRunExecutorService());
|
ci.setReturnValue(new DummyRunExecutorService());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.mojang.math.Matrix4f;
|
|||||||
import com.seibel.lod.common.wrappers.McObjectConverter;
|
import com.seibel.lod.common.wrappers.McObjectConverter;
|
||||||
import com.seibel.lod.core.api.ClientApi;
|
import com.seibel.lod.core.api.ClientApi;
|
||||||
import com.seibel.lod.core.objects.math.Mat4f;
|
import com.seibel.lod.core.objects.math.Mat4f;
|
||||||
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.client.renderer.LevelRenderer;
|
import net.minecraft.client.renderer.LevelRenderer;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@@ -61,7 +62,25 @@ public class MixinWorldRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HEAD or RETURN
|
// HEAD or RETURN
|
||||||
@Inject(at = @At("HEAD"), method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLcom/mojang/math/Matrix4f;)V")
|
@Inject(at = @At("RETURN"),
|
||||||
|
method = "renderSky",
|
||||||
|
cancellable = true)
|
||||||
|
private void renderLod(PoseStack modelViewMatrixStack, Matrix4f projectionMatrix, float f,
|
||||||
|
#if MC_VERSION_1_18_2 Camera camera, boolean bl,#endif Runnable r, CallbackInfo callback) {
|
||||||
|
|
||||||
|
Mat4f mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose());
|
||||||
|
Mat4f mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
|
||||||
|
|
||||||
|
ClientApi.INSTANCE.renderLods(mcModelViewMatrix, mcProjectionMatrix, previousPartialTicks);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
// HEAD or RETURN
|
||||||
|
@Inject(at = @At("HEAD"),
|
||||||
|
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLcom/mojang/math/Matrix4f;)V",
|
||||||
|
cancellable = true)
|
||||||
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
|
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
|
||||||
{
|
{
|
||||||
// only render before solid blocks
|
// only render before solid blocks
|
||||||
@@ -72,5 +91,6 @@ public class MixinWorldRenderer
|
|||||||
|
|
||||||
ClientApi.INSTANCE.renderLods(mcModelViewMatrix, mcProjectionMatrix, previousPartialTicks);
|
ClientApi.INSTANCE.renderLods(mcModelViewMatrix, mcProjectionMatrix, previousPartialTicks);
|
||||||
}
|
}
|
||||||
}
|
//callback.cancel();
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import com.seibel.lod.fabric.Main;
|
|||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||||
import net.minecraft.client.renderer.LevelRenderer;
|
import net.minecraft.client.renderer.LevelRenderer;
|
||||||
|
#if MC_VERSION_1_18_2
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
#endif
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
@@ -18,12 +21,21 @@ import java.util.function.Supplier;
|
|||||||
* This class is used for world loading events
|
* This class is used for world loading events
|
||||||
* @author Ran
|
* @author Ran
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Mixin(ClientLevel.class)
|
@Mixin(ClientLevel.class)
|
||||||
public class MixinClientLevel {
|
public class MixinClientLevel {
|
||||||
|
#if MC_VERSION_1_18_2
|
||||||
|
@Inject(method = "<init>", at = @At("TAIL"))
|
||||||
|
private void loadWorldEvent(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData, ResourceKey resourceKey, Holder holder, int i, int j, Supplier supplier, LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci) {
|
||||||
|
Main.client_proxy.worldLoadEvent((ClientLevel) (Object) this);
|
||||||
|
}
|
||||||
|
#elif MC_VERSION_1_18_1
|
||||||
@Inject(method = "<init>", at = @At("TAIL"))
|
@Inject(method = "<init>", at = @At("TAIL"))
|
||||||
private void loadWorldEvent(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData, ResourceKey resourceKey, DimensionType dimensionType, int i, int j, Supplier supplier, LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci) {
|
private void loadWorldEvent(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData, ResourceKey resourceKey, DimensionType dimensionType, int i, int j, Supplier supplier, LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci) {
|
||||||
Main.client_proxy.worldLoadEvent((ClientLevel) (Object) this);
|
Main.client_proxy.worldLoadEvent((ClientLevel) (Object) this);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
@Inject(method = "setLightReady", at = @At("HEAD"))
|
@Inject(method = "setLightReady", at = @At("HEAD"))
|
||||||
private void onChunkLightReady(int x, int z, CallbackInfo ci) {
|
private void onChunkLightReady(int x, int z, CallbackInfo ci) {
|
||||||
ClientLevel l = (ClientLevel) (Object) this;
|
ClientLevel l = (ClientLevel) (Object) this;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.seibel.lod.fabric.networking;
|
||||||
|
|
||||||
|
import com.seibel.lod.common.networking.NetworkInterface;
|
||||||
|
import com.seibel.lod.common.networking.Networking;
|
||||||
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ran
|
||||||
|
*/
|
||||||
|
public class NetworkHandler implements NetworkInterface {
|
||||||
|
@Override
|
||||||
|
public void register_Client() {
|
||||||
|
ClientPlayNetworking.registerGlobalReceiver(Networking.resourceLocation_meow, (client, handler, buf, responseSender) -> {
|
||||||
|
com.seibel.lod.common.networking.NetworkHandler.receivePacketClient(client, handler, buf);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void register_Server() {
|
||||||
|
ServerPlayNetworking.registerGlobalReceiver(Networking.resourceLocation_meow, (server, player, handler, buf, responseSender) -> {
|
||||||
|
com.seibel.lod.common.networking.NetworkHandler.receivePacketServer(server, player, handler, buf);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package com.seibel.lod.fabric.wrappers;
|
|
||||||
|
|
||||||
import com.seibel.lod.common.LodCommonMain;
|
|
||||||
import com.seibel.lod.common.wrappers.config.NewLodConfigWrapperSingleton;
|
|
||||||
import com.seibel.lod.core.util.SingletonHandler;
|
|
||||||
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
|
||||||
import com.seibel.lod.common.wrappers.config.LodConfigWrapperSingleton;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds all necessary dependencies, so we
|
|
||||||
* can access them in Core. <br>
|
|
||||||
* This needs to be called before any Core classes
|
|
||||||
* are loaded.
|
|
||||||
*
|
|
||||||
* @author James Seibel
|
|
||||||
* @author Ran
|
|
||||||
* @version 12-1-2021
|
|
||||||
*/
|
|
||||||
public class DependencySetup
|
|
||||||
{
|
|
||||||
public static void createInitialBindings()
|
|
||||||
{
|
|
||||||
if (!LodCommonMain.IsNewConfig)
|
|
||||||
SingletonHandler.bind(ILodConfigWrapperSingleton.class, LodConfigWrapperSingleton.INSTANCE);
|
|
||||||
else
|
|
||||||
SingletonHandler.bind(ILodConfigWrapperSingleton.class, NewLodConfigWrapperSingleton.INSTANCE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.seibel.lod.fabric.wrappers;
|
||||||
|
|
||||||
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
|
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
|
||||||
|
import com.seibel.lod.common.wrappers.config.LodConfigWrapperSingleton;
|
||||||
|
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||||
|
import com.seibel.lod.fabric.wrappers.modAccessor.ModChecker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds all necessary dependencies, so we
|
||||||
|
* can access them in Core. <br>
|
||||||
|
* This needs to be called before any Core classes
|
||||||
|
* are loaded.
|
||||||
|
*
|
||||||
|
* @author James Seibel
|
||||||
|
* @author Ran
|
||||||
|
* @version 3-5-2022
|
||||||
|
*/
|
||||||
|
public class FabricDependencySetup
|
||||||
|
{
|
||||||
|
public static void createInitialBindings()
|
||||||
|
{
|
||||||
|
SingletonHandler.bind(IModChecker.class, ModChecker.INSTANCE);
|
||||||
|
|
||||||
|
SingletonHandler.bind(ILodConfigWrapperSingleton.class, LodConfigWrapperSingleton.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void finishBinding() {
|
||||||
|
SingletonHandler.finishBinding();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ package com.seibel.lod.fabric.wrappers.modAccessor;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.seibel.lod.core.util.SingletonHandler;
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
||||||
|
|||||||
@@ -17,7 +17,9 @@
|
|||||||
"events.MixinMinecraft",
|
"events.MixinMinecraft",
|
||||||
"events.MixinBlockUpdate"
|
"events.MixinBlockUpdate"
|
||||||
],
|
],
|
||||||
"server": [],
|
"server": [
|
||||||
|
"MixinDedicatedServer"
|
||||||
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,8 @@
|
|||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": "*",
|
"fabricloader": "*",
|
||||||
"fabric": "*",
|
"fabric": "*",
|
||||||
"minecraft": "1.18.x",
|
"minecraft": "${minecraft_version}",
|
||||||
"java": ">=17"
|
"java": ">=${java_version}"
|
||||||
},
|
},
|
||||||
"suggests": {
|
"suggests": {
|
||||||
"another-mod": "*"
|
"another-mod": "*"
|
||||||
|
|||||||
@@ -22,14 +22,15 @@ package com.seibel.lod.forge;
|
|||||||
import com.seibel.lod.common.LodCommonMain;
|
import com.seibel.lod.common.LodCommonMain;
|
||||||
import com.seibel.lod.common.forge.LodForgeMethodCaller;
|
import com.seibel.lod.common.forge.LodForgeMethodCaller;
|
||||||
import com.seibel.lod.common.wrappers.config.ConfigGui;
|
import com.seibel.lod.common.wrappers.config.ConfigGui;
|
||||||
import com.seibel.lod.common.wrappers.minecraft.MinecraftWrapper;
|
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
|
||||||
import com.seibel.lod.core.ModInfo;
|
import com.seibel.lod.core.ModInfo;
|
||||||
import com.seibel.lod.core.api.ClientApi;
|
import com.seibel.lod.core.api.ApiShared;
|
||||||
import com.seibel.lod.core.api.ModAccessorApi;
|
|
||||||
import com.seibel.lod.core.handlers.ReflectionHandler;
|
import com.seibel.lod.core.handlers.ReflectionHandler;
|
||||||
import com.seibel.lod.core.util.SingletonHandler;
|
import com.seibel.lod.core.handlers.dependencyInjection.ModAccessorHandler;
|
||||||
|
import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IModChecker;
|
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||||
|
import com.seibel.lod.forge.networking.NetworkHandler;
|
||||||
import com.seibel.lod.forge.wrappers.ForgeDependencySetup;
|
import com.seibel.lod.forge.wrappers.ForgeDependencySetup;
|
||||||
|
|
||||||
import com.seibel.lod.forge.wrappers.modAccessor.ModChecker;
|
import com.seibel.lod.forge.wrappers.modAccessor.ModChecker;
|
||||||
@@ -42,14 +43,12 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||||||
import net.minecraftforge.client.model.data.ModelDataMap;
|
import net.minecraftforge.client.model.data.ModelDataMap;
|
||||||
import net.minecraftforge.client.ConfigGuiHandler;
|
import net.minecraftforge.client.ConfigGuiHandler;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.fml.ModList;
|
|
||||||
import net.minecraftforge.fml.ModLoadingContext;
|
import net.minecraftforge.fml.ModLoadingContext;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||||
import net.minecraftforge.fml.loading.FMLLoader;
|
import net.minecraftforge.fml.loading.FMLLoader;
|
||||||
import net.minecraftforge.forgespi.language.IModInfo;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
@@ -71,29 +70,27 @@ public class ForgeMain implements LodForgeMethodCaller
|
|||||||
{
|
{
|
||||||
// make sure the dependencies are set up before the mod needs them
|
// make sure the dependencies are set up before the mod needs them
|
||||||
LodCommonMain.initConfig();
|
LodCommonMain.initConfig();
|
||||||
LodCommonMain.startup(this, !FMLLoader.getDist().isClient());
|
LodCommonMain.startup(this, !FMLLoader.getDist().isClient(), new NetworkHandler());
|
||||||
ForgeDependencySetup.createInitialBindings();
|
ForgeDependencySetup.createInitialBindings();
|
||||||
ClientApi.LOGGER.info("Distant Horizons initializing...");
|
ForgeDependencySetup.finishBinding();
|
||||||
SingletonHandler.bind(IModChecker.class, ModChecker.INSTANCE);
|
ApiShared.LOGGER.info("Distant Horizons initializing...");
|
||||||
|
|
||||||
if (ReflectionHandler.instance.optifinePresent()) {
|
|
||||||
ModAccessorApi.bind(IOptifineAccessor.class, new OptifineAccessor());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ForgeMain()
|
public ForgeMain()
|
||||||
{
|
{
|
||||||
// Register the methods
|
// Register the methods for server and other game events we are interested in
|
||||||
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::init);
|
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::init);
|
||||||
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientStart);
|
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientStart);
|
||||||
|
|
||||||
// Register ourselves for server and other game events we are interested in
|
|
||||||
MinecraftForge.EVENT_BUS.register(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onClientStart(final FMLClientSetupEvent event)
|
private void onClientStart(final FMLClientSetupEvent event)
|
||||||
{
|
{
|
||||||
|
if (ReflectionHandler.instance.optifinePresent()) {
|
||||||
|
ModAccessorHandler.bind(IOptifineAccessor.class, new OptifineAccessor());
|
||||||
|
}
|
||||||
|
|
||||||
|
ModAccessorHandler.finishBinding();
|
||||||
|
|
||||||
ModLoadingContext.get().registerExtensionPoint(ConfigGuiHandler.ConfigGuiFactory.class,
|
ModLoadingContext.get().registerExtensionPoint(ConfigGuiHandler.ConfigGuiFactory.class,
|
||||||
() -> new ConfigGuiHandler.ConfigGuiFactory((client, parent) -> ConfigGui.getScreen(parent, "")));
|
() -> new ConfigGuiHandler.ConfigGuiFactory((client, parent) -> ConfigGui.getScreen(parent, "")));
|
||||||
forgeClientProxy = new ForgeClientProxy();
|
forgeClientProxy = new ForgeClientProxy();
|
||||||
@@ -102,7 +99,7 @@ public class ForgeMain implements LodForgeMethodCaller
|
|||||||
|
|
||||||
private final ModelDataMap dataMap = new ModelDataMap.Builder().build();
|
private final ModelDataMap dataMap = new ModelDataMap.Builder().build();
|
||||||
@Override
|
@Override
|
||||||
public List<BakedQuad> getQuads(MinecraftWrapper mc, Block block, BlockState blockState, Direction direction, Random random) {
|
public List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, Random random) {
|
||||||
return mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random, dataMap);
|
return mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random, dataMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.client.networking.v1;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.Event;
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.EventFactory;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.PacketSender;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offers access to events related to the indication of a connected server's ability to receive packets in certain channels.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class C2SPlayChannelEvents {
|
||||||
|
/**
|
||||||
|
* An event for the client play network handler receiving an update indicating the connected server's ability to receive packets in certain channels.
|
||||||
|
* This event may be invoked at any time after login and up to disconnection.
|
||||||
|
*/
|
||||||
|
public static final Event<Register> REGISTER = EventFactory.createArrayBacked(Register.class, callbacks -> (handler, sender, client, channels) -> {
|
||||||
|
for (Register callback : callbacks) {
|
||||||
|
callback.onChannelRegister(handler, sender, client, channels);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event for the client play network handler receiving an update indicating the connected server's lack of ability to receive packets in certain channels.
|
||||||
|
* This event may be invoked at any time after login and up to disconnection.
|
||||||
|
*/
|
||||||
|
public static final Event<Unregister> UNREGISTER = EventFactory.createArrayBacked(Unregister.class, callbacks -> (handler, sender, client, channels) -> {
|
||||||
|
for (Unregister callback : callbacks) {
|
||||||
|
callback.onChannelUnregister(handler, sender, client, channels);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private C2SPlayChannelEvents() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see C2SPlayChannelEvents#REGISTER
|
||||||
|
*/
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Register {
|
||||||
|
void onChannelRegister(ClientPacketListener handler, PacketSender sender, Minecraft client, List<ResourceLocation> channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see C2SPlayChannelEvents#UNREGISTER
|
||||||
|
*/
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Unregister {
|
||||||
|
void onChannelUnregister(ClientPacketListener handler, PacketSender sender, Minecraft client, List<ResourceLocation> channels);
|
||||||
|
}
|
||||||
|
}
|
||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.client.networking.v1;
|
||||||
|
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.Event;
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.EventFactory;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.ClientHandshakePacketListenerImpl;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offers access to events related to the connection to a server on the client while the server is processing the client's login request.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class ClientLoginConnectionEvents {
|
||||||
|
/**
|
||||||
|
* Event indicating a connection entered the LOGIN state, ready for registering query request handlers.
|
||||||
|
* This event may be used by mods to prepare their client side state.
|
||||||
|
* This event does not guarantee that a login attempt will be successful.
|
||||||
|
*
|
||||||
|
* @see ClientLoginNetworking#registerReceiver(ResourceLocation, ClientLoginNetworking.LoginQueryRequestHandler)
|
||||||
|
*/
|
||||||
|
public static final Event<Init> INIT = EventFactory.createArrayBacked(Init.class, callbacks -> (handler, client) -> {
|
||||||
|
for (Init callback : callbacks) {
|
||||||
|
callback.onLoginStart(handler, client);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event for when the client has started receiving login queries.
|
||||||
|
* A client can only start receiving login queries when a server has sent the first login query.
|
||||||
|
* Vanilla servers will typically never make the client enter this login phase, but it is not a guarantee that the
|
||||||
|
* connected server is a vanilla server since a modded server or proxy may have no login queries to send to the client
|
||||||
|
* and therefore bypass the login query phase.
|
||||||
|
* If this event is fired then it is a sign that a server is not a vanilla server or the server is behind a proxy which
|
||||||
|
* is capable of handling login queries.
|
||||||
|
*
|
||||||
|
* <p>This event may be used to {@link ClientLoginNetworking.LoginQueryRequestHandler register login query handlers}
|
||||||
|
* which may be used to send a response to a server.
|
||||||
|
*
|
||||||
|
* <p>No packets should be sent when this event is invoked.
|
||||||
|
*/
|
||||||
|
public static final Event<QueryStart> QUERY_START = EventFactory.createArrayBacked(QueryStart.class, callbacks -> (handler, client) -> {
|
||||||
|
for (QueryStart callback : callbacks) {
|
||||||
|
callback.onLoginQueryStart(handler, client);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event for when the client's login process has ended due to disconnection.
|
||||||
|
*
|
||||||
|
* <p>No packets should be sent when this event is invoked.
|
||||||
|
*/
|
||||||
|
public static final Event<Disconnect> DISCONNECT = EventFactory.createArrayBacked(Disconnect.class, callbacks -> (handler, client) -> {
|
||||||
|
for (Disconnect callback : callbacks) {
|
||||||
|
callback.onLoginDisconnect(handler, client);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private ClientLoginConnectionEvents() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ClientLoginConnectionEvents#INIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Init {
|
||||||
|
void onLoginStart(ClientHandshakePacketListenerImpl handler, Minecraft client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ClientLoginConnectionEvents#QUERY_START
|
||||||
|
*/
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface QueryStart {
|
||||||
|
void onLoginQueryStart(ClientHandshakePacketListenerImpl handler, Minecraft client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ClientLoginConnectionEvents#DISCONNECT
|
||||||
|
*/
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Disconnect {
|
||||||
|
void onLoginDisconnect(ClientHandshakePacketListenerImpl handler, Minecraft client);
|
||||||
|
}
|
||||||
|
}
|
||||||
+161
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.client.networking.v1;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import io.netty.util.concurrent.Future;
|
||||||
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.ServerLoginNetworking;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.client.ClientNetworkingImpl;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.ClientHandshakePacketListenerImpl;
|
||||||
|
import net.minecraft.network.Connection;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.PacketListener;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offers access to login stage client-side networking functionalities.
|
||||||
|
*
|
||||||
|
* <p>The Minecraft login protocol only allows the client to respond to a server's request, but not initiate one of its own.
|
||||||
|
*
|
||||||
|
* @see ClientPlayNetworking
|
||||||
|
* @see ServerLoginNetworking
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class ClientLoginNetworking {
|
||||||
|
/**
|
||||||
|
* Registers a handler to a query request channel.
|
||||||
|
* A global receiver is registered to all connections, in the present and future.
|
||||||
|
*
|
||||||
|
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
|
||||||
|
* Use {@link #unregisterGlobalReceiver(ResourceLocation)} to unregister the existing handler.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @param queryHandler the handler
|
||||||
|
* @return false if a handler is already registered to the channel
|
||||||
|
* @see ClientLoginNetworking#unregisterGlobalReceiver(ResourceLocation)
|
||||||
|
* @see ClientLoginNetworking#registerReceiver(ResourceLocation, LoginQueryRequestHandler)
|
||||||
|
*/
|
||||||
|
public static boolean registerGlobalReceiver(ResourceLocation channelName, LoginQueryRequestHandler queryHandler) {
|
||||||
|
return ClientNetworkingImpl.LOGIN.registerGlobalReceiver(channelName, queryHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the handler of a query request channel.
|
||||||
|
* A global receiver is registered to all connections, in the present and future.
|
||||||
|
*
|
||||||
|
* <p>The {@code channel} is guaranteed not to have a handler after this call.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @return the previous handler, or {@code null} if no handler was bound to the channel
|
||||||
|
* @see ClientLoginNetworking#registerGlobalReceiver(ResourceLocation, LoginQueryRequestHandler)
|
||||||
|
* @see ClientLoginNetworking#unregisterReceiver(ResourceLocation)
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static ClientLoginNetworking.LoginQueryRequestHandler unregisterGlobalReceiver(ResourceLocation channelName) {
|
||||||
|
return ClientNetworkingImpl.LOGIN.unregisterGlobalReceiver(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all query request channel names which global receivers are registered for.
|
||||||
|
* A global receiver is registered to all connections, in the present and future.
|
||||||
|
*
|
||||||
|
* @return all channel names which global receivers are registered for.
|
||||||
|
*/
|
||||||
|
public static Set<ResourceLocation> getGlobalReceivers() {
|
||||||
|
return ClientNetworkingImpl.LOGIN.getChannels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a handler to a query request channel.
|
||||||
|
*
|
||||||
|
* <p>If a handler is already registered to the {@code channelName}, this method will return {@code false}, and no change will be made.
|
||||||
|
* Use {@link #unregisterReceiver(ResourceLocation)} to unregister the existing handler.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @param queryHandler the handler
|
||||||
|
* @return false if a handler is already registered to the channel name
|
||||||
|
* @throws IllegalStateException if the client is not logging in
|
||||||
|
*/
|
||||||
|
public static boolean registerReceiver(ResourceLocation channelName, LoginQueryRequestHandler queryHandler) throws IllegalStateException {
|
||||||
|
final Connection connection = ClientNetworkingImpl.getLoginConnection();
|
||||||
|
|
||||||
|
if (connection != null) {
|
||||||
|
final PacketListener packetListener = connection.getPacketListener();
|
||||||
|
|
||||||
|
if (packetListener instanceof ClientHandshakePacketListenerImpl) {
|
||||||
|
return ClientNetworkingImpl.getAddon(((ClientHandshakePacketListenerImpl) packetListener)).registerChannel(channelName, queryHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Cannot register receiver while client is not logging in!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the handler of a query request channel.
|
||||||
|
*
|
||||||
|
* <p>The {@code channelName} is guaranteed not to have a handler after this call.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @return the previous handler, or {@code null} if no handler was bound to the channel name
|
||||||
|
* @throws IllegalStateException if the client is not logging in
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static LoginQueryRequestHandler unregisterReceiver(ResourceLocation channelName) throws IllegalStateException {
|
||||||
|
final Connection connection = ClientNetworkingImpl.getLoginConnection();
|
||||||
|
|
||||||
|
if (connection != null) {
|
||||||
|
final PacketListener packetListener = connection.getPacketListener();
|
||||||
|
|
||||||
|
if (packetListener instanceof ClientHandshakePacketListenerImpl) {
|
||||||
|
return ClientNetworkingImpl.getAddon(((ClientHandshakePacketListenerImpl) packetListener)).unregisterChannel(channelName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Cannot unregister receiver while client is not logging in!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientLoginNetworking() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface LoginQueryRequestHandler {
|
||||||
|
/**
|
||||||
|
* Handles an incoming query request from a server.
|
||||||
|
*
|
||||||
|
* <p>This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}.
|
||||||
|
* Modification to the game should be {@linkplain net.minecraft.util.thread.BlockableEventLoop#submit(Runnable) scheduled} using the provided Minecraft client instance.
|
||||||
|
*
|
||||||
|
* <p>The return value of this method is a completable future that may be used to delay the login process to the server until a task {@link CompletableFuture#isDone() is done}.
|
||||||
|
* The future should complete in reasonably time to prevent disconnection by the server.
|
||||||
|
* If your request processes instantly, you may use {@link CompletableFuture#completedFuture(Object)} to wrap your response for immediate sending.
|
||||||
|
*
|
||||||
|
* @param client the client
|
||||||
|
* @param handler the network handler that received this packet
|
||||||
|
* @param buf the payload of the packet
|
||||||
|
* @param listenerAdder listeners to be called when the response packet is sent to the server
|
||||||
|
* @return a completable future which contains the payload to respond to the server with.
|
||||||
|
* If the future contains {@code null}, then the server will be notified that the client did not understand the query.
|
||||||
|
*/
|
||||||
|
CompletableFuture<@Nullable FriendlyByteBuf> receive(Minecraft client, ClientHandshakePacketListenerImpl handler, FriendlyByteBuf buf, Consumer<GenericFutureListener<? extends Future<? super Void>>> listenerAdder);
|
||||||
|
}
|
||||||
|
}
|
||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.client.networking.v1;
|
||||||
|
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.Event;
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.EventFactory;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.PacketSender;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offers access to events related to the connection to a server on a logical client.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class ClientPlayConnectionEvents {
|
||||||
|
/**
|
||||||
|
* Event indicating a connection entered the PLAY state, ready for registering channel handlers.
|
||||||
|
*
|
||||||
|
* @see ClientPlayNetworking#registerReceiver(ResourceLocation, ClientPlayNetworking.PlayChannelHandler)
|
||||||
|
*/
|
||||||
|
public static final Event<Init> INIT = EventFactory.createArrayBacked(Init.class, callbacks -> (handler, client) -> {
|
||||||
|
for (Init callback : callbacks) {
|
||||||
|
callback.onPlayInit(handler, client);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event for notification when the client play network handler is ready to send packets to the server.
|
||||||
|
*
|
||||||
|
* <p>At this stage, the network handler is ready to send packets to the server.
|
||||||
|
* Since the client's local state has been setup.
|
||||||
|
*/
|
||||||
|
public static final Event<Join> JOIN = EventFactory.createArrayBacked(Join.class, callbacks -> (handler, sender, client) -> {
|
||||||
|
for (Join callback : callbacks) {
|
||||||
|
callback.onPlayReady(handler, sender, client);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event for the disconnection of the client play network handler.
|
||||||
|
*
|
||||||
|
* <p>No packets should be sent when this event is invoked.
|
||||||
|
*/
|
||||||
|
public static final Event<Disconnect> DISCONNECT = EventFactory.createArrayBacked(Disconnect.class, callbacks -> (handler, client) -> {
|
||||||
|
for (Disconnect callback : callbacks) {
|
||||||
|
callback.onPlayDisconnect(handler, client);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private ClientPlayConnectionEvents() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Init {
|
||||||
|
void onPlayInit(ClientPacketListener handler, Minecraft client);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Join {
|
||||||
|
void onPlayReady(ClientPacketListener handler, PacketSender sender, Minecraft client);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Disconnect {
|
||||||
|
void onPlayDisconnect(ClientPacketListener handler, Minecraft client);
|
||||||
|
}
|
||||||
|
}
|
||||||
+256
@@ -0,0 +1,256 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.client.networking.v1;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.PacketSender;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.ServerPlayNetworking;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.client.ClientNetworkingImpl;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.client.ClientPlayNetworkAddon;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offers access to play stage client-side networking functionalities.
|
||||||
|
*
|
||||||
|
* <p>Client-side networking functionalities include receiving clientbound packets,
|
||||||
|
* sending serverbound packets, and events related to client-side network handlers.
|
||||||
|
*
|
||||||
|
* <p>This class should be only used on the physical client and for the logical client.
|
||||||
|
*
|
||||||
|
* @see ClientLoginNetworking
|
||||||
|
* @see ServerPlayNetworking
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class ClientPlayNetworking {
|
||||||
|
/**
|
||||||
|
* Registers a handler to a channel.
|
||||||
|
* A global receiver is registered to all connections, in the present and future.
|
||||||
|
*
|
||||||
|
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
|
||||||
|
* Use {@link #unregisterGlobalReceiver(ResourceLocation)} to unregister the existing handler.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @param channelHandler the handler
|
||||||
|
* @return false if a handler is already registered to the channel
|
||||||
|
* @see ClientPlayNetworking#unregisterGlobalReceiver(ResourceLocation)
|
||||||
|
* @see ClientPlayNetworking#registerReceiver(ResourceLocation, PlayChannelHandler)
|
||||||
|
*/
|
||||||
|
public static boolean registerGlobalReceiver(ResourceLocation channelName, PlayChannelHandler channelHandler) {
|
||||||
|
return ClientNetworkingImpl.PLAY.registerGlobalReceiver(channelName, channelHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the handler of a channel.
|
||||||
|
* A global receiver is registered to all connections, in the present and future.
|
||||||
|
*
|
||||||
|
* <p>The {@code channel} is guaranteed not to have a handler after this call.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @return the previous handler, or {@code null} if no handler was bound to the channel
|
||||||
|
* @see ClientPlayNetworking#registerGlobalReceiver(ResourceLocation, PlayChannelHandler)
|
||||||
|
* @see ClientPlayNetworking#unregisterReceiver(ResourceLocation)
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static PlayChannelHandler unregisterGlobalReceiver(ResourceLocation channelName) {
|
||||||
|
return ClientNetworkingImpl.PLAY.unregisterGlobalReceiver(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all channel names which global receivers are registered for.
|
||||||
|
* A global receiver is registered to all connections, in the present and future.
|
||||||
|
*
|
||||||
|
* @return all channel names which global receivers are registered for.
|
||||||
|
*/
|
||||||
|
public static Set<ResourceLocation> getGlobalReceivers() {
|
||||||
|
return ClientNetworkingImpl.PLAY.getChannels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a handler to a channel.
|
||||||
|
*
|
||||||
|
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
|
||||||
|
* Use {@link #unregisterReceiver(ResourceLocation)} to unregister the existing handler.
|
||||||
|
*
|
||||||
|
* <p>For example, if you only register a receiver using this method when a {@linkplain ClientLoginNetworking#registerGlobalReceiver(ResourceLocation, ClientLoginNetworking.LoginQueryRequestHandler)}
|
||||||
|
* login query has been received, you should use {@link ClientPlayConnectionEvents#INIT} to register the channel handler.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @return false if a handler is already registered to the channel
|
||||||
|
* @throws IllegalStateException if the client is not connected to a server
|
||||||
|
* @see ClientPlayConnectionEvents#INIT
|
||||||
|
*/
|
||||||
|
public static boolean registerReceiver(ResourceLocation channelName, PlayChannelHandler channelHandler) {
|
||||||
|
final ClientPlayNetworkAddon addon = ClientNetworkingImpl.getClientPlayAddon();
|
||||||
|
|
||||||
|
if (addon != null) {
|
||||||
|
return addon.registerChannel(channelName, channelHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Cannot register receiver while not in game!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the handler of a channel.
|
||||||
|
*
|
||||||
|
* <p>The {@code channelName} is guaranteed not to have a handler after this call.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @return the previous handler, or {@code null} if no handler was bound to the channel
|
||||||
|
* @throws IllegalStateException if the client is not connected to a server
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static PlayChannelHandler unregisterReceiver(ResourceLocation channelName) throws IllegalStateException {
|
||||||
|
final ClientPlayNetworkAddon addon = ClientNetworkingImpl.getClientPlayAddon();
|
||||||
|
|
||||||
|
if (addon != null) {
|
||||||
|
return addon.unregisterChannel(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Cannot unregister receiver while not in game!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the channel names that the client can receive packets on.
|
||||||
|
*
|
||||||
|
* @return All the channel names that the client can receive packets on
|
||||||
|
* @throws IllegalStateException if the client is not connected to a server
|
||||||
|
*/
|
||||||
|
public static Set<ResourceLocation> getReceived() throws IllegalStateException {
|
||||||
|
final ClientPlayNetworkAddon addon = ClientNetworkingImpl.getClientPlayAddon();
|
||||||
|
|
||||||
|
if (addon != null) {
|
||||||
|
return addon.getReceivableChannels();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Cannot get a list of channels the client can receive packets on while not in game!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all channel names that the connected server declared the ability to receive a packets on.
|
||||||
|
*
|
||||||
|
* @return All the channel names the connected server declared the ability to receive a packets on
|
||||||
|
* @throws IllegalStateException if the client is not connected to a server
|
||||||
|
*/
|
||||||
|
public static Set<ResourceLocation> getSendable() throws IllegalStateException {
|
||||||
|
final ClientPlayNetworkAddon addon = ClientNetworkingImpl.getClientPlayAddon();
|
||||||
|
|
||||||
|
if (addon != null) {
|
||||||
|
return addon.getSendableChannels();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Cannot get a list of channels the server can receive packets on while not in game!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the connected server declared the ability to receive a packet on a specified channel name.
|
||||||
|
*
|
||||||
|
* @param channelName the channel name
|
||||||
|
* @return True if the connected server has declared the ability to receive a packet on the specified channel.
|
||||||
|
* False if the client is not in game.
|
||||||
|
*/
|
||||||
|
public static boolean canSend(ResourceLocation channelName) throws IllegalArgumentException {
|
||||||
|
// You cant send without a client player, so this is fine
|
||||||
|
if (Minecraft.getInstance().getConnection() != null) {
|
||||||
|
return ClientNetworkingImpl.getAddon(Minecraft.getInstance().getConnection()).getSendableChannels().contains(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a packet which may be sent to a the connected server.
|
||||||
|
*
|
||||||
|
* @param channelName the channel name
|
||||||
|
* @param buf the packet byte buf which represents the payload of the packet
|
||||||
|
* @return a new packet
|
||||||
|
*/
|
||||||
|
public static Packet<?> createC2SPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
|
||||||
|
Objects.requireNonNull(channelName, "Channel name cannot be null");
|
||||||
|
Objects.requireNonNull(buf, "Buf cannot be null");
|
||||||
|
|
||||||
|
return ClientNetworkingImpl.createPlayC2SPacket(channelName, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the packet sender which sends packets to the connected server.
|
||||||
|
*
|
||||||
|
* @return the client's packet sender
|
||||||
|
* @throws IllegalStateException if the client is not connected to a server
|
||||||
|
*/
|
||||||
|
public static PacketSender getSender() throws IllegalStateException {
|
||||||
|
// You cant send without a client player, so this is fine
|
||||||
|
if (Minecraft.getInstance().getConnection() != null) {
|
||||||
|
return ClientNetworkingImpl.getAddon(Minecraft.getInstance().getConnection());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Cannot get packet sender when not in game!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a packet to the connected server.
|
||||||
|
*
|
||||||
|
* @param channelName the channel of the packet
|
||||||
|
* @param buf the payload of the packet
|
||||||
|
* @throws IllegalStateException if the client is not connected to a server
|
||||||
|
*/
|
||||||
|
public static void send(ResourceLocation channelName, FriendlyByteBuf buf) throws IllegalStateException {
|
||||||
|
// You cant send without a client player, so this is fine
|
||||||
|
if (Minecraft.getInstance().getConnection() != null) {
|
||||||
|
Minecraft.getInstance().getConnection().send(createC2SPacket(channelName, buf));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Cannot send packets when not in game!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientPlayNetworking() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface PlayChannelHandler {
|
||||||
|
/**
|
||||||
|
* Handles an incoming packet.
|
||||||
|
*
|
||||||
|
* <p>This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}.
|
||||||
|
* Modification to the game should be {@linkplain net.minecraft.util.thread.BlockableEventLoop#submit(Runnable) scheduled} using the provided Minecraft client instance.
|
||||||
|
*
|
||||||
|
* <p>An example usage of this is to display an overlay message:
|
||||||
|
* <pre>{@code
|
||||||
|
* ClientPlayNetworking.registerReceiver(new Identifier("mymod", "overlay"), (client, handler, buf, responseSender) -&rt; {
|
||||||
|
* String message = buf.readString(32767);
|
||||||
|
*
|
||||||
|
* // All operations on the server or world must be executed on the server thread
|
||||||
|
* client.execute(() -&rt; {
|
||||||
|
* client.inGameHud.setOverlayMessage(message, true);
|
||||||
|
* });
|
||||||
|
* });
|
||||||
|
* }</pre>
|
||||||
|
* @param client the client
|
||||||
|
* @param handler the network handler that received this packet
|
||||||
|
* @param buf the payload of the packet
|
||||||
|
* @param responseSender the packet sender
|
||||||
|
*/
|
||||||
|
void receive(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender);
|
||||||
|
}
|
||||||
|
}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Networking API (client side), version 1.
|
||||||
|
*
|
||||||
|
* <p>For login stage networking see {@link net.fabricmc.fabric.api.client.networking.v1.ClientLoginNetworking}.
|
||||||
|
* For play stage networking see {@link net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking}.
|
||||||
|
*
|
||||||
|
* <p>For events related to connection to a server see {@link net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents} for login stage
|
||||||
|
* or {@link net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents} for play stage.
|
||||||
|
*
|
||||||
|
* <p>For events related to the ability of a server to receive packets on a channel of a specific name see {@link net.fabricmc.fabric.api.client.networking.v1.C2SPlayChannelEvents}.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.client.networking.v1;
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.event;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that this {@link Event} is auto-invoking:
|
||||||
|
* it calls the event callback implemented by a context parameter type automatically and without registration.
|
||||||
|
*
|
||||||
|
* <p>This means that this event can be listened to in two ways:
|
||||||
|
* <ul>
|
||||||
|
* <li>If the consumer is the context parameter and it implements the callback, it will be automatically invoked, don't register manually.
|
||||||
|
* <li>Otherwise, there is no invocation and the listener needs manual registration as usual.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>Do note that there may be more than one context parameter.
|
||||||
|
*
|
||||||
|
* <p>A typical use case is feature augmentation, for example to expose raw clicks to slots.
|
||||||
|
* The event callback has a slot parameter - the context parameter - and the event itself is carrying this annotation.
|
||||||
|
* All the slot needs to receive slot clicks is to implement {@code SlotClickCallback} on itself.
|
||||||
|
* It shouldn't do any explicit event registration like {@code SLOT_CLICK_EVENT.register(this::onSlotClick)},
|
||||||
|
* otherwise it will see extraneous callback invocations.
|
||||||
|
*
|
||||||
|
* <p>In general, an auto-invoking event bridges the gap between the flexibility of an event with global reach,
|
||||||
|
* and the convenience of implementing an interface that gets detected automatically.
|
||||||
|
*
|
||||||
|
* <p>This is a documentation-only annotation, the event factory has to implement the functionality explicitly by checking the parameter type and invoking it.
|
||||||
|
* On top of adding this annotation, the event field or method should document which parameters are context parameters,
|
||||||
|
* and under which circumstances they are invoked.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||||
|
public @interface AutoInvokingEvent {
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.event;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for Fabric's event implementations.
|
||||||
|
*
|
||||||
|
* @param <T> The listener type.
|
||||||
|
* @see EventFactory
|
||||||
|
*/
|
||||||
|
@ApiStatus.NonExtendable // Should only be extended by fabric API.
|
||||||
|
public abstract class Event<T> {
|
||||||
|
/**
|
||||||
|
* The invoker field. This should be updated by the implementation to
|
||||||
|
* always refer to an instance containing all code that should be
|
||||||
|
* executed upon event emission.
|
||||||
|
*/
|
||||||
|
protected volatile T invoker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the invoker instance.
|
||||||
|
*
|
||||||
|
* <p>An "invoker" is an object which hides multiple registered
|
||||||
|
* listeners of type T under one instance of type T, executing
|
||||||
|
* them and leaving early as necessary.
|
||||||
|
*
|
||||||
|
* @return The invoker instance.
|
||||||
|
*/
|
||||||
|
public final T invoker() {
|
||||||
|
return invoker;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a listener to the event, in the default phase.
|
||||||
|
* Have a look at {@link #addPhaseOrdering} for an explanation of event phases.
|
||||||
|
*
|
||||||
|
* @param listener The desired listener.
|
||||||
|
*/
|
||||||
|
public abstract void register(T listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ResourceLocation of the default phase.
|
||||||
|
* Have a look at {@link EventFactory#createWithPhases} for an explanation of event phases.
|
||||||
|
*/
|
||||||
|
public static final ResourceLocation DEFAULT_PHASE = new ResourceLocation("fabric", "default");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a listener to the event for the specified phase.
|
||||||
|
* Have a look at {@link EventFactory#createWithPhases} for an explanation of event phases.
|
||||||
|
*
|
||||||
|
* @param phase ResourceLocation of the phase this listener should be registered for. It will be created if it didn't exist yet.
|
||||||
|
* @param listener The desired listener.
|
||||||
|
*/
|
||||||
|
public void register(ResourceLocation phase, T listener) {
|
||||||
|
// This is done to keep compatibility with existing Event subclasses, but they should really not be subclassing Event.
|
||||||
|
register(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request that listeners registered for one phase be executed before listeners registered for another phase.
|
||||||
|
* Relying on the default phases supplied to {@link EventFactory#createWithPhases} should be preferred over manually
|
||||||
|
* registering phase ordering dependencies.
|
||||||
|
*
|
||||||
|
* <p>Incompatible ordering constraints such as cycles will lead to inconsistent behavior:
|
||||||
|
* some constraints will be respected and some will be ignored. If this happens, a warning will be logged.
|
||||||
|
*
|
||||||
|
* @param firstPhase The ResourceLocation of the phase that should run before the other. It will be created if it didn't exist yet.
|
||||||
|
* @param secondPhase The ResourceLocation of the phase that should run after the other. It will be created if it didn't exist yet.
|
||||||
|
*/
|
||||||
|
public void addPhaseOrdering(ResourceLocation firstPhase, ResourceLocation secondPhase) {
|
||||||
|
// This is not abstract to avoid breaking existing Event subclasses, but they should really not be subclassing Event.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.event;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
import com.seibel.lod.forge.fabric.impl.base.event.EventFactoryImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for creating {@link Event} classes.
|
||||||
|
*/
|
||||||
|
public final class EventFactory {
|
||||||
|
private static boolean profilingEnabled = true;
|
||||||
|
|
||||||
|
private EventFactory() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if events are supposed to be profiled.
|
||||||
|
*/
|
||||||
|
public static boolean isProfilingEnabled() {
|
||||||
|
return profilingEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidate and re-create all existing "invoker" instances across
|
||||||
|
* events created by this EventFactory. Use this if, for instance,
|
||||||
|
* the profilingEnabled field changes.
|
||||||
|
*/
|
||||||
|
// TODO: Turn this into an event?
|
||||||
|
public static void invalidate() {
|
||||||
|
EventFactoryImpl.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an "array-backed" Event instance.
|
||||||
|
*
|
||||||
|
* <p>If your factory simply delegates to the listeners without adding custom behavior,
|
||||||
|
* consider using {@linkplain #createArrayBacked(Class, Object, Function) the other overload}
|
||||||
|
* if performance of this event is critical.
|
||||||
|
*
|
||||||
|
* @param type The listener class type.
|
||||||
|
* @param invokerFactory The invoker factory, combining multiple listeners into one instance.
|
||||||
|
* @param <T> The listener type.
|
||||||
|
* @return The Event instance.
|
||||||
|
*/
|
||||||
|
public static <T> Event<T> createArrayBacked(Class<? super T> type, Function<T[], T> invokerFactory) {
|
||||||
|
return EventFactoryImpl.createArrayBacked(type, invokerFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an "array-backed" Event instance with a custom empty invoker,
|
||||||
|
* for an event whose {@code invokerFactory} only delegates to the listeners.
|
||||||
|
* <ul>
|
||||||
|
* <li>If there is no listener, the custom empty invoker will be used.</li>
|
||||||
|
* <li><b>If there is only one listener, that one will be used as the invoker
|
||||||
|
* and the factory will not be called.</b></li>
|
||||||
|
* <li>Only when there are at least two listeners will the factory be used.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>Having a custom empty invoker (of type (...) -> {}) increases performance
|
||||||
|
* relative to iterating over an empty array; however, it only really matters
|
||||||
|
* if the event is executed thousands of times a second.
|
||||||
|
*
|
||||||
|
* @param type The listener class type.
|
||||||
|
* @param emptyInvoker The custom empty invoker.
|
||||||
|
* @param invokerFactory The invoker factory, combining multiple listeners into one instance.
|
||||||
|
* @param <T> The listener type.
|
||||||
|
* @return The Event instance.
|
||||||
|
*/
|
||||||
|
public static <T> Event<T> createArrayBacked(Class<T> type, T emptyInvoker, Function<T[], T> invokerFactory) {
|
||||||
|
return createArrayBacked(type, listeners -> {
|
||||||
|
if (listeners.length == 0) {
|
||||||
|
return emptyInvoker;
|
||||||
|
} else if (listeners.length == 1) {
|
||||||
|
return listeners[0];
|
||||||
|
} else {
|
||||||
|
return invokerFactory.apply(listeners);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an array-backed event with a list of default phases that get invoked in order.
|
||||||
|
* Exposing the ResourceLocations of the default phases as {@code public static final} constants is encouraged.
|
||||||
|
*
|
||||||
|
* <p>An event phase is a named group of listeners, which may be ordered before or after other groups of listeners.
|
||||||
|
* This allows some listeners to take priority over other listeners.
|
||||||
|
* Adding separate events should be considered before making use of multiple event phases.
|
||||||
|
*
|
||||||
|
* <p>Phases may be freely added to events created with any of the factory functions,
|
||||||
|
* however using this function is preferred for widely used event phases.
|
||||||
|
* If more phases are necessary, discussion with the author of the Event is encouraged.
|
||||||
|
*
|
||||||
|
* <p>Refer to {@link Event#addPhaseOrdering} for an explanation of event phases.
|
||||||
|
*
|
||||||
|
* @param type The listener class type.
|
||||||
|
* @param invokerFactory The invoker factory, combining multiple listeners into one instance.
|
||||||
|
* @param defaultPhases The default phases of this event, in the correct order. Must contain {@link Event#DEFAULT_PHASE}.
|
||||||
|
* @param <T> The listener type.
|
||||||
|
* @return The Event instance.
|
||||||
|
*/
|
||||||
|
public static <T> Event<T> createWithPhases(Class<? super T> type, Function<T[], T> invokerFactory, ResourceLocation... defaultPhases) {
|
||||||
|
EventFactoryImpl.ensureContainsDefault(defaultPhases);
|
||||||
|
EventFactoryImpl.ensureNoDuplicates(defaultPhases);
|
||||||
|
|
||||||
|
Event<T> event = createArrayBacked(type, invokerFactory);
|
||||||
|
|
||||||
|
for (int i = 1; i < defaultPhases.length; ++i) {
|
||||||
|
event.addPhaseOrdering(defaultPhases[i-1], defaultPhases[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the listener object name. This can be used in debugging/profiling
|
||||||
|
* scenarios.
|
||||||
|
*
|
||||||
|
* @param handler The listener object.
|
||||||
|
* @return The listener name.
|
||||||
|
*/
|
||||||
|
public static String getHandlerName(Object handler) {
|
||||||
|
return handler.getClass().getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.networking.v1;
|
||||||
|
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.Event;
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.EventFactory;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Events related to a tracking entities within a player's view distance.
|
||||||
|
*/
|
||||||
|
public final class EntityTrackingEvents {
|
||||||
|
/**
|
||||||
|
* An event that is called before player starts tracking an entity.
|
||||||
|
* Typically this occurs when an entity enters a client's view distance.
|
||||||
|
* This event is called before the player's client is sent the entity's {@link Entity#getAddEntityPacket() spawn packet}.
|
||||||
|
*/
|
||||||
|
public static final Event<StartTracking> START_TRACKING = EventFactory.createArrayBacked(StartTracking.class, callbacks -> (trackedEntity, player) -> {
|
||||||
|
for (StartTracking callback : callbacks) {
|
||||||
|
callback.onStartTracking(trackedEntity, player);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that is called after a player has stopped tracking an entity.
|
||||||
|
* The client at this point was sent a packet to {@link net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket destroy} the entity on the client.
|
||||||
|
* The entity still exists on the server.
|
||||||
|
*/
|
||||||
|
public static final Event<StopTracking> STOP_TRACKING = EventFactory.createArrayBacked(StopTracking.class, callbacks -> (trackedEntity, player) -> {
|
||||||
|
for (StopTracking callback : callbacks) {
|
||||||
|
callback.onStopTracking(trackedEntity, player);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface StartTracking {
|
||||||
|
/**
|
||||||
|
* Called before an entity starts getting tracked by a player.
|
||||||
|
*
|
||||||
|
* @param trackedEntity the entity that will be tracked
|
||||||
|
* @param player the player that will track the entity
|
||||||
|
*/
|
||||||
|
void onStartTracking(Entity trackedEntity, ServerPlayer player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface StopTracking {
|
||||||
|
/**
|
||||||
|
* Called after an entity stops getting tracked by a player.
|
||||||
|
*
|
||||||
|
* @param trackedEntity the entity that is no longer being tracked
|
||||||
|
* @param player the player that is no longer tracking the entity
|
||||||
|
*/
|
||||||
|
void onStopTracking(Entity trackedEntity, ServerPlayer player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntityTrackingEvents() {
|
||||||
|
}
|
||||||
|
}
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.networking.v1;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
import io.netty.channel.local.LocalChannel;
|
||||||
|
import io.netty.channel.local.LocalServerChannel;
|
||||||
|
import io.netty.util.concurrent.Future;
|
||||||
|
import io.netty.util.concurrent.FutureListener;
|
||||||
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities for working with netty's future listeners.
|
||||||
|
* @see FutureListener
|
||||||
|
* @see ChannelFutureListener
|
||||||
|
*/
|
||||||
|
public final class FutureListeners {
|
||||||
|
/**
|
||||||
|
* Returns a future listener that releases a packet byte buf when the buffer has been sent to a remote connection.
|
||||||
|
*
|
||||||
|
* @param buf the buffer
|
||||||
|
* @return the future listener
|
||||||
|
*/
|
||||||
|
public static ChannelFutureListener free(FriendlyByteBuf buf) {
|
||||||
|
Objects.requireNonNull(buf, "PacketByteBuf cannot be null");
|
||||||
|
|
||||||
|
return (future) -> {
|
||||||
|
if (!isLocalChannel(future.channel())) {
|
||||||
|
buf.release();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a netty channel performs local transportation, or if the message objects in the channel are directly passed than written to and read from a byte buf.
|
||||||
|
*
|
||||||
|
* @param channel the channel to check
|
||||||
|
* @return whether the channel is local
|
||||||
|
*/
|
||||||
|
public static boolean isLocalChannel(Channel channel) {
|
||||||
|
return channel instanceof LocalServerChannel || channel instanceof LocalChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines two future listeners.
|
||||||
|
*
|
||||||
|
* @param first the first future listener
|
||||||
|
* @param second the second future listener
|
||||||
|
* @param <A> the future type of the first listener, used for casting
|
||||||
|
* @param <B> the future type of the second listener, used for casting
|
||||||
|
* @return the combined future listener.
|
||||||
|
*/
|
||||||
|
// A, B exist just to allow casting
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <A extends Future<? super Void>, B extends Future<? super Void>> GenericFutureListener<? extends Future<? super Void>> union(GenericFutureListener<A> first, GenericFutureListener<B> second) {
|
||||||
|
// Return an empty future listener in the case of both parameters somehow being null
|
||||||
|
if (first == null && second == null) {
|
||||||
|
return future -> { };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first == null) {
|
||||||
|
return second;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (second == null) {
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
return future -> {
|
||||||
|
first.operationComplete((A) future);
|
||||||
|
second.operationComplete((B) future);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private FutureListeners() {
|
||||||
|
}
|
||||||
|
}
|
||||||
+204
@@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.networking.v1;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper methods for working with and creating {@link FriendlyByteBuf}s.
|
||||||
|
*/
|
||||||
|
public final class PacketByteBufs {
|
||||||
|
private static final FriendlyByteBuf EMPTY_PACKET_BYTE_BUF = new FriendlyByteBuf(Unpooled.EMPTY_BUFFER);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an empty instance of packet byte buf.
|
||||||
|
*
|
||||||
|
* @return an empty buf
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf empty() {
|
||||||
|
return EMPTY_PACKET_BYTE_BUF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new heap memory-backed instance of packet byte buf.
|
||||||
|
*
|
||||||
|
* @return a new buf
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf create() {
|
||||||
|
return new FriendlyByteBuf(Unpooled.buffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience methods for byte buf methods that return a new byte buf
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the newly created buf from {@code buf.readBytes} in a packet byte buf.
|
||||||
|
*
|
||||||
|
* @param buf the original buf
|
||||||
|
* @param length the number of bytes to transfer
|
||||||
|
* @return the transferred bytes
|
||||||
|
* @see ByteBuf#readBytes(int)
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf readBytes(ByteBuf buf, int length) {
|
||||||
|
Objects.requireNonNull(buf, "ByteBuf cannot be null");
|
||||||
|
|
||||||
|
return new FriendlyByteBuf(buf.readBytes(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the newly created buf from {@code buf.readSlice} in a packet byte buf.
|
||||||
|
*
|
||||||
|
* @param buf the original buf
|
||||||
|
* @param length the size of the new slice
|
||||||
|
* @return the newly created slice
|
||||||
|
* @see ByteBuf#readSlice(int)
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf readSlice(ByteBuf buf, int length) {
|
||||||
|
Objects.requireNonNull(buf, "ByteBuf cannot be null");
|
||||||
|
|
||||||
|
return new FriendlyByteBuf(buf.readSlice(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the newly created buf from {@code buf.readRetainedSlice} in a packet byte buf.
|
||||||
|
*
|
||||||
|
* @param buf the original buf
|
||||||
|
* @param length the size of the new slice
|
||||||
|
* @return the newly created slice
|
||||||
|
* @see ByteBuf#readRetainedSlice(int)
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf readRetainedSlice(ByteBuf buf, int length) {
|
||||||
|
Objects.requireNonNull(buf, "ByteBuf cannot be null");
|
||||||
|
|
||||||
|
return new FriendlyByteBuf(buf.readRetainedSlice(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the newly created buf from {@code buf.copy} in a packet byte buf.
|
||||||
|
*
|
||||||
|
* @param buf the original buf
|
||||||
|
* @return a copy of the buf
|
||||||
|
* @see ByteBuf#copy()
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf copy(ByteBuf buf) {
|
||||||
|
Objects.requireNonNull(buf, "ByteBuf cannot be null");
|
||||||
|
|
||||||
|
return new FriendlyByteBuf(buf.copy());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the newly created buf from {@code buf.copy} in a packet byte buf.
|
||||||
|
*
|
||||||
|
* @param buf the original buf
|
||||||
|
* @param index the starting index
|
||||||
|
* @param length the size of the copy
|
||||||
|
* @return a copy of the buf
|
||||||
|
* @see ByteBuf#copy(int, int)
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf copy(ByteBuf buf, int index, int length) {
|
||||||
|
Objects.requireNonNull(buf, "ByteBuf cannot be null");
|
||||||
|
|
||||||
|
return new FriendlyByteBuf(buf.copy(index, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the newly created buf from {@code buf.slice} in a packet byte buf.
|
||||||
|
*
|
||||||
|
* @param buf the original buf
|
||||||
|
* @return a slice of the buf
|
||||||
|
* @see ByteBuf#slice()
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf slice(ByteBuf buf) {
|
||||||
|
Objects.requireNonNull(buf, "ByteBuf cannot be null");
|
||||||
|
|
||||||
|
return new FriendlyByteBuf(buf.slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the newly created buf from {@code buf.retainedSlice} in a packet byte buf.
|
||||||
|
*
|
||||||
|
* @param buf the original buf
|
||||||
|
* @return a slice of the buf
|
||||||
|
* @see ByteBuf#retainedSlice()
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf retainedSlice(ByteBuf buf) {
|
||||||
|
Objects.requireNonNull(buf, "ByteBuf cannot be null");
|
||||||
|
|
||||||
|
return new FriendlyByteBuf(buf.retainedSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the newly created buf from {@code buf.slice} in a packet byte buf.
|
||||||
|
*
|
||||||
|
* @param buf the original buf
|
||||||
|
* @param index the starting index
|
||||||
|
* @param length the size of the copy
|
||||||
|
* @return a slice of the buf
|
||||||
|
* @see ByteBuf#slice(int, int)
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf slice(ByteBuf buf, int index, int length) {
|
||||||
|
Objects.requireNonNull(buf, "ByteBuf cannot be null");
|
||||||
|
|
||||||
|
return new FriendlyByteBuf(buf.slice(index, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the newly created buf from {@code buf.retainedSlice} in a packet byte buf.
|
||||||
|
*
|
||||||
|
* @param buf the original buf
|
||||||
|
* @param index the starting index
|
||||||
|
* @param length the size of the copy
|
||||||
|
* @return a slice of the buf
|
||||||
|
* @see ByteBuf#retainedSlice(int, int)
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf retainedSlice(ByteBuf buf, int index, int length) {
|
||||||
|
Objects.requireNonNull(buf, "ByteBuf cannot be null");
|
||||||
|
|
||||||
|
return new FriendlyByteBuf(buf.retainedSlice(index, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the newly created buf from {@code buf.duplicate} in a packet byte buf.
|
||||||
|
*
|
||||||
|
* @param buf the original buf
|
||||||
|
* @return a duplicate of the buf
|
||||||
|
* @see ByteBuf#duplicate()
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf duplicate(ByteBuf buf) {
|
||||||
|
Objects.requireNonNull(buf, "ByteBuf cannot be null");
|
||||||
|
|
||||||
|
return new FriendlyByteBuf(buf.duplicate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the newly created buf from {@code buf.retainedDuplicate} in a packet byte buf.
|
||||||
|
*
|
||||||
|
* @param buf the original buf
|
||||||
|
* @return a duplicate of the buf
|
||||||
|
* @see ByteBuf#retainedDuplicate()
|
||||||
|
*/
|
||||||
|
public static FriendlyByteBuf retainedDuplicate(ByteBuf buf) {
|
||||||
|
Objects.requireNonNull(buf, "ByteBuf cannot be null");
|
||||||
|
|
||||||
|
return new FriendlyByteBuf(buf.retainedDuplicate());
|
||||||
|
}
|
||||||
|
|
||||||
|
private PacketByteBufs() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.networking.v1;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
import io.netty.util.concurrent.Future;
|
||||||
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents something that supports sending packets to channels.
|
||||||
|
* @see PacketByteBufs
|
||||||
|
*/
|
||||||
|
public interface PacketSender {
|
||||||
|
/**
|
||||||
|
* Makes a packet for a channel.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @param buf the content of the packet
|
||||||
|
*/
|
||||||
|
Packet<?> createPacket(ResourceLocation channelName, FriendlyByteBuf buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a packet.
|
||||||
|
*
|
||||||
|
* @param packet the packet
|
||||||
|
*/
|
||||||
|
void sendPacket(Packet<?> packet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a packet.
|
||||||
|
*
|
||||||
|
* @param packet the packet
|
||||||
|
* @param callback an optional callback to execute after the packet is sent, may be {@code null}. The callback may also accept a {@link ChannelFutureListener}.
|
||||||
|
*/
|
||||||
|
void sendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a packet to a channel.
|
||||||
|
*
|
||||||
|
* @param channel the id of the channel
|
||||||
|
* @param buf the content of the packet
|
||||||
|
*/
|
||||||
|
default void sendPacket(ResourceLocation channel, FriendlyByteBuf buf) {
|
||||||
|
Objects.requireNonNull(channel, "Channel cannot be null");
|
||||||
|
Objects.requireNonNull(buf, "Payload cannot be null");
|
||||||
|
|
||||||
|
this.sendPacket(this.createPacket(channel, buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a packet to a channel.
|
||||||
|
*
|
||||||
|
* @param channel the id of the channel
|
||||||
|
* @param buf the content of the packet
|
||||||
|
* @param callback an optional callback to execute after the packet is sent, may be {@code null}
|
||||||
|
*/
|
||||||
|
// the generic future listener can accept ChannelFutureListener
|
||||||
|
default void sendPacket(ResourceLocation channel, FriendlyByteBuf buf, @Nullable GenericFutureListener<? extends Future<? super Void>> callback) {
|
||||||
|
Objects.requireNonNull(channel, "Channel cannot be null");
|
||||||
|
Objects.requireNonNull(buf, "Payload cannot be null");
|
||||||
|
|
||||||
|
this.sendPacket(this.createPacket(channel, buf), callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.networking.v1;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Vec3i;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ChunkMap;
|
||||||
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.network.ServerPlayerConnection;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkSource;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor.EntityTrackerAccessor;
|
||||||
|
import com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor.ThreadedAnvilChunkStorageAccessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For example, a block entity may use the methods in this class to send a packet to all clients which can see the block entity in order notify clients about a change.
|
||||||
|
*
|
||||||
|
* <p>The word "tracking" means that an entity/chunk on the server is known to a player's client (within in view distance) and the (block) entity should notify tracking clients of changes.
|
||||||
|
*
|
||||||
|
* <p>These methods should only be called on the server thread and only be used on logical a server.
|
||||||
|
*/
|
||||||
|
public final class PlayerLookup {
|
||||||
|
/**
|
||||||
|
* Gets all the players on the minecraft server.
|
||||||
|
*
|
||||||
|
* <p>The returned collection is immutable.
|
||||||
|
*
|
||||||
|
* @param server the server
|
||||||
|
* @return all players on the server
|
||||||
|
*/
|
||||||
|
public static Collection<ServerPlayer> all(MinecraftServer server) {
|
||||||
|
Objects.requireNonNull(server, "The server cannot be null");
|
||||||
|
|
||||||
|
// return an immutable collection to guard against accidental removals.
|
||||||
|
if (server.getPlayerList() != null) {
|
||||||
|
return Collections.unmodifiableCollection(server.getPlayerList().getPlayers());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the players in a server world.
|
||||||
|
*
|
||||||
|
* <p>The returned collection is immutable.
|
||||||
|
*
|
||||||
|
* @param world the server world
|
||||||
|
* @return the players in the server world
|
||||||
|
*/
|
||||||
|
public static Collection<ServerPlayer> world(ServerLevel world) {
|
||||||
|
Objects.requireNonNull(world, "The world cannot be null");
|
||||||
|
|
||||||
|
// return an immutable collection to guard against accidental removals.
|
||||||
|
return Collections.unmodifiableCollection(world.players());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all players tracking a chunk in a server world.
|
||||||
|
*
|
||||||
|
* @param world the server world
|
||||||
|
* @param pos the chunk in question
|
||||||
|
* @return the players tracking the chunk
|
||||||
|
*/
|
||||||
|
public static Collection<ServerPlayer> tracking(ServerLevel world, ChunkPos pos) {
|
||||||
|
Objects.requireNonNull(world, "The world cannot be null");
|
||||||
|
Objects.requireNonNull(pos, "The chunk pos cannot be null");
|
||||||
|
|
||||||
|
return world.getChunkSource().chunkMap.getPlayers(pos, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all players tracking an entity in a server world.
|
||||||
|
*
|
||||||
|
* <p>The returned collection is immutable.
|
||||||
|
*
|
||||||
|
* <p><b>Warning</b>: If the provided entity is a player, it is not
|
||||||
|
* guaranteed by the contract that said player is included in the
|
||||||
|
* resulting stream.
|
||||||
|
*
|
||||||
|
* @param entity the entity being tracked
|
||||||
|
* @return the players tracking the entity
|
||||||
|
* @throws IllegalArgumentException if the entity is not in a server world
|
||||||
|
*/
|
||||||
|
public static Collection<ServerPlayer> tracking(Entity entity) {
|
||||||
|
Objects.requireNonNull(entity, "Entity cannot be null");
|
||||||
|
ChunkSource manager = entity.level.getChunkSource();
|
||||||
|
|
||||||
|
if (manager instanceof ServerChunkCache) {
|
||||||
|
ChunkMap storage = ((ServerChunkCache) manager).chunkMap;
|
||||||
|
EntityTrackerAccessor tracker = ((ThreadedAnvilChunkStorageAccessor) storage).getEntityMap().get(entity.getId());
|
||||||
|
|
||||||
|
// return an immutable collection to guard against accidental removals.
|
||||||
|
if (tracker != null) {
|
||||||
|
return Collections.unmodifiableCollection(tracker.getPlayersTracking()
|
||||||
|
.stream().map(ServerPlayerConnection::getPlayer).collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Only supported on server worlds!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all players tracking a block entity in a server world.
|
||||||
|
*
|
||||||
|
* @param blockEntity the block entity
|
||||||
|
* @return the players tracking the block position
|
||||||
|
* @throws IllegalArgumentException if the block entity is not in a server world
|
||||||
|
*/
|
||||||
|
public static Collection<ServerPlayer> tracking(BlockEntity blockEntity) {
|
||||||
|
Objects.requireNonNull(blockEntity, "BlockEntity cannot be null");
|
||||||
|
|
||||||
|
//noinspection ConstantConditions - IJ intrinsics don't know hasWorld == true will result in no null
|
||||||
|
if (!blockEntity.hasLevel() || blockEntity.getLevel().isClientSide()) {
|
||||||
|
throw new IllegalArgumentException("Only supported on server worlds!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return tracking((ServerLevel) blockEntity.getLevel(), blockEntity.getBlockPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all players tracking a block position in a server world.
|
||||||
|
*
|
||||||
|
* @param world the server world
|
||||||
|
* @param pos the block position
|
||||||
|
* @return the players tracking the block position
|
||||||
|
*/
|
||||||
|
public static Collection<ServerPlayer> tracking(ServerLevel world, BlockPos pos) {
|
||||||
|
Objects.requireNonNull(pos, "BlockPos cannot be null");
|
||||||
|
|
||||||
|
return tracking(world, new ChunkPos(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all players around a position in a world.
|
||||||
|
*
|
||||||
|
* <p>The distance check is done in the three-dimensional space instead of in the horizontal plane.
|
||||||
|
*
|
||||||
|
* @param world the world
|
||||||
|
* @param pos the position
|
||||||
|
* @param radius the maximum distance from the position in blocks
|
||||||
|
* @return the players around the position
|
||||||
|
*/
|
||||||
|
public static Collection<ServerPlayer> around(ServerLevel world, Vec3 pos, double radius) {
|
||||||
|
double radiusSq = radius * radius;
|
||||||
|
|
||||||
|
return world(world)
|
||||||
|
.stream()
|
||||||
|
.filter((p) -> p.distanceToSqr(pos) <= radiusSq)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all players around a position in a world.
|
||||||
|
*
|
||||||
|
* <p>The distance check is done in the three-dimensional space instead of in the horizontal plane.
|
||||||
|
*
|
||||||
|
* @param world the world
|
||||||
|
* @param pos the position (can be a block pos)
|
||||||
|
* @param radius the maximum distance from the position in blocks
|
||||||
|
* @return the players around the position
|
||||||
|
*/
|
||||||
|
public static Collection<ServerPlayer> around(ServerLevel world, Vec3i pos, double radius) {
|
||||||
|
double radiusSq = radius * radius;
|
||||||
|
|
||||||
|
return world(world)
|
||||||
|
.stream()
|
||||||
|
.filter((p) -> p.distanceToSqr(pos.getX(), pos.getY(), pos.getZ()) <= radiusSq)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlayerLookup() {
|
||||||
|
}
|
||||||
|
}
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.networking.v1;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.Event;
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.EventFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offers access to events related to the indication of a connected client's ability to receive packets in certain channels.
|
||||||
|
*/
|
||||||
|
public final class S2CPlayChannelEvents {
|
||||||
|
/**
|
||||||
|
* An event for the server play network handler receiving an update indicating the connected client's ability to receive packets in certain channels.
|
||||||
|
* This event may be invoked at any time after login and up to disconnection.
|
||||||
|
*/
|
||||||
|
public static final Event<Register> REGISTER = EventFactory.createArrayBacked(Register.class, callbacks -> (handler, sender, server, channels) -> {
|
||||||
|
for (Register callback : callbacks) {
|
||||||
|
callback.onChannelRegister(handler, sender, server, channels);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event for the server play network handler receiving an update indicating the connected client's lack of ability to receive packets in certain channels.
|
||||||
|
* This event may be invoked at any time after login and up to disconnection.
|
||||||
|
*/
|
||||||
|
public static final Event<Unregister> UNREGISTER = EventFactory.createArrayBacked(Unregister.class, callbacks -> (handler, sender, server, channels) -> {
|
||||||
|
for (Unregister callback : callbacks) {
|
||||||
|
callback.onChannelUnregister(handler, sender, server, channels);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private S2CPlayChannelEvents() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see S2CPlayChannelEvents#REGISTER
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Register {
|
||||||
|
void onChannelRegister(ServerGamePacketListenerImpl handler, PacketSender sender, MinecraftServer server, List<ResourceLocation> channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see S2CPlayChannelEvents#UNREGISTER
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Unregister {
|
||||||
|
void onChannelUnregister(ServerGamePacketListenerImpl handler, PacketSender sender, MinecraftServer server, List<ResourceLocation> channels);
|
||||||
|
}
|
||||||
|
}
|
||||||
+91
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.networking.v1;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.network.ServerLoginPacketListenerImpl;
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.Event;
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.EventFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offers access to events related to the connection to a client on a logical server while a client is logging in.
|
||||||
|
*/
|
||||||
|
public final class ServerLoginConnectionEvents {
|
||||||
|
/**
|
||||||
|
* Event indicating a connection entered the LOGIN state, ready for registering query response handlers.
|
||||||
|
*
|
||||||
|
* @see ServerLoginNetworking#registerReceiver(ServerLoginPacketListenerImpl, ResourceLocation, ServerLoginNetworking.LoginQueryResponseHandler)
|
||||||
|
*/
|
||||||
|
public static final Event<Init> INIT = EventFactory.createArrayBacked(Init.class, callbacks -> (handler, server) -> {
|
||||||
|
for (Init callback : callbacks) {
|
||||||
|
callback.onLoginInit(handler, server);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event for the start of login queries of the server login network handler.
|
||||||
|
* This event may be used to register {@link ServerLoginNetworking.LoginQueryResponseHandler login query response handlers}
|
||||||
|
* using {@link ServerLoginNetworking#registerReceiver(ServerLoginPacketListenerImpl, ResourceLocation, ServerLoginNetworking.LoginQueryResponseHandler)}
|
||||||
|
* since this event is fired just before the first login query response is processed.
|
||||||
|
*
|
||||||
|
* <p>You may send login queries to the connected client using the provided {@link PacketSender}.
|
||||||
|
*/
|
||||||
|
public static final Event<QueryStart> QUERY_START = EventFactory.createArrayBacked(QueryStart.class, callbacks -> (handler, server, sender, synchronizer) -> {
|
||||||
|
for (QueryStart callback : callbacks) {
|
||||||
|
callback.onLoginStart(handler, server, sender, synchronizer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event for the disconnection of the server login network handler.
|
||||||
|
*
|
||||||
|
* <p>No packets should be sent when this event is invoked.
|
||||||
|
*/
|
||||||
|
public static final Event<Disconnect> DISCONNECT = EventFactory.createArrayBacked(Disconnect.class, callbacks -> (handler, server) -> {
|
||||||
|
for (Disconnect callback : callbacks) {
|
||||||
|
callback.onLoginDisconnect(handler, server);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private ServerLoginConnectionEvents() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ServerLoginConnectionEvents#INIT
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Init {
|
||||||
|
void onLoginInit(ServerLoginPacketListenerImpl handler, MinecraftServer server);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ServerLoginConnectionEvents#QUERY_START
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface QueryStart {
|
||||||
|
void onLoginStart(ServerLoginPacketListenerImpl handler, MinecraftServer server, PacketSender sender, ServerLoginNetworking.LoginSynchronizer synchronizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ServerLoginConnectionEvents#DISCONNECT
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Disconnect {
|
||||||
|
void onLoginDisconnect(ServerLoginPacketListenerImpl handler, MinecraftServer server);
|
||||||
|
}
|
||||||
|
}
|
||||||
+196
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.networking.v1;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.network.ServerLoginPacketListenerImpl;
|
||||||
|
import com.seibel.lod.forge.fabric.api.client.networking.v1.ClientLoginNetworking;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.server.ServerNetworkingImpl;
|
||||||
|
import com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor.ServerLoginNetworkHandlerAccessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offers access to login stage server-side networking functionalities.
|
||||||
|
*
|
||||||
|
* <p>Server-side networking functionalities include receiving serverbound query responses and sending clientbound query requests.
|
||||||
|
*
|
||||||
|
* @see ServerPlayNetworking
|
||||||
|
* @see ClientLoginNetworking
|
||||||
|
*/
|
||||||
|
public final class ServerLoginNetworking {
|
||||||
|
/**
|
||||||
|
* Registers a handler to a query response channel.
|
||||||
|
* A global receiver is registered to all connections, in the present and future.
|
||||||
|
*
|
||||||
|
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
|
||||||
|
* Use {@link #unregisterGlobalReceiver(ResourceLocation)} to unregister the existing handler.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @param channelHandler the handler
|
||||||
|
* @return false if a handler is already registered to the channel
|
||||||
|
* @see ServerLoginNetworking#unregisterGlobalReceiver(ResourceLocation)
|
||||||
|
* @see ServerLoginNetworking#registerReceiver(ServerLoginPacketListenerImpl, ResourceLocation, LoginQueryResponseHandler)
|
||||||
|
*/
|
||||||
|
public static boolean registerGlobalReceiver(ResourceLocation channelName, LoginQueryResponseHandler channelHandler) {
|
||||||
|
return ServerNetworkingImpl.LOGIN.registerGlobalReceiver(channelName, channelHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the handler of a query response channel.
|
||||||
|
* A global receiver is registered to all connections, in the present and future.
|
||||||
|
*
|
||||||
|
* <p>The {@code channel} is guaranteed not to have a handler after this call.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @return the previous handler, or {@code null} if no handler was bound to the channel
|
||||||
|
* @see ServerLoginNetworking#registerGlobalReceiver(ResourceLocation, LoginQueryResponseHandler)
|
||||||
|
* @see ServerLoginNetworking#unregisterReceiver(ServerLoginPacketListenerImpl, ResourceLocation)
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static ServerLoginNetworking.LoginQueryResponseHandler unregisterGlobalReceiver(ResourceLocation channelName) {
|
||||||
|
return ServerNetworkingImpl.LOGIN.unregisterGlobalReceiver(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all channel names which global receivers are registered for.
|
||||||
|
* A global receiver is registered to all connections, in the present and future.
|
||||||
|
*
|
||||||
|
* @return all channel names which global receivers are registered for.
|
||||||
|
*/
|
||||||
|
public static Set<ResourceLocation> getGlobalReceivers() {
|
||||||
|
return ServerNetworkingImpl.LOGIN.getChannels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a handler to a query response channel.
|
||||||
|
*
|
||||||
|
* <p>If a handler is already registered to the {@code channelName}, this method will return {@code false}, and no change will be made.
|
||||||
|
* Use {@link #unregisterReceiver(ServerLoginPacketListenerImpl, ResourceLocation)} to unregister the existing handler.
|
||||||
|
*
|
||||||
|
* @param networkHandler the handler
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @param responseHandler the handler
|
||||||
|
* @return false if a handler is already registered to the channel name
|
||||||
|
*/
|
||||||
|
public static boolean registerReceiver(ServerLoginPacketListenerImpl networkHandler, ResourceLocation channelName, LoginQueryResponseHandler responseHandler) {
|
||||||
|
Objects.requireNonNull(networkHandler, "Network handler cannot be null");
|
||||||
|
|
||||||
|
return ServerNetworkingImpl.getAddon(networkHandler).registerChannel(channelName, responseHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the handler of a query response channel.
|
||||||
|
*
|
||||||
|
* <p>The {@code channelName} is guaranteed not to have a handler after this call.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @return the previous handler, or {@code null} if no handler was bound to the channel name
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static ServerLoginNetworking.LoginQueryResponseHandler unregisterReceiver(ServerLoginPacketListenerImpl networkHandler, ResourceLocation channelName) {
|
||||||
|
Objects.requireNonNull(networkHandler, "Network handler cannot be null");
|
||||||
|
|
||||||
|
return ServerNetworkingImpl.getAddon(networkHandler).unregisterChannel(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the <i>Minecraft</i> Server of a server login network handler.
|
||||||
|
*
|
||||||
|
* @param handler the server login network handler
|
||||||
|
*/
|
||||||
|
public static MinecraftServer getServer(ServerLoginPacketListenerImpl handler) {
|
||||||
|
Objects.requireNonNull(handler, "Network handler cannot be null");
|
||||||
|
|
||||||
|
return ((ServerLoginNetworkHandlerAccessor) handler).getServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerLoginNetworking() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface LoginQueryResponseHandler {
|
||||||
|
/**
|
||||||
|
* Handles an incoming query response from a client.
|
||||||
|
*
|
||||||
|
* <p>This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}.
|
||||||
|
* Modification to the game should be {@linkplain net.minecraft.util.thread.BlockableEventLoop#submit(Runnable) scheduled} using the provided Minecraft client instance.
|
||||||
|
*
|
||||||
|
* <p><b>Whether the client understood the query should be checked before reading from the payload of the packet.</b>
|
||||||
|
* @param server the server
|
||||||
|
* @param handler the network handler that received this packet, representing the player/client who sent the response
|
||||||
|
* @param understood whether the client understood the packet
|
||||||
|
* @param buf the payload of the packet
|
||||||
|
* @param synchronizer the synchronizer which may be used to delay log-in till a {@link Future} is completed.
|
||||||
|
* @param responseSender the packet sender
|
||||||
|
*/
|
||||||
|
void receive(MinecraftServer server, ServerLoginPacketListenerImpl handler, boolean understood, FriendlyByteBuf buf, LoginSynchronizer synchronizer, PacketSender responseSender);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows blocking client log-in until all all futures passed into {@link LoginSynchronizer#waitFor(Future)} are completed.
|
||||||
|
*
|
||||||
|
* @apiNote this interface is not intended to be implemented by users of api.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface LoginSynchronizer {
|
||||||
|
/**
|
||||||
|
* Allows blocking client log-in until the {@code future} is {@link Future#isDone() done}.
|
||||||
|
*
|
||||||
|
* <p>Since packet reception happens on netty's event loops, this allows handlers to
|
||||||
|
* perform logic on the Server Thread, etc. For instance, a handler can prepare an
|
||||||
|
* upcoming query request or check necessary login data on the server thread.</p>
|
||||||
|
*
|
||||||
|
* <p>Here is an example where the player log-in is blocked so that a credential check and
|
||||||
|
* building of a followup query request can be performed properly on the logical server
|
||||||
|
* thread before the player successfully logs in:
|
||||||
|
* <pre>{@code
|
||||||
|
* ServerLoginNetworking.registerGlobalReceiver(CHECK_CHANNEL, (server, handler, understood, buf, synchronizer, responseSender) -> {
|
||||||
|
* if (!understood) {
|
||||||
|
* handler.disconnect(new LiteralText("Only accept clients that can check!"));
|
||||||
|
* return;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* String checkMessage = buf.readString(32767);
|
||||||
|
*
|
||||||
|
* // Just send the CompletableFuture returned by the server's submit method
|
||||||
|
* synchronizer.waitFor(server.submit(() -> {
|
||||||
|
* LoginInfoChecker checker = LoginInfoChecker.get(server);
|
||||||
|
*
|
||||||
|
* if (!checker.check(handler.getConnectionInfo(), checkMessage)) {
|
||||||
|
* handler.disconnect(new LiteralText("Invalid credentials!"));
|
||||||
|
* return;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* responseSender.send(UPCOMING_CHECK, checker.buildSecondQueryPacket(handler, checkMessage));
|
||||||
|
* }));
|
||||||
|
* });
|
||||||
|
* }</pre>
|
||||||
|
* Usually it is enough to pass the return value for {@link net.minecraft.util.thread.BlockableEventLoop#submit(Runnable)} for {@code future}.</p>
|
||||||
|
*
|
||||||
|
* @param future the future that must be done before the player can log in
|
||||||
|
*/
|
||||||
|
void waitFor(Future<?> future);
|
||||||
|
}
|
||||||
|
}
|
||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.networking.v1;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.Event;
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.EventFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offers access to events related to the connection to a client on a logical server while a client is in game.
|
||||||
|
*/
|
||||||
|
public final class ServerPlayConnectionEvents {
|
||||||
|
/**
|
||||||
|
* Event indicating a connection entered the PLAY state, ready for registering channel handlers.
|
||||||
|
*
|
||||||
|
* @see ServerPlayNetworking#registerReceiver(ServerGamePacketListenerImpl, ResourceLocation, ServerPlayNetworking.PlayChannelHandler)
|
||||||
|
*/
|
||||||
|
public static final Event<Init> INIT = EventFactory.createArrayBacked(Init.class, callbacks -> (handler, server) -> {
|
||||||
|
for (Init callback : callbacks) {
|
||||||
|
callback.onPlayInit(handler, server);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event for notification when the server play network handler is ready to send packets to the client.
|
||||||
|
*
|
||||||
|
* <p>At this stage, the network handler is ready to send packets to the client.
|
||||||
|
*/
|
||||||
|
public static final Event<Join> JOIN = EventFactory.createArrayBacked(Join.class, callbacks -> (handler, sender, server) -> {
|
||||||
|
for (Join callback : callbacks) {
|
||||||
|
callback.onPlayReady(handler, sender, server);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event for the disconnection of the server play network handler.
|
||||||
|
*
|
||||||
|
* <p>No packets should be sent when this event is invoked.
|
||||||
|
*/
|
||||||
|
public static final Event<Disconnect> DISCONNECT = EventFactory.createArrayBacked(Disconnect.class, callbacks -> (handler, server) -> {
|
||||||
|
for (Disconnect callback : callbacks) {
|
||||||
|
callback.onPlayDisconnect(handler, server);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private ServerPlayConnectionEvents() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Init {
|
||||||
|
void onPlayInit(ServerGamePacketListenerImpl handler, MinecraftServer server);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Join {
|
||||||
|
void onPlayReady(ServerGamePacketListenerImpl handler, PacketSender sender, MinecraftServer server);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Disconnect {
|
||||||
|
void onPlayDisconnect(ServerGamePacketListenerImpl handler, MinecraftServer server);
|
||||||
|
}
|
||||||
|
}
|
||||||
+295
@@ -0,0 +1,295 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.networking.v1;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||||
|
import com.seibel.lod.forge.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.server.ServerNetworkingImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offers access to play stage server-side networking functionalities.
|
||||||
|
*
|
||||||
|
* <p>Server-side networking functionalities include receiving serverbound packets, sending clientbound packets, and events related to server-side network handlers.
|
||||||
|
*
|
||||||
|
* <p>This class should be only used for the logical server.
|
||||||
|
*
|
||||||
|
* @see ServerLoginNetworking
|
||||||
|
* @see ClientPlayNetworking
|
||||||
|
*/
|
||||||
|
public final class ServerPlayNetworking {
|
||||||
|
/**
|
||||||
|
* Registers a handler to a channel.
|
||||||
|
* A global receiver is registered to all connections, in the present and future.
|
||||||
|
*
|
||||||
|
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
|
||||||
|
* Use {@link #unregisterReceiver(ServerGamePacketListenerImpl, ResourceLocation)} to unregister the existing handler.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @param channelHandler the handler
|
||||||
|
* @return false if a handler is already registered to the channel
|
||||||
|
* @see ServerPlayNetworking#unregisterGlobalReceiver(ResourceLocation)
|
||||||
|
* @see ServerPlayNetworking#registerReceiver(ServerGamePacketListenerImpl, ResourceLocation, PlayChannelHandler)
|
||||||
|
*/
|
||||||
|
public static boolean registerGlobalReceiver(ResourceLocation channelName, PlayChannelHandler channelHandler) {
|
||||||
|
return ServerNetworkingImpl.PLAY.registerGlobalReceiver(channelName, channelHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the handler of a channel.
|
||||||
|
* A global receiver is registered to all connections, in the present and future.
|
||||||
|
*
|
||||||
|
* <p>The {@code channel} is guaranteed not to have a handler after this call.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @return the previous handler, or {@code null} if no handler was bound to the channel
|
||||||
|
* @see ServerPlayNetworking#registerGlobalReceiver(ResourceLocation, PlayChannelHandler)
|
||||||
|
* @see ServerPlayNetworking#unregisterReceiver(ServerGamePacketListenerImpl, ResourceLocation)
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static PlayChannelHandler unregisterGlobalReceiver(ResourceLocation channelName) {
|
||||||
|
return ServerNetworkingImpl.PLAY.unregisterGlobalReceiver(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all channel names which global receivers are registered for.
|
||||||
|
* A global receiver is registered to all connections, in the present and future.
|
||||||
|
*
|
||||||
|
* @return all channel names which global receivers are registered for.
|
||||||
|
*/
|
||||||
|
public static Set<ResourceLocation> getGlobalReceivers() {
|
||||||
|
return ServerNetworkingImpl.PLAY.getChannels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a handler to a channel.
|
||||||
|
* This method differs from {@link ServerPlayNetworking#registerGlobalReceiver(ResourceLocation, PlayChannelHandler)} since
|
||||||
|
* the channel handler will only be applied to the player represented by the {@link ServerGamePacketListenerImpl}.
|
||||||
|
*
|
||||||
|
* <p>For example, if you only register a receiver using this method when a {@linkplain ServerLoginNetworking#registerGlobalReceiver(ResourceLocation, ServerLoginNetworking.LoginQueryResponseHandler)}
|
||||||
|
* login response has been received, you should use {@link ServerPlayConnectionEvents#INIT} to register the channel handler.
|
||||||
|
*
|
||||||
|
* <p>If a handler is already registered to the {@code channelName}, this method will return {@code false}, and no change will be made.
|
||||||
|
* Use {@link #unregisterReceiver(ServerGamePacketListenerImpl, ResourceLocation)} to unregister the existing handler.
|
||||||
|
*
|
||||||
|
* @param networkHandler the handler
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @param channelHandler the handler
|
||||||
|
* @return false if a handler is already registered to the channel name
|
||||||
|
* @see ServerPlayConnectionEvents#INIT
|
||||||
|
*/
|
||||||
|
public static boolean registerReceiver(ServerGamePacketListenerImpl networkHandler, ResourceLocation channelName, PlayChannelHandler channelHandler) {
|
||||||
|
Objects.requireNonNull(networkHandler, "Network handler cannot be null");
|
||||||
|
|
||||||
|
return ServerNetworkingImpl.getAddon(networkHandler).registerChannel(channelName, channelHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the handler of a channel.
|
||||||
|
*
|
||||||
|
* <p>The {@code channelName} is guaranteed not to have a handler after this call.
|
||||||
|
*
|
||||||
|
* @param channelName the id of the channel
|
||||||
|
* @return the previous handler, or {@code null} if no handler was bound to the channel name
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static PlayChannelHandler unregisterReceiver(ServerGamePacketListenerImpl networkHandler, ResourceLocation channelName) {
|
||||||
|
Objects.requireNonNull(networkHandler, "Network handler cannot be null");
|
||||||
|
|
||||||
|
return ServerNetworkingImpl.getAddon(networkHandler).unregisterChannel(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the channel names that the server can receive packets on.
|
||||||
|
*
|
||||||
|
* @param player the player
|
||||||
|
* @return All the channel names that the server can receive packets on
|
||||||
|
*/
|
||||||
|
public static Set<ResourceLocation> getReceived(ServerPlayer player) {
|
||||||
|
Objects.requireNonNull(player, "Server player entity cannot be null");
|
||||||
|
|
||||||
|
return getReceived(player.connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the channel names that the server can receive packets on.
|
||||||
|
*
|
||||||
|
* @param handler the network handler
|
||||||
|
* @return All the channel names that the server can receive packets on
|
||||||
|
*/
|
||||||
|
public static Set<ResourceLocation> getReceived(ServerGamePacketListenerImpl handler) {
|
||||||
|
Objects.requireNonNull(handler, "Server play network handler cannot be null");
|
||||||
|
|
||||||
|
return ServerNetworkingImpl.getAddon(handler).getReceivableChannels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all channel names that the connected client declared the ability to receive a packets on.
|
||||||
|
*
|
||||||
|
* @param player the player
|
||||||
|
* @return All the channel names the connected client declared the ability to receive a packets on
|
||||||
|
*/
|
||||||
|
public static Set<ResourceLocation> getSendable(ServerPlayer player) {
|
||||||
|
Objects.requireNonNull(player, "Server player entity cannot be null");
|
||||||
|
|
||||||
|
return getSendable(player.connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all channel names that a the connected client declared the ability to receive a packets on.
|
||||||
|
*
|
||||||
|
* @param handler the network handler
|
||||||
|
* @return True if the connected client has declared the ability to receive a packet on the specified channel
|
||||||
|
*/
|
||||||
|
public static Set<ResourceLocation> getSendable(ServerGamePacketListenerImpl handler) {
|
||||||
|
Objects.requireNonNull(handler, "Server play network handler cannot be null");
|
||||||
|
|
||||||
|
return ServerNetworkingImpl.getAddon(handler).getSendableChannels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the connected client declared the ability to receive a packet on a specified channel name.
|
||||||
|
*
|
||||||
|
* @param player the player
|
||||||
|
* @param channelName the channel name
|
||||||
|
* @return True if the connected client has declared the ability to receive a packet on the specified channel
|
||||||
|
*/
|
||||||
|
public static boolean canSend(ServerPlayer player, ResourceLocation channelName) {
|
||||||
|
Objects.requireNonNull(player, "Server player entity cannot be null");
|
||||||
|
|
||||||
|
return canSend(player.connection, channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the connected client declared the ability to receive a packet on a specified channel name.
|
||||||
|
*
|
||||||
|
* @param handler the network handler
|
||||||
|
* @param channelName the channel name
|
||||||
|
* @return True if the connected client has declared the ability to receive a packet on the specified channel
|
||||||
|
*/
|
||||||
|
public static boolean canSend(ServerGamePacketListenerImpl handler, ResourceLocation channelName) {
|
||||||
|
Objects.requireNonNull(handler, "Server play network handler cannot be null");
|
||||||
|
Objects.requireNonNull(channelName, "Channel name cannot be null");
|
||||||
|
|
||||||
|
return ServerNetworkingImpl.getAddon(handler).getSendableChannels().contains(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a packet which may be sent to a the connected client.
|
||||||
|
*
|
||||||
|
* @param channelName the channel name
|
||||||
|
* @param buf the packet byte buf which represents the payload of the packet
|
||||||
|
* @return a new packet
|
||||||
|
*/
|
||||||
|
public static Packet<?> createS2CPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
|
||||||
|
Objects.requireNonNull(channelName, "Channel cannot be null");
|
||||||
|
Objects.requireNonNull(buf, "Buf cannot be null");
|
||||||
|
|
||||||
|
return ServerNetworkingImpl.createPlayC2SPacket(channelName, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the packet sender which sends packets to the connected client.
|
||||||
|
*
|
||||||
|
* @param player the player
|
||||||
|
* @return the packet sender
|
||||||
|
*/
|
||||||
|
public static PacketSender getSender(ServerPlayer player) {
|
||||||
|
Objects.requireNonNull(player, "Server player entity cannot be null");
|
||||||
|
|
||||||
|
return getSender(player.connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the packet sender which sends packets to the connected client.
|
||||||
|
*
|
||||||
|
* @param handler the network handler, representing the connection to the player/client
|
||||||
|
* @return the packet sender
|
||||||
|
*/
|
||||||
|
public static PacketSender getSender(ServerGamePacketListenerImpl handler) {
|
||||||
|
Objects.requireNonNull(handler, "Server play network handler cannot be null");
|
||||||
|
|
||||||
|
return ServerNetworkingImpl.getAddon(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a packet to a player.
|
||||||
|
*
|
||||||
|
* @param player the player to send the packet to
|
||||||
|
* @param channelName the channel of the packet
|
||||||
|
* @param buf the payload of the packet.
|
||||||
|
*/
|
||||||
|
public static void send(ServerPlayer player, ResourceLocation channelName, FriendlyByteBuf buf) {
|
||||||
|
Objects.requireNonNull(player, "Server player entity cannot be null");
|
||||||
|
Objects.requireNonNull(channelName, "Channel name cannot be null");
|
||||||
|
Objects.requireNonNull(buf, "Packet byte buf cannot be null");
|
||||||
|
|
||||||
|
player.connection.send(createS2CPacket(channelName, buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the <i>Minecraft</i> Server of a server play network handler.
|
||||||
|
*
|
||||||
|
* @param handler the server play network handler
|
||||||
|
*/
|
||||||
|
public static MinecraftServer getServer(ServerGamePacketListenerImpl handler) {
|
||||||
|
Objects.requireNonNull(handler, "Network handler cannot be null");
|
||||||
|
|
||||||
|
return handler.player.server;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerPlayNetworking() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface PlayChannelHandler {
|
||||||
|
/**
|
||||||
|
* Handles an incoming packet.
|
||||||
|
*
|
||||||
|
* <p>This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}.
|
||||||
|
* Modification to the game should be {@linkplain net.minecraft.util.thread.BlockableEventLoop#submit(Runnable) scheduled} using the provided Minecraft server instance.
|
||||||
|
*
|
||||||
|
* <p>An example usage of this is to create an explosion where the player is looking:
|
||||||
|
* <pre>{@code
|
||||||
|
* ServerPlayNetworking.registerReceiver(new Identifier("mymod", "boom"), (server, player, handler, buf, responseSender) -&rt; {
|
||||||
|
* boolean fire = buf.readBoolean();
|
||||||
|
*
|
||||||
|
* // All operations on the server or world must be executed on the server thread
|
||||||
|
* server.execute(() -&rt; {
|
||||||
|
* ModPacketHandler.createExplosion(player, fire);
|
||||||
|
* });
|
||||||
|
* });
|
||||||
|
* }</pre>
|
||||||
|
* @param server the server
|
||||||
|
* @param player the player
|
||||||
|
* @param handler the network handler that received this packet, representing the player/client who sent the packet
|
||||||
|
* @param buf the payload of the packet
|
||||||
|
* @param responseSender the packet sender
|
||||||
|
*/
|
||||||
|
void receive(MinecraftServer server, ServerPlayer player, ServerGamePacketListenerImpl handler, FriendlyByteBuf buf, PacketSender responseSender);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Networking API, version 1.
|
||||||
|
*
|
||||||
|
* <p>For login stage networking see {@link net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking}.
|
||||||
|
* For play stage networking see {@link net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking}.
|
||||||
|
*
|
||||||
|
* <p>For events related to the connection to a client see {@link net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents} for login stage
|
||||||
|
* or {@link net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents} for play stage.
|
||||||
|
*
|
||||||
|
* <p>For events related to the ability of a client to receive packets on a channel of a specific name see {@link net.fabricmc.fabric.api.networking.v1.S2CPlayChannelEvents}.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.networking.v1;
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a function that accepts an boolean-valued argument and produces a result.
|
||||||
|
*
|
||||||
|
* <p>This is the {@code boolean}-consuming primitive specialization for {@link java.util.function.Function}.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface BooleanFunction<R> {
|
||||||
|
/**
|
||||||
|
* Applies this function to the given argument.
|
||||||
|
*
|
||||||
|
* @param value the function argument
|
||||||
|
* @return the function result
|
||||||
|
*/
|
||||||
|
R apply(boolean value);
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NBT type ID constants. Useful for filtering by value type in a few cases.
|
||||||
|
*
|
||||||
|
* <p>For the current list of types, check with {@link NbtElement#TYPES}.
|
||||||
|
*
|
||||||
|
* @see NbtCompound#contains(String, int)
|
||||||
|
* @see net.minecraft.nbt.NbtTypes#byId(int)
|
||||||
|
*/
|
||||||
|
public final class NbtType {
|
||||||
|
public static final int END = 0;
|
||||||
|
public static final int BYTE = 1;
|
||||||
|
public static final int SHORT = 2;
|
||||||
|
public static final int INT = 3;
|
||||||
|
public static final int LONG = 4;
|
||||||
|
public static final int FLOAT = 5;
|
||||||
|
public static final int DOUBLE = 6;
|
||||||
|
public static final int BYTE_ARRAY = 7;
|
||||||
|
public static final int STRING = 8;
|
||||||
|
public static final int LIST = 9;
|
||||||
|
public static final int COMPOUND = 10;
|
||||||
|
public static final int INT_ARRAY = 11;
|
||||||
|
public static final int LONG_ARRAY = 12;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any numeric value: byte, short, int, long, float, double.
|
||||||
|
*
|
||||||
|
* @see NbtCompound#contains(String, int)
|
||||||
|
*/
|
||||||
|
public static final int NUMBER = 99;
|
||||||
|
|
||||||
|
private NbtType() { }
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.api.util;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a boolean value which can be true, false or refer to a default value.
|
||||||
|
*/
|
||||||
|
public enum TriState {
|
||||||
|
/**
|
||||||
|
* Represents the boolean value of {@code false}.
|
||||||
|
*/
|
||||||
|
FALSE,
|
||||||
|
/**
|
||||||
|
* Represents a value that refers to a "default" value, often as a fallback.
|
||||||
|
*/
|
||||||
|
DEFAULT,
|
||||||
|
/**
|
||||||
|
* Represents the boolean value of {@code true}.
|
||||||
|
*/
|
||||||
|
TRUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the corresponding tri-state from a boolean value.
|
||||||
|
*
|
||||||
|
* @param bool the boolean value
|
||||||
|
* @return {@link TriState#TRUE} or {@link TriState#FALSE} depending on the value of the boolean.
|
||||||
|
*/
|
||||||
|
public static TriState of(boolean bool) {
|
||||||
|
return bool ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a tri-state from a nullable boxed boolean.
|
||||||
|
*
|
||||||
|
* @param bool the boolean value
|
||||||
|
* @return {@link TriState#DEFAULT} if {@code null}.
|
||||||
|
* Otherwise {@link TriState#TRUE} or {@link TriState#FALSE} depending on the value of the boolean.
|
||||||
|
*/
|
||||||
|
public static TriState of(@Nullable Boolean bool) {
|
||||||
|
return bool == null ? DEFAULT : of(bool.booleanValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the tri-state.
|
||||||
|
*
|
||||||
|
* @return true if the tri-state is {@link TriState#TRUE}.
|
||||||
|
* Otherwise false.
|
||||||
|
*/
|
||||||
|
public boolean get() {
|
||||||
|
return this == TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the tri-state as a boxed, nullable boolean.
|
||||||
|
*
|
||||||
|
* @return {@code null} if {@link TriState#DEFAULT}.
|
||||||
|
* Otherwise {@code true} if {@link TriState#TRUE} or {@code false} if {@link TriState#FALSE}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public Boolean getBoxed() {
|
||||||
|
return this == DEFAULT ? null : this.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of this tri-state.
|
||||||
|
* If the value is {@link TriState#DEFAULT} then use the supplied value.
|
||||||
|
*
|
||||||
|
* @param value the value to fallback to
|
||||||
|
* @return the value of the tri-state or the supplied value if {@link TriState#DEFAULT}.
|
||||||
|
*/
|
||||||
|
public boolean orElse(boolean value) {
|
||||||
|
return this == DEFAULT ? value : this.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of this tri-state.
|
||||||
|
* If the value is {@link TriState#DEFAULT} then use the supplied value.
|
||||||
|
*
|
||||||
|
* @param supplier the supplier used to get the value to fallback to
|
||||||
|
* @return the value of the tri-state or the value of the supplier if the tri-state is {@link TriState#DEFAULT}.
|
||||||
|
*/
|
||||||
|
public boolean orElseGet(BooleanSupplier supplier) {
|
||||||
|
return this == DEFAULT ? supplier.getAsBoolean() : this.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the boolean value of this tri-state if it is {@link TriState#TRUE} or {@link TriState#FALSE}.
|
||||||
|
*
|
||||||
|
* @param mapper the mapper to use
|
||||||
|
* @param <T> the type of object being supplier by the mapper
|
||||||
|
* @return an optional containing the mapped value; {@link Optional#empty()} if the tri-state is {@link TriState#DEFAULT} or the value provided by the mapper is {@code null}.
|
||||||
|
*/
|
||||||
|
public <T> Optional<T> map(BooleanFunction<@Nullable ? extends T> mapper) {
|
||||||
|
Objects.requireNonNull(mapper, "Mapper function cannot be null");
|
||||||
|
|
||||||
|
if (this == DEFAULT) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.ofNullable(mapper.apply(this.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of this tri-state, or throws an exception if this tri-state's value is {@link TriState#DEFAULT}.
|
||||||
|
*
|
||||||
|
* @param exceptionSupplier the supplying function that produces an exception to be thrown
|
||||||
|
* @param <X> Type of the exception to be thrown
|
||||||
|
* @return the value
|
||||||
|
* @throws X if the value is {@link TriState#DEFAULT}
|
||||||
|
*/
|
||||||
|
public <X extends Throwable> boolean orElseThrow(Supplier<X> exceptionSupplier) throws X {
|
||||||
|
if (this != DEFAULT) {
|
||||||
|
return this.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw exceptionSupplier.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
+130
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.base.event;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.Event;
|
||||||
|
|
||||||
|
class ArrayBackedEvent<T> extends Event<T> {
|
||||||
|
static final Logger LOGGER = LoggerFactory.getLogger("fabric-api-base");
|
||||||
|
|
||||||
|
private final Function<T[], T> invokerFactory;
|
||||||
|
private final Object lock = new Object();
|
||||||
|
private T[] handlers;
|
||||||
|
/**
|
||||||
|
* Registered event phases.
|
||||||
|
*/
|
||||||
|
private final Map<ResourceLocation, EventPhaseData<T>> phases = new LinkedHashMap<>();
|
||||||
|
/**
|
||||||
|
* Phases sorted in the correct dependency order.
|
||||||
|
*/
|
||||||
|
private final List<EventPhaseData<T>> sortedPhases = new ArrayList<>();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ArrayBackedEvent(Class<? super T> type, Function<T[], T> invokerFactory) {
|
||||||
|
this.invokerFactory = invokerFactory;
|
||||||
|
this.handlers = (T[]) Array.newInstance(type, 0);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
this.invoker = invokerFactory.apply(handlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void register(T listener) {
|
||||||
|
register(DEFAULT_PHASE, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void register(ResourceLocation phaseResourceLocation, T listener) {
|
||||||
|
Objects.requireNonNull(phaseResourceLocation, "Tried to register a listener for a null phase!");
|
||||||
|
Objects.requireNonNull(listener, "Tried to register a null listener!");
|
||||||
|
|
||||||
|
synchronized (lock) {
|
||||||
|
getOrCreatePhase(phaseResourceLocation, true).addListener(listener);
|
||||||
|
rebuildInvoker(handlers.length + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private EventPhaseData<T> getOrCreatePhase(ResourceLocation id, boolean sortIfCreate) {
|
||||||
|
EventPhaseData<T> phase = phases.get(id);
|
||||||
|
|
||||||
|
if (phase == null) {
|
||||||
|
phase = new EventPhaseData<>(id, handlers.getClass().getComponentType());
|
||||||
|
phases.put(id, phase);
|
||||||
|
sortedPhases.add(phase);
|
||||||
|
|
||||||
|
if (sortIfCreate) {
|
||||||
|
PhaseSorting.sortPhases(sortedPhases);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return phase;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rebuildInvoker(int newLength) {
|
||||||
|
// Rebuild handlers.
|
||||||
|
if (sortedPhases.size() == 1) {
|
||||||
|
// Special case with a single phase: use the array of the phase directly.
|
||||||
|
handlers = sortedPhases.get(0).listeners;
|
||||||
|
} else {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
T[] newHandlers = (T[]) Array.newInstance(handlers.getClass().getComponentType(), newLength);
|
||||||
|
int newHandlersIndex = 0;
|
||||||
|
|
||||||
|
for (EventPhaseData<T> existingPhase : sortedPhases) {
|
||||||
|
int length = existingPhase.listeners.length;
|
||||||
|
System.arraycopy(existingPhase.listeners, 0, newHandlers, newHandlersIndex, length);
|
||||||
|
newHandlersIndex += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers = newHandlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild invoker.
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addPhaseOrdering(ResourceLocation firstPhase, ResourceLocation secondPhase) {
|
||||||
|
Objects.requireNonNull(firstPhase, "Tried to add an ordering for a null phase.");
|
||||||
|
Objects.requireNonNull(secondPhase, "Tried to add an ordering for a null phase.");
|
||||||
|
if (firstPhase.equals(secondPhase)) throw new IllegalArgumentException("Tried to add a phase that depends on itself.");
|
||||||
|
|
||||||
|
synchronized (lock) {
|
||||||
|
EventPhaseData<T> first = getOrCreatePhase(firstPhase, false);
|
||||||
|
EventPhaseData<T> second = getOrCreatePhase(secondPhase, false);
|
||||||
|
first.subsequentPhases.add(second);
|
||||||
|
second.previousPhases.add(first);
|
||||||
|
PhaseSorting.sortPhases(this.sortedPhases);
|
||||||
|
rebuildInvoker(handlers.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.base.event;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
import com.seibel.lod.forge.fabric.api.event.Event;
|
||||||
|
|
||||||
|
public final class EventFactoryImpl {
|
||||||
|
private static final List<ArrayBackedEvent<?>> ARRAY_BACKED_EVENTS = new ArrayList<>();
|
||||||
|
|
||||||
|
private EventFactoryImpl() { }
|
||||||
|
|
||||||
|
public static void invalidate() {
|
||||||
|
ARRAY_BACKED_EVENTS.forEach(ArrayBackedEvent::update);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Event<T> createArrayBacked(Class<? super T> type, Function<T[], T> invokerFactory) {
|
||||||
|
ArrayBackedEvent<T> event = new ArrayBackedEvent<>(type, invokerFactory);
|
||||||
|
ARRAY_BACKED_EVENTS.add(event);
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ensureContainsDefault(ResourceLocation[] defaultPhases) {
|
||||||
|
for (ResourceLocation id : defaultPhases) {
|
||||||
|
if (id.equals(Event.DEFAULT_PHASE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("The event phases must contain Event.DEFAULT_PHASE.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ensureNoDuplicates(ResourceLocation[] defaultPhases) {
|
||||||
|
for (int i = 0; i < defaultPhases.length; ++i) {
|
||||||
|
for (int j = i+1; j < defaultPhases.length; ++j) {
|
||||||
|
if (defaultPhases[i].equals(defaultPhases[j])) {
|
||||||
|
throw new IllegalArgumentException("Duplicate event phase: " + defaultPhases[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code originally by sfPlayer1.
|
||||||
|
// Unfortunately, it's slightly slower than just passing an empty array in the first place.
|
||||||
|
private static <T> T buildEmptyInvoker(Class<T> handlerClass, Function<T[], T> invokerSetup) {
|
||||||
|
// find the functional interface method
|
||||||
|
Method funcIfMethod = null;
|
||||||
|
|
||||||
|
for (Method m : handlerClass.getMethods()) {
|
||||||
|
if ((m.getModifiers() & (Modifier.STRICT | Modifier.PRIVATE)) == 0) {
|
||||||
|
if (funcIfMethod != null) {
|
||||||
|
throw new IllegalStateException("Multiple virtual methods in " + handlerClass + "; cannot build empty invoker!");
|
||||||
|
}
|
||||||
|
|
||||||
|
funcIfMethod = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (funcIfMethod == null) {
|
||||||
|
throw new IllegalStateException("No virtual methods in " + handlerClass + "; cannot build empty invoker!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Object defValue = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// concert to mh, determine its type without the "this" reference
|
||||||
|
MethodHandle target = MethodHandles.lookup().unreflect(funcIfMethod);
|
||||||
|
MethodType type = target.type().dropParameterTypes(0, 1);
|
||||||
|
|
||||||
|
if (type.returnType() != void.class) {
|
||||||
|
// determine default return value by invoking invokerSetup.apply(T[0]) with all-jvm-default args (null for refs, false for boolean, etc.)
|
||||||
|
// explicitCastArguments is being used to cast Object=null to the jvm default value for the correct type
|
||||||
|
|
||||||
|
// construct method desc (TLjava/lang/Object;Ljava/lang/Object;...)R where T = invoker ref ("this"), R = invoker ret type and args 1+ are Object for each non-"this" invoker arg
|
||||||
|
MethodType objTargetType = MethodType.genericMethodType(type.parameterCount()).changeReturnType(type.returnType()).insertParameterTypes(0, target.type().parameterType(0));
|
||||||
|
// explicit cast to translate to the invoker args from Object to their real type, inferring jvm default values
|
||||||
|
MethodHandle objTarget = MethodHandles.explicitCastArguments(target, objTargetType);
|
||||||
|
|
||||||
|
// build invocation args with 0 = "this", 1+ = null
|
||||||
|
Object[] args = new Object[target.type().parameterCount()];
|
||||||
|
//noinspection unchecked
|
||||||
|
args[0] = invokerSetup.apply((T[]) Array.newInstance(handlerClass, 0));
|
||||||
|
|
||||||
|
// retrieve default by invoking invokerSetup.apply(T[0]).targetName(def,def,...)
|
||||||
|
defValue = objTarget.invokeWithArguments(args);
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw new RuntimeException(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object returnValue = defValue;
|
||||||
|
//noinspection unchecked
|
||||||
|
return (T) Proxy.newProxyInstance(EventFactoryImpl.class.getClassLoader(), new Class[]{handlerClass},
|
||||||
|
(proxy, method, args) -> returnValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.base.event;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data of an {@link ArrayBackedEvent} phase.
|
||||||
|
*/
|
||||||
|
class EventPhaseData<T> {
|
||||||
|
final ResourceLocation id;
|
||||||
|
T[] listeners;
|
||||||
|
final List<EventPhaseData<T>> subsequentPhases = new ArrayList<>();
|
||||||
|
final List<EventPhaseData<T>> previousPhases = new ArrayList<>();
|
||||||
|
int visitStatus = 0; // 0: not visited, 1: visiting, 2: visited
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
EventPhaseData(ResourceLocation id, Class<?> listenerClass) {
|
||||||
|
this.id = id;
|
||||||
|
this.listeners = (T[]) Array.newInstance(listenerClass, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addListener(T listener) {
|
||||||
|
int oldLength = listeners.length;
|
||||||
|
listeners = Arrays.copyOf(listeners, oldLength + 1);
|
||||||
|
listeners[oldLength] = listener;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.base.event;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains phase-sorting logic for {@link ArrayBackedEvent}.
|
||||||
|
*/
|
||||||
|
@ApiStatus.Internal
|
||||||
|
public class PhaseSorting {
|
||||||
|
@VisibleForTesting
|
||||||
|
public static boolean ENABLE_CYCLE_WARNING = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deterministically sort a list of phases.
|
||||||
|
* 1) Compute phase SCCs (i.e. cycles).
|
||||||
|
* 2) Sort phases by id within SCCs.
|
||||||
|
* 3) Sort SCCs with respect to each other by respecting constraints, and by id in case of a tie.
|
||||||
|
*/
|
||||||
|
static <T> void sortPhases(List<EventPhaseData<T>> sortedPhases) {
|
||||||
|
// FIRST KOSARAJU SCC VISIT
|
||||||
|
List<EventPhaseData<T>> toposort = new ArrayList<>(sortedPhases.size());
|
||||||
|
|
||||||
|
for (EventPhaseData<T> phase : sortedPhases) {
|
||||||
|
forwardVisit(phase, null, toposort);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearStatus(toposort);
|
||||||
|
Collections.reverse(toposort);
|
||||||
|
|
||||||
|
// SECOND KOSARAJU SCC VISIT
|
||||||
|
Map<EventPhaseData<T>, PhaseScc<T>> phaseToScc = new IdentityHashMap<>();
|
||||||
|
|
||||||
|
for (EventPhaseData<T> phase : toposort) {
|
||||||
|
if (phase.visitStatus == 0) {
|
||||||
|
List<EventPhaseData<T>> sccPhases = new ArrayList<>();
|
||||||
|
// Collect phases in SCC.
|
||||||
|
backwardVisit(phase, sccPhases);
|
||||||
|
// Sort phases by id.
|
||||||
|
sccPhases.sort(Comparator.comparing(p -> p.id));
|
||||||
|
// Mark phases as belonging to this SCC.
|
||||||
|
PhaseScc<T> scc = new PhaseScc<>(sccPhases);
|
||||||
|
|
||||||
|
for (EventPhaseData<T> phaseInScc : sccPhases) {
|
||||||
|
phaseToScc.put(phaseInScc, scc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearStatus(toposort);
|
||||||
|
|
||||||
|
// Build SCC graph
|
||||||
|
for (PhaseScc<T> scc : phaseToScc.values()) {
|
||||||
|
for (EventPhaseData<T> phase : scc.phases) {
|
||||||
|
for (EventPhaseData<T> subsequentPhase : phase.subsequentPhases) {
|
||||||
|
PhaseScc<T> subsequentScc = phaseToScc.get(subsequentPhase);
|
||||||
|
|
||||||
|
if (subsequentScc != scc) {
|
||||||
|
scc.subsequentSccs.add(subsequentScc);
|
||||||
|
subsequentScc.inDegree++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Order SCCs according to priorities. When there is a choice, use the SCC with the lowest id.
|
||||||
|
// The priority queue contains all SCCs that currently have 0 in-degree.
|
||||||
|
PriorityQueue<PhaseScc<T>> pq = new PriorityQueue<>(Comparator.comparing(scc -> scc.phases.get(0).id));
|
||||||
|
sortedPhases.clear();
|
||||||
|
|
||||||
|
for (PhaseScc<T> scc : phaseToScc.values()) {
|
||||||
|
if (scc.inDegree == 0) {
|
||||||
|
pq.add(scc);
|
||||||
|
// Prevent adding the same SCC multiple times, as phaseToScc may contain the same value multiple times.
|
||||||
|
scc.inDegree = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!pq.isEmpty()) {
|
||||||
|
PhaseScc<T> scc = pq.poll();
|
||||||
|
sortedPhases.addAll(scc.phases);
|
||||||
|
|
||||||
|
for (PhaseScc<T> subsequentScc : scc.subsequentSccs) {
|
||||||
|
subsequentScc.inDegree--;
|
||||||
|
|
||||||
|
if (subsequentScc.inDegree == 0) {
|
||||||
|
pq.add(subsequentScc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> void forwardVisit(EventPhaseData<T> phase, EventPhaseData<T> parent, List<EventPhaseData<T>> toposort) {
|
||||||
|
if (phase.visitStatus == 0) {
|
||||||
|
// Not yet visited.
|
||||||
|
phase.visitStatus = 1;
|
||||||
|
|
||||||
|
for (EventPhaseData<T> data : phase.subsequentPhases) {
|
||||||
|
forwardVisit(data, phase, toposort);
|
||||||
|
}
|
||||||
|
|
||||||
|
toposort.add(phase);
|
||||||
|
phase.visitStatus = 2;
|
||||||
|
} else if (phase.visitStatus == 1 && ENABLE_CYCLE_WARNING) {
|
||||||
|
// Already visiting, so we have found a cycle.
|
||||||
|
ArrayBackedEvent.LOGGER.warn(String.format(
|
||||||
|
"Event phase ordering conflict detected.%nEvent phase %s is ordered both before and after event phase %s.",
|
||||||
|
phase.id,
|
||||||
|
parent.id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> void clearStatus(List<EventPhaseData<T>> phases) {
|
||||||
|
for (EventPhaseData<T> phase : phases) {
|
||||||
|
phase.visitStatus = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> void backwardVisit(EventPhaseData<T> phase, List<EventPhaseData<T>> sccPhases) {
|
||||||
|
if (phase.visitStatus == 0) {
|
||||||
|
phase.visitStatus = 1;
|
||||||
|
sccPhases.add(phase);
|
||||||
|
|
||||||
|
for (EventPhaseData<T> data : phase.previousPhases) {
|
||||||
|
backwardVisit(data, sccPhases);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PhaseScc<T> {
|
||||||
|
final List<EventPhaseData<T>> phases;
|
||||||
|
final List<PhaseScc<T>> subsequentSccs = new ArrayList<>();
|
||||||
|
int inDegree = 0;
|
||||||
|
|
||||||
|
private PhaseScc(List<EventPhaseData<T>> phases) {
|
||||||
|
this.phases = phases;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+205
@@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import io.netty.util.AsciiString;
|
||||||
|
import io.netty.util.concurrent.Future;
|
||||||
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.PacketByteBufs;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.PacketSender;
|
||||||
|
import net.minecraft.ResourceLocationException;
|
||||||
|
import net.minecraft.network.Connection;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A network addon which is aware of the channels the other side may receive.
|
||||||
|
*
|
||||||
|
* @param <H> the channel handler type
|
||||||
|
*/
|
||||||
|
public abstract class AbstractChanneledNetworkAddon<H> extends AbstractNetworkAddon<H> implements PacketSender {
|
||||||
|
protected final Connection connection;
|
||||||
|
protected final GlobalReceiverRegistry<H> receiver;
|
||||||
|
protected final Set<ResourceLocation> sendableChannels;
|
||||||
|
protected final Set<ResourceLocation> sendableChannelsView;
|
||||||
|
|
||||||
|
protected AbstractChanneledNetworkAddon(GlobalReceiverRegistry<H> receiver, Connection connection, String description) {
|
||||||
|
this(receiver, connection, new HashSet<>(), description);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractChanneledNetworkAddon(GlobalReceiverRegistry<H> receiver, Connection connection, Set<ResourceLocation> sendableChannels, String description) {
|
||||||
|
super(receiver, description);
|
||||||
|
this.connection = connection;
|
||||||
|
this.receiver = receiver;
|
||||||
|
this.sendableChannels = sendableChannels;
|
||||||
|
this.sendableChannelsView = Collections.unmodifiableSet(sendableChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void lateInit();
|
||||||
|
|
||||||
|
protected void registerPendingChannels(ChannelInfoHolder holder) {
|
||||||
|
final Collection<ResourceLocation> pending = holder.getPendingChannelsNames();
|
||||||
|
|
||||||
|
if (!pending.isEmpty()) {
|
||||||
|
register(new ArrayList<>(pending));
|
||||||
|
pending.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// always supposed to handle async!
|
||||||
|
protected boolean handle(ResourceLocation channelName, FriendlyByteBuf originalBuf) {
|
||||||
|
this.logger.debug("Handling inbound packet from channel with name \"{}\"", channelName);
|
||||||
|
|
||||||
|
// Handle reserved packets
|
||||||
|
if (NetworkingImpl.REGISTER_CHANNEL.equals(channelName)) {
|
||||||
|
this.receiveRegistration(true, PacketByteBufs.slice(originalBuf));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NetworkingImpl.UNREGISTER_CHANNEL.equals(channelName)) {
|
||||||
|
this.receiveRegistration(false, PacketByteBufs.slice(originalBuf));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable H handler = this.getHandler(channelName);
|
||||||
|
|
||||||
|
if (handler == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FriendlyByteBuf buf = PacketByteBufs.slice(originalBuf);
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.receive(handler, buf);
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
this.logger.error("Encountered exception while handling in channel with name \"{}\"", channelName, ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void receive(H handler, FriendlyByteBuf buf);
|
||||||
|
|
||||||
|
protected void sendInitialChannelRegistrationPacket() {
|
||||||
|
final FriendlyByteBuf buf = this.createRegistrationPacket(this.getReceivableChannels());
|
||||||
|
|
||||||
|
if (buf != null) {
|
||||||
|
this.sendPacket(NetworkingImpl.REGISTER_CHANNEL, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected FriendlyByteBuf createRegistrationPacket(Collection<ResourceLocation> channels) {
|
||||||
|
if (channels.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
FriendlyByteBuf buf = PacketByteBufs.create();
|
||||||
|
boolean first = true;
|
||||||
|
|
||||||
|
for (ResourceLocation channel : channels) {
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
buf.writeByte(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.writeBytes(channel.toString().getBytes(StandardCharsets.US_ASCII));
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap in try with res (buf)
|
||||||
|
protected void receiveRegistration(boolean register, FriendlyByteBuf buf) {
|
||||||
|
List<ResourceLocation> ids = new ArrayList<>();
|
||||||
|
StringBuilder active = new StringBuilder();
|
||||||
|
|
||||||
|
while (buf.isReadable()) {
|
||||||
|
byte b = buf.readByte();
|
||||||
|
|
||||||
|
if (b != 0) {
|
||||||
|
active.append(AsciiString.b2c(b));
|
||||||
|
} else {
|
||||||
|
this.addId(ids, active);
|
||||||
|
active = new StringBuilder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addId(ids, active);
|
||||||
|
this.schedule(register ? () -> register(ids) : () -> unregister(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
void register(List<ResourceLocation> ids) {
|
||||||
|
this.sendableChannels.addAll(ids);
|
||||||
|
this.invokeRegisterEvent(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unregister(List<ResourceLocation> ids) {
|
||||||
|
this.sendableChannels.removeAll(ids);
|
||||||
|
this.invokeUnregisterEvent(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPacket(Packet<?> packet) {
|
||||||
|
Objects.requireNonNull(packet, "Packet cannot be null");
|
||||||
|
|
||||||
|
this.connection.send(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPacket(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> callback) {
|
||||||
|
Objects.requireNonNull(packet, "Packet cannot be null");
|
||||||
|
|
||||||
|
this.connection.send(packet, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules a task to run on the main thread.
|
||||||
|
*/
|
||||||
|
protected abstract void schedule(Runnable task);
|
||||||
|
|
||||||
|
protected abstract void invokeRegisterEvent(List<ResourceLocation> ids);
|
||||||
|
|
||||||
|
protected abstract void invokeUnregisterEvent(List<ResourceLocation> ids);
|
||||||
|
|
||||||
|
private void addId(List<ResourceLocation> ids, StringBuilder sb) {
|
||||||
|
String literal = sb.toString();
|
||||||
|
|
||||||
|
try {
|
||||||
|
ids.add(new ResourceLocation(literal));
|
||||||
|
} catch (ResourceLocationException ex) {
|
||||||
|
this.logger.warn("Received invalid channel identifier \"{}\" from connection {}", literal, this.connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<ResourceLocation> getSendableChannels() {
|
||||||
|
return this.sendableChannelsView;
|
||||||
|
}
|
||||||
|
}
|
||||||
+143
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A network addon is a simple abstraction to hold information about a player's registered channels.
|
||||||
|
*
|
||||||
|
* @param <H> the channel handler type
|
||||||
|
*/
|
||||||
|
public abstract class AbstractNetworkAddon<H> {
|
||||||
|
protected final GlobalReceiverRegistry<H> receiver;
|
||||||
|
protected final Logger logger;
|
||||||
|
// A lock is used due to possible access on netty's event loops and game thread at same times such as during dynamic registration
|
||||||
|
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||||
|
// Sync map should be fine as there is little read write competition
|
||||||
|
// All access to this map is guarded by the lock
|
||||||
|
private final Map<ResourceLocation, H> handlers = new HashMap<>();
|
||||||
|
private final AtomicBoolean disconnected = new AtomicBoolean(); // blocks redundant disconnect notifications
|
||||||
|
|
||||||
|
protected AbstractNetworkAddon(GlobalReceiverRegistry<H> receiver, String description) {
|
||||||
|
this.receiver = receiver;
|
||||||
|
this.logger = LoggerFactory.getLogger(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public H getHandler(ResourceLocation channel) {
|
||||||
|
Lock lock = this.lock.readLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
return this.handlers.get(channel);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean registerChannel(ResourceLocation channelName, H handler) {
|
||||||
|
Objects.requireNonNull(channelName, "Channel name cannot be null");
|
||||||
|
Objects.requireNonNull(handler, "Packet handler cannot be null");
|
||||||
|
|
||||||
|
if (this.isReservedChannel(channelName)) {
|
||||||
|
throw new IllegalArgumentException(String.format("Cannot register handler for reserved channel with name \"%s\"", channelName));
|
||||||
|
}
|
||||||
|
|
||||||
|
Lock lock = this.lock.writeLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final boolean replaced = this.handlers.putIfAbsent(channelName, handler) == null;
|
||||||
|
|
||||||
|
if (replaced) {
|
||||||
|
this.handleRegistration(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return replaced;
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public H unregisterChannel(ResourceLocation channelName) {
|
||||||
|
Objects.requireNonNull(channelName, "Channel name cannot be null");
|
||||||
|
|
||||||
|
if (this.isReservedChannel(channelName)) {
|
||||||
|
throw new IllegalArgumentException(String.format("Cannot register handler for reserved channel with name \"%s\"", channelName));
|
||||||
|
}
|
||||||
|
|
||||||
|
Lock lock = this.lock.writeLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final H removed = this.handlers.remove(channelName);
|
||||||
|
|
||||||
|
if (removed != null) {
|
||||||
|
this.handleUnregistration(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<ResourceLocation> getReceivableChannels() {
|
||||||
|
Lock lock = this.lock.readLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new HashSet<>(this.handlers.keySet());
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void handleRegistration(ResourceLocation channelName);
|
||||||
|
|
||||||
|
protected abstract void handleUnregistration(ResourceLocation channelName);
|
||||||
|
|
||||||
|
public final void handleDisconnect() {
|
||||||
|
if (disconnected.compareAndSet(false, true)) {
|
||||||
|
invokeDisconnectEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void invokeDisconnectEvent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a channel is considered a "reserved" channel.
|
||||||
|
* A reserved channel such as "minecraft:(un)register" has special handling and should not have any channel handlers registered for it.
|
||||||
|
*
|
||||||
|
* @param channelName the channel name
|
||||||
|
* @return whether the channel is reserved
|
||||||
|
*/
|
||||||
|
protected abstract boolean isReservedChannel(ResourceLocation channelName);
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public interface ChannelInfoHolder {
|
||||||
|
/**
|
||||||
|
* @return Channels which are declared as receivable by the other side but have not been declared yet.
|
||||||
|
*/
|
||||||
|
Collection<ResourceLocation> getPendingChannelsNames();
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking;
|
||||||
|
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
|
||||||
|
public interface DisconnectPacketSource {
|
||||||
|
Packet<?> createDisconnectPacket(Component message);
|
||||||
|
}
|
||||||
+173
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public final class GlobalReceiverRegistry<H> {
|
||||||
|
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||||
|
private final Map<ResourceLocation, H> handlers;
|
||||||
|
private final Set<AbstractNetworkAddon<H>> trackedAddons = new HashSet<>();
|
||||||
|
|
||||||
|
public GlobalReceiverRegistry() {
|
||||||
|
this(new HashMap<>()); // sync map should be fine as there is little read write competitions
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlobalReceiverRegistry(Map<ResourceLocation, H> map) {
|
||||||
|
this.handlers = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public H getHandler(ResourceLocation channelName) {
|
||||||
|
Lock lock = this.lock.readLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
return this.handlers.get(channelName);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean registerGlobalReceiver(ResourceLocation channelName, H handler) {
|
||||||
|
Objects.requireNonNull(channelName, "Channel name cannot be null");
|
||||||
|
Objects.requireNonNull(handler, "Channel handler cannot be null");
|
||||||
|
|
||||||
|
if (NetworkingImpl.isReservedPlayChannel(channelName)) {
|
||||||
|
throw new IllegalArgumentException(String.format("Cannot register handler for reserved channel with name \"%s\"", channelName));
|
||||||
|
}
|
||||||
|
|
||||||
|
Lock lock = this.lock.writeLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final boolean replaced = this.handlers.putIfAbsent(channelName, handler) == null;
|
||||||
|
|
||||||
|
if (!replaced) {
|
||||||
|
this.handleRegistration(channelName, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
return replaced;
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public H unregisterGlobalReceiver(ResourceLocation channelName) {
|
||||||
|
Objects.requireNonNull(channelName, "Channel name cannot be null");
|
||||||
|
|
||||||
|
if (NetworkingImpl.isReservedPlayChannel(channelName)) {
|
||||||
|
throw new IllegalArgumentException(String.format("Cannot unregister packet handler for reserved channel with name \"%s\"", channelName));
|
||||||
|
}
|
||||||
|
|
||||||
|
Lock lock = this.lock.writeLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final H removed = this.handlers.remove(channelName);
|
||||||
|
|
||||||
|
if (removed != null) {
|
||||||
|
this.handleUnregistration(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<ResourceLocation, H> getHandlers() {
|
||||||
|
Lock lock = this.lock.writeLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new HashMap<>(this.handlers);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<ResourceLocation> getChannels() {
|
||||||
|
Lock lock = this.lock.readLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new HashSet<>(this.handlers.keySet());
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// State tracking methods
|
||||||
|
|
||||||
|
public void startSession(AbstractNetworkAddon<H> addon) {
|
||||||
|
Lock lock = this.lock.writeLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.trackedAddons.add(addon);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void endSession(AbstractNetworkAddon<H> addon) {
|
||||||
|
Lock lock = this.lock.writeLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.trackedAddons.remove(addon);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRegistration(ResourceLocation channelName, H handler) {
|
||||||
|
Lock lock = this.lock.writeLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (AbstractNetworkAddon<H> addon : this.trackedAddons) {
|
||||||
|
addon.registerChannel(channelName, handler);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleUnregistration(ResourceLocation channelName) {
|
||||||
|
Lock lock = this.lock.writeLock();
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (AbstractNetworkAddon<H> addon : this.trackedAddons) {
|
||||||
|
addon.unregisterChannel(channelName);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking;
|
||||||
|
|
||||||
|
public interface NetworkHandlerExtensions {
|
||||||
|
AbstractNetworkAddon<?> getAddon();
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.PacketByteBufs;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.ServerLoginConnectionEvents;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.ServerLoginNetworking;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.ServerPlayNetworking;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public final class NetworkingImpl {
|
||||||
|
public static final String MOD_ID = "fabric-networking-api-v1";
|
||||||
|
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
||||||
|
/**
|
||||||
|
* Id of packet used to register supported channels.
|
||||||
|
*/
|
||||||
|
public static final ResourceLocation REGISTER_CHANNEL = new ResourceLocation("minecraft", "register");
|
||||||
|
/**
|
||||||
|
* Id of packet used to unregister supported channels.
|
||||||
|
*/
|
||||||
|
public static final ResourceLocation UNREGISTER_CHANNEL = new ResourceLocation("minecraft", "unregister");
|
||||||
|
/**
|
||||||
|
* Id of the packet used to declare all currently supported channels.
|
||||||
|
* Dynamic registration of supported channels is still allowed using {@link NetworkingImpl#REGISTER_CHANNEL} and {@link NetworkingImpl#UNREGISTER_CHANNEL}.
|
||||||
|
*/
|
||||||
|
public static final ResourceLocation EARLY_REGISTRATION_CHANNEL = new ResourceLocation(MOD_ID, "early_registration");
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
// Login setup
|
||||||
|
ServerLoginConnectionEvents.QUERY_START.register((handler, server, sender, synchronizer) -> {
|
||||||
|
// Send early registration packet
|
||||||
|
FriendlyByteBuf buf = PacketByteBufs.create();
|
||||||
|
Collection<ResourceLocation> channelsNames = ServerPlayNetworking.getGlobalReceivers();
|
||||||
|
buf.writeVarInt(channelsNames.size());
|
||||||
|
|
||||||
|
for (ResourceLocation id : channelsNames) {
|
||||||
|
buf.writeResourceLocation(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendPacket(EARLY_REGISTRATION_CHANNEL, buf);
|
||||||
|
NetworkingImpl.LOGGER.debug("Sent accepted channels to the client for \"{}\"", handler.getUserName());
|
||||||
|
});
|
||||||
|
|
||||||
|
ServerLoginNetworking.registerGlobalReceiver(EARLY_REGISTRATION_CHANNEL, (server, handler, understood, buf, synchronizer, sender) -> {
|
||||||
|
if (!understood) {
|
||||||
|
// The client is likely a vanilla client.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = buf.readVarInt();
|
||||||
|
List<ResourceLocation> ids = new ArrayList<>(n);
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
ids.add(buf.readResourceLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
((ChannelInfoHolder) handler.getConnection()).getPendingChannelsNames().addAll(ids);
|
||||||
|
NetworkingImpl.LOGGER.debug("Received accepted channels from the client for \"{}\"", handler.getUserName());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isReservedPlayChannel(ResourceLocation channelName) {
|
||||||
|
return channelName.equals(REGISTER_CHANNEL) || channelName.equals(UNREGISTER_CHANNEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking;
|
||||||
|
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
|
||||||
|
public interface PacketCallbackListener {
|
||||||
|
/**
|
||||||
|
* Called after a packet has been sent.
|
||||||
|
*
|
||||||
|
* @param packet the packet
|
||||||
|
*/
|
||||||
|
void sent(Packet<?> packet);
|
||||||
|
}
|
||||||
+121
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking.client;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import io.netty.util.concurrent.Future;
|
||||||
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import com.seibel.lod.forge.fabric.api.client.networking.v1.ClientLoginConnectionEvents;
|
||||||
|
import com.seibel.lod.forge.fabric.api.client.networking.v1.ClientLoginNetworking;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.FutureListeners;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.PacketByteBufs;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.AbstractNetworkAddon;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.ClientHandshakePacketListenerImpl;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.login.ClientboundCustomQueryPacket;
|
||||||
|
import net.minecraft.network.protocol.login.ServerboundCustomQueryPacket;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public final class ClientLoginNetworkAddon extends AbstractNetworkAddon<ClientLoginNetworking.LoginQueryRequestHandler> {
|
||||||
|
private final ClientHandshakePacketListenerImpl handler;
|
||||||
|
private final Minecraft client;
|
||||||
|
private boolean firstResponse = true;
|
||||||
|
|
||||||
|
public ClientLoginNetworkAddon(ClientHandshakePacketListenerImpl handler, Minecraft client) {
|
||||||
|
super(ClientNetworkingImpl.LOGIN, "ClientLoginNetworkAddon for Client");
|
||||||
|
this.handler = handler;
|
||||||
|
this.client = client;
|
||||||
|
|
||||||
|
ClientLoginConnectionEvents.INIT.invoker().onLoginStart(this.handler, this.client);
|
||||||
|
this.receiver.startSession(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean handlePacket(ClientboundCustomQueryPacket packet) {
|
||||||
|
return handlePacket(packet.getTransactionId(), packet.getIdentifier(), packet.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handlePacket(int queryId, ResourceLocation channelName, FriendlyByteBuf originalBuf) {
|
||||||
|
this.logger.debug("Handling inbound login response with id {} and channel with name {}", queryId, channelName);
|
||||||
|
|
||||||
|
if (this.firstResponse) {
|
||||||
|
// Register global handlers
|
||||||
|
for (Map.Entry<ResourceLocation, ClientLoginNetworking.LoginQueryRequestHandler> entry : ClientNetworkingImpl.LOGIN.getHandlers().entrySet()) {
|
||||||
|
ClientLoginNetworking.registerReceiver(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientLoginConnectionEvents.QUERY_START.invoker().onLoginQueryStart(this.handler, this.client);
|
||||||
|
this.firstResponse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable ClientLoginNetworking.LoginQueryRequestHandler handler = this.getHandler(channelName);
|
||||||
|
|
||||||
|
if (handler == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FriendlyByteBuf buf = PacketByteBufs.slice(originalBuf);
|
||||||
|
List<GenericFutureListener<? extends Future<? super Void>>> futureListeners = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
CompletableFuture<@Nullable FriendlyByteBuf> future = handler.receive(this.client, this.handler, buf, futureListeners::add);
|
||||||
|
future.thenAccept(result -> {
|
||||||
|
ServerboundCustomQueryPacket packet = new ServerboundCustomQueryPacket(queryId, result);
|
||||||
|
GenericFutureListener<? extends Future<? super Void>> listener = null;
|
||||||
|
|
||||||
|
for (GenericFutureListener<? extends Future<? super Void>> each : futureListeners) {
|
||||||
|
listener = FutureListeners.union(listener, each);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handler.getConnection().send(packet, listener);
|
||||||
|
});
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
this.logger.error("Encountered exception while handling in channel with name \"{}\"", channelName, ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleRegistration(ResourceLocation channelName) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleUnregistration(ResourceLocation channelName) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void invokeDisconnectEvent() {
|
||||||
|
ClientLoginConnectionEvents.DISCONNECT.invoker().onLoginDisconnect(this.handler, this.client);
|
||||||
|
this.receiver.endSession(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handlePlayTransition() {
|
||||||
|
this.receiver.endSession(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isReservedChannel(ResourceLocation channelName) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+136
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking.client;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import com.seibel.lod.forge.fabric.api.client.networking.v1.ClientLoginNetworking;
|
||||||
|
import com.seibel.lod.forge.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||||
|
import com.seibel.lod.forge.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.PacketByteBufs;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.ChannelInfoHolder;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.GlobalReceiverRegistry;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.NetworkHandlerExtensions;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.NetworkingImpl;
|
||||||
|
import com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor.ConnectScreenAccessor;
|
||||||
|
import com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor.MinecraftClientAccessor;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.screens.ConnectScreen;
|
||||||
|
import net.minecraft.client.multiplayer.ClientHandshakePacketListenerImpl;
|
||||||
|
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||||
|
import net.minecraft.network.Connection;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public final class ClientNetworkingImpl {
|
||||||
|
public static final GlobalReceiverRegistry<ClientLoginNetworking.LoginQueryRequestHandler> LOGIN = new GlobalReceiverRegistry<>();
|
||||||
|
public static final GlobalReceiverRegistry<ClientPlayNetworking.PlayChannelHandler> PLAY = new GlobalReceiverRegistry<>();
|
||||||
|
private static ClientPlayNetworkAddon currentPlayAddon;
|
||||||
|
|
||||||
|
public static ClientPlayNetworkAddon getAddon(ClientPacketListener handler) {
|
||||||
|
return (ClientPlayNetworkAddon) ((NetworkHandlerExtensions) handler).getAddon();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClientLoginNetworkAddon getAddon(ClientHandshakePacketListenerImpl handler) {
|
||||||
|
return (ClientLoginNetworkAddon) ((NetworkHandlerExtensions) handler).getAddon();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Packet<?> createPlayC2SPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
|
||||||
|
return new ServerboundCustomPayloadPacket(channelName, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Due to the way logging into a integrated or remote dedicated server will differ, we need to obtain the login client connection differently.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static Connection getLoginConnection() {
|
||||||
|
final Connection connection = ((MinecraftClientAccessor) Minecraft.getInstance()).getConnection();
|
||||||
|
|
||||||
|
// Check if we are connecting to an integrated server. This will set the field on MinecraftClient
|
||||||
|
if (connection != null) {
|
||||||
|
return connection;
|
||||||
|
} else {
|
||||||
|
// We are probably connecting to a remote server.
|
||||||
|
// Check if the ConnectScreen is the currentScreen to determine that:
|
||||||
|
if (Minecraft.getInstance().screen instanceof ConnectScreen) {
|
||||||
|
return ((ConnectScreenAccessor) Minecraft.getInstance().screen).getConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are not connected to a server at all.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static ClientPlayNetworkAddon getClientPlayAddon() {
|
||||||
|
// Since Minecraft can be a bit weird, we need to check for the play addon in a few ways:
|
||||||
|
// If the client's player is set this will work
|
||||||
|
if (Minecraft.getInstance().getConnection() != null) {
|
||||||
|
currentPlayAddon = null; // Shouldn't need this anymore
|
||||||
|
return ClientNetworkingImpl.getAddon(Minecraft.getInstance().getConnection());
|
||||||
|
}
|
||||||
|
|
||||||
|
// We haven't hit the end of onGameJoin yet, use our backing field here to access the network handler
|
||||||
|
if (currentPlayAddon != null) {
|
||||||
|
return currentPlayAddon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are not in play stage
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setClientPlayAddon(ClientPlayNetworkAddon addon) {
|
||||||
|
currentPlayAddon = addon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clientInit() {
|
||||||
|
// Reference cleanup for the locally stored addon if we are disconnected
|
||||||
|
ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> {
|
||||||
|
currentPlayAddon = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Register a login query handler for early channel registration.
|
||||||
|
ClientLoginNetworking.registerGlobalReceiver(NetworkingImpl.EARLY_REGISTRATION_CHANNEL, (client, handler, buf, listenerAdder) -> {
|
||||||
|
int n = buf.readVarInt();
|
||||||
|
List<ResourceLocation> ids = new ArrayList<>(n);
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
ids.add(buf.readResourceLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
((ChannelInfoHolder) handler.getConnection()).getPendingChannelsNames().addAll(ids);
|
||||||
|
NetworkingImpl.LOGGER.debug("Received accepted channels from the server");
|
||||||
|
|
||||||
|
FriendlyByteBuf response = PacketByteBufs.create();
|
||||||
|
Collection<ResourceLocation> channels = ClientPlayNetworking.getGlobalReceivers();
|
||||||
|
response.writeVarInt(channels.size());
|
||||||
|
|
||||||
|
for (ResourceLocation id : channels) {
|
||||||
|
response.writeResourceLocation(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkingImpl.LOGGER.debug("Sent accepted channels to the server");
|
||||||
|
return CompletableFuture.completedFuture(response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking.client;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import com.seibel.lod.forge.fabric.api.client.networking.v1.C2SPlayChannelEvents;
|
||||||
|
import com.seibel.lod.forge.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||||
|
import com.seibel.lod.forge.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.AbstractChanneledNetworkAddon;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.ChannelInfoHolder;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.NetworkingImpl;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon<ClientPlayNetworking.PlayChannelHandler> {
|
||||||
|
private final ClientPacketListener handler;
|
||||||
|
private final Minecraft client;
|
||||||
|
private boolean sentInitialRegisterPacket;
|
||||||
|
|
||||||
|
public ClientPlayNetworkAddon(ClientPacketListener handler, Minecraft client) {
|
||||||
|
super(ClientNetworkingImpl.PLAY, handler.getConnection(), "ClientPlayNetworkAddon for " + handler.getLocalGameProfile().getName());
|
||||||
|
this.handler = handler;
|
||||||
|
this.client = client;
|
||||||
|
|
||||||
|
// Must register pending channels via lateinit
|
||||||
|
this.registerPendingChannels((ChannelInfoHolder) this.connection);
|
||||||
|
|
||||||
|
// Register global receivers and attach to session
|
||||||
|
this.receiver.startSession(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lateInit() {
|
||||||
|
for (Map.Entry<ResourceLocation, ClientPlayNetworking.PlayChannelHandler> entry : this.receiver.getHandlers().entrySet()) {
|
||||||
|
this.registerChannel(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientPlayConnectionEvents.INIT.invoker().onPlayInit(this.handler, this.client);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServerReady() {
|
||||||
|
ClientPlayConnectionEvents.JOIN.invoker().onPlayReady(this.handler, this, this.client);
|
||||||
|
|
||||||
|
// The client cannot send any packets, including `minecraft:register` until after GameJoinS2CPacket is received.
|
||||||
|
this.sendInitialChannelRegistrationPacket();
|
||||||
|
this.sentInitialRegisterPacket = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles an incoming packet.
|
||||||
|
*
|
||||||
|
* @param packet the packet to handle
|
||||||
|
* @return true if the packet has been handled
|
||||||
|
*/
|
||||||
|
public boolean handle(ClientboundCustomPayloadPacket packet) {
|
||||||
|
// Do not handle the packet on game thread
|
||||||
|
if (this.client.isSameThread()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FriendlyByteBuf buf = packet.getData();
|
||||||
|
|
||||||
|
try {
|
||||||
|
return this.handle(packet.getIdentifier(), buf);
|
||||||
|
} finally {
|
||||||
|
buf.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void receive(ClientPlayNetworking.PlayChannelHandler handler, FriendlyByteBuf buf) {
|
||||||
|
handler.receive(this.client, this.handler, buf, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl details
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void schedule(Runnable task) {
|
||||||
|
Minecraft.getInstance().execute(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Packet<?> createPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
|
||||||
|
return ClientPlayNetworking.createC2SPacket(channelName, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void invokeRegisterEvent(List<ResourceLocation> ids) {
|
||||||
|
C2SPlayChannelEvents.REGISTER.invoker().onChannelRegister(this.handler, this, this.client, ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void invokeUnregisterEvent(List<ResourceLocation> ids) {
|
||||||
|
C2SPlayChannelEvents.UNREGISTER.invoker().onChannelUnregister(this.handler, this, this.client, ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleRegistration(ResourceLocation channelName) {
|
||||||
|
// If we can already send packets, immediately send the register packet for this channel
|
||||||
|
if (this.sentInitialRegisterPacket) {
|
||||||
|
final FriendlyByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName));
|
||||||
|
|
||||||
|
if (buf != null) {
|
||||||
|
this.sendPacket(NetworkingImpl.REGISTER_CHANNEL, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleUnregistration(ResourceLocation channelName) {
|
||||||
|
// If we can already send packets, immediately send the unregister packet for this channel
|
||||||
|
if (this.sentInitialRegisterPacket) {
|
||||||
|
final FriendlyByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName));
|
||||||
|
|
||||||
|
if (buf != null) {
|
||||||
|
this.sendPacket(NetworkingImpl.UNREGISTER_CHANNEL, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void invokeDisconnectEvent() {
|
||||||
|
ClientPlayConnectionEvents.DISCONNECT.invoker().onPlayDisconnect(this.handler, this.client);
|
||||||
|
this.receiver.endSession(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isReservedChannel(ResourceLocation channelName) {
|
||||||
|
return NetworkingImpl.isReservedPlayChannel(channelName);
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking.server;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks the current query id used for login query responses.
|
||||||
|
*/
|
||||||
|
interface QueryIdFactory {
|
||||||
|
static QueryIdFactory create() {
|
||||||
|
return new QueryIdFactory() {
|
||||||
|
private final AtomicInteger currentId = new AtomicInteger();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int nextId() {
|
||||||
|
return this.currentId.getAndIncrement();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// called async prob.
|
||||||
|
int nextId();
|
||||||
|
}
|
||||||
+207
@@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking.server;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import net.minecraft.network.Connection;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.network.protocol.login.ClientboundCustomQueryPacket;
|
||||||
|
import net.minecraft.network.protocol.login.ClientboundLoginCompressionPacket;
|
||||||
|
import net.minecraft.network.protocol.login.ServerboundCustomQueryPacket;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.network.ServerLoginPacketListenerImpl;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.PacketByteBufs;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.PacketSender;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.ServerLoginConnectionEvents;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.ServerLoginNetworking;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.AbstractNetworkAddon;
|
||||||
|
import com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor.LoginQueryResponseC2SPacketAccessor;
|
||||||
|
import com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor.ServerLoginNetworkHandlerAccessor;
|
||||||
|
|
||||||
|
public final class ServerLoginNetworkAddon extends AbstractNetworkAddon<ServerLoginNetworking.LoginQueryResponseHandler> implements PacketSender {
|
||||||
|
private final Connection connection;
|
||||||
|
private final ServerLoginPacketListenerImpl handler;
|
||||||
|
private final MinecraftServer server;
|
||||||
|
private final QueryIdFactory queryIdFactory;
|
||||||
|
private final Collection<Future<?>> waits = new ConcurrentLinkedQueue<>();
|
||||||
|
private final Map<Integer, ResourceLocation> channels = new ConcurrentHashMap<>();
|
||||||
|
private boolean firstQueryTick = true;
|
||||||
|
|
||||||
|
public ServerLoginNetworkAddon(ServerLoginPacketListenerImpl handler) {
|
||||||
|
super(ServerNetworkingImpl.LOGIN, "ServerLoginNetworkAddon for " + handler.getUserName());
|
||||||
|
this.connection = handler.connection;
|
||||||
|
this.handler = handler;
|
||||||
|
this.server = ((ServerLoginNetworkHandlerAccessor) handler).getServer();
|
||||||
|
this.queryIdFactory = QueryIdFactory.create();
|
||||||
|
|
||||||
|
ServerLoginConnectionEvents.INIT.invoker().onLoginInit(handler, this.server);
|
||||||
|
this.receiver.startSession(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return true if no longer ticks query
|
||||||
|
public boolean queryTick() {
|
||||||
|
if (this.firstQueryTick) {
|
||||||
|
// Send the compression packet now so clients receive compressed login queries
|
||||||
|
this.sendCompressionPacket();
|
||||||
|
|
||||||
|
// Register global receivers.
|
||||||
|
for (Map.Entry<ResourceLocation, ServerLoginNetworking.LoginQueryResponseHandler> entry : ServerNetworkingImpl.LOGIN.getHandlers().entrySet()) {
|
||||||
|
ServerLoginNetworking.registerReceiver(this.handler, entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerLoginConnectionEvents.QUERY_START.invoker().onLoginStart(this.handler, this.server, this, this.waits::add);
|
||||||
|
this.firstQueryTick = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AtomicReference<Throwable> error = new AtomicReference<>();
|
||||||
|
this.waits.removeIf(future -> {
|
||||||
|
if (!future.isDone()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
future.get();
|
||||||
|
} catch (ExecutionException ex) {
|
||||||
|
Throwable caught = ex.getCause();
|
||||||
|
error.getAndUpdate(oldEx -> {
|
||||||
|
if (oldEx == null) {
|
||||||
|
return caught;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldEx.addSuppressed(caught);
|
||||||
|
return oldEx;
|
||||||
|
});
|
||||||
|
} catch (InterruptedException | CancellationException ignored) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.channels.isEmpty() && this.waits.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendCompressionPacket() {
|
||||||
|
// Compression is not needed for local transport
|
||||||
|
if (this.server.getCompressionThreshold() >= 0 && !this.connection.isMemoryConnection()) {
|
||||||
|
this.connection.send(new ClientboundLoginCompressionPacket(this.server.getCompressionThreshold()), (channelFuture) ->
|
||||||
|
this.connection.setupCompression(this.server.getCompressionThreshold(), true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles an incoming query response during login.
|
||||||
|
*
|
||||||
|
* @param packet the packet to handle
|
||||||
|
* @return true if the packet was handled
|
||||||
|
*/
|
||||||
|
public boolean handle(ServerboundCustomQueryPacket packet) {
|
||||||
|
LoginQueryResponseC2SPacketAccessor access = (LoginQueryResponseC2SPacketAccessor) packet;
|
||||||
|
return handle(access.getTransactionId(), access.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handle(int queryId, @Nullable FriendlyByteBuf originalBuf) {
|
||||||
|
this.logger.debug("Handling inbound login query with id {}", queryId);
|
||||||
|
ResourceLocation channel = this.channels.remove(queryId);
|
||||||
|
|
||||||
|
if (channel == null) {
|
||||||
|
this.logger.warn("Query ID {} was received but no query has been associated in {}!", queryId, this.connection);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean understood = originalBuf != null;
|
||||||
|
@Nullable ServerLoginNetworking.LoginQueryResponseHandler handler = ServerNetworkingImpl.LOGIN.getHandler(channel);
|
||||||
|
|
||||||
|
if (handler == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FriendlyByteBuf buf = understood ? PacketByteBufs.slice(originalBuf) : PacketByteBufs.empty();
|
||||||
|
|
||||||
|
try {
|
||||||
|
handler.receive(this.server, this.handler, understood, buf, this.waits::add, this);
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
this.logger.error("Encountered exception while handling in channel \"{}\"", channel, ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Packet<?> createPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
|
||||||
|
int queryId = this.queryIdFactory.nextId();
|
||||||
|
|
||||||
|
ClientboundCustomQueryPacket ret = new ClientboundCustomQueryPacket(queryId, channelName, buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPacket(Packet<?> packet) {
|
||||||
|
Objects.requireNonNull(packet, "Packet cannot be null");
|
||||||
|
|
||||||
|
this.connection.send(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPacket(Packet<?> packet, GenericFutureListener<? extends io.netty.util.concurrent.Future<? super Void>> callback) {
|
||||||
|
Objects.requireNonNull(packet, "Packet cannot be null");
|
||||||
|
|
||||||
|
this.connection.send(packet, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerOutgoingPacket(ClientboundCustomQueryPacket packet) {
|
||||||
|
this.channels.put(packet.getTransactionId(), packet.getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleRegistration(ResourceLocation channelName) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleUnregistration(ResourceLocation channelName) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void invokeDisconnectEvent() {
|
||||||
|
ServerLoginConnectionEvents.DISCONNECT.invoker().onLoginDisconnect(this.handler, this.server);
|
||||||
|
this.receiver.endSession(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handlePlayTransition() {
|
||||||
|
this.receiver.endSession(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isReservedChannel(ResourceLocation channelName) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.lod.forge.fabric.impl.networking.server;
|
||||||
|
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.ServerLoginNetworking;
|
||||||
|
import com.seibel.lod.forge.fabric.api.networking.v1.ServerPlayNetworking;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.GlobalReceiverRegistry;
|
||||||
|
import com.seibel.lod.forge.fabric.impl.networking.NetworkHandlerExtensions;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||||
|
import net.minecraft.server.network.ServerLoginPacketListenerImpl;
|
||||||
|
|
||||||
|
public final class ServerNetworkingImpl {
|
||||||
|
public static final GlobalReceiverRegistry<ServerLoginNetworking.LoginQueryResponseHandler> LOGIN = new GlobalReceiverRegistry<>();
|
||||||
|
public static final GlobalReceiverRegistry<ServerPlayNetworking.PlayChannelHandler> PLAY = new GlobalReceiverRegistry<>();
|
||||||
|
|
||||||
|
public static ServerPlayNetworkAddon getAddon(ServerGamePacketListenerImpl handler) {
|
||||||
|
return (ServerPlayNetworkAddon) ((NetworkHandlerExtensions) handler).getAddon();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerLoginNetworkAddon getAddon(ServerLoginPacketListenerImpl handler) {
|
||||||
|
return (ServerLoginNetworkAddon) ((NetworkHandlerExtensions) handler).getAddon();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Packet<?> createPlayC2SPacket(ResourceLocation channel, FriendlyByteBuf buf) {
|
||||||
|
return new ClientboundCustomPayloadPacket(channel, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user