Compare commits
53 Commits
java_omega
...
1.6.7a
| Author | SHA1 | Date | |
|---|---|---|---|
| 086185783c | |||
| 70321c2d0f | |||
| 9ce353d897 | |||
| 1d1a2d455d | |||
| fa1e7704e0 | |||
| 1227c56353 | |||
| 22c85f1eda | |||
| d75a4f8d1a | |||
| 7f69809345 | |||
| e460aa2e0d | |||
| 705535e574 | |||
| f0966befb2 | |||
| ec3bab3158 | |||
| 7510f23d19 | |||
| 9c9974de5b | |||
| e49a400dba | |||
| 893e82b181 | |||
| f8427c4f40 | |||
| 6576f55c55 | |||
| ddca97f679 | |||
| 6bf405c0b1 | |||
| d97bc912f7 | |||
| ac91979a3f | |||
| 3119fae67b | |||
| b77a53fc2a | |||
| 9d45717356 | |||
| 6235453387 | |||
| 0e52c06d35 | |||
| 680ab28491 | |||
| b31ee404fd | |||
| 4c604a24cb | |||
| ebba4939c5 | |||
| 285a507370 | |||
| 2f7008bbc3 | |||
| 68b0550696 | |||
| bafe93a28a | |||
| b1b464c592 | |||
| b21cfd8304 | |||
| 8dc3f744fe | |||
| 225703cdf1 | |||
| 3fb9fa8609 | |||
| a4fca06531 | |||
| fdd416b514 | |||
| 03f134bde3 | |||
| e8d1ca995c | |||
| 00b43dc90f | |||
| 2efb6fff49 | |||
| 16adf15975 | |||
| 417b98f881 | |||
| ffa64874c9 | |||
| 8454b5056d | |||
| a81fd9a483 | |||
| 4ee1949873 |
+52
-14
@@ -3,6 +3,7 @@ image: gradle:eclipse-temurin
|
|||||||
|
|
||||||
# all stages need to be defined here
|
# all stages need to be defined here
|
||||||
stages:
|
stages:
|
||||||
|
- build_19
|
||||||
- build_18_2
|
- build_18_2
|
||||||
- build_18_1
|
- build_18_1
|
||||||
- build_17_1
|
- build_17_1
|
||||||
@@ -24,10 +25,13 @@ before_script:
|
|||||||
build_16_5:
|
build_16_5:
|
||||||
stage: build_16_5
|
stage: build_16_5
|
||||||
script:
|
script:
|
||||||
- ./gradlew deleteMerged --gradle-user-home cache/;
|
- echo "Building 1.16.5..."
|
||||||
- ./gradlew build -PmcVer=1.16.5 --gradle-user-home cache/;
|
- ./gradlew deleteMerged -PmcVer="1.16.5" --gradle-user-home cache/;
|
||||||
- ./gradlew merge --gradle-user-home cache/;
|
- ./gradlew clean -PmcVer="1.16.5" --gradle-user-home cache/;
|
||||||
image: eclipse-temurin:16
|
- ./gradlew core:build -PmcVer="1.16.5" --gradle-user-home cache/;
|
||||||
|
- ./gradlew build -PmcVer="1.16.5" --gradle-user-home cache/;
|
||||||
|
- ./gradlew mergeJars -PmcVer="1.16.5" --gradle-user-home cache/;
|
||||||
|
image: eclipse-temurin:17
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "Merged_NightlyBuild_1_16_5-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
name: "Merged_NightlyBuild_1_16_5-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||||
paths:
|
paths:
|
||||||
@@ -46,10 +50,13 @@ build_16_5:
|
|||||||
build_17_1:
|
build_17_1:
|
||||||
stage: build_17_1
|
stage: build_17_1
|
||||||
script:
|
script:
|
||||||
- ./gradlew deleteMerged --gradle-user-home cache/;
|
- echo "Building 1.17.1..."
|
||||||
- ./gradlew build -PmcVer=1.17.1 --gradle-user-home cache/;
|
- ./gradlew deleteMerged -PmcVer="1.17.1" --gradle-user-home cache/;
|
||||||
- ./gradlew merge --gradle-user-home cache/;
|
- ./gradlew clean -PmcVer="1.17.1" --gradle-user-home cache/;
|
||||||
image: eclipse-temurin:16
|
- ./gradlew core:build -PmcVer="1.17.7" --gradle-user-home cache/;
|
||||||
|
- ./gradlew build -PmcVer="1.17.1" --gradle-user-home cache/;
|
||||||
|
- ./gradlew mergeJars -PmcVer="1.17.1" --gradle-user-home cache/;
|
||||||
|
image: eclipse-temurin:17
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "Merged_NightlyBuild_1_17_1-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
name: "Merged_NightlyBuild_1_17_1-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||||
paths:
|
paths:
|
||||||
@@ -69,9 +76,12 @@ build_17_1:
|
|||||||
build_18_1:
|
build_18_1:
|
||||||
stage: build_18_1
|
stage: build_18_1
|
||||||
script:
|
script:
|
||||||
- ./gradlew deleteMerged --gradle-user-home cache/; # make sure any previously merged jars are removed before running this job
|
- echo "Building 1.18.1..."
|
||||||
- ./gradlew build -PmcVer=1.18.1 --gradle-user-home cache/;
|
- ./gradlew deleteMerged -PmcVer="1.18.1" --gradle-user-home cache/; # make sure any previously merged jars are removed before running this job
|
||||||
- ./gradlew merge --gradle-user-home cache/;
|
- ./gradlew clean -PmcVer="1.18.1" --gradle-user-home cache/;
|
||||||
|
- ./gradlew core:build -PmcVer="1.18.1" --gradle-user-home cache/;
|
||||||
|
- ./gradlew build -PmcVer="1.18.1" --gradle-user-home cache/;
|
||||||
|
- ./gradlew mergeJars -PmcVer="1.18.1" --gradle-user-home cache/;
|
||||||
# build using Java 17
|
# build using Java 17
|
||||||
image: eclipse-temurin:17
|
image: eclipse-temurin:17
|
||||||
artifacts:
|
artifacts:
|
||||||
@@ -93,9 +103,12 @@ build_18_1:
|
|||||||
build_18_2:
|
build_18_2:
|
||||||
stage: build_18_2
|
stage: build_18_2
|
||||||
script:
|
script:
|
||||||
- ./gradlew deleteMerged --gradle-user-home cache/;
|
- echo "Building 1.18.2..."
|
||||||
- ./gradlew build -PmcVer=1.18.2 --gradle-user-home cache/;
|
- ./gradlew deleteMerged -PmcVer="1.18.2" --gradle-user-home cache/;
|
||||||
- ./gradlew merge --gradle-user-home cache/;
|
- ./gradlew clean -PmcVer="1.18.2" --gradle-user-home cache/;
|
||||||
|
- ./gradlew core:build -PmcVer="1.18.2" --gradle-user-home cache/;
|
||||||
|
- ./gradlew build -PmcVer="1.18.2" --gradle-user-home cache/;
|
||||||
|
- ./gradlew mergeJars -PmcVer="1.18.2" --gradle-user-home cache/;
|
||||||
image: eclipse-temurin:17
|
image: eclipse-temurin:17
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "Merged_NightlyBuild_1_18_2-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
name: "Merged_NightlyBuild_1_18_2-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||||
@@ -111,6 +124,31 @@ build_18_2:
|
|||||||
- cache/
|
- cache/
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
|
|
||||||
|
# 1.19 build
|
||||||
|
build_19:
|
||||||
|
stage: build_19
|
||||||
|
script:
|
||||||
|
- echo "Building 1.19..."
|
||||||
|
- ./gradlew deleteMerged -PmcVer="1.19" --gradle-user-home cache/;
|
||||||
|
- ./gradlew clean -PmcVer="1.19" --gradle-user-home cache/;
|
||||||
|
- ./gradlew core:build -PmcVer="1.19" --gradle-user-home cache/;
|
||||||
|
- ./gradlew build -PmcVer="1.19" --gradle-user-home cache/;
|
||||||
|
- ./gradlew mergeJars -PmcVer="1.19" --gradle-user-home cache/;
|
||||||
|
image: eclipse-temurin:17
|
||||||
|
artifacts:
|
||||||
|
name: "Merged_NightlyBuild_1_19-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||||
|
paths:
|
||||||
|
- Merged
|
||||||
|
expire_in: 1 day
|
||||||
|
when: always
|
||||||
|
cache:
|
||||||
|
key: "gradleCache"
|
||||||
|
policy: pull-push
|
||||||
|
paths:
|
||||||
|
- .gradle
|
||||||
|
- cache/
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
|
||||||
# unused deployment stage
|
# unused deployment stage
|
||||||
#deploy:
|
#deploy:
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# 1.18.2 version based stuff
|
||||||
|
|
||||||
|
java_version = 17
|
||||||
|
minecraft_version=1.19
|
||||||
|
parchment_version=2022.03.13
|
||||||
|
compatible_minecraft_versions=["1.19"]
|
||||||
|
|
||||||
|
# Fabric loader
|
||||||
|
fabric_loader_version=0.14.8
|
||||||
|
fabric_api_version=0.57.0+1.19
|
||||||
|
# Fabric mod versions
|
||||||
|
modmenu_version=4.0.0
|
||||||
|
starlight_version_fabric=0
|
||||||
|
phosphor_version_fabric=0
|
||||||
|
lithium_version=0
|
||||||
|
sodium_version=3820973
|
||||||
|
iris_version=1.19.x-v1.2.5
|
||||||
|
immersive_portals_version = 0
|
||||||
|
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_phosphor=0
|
||||||
|
enable_sodium=1
|
||||||
|
enable_lithium=0
|
||||||
|
enable_iris=0
|
||||||
|
enable_bclib=0
|
||||||
|
|
||||||
|
# Forge loader
|
||||||
|
forge_version=41.0.94
|
||||||
|
# Forge mod versions
|
||||||
|
starlight_version_forge=0
|
||||||
|
terraforged_version=
|
||||||
|
|
||||||
|
# Forge mod run
|
||||||
|
# 0 = Don't enable and don't run
|
||||||
|
# 1 = Can be referenced in code but doesn't run
|
||||||
|
# 2 = Can be referenced in code and runs in client
|
||||||
|
enable_starlight_forge=0
|
||||||
|
enable_terraforged=0
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
> A mod that adds a Level of Detail System to Minecraft
|
> A mod that adds a Level of Detail System to Minecraft
|
||||||
|
|
||||||
|
|
||||||
# What is Distant Horizons?
|
# 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.\
|
||||||
@@ -12,19 +11,27 @@ allowing for an increased view distance without harming performance.
|
|||||||
Or in other words: this mod lets you see farther without turning your game into a slide show.\
|
Or in other words: this mod lets you see farther without turning your game into a slide show.\
|
||||||
If you want to see a quick demo, check out a video covering the mod here:
|
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://youtu.be/_04BZ8W2bDM" target="_blank"></a>
|
||||||
|
|
||||||
### Versions
|
### Versions
|
||||||
|
|
||||||
This branch is for these versions of Minecraft
|
This branch is for these versions of Minecraft
|
||||||
|
- 1.19
|
||||||
- 1.18.2
|
- 1.18.2
|
||||||
- 1.18.1 & 1.18
|
- 1.18.1 & 1.18
|
||||||
- 1.17.1 & 1.17
|
- 1.17.1 & 1.17
|
||||||
- 1.16.5 & 1.16.4
|
- 1.16.5 & 1.16.4
|
||||||
|
|
||||||
Architectury version: 3.4-SNAPSHOT\
|
Architectury version: 3.4-SNAPSHOT\
|
||||||
|
Architectury loom version: 0.12.0-SNAPSHOT\
|
||||||
Java Compiler plugin: Manifold Preprocessor
|
Java Compiler plugin: Manifold Preprocessor
|
||||||
|
|
||||||
|
#### 1.19 mods
|
||||||
|
Forge version: 41.0.94\
|
||||||
|
Fabric version: 0.14.8\
|
||||||
|
Fabric API version: 0.57.0+1.19\
|
||||||
|
Modmenu version: 4.0.0
|
||||||
|
|
||||||
#### 1.18.2 mods
|
#### 1.18.2 mods
|
||||||
Forge version: 40.0.18\
|
Forge version: 40.0.18\
|
||||||
Fabric version: 0.13.3\
|
Fabric version: 0.13.3\
|
||||||
@@ -59,10 +66,11 @@ This version has been confirmed to work in IDE and Retail Minecraft with ether t
|
|||||||
|
|
||||||
#### Nightlly builds
|
#### Nightlly builds
|
||||||
This mod has an autobuild system to automatically build the mod on each commit
|
This mod has an autobuild system to automatically build the mod on each commit
|
||||||
- 1.18.2: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/main/download?job=build_18_2
|
- 1.19: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/1.6.4a_dev/download?job=build_19
|
||||||
- 1.18.1: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/main/download?job=build_18_1
|
- 1.18.2: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/1.6.4a_dev/download?job=build_18_2
|
||||||
- 1.17.1: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/main/download?job=build_17_1
|
- 1.18.1: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/1.6.4a_dev/download?job=build_18_1
|
||||||
- 1.16.5: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/main/download?job=build_16_5
|
- 1.17.1: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/1.6.4a_dev/download?job=build_17_1
|
||||||
|
- 1.16.5: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/1.6.4a_dev/download?job=build_16_5
|
||||||
|
|
||||||
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
|
||||||
@@ -85,11 +93,12 @@ https://fabricmc.net/wiki/tutorial:setup
|
|||||||
4. Import the project into eclipse
|
4. Import the project into eclipse
|
||||||
|
|
||||||
## Switching Versions
|
## Switching Versions
|
||||||
This branch support 4 built versions:
|
This branch support 5 built versions:
|
||||||
|
- 1.19
|
||||||
- 1.18.2
|
- 1.18.2
|
||||||
- 1.18.1 (which also runs on 1.18)
|
- 1.18.1 (which also runs on 1.18)
|
||||||
- 1.17.1 (which also runs on 1.17)
|
- 1.17.1 (which also runs on 1.17)
|
||||||
- 1.16.5 (which also runs 1.16.5)
|
- 1.16.5 (which also runs 1.16.4)
|
||||||
|
|
||||||
To switch between active versions, change `mcVer=1.?` in `gradle.properties` file.
|
To switch between active versions, change `mcVer=1.?` in `gradle.properties` file.
|
||||||
|
|
||||||
@@ -107,7 +116,7 @@ If running on IDE, to ensure IDE pickup the changed versions, you will need to r
|
|||||||
6. The compiled jar file will be in the folder `Merged`
|
6. The compiled jar file will be in the folder `Merged`
|
||||||
|
|
||||||
**If in terminal:**
|
**If in terminal:**
|
||||||
1. `git clone --recurse-submodules https://gitlab.com/jeseibel/minecraft-lod-mod.git`
|
1. `git clone -b 1.6.4a_dev --recurse-submodules https://gitlab.com/jeseibel/minecraft-lod-mod.git`
|
||||||
2. `cd minecraft-lod-mod`
|
2. `cd minecraft-lod-mod`
|
||||||
3. `./gradlew assemble`
|
3. `./gradlew assemble`
|
||||||
4. `./gradlew mergeJars`
|
4. `./gradlew mergeJars`
|
||||||
|
|||||||
+297
-199
@@ -1,6 +1,5 @@
|
|||||||
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')
|
||||||
@@ -9,7 +8,25 @@ buildscript {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "architectury-plugin" version "3.4-SNAPSHOT"
|
id "architectury-plugin" version "3.4-SNAPSHOT"
|
||||||
id "dev.architectury.loom" version "0.10.0-SNAPSHOT" apply false
|
id "dev.architectury.loom" version "0.12.0-SNAPSHOT" apply false
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: "java"
|
||||||
|
apply plugin: "architectury-plugin"
|
||||||
|
apply plugin: "maven-publish"
|
||||||
|
apply plugin: JarMergerPlugin
|
||||||
|
|
||||||
|
archivesBaseName = rootProject.archives_base_name
|
||||||
|
version = rootProject.mod_version
|
||||||
|
group = rootProject.maven_group
|
||||||
|
|
||||||
|
task printConfigurations {
|
||||||
|
doLast {task ->
|
||||||
|
println "Project Name: $name configurations:"
|
||||||
|
configurations.each {
|
||||||
|
println " $it.name"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def writeBuildGradlePredefine(List<String> mcVers, int mcIndex) {
|
def writeBuildGradlePredefine(List<String> mcVers, int mcIndex) {
|
||||||
@@ -36,7 +53,7 @@ def writeBuildGradlePredefine(List<String> mcVers, int mcIndex) {
|
|||||||
|
|
||||||
// Sets up the variables for Manifold in the code
|
// Sets up the variables for Manifold in the code
|
||||||
def loadProperties() {
|
def loadProperties() {
|
||||||
def defaultMcVersion = "1.18.2"
|
def defaultMcVersion = "1.19"
|
||||||
def mcVersion = ""
|
def mcVersion = ""
|
||||||
def mcVers = mcVersions.split(",")
|
def mcVers = mcVersions.split(",")
|
||||||
int mcIndex = -1
|
int mcIndex = -1
|
||||||
@@ -69,237 +86,318 @@ def loadProperties() {
|
|||||||
"1.17.1": "1_17",
|
"1.17.1": "1_17",
|
||||||
"1.18.1": "1_18",
|
"1.18.1": "1_18",
|
||||||
"1.18.2": "1_18",
|
"1.18.2": "1_18",
|
||||||
|
"1.19" : "1_19"
|
||||||
]
|
]
|
||||||
// Use this as sometimes multiple versions use the same access wideners
|
// Use this as sometimes multiple versions use the same access wideners
|
||||||
rootProject.ext.set("acsessWidenerVersion", mcVersionToAcsessWidenerVersion.get(mcVersion))
|
rootProject.ext.set("acsessWidenerVersion", mcVersionToAcsessWidenerVersion.get(mcVersion))
|
||||||
}
|
}
|
||||||
loadProperties()
|
loadProperties()
|
||||||
|
|
||||||
apply plugin: JarMergerPlugin
|
|
||||||
|
|
||||||
architectury {
|
architectury {
|
||||||
minecraft = rootProject.minecraft_version
|
minecraft = rootProject.minecraft_version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
|
||||||
subprojects { p ->
|
// For parchment mappings
|
||||||
apply plugin: "dev.architectury.loom"
|
maven { url "https://maven.parchmentmc.org" }
|
||||||
|
|
||||||
loom {
|
// used to download and compile dependencies from git repos
|
||||||
silentMojangMappingsLicense()
|
maven { url 'https://jitpack.io' }
|
||||||
|
|
||||||
if (p != project(":core")) {
|
// For Manifold Preprocessor
|
||||||
accessWidenerPath.set(project(":common").file("src/main/resources/${acsessWidenerVersion}.lod.accesswidener"))
|
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
|
||||||
|
|
||||||
|
// Required for importing Modrinth mods
|
||||||
|
maven {
|
||||||
|
name = "Modrinth"
|
||||||
|
url = "https://api.modrinth.com/maven"
|
||||||
|
content {
|
||||||
|
includeGroup "maven.modrinth"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
// Required for importing CursedForge mods
|
||||||
common
|
maven {
|
||||||
shadowMe
|
url "https://www.cursemaven.com"
|
||||||
implementation.extendsFrom shadowMe
|
content {
|
||||||
}
|
includeGroup "curse.maven"
|
||||||
|
|
||||||
dependencies {
|
|
||||||
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
|
||||||
// The following line declares the mojmap mappings & parchment mappings
|
|
||||||
mappings loom.layered() {
|
|
||||||
// Mojmap mappings
|
|
||||||
officialMojangMappings()
|
|
||||||
// Parchment mappings (it adds parameter mappings & javadoc)
|
|
||||||
parchment("org.parchmentmc.data:parchment-${rootProject.minecraft_version}:${rootProject.parchment_version}@zip")
|
|
||||||
}
|
|
||||||
|
|
||||||
//Manifold
|
|
||||||
annotationProcessor "systems.manifold:manifold-preprocessor:${rootProject.manifold_version}"
|
|
||||||
|
|
||||||
// Toml
|
|
||||||
implementation("com.electronwill.night-config:toml:${rootProject.toml_version}")
|
|
||||||
|
|
||||||
if (p != project(":forge")) {
|
|
||||||
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
|
|
||||||
// Do NOT use other classes from fabric loader unless working with fabric
|
|
||||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p != project(":core")) {
|
|
||||||
common(project(":core")) { transitive false }
|
|
||||||
shadowMe(project(":core")) { transitive false }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allows the jar to run standalone
|
// These 2 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
|
||||||
jar {
|
flatDir {
|
||||||
manifest {
|
dirs "${rootDir}/mods/fabric"
|
||||||
attributes 'Implementation-Title': rootProject.archives_base_name,
|
content {
|
||||||
'Implementation-Version': rootProject.mod_version,
|
includeGroup "fabric-mod"
|
||||||
'Main-Class': 'com.seibel.lod.core.JarMain' // When changing the main of the jar change this line
|
}
|
||||||
|
}
|
||||||
|
flatDir {
|
||||||
|
dirs "${rootDir}/mods/forge"
|
||||||
|
content {
|
||||||
|
includeGroup "forge-mod"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects { p ->
|
processResources {
|
||||||
apply plugin: "java"
|
def resourceTargets = ["fabric.mod.json", "META-INF/mods.toml"] // Location of where to put
|
||||||
apply plugin: "architectury-plugin"
|
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
||||||
apply plugin: "maven-publish"
|
def replaceProperties = [
|
||||||
|
version : mod_version,
|
||||||
|
mod_name : mod_name,
|
||||||
|
authors : mod_authors,
|
||||||
|
description : mod_description,
|
||||||
|
homepage : mod_homepage,
|
||||||
|
source : mod_source,
|
||||||
|
issues : mod_issues,
|
||||||
|
minecraft_version : minecraft_version,
|
||||||
|
compatible_minecraft_versions: compatible_minecraft_versions,
|
||||||
|
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
|
||||||
|
//TODO: Make Forge loader version also be relaced with non hardcoded value instead of "[36,42)"
|
||||||
|
|
||||||
archivesBaseName = rootProject.archives_base_name
|
inputs.properties replaceProperties
|
||||||
version = rootProject.mod_version
|
replaceProperties.put 'project', project
|
||||||
group = rootProject.maven_group
|
filesMatching(resourceTargets) {
|
||||||
|
expand replaceProperties
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
|
|
||||||
// For parchment mappings
|
|
||||||
maven { url "https://maven.parchmentmc.org" }
|
|
||||||
|
|
||||||
// used to download and compile dependencies from git repos
|
|
||||||
maven { url 'https://jitpack.io' }
|
|
||||||
|
|
||||||
// For Manifold Preprocessor
|
|
||||||
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
|
|
||||||
|
|
||||||
// Required for importing Modrinth mods
|
|
||||||
maven {
|
|
||||||
name = "Modrinth"
|
|
||||||
url = "https://api.modrinth.com/maven"
|
|
||||||
content {
|
|
||||||
includeGroup "maven.modrinth"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required for importing CursedForge mods
|
|
||||||
maven {
|
|
||||||
url "https://www.cursemaven.com"
|
|
||||||
content {
|
|
||||||
includeGroup "curse.maven"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// These 2 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
|
|
||||||
flatDir {
|
|
||||||
dirs "${rootDir}/mods/fabric"
|
|
||||||
content {
|
|
||||||
includeGroup "fabric-mod"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flatDir {
|
|
||||||
dirs "${rootDir}/mods/forge"
|
|
||||||
content {
|
|
||||||
includeGroup "forge-mod"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intoTargets.each { target ->
|
||||||
// Put stuff from gradle.properties into the mod info
|
if (file(target).exists()) {
|
||||||
processResources {
|
copy {
|
||||||
def resourceTargets = ["fabric.mod.json", "META-INF/mods.toml"] // Location of where to put
|
from(sourceSets.main.resources) {
|
||||||
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
include resourceTargets
|
||||||
def replaceProperties = [
|
expand replaceProperties
|
||||||
version : mod_version,
|
|
||||||
mod_name : mod_name,
|
|
||||||
authors : mod_authors,
|
|
||||||
description : mod_description,
|
|
||||||
homepage : mod_homepage,
|
|
||||||
source : mod_source,
|
|
||||||
issues : mod_issues,
|
|
||||||
minecraft_version : minecraft_version,
|
|
||||||
compatible_minecraft_versions: compatible_minecraft_versions,
|
|
||||||
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
|
|
||||||
//TODO: Make Forge loader version also be relaced with non hardcoded value instead of "[36,41)"
|
|
||||||
|
|
||||||
inputs.properties replaceProperties
|
|
||||||
replaceProperties.put 'project', project
|
|
||||||
filesMatching(resourceTargets) {
|
|
||||||
expand replaceProperties
|
|
||||||
}
|
|
||||||
|
|
||||||
intoTargets.each { target ->
|
|
||||||
if (file(target).exists()) {
|
|
||||||
copy {
|
|
||||||
from(sourceSets.main.resources) {
|
|
||||||
include resourceTargets
|
|
||||||
expand replaceProperties
|
|
||||||
}
|
|
||||||
into target
|
|
||||||
}
|
}
|
||||||
|
into target
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Copies the correct accesswidener and renames it
|
|
||||||
task copyAccessWidener(type: Copy) {
|
|
||||||
from project(":common").file("src/main/resources/${rootProject.acsessWidenerVersion}.lod.accesswidener")
|
|
||||||
into(file(p.file("build/resources/main")))
|
|
||||||
rename "${rootProject.acsessWidenerVersion}.lod.accesswidener", "lod.accesswidener"
|
|
||||||
}
|
|
||||||
|
|
||||||
task copyCoreResources(type: Copy) {
|
|
||||||
from fileTree(project(":core").file("src/main/resources"))
|
|
||||||
into p.file("build/resources/main")
|
|
||||||
}
|
|
||||||
|
|
||||||
task copyCommonResources(type: Copy) {
|
|
||||||
from fileTree(project(":common").file("src/main/resources"))
|
|
||||||
into p.file("build/resources/main")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Is this necessary for running the fabric build
|
|
||||||
if (p == project(":common")) {
|
|
||||||
println "Copying [common/src/main/resources/${acsessWidenerVersion}.lod.accesswidner] to [fabric/build/resources/main]."
|
|
||||||
|
|
||||||
copy {
|
|
||||||
from project(":common").file("src/main/resources/${acsessWidenerVersion}.lod.accesswidener")
|
|
||||||
into project(":fabric").file("build/resources/main")
|
|
||||||
rename "${acsessWidenerVersion}.lod.accesswidener", "lod.accesswidener"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
|
||||||
// Add Manifold Preprocessor
|
|
||||||
// def excapedMCVersion = rootProject.minecraft_version.replace(".", "_")
|
|
||||||
// options.compilerArgs += ['-Xplugin:Manifold', "-AMC_VERSION_${excapedMCVersion}"]
|
|
||||||
//
|
|
||||||
//options.compilerArgs += ['-deprecation']
|
|
||||||
//options.compilerArgs += ['-verbose']
|
|
||||||
//options.compilerArgs += ['-Xlint:unchecked']
|
|
||||||
//options.compilerArgs += ['-Xdiags:verbose']
|
|
||||||
//options.compilerArgs += ['-Xprint']
|
|
||||||
//options.compilerArgs += ['-XprintProcessorInfo']
|
|
||||||
//options.compilerArgs += ['-XprintRounds']
|
|
||||||
|
|
||||||
// println options.compilerArgs
|
|
||||||
|
|
||||||
// Set the java version
|
|
||||||
if (p != project(":core")) {
|
|
||||||
options.compilerArgs += ['-Xplugin:Manifold']
|
|
||||||
options.release = rootProject.java_version as Integer
|
|
||||||
} else if (p == project(":core")) {
|
|
||||||
options.release = 8; // Core should use Java 8 no matter what
|
|
||||||
}
|
|
||||||
// TODO: make everything use java 8
|
|
||||||
// options.release = 8 // Use Java 8 for everything so back porting is easier
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
withSourcesJar()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable running the core and common
|
|
||||||
if (p == project(":core") || p == project(":common")) {
|
|
||||||
runClient.enabled = false
|
|
||||||
runServer.enabled = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copies the correct accesswidener and renames it
|
||||||
|
task copyAccessWidener(type: Copy) {
|
||||||
|
from project(":common").file("src/main/resources/${rootProject.acsessWidenerVersion}.lod.accesswidener")
|
||||||
|
into(file("build/resources/main"))
|
||||||
|
rename "${rootProject.acsessWidenerVersion}.lod.accesswidener", "lod.accesswidener"
|
||||||
|
}
|
||||||
|
|
||||||
|
task copyCoreResources(type: Copy) {
|
||||||
|
from fileTree(project(":core").file("src/main/resources"))
|
||||||
|
into file("build/resources/main")
|
||||||
|
}
|
||||||
|
|
||||||
|
task copyCommonResources(type: Copy) {
|
||||||
|
from fileTree(project(":common").file("src/main/resources"))
|
||||||
|
into file("build/resources/main")
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
//runClient.enabled = false
|
||||||
|
//runServer.enabled = false
|
||||||
|
|
||||||
// this deletes the merged folder so we don't carry over
|
// this deletes the merged folder so we don't carry over
|
||||||
// the previous merges to each new build job in the CI/CD pipeline
|
// the previous merges to each new build job in the CI/CD pipeline
|
||||||
task deleteMerged(type: Delete) {
|
task deleteMerged(type: Delete) {
|
||||||
delete files("./Merged")
|
delete files("./Merged")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ===============================CORE Gradle basically================================
|
||||||
|
subprojects { p ->
|
||||||
|
if (p == project(":core")) {
|
||||||
|
|
||||||
|
apply plugin: "java"
|
||||||
|
apply plugin: "architectury-plugin"
|
||||||
|
apply plugin: "maven-publish"
|
||||||
|
apply plugin: "dev.architectury.loom"
|
||||||
|
|
||||||
|
p.archivesBaseName = rootProject.archives_base_name
|
||||||
|
p.version = rootProject.mod_version
|
||||||
|
p.group = rootProject.maven_group
|
||||||
|
|
||||||
|
loom {
|
||||||
|
silentMojangMappingsLicense()
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
common
|
||||||
|
shadowMe
|
||||||
|
implementation.extendsFrom shadowMe
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||||
|
// The following line declares the mojmap mappings & parchment mappings
|
||||||
|
mappings loom.layered() {
|
||||||
|
// Mojmap mappings
|
||||||
|
officialMojangMappings()
|
||||||
|
// Parchment mappings (it adds parameter mappings & javadoc)
|
||||||
|
if (rootProject.minecraft_version != "1.19")
|
||||||
|
parchment("org.parchmentmc.data:parchment-${rootProject.minecraft_version}:${rootProject.parchment_version}@zip")
|
||||||
|
else
|
||||||
|
parchment("org.parchmentmc.data:parchment-1.18.2:${rootProject.parchment_version}@zip") // As 1.19 dosnt have parchment mappings yet, we use 1.18.2 mapping
|
||||||
|
}
|
||||||
|
|
||||||
|
//Manifold
|
||||||
|
annotationProcessor "systems.manifold:manifold-preprocessor:${rootProject.manifold_version}"
|
||||||
|
|
||||||
|
// Toml
|
||||||
|
implementation("com.electronwill.night-config:toml:${rootProject.toml_version}")
|
||||||
|
|
||||||
|
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
|
||||||
|
// Do NOT use other classes from fabric loader unless working with fabric
|
||||||
|
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allows the jar to run standalone
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes 'Implementation-Title': rootProject.archives_base_name,
|
||||||
|
'Implementation-Version': rootProject.mod_version,
|
||||||
|
'Main-Class': 'com.seibel.lod.core.JarMain'
|
||||||
|
// When changing the main of the jar change this line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task printConfigurations {
|
||||||
|
doLast {task ->
|
||||||
|
println "Project Name: $p.name configurations:"
|
||||||
|
configurations.each {
|
||||||
|
println " $it.name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
|
||||||
|
// For parchment mappings
|
||||||
|
maven { url "https://maven.parchmentmc.org" }
|
||||||
|
|
||||||
|
// used to download and compile dependencies from git repos
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
|
||||||
|
// For Manifold Preprocessor
|
||||||
|
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
|
||||||
|
|
||||||
|
// Required for importing Modrinth mods
|
||||||
|
maven {
|
||||||
|
name = "Modrinth"
|
||||||
|
url = "https://api.modrinth.com/maven"
|
||||||
|
content {
|
||||||
|
includeGroup "maven.modrinth"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required for importing CursedForge mods
|
||||||
|
maven {
|
||||||
|
url "https://www.cursemaven.com"
|
||||||
|
content {
|
||||||
|
includeGroup "curse.maven"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// These 2 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
|
||||||
|
flatDir {
|
||||||
|
dirs "${rootDir}/mods/fabric"
|
||||||
|
content {
|
||||||
|
includeGroup "fabric-mod"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flatDir {
|
||||||
|
dirs "${rootDir}/mods/forge"
|
||||||
|
content {
|
||||||
|
includeGroup "forge-mod"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
def resourceTargets = ["fabric.mod.json", "META-INF/mods.toml"] // Location of where to put
|
||||||
|
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
||||||
|
def replaceProperties = [
|
||||||
|
version : mod_version,
|
||||||
|
mod_name : mod_name,
|
||||||
|
authors : mod_authors,
|
||||||
|
description : mod_description,
|
||||||
|
homepage : mod_homepage,
|
||||||
|
source : mod_source,
|
||||||
|
issues : mod_issues,
|
||||||
|
minecraft_version : minecraft_version,
|
||||||
|
compatible_minecraft_versions: compatible_minecraft_versions,
|
||||||
|
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
|
||||||
|
//TODO: Make Forge loader version also be relaced with non hardcoded value instead of "[36,42)"
|
||||||
|
|
||||||
|
inputs.properties replaceProperties
|
||||||
|
replaceProperties.put 'project', project
|
||||||
|
filesMatching(resourceTargets) {
|
||||||
|
expand replaceProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
intoTargets.each { target ->
|
||||||
|
if (file(target).exists()) {
|
||||||
|
copy {
|
||||||
|
from(sourceSets.main.resources) {
|
||||||
|
include resourceTargets
|
||||||
|
expand replaceProperties
|
||||||
|
}
|
||||||
|
into target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Copies the correct accesswidener and renames it
|
||||||
|
task copyAccessWidener(type: Copy) {
|
||||||
|
from project(":common").file("src/main/resources/${rootProject.acsessWidenerVersion}.lod.accesswidener")
|
||||||
|
into(file(p.file("build/resources/main")))
|
||||||
|
rename "${rootProject.acsessWidenerVersion}.lod.accesswidener", "lod.accesswidener"
|
||||||
|
}
|
||||||
|
|
||||||
|
task copyCoreResources(type: Copy) {
|
||||||
|
from fileTree(project(":core").file("src/main/resources"))
|
||||||
|
into p.file("build/resources/main")
|
||||||
|
}
|
||||||
|
|
||||||
|
task copyCommonResources(type: Copy) {
|
||||||
|
from fileTree(project(":common").file("src/main/resources"))
|
||||||
|
into p.file("build/resources/main")
|
||||||
|
}
|
||||||
|
|
||||||
|
p.tasks.withType(JavaCompile) {
|
||||||
|
// Add Manifold Preprocessor
|
||||||
|
// def excapedMCVersion = rootProject.minecraft_version.replace(".", "_")
|
||||||
|
// options.compilerArgs += ['-Xplugin:Manifold', "-AMC_VERSION_${excapedMCVersion}"]
|
||||||
|
//
|
||||||
|
//options.compilerArgs += ['-deprecation']
|
||||||
|
//options.compilerArgs += ['-verbose']
|
||||||
|
//options.compilerArgs += ['-Xlint:unchecked']
|
||||||
|
//options.compilerArgs += ['-Xdiags:verbose']
|
||||||
|
//options.compilerArgs += ['-Xprint']
|
||||||
|
//options.compilerArgs += ['-XprintProcessorInfo']
|
||||||
|
//options.compilerArgs += ['-XprintRounds']
|
||||||
|
|
||||||
|
// println options.compilerArgs
|
||||||
|
|
||||||
|
// Set the java version
|
||||||
|
options.release = 8; // Core should use Java 8 no matter what
|
||||||
|
// TODO: make everything use java 8
|
||||||
|
// options.release = 8 // Use Java 8 for everything so back porting is easier
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
p.runClient.enabled = false
|
||||||
|
p.runServer.enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
+200
-7
@@ -1,12 +1,64 @@
|
|||||||
|
apply plugin: "java"
|
||||||
|
apply plugin: "architectury-plugin"
|
||||||
|
apply plugin: "maven-publish"
|
||||||
|
apply plugin: "dev.architectury.loom"
|
||||||
|
|
||||||
|
archivesBaseName = rootProject.archives_base_name
|
||||||
|
version = rootProject.mod_version
|
||||||
|
group = rootProject.maven_group
|
||||||
|
|
||||||
architectury {
|
architectury {
|
||||||
common()
|
common(rootProject.enabled_platforms.split(","))
|
||||||
}
|
}
|
||||||
|
|
||||||
afterEvaluate {
|
loom {
|
||||||
tasks {
|
silentMojangMappingsLicense()
|
||||||
remapJar {
|
accessWidenerPath.set(project(":common").file("src/main/resources/${acsessWidenerVersion}.lod.accesswidener"))
|
||||||
remapAccessWidener.set(false)
|
}
|
||||||
}
|
|
||||||
|
configurations {
|
||||||
|
common
|
||||||
|
shadowMe
|
||||||
|
implementation.extendsFrom shadowMe
|
||||||
|
}
|
||||||
|
java {
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||||
|
// The following line declares the mojmap mappings & parchment mappings
|
||||||
|
mappings loom.layered() {
|
||||||
|
// Mojmap mappings
|
||||||
|
officialMojangMappings()
|
||||||
|
// Parchment mappings (it adds parameter mappings & javadoc)
|
||||||
|
if (rootProject.minecraft_version != "1.19")
|
||||||
|
parchment("org.parchmentmc.data:parchment-${rootProject.minecraft_version}:${rootProject.parchment_version}@zip")
|
||||||
|
else
|
||||||
|
parchment("org.parchmentmc.data:parchment-1.18.2:${rootProject.parchment_version}@zip") // As 1.19 dosnt have parchment mappings yet, we use 1.18.2 mapping
|
||||||
|
}
|
||||||
|
|
||||||
|
//Manifold
|
||||||
|
annotationProcessor "systems.manifold:manifold-preprocessor:${rootProject.manifold_version}"
|
||||||
|
|
||||||
|
// Toml
|
||||||
|
implementation("com.electronwill.night-config:toml:${rootProject.toml_version}")
|
||||||
|
|
||||||
|
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
|
||||||
|
// Do NOT use other classes from fabric loader unless working with fabric
|
||||||
|
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"\
|
||||||
|
|
||||||
|
common(project(":core")) { transitive false }
|
||||||
|
shadowMe(project(":core")) { transitive false }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allows the jar to run standalone
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes 'Implementation-Title': rootProject.archives_base_name,
|
||||||
|
'Implementation-Version': rootProject.mod_version,
|
||||||
|
'Main-Class': 'com.seibel.lod.core.JarMain' // When changing the main of the jar change this line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,4 +74,145 @@ publishing {
|
|||||||
repositories {
|
repositories {
|
||||||
// Add repositories to publish to here.
|
// Add repositories to publish to here.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task printConfigurations {
|
||||||
|
doLast {task ->
|
||||||
|
println "Project Name: $name configurations:"
|
||||||
|
configurations.each {
|
||||||
|
println " $it.name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
|
||||||
|
// For parchment mappings
|
||||||
|
maven { url "https://maven.parchmentmc.org" }
|
||||||
|
|
||||||
|
// used to download and compile dependencies from git repos
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
|
||||||
|
// For Manifold Preprocessor
|
||||||
|
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
|
||||||
|
|
||||||
|
// Required for importing Modrinth mods
|
||||||
|
maven {
|
||||||
|
name = "Modrinth"
|
||||||
|
url = "https://api.modrinth.com/maven"
|
||||||
|
content {
|
||||||
|
includeGroup "maven.modrinth"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required for importing CursedForge mods
|
||||||
|
maven {
|
||||||
|
url "https://www.cursemaven.com"
|
||||||
|
content {
|
||||||
|
includeGroup "curse.maven"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// These 2 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
|
||||||
|
flatDir {
|
||||||
|
dirs "${rootDir}/mods/fabric"
|
||||||
|
content {
|
||||||
|
includeGroup "fabric-mod"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flatDir {
|
||||||
|
dirs "${rootDir}/mods/forge"
|
||||||
|
content {
|
||||||
|
includeGroup "forge-mod"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies the correct accesswidener and renames it
|
||||||
|
task copyAccessWidener(type: Copy) {
|
||||||
|
from project(":common").file("src/main/resources/${rootProject.acsessWidenerVersion}.lod.accesswidener")
|
||||||
|
into(file("build/resources/main"))
|
||||||
|
rename "${rootProject.acsessWidenerVersion}.lod.accesswidener", "lod.accesswidener"
|
||||||
|
}
|
||||||
|
|
||||||
|
task copyCoreResources(type: Copy) {
|
||||||
|
from fileTree(project(":core").file("src/main/resources"))
|
||||||
|
into file("build/resources/main")
|
||||||
|
}
|
||||||
|
|
||||||
|
task copyCommonResources(type: Copy) {
|
||||||
|
from fileTree(project(":common").file("src/main/resources"))
|
||||||
|
into file("build/resources/main")
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
def resourceTargets = ["fabric.mod.json", "META-INF/mods.toml"] // Location of where to put
|
||||||
|
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
||||||
|
def replaceProperties = [
|
||||||
|
version : mod_version,
|
||||||
|
mod_name : mod_name,
|
||||||
|
authors : mod_authors,
|
||||||
|
description : mod_description,
|
||||||
|
homepage : mod_homepage,
|
||||||
|
source : mod_source,
|
||||||
|
issues : mod_issues,
|
||||||
|
minecraft_version : minecraft_version,
|
||||||
|
compatible_minecraft_versions: compatible_minecraft_versions,
|
||||||
|
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
|
||||||
|
//TODO: Make Forge loader version also be relaced with non hardcoded value instead of "[36,42)"
|
||||||
|
|
||||||
|
inputs.properties replaceProperties
|
||||||
|
replaceProperties.put 'project', project
|
||||||
|
filesMatching(resourceTargets) {
|
||||||
|
expand replaceProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
intoTargets.each { target ->
|
||||||
|
if (file(target).exists()) {
|
||||||
|
copy {
|
||||||
|
from(sourceSets.main.resources) {
|
||||||
|
include resourceTargets
|
||||||
|
expand replaceProperties
|
||||||
|
}
|
||||||
|
into target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println "Copying [common/src/main/resources/${acsessWidenerVersion}.lod.accesswidner] to [fabric/build/resources/main]."
|
||||||
|
copy {
|
||||||
|
from project(":common").file("src/main/resources/${acsessWidenerVersion}.lod.accesswidener")
|
||||||
|
into project(":fabric").file("build/resources/main")
|
||||||
|
rename "${acsessWidenerVersion}.lod.accesswidener", "lod.accesswidener"
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile) {
|
||||||
|
// Add Manifold Preprocessor
|
||||||
|
// def excapedMCVersion = rootProject.minecraft_version.replace(".", "_")
|
||||||
|
// options.compilerArgs += ['-Xplugin:Manifold', "-AMC_VERSION_${excapedMCVersion}"]
|
||||||
|
//
|
||||||
|
//options.compilerArgs += ['-deprecation']
|
||||||
|
//options.compilerArgs += ['-verbose']
|
||||||
|
//options.compilerArgs += ['-Xlint:unchecked']
|
||||||
|
//options.compilerArgs += ['-Xdiags:verbose']
|
||||||
|
//options.compilerArgs += ['-Xprint']
|
||||||
|
//options.compilerArgs += ['-XprintProcessorInfo']
|
||||||
|
//options.compilerArgs += ['-XprintRounds']
|
||||||
|
|
||||||
|
// println options.compilerArgs
|
||||||
|
|
||||||
|
// Set the java version
|
||||||
|
options.compilerArgs += ['-Xplugin:Manifold']
|
||||||
|
options.release = rootProject.java_version as Integer
|
||||||
|
// TODO: make everything use java 8
|
||||||
|
// options.release = 8 // Use Java 8 for everything so back porting is easier
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcesJar {
|
||||||
|
}
|
||||||
|
|
||||||
|
runClient.enabled = false
|
||||||
|
runServer.enabled = false
|
||||||
@@ -35,7 +35,7 @@ import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton.I
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This handles any configuration the user has access to.
|
* This handles any configuration the user has access to.
|
||||||
* @author coolGi2007
|
* @author coolGi
|
||||||
* @version 12-12-2021
|
* @version 12-12-2021
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,8 @@ public class LodCommonMain {
|
|||||||
public static boolean forge = false;
|
public static boolean forge = false;
|
||||||
public static boolean serverSided;
|
public static boolean serverSided;
|
||||||
public static LodForgeMethodCaller forgeMethodCaller;
|
public static LodForgeMethodCaller forgeMethodCaller;
|
||||||
public static NetworkInterface networkInterface;
|
|
||||||
|
|
||||||
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;
|
||||||
@@ -42,13 +41,6 @@ public class LodCommonMain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DependencySetup.createInitialBindings();
|
DependencySetup.createInitialBindings();
|
||||||
|
|
||||||
LodCommonMain.networkInterface = networkInterface;
|
|
||||||
if (!serverSided) {
|
|
||||||
networkInterface.register_Client();
|
|
||||||
} else {
|
|
||||||
networkInterface.register_Server();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ package com.seibel.lod.common.forge;
|
|||||||
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
|
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;
|
||||||
|
#if POST_MC_1_19
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
#endif
|
||||||
import net.minecraft.world.level.ColorResolver;
|
import net.minecraft.world.level.ColorResolver;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
@@ -36,7 +39,11 @@ import java.util.Random;
|
|||||||
* @author Ran
|
* @author Ran
|
||||||
*/
|
*/
|
||||||
public interface LodForgeMethodCaller {
|
public interface LodForgeMethodCaller {
|
||||||
List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, Random random);
|
#if PRE_MC_1_19
|
||||||
|
List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, Random random); // FIXME: For 1.19
|
||||||
|
#else
|
||||||
|
List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, RandomSource random); // FIXME: For 1.19
|
||||||
|
#endif
|
||||||
|
|
||||||
int colorResolverGetColor(ColorResolver resolver, Biome biome, double x, double z);
|
int colorResolverGetColor(ColorResolver resolver, Biome biome, double x, double z);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,10 @@ public class McObjectConverter
|
|||||||
directions = new Direction[lodDirs.length];
|
directions = new Direction[lodDirs.length];
|
||||||
lodDirections = new LodDirection[lodDirs.length];
|
lodDirections = new LodDirection[lodDirs.length];
|
||||||
for (LodDirection lodDir : lodDirs) {
|
for (LodDirection lodDir : lodDirs) {
|
||||||
Direction dir = Direction.byName(lodDir.name());
|
Direction dir = Enum.valueOf(Direction.class, lodDir.name());
|
||||||
|
if (dir == null) {
|
||||||
|
throw new IllegalArgumentException("Invalid direction on init mapping: " + lodDir);
|
||||||
|
}
|
||||||
directions[lodDir.ordinal()] = dir;
|
directions[lodDir.ordinal()] = dir;
|
||||||
lodDirections[dir.ordinal()] = lodDir;
|
lodDirections[dir.ordinal()] = lodDir;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ import net.minecraft.world.phys.BlockHitResult;
|
|||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
#if POST_MC_1_19
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*-- WARN: This class should NEVER hold reference to anything large,
|
/*-- WARN: This class should NEVER hold reference to anything large,
|
||||||
as this is never dealloc until the end of runtime!! --*/
|
as this is never dealloc until the end of runtime!! --*/
|
||||||
@@ -77,7 +80,11 @@ public class BlockDetailWrapper extends IBlockDetailWrapper
|
|||||||
|
|
||||||
public static final int FLOWER_COLOR_SCALE = 5;
|
public static final int FLOWER_COLOR_SCALE = 5;
|
||||||
|
|
||||||
|
#if PRE_MC_1_19
|
||||||
public static final Random random = new Random(0);
|
public static final Random random = new Random(0);
|
||||||
|
#else
|
||||||
|
public static final RandomSource random = RandomSource.create();
|
||||||
|
#endif
|
||||||
|
|
||||||
enum ColorMode {
|
enum ColorMode {
|
||||||
Default,
|
Default,
|
||||||
|
|||||||
@@ -47,8 +47,10 @@ import net.minecraft.client.gui.components.events.GuiEventListener;
|
|||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.network.chat.CommonComponents;
|
import net.minecraft.network.chat.CommonComponents;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraft.network.chat.TextComponent;
|
import net.minecraft.network.chat.TextComponent;
|
||||||
import net.minecraft.network.chat.TranslatableComponent;
|
import net.minecraft.network.chat.TranslatableComponent;
|
||||||
|
#endif
|
||||||
import net.minecraft.client.resources.language.I18n; // translation
|
import net.minecraft.client.resources.language.I18n; // translation
|
||||||
#if POST_MC_1_17_1
|
#if POST_MC_1_17_1
|
||||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
import net.minecraft.client.gui.narration.NarratableEntry;
|
||||||
@@ -62,29 +64,15 @@ import net.minecraft.client.gui.narration.NarratableEntry;
|
|||||||
*
|
*
|
||||||
* Credits to Motschen
|
* Credits to Motschen
|
||||||
*
|
*
|
||||||
* @author coolGi2007
|
* REMOVED IN a1.7
|
||||||
|
*
|
||||||
|
* @author coolGi
|
||||||
* @version 1-14-2022
|
* @version 1-14-2022
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public abstract class ConfigGui
|
public abstract class ConfigGui
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
TODO list
|
|
||||||
|
|
||||||
Fix floats not working
|
|
||||||
Make a wiki
|
|
||||||
Make it so you can enable and disable buttons from showing
|
|
||||||
Make min and max not final
|
|
||||||
Move the ConfigScreenConfigs class to the config class that extends this
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
List of hacky things that are done that should be done properly
|
|
||||||
|
|
||||||
The buttons that don't show are still loaded but just not rendered
|
|
||||||
The screen with is set to double so the scroll bar doesn't show
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
private static final Pattern INTEGER_ONLY_REGEX = Pattern.compile("(-?[0-9]*)");
|
private static final Pattern INTEGER_ONLY_REGEX = Pattern.compile("(-?[0-9]*)");
|
||||||
private static final Pattern DECIMAL_ONLY_REGEX = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
|
private static final Pattern DECIMAL_ONLY_REGEX = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
|
||||||
|
|
||||||
@@ -123,7 +111,11 @@ public abstract class ConfigGui
|
|||||||
Object value;
|
Object value;
|
||||||
String tempValue;
|
String tempValue;
|
||||||
boolean inLimits = true;
|
boolean inLimits = true;
|
||||||
|
#if PRE_MC_1_19
|
||||||
TranslatableComponent name;
|
TranslatableComponent name;
|
||||||
|
#else
|
||||||
|
Component name;
|
||||||
|
#endif
|
||||||
int index;
|
int index;
|
||||||
/** Hides the button */
|
/** Hides the button */
|
||||||
boolean hideOption = false;
|
boolean hideOption = false;
|
||||||
@@ -220,8 +212,11 @@ public abstract class ConfigGui
|
|||||||
if (entry != null)
|
if (entry != null)
|
||||||
{
|
{
|
||||||
if (!entry.name().equals(""))
|
if (!entry.name().equals(""))
|
||||||
|
#if PRE_MC_1_19
|
||||||
info.name = new TranslatableComponent(entry.name());
|
info.name = new TranslatableComponent(entry.name());
|
||||||
|
#else
|
||||||
|
info.name = Component.translatable(entry.name());
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fieldClass == int.class)
|
if (fieldClass == int.class)
|
||||||
{
|
{
|
||||||
@@ -242,7 +237,11 @@ public abstract class ConfigGui
|
|||||||
else if (fieldClass == boolean.class)
|
else if (fieldClass == boolean.class)
|
||||||
{
|
{
|
||||||
// For boolean
|
// For boolean
|
||||||
|
#if PRE_MC_1_19
|
||||||
Function<Object, Component> func = value -> new TextComponent((Boolean) value ? "True" : "False").withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
|
Function<Object, Component> func = value -> new TextComponent((Boolean) value ? "True" : "False").withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
|
||||||
|
#else
|
||||||
|
Function<Object, Component> func = value -> Component.translatable((Boolean) value ? "True" : "False").withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
|
||||||
|
#endif
|
||||||
info.widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
|
info.widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
|
||||||
info.value = !(Boolean) info.value;
|
info.value = !(Boolean) info.value;
|
||||||
button.setMessage(func.apply(info.value));
|
button.setMessage(func.apply(info.value));
|
||||||
@@ -252,7 +251,11 @@ public abstract class ConfigGui
|
|||||||
{
|
{
|
||||||
// For enum
|
// For enum
|
||||||
List<?> values = Arrays.asList(field.getType().getEnumConstants());
|
List<?> values = Arrays.asList(field.getType().getEnumConstants());
|
||||||
|
#if PRE_MC_1_19
|
||||||
Function<Object, Component> func = value -> new TranslatableComponent(MOD_NAME + ".config." + "enum." + fieldClass.getSimpleName() + "." + info.value.toString());
|
Function<Object, Component> func = value -> new TranslatableComponent(MOD_NAME + ".config." + "enum." + fieldClass.getSimpleName() + "." + info.value.toString());
|
||||||
|
#else
|
||||||
|
Function<Object, Component> func = value -> Component.translatable(MOD_NAME + ".config." + "enum." + fieldClass.getSimpleName() + "." + info.value.toString());
|
||||||
|
#endif
|
||||||
info.widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
|
info.widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
|
||||||
int index = values.indexOf(info.value) + 1;
|
int index = values.indexOf(info.value) + 1;
|
||||||
info.value = values.get(index >= values.size() ? 0 : index);
|
info.value = values.get(index >= values.size() ? 0 : index);
|
||||||
@@ -263,7 +266,12 @@ public abstract class ConfigGui
|
|||||||
else if (screenEntry != null)
|
else if (screenEntry != null)
|
||||||
{
|
{
|
||||||
if (!screenEntry.name().equals(""))
|
if (!screenEntry.name().equals(""))
|
||||||
|
#if PRE_MC_1_19
|
||||||
info.name = new TranslatableComponent(screenEntry.name());
|
info.name = new TranslatableComponent(screenEntry.name());
|
||||||
|
#else
|
||||||
|
info.name = Component.translatable(screenEntry.name());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
info.screenButton = true;
|
info.screenButton = true;
|
||||||
info.gotoScreen = (!info.category.isEmpty() ? info.category + "." : "") + field.getName();
|
info.gotoScreen = (!info.category.isEmpty() ? info.category + "." : "") + field.getName();
|
||||||
@@ -291,7 +299,11 @@ public abstract class ConfigGui
|
|||||||
{
|
{
|
||||||
value = func.apply(stringValue);
|
value = func.apply(stringValue);
|
||||||
inLimits = value.doubleValue() >= minValue && value.doubleValue() <= maxValue;
|
inLimits = value.doubleValue() >= minValue && value.doubleValue() <= maxValue;
|
||||||
|
#if PRE_MC_1_19
|
||||||
info.error = inLimits ? null : new AbstractMap.SimpleEntry<>(editBox, new TextComponent(value.doubleValue() < minValue ?
|
info.error = inLimits ? null : new AbstractMap.SimpleEntry<>(editBox, new TextComponent(value.doubleValue() < minValue ?
|
||||||
|
#else
|
||||||
|
info.error = inLimits ? null : new AbstractMap.SimpleEntry<>(editBox, Component.translatable(value.doubleValue() < minValue ?
|
||||||
|
#endif
|
||||||
"§cMinimum " + "length" + (cast ? " is " + (int) minValue : " is " + minValue) :
|
"§cMinimum " + "length" + (cast ? " is " + (int) minValue : " is " + minValue) :
|
||||||
"§cMaximum " + "length" + (cast ? " is " + (int) maxValue : " is " + maxValue)));
|
"§cMaximum " + "length" + (cast ? " is " + (int) maxValue : " is " + maxValue)));
|
||||||
}
|
}
|
||||||
@@ -331,6 +343,8 @@ public abstract class ConfigGui
|
|||||||
|
|
||||||
// First try to create a config file
|
// First try to create a config file
|
||||||
try {
|
try {
|
||||||
|
if (!configFilePath.getParent().toFile().exists())
|
||||||
|
Files.createDirectory(configFilePath.getParent());
|
||||||
if (!Files.exists(configFilePath))
|
if (!Files.exists(configFilePath))
|
||||||
Files.createFile(configFilePath);
|
Files.createFile(configFilePath);
|
||||||
}
|
}
|
||||||
@@ -343,8 +357,7 @@ public abstract class ConfigGui
|
|||||||
|
|
||||||
|
|
||||||
// Just put this here for the future
|
// Just put this here for the future
|
||||||
config.setComment("_Version", " DONT TOUCH THIS, IF YOU DO THEN CONFIG FILE WOULD BREAK");
|
config.set("_version", 1);
|
||||||
config.set("_Versions", ModInfo.VERSION);
|
|
||||||
|
|
||||||
|
|
||||||
for (EntryInfo info : entries) {
|
for (EntryInfo info : entries) {
|
||||||
@@ -379,8 +392,7 @@ public abstract class ConfigGui
|
|||||||
|
|
||||||
|
|
||||||
// Just put this here for the future
|
// Just put this here for the future
|
||||||
config.setComment("_Version", " DONT TOUCH THIS, IF YOU DO THEN CONFIG FILE WOULD BREAK");
|
config.set("_version", 1);
|
||||||
config.set("_Versions", ModInfo.VERSION);
|
|
||||||
|
|
||||||
|
|
||||||
// Puts everything into its variable
|
// Puts everything into its variable
|
||||||
@@ -451,8 +463,13 @@ public abstract class ConfigGui
|
|||||||
{
|
{
|
||||||
String itemPath = (info.category.isEmpty() ? "" : info.category + ".") + info.field.getName();
|
String itemPath = (info.category.isEmpty() ? "" : info.category + ".") + info.field.getName();
|
||||||
if (config.contains(itemPath)) {
|
if (config.contains(itemPath)) {
|
||||||
if (info.field.getType().isEnum())
|
if (info.field.getType().isEnum()) {
|
||||||
info.value = config.getEnum(itemPath, info.varClass);
|
try {
|
||||||
|
info.value = config.getEnum(itemPath, info.varClass);
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
info.value = config.get(itemPath);
|
info.value = config.get(itemPath);
|
||||||
} else
|
} else
|
||||||
@@ -498,7 +515,11 @@ public abstract class ConfigGui
|
|||||||
{
|
{
|
||||||
protected ConfigScreen(Screen parent, String category)
|
protected ConfigScreen(Screen parent, String category)
|
||||||
{
|
{
|
||||||
|
#if PRE_MC_1_19
|
||||||
super(new TranslatableComponent(
|
super(new TranslatableComponent(
|
||||||
|
#else
|
||||||
|
super(Component.translatable(
|
||||||
|
#endif
|
||||||
I18n.exists(MOD_NAME + ".config" + (category.isEmpty()? "." + category : "") + ".title") ?
|
I18n.exists(MOD_NAME + ".config" + (category.isEmpty()? "." + category : "") + ".title") ?
|
||||||
MOD_NAME + ".config.title" :
|
MOD_NAME + ".config.title" :
|
||||||
MOD_NAME + ".config" + (category.isEmpty() ? "" : "." + category) + ".title")
|
MOD_NAME + ".config" + (category.isEmpty() ? "" : "." + category) + ".title")
|
||||||
@@ -565,8 +586,13 @@ public abstract class ConfigGui
|
|||||||
{
|
{
|
||||||
if (info.category.matches(category) && !info.hideOption)
|
if (info.category.matches(category) && !info.hideOption)
|
||||||
{
|
{
|
||||||
|
#if PRE_MC_1_19
|
||||||
TranslatableComponent name = (info.name == null ? new TranslatableComponent(translationPrefix + (!info.category.isEmpty() ? info.category + "." : "") + info.field.getName()) : info.name);
|
TranslatableComponent name = (info.name == null ? new TranslatableComponent(translationPrefix + (!info.category.isEmpty() ? info.category + "." : "") + info.field.getName()) : info.name);
|
||||||
Button resetButton = new Button(this.width - ConfigScreenConfigs.SpaceFromRightScreen - info.width - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth, 0, ConfigScreenConfigs.ResetButtonWidth, 20, new TextComponent("Reset").withStyle(ChatFormatting.RED), (button -> {
|
Button resetButton = new Button(this.width - ConfigScreenConfigs.SpaceFromRightScreen - info.width - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth, 0, ConfigScreenConfigs.ResetButtonWidth, 20, new TextComponent("Reset").withStyle(ChatFormatting.RED), (button -> {
|
||||||
|
#else
|
||||||
|
Component name = (info.name == null ? Component.translatable(translationPrefix + (!info.category.isEmpty() ? info.category + "." : "") + info.field.getName()) : info.name);
|
||||||
|
Button resetButton = new Button(this.width - ConfigScreenConfigs.SpaceFromRightScreen - info.width - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth, 0, ConfigScreenConfigs.ResetButtonWidth, 20, Component.translatable("Reset").withStyle(ChatFormatting.RED), (button -> {
|
||||||
|
#endif
|
||||||
info.value = info.defaultValue;
|
info.value = info.defaultValue;
|
||||||
info.tempValue = info.defaultValue.toString();
|
info.tempValue = info.defaultValue.toString();
|
||||||
info.index = 0;
|
info.index = 0;
|
||||||
@@ -578,7 +604,11 @@ public abstract class ConfigGui
|
|||||||
{
|
{
|
||||||
Map.Entry<Button.OnPress, Function<Object, Component>> widget = (Map.Entry<Button.OnPress, Function<Object, Component>>) info.widget;
|
Map.Entry<Button.OnPress, Function<Object, Component>> widget = (Map.Entry<Button.OnPress, Function<Object, Component>>) info.widget;
|
||||||
if (info.field.getType().isEnum())
|
if (info.field.getType().isEnum())
|
||||||
|
#if PRE_MC_1_19
|
||||||
widget.setValue(value -> new TranslatableComponent(translationPrefix + "enum." + info.field.getType().getSimpleName() + "." + info.value.toString()));
|
widget.setValue(value -> new TranslatableComponent(translationPrefix + "enum." + info.field.getType().getSimpleName() + "." + info.value.toString()));
|
||||||
|
#else
|
||||||
|
widget.setValue(value -> Component.translatable(translationPrefix + "enum." + info.field.getType().getSimpleName() + "." + info.value.toString()));
|
||||||
|
#endif
|
||||||
this.list.addButton(new Button(this.width - info.width - ConfigScreenConfigs.SpaceFromRightScreen, 0, info.width, 20, widget.getValue().apply(info.value), widget.getKey()), resetButton, null, name);
|
this.list.addButton(new Button(this.width - info.width - ConfigScreenConfigs.SpaceFromRightScreen, 0, info.width, 20, widget.getValue().apply(info.value), widget.getKey()), resetButton, null, name);
|
||||||
}
|
}
|
||||||
else if (info.field.getType() == List.class)
|
else if (info.field.getType() == List.class)
|
||||||
@@ -594,8 +624,13 @@ public abstract class ConfigGui
|
|||||||
Predicate<String> processor = ((BiFunction<EditBox, Button, Predicate<String>>) info.widget).apply(widget, done);
|
Predicate<String> processor = ((BiFunction<EditBox, Button, Predicate<String>>) info.widget).apply(widget, done);
|
||||||
widget.setFilter(processor);
|
widget.setFilter(processor);
|
||||||
resetButton.setWidth(20);
|
resetButton.setWidth(20);
|
||||||
resetButton.setMessage(new TextComponent("R").withStyle(ChatFormatting.RED));
|
#if PRE_MC_1_19
|
||||||
Button cycleButton = new Button(this.width - 185, 0, 20, 20, new TextComponent(String.valueOf(info.index)).withStyle(ChatFormatting.GOLD), (button -> {
|
resetButton.setMessage(new TextComponent("R").withStyle(ChatFormatting.RED));
|
||||||
|
Button cycleButton = new Button(this.width - 185, 0, 20, 20, new TextComponent(String.valueOf(info.index)).withStyle(ChatFormatting.GOLD), (button -> {
|
||||||
|
#else
|
||||||
|
resetButton.setMessage(Component.translatable("R").withStyle(ChatFormatting.RED));
|
||||||
|
Button cycleButton = new Button(this.width - 185, 0, 20, 20, Component.translatable(String.valueOf(info.index)).withStyle(ChatFormatting.GOLD), (button -> {
|
||||||
|
#endif
|
||||||
((List<String>) info.value).remove("");
|
((List<String>) info.value).remove("");
|
||||||
this.reload = true;
|
this.reload = true;
|
||||||
info.index = info.index + 1;
|
info.index = info.index + 1;
|
||||||
@@ -644,14 +679,22 @@ public abstract class ConfigGui
|
|||||||
if (list.getHoveredButton(mouseX,mouseY).isPresent()) {
|
if (list.getHoveredButton(mouseX,mouseY).isPresent()) {
|
||||||
AbstractWidget buttonWidget = list.getHoveredButton(mouseX,mouseY).get();
|
AbstractWidget buttonWidget = list.getHoveredButton(mouseX,mouseY).get();
|
||||||
Component text = ButtonEntry.buttonsWithText.get(buttonWidget);
|
Component text = ButtonEntry.buttonsWithText.get(buttonWidget);
|
||||||
|
#if PRE_MC_1_19
|
||||||
TranslatableComponent name = new TranslatableComponent(this.translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.field.getName());
|
TranslatableComponent name = new TranslatableComponent(this.translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.field.getName());
|
||||||
|
#else
|
||||||
|
Component name = Component.translatable(this.translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.field.getName());
|
||||||
|
#endif
|
||||||
String key = translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.field.getName() + ".@tooltip";
|
String key = translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.field.getName() + ".@tooltip";
|
||||||
|
|
||||||
if (info.error != null && text.equals(name)) renderTooltip(matrices, (Component) info.error.getValue(), mouseX, mouseY);
|
if (info.error != null && text.equals(name)) renderTooltip(matrices, (Component) info.error.getValue(), mouseX, mouseY);
|
||||||
else if (I18n.exists(key) && (text != null && text.equals(name))) {
|
else if (I18n.exists(key) && (text != null && text.equals(name))) {
|
||||||
List<Component> list = new ArrayList<>();
|
List<Component> list = new ArrayList<>();
|
||||||
for (String str : I18n.get(key).split("\n"))
|
for (String str : I18n.get(key).split("\n"))
|
||||||
|
#if PRE_MC_1_19
|
||||||
list.add(new TextComponent(str));
|
list.add(new TextComponent(str));
|
||||||
|
#else
|
||||||
|
list.add(Component.translatable(str));
|
||||||
|
#endif
|
||||||
renderComponentTooltip(matrices, list, mouseX, mouseY);
|
renderComponentTooltip(matrices, list, mouseX, mouseY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -55,7 +55,10 @@ import net.minecraft.client.resources.model.ModelManager;
|
|||||||
import net.minecraft.client.server.IntegratedServer;
|
import net.minecraft.client.server.IntegratedServer;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraft.network.chat.TextComponent;
|
import net.minecraft.network.chat.TextComponent;
|
||||||
|
#endif
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
@@ -365,7 +368,11 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper
|
|||||||
@Override
|
@Override
|
||||||
public void sendChatMessage(String string)
|
public void sendChatMessage(String string)
|
||||||
{
|
{
|
||||||
|
#if PRE_MC_1_19
|
||||||
getPlayer().sendMessage(new TextComponent(string), getPlayer().getUUID());
|
getPlayer().sendMessage(new TextComponent(string), getPlayer().getUUID());
|
||||||
|
#else
|
||||||
|
getPlayer().sendSystemMessage(Component.translatable(string));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+4
@@ -133,7 +133,11 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
|||||||
@Override
|
@Override
|
||||||
public double getGamma()
|
public double getGamma()
|
||||||
{
|
{
|
||||||
|
#if PRE_MC_1_19
|
||||||
return MC.options.gamma;
|
return MC.options.gamma;
|
||||||
|
#else
|
||||||
|
return MC.options.gamma().get();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -20,14 +20,26 @@
|
|||||||
package com.seibel.lod.common.wrappers.world;
|
package com.seibel.lod.common.wrappers.world;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableBiMap;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.seibel.lod.core.util.LodUtil;
|
import com.seibel.lod.core.util.LodUtil;
|
||||||
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
|
|
||||||
|
import net.minecraft.data.BuiltinRegistries;
|
||||||
|
#if POST_MC_1_19
|
||||||
|
import net.minecraft.data.worldgen.biome.EndBiomes;
|
||||||
|
import net.minecraft.data.worldgen.biome.NetherBiomes;
|
||||||
|
#endif
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
import net.minecraft.world.level.biome.Biomes;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.material.MaterialColor;
|
import net.minecraft.world.level.material.MaterialColor;
|
||||||
|
|
||||||
@@ -58,13 +70,12 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
return biomeWrapper;
|
return biomeWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Returns a color int for the given biome. */
|
/** Returns a color int for the given biome. */
|
||||||
|
#if PRE_MC_1_19
|
||||||
@Override
|
@Override
|
||||||
public int getColorForBiome(int x, int z)
|
public int getColorForBiome(int x, int z)
|
||||||
{
|
{
|
||||||
int colorInt;
|
int colorInt;
|
||||||
|
|
||||||
switch (biome.biomeCategory)
|
switch (biome.biomeCategory)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -121,7 +132,140 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
|
|
||||||
return colorInt;
|
return colorInt;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
|
||||||
|
private static int _colorEnd(Biome b) {
|
||||||
|
return Blocks.END_STONE.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorNether(Biome b) {
|
||||||
|
return Blocks.NETHERRACK.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorSand(Biome b) {
|
||||||
|
return Blocks.SAND.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorStone(Biome b) {
|
||||||
|
return Blocks.STONE.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorGravel(Biome b) {
|
||||||
|
return Blocks.GRAVEL.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorDripStone(Biome b) {
|
||||||
|
return Blocks.DRIPSTONE_BLOCK.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorMoss(Biome b) {
|
||||||
|
return Blocks.MOSS_BLOCK.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorSculk(Biome b) {
|
||||||
|
return Blocks.SCULK.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorMushoom(Biome b) {
|
||||||
|
return Blocks.MYCELIUM.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorBamboo(Biome b) {
|
||||||
|
return Blocks.BAMBOO.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorSnow(Biome b) {
|
||||||
|
return Blocks.SNOW.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorIce(Biome b) {
|
||||||
|
return Blocks.ICE.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorRedSand(Biome b) {
|
||||||
|
return Blocks.RED_SAND.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorSoulSand(Biome b) {
|
||||||
|
return Blocks.SOUL_SAND.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorBasalt(Biome b) {
|
||||||
|
return Blocks.BASALT.defaultMaterialColor().col;
|
||||||
|
}
|
||||||
|
private static int _colorWater(Biome b) {
|
||||||
|
return b.getWaterColor();
|
||||||
|
}
|
||||||
|
private static int _colorFoliage(Biome b) {
|
||||||
|
return b.getFoliageColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Biome _get(ResourceKey<Biome> r) {
|
||||||
|
return BuiltinRegistries.BIOME.getOrThrow(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIXME: THIS IS HELL!
|
||||||
|
private static final ImmutableBiMap<Biome, Function<Biome, Integer>> BIOME_COLOR_MAP =
|
||||||
|
ImmutableBiMap.<Biome, Function<Biome, Integer>>builder()
|
||||||
|
.put(_get(Biomes.SNOWY_PLAINS), BiomeWrapper::_colorSnow)
|
||||||
|
.put(_get(Biomes.ICE_SPIKES), BiomeWrapper::_colorIce)
|
||||||
|
.put(_get(Biomes.DESERT), BiomeWrapper::_colorSand)
|
||||||
|
.put(_get(Biomes.SWAMP), BiomeWrapper::_colorWater)
|
||||||
|
.put(_get(Biomes.MANGROVE_SWAMP), BiomeWrapper::_colorWater)
|
||||||
|
.put(_get(Biomes.FOREST), BiomeWrapper::_colorFoliage)
|
||||||
|
.put(_get(Biomes.FLOWER_FOREST), BiomeWrapper::_colorFoliage)
|
||||||
|
.put(_get(Biomes.BIRCH_FOREST), BiomeWrapper::_colorFoliage)
|
||||||
|
.put(_get(Biomes.DARK_FOREST), BiomeWrapper::_colorFoliage)
|
||||||
|
.put(_get(Biomes.OLD_GROWTH_BIRCH_FOREST), BiomeWrapper::_colorFoliage)
|
||||||
|
.put(_get(Biomes.OLD_GROWTH_PINE_TAIGA), BiomeWrapper::_colorFoliage)
|
||||||
|
.put(_get(Biomes.OLD_GROWTH_SPRUCE_TAIGA), BiomeWrapper::_colorFoliage)
|
||||||
|
.put(_get(Biomes.TAIGA), BiomeWrapper::_colorFoliage)
|
||||||
|
.put(_get(Biomes.SNOWY_TAIGA), BiomeWrapper::_colorSnow)
|
||||||
|
.put(_get(Biomes.WINDSWEPT_GRAVELLY_HILLS), BiomeWrapper::_colorGravel)
|
||||||
|
.put(_get(Biomes.WINDSWEPT_FOREST), BiomeWrapper::_colorFoliage)
|
||||||
|
.put(_get(Biomes.JUNGLE), BiomeWrapper::_colorFoliage)
|
||||||
|
.put(_get(Biomes.BAMBOO_JUNGLE), BiomeWrapper::_colorBamboo)
|
||||||
|
.put(_get(Biomes.BADLANDS), BiomeWrapper::_colorRedSand)
|
||||||
|
.put(_get(Biomes.ERODED_BADLANDS), BiomeWrapper::_colorRedSand)
|
||||||
|
.put(_get(Biomes.WOODED_BADLANDS), BiomeWrapper::_colorStone)
|
||||||
|
.put(_get(Biomes.GROVE), BiomeWrapper::_colorSnow)
|
||||||
|
.put(_get(Biomes.SNOWY_SLOPES), BiomeWrapper::_colorSnow)
|
||||||
|
.put(_get(Biomes.FROZEN_PEAKS), BiomeWrapper::_colorIce)
|
||||||
|
.put(_get(Biomes.JAGGED_PEAKS), BiomeWrapper::_colorSnow)
|
||||||
|
.put(_get(Biomes.STONY_PEAKS), BiomeWrapper::_colorStone)
|
||||||
|
.put(_get(Biomes.RIVER), BiomeWrapper::_colorWater)
|
||||||
|
.put(_get(Biomes.FROZEN_RIVER), BiomeWrapper::_colorIce)
|
||||||
|
.put(_get(Biomes.BEACH), BiomeWrapper::_colorSand)
|
||||||
|
.put(_get(Biomes.SNOWY_BEACH), BiomeWrapper::_colorSnow)
|
||||||
|
.put(_get(Biomes.STONY_SHORE), BiomeWrapper::_colorStone)
|
||||||
|
.put(_get(Biomes.WARM_OCEAN), BiomeWrapper::_colorWater)
|
||||||
|
.put(_get(Biomes.LUKEWARM_OCEAN), BiomeWrapper::_colorWater)
|
||||||
|
.put(_get(Biomes.DEEP_LUKEWARM_OCEAN), BiomeWrapper::_colorWater)
|
||||||
|
.put(_get(Biomes.OCEAN), BiomeWrapper::_colorWater)
|
||||||
|
.put(_get(Biomes.DEEP_OCEAN), BiomeWrapper::_colorWater)
|
||||||
|
.put(_get(Biomes.COLD_OCEAN), BiomeWrapper::_colorWater)
|
||||||
|
.put(_get(Biomes.DEEP_COLD_OCEAN), BiomeWrapper::_colorWater)
|
||||||
|
.put(_get(Biomes.FROZEN_OCEAN), BiomeWrapper::_colorIce)
|
||||||
|
.put(_get(Biomes.DEEP_FROZEN_OCEAN), BiomeWrapper::_colorIce)
|
||||||
|
.put(_get(Biomes.MUSHROOM_FIELDS), BiomeWrapper::_colorMushoom)
|
||||||
|
.put(_get(Biomes.DRIPSTONE_CAVES), BiomeWrapper::_colorDripStone)
|
||||||
|
.put(_get(Biomes.LUSH_CAVES), BiomeWrapper::_colorMoss)
|
||||||
|
.put(_get(Biomes.DEEP_DARK), BiomeWrapper::_colorSculk)
|
||||||
|
.put(_get(Biomes.NETHER_WASTES), BiomeWrapper::_colorNether)
|
||||||
|
.put(_get(Biomes.WARPED_FOREST), BiomeWrapper::_colorNether)
|
||||||
|
.put(_get(Biomes.CRIMSON_FOREST), BiomeWrapper::_colorNether)
|
||||||
|
.put(_get(Biomes.SOUL_SAND_VALLEY), BiomeWrapper::_colorSoulSand)
|
||||||
|
.put(_get(Biomes.BASALT_DELTAS), BiomeWrapper::_colorBasalt)
|
||||||
|
.put(_get(Biomes.THE_END), BiomeWrapper::_colorEnd)
|
||||||
|
.put(_get(Biomes.END_HIGHLANDS), BiomeWrapper::_colorEnd)
|
||||||
|
.put(_get(Biomes.END_MIDLANDS), BiomeWrapper::_colorEnd)
|
||||||
|
.put(_get(Biomes.SMALL_END_ISLANDS), BiomeWrapper::_colorEnd)
|
||||||
|
.put(_get(Biomes.END_BARRENS), BiomeWrapper::_colorEnd)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColorForBiome(int x, int z)
|
||||||
|
{
|
||||||
|
int colorInt;
|
||||||
|
Function<Biome, Integer> colorFunction = BIOME_COLOR_MAP.get(biome);
|
||||||
|
if (colorFunction != null)
|
||||||
|
{
|
||||||
|
colorInt = colorFunction.apply(biome);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
colorInt = biome.getGrassColor(x, z);
|
||||||
|
}
|
||||||
|
return colorInt;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@Override public String getName()
|
@Override public String getName()
|
||||||
{
|
{
|
||||||
return biome.toString();
|
return biome.toString();
|
||||||
|
|||||||
+4
@@ -367,7 +367,11 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
|
|||||||
CompoundTag chunkData = null;
|
CompoundTag chunkData = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
#if POST_MC_1_19
|
||||||
|
chunkData = level.getChunkSource().chunkMap.readChunk(chunkPos).get().orElse(null);
|
||||||
|
#else
|
||||||
chunkData = level.getChunkSource().chunkMap.readChunk(chunkPos);
|
chunkData = level.getChunkSource().chunkMap.readChunk(chunkPos);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
+13
@@ -35,13 +35,23 @@ import net.minecraft.world.level.chunk.ChunkGenerator;
|
|||||||
import net.minecraft.world.level.chunk.storage.ChunkScanAccess;
|
import net.minecraft.world.level.chunk.storage.ChunkScanAccess;
|
||||||
#endif
|
#endif
|
||||||
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.levelgen.RandomState;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
|
#endif
|
||||||
import net.minecraft.world.level.storage.WorldData;
|
import net.minecraft.world.level.storage.WorldData;
|
||||||
|
|
||||||
public final class GlobalParameters
|
public final class GlobalParameters
|
||||||
{
|
{
|
||||||
public final ChunkGenerator generator;
|
public final ChunkGenerator generator;
|
||||||
|
#if PRE_MC_1_19
|
||||||
public final StructureManager structures;
|
public final StructureManager structures;
|
||||||
|
#else
|
||||||
|
public final StructureTemplateManager structures;
|
||||||
|
public final RandomState randomState;
|
||||||
|
#endif
|
||||||
public final WorldGenSettings worldGenSettings;
|
public final WorldGenSettings worldGenSettings;
|
||||||
public final ThreadedLevelLightEngine lightEngine;
|
public final ThreadedLevelLightEngine lightEngine;
|
||||||
public final LodBuilder lodBuilder;
|
public final LodBuilder lodBuilder;
|
||||||
@@ -75,5 +85,8 @@ public final class GlobalParameters
|
|||||||
structures = server.getStructureManager();
|
structures = server.getStructureManager();
|
||||||
generator = level.getChunkSource().getGenerator();
|
generator = level.getChunkSource().getGenerator();
|
||||||
fixerUpper = server.getFixerUpper();
|
fixerUpper = server.getFixerUpper();
|
||||||
|
#if POST_MC_1_19
|
||||||
|
randomState = level.getChunkSource().randomState();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5
-2
@@ -25,7 +25,6 @@ import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.WorldGenStruct
|
|||||||
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.WorldGenLevel;
|
import net.minecraft.world.level.WorldGenLevel;
|
||||||
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
|
||||||
#if POST_MC_1_18_1
|
#if POST_MC_1_18_1
|
||||||
import net.minecraft.world.level.levelgen.structure.StructureCheck;
|
import net.minecraft.world.level.levelgen.structure.StructureCheck;
|
||||||
#endif
|
#endif
|
||||||
@@ -61,10 +60,14 @@ public final class ThreadedParameters
|
|||||||
level = param.level;
|
level = param.level;
|
||||||
#if PRE_MC_1_18_1
|
#if PRE_MC_1_18_1
|
||||||
structFeat = new WorldGenStructFeatManager(param.worldGenSettings, level);
|
structFeat = new WorldGenStructFeatManager(param.worldGenSettings, level);
|
||||||
#else
|
#elif PRE_MC_1_19
|
||||||
structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
||||||
param.level.dimension(), param.generator, level, param.generator.getBiomeSource(), param.worldSeed,
|
param.level.dimension(), param.generator, level, param.generator.getBiomeSource(), param.worldSeed,
|
||||||
param.fixerUpper);
|
param.fixerUpper);
|
||||||
|
#else
|
||||||
|
structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
||||||
|
param.level.dimension(), param.generator, param.randomState, level, param.generator.getBiomeSource(), param.worldSeed,
|
||||||
|
param.fixerUpper);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-2
@@ -52,7 +52,9 @@ import net.minecraft.world.level.chunk.storage.ChunkSerializer;
|
|||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
#if POST_MC_1_18_1
|
#if POST_MC_1_18_1
|
||||||
import net.minecraft.world.level.levelgen.blending.BlendingData;
|
import net.minecraft.world.level.levelgen.blending.BlendingData;
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
||||||
|
#endif
|
||||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceSerializationContext;
|
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceSerializationContext;
|
||||||
import net.minecraft.world.ticks.LevelChunkTicks;
|
import net.minecraft.world.ticks.LevelChunkTicks;
|
||||||
@@ -60,8 +62,10 @@ import net.minecraft.world.ticks.LevelChunkTicks;
|
|||||||
#if POST_MC_1_18_2
|
#if POST_MC_1_18_2
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.core.RegistryAccess;
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||||
import net.minecraft.world.level.material.Fluid;
|
import net.minecraft.world.level.material.Fluid;
|
||||||
@@ -70,7 +74,9 @@ import org.apache.logging.log4j.Logger;
|
|||||||
|
|
||||||
public class ChunkLoader
|
public class ChunkLoader
|
||||||
{
|
{
|
||||||
#if POST_MC_1_18_1
|
#if POST_MC_1_19
|
||||||
|
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
||||||
|
#elif POST_MC_1_18_1
|
||||||
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());
|
||||||
#endif
|
#endif
|
||||||
private static final String TAG_UPGRADE_DATA = "UpgradeData";
|
private static final String TAG_UPGRADE_DATA = "UpgradeData";
|
||||||
@@ -101,9 +107,12 @@ public class ChunkLoader
|
|||||||
#if PRE_MC_1_18_2
|
#if PRE_MC_1_18_2
|
||||||
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));
|
||||||
#else
|
#elif PRE_MC_1_19
|
||||||
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codec(
|
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codec(
|
||||||
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
|
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
|
||||||
|
#else
|
||||||
|
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
|
||||||
|
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
int i = #if PRE_MC_1_17_1 16; #else level.getSectionsCount(); #endif
|
int i = #if PRE_MC_1_17_1 16; #else level.getSectionsCount(); #endif
|
||||||
@@ -222,8 +231,13 @@ public class ChunkLoader
|
|||||||
return null;
|
return null;
|
||||||
#else
|
#else
|
||||||
BlendingData blendingData = readBlendingData(tagLevel);
|
BlendingData blendingData = readBlendingData(tagLevel);
|
||||||
|
#if PRE_MC_1_19
|
||||||
if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || !blendingData.oldNoise()))
|
if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || !blendingData.oldNoise()))
|
||||||
return null;
|
return null;
|
||||||
|
#else
|
||||||
|
if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || level.getChunk(chunkPos.getMiddleBlockX(),chunkPos.getMiddleBlockZ()).isOldNoiseGeneration()))
|
||||||
|
return null;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
long inhabitedTime = tagLevel.getLong("InhabitedTime");
|
long inhabitedTime = tagLevel.getLong("InhabitedTime");
|
||||||
|
|||||||
+7
-1
@@ -46,7 +46,10 @@ import net.minecraft.world.level.ColorResolver;
|
|||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
import net.minecraft.world.level.LevelHeightAccessor;
|
||||||
#endif
|
#endif
|
||||||
import net.minecraft.world.level.LightLayer;
|
import net.minecraft.world.level.LightLayer;
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraft.world.level.StructureFeatureManager;
|
import net.minecraft.world.level.StructureFeatureManager;
|
||||||
|
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
||||||
|
#endif
|
||||||
import net.minecraft.world.level.biome.Biome;
|
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;
|
||||||
@@ -56,7 +59,6 @@ import net.minecraft.world.level.chunk.ChunkStatus;
|
|||||||
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
|
||||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||||
|
|
||||||
@@ -290,7 +292,11 @@ public class LightedWorldGenRegion extends WorldGenRegion {
|
|||||||
|
|
||||||
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
||||||
{
|
{
|
||||||
|
#if PRE_MC_1_19
|
||||||
int i = (Minecraft.getInstance()).options.biomeBlendRadius;
|
int i = (Minecraft.getInstance()).options.biomeBlendRadius;
|
||||||
|
#else
|
||||||
|
int i = (Minecraft.getInstance()).options.biomeBlendRadius().get();
|
||||||
|
#endif
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
return colorResolver.getColor((Biome) _getBiome(blockPos), blockPos.getX(), blockPos.getZ());
|
return colorResolver.getColor((Biome) _getBiome(blockPos), blockPos.getX(), blockPos.getZ());
|
||||||
int j = (i * 2 + 1) * (i * 2 + 1);
|
int j = (i * 2 + 1) * (i * 2 + 1);
|
||||||
|
|||||||
+58
-1
@@ -37,19 +37,29 @@ import net.minecraft.core.SectionPos;
|
|||||||
import net.minecraft.server.level.WorldGenRegion;
|
import net.minecraft.server.level.WorldGenRegion;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.StructureFeatureManager;
|
|
||||||
import net.minecraft.world.level.WorldGenLevel;
|
import net.minecraft.world.level.WorldGenLevel;
|
||||||
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.ChunkStatus;
|
||||||
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
||||||
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
||||||
|
import net.minecraft.world.level.StructureFeatureManager;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
|
import net.minecraft.world.level.StructureManager;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if POST_MC_1_18_1
|
#if POST_MC_1_18_1
|
||||||
import net.minecraft.world.level.levelgen.structure.StructureCheck;
|
import net.minecraft.world.level.levelgen.structure.StructureCheck;
|
||||||
#endif
|
#endif
|
||||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
|
|
||||||
|
#if PRE_MC_1_19
|
||||||
public class WorldGenStructFeatManager extends StructureFeatureManager {
|
public class WorldGenStructFeatManager extends StructureFeatureManager {
|
||||||
|
#else
|
||||||
|
public class WorldGenStructFeatManager extends StructureManager {
|
||||||
|
#endif
|
||||||
final WorldGenLevel genLevel;
|
final WorldGenLevel genLevel;
|
||||||
WorldGenSettings worldGenSettings;
|
WorldGenSettings worldGenSettings;
|
||||||
#if POST_MC_1_18_1
|
#if POST_MC_1_18_1
|
||||||
@@ -122,6 +132,7 @@ public class WorldGenStructFeatManager extends StructureFeatureManager {
|
|||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
#if PRE_MC_1_19
|
||||||
@Override
|
@Override
|
||||||
public List<StructureStart> startsForFeature(SectionPos sectionPos, Predicate<ConfiguredStructureFeature<?, ?>> predicate) {
|
public List<StructureStart> startsForFeature(SectionPos sectionPos, Predicate<ConfiguredStructureFeature<?, ?>> predicate) {
|
||||||
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
|
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
|
||||||
@@ -166,6 +177,52 @@ public class WorldGenStructFeatManager extends StructureFeatureManager {
|
|||||||
if (chunk == null) return (Map<ConfiguredStructureFeature<?, ?>, LongSet>) Stream.empty();
|
if (chunk == null) return (Map<ConfiguredStructureFeature<?, ?>, LongSet>) Stream.empty();
|
||||||
return chunk.getAllReferences();
|
return chunk.getAllReferences();
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
@Override
|
||||||
|
public List<StructureStart> startsForStructure(ChunkPos sectionPos, Predicate<Structure> predicate) {
|
||||||
|
ChunkAccess chunk = _getChunk(sectionPos.x, sectionPos.z, ChunkStatus.STRUCTURE_REFERENCES);
|
||||||
|
if (chunk == null) return List.of();
|
||||||
|
|
||||||
|
// Copied from StructureFeatureManager::startsForFeature(...)
|
||||||
|
Map<Structure, LongSet> map = chunk.getAllReferences();
|
||||||
|
|
||||||
|
ImmutableList.Builder<StructureStart> builder = ImmutableList.builder();
|
||||||
|
Iterator<Map.Entry<Structure, LongSet>> var5 = map.entrySet().iterator();
|
||||||
|
|
||||||
|
while(var5.hasNext()) {
|
||||||
|
Map.Entry<Structure, LongSet> entry = var5.next();
|
||||||
|
Structure configuredStructureFeature = entry.getKey();
|
||||||
|
if (predicate.test(configuredStructureFeature)) {
|
||||||
|
LongSet var10002 = (LongSet)entry.getValue();
|
||||||
|
Objects.requireNonNull(builder);
|
||||||
|
this.fillStartsForStructure(configuredStructureFeature, var10002, builder::add);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StructureStart> startsForStructure(SectionPos sectionPos, Structure structure) {
|
||||||
|
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
|
||||||
|
if (chunk == null) return (List<StructureStart>) Stream.empty();
|
||||||
|
|
||||||
|
// Copied from StructureFeatureManager::startsForFeature(...)
|
||||||
|
LongSet longSet = chunk.getReferencesForStructure(structure);
|
||||||
|
ImmutableList.Builder<StructureStart> builder = ImmutableList.builder();
|
||||||
|
Objects.requireNonNull(builder);
|
||||||
|
this.fillStartsForStructure(structure, longSet, builder::add);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Structure, LongSet> getAllStructuresAt(BlockPos blockPos) {
|
||||||
|
SectionPos sectionPos = SectionPos.of(blockPos);
|
||||||
|
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
|
||||||
|
if (chunk == null) return (Map<Structure, LongSet>) Stream.empty();
|
||||||
|
return chunk.getAllReferences();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -27,7 +27,9 @@ import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
|
|||||||
|
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
import net.minecraft.server.level.WorldGenRegion;
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraft.world.level.StructureFeatureManager;
|
import net.minecraft.world.level.StructureFeatureManager;
|
||||||
|
#endif
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
@@ -71,9 +73,12 @@ public final class StepBiomes {
|
|||||||
// System.out.println("StepBiomes: "+chunk.getPos());
|
// System.out.println("StepBiomes: "+chunk.getPos());
|
||||||
#if PRE_MC_1_18_1
|
#if PRE_MC_1_18_1
|
||||||
environment.params.generator.createBiomes(environment.params.biomes, chunk);
|
environment.params.generator.createBiomes(environment.params.biomes, chunk);
|
||||||
#else
|
#elif PRE_MC_1_19
|
||||||
chunk = environment.joinSync(environment.params.generator.createBiomes(environment.params.biomes, Runnable::run, Blender.of(worldGenRegion),
|
chunk = environment.joinSync(environment.params.generator.createBiomes(environment.params.biomes, Runnable::run, Blender.of(worldGenRegion),
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
|
#else
|
||||||
|
chunk = environment.joinSync(environment.params.generator.createBiomes(environment.params.biomes, Runnable::run, environment.params.randomState, Blender.of(worldGenRegion),
|
||||||
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -34,7 +34,9 @@ import net.minecraft.util.Mth;
|
|||||||
#if POST_MC_1_17_1
|
#if POST_MC_1_17_1
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
import net.minecraft.world.level.LevelHeightAccessor;
|
||||||
#endif
|
#endif
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraft.world.level.StructureFeatureManager;
|
import net.minecraft.world.level.StructureFeatureManager;
|
||||||
|
#endif
|
||||||
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.ChunkStatus;
|
||||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||||
@@ -79,9 +81,12 @@ public final class StepNoise {
|
|||||||
#elif PRE_MC_1_18_1
|
#elif PRE_MC_1_18_1
|
||||||
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run,
|
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run,
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
#else
|
#elif PRE_MC_1_19
|
||||||
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion),
|
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion),
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
|
#else
|
||||||
|
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), environment.params.randomState,
|
||||||
|
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||||
#endif
|
#endif
|
||||||
LodUtil.checkInterruptsUnchecked(); // Speed up termination responsiveness
|
LodUtil.checkInterruptsUnchecked(); // Speed up termination responsiveness
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -32,7 +32,9 @@ import net.minecraft.core.Registry;
|
|||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
import net.minecraft.server.level.WorldGenRegion;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraft.world.level.StructureFeatureManager;
|
import net.minecraft.world.level.StructureFeatureManager;
|
||||||
|
#endif
|
||||||
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.ChunkStatus;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
|
|||||||
+10
-2
@@ -66,13 +66,21 @@ public final class StepStructureStart {
|
|||||||
((ProtoChunk) chunk).setStatus(STATUS);
|
((ProtoChunk) chunk).setStatus(STATUS);
|
||||||
chunksToDo.add(chunk);
|
chunksToDo.add(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if PRE_MC_1_19
|
||||||
if (environment.params.worldGenSettings.generateFeatures()) {
|
if (environment.params.worldGenSettings.generateFeatures()) {
|
||||||
|
#elif POST_MC_1_19
|
||||||
|
if (environment.params.worldGenSettings.generateStructures()) {
|
||||||
|
#endif
|
||||||
for (ChunkAccess chunk : chunksToDo) {
|
for (ChunkAccess chunk : chunksToDo) {
|
||||||
// System.out.println("StepStructureStart: "+chunk.getPos());
|
// System.out.println("StepStructureStart: "+chunk.getPos());
|
||||||
|
#if PRE_MC_1_19
|
||||||
environment.params.generator.createStructures(environment.params.registry, tParams.structFeat, chunk, environment.params.structures,
|
environment.params.generator.createStructures(environment.params.registry, tParams.structFeat, chunk, environment.params.structures,
|
||||||
environment.params.worldSeed);
|
environment.params.worldSeed);
|
||||||
|
#elif POST_MC_1_19
|
||||||
|
environment.params.generator.createStructures(environment.params.registry, environment.params.randomState, tParams.structFeat, chunk, environment.params.structures,
|
||||||
|
environment.params.worldSeed);
|
||||||
|
#endif
|
||||||
#if POST_MC_1_18_1
|
#if POST_MC_1_18_1
|
||||||
try {
|
try {
|
||||||
tParams.structCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts());
|
tParams.structCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts());
|
||||||
|
|||||||
+3
-2
@@ -60,9 +60,10 @@ public final class StepSurface {
|
|||||||
// System.out.println("StepSurface: "+chunk.getPos());
|
// System.out.println("StepSurface: "+chunk.getPos());
|
||||||
#if PRE_MC_1_18_1
|
#if PRE_MC_1_18_1
|
||||||
environment.params.generator.buildSurfaceAndBedrock(worldGenRegion, chunk);
|
environment.params.generator.buildSurfaceAndBedrock(worldGenRegion, chunk);
|
||||||
|
#elif PRE_MC_1_19
|
||||||
#else
|
|
||||||
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk);
|
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk);
|
||||||
|
#else
|
||||||
|
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), environment.params.randomState, chunk);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
accessWidener v1 named
|
||||||
|
|
||||||
|
|
||||||
|
# used when determining where to save files to
|
||||||
|
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/io/File;
|
||||||
|
|
||||||
|
# used when rendering
|
||||||
|
accessible field com/mojang/blaze3d/vertex/VertexBuffer indexCount I
|
||||||
|
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)D
|
||||||
|
|
||||||
|
# used for grabbing vanilla rendered chunks
|
||||||
|
accessible field net/minecraft/client/renderer/LevelRenderer renderChunkStorage Ljava/util/concurrent/atomic/AtomicReference;
|
||||||
|
accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkStorage
|
||||||
|
accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo
|
||||||
|
accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chunk Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;
|
||||||
|
|
||||||
|
# lighting
|
||||||
|
accessible field net/minecraft/client/renderer/LightTexture lightPixels Lcom/mojang/blaze3d/platform/NativeImage;
|
||||||
|
accessible field net/minecraft/client/renderer/LightTexture lightTexture Lnet/minecraft/client/renderer/texture/DynamicTexture;
|
||||||
|
accessible field net/minecraft/world/level/lighting/LevelLightEngine blockEngine Lnet/minecraft/world/level/lighting/LayerLightEngine;
|
||||||
|
accessible field net/minecraft/world/level/lighting/LevelLightEngine skyEngine Lnet/minecraft/world/level/lighting/LayerLightEngine;
|
||||||
|
|
||||||
|
# world generation
|
||||||
|
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/levelgen/NoiseBasedChunkGenerator settings Lnet/minecraft/core/Holder;
|
||||||
|
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
|
||||||
|
accessible method net/minecraft/server/level/ChunkMap readChunk (Lnet/minecraft/world/level/ChunkPos;)Ljava/util/concurrent/CompletableFuture;
|
||||||
|
|
||||||
|
|
||||||
|
# lod generation from save file
|
||||||
|
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
|
||||||
|
|
||||||
|
|
||||||
|
# grabbing textures
|
||||||
|
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite animatedTexture Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture;
|
||||||
|
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite width I
|
||||||
|
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite height I
|
||||||
|
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite mainImage [Lcom/mojang/blaze3d/platform/NativeImage;
|
||||||
|
accessible class net/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture
|
||||||
|
accessible method net/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture getFrameX (I)I
|
||||||
|
accessible method net/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture getFrameY (I)I
|
||||||
|
extendable class com/mojang/math/Matrix4f
|
||||||
|
|
||||||
|
# hacky stuff
|
||||||
|
accessible field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
|
||||||
|
mutable field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
|
||||||
+1
-1
Submodule core updated: f0f18993d1...9557912101
+184
-2
@@ -2,14 +2,34 @@ plugins {
|
|||||||
id "com.github.johnrengelman.shadow" version "7.1.0"
|
id "com.github.johnrengelman.shadow" version "7.1.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From parent
|
||||||
|
apply plugin: "java"
|
||||||
|
apply plugin: "architectury-plugin"
|
||||||
|
apply plugin: "maven-publish"
|
||||||
|
apply plugin: "dev.architectury.loom"
|
||||||
|
|
||||||
|
archivesBaseName = rootProject.archives_base_name
|
||||||
|
version = rootProject.mod_version //FIXME: Redef
|
||||||
|
group = rootProject.maven_group
|
||||||
|
|
||||||
version = rootProject.mod_version+"-"+rootProject.minecraft_version+"-"+new Date().format("yyyy_MM_dd_HH_mm")
|
version = rootProject.mod_version+"-"+rootProject.minecraft_version+"-"+new Date().format("yyyy_MM_dd_HH_mm")
|
||||||
|
|
||||||
|
loom {
|
||||||
|
silentMojangMappingsLicense()
|
||||||
|
accessWidenerPath.set(project(":common").file("src/main/resources/${acsessWidenerVersion}.lod.accesswidener"))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
architectury {
|
architectury {
|
||||||
platformSetupLoomIde()
|
platformSetupLoomIde()
|
||||||
fabric()
|
fabric()
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
|
common
|
||||||
|
shadowMe
|
||||||
|
implementation.extendsFrom shadowMe
|
||||||
|
|
||||||
compileClasspath.extendsFrom common
|
compileClasspath.extendsFrom common
|
||||||
runtimeClasspath.extendsFrom common
|
runtimeClasspath.extendsFrom common
|
||||||
developmentFabric.extendsFrom common
|
developmentFabric.extendsFrom common
|
||||||
@@ -19,9 +39,58 @@ configurations {
|
|||||||
modImplementation.extendsFrom addModJar
|
modImplementation.extendsFrom addModJar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
jar.dependsOn(project(":core").remapJar)
|
||||||
|
remapSourcesJar.dependsOn(project(":core").remapJar)
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
// Required for ModMenu
|
// Required for ModMenu
|
||||||
maven { url "https://maven.terraformersmc.com/" }
|
maven { url "https://maven.terraformersmc.com/" }
|
||||||
|
|
||||||
|
mavenCentral()
|
||||||
|
|
||||||
|
// For parchment mappings
|
||||||
|
maven { url "https://maven.parchmentmc.org" }
|
||||||
|
|
||||||
|
// used to download and compile dependencies from git repos
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
|
||||||
|
// For Manifold Preprocessor
|
||||||
|
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
|
||||||
|
|
||||||
|
// Required for importing Modrinth mods
|
||||||
|
maven {
|
||||||
|
name = "Modrinth"
|
||||||
|
url = "https://api.modrinth.com/maven"
|
||||||
|
content {
|
||||||
|
includeGroup "maven.modrinth"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required for importing CursedForge mods
|
||||||
|
maven {
|
||||||
|
url "https://www.cursemaven.com"
|
||||||
|
content {
|
||||||
|
includeGroup "curse.maven"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// These 2 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
|
||||||
|
flatDir {
|
||||||
|
dirs "${rootDir}/mods/fabric"
|
||||||
|
content {
|
||||||
|
includeGroup "fabric-mod"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flatDir {
|
||||||
|
dirs "${rootDir}/mods/forge"
|
||||||
|
content {
|
||||||
|
includeGroup "forge-mod"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def addMod(path, enabled) {
|
def addMod(path, enabled) {
|
||||||
@@ -32,13 +101,39 @@ def addMod(path, enabled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||||
|
// The following line declares the mojmap mappings & parchment mappings
|
||||||
|
mappings loom.layered() {
|
||||||
|
// Mojmap mappings
|
||||||
|
officialMojangMappings()
|
||||||
|
// Parchment mappings (it adds parameter mappings & javadoc)
|
||||||
|
if (rootProject.minecraft_version != "1.19")
|
||||||
|
parchment("org.parchmentmc.data:parchment-${rootProject.minecraft_version}:${rootProject.parchment_version}@zip")
|
||||||
|
else
|
||||||
|
parchment("org.parchmentmc.data:parchment-1.18.2:${rootProject.parchment_version}@zip") // As 1.19 dosnt have parchment mappings yet, we use 1.18.2 mapping
|
||||||
|
}
|
||||||
|
|
||||||
|
//Manifold
|
||||||
|
annotationProcessor "systems.manifold:manifold-preprocessor:${rootProject.manifold_version}"
|
||||||
|
|
||||||
|
// Toml
|
||||||
|
implementation("com.electronwill.night-config:toml:${rootProject.toml_version}")
|
||||||
|
|
||||||
|
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
|
||||||
|
// Do NOT use other classes from fabric loader unless working with fabric
|
||||||
|
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||||
|
|
||||||
|
common(project(":core"))
|
||||||
|
|
||||||
// Fabric loader
|
// Fabric loader
|
||||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||||
|
|
||||||
// Fabric API
|
// Fabric API
|
||||||
addModJar(fabricApi.module("fabric-lifecycle-events-v1", rootProject.fabric_api_version))
|
addModJar(fabricApi.module("fabric-lifecycle-events-v1", rootProject.fabric_api_version))
|
||||||
|
addModJar(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version))
|
||||||
addModJar(fabricApi.module("fabric-key-binding-api-v1", rootProject.fabric_api_version))
|
addModJar(fabricApi.module("fabric-key-binding-api-v1", rootProject.fabric_api_version))
|
||||||
addModJar(fabricApi.module("fabric-networking-api-v1", rootProject.fabric_api_version))
|
addModJar(fabricApi.module("fabric-networking-api-v1", rootProject.fabric_api_version))
|
||||||
|
addModJar(fabricApi.module("fabric-api-base", rootProject.fabric_api_version))
|
||||||
|
|
||||||
// Mod Menu
|
// Mod Menu
|
||||||
modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}")
|
modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}")
|
||||||
@@ -80,13 +175,12 @@ dependencies {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Toml
|
// Toml
|
||||||
shadowMe("com.electronwill.night-config:toml:${rootProject.toml_version}") {}
|
shadowMe("com.electronwill.night-config:toml:${rootProject.toml_version}") {}
|
||||||
|
|
||||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
||||||
shadowMe(project(path: ":common", configuration: "transformProductionFabric")) { transitive false }
|
shadowMe(project(path: ":common", configuration: "transformProductionFabric")) { transitive false }
|
||||||
|
shadowMe files(project(":core").file("build/libs/DistantHorizons-${rootProject.mod_version}.jar"))
|
||||||
|
|
||||||
// Compression
|
// Compression
|
||||||
common 'org.tukaani:xz:1.9'
|
common 'org.tukaani:xz:1.9'
|
||||||
@@ -98,11 +192,62 @@ dependencies {
|
|||||||
task deleteResources(type: Delete) {
|
task deleteResources(type: Delete) {
|
||||||
delete file("build/resources/main")
|
delete file("build/resources/main")
|
||||||
}
|
}
|
||||||
|
// Copies the correct accesswidener and renames it
|
||||||
|
task copyAccessWidener(type: Copy) {
|
||||||
|
from project(":common").file("src/main/resources/${rootProject.acsessWidenerVersion}.lod.accesswidener")
|
||||||
|
into(file("build/resources/main"))
|
||||||
|
rename "${rootProject.acsessWidenerVersion}.lod.accesswidener", "lod.accesswidener"
|
||||||
|
}
|
||||||
|
|
||||||
|
task copyCoreResources(type: Copy) {
|
||||||
|
from fileTree(project(":core").file("src/main/resources"))
|
||||||
|
into file("build/resources/main")
|
||||||
|
}
|
||||||
|
|
||||||
|
task copyCommonResources(type: Copy) {
|
||||||
|
from fileTree(project(":common").file("src/main/resources"))
|
||||||
|
into file("build/resources/main")
|
||||||
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
dependsOn(copyCoreResources)
|
dependsOn(copyCoreResources)
|
||||||
dependsOn(copyCommonResources)
|
dependsOn(copyCommonResources)
|
||||||
dependsOn(copyAccessWidener)
|
dependsOn(copyAccessWidener)
|
||||||
|
|
||||||
|
def resourceTargets = ["fabric.mod.json", "META-INF/mods.toml"] // Location of where to put
|
||||||
|
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
||||||
|
def replaceProperties = [
|
||||||
|
version : mod_version,
|
||||||
|
mod_name : mod_name,
|
||||||
|
authors : mod_authors,
|
||||||
|
description : mod_description,
|
||||||
|
homepage : mod_homepage,
|
||||||
|
source : mod_source,
|
||||||
|
issues : mod_issues,
|
||||||
|
minecraft_version : minecraft_version,
|
||||||
|
compatible_minecraft_versions: compatible_minecraft_versions,
|
||||||
|
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
|
||||||
|
//TODO: Make Forge loader version also be relaced with non hardcoded value instead of "[36,42)"
|
||||||
|
|
||||||
|
inputs.properties replaceProperties
|
||||||
|
replaceProperties.put 'project', project
|
||||||
|
filesMatching(resourceTargets) {
|
||||||
|
expand replaceProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
intoTargets.each { target ->
|
||||||
|
if (file(target).exists()) {
|
||||||
|
copy {
|
||||||
|
from(sourceSets.main.resources) {
|
||||||
|
include resourceTargets
|
||||||
|
expand replaceProperties
|
||||||
|
}
|
||||||
|
into target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runClient {
|
runClient {
|
||||||
@@ -131,6 +276,11 @@ remapJar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes 'Implementation-Title': rootProject.archives_base_name,
|
||||||
|
'Implementation-Version': rootProject.mod_version,
|
||||||
|
'Main-Class': 'com.seibel.lod.core.JarMain' // When changing the main of the jar change this line
|
||||||
|
}
|
||||||
classifier "dev"
|
classifier "dev"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,3 +309,35 @@ publishing {
|
|||||||
// Add repositories to publish to here.
|
// Add repositories to publish to here.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task printConfigurations {
|
||||||
|
doLast {task ->
|
||||||
|
println "Project Name: $name configurations:"
|
||||||
|
configurations.each {
|
||||||
|
println " $it.name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile) {
|
||||||
|
// Add Manifold Preprocessor
|
||||||
|
// def excapedMCVersion = rootProject.minecraft_version.replace(".", "_")
|
||||||
|
// options.compilerArgs += ['-Xplugin:Manifold', "-AMC_VERSION_${excapedMCVersion}"]
|
||||||
|
//
|
||||||
|
//options.compilerArgs += ['-deprecation']
|
||||||
|
//options.compilerArgs += ['-verbose']
|
||||||
|
//options.compilerArgs += ['-Xlint:unchecked']
|
||||||
|
//options.compilerArgs += ['-Xdiags:verbose']
|
||||||
|
//options.compilerArgs += ['-Xprint']
|
||||||
|
//options.compilerArgs += ['-XprintProcessorInfo']
|
||||||
|
//options.compilerArgs += ['-XprintRounds']
|
||||||
|
|
||||||
|
// println options.compilerArgs
|
||||||
|
|
||||||
|
// Set the java version
|
||||||
|
options.compilerArgs += ['-Xplugin:Manifold']
|
||||||
|
options.release = rootProject.java_version as Integer
|
||||||
|
// TODO: make everything use java 8
|
||||||
|
// options.release = 8 // Use Java 8 for everything so back porting is easier
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ import org.lwjgl.glfw.GLFW;
|
|||||||
* This handles all events sent to the client,
|
* This handles all events sent to the client,
|
||||||
* and is the starting point for most of the mod.
|
* and is the starting point for most of the mod.
|
||||||
*
|
*
|
||||||
* @author coolGi2007
|
* @author coolGi
|
||||||
* @author Ran
|
* @author Ran
|
||||||
* @version 11-23-2021
|
* @version 11-23-2021
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ 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;
|
||||||
@@ -43,7 +42,7 @@ import net.fabricmc.api.ClientModInitializer;
|
|||||||
* If you are looking for the real start of the mod
|
* If you are looking for the real start of the mod
|
||||||
* check out the ClientProxy.
|
* check out the ClientProxy.
|
||||||
*
|
*
|
||||||
* @author coolGi2007
|
* @author coolGi
|
||||||
* @author Ran
|
* @author Ran
|
||||||
* @version 12-1-2021
|
* @version 12-1-2021
|
||||||
*/
|
*/
|
||||||
@@ -65,7 +64,7 @@ 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, new NetworkHandler());
|
LodCommonMain.startup(null, false);
|
||||||
FabricDependencySetup.createInitialBindings();
|
FabricDependencySetup.createInitialBindings();
|
||||||
FabricDependencySetup.finishBinding();
|
FabricDependencySetup.finishBinding();
|
||||||
ApiShared.LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
|
ApiShared.LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
|
||||||
@@ -88,7 +87,7 @@ public class Main implements ClientModInitializer
|
|||||||
|
|
||||||
public static void initServer() {
|
public static void initServer() {
|
||||||
LodCommonMain.initConfig();
|
LodCommonMain.initConfig();
|
||||||
LodCommonMain.startup(null, true, new NetworkHandler());
|
LodCommonMain.startup(null, true);
|
||||||
FabricDependencySetup.createInitialBindings();
|
FabricDependencySetup.createInitialBindings();
|
||||||
FabricDependencySetup.finishBinding();
|
FabricDependencySetup.finishBinding();
|
||||||
ApiShared.LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
|
ApiShared.LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.seibel.lod.fabric.mixins;
|
||||||
|
|
||||||
|
import com.seibel.lod.core.render.F3Screen;
|
||||||
|
import net.minecraft.client.gui.components.DebugScreenOverlay;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mixin(DebugScreenOverlay.class)
|
||||||
|
public class MixinDebugScreenOverlay {
|
||||||
|
|
||||||
|
@Inject(method = "getSystemInformation", at = @At("RETURN"))
|
||||||
|
private void addCustomF3(CallbackInfoReturnable<List<String>> cir) {
|
||||||
|
List<String> messages = cir.getReturnValue();
|
||||||
|
|
||||||
|
for (String i: F3Screen.f3List) {
|
||||||
|
messages.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -48,8 +48,12 @@ public class MixinFogRenderer {
|
|||||||
private static final float A_REALLY_REALLY_BIG_VALUE = 420694206942069.F;
|
private static final float A_REALLY_REALLY_BIG_VALUE = 420694206942069.F;
|
||||||
private static final float A_EVEN_LARGER_VALUE = 42069420694206942069.F;
|
private static final float A_EVEN_LARGER_VALUE = 42069420694206942069.F;
|
||||||
|
|
||||||
@Inject(at = @At("RETURN"), method = "setupFog(Lnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/FogRenderer$FogMode;FZ)V")
|
@Inject(at = @At("RETURN"), method = "setupFog")
|
||||||
|
#if PRE_MC_1_19
|
||||||
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, CallbackInfo callback) {
|
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, CallbackInfo callback) {
|
||||||
|
#else
|
||||||
|
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, float g, CallbackInfo callback) {
|
||||||
|
#endif
|
||||||
#if PRE_MC_1_17_1
|
#if PRE_MC_1_17_1
|
||||||
FluidState fluidState = camera.getFluidInCamera();
|
FluidState fluidState = camera.getFluidInCamera();
|
||||||
boolean cameraNotInFluid = fluidState.isEmpty();
|
boolean cameraNotInFluid = fluidState.isEmpty();
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ 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;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraft.network.chat.TranslatableComponent;
|
import net.minecraft.network.chat.TranslatableComponent;
|
||||||
|
#endif
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
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;
|
||||||
@@ -39,7 +41,7 @@ import java.util.Objects;
|
|||||||
/**
|
/**
|
||||||
* Adds a button to the menu to goto the config
|
* Adds a button to the menu to goto the config
|
||||||
*
|
*
|
||||||
* @author coolGi2007
|
* @author coolGi
|
||||||
* @version 12-02-2021
|
* @version 12-02-2021
|
||||||
*/
|
*/
|
||||||
@Mixin(OptionsScreen.class)
|
@Mixin(OptionsScreen.class)
|
||||||
@@ -67,6 +69,10 @@ public class MixinOptionsScreen extends Screen {
|
|||||||
// For now it goes to the client option by default
|
// For now it goes to the client option by default
|
||||||
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(ConfigGui.getScreen(this, "client")),
|
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(ConfigGui.getScreen(this, "client")),
|
||||||
// Add a title to the screen
|
// Add a title to the screen
|
||||||
|
#if PRE_MC_1_19
|
||||||
new TranslatableComponent("text.autoconfig." + ModInfo.ID + ".title")));
|
new TranslatableComponent("text.autoconfig." + ModInfo.ID + ".title")));
|
||||||
|
#else
|
||||||
|
Component.translatable("text.autoconfig." + ModInfo.ID + ".title")));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
*
|
*
|
||||||
* This is also the mixin for rendering the clouds
|
* This is also the mixin for rendering the clouds
|
||||||
*
|
*
|
||||||
* @author coolGi2007
|
* @author coolGi
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 12-31-2021
|
* @version 12-31-2021
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
|
||||||
* licensed under the GNU GPL v3 License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020-2022 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.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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
"MixinWorldRenderer",
|
"MixinWorldRenderer",
|
||||||
"MixinFogRenderer",
|
"MixinFogRenderer",
|
||||||
"MixinChunkGenerator",
|
"MixinChunkGenerator",
|
||||||
|
"MixinDebugScreenOverlay",
|
||||||
"events.MixinClientLevel",
|
"events.MixinClientLevel",
|
||||||
"events.MixinMinecraft",
|
"events.MixinMinecraft",
|
||||||
"events.MixinBlockUpdate",
|
"events.MixinBlockUpdate",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
"name": "${mod_name}",
|
"name": "${mod_name}",
|
||||||
"description": "${description}",
|
"description": "${description}",
|
||||||
"authors": ${authors},
|
"authors": $authors,
|
||||||
|
|
||||||
"contact": {
|
"contact": {
|
||||||
"homepage": "${homepage}",
|
"homepage": "${homepage}",
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
"fabric-lifecycle-events-v1": "*",
|
"fabric-lifecycle-events-v1": "*",
|
||||||
"fabric-key-binding-api-v1": "*",
|
"fabric-key-binding-api-v1": "*",
|
||||||
"fabric-networking-api-v1": "*",
|
"fabric-networking-api-v1": "*",
|
||||||
"minecraft": ${compatible_minecraft_versions},
|
"minecraft": $compatible_minecraft_versions,
|
||||||
"java": ">=${java_version}"
|
"java": ">=${java_version}"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,23 @@
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "com.github.johnrengelman.shadow" version "7.1.0"
|
id "com.github.johnrengelman.shadow" version "7.1.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply plugin: "java"
|
||||||
|
apply plugin: "architectury-plugin"
|
||||||
|
apply plugin: "maven-publish"
|
||||||
|
apply plugin: "dev.architectury.loom"
|
||||||
|
|
||||||
|
archivesBaseName = rootProject.archives_base_name
|
||||||
|
version = rootProject.mod_version //FIXME: HERE repeated def
|
||||||
|
group = rootProject.maven_group
|
||||||
|
|
||||||
version = rootProject.mod_version+"-"+rootProject.minecraft_version+"-"+new Date().format("yyyy_MM_dd_HH_mm")
|
version = rootProject.mod_version+"-"+rootProject.minecraft_version+"-"+new Date().format("yyyy_MM_dd_HH_mm")
|
||||||
|
|
||||||
|
|
||||||
loom {
|
loom {
|
||||||
|
silentMojangMappingsLicense()
|
||||||
|
accessWidenerPath.set(project(":common").file("src/main/resources/${acsessWidenerVersion}.lod.accesswidener"))
|
||||||
forge {
|
forge {
|
||||||
convertAccessWideners.set(true)
|
convertAccessWideners.set(true)
|
||||||
extraAccessWideners.add("lod.accesswidener")
|
extraAccessWideners.add("lod.accesswidener")
|
||||||
@@ -18,11 +31,21 @@ architectury {
|
|||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
|
common
|
||||||
|
shadowMe
|
||||||
|
implementation.extendsFrom shadowMe
|
||||||
|
|
||||||
compileClasspath.extendsFrom common
|
compileClasspath.extendsFrom common
|
||||||
runtimeClasspath.extendsFrom common
|
runtimeClasspath.extendsFrom common
|
||||||
developmentForge.extendsFrom common
|
developmentForge.extendsFrom common
|
||||||
}
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
jar.dependsOn(project(":core").remapJar)
|
||||||
|
remapSourcesJar.dependsOn(project(":core").remapJar)
|
||||||
|
|
||||||
def addMod(path, enabled) {
|
def addMod(path, enabled) {
|
||||||
if (enabled == "2")
|
if (enabled == "2")
|
||||||
dependencies { modImplementation(path) }
|
dependencies { modImplementation(path) }
|
||||||
@@ -31,6 +54,27 @@ def addMod(path, enabled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
|
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||||
|
// The following line declares the mojmap mappings & parchment mappings
|
||||||
|
mappings loom.layered() {
|
||||||
|
// Mojmap mappings
|
||||||
|
officialMojangMappings()
|
||||||
|
// Parchment mappings (it adds parameter mappings & javadoc)
|
||||||
|
if (rootProject.minecraft_version != "1.19")
|
||||||
|
parchment("org.parchmentmc.data:parchment-${rootProject.minecraft_version}:${rootProject.parchment_version}@zip")
|
||||||
|
else
|
||||||
|
parchment("org.parchmentmc.data:parchment-1.18.2:${rootProject.parchment_version}@zip") // As 1.19 dosnt have parchment mappings yet, we use 1.18.2 mapping
|
||||||
|
}
|
||||||
|
|
||||||
|
//Manifold
|
||||||
|
annotationProcessor "systems.manifold:manifold-preprocessor:${rootProject.manifold_version}"
|
||||||
|
|
||||||
|
// Toml
|
||||||
|
implementation("com.electronwill.night-config:toml:${rootProject.toml_version}")
|
||||||
|
|
||||||
|
common(project(":core")) { transitive false }
|
||||||
|
|
||||||
// Forge loader
|
// Forge loader
|
||||||
forge "net.minecraftforge:forge:${rootProject.minecraft_version}-${rootProject.forge_version}"
|
forge "net.minecraftforge:forge:${rootProject.minecraft_version}-${rootProject.forge_version}"
|
||||||
|
|
||||||
@@ -42,6 +86,7 @@ dependencies {
|
|||||||
|
|
||||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
||||||
shadowMe(project(path: ":common", configuration: "transformProductionForge")) { transitive = false }
|
shadowMe(project(path: ":common", configuration: "transformProductionForge")) { transitive = false }
|
||||||
|
shadowMe files(project(":core").file("build/libs/DistantHorizons-${rootProject.mod_version}.jar"))
|
||||||
|
|
||||||
// forgeDependencies(project(":core")) { transitive false }
|
// forgeDependencies(project(":core")) { transitive false }
|
||||||
|
|
||||||
@@ -56,10 +101,63 @@ dependencies {
|
|||||||
shadowMe 'org.apache.commons:commons-compress:1.21'
|
shadowMe 'org.apache.commons:commons-compress:1.21'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copies the correct accesswidener and renames it
|
||||||
|
task copyAccessWidener(type: Copy) {
|
||||||
|
from project(":common").file("src/main/resources/${rootProject.acsessWidenerVersion}.lod.accesswidener")
|
||||||
|
into(file("build/resources/main"))
|
||||||
|
rename "${rootProject.acsessWidenerVersion}.lod.accesswidener", "lod.accesswidener"
|
||||||
|
}
|
||||||
|
|
||||||
|
task copyCoreResources(type: Copy) {
|
||||||
|
from fileTree(project(":core").file("src/main/resources"))
|
||||||
|
into file("build/resources/main")
|
||||||
|
}
|
||||||
|
|
||||||
|
task copyCommonResources(type: Copy) {
|
||||||
|
from fileTree(project(":common").file("src/main/resources"))
|
||||||
|
into file("build/resources/main")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put stuff from gradle.properties into the mod info
|
||||||
processResources {
|
processResources {
|
||||||
dependsOn(copyAccessWidener)
|
dependsOn(copyAccessWidener)
|
||||||
dependsOn(copyCoreResources)
|
dependsOn(copyCoreResources)
|
||||||
dependsOn(copyCommonResources)
|
dependsOn(copyCommonResources)
|
||||||
|
|
||||||
|
def resourceTargets = ["fabric.mod.json", "META-INF/mods.toml"] // Location of where to put
|
||||||
|
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
||||||
|
def replaceProperties = [
|
||||||
|
version : mod_version,
|
||||||
|
mod_name : mod_name,
|
||||||
|
authors : mod_authors,
|
||||||
|
description : mod_description,
|
||||||
|
homepage : mod_homepage,
|
||||||
|
source : mod_source,
|
||||||
|
issues : mod_issues,
|
||||||
|
minecraft_version : minecraft_version,
|
||||||
|
compatible_minecraft_versions: compatible_minecraft_versions,
|
||||||
|
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
|
||||||
|
//TODO: Make Forge loader version also be relaced with non hardcoded value instead of "[36,42)"
|
||||||
|
|
||||||
|
inputs.properties replaceProperties
|
||||||
|
replaceProperties.put 'project', project
|
||||||
|
filesMatching(resourceTargets) {
|
||||||
|
expand replaceProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
intoTargets.each { target ->
|
||||||
|
if (file(target).exists()) {
|
||||||
|
copy {
|
||||||
|
from(sourceSets.main.resources) {
|
||||||
|
include resourceTargets
|
||||||
|
expand replaceProperties
|
||||||
|
}
|
||||||
|
into target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
@@ -84,6 +182,11 @@ remapJar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes 'Implementation-Title': rootProject.archives_base_name,
|
||||||
|
'Implementation-Version': rootProject.mod_version,
|
||||||
|
'Main-Class': 'com.seibel.lod.core.JarMain' // When changing the main of the jar change this line
|
||||||
|
}
|
||||||
classifier "dev"
|
classifier "dev"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,3 +215,79 @@ publishing {
|
|||||||
// Add repositories to publish to here.
|
// Add repositories to publish to here.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task printConfigurations {
|
||||||
|
doLast {task ->
|
||||||
|
println "Project Name: $name configurations:"
|
||||||
|
configurations.each {
|
||||||
|
println " $it.name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
|
||||||
|
// For parchment mappings
|
||||||
|
maven { url "https://maven.parchmentmc.org" }
|
||||||
|
|
||||||
|
// used to download and compile dependencies from git repos
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
|
||||||
|
// For Manifold Preprocessor
|
||||||
|
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
|
||||||
|
|
||||||
|
// Required for importing Modrinth mods
|
||||||
|
maven {
|
||||||
|
name = "Modrinth"
|
||||||
|
url = "https://api.modrinth.com/maven"
|
||||||
|
content {
|
||||||
|
includeGroup "maven.modrinth"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required for importing CursedForge mods
|
||||||
|
maven {
|
||||||
|
url "https://www.cursemaven.com"
|
||||||
|
content {
|
||||||
|
includeGroup "curse.maven"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// These 2 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
|
||||||
|
flatDir {
|
||||||
|
dirs "${rootDir}/mods/fabric"
|
||||||
|
content {
|
||||||
|
includeGroup "fabric-mod"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flatDir {
|
||||||
|
dirs "${rootDir}/mods/forge"
|
||||||
|
content {
|
||||||
|
includeGroup "forge-mod"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile) {
|
||||||
|
// Add Manifold Preprocessor
|
||||||
|
// def excapedMCVersion = rootProject.minecraft_version.replace(".", "_")
|
||||||
|
// options.compilerArgs += ['-Xplugin:Manifold', "-AMC_VERSION_${excapedMCVersion}"]
|
||||||
|
//
|
||||||
|
//options.compilerArgs += ['-deprecation']
|
||||||
|
//options.compilerArgs += ['-verbose']
|
||||||
|
//options.compilerArgs += ['-Xlint:unchecked']
|
||||||
|
//options.compilerArgs += ['-Xdiags:verbose']
|
||||||
|
//options.compilerArgs += ['-Xprint']
|
||||||
|
//options.compilerArgs += ['-XprintProcessorInfo']
|
||||||
|
//options.compilerArgs += ['-XprintRounds']
|
||||||
|
|
||||||
|
// println options.compilerArgs
|
||||||
|
|
||||||
|
// Set the java version
|
||||||
|
options.compilerArgs += ['-Xplugin:Manifold']
|
||||||
|
options.release = rootProject.java_version as Integer //FIXME: This warning??
|
||||||
|
|
||||||
|
// TODO: make everything use java 8
|
||||||
|
// options.release = 8 // Use Java 8 for everything so back porting is easier?
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,9 +35,15 @@ import com.seibel.lod.common.wrappers.world.WorldWrapper;
|
|||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraftforge.client.event.InputEvent;
|
import net.minecraftforge.client.event.InputEvent;
|
||||||
import net.minecraftforge.event.TickEvent;
|
import net.minecraftforge.event.TickEvent;
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraftforge.event.world.BlockEvent;
|
import net.minecraftforge.event.world.BlockEvent;
|
||||||
import net.minecraftforge.event.world.ChunkEvent;
|
import net.minecraftforge.event.world.ChunkEvent;
|
||||||
import net.minecraftforge.event.world.WorldEvent;
|
import net.minecraftforge.event.world.WorldEvent;
|
||||||
|
#else
|
||||||
|
import net.minecraftforge.event.level.BlockEvent;
|
||||||
|
import net.minecraftforge.event.level.ChunkEvent;
|
||||||
|
import net.minecraftforge.event.level.LevelEvent;
|
||||||
|
#endif
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,30 +70,55 @@ public class ForgeClientProxy
|
|||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void chunkLoadEvent(ChunkEvent.Load event)
|
public void chunkLoadEvent(ChunkEvent.Load event)
|
||||||
{
|
{
|
||||||
|
#if PRE_MC_1_19
|
||||||
clientApi.clientChunkLoadEvent(new ChunkWrapper(event.getChunk(), event.getWorld()), WorldWrapper.getWorldWrapper(event.getWorld()));
|
clientApi.clientChunkLoadEvent(new ChunkWrapper(event.getChunk(), event.getWorld()), WorldWrapper.getWorldWrapper(event.getWorld()));
|
||||||
|
#else
|
||||||
|
clientApi.clientChunkLoadEvent(new ChunkWrapper(event.getChunk(), event.getLevel()), WorldWrapper.getWorldWrapper(event.getLevel()));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
|
#if PRE_MC_1_19
|
||||||
public void worldSaveEvent(WorldEvent.Save event)
|
public void worldSaveEvent(WorldEvent.Save event)
|
||||||
|
#else
|
||||||
|
public void worldSaveEvent(LevelEvent.Save event)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
eventApi.worldSaveEvent();
|
eventApi.worldSaveEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This is also called when a new dimension loads */
|
/** This is also called when a new dimension loads */
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
|
#if PRE_MC_1_19
|
||||||
public void worldLoadEvent(WorldEvent.Load event)
|
public void worldLoadEvent(WorldEvent.Load event)
|
||||||
|
#else
|
||||||
|
public void worldLoadEvent(LevelEvent.Load event)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if (Minecraft.getInstance().screen instanceof TitleScreen) return;
|
if (Minecraft.getInstance().screen instanceof TitleScreen) return;
|
||||||
|
#if PRE_MC_1_19
|
||||||
if (event.getWorld() != null) {
|
if (event.getWorld() != null) {
|
||||||
eventApi.worldLoadEvent(WorldWrapper.getWorldWrapper(event.getWorld()));
|
eventApi.worldLoadEvent(WorldWrapper.getWorldWrapper(event.getWorld()));
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (event.getLevel() != null) {
|
||||||
|
eventApi.worldLoadEvent(WorldWrapper.getWorldWrapper(event.getLevel()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
|
#if PRE_MC_1_19
|
||||||
public void worldUnloadEvent(WorldEvent.Unload event)
|
public void worldUnloadEvent(WorldEvent.Unload event)
|
||||||
{
|
{
|
||||||
eventApi.worldUnloadEvent(WorldWrapper.getWorldWrapper(event.getWorld()));
|
eventApi.worldUnloadEvent(WorldWrapper.getWorldWrapper(event.getWorld()));
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
public void worldUnloadEvent(LevelEvent.Unload event)
|
||||||
|
{
|
||||||
|
eventApi.worldUnloadEvent(WorldWrapper.getWorldWrapper(event.getLevel()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void blockChangeEvent(BlockEvent event)
|
public void blockChangeEvent(BlockEvent event)
|
||||||
@@ -99,8 +130,13 @@ public class ForgeClientProxy
|
|||||||
event.getClass() == BlockEvent.FluidPlaceBlockEvent.class ||
|
event.getClass() == BlockEvent.FluidPlaceBlockEvent.class ||
|
||||||
event.getClass() == BlockEvent.PortalSpawnEvent.class)
|
event.getClass() == BlockEvent.PortalSpawnEvent.class)
|
||||||
{
|
{
|
||||||
|
#if PRE_MC_1_19
|
||||||
IChunkWrapper chunk = new ChunkWrapper(event.getWorld().getChunk(event.getPos()), event.getWorld());
|
IChunkWrapper chunk = new ChunkWrapper(event.getWorld().getChunk(event.getPos()), event.getWorld());
|
||||||
DimensionTypeWrapper dimType = DimensionTypeWrapper.getDimensionTypeWrapper(event.getWorld().dimensionType());
|
DimensionTypeWrapper dimType = DimensionTypeWrapper.getDimensionTypeWrapper(event.getWorld().dimensionType());
|
||||||
|
#else
|
||||||
|
IChunkWrapper chunk = new ChunkWrapper(event.getLevel().getChunk(event.getPos()), event.getLevel());
|
||||||
|
DimensionTypeWrapper dimType = DimensionTypeWrapper.getDimensionTypeWrapper(event.getLevel().dimensionType());
|
||||||
|
#endif
|
||||||
|
|
||||||
// recreate the LOD where the blocks were changed
|
// recreate the LOD where the blocks were changed
|
||||||
eventApi.blockChangeEvent(chunk, dimType);
|
eventApi.blockChangeEvent(chunk, dimType);
|
||||||
@@ -108,7 +144,7 @@ public class ForgeClientProxy
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onKeyInput(InputEvent.KeyInputEvent event)
|
public void onKeyInput(#if PRE_MC_1_19 InputEvent.KeyInputEvent event #else InputEvent.Key event #endif)
|
||||||
{
|
{
|
||||||
if (Minecraft.getInstance().player == null) return;
|
if (Minecraft.getInstance().player == null) return;
|
||||||
if (event.getAction() != GLFW.GLFW_PRESS) return;
|
if (event.getAction() != GLFW.GLFW_PRESS) return;
|
||||||
@@ -116,5 +152,4 @@ public class ForgeClientProxy
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import com.seibel.lod.core.api.ApiShared;
|
|||||||
import com.seibel.lod.core.handlers.ReflectionHandler;
|
import com.seibel.lod.core.handlers.ReflectionHandler;
|
||||||
import com.seibel.lod.core.handlers.dependencyInjection.ModAccessorHandler;
|
import com.seibel.lod.core.handlers.dependencyInjection.ModAccessorHandler;
|
||||||
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.OptifineAccessor;
|
import com.seibel.lod.forge.wrappers.modAccessor.OptifineAccessor;
|
||||||
@@ -39,7 +38,6 @@ import net.minecraft.world.level.ColorResolver;
|
|||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraftforge.client.model.data.ModelDataMap;
|
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.fml.ModLoadingContext;
|
import net.minecraftforge.fml.ModLoadingContext;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
@@ -51,12 +49,24 @@ import net.minecraftforge.fml.loading.FMLLoader;
|
|||||||
import net.minecraftforge.fml.ExtensionPoint;
|
import net.minecraftforge.fml.ExtensionPoint;
|
||||||
#elif MC_1_17_1
|
#elif MC_1_17_1
|
||||||
import net.minecraftforge.fmlclient.ConfigGuiHandler;
|
import net.minecraftforge.fmlclient.ConfigGuiHandler;
|
||||||
#else // 1.18+
|
#elif POST_MC_1_19
|
||||||
|
import net.minecraftforge.client.ConfigScreenHandler;
|
||||||
|
#else // 1.18+ untill 1.19
|
||||||
import net.minecraftforge.client.ConfigGuiHandler;
|
import net.minecraftforge.client.ConfigGuiHandler;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
import java.util.List;
|
// these imports change due to forge refactoring classes in 1.19
|
||||||
|
#if POST_MC_1_19
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraftforge.client.model.data.ModelData;
|
||||||
|
#else
|
||||||
|
import net.minecraftforge.client.model.data.ModelDataMap;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize and setup the Mod. <br>
|
* Initialize and setup the Mod. <br>
|
||||||
@@ -75,7 +85,7 @@ 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(), new NetworkHandler());
|
LodCommonMain.startup(this, !FMLLoader.getDist().isClient());
|
||||||
ForgeDependencySetup.createInitialBindings();
|
ForgeDependencySetup.createInitialBindings();
|
||||||
ForgeDependencySetup.finishBinding();
|
ForgeDependencySetup.finishBinding();
|
||||||
ApiShared.LOGGER.info("Distant Horizons initializing...");
|
ApiShared.LOGGER.info("Distant Horizons initializing...");
|
||||||
@@ -99,6 +109,9 @@ public class ForgeMain implements LodForgeMethodCaller
|
|||||||
#if PRE_MC_1_17_1
|
#if PRE_MC_1_17_1
|
||||||
ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY,
|
ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY,
|
||||||
() -> (client, parent) -> ConfigGui.getScreen(parent, ""));
|
() -> (client, parent) -> ConfigGui.getScreen(parent, ""));
|
||||||
|
#elif POST_MC_1_19
|
||||||
|
ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class,
|
||||||
|
() -> new ConfigScreenHandler.ConfigScreenFactory((client, parent) -> ConfigGui.getScreen(parent, "")));
|
||||||
#else
|
#else
|
||||||
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, "")));
|
||||||
@@ -107,15 +120,27 @@ public class ForgeMain implements LodForgeMethodCaller
|
|||||||
MinecraftForge.EVENT_BUS.register(forgeClientProxy);
|
MinecraftForge.EVENT_BUS.register(forgeClientProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ModelDataMap dataMap = new ModelDataMap.Builder().build();
|
#if PRE_MC_1_19
|
||||||
|
private final ModelDataMap modelData = new ModelDataMap.Builder().build();
|
||||||
|
#else
|
||||||
|
private final ModelData modelData = ModelData.EMPTY;
|
||||||
|
#endif
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
#if PRE_MC_1_19
|
||||||
public List<BakedQuad> getQuads(MinecraftClientWrapper 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, modelData);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
public List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, RandomSource random)
|
||||||
|
{
|
||||||
|
return mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random, modelData #if POST_MC_1_19, RenderType.solid() #endif);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int colorResolverGetColor(ColorResolver resolver, Biome biome, double x, double z) {
|
public int colorResolverGetColor(ColorResolver resolver, Biome biome, double x, double z) {
|
||||||
#if MC_1_17_1
|
#if MC_1_17_1_I_THINK_ITS_FIXED?
|
||||||
return resolver.m_130045_(biome, x, z);
|
return resolver.m_130045_(biome, x, z);
|
||||||
#else
|
#else
|
||||||
return resolver.getColor(biome, x, z);
|
return resolver.getColor(biome, x, z);
|
||||||
|
|||||||
-72
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,161 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,256 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 {
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,204 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-68
@@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,196 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,295 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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() { }
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,130 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.apache.logging.log4j.LogManager;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
|
|
||||||
import com.seibel.lod.forge.fabric.api.event.Event;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
class ArrayBackedEvent<T> extends Event<T> {
|
|
||||||
static final Logger LOGGER = LogManager.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
@@ -1,122 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,205 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,143 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.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 = LogManager.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
@@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,173 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.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 = LogManager.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
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
-125
@@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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) {
|
|
||||||
#if MC_1_16_5
|
|
||||||
return handlePacket(packet.getTransactionId(), packet.getName(), packet.getInternalData());
|
|
||||||
#else
|
|
||||||
return handlePacket(packet.getTransactionId(), packet.getIdentifier(), packet.getData());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
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
@@ -1,136 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,151 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
-221
@@ -1,221 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor.ClientboundCustomQueryPacketAccessor;
|
|
||||||
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) ->
|
|
||||||
#if MC_1_16_5
|
|
||||||
this.connection.setupCompression(this.server.getCompressionThreshold())
|
|
||||||
#else
|
|
||||||
this.connection.setupCompression(this.server.getCompressionThreshold(), true)
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
#if MC_1_16_5
|
|
||||||
ret = new ClientboundCustomQueryPacket();
|
|
||||||
ClientboundCustomQueryPacketAccessor access = (ClientboundCustomQueryPacketAccessor) ret;
|
|
||||||
access.setIdentifier(channelName);
|
|
||||||
access.setTransactionId(queryId);
|
|
||||||
access.setData(buf);
|
|
||||||
#else
|
|
||||||
ret = new ClientboundCustomQueryPacket(queryId, channelName, buf);
|
|
||||||
#endif
|
|
||||||
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(), #if MC_1_16_5 packet.getName() #else packet.getIdentifier() #endif);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-146
@@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.network.protocol.Packet;
|
|
||||||
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
|
||||||
import com.seibel.lod.forge.fabric.api.networking.v1.S2CPlayChannelEvents;
|
|
||||||
import com.seibel.lod.forge.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
|
||||||
import com.seibel.lod.forge.fabric.api.networking.v1.ServerPlayNetworking;
|
|
||||||
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 com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor.CustomPayloadC2SPacketAccessor;
|
|
||||||
|
|
||||||
public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon<ServerPlayNetworking.PlayChannelHandler> {
|
|
||||||
private final ServerGamePacketListenerImpl handler;
|
|
||||||
private final MinecraftServer server;
|
|
||||||
private boolean sentInitialRegisterPacket;
|
|
||||||
|
|
||||||
public ServerPlayNetworkAddon(ServerGamePacketListenerImpl handler, MinecraftServer server) {
|
|
||||||
super(ServerNetworkingImpl.PLAY, handler.getConnection(), "ServerPlayNetworkAddon for " + handler.player.getScoreboardName());
|
|
||||||
this.handler = handler;
|
|
||||||
this.server = server;
|
|
||||||
|
|
||||||
// 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, ServerPlayNetworking.PlayChannelHandler> entry : this.receiver.getHandlers().entrySet()) {
|
|
||||||
this.registerChannel(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerPlayConnectionEvents.INIT.invoker().onPlayInit(this.handler, this.server);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onClientReady() {
|
|
||||||
ServerPlayConnectionEvents.JOIN.invoker().onPlayReady(this.handler, this, this.server);
|
|
||||||
|
|
||||||
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(ServerboundCustomPayloadPacket packet) {
|
|
||||||
// Do not handle the packet on game thread
|
|
||||||
if (this.server.isSameThread()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomPayloadC2SPacketAccessor access = (CustomPayloadC2SPacketAccessor) packet;
|
|
||||||
return this.handle(access.getIdentifier(), access.getData());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void receive(ServerPlayNetworking.PlayChannelHandler handler, FriendlyByteBuf buf) {
|
|
||||||
handler.receive(this.server, this.handler.player, this.handler, buf, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// impl details
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void schedule(Runnable task) {
|
|
||||||
this.handler.player.server.execute(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Packet<?> createPacket(ResourceLocation channelName, FriendlyByteBuf buf) {
|
|
||||||
return ServerPlayNetworking.createS2CPacket(channelName, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void invokeRegisterEvent(List<ResourceLocation> ids) {
|
|
||||||
S2CPlayChannelEvents.REGISTER.invoker().onChannelRegister(this.handler, this, this.server, ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void invokeUnregisterEvent(List<ResourceLocation> ids) {
|
|
||||||
S2CPlayChannelEvents.UNREGISTER.invoker().onChannelUnregister(this.handler, this, this.server, 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() {
|
|
||||||
ServerPlayConnectionEvents.DISCONNECT.invoker().onPlayDisconnect(this.handler, this.server);
|
|
||||||
this.receiver.endSession(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isReservedChannel(ResourceLocation channelName) {
|
|
||||||
return NetworkingImpl.isReservedPlayChannel(channelName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.seibel.lod.forge.mixins;
|
||||||
|
|
||||||
|
import com.seibel.lod.core.render.F3Screen;
|
||||||
|
import net.minecraft.client.gui.components.DebugScreenOverlay;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mixin(DebugScreenOverlay.class)
|
||||||
|
public class MixinDebugScreenOverlay {
|
||||||
|
|
||||||
|
@Inject(method = "getSystemInformation", at = @At("RETURN"))
|
||||||
|
private void addCustomF3(CallbackInfoReturnable<List<String>> cir) {
|
||||||
|
List<String> messages = cir.getReturnValue();
|
||||||
|
|
||||||
|
for (String i: F3Screen.f3List) {
|
||||||
|
messages.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -52,7 +52,11 @@ public class MixinFogRenderer
|
|||||||
|
|
||||||
@Inject(at = @At("RETURN"),
|
@Inject(at = @At("RETURN"),
|
||||||
method = "setupFog(Lnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/FogRenderer$FogMode;FZF)V",
|
method = "setupFog(Lnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/FogRenderer$FogMode;FZF)V",
|
||||||
remap = #if MC_1_16_5 true #else false #endif) // Remap messiness due to this being added by forge.
|
remap = // Remap messiness due to this being added by forge.
|
||||||
|
#if MC_1_16_5 true
|
||||||
|
#elif PRE_MC_1_19 false
|
||||||
|
#else true #endif
|
||||||
|
)
|
||||||
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, float partTick, CallbackInfo callback)
|
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, float partTick, CallbackInfo callback)
|
||||||
{
|
{
|
||||||
ILodConfigWrapperSingleton CONFIG;
|
ILodConfigWrapperSingleton CONFIG;
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ 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;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
|
#if PRE_MC_1_19
|
||||||
import net.minecraft.network.chat.TranslatableComponent;
|
import net.minecraft.network.chat.TranslatableComponent;
|
||||||
|
#endif
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
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;
|
||||||
@@ -39,7 +41,7 @@ import java.util.Objects;
|
|||||||
/**
|
/**
|
||||||
* Adds a button to the menu to goto the config
|
* Adds a button to the menu to goto the config
|
||||||
*
|
*
|
||||||
* @author coolGi2007
|
* @author coolGi
|
||||||
* @version 12-02-2021
|
* @version 12-02-2021
|
||||||
*/
|
*/
|
||||||
@Mixin(OptionsScreen.class)
|
@Mixin(OptionsScreen.class)
|
||||||
@@ -67,6 +69,10 @@ public class MixinOptionsScreen extends Screen {
|
|||||||
// For now it goes to the client option by default
|
// For now it goes to the client option by default
|
||||||
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(ConfigGui.getScreen(this, "client")),
|
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(ConfigGui.getScreen(this, "client")),
|
||||||
// Add a title to the screen
|
// Add a title to the screen
|
||||||
|
#if PRE_MC_1_19
|
||||||
new TranslatableComponent("text.autoconfig." + ModInfo.ID + ".title")));
|
new TranslatableComponent("text.autoconfig." + ModInfo.ID + ".title")));
|
||||||
|
#else
|
||||||
|
Component.translatable("text.autoconfig." + ModInfo.ID + ".title")));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
*
|
*
|
||||||
* This is also the mixin for rendering the clouds
|
* This is also the mixin for rendering the clouds
|
||||||
*
|
*
|
||||||
* @author coolGi2007
|
* @author coolGi
|
||||||
* @author James Seibel
|
* @author James Seibel
|
||||||
* @version 12-31-2021
|
* @version 12-31-2021
|
||||||
*/
|
*/
|
||||||
|
|||||||
-95
@@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.mixins.fabric.mixin.networking;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
|
||||||
import io.netty.util.concurrent.Future;
|
|
||||||
import io.netty.util.concurrent.GenericFutureListener;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.ChannelInfoHolder;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.DisconnectPacketSource;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.NetworkHandlerExtensions;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.PacketCallbackListener;
|
|
||||||
import net.minecraft.network.Connection;
|
|
||||||
import net.minecraft.network.PacketListener;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.chat.TranslatableComponent;
|
|
||||||
import net.minecraft.network.protocol.Packet;
|
|
||||||
import net.minecraft.network.protocol.PacketFlow;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
|
|
||||||
@Mixin(Connection.class)
|
|
||||||
abstract class ClientConnectionMixin implements ChannelInfoHolder {
|
|
||||||
@Shadow
|
|
||||||
private PacketListener packetListener;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
public abstract void send(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> callback);
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
public abstract void disconnect(Component disconnectReason);
|
|
||||||
|
|
||||||
@Unique
|
|
||||||
private Collection<ResourceLocation> playChannels;
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void initAddedFields(PacketFlow side, CallbackInfo ci) {
|
|
||||||
this.playChannels = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must be fully qualified due to mixin not working in production without it
|
|
||||||
@SuppressWarnings("UnnecessaryQualifiedMemberReference")
|
|
||||||
@Redirect(method = "Lnet/minecraft/network/Connection;exceptionCaught(Lio/netty/channel/ChannelHandlerContext;Ljava/lang/Throwable;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/Connection;send(Lnet/minecraft/network/protocol/Packet;Lio/netty/util/concurrent/GenericFutureListener;)V"))
|
|
||||||
private void resendOnExceptionCaught(Connection self, Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> listener) {
|
|
||||||
PacketListener handler = this.packetListener;
|
|
||||||
|
|
||||||
if (handler instanceof DisconnectPacketSource) {
|
|
||||||
this.send(((DisconnectPacketSource) handler).createDisconnectPacket(new TranslatableComponent("disconnect.genericReason")), listener);
|
|
||||||
} else {
|
|
||||||
this.disconnect(new TranslatableComponent("disconnect.genericReason")); // Don't send packet if we cannot send proper packets
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "sendPacket", at = @At(value = "FIELD", target = "Lnet/minecraft/network/Connection;sentPackets:I"))
|
|
||||||
private void checkPacket(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> callback, CallbackInfo ci) {
|
|
||||||
if (this.packetListener instanceof PacketCallbackListener) {
|
|
||||||
((PacketCallbackListener) this.packetListener).sent(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "channelInactive", at = @At("HEAD"))
|
|
||||||
private void handleDisconnect(ChannelHandlerContext channelHandlerContext, CallbackInfo ci) throws Exception {
|
|
||||||
if (packetListener instanceof NetworkHandlerExtensions) { // not the case for client/server query
|
|
||||||
((NetworkHandlerExtensions) packetListener).getAddon().handleDisconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<ResourceLocation> getPendingChannelsNames() {
|
|
||||||
return this.playChannels;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-45
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.mixins.fabric.mixin.networking;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import com.seibel.lod.forge.fabric.api.networking.v1.EntityTrackingEvents;
|
|
||||||
import net.minecraft.server.level.ServerEntity;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
|
|
||||||
@Mixin(ServerEntity.class)
|
|
||||||
abstract class EntityTrackerEntryMixin {
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private Entity entity;
|
|
||||||
|
|
||||||
@Inject(method = "addPairing", at = @At("HEAD"))
|
|
||||||
private void onStartTracking(ServerPlayer player, CallbackInfo ci) {
|
|
||||||
EntityTrackingEvents.START_TRACKING.invoker().onStartTracking(this.entity, player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "removePairing", at = @At("TAIL"))
|
|
||||||
private void onStopTracking(ServerPlayer player, CallbackInfo ci) {
|
|
||||||
EntityTrackingEvents.STOP_TRACKING.invoker().onStopTracking(this.entity, player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-34
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.mixins.fabric.mixin.networking;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.server.ServerNetworkingImpl;
|
|
||||||
import net.minecraft.network.Connection;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.server.players.PlayerList;
|
|
||||||
|
|
||||||
@Mixin(PlayerList.class)
|
|
||||||
abstract class PlayerManagerMixin {
|
|
||||||
@Inject(method = "placeNewPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/protocol/game/ClientboundCustomPayloadPacket;<init>(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/network/FriendlyByteBuf;)V"))
|
|
||||||
private void handlePlayerConnection(Connection connection, ServerPlayer player, CallbackInfo ci) {
|
|
||||||
ServerNetworkingImpl.getAddon(player.connection).onClientReady();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-116
@@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.mixins.fabric.mixin.networking;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.protocol.Packet;
|
|
||||||
import net.minecraft.network.protocol.login.ClientboundCustomQueryPacket;
|
|
||||||
import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket;
|
|
||||||
import net.minecraft.network.protocol.login.ServerboundCustomQueryPacket;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.server.network.ServerLoginPacketListenerImpl;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.DisconnectPacketSource;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.NetworkHandlerExtensions;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.PacketCallbackListener;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.server.ServerLoginNetworkAddon;
|
|
||||||
|
|
||||||
@Mixin(ServerLoginPacketListenerImpl.class)
|
|
||||||
abstract class ServerLoginNetworkHandlerMixin implements NetworkHandlerExtensions, DisconnectPacketSource, PacketCallbackListener {
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private MinecraftServer server;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
public abstract void handleAcceptedLogin();
|
|
||||||
|
|
||||||
@Unique
|
|
||||||
private ServerLoginNetworkAddon addon;
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void initAddon(CallbackInfo ci) {
|
|
||||||
this.addon = new ServerLoginNetworkAddon((ServerLoginPacketListenerImpl) (Object) this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerLoginPacketListenerImpl;handleAcceptedLogin()V"))
|
|
||||||
private void handlePlayerJoin(ServerLoginPacketListenerImpl handler) {
|
|
||||||
// Do not accept the player, thereby moving into play stage until all login futures being waited on are completed
|
|
||||||
if (this.addon.queryTick()) {
|
|
||||||
this.handleAcceptedLogin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "handleCustomQueryPacket", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void handleCustomPayloadReceivedAsync(ServerboundCustomQueryPacket packet, CallbackInfo ci) {
|
|
||||||
// Handle queries
|
|
||||||
if (this.addon.handle(packet)) {
|
|
||||||
ci.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "handleAcceptedLogin", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getCompressionThreshold()I", ordinal = 0))
|
|
||||||
private int removeLateCompressionPacketSending(MinecraftServer server) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "onDisconnect", at = @At("HEAD"))
|
|
||||||
private void handleDisconnection(Component reason, CallbackInfo ci) {
|
|
||||||
this.addon.handleDisconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if MC_1_16_5
|
|
||||||
@Inject(method = "handleAcceptedLogin", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/players/PlayerList;placeNewPlayer(Lnet/minecraft/network/Connection;Lnet/minecraft/server/level/ServerPlayer;)V"))
|
|
||||||
private void handlePlayTransitionNormal(CallbackInfo ci) {
|
|
||||||
this.addon.handlePlayTransition();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/players/PlayerList;placeNewPlayer(Lnet/minecraft/network/Connection;Lnet/minecraft/server/level/ServerPlayer;)V"))
|
|
||||||
private void handlePlayTransitionDelayed(CallbackInfo ci) {
|
|
||||||
this.addon.handlePlayTransition();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
@Inject(method = "placeNewPlayer", at = @At("HEAD"))
|
|
||||||
private void handlePlayTransitionNormal(ServerPlayer player, CallbackInfo ci) {
|
|
||||||
this.addon.handlePlayTransition();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sent(Packet<?> packet) {
|
|
||||||
if (packet instanceof ClientboundCustomQueryPacket) {
|
|
||||||
this.addon.registerOutgoingPacket((ClientboundCustomQueryPacket) packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ServerLoginNetworkAddon getAddon() {
|
|
||||||
return this.addon;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Packet<?> createDisconnectPacket(Component message) {
|
|
||||||
return new ClientboundLoginDisconnectPacket(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-78
@@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.mixins.fabric.mixin.networking;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import net.minecraft.network.Connection;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.protocol.Packet;
|
|
||||||
import net.minecraft.network.protocol.game.ClientboundDisconnectPacket;
|
|
||||||
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.DisconnectPacketSource;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.NetworkHandlerExtensions;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.server.ServerPlayNetworkAddon;
|
|
||||||
|
|
||||||
// We want to apply a bit earlier than other mods which may not use us in order to prevent refCount issues
|
|
||||||
@Mixin(value = ServerGamePacketListenerImpl.class, priority = 999)
|
|
||||||
abstract class ServerPlayNetworkHandlerMixin implements NetworkHandlerExtensions, DisconnectPacketSource {
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private MinecraftServer server;
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
public Connection connection;
|
|
||||||
|
|
||||||
@Unique
|
|
||||||
private ServerPlayNetworkAddon addon;
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void initAddon(CallbackInfo ci) {
|
|
||||||
this.addon = new ServerPlayNetworkAddon((ServerGamePacketListenerImpl) (Object) this, this.server);
|
|
||||||
// A bit of a hack but it allows the field above to be set in case someone registers handlers during INIT event which refers to said field
|
|
||||||
this.addon.lateInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "handleCustomPayload", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void handleCustomPayloadReceivedAsync(ServerboundCustomPayloadPacket packet, CallbackInfo ci) {
|
|
||||||
if (this.addon.handle(packet)) {
|
|
||||||
ci.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "onDisconnect", at = @At("HEAD"))
|
|
||||||
private void handleDisconnection(Component reason, CallbackInfo ci) {
|
|
||||||
this.addon.handleDisconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ServerPlayNetworkAddon getAddon() {
|
|
||||||
return this.addon;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Packet<?> createDisconnectPacket(Component message) {
|
|
||||||
return new ClientboundDisconnectPacket(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-21
@@ -1,21 +0,0 @@
|
|||||||
package com.seibel.lod.forge.mixins.fabric.mixin.networking.accessor;
|
|
||||||
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.network.protocol.login.ClientboundCustomQueryPacket;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
|
||||||
|
|
||||||
@Mixin(ClientboundCustomQueryPacket.class)
|
|
||||||
public interface ClientboundCustomQueryPacketAccessor {
|
|
||||||
#if MC_1_16_5
|
|
||||||
@Accessor
|
|
||||||
void setTransactionId(int transactionId);
|
|
||||||
|
|
||||||
@Accessor
|
|
||||||
void setIdentifier(ResourceLocation identifier);
|
|
||||||
|
|
||||||
@Accessor
|
|
||||||
void setData(FriendlyByteBuf data);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
-28
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.mixins.fabric.mixin.networking.accessor;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
|
||||||
import net.minecraft.client.gui.screens.ConnectScreen;
|
|
||||||
import net.minecraft.network.Connection;
|
|
||||||
|
|
||||||
@Mixin(ConnectScreen.class)
|
|
||||||
public interface ConnectScreenAccessor {
|
|
||||||
@Accessor
|
|
||||||
Connection getConnection();
|
|
||||||
}
|
|
||||||
-32
@@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.mixins.fabric.mixin.networking.accessor;
|
|
||||||
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
|
||||||
|
|
||||||
@Mixin(ServerboundCustomPayloadPacket.class)
|
|
||||||
public interface CustomPayloadC2SPacketAccessor {
|
|
||||||
@Accessor
|
|
||||||
ResourceLocation getIdentifier();
|
|
||||||
|
|
||||||
@Accessor
|
|
||||||
FriendlyByteBuf getData();
|
|
||||||
}
|
|
||||||
-33
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.mixins.fabric.mixin.networking.accessor;
|
|
||||||
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.network.protocol.login.ServerboundCustomQueryPacket;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
|
||||||
|
|
||||||
@Mixin(ServerboundCustomQueryPacket.class)
|
|
||||||
public interface LoginQueryResponseC2SPacketAccessor {
|
|
||||||
@Accessor
|
|
||||||
int getTransactionId();
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Accessor
|
|
||||||
FriendlyByteBuf getData();
|
|
||||||
}
|
|
||||||
-30
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.mixins.fabric.mixin.networking.accessor;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.network.Connection;
|
|
||||||
|
|
||||||
@Mixin(Minecraft.class)
|
|
||||||
public interface MinecraftClientAccessor {
|
|
||||||
@Nullable
|
|
||||||
@Accessor("pendingConnection")
|
|
||||||
Connection getConnection();
|
|
||||||
}
|
|
||||||
-29
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.mixins.fabric.mixin.networking.accessor;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
|
||||||
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.network.ServerLoginPacketListenerImpl;
|
|
||||||
|
|
||||||
@Mixin(ServerLoginPacketListenerImpl.class)
|
|
||||||
public interface ServerLoginNetworkHandlerAccessor {
|
|
||||||
@Accessor
|
|
||||||
MinecraftServer getServer();
|
|
||||||
}
|
|
||||||
-68
@@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.mixins.fabric.mixin.networking.client;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.NetworkHandlerExtensions;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.client.ClientLoginNetworkAddon;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.multiplayer.ClientHandshakePacketListenerImpl;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.protocol.login.ClientboundCustomQueryPacket;
|
|
||||||
|
|
||||||
@Mixin(ClientHandshakePacketListenerImpl.class)
|
|
||||||
abstract class ClientLoginNetworkHandlerMixin implements NetworkHandlerExtensions {
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private Minecraft minecraft;
|
|
||||||
|
|
||||||
@Unique
|
|
||||||
private ClientLoginNetworkAddon addon;
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void initAddon(CallbackInfo ci) {
|
|
||||||
this.addon = new ClientLoginNetworkAddon((ClientHandshakePacketListenerImpl) (Object) this, this.minecraft);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "handleCustomQuery", at = @At(value = "INVOKE", target = "Ljava/util/function/Consumer;accept(Ljava/lang/Object;)V", remap = false, shift = At.Shift.AFTER), cancellable = true)
|
|
||||||
private void handleQueryRequest(ClientboundCustomQueryPacket packet, CallbackInfo ci) {
|
|
||||||
if (this.addon.handlePacket(packet)) {
|
|
||||||
ci.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "onDisconnect", at = @At("HEAD"))
|
|
||||||
private void invokeLoginDisconnectEvent(Component reason, CallbackInfo ci) {
|
|
||||||
this.addon.handleDisconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "handleGameProfile", at = @At("HEAD"))
|
|
||||||
private void handlePlayTransition(CallbackInfo ci) {
|
|
||||||
addon.handlePlayTransition();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClientLoginNetworkAddon getAddon() {
|
|
||||||
return this.addon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-73
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.mixins.fabric.mixin.networking.client;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import com.seibel.lod.forge.fabric.impl.networking.NetworkHandlerExtensions;
|
|
||||||
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.chat.Component;
|
|
||||||
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
|
|
||||||
import net.minecraft.network.protocol.game.ClientboundLoginPacket;
|
|
||||||
|
|
||||||
// We want to apply a bit earlier than other mods which may not use us in order to prevent refCount issues
|
|
||||||
|
|
||||||
@Mixin(value = ClientPacketListener.class, priority = 999)
|
|
||||||
abstract class ClientPlayNetworkHandlerMixin implements NetworkHandlerExtensions {
|
|
||||||
@Shadow
|
|
||||||
private Minecraft minecraft;
|
|
||||||
|
|
||||||
@Unique
|
|
||||||
private ClientPlayNetworkAddon addon;
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void initAddon(CallbackInfo ci) {
|
|
||||||
this.addon = new ClientPlayNetworkAddon((ClientPacketListener) (Object) this, this.minecraft);
|
|
||||||
// A bit of a hack but it allows the field above to be set in case someone registers handlers during INIT event which refers to said field
|
|
||||||
ClientNetworkingImpl.setClientPlayAddon(this.addon);
|
|
||||||
this.addon.lateInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "handleLogin", at = @At("RETURN"))
|
|
||||||
private void handleServerPlayReady(ClientboundLoginPacket packet, CallbackInfo ci) {
|
|
||||||
this.addon.onServerReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "handleCustomPayload", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void handleCustomPayload(ClientboundCustomPayloadPacket packet, CallbackInfo ci) {
|
|
||||||
if (this.addon.handle(packet)) {
|
|
||||||
ci.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "onDisconnect", at = @At("HEAD"))
|
|
||||||
private void handleDisconnection(Component reason, CallbackInfo ci) {
|
|
||||||
this.addon.handleDisconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClientPlayNetworkAddon getAddon() {
|
|
||||||
return this.addon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
|
||||||
* licensed under the GNU GPL v3 License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020-2022 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.forge.networking;
|
|
||||||
|
|
||||||
import com.seibel.lod.common.networking.NetworkInterface;
|
|
||||||
import com.seibel.lod.common.networking.Networking;
|
|
||||||
import com.seibel.lod.forge.fabric.api.client.networking.v1.ClientPlayNetworking;
|
|
||||||
import com.seibel.lod.forge.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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user