mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-14 09:05:17 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
104daf8ef0 | ||
|
|
d9a04b881a | ||
|
|
ae62362d49 | ||
|
|
2f8c3ea738 | ||
|
|
f0c2554b1c | ||
|
|
bb547a5748 | ||
|
|
5dd3842b77 | ||
|
|
2ab4685149 | ||
|
|
edbc07ed22 | ||
|
|
e225dbc8d1 | ||
|
|
117be913da | ||
|
|
512d4d7271 | ||
|
|
a9237cff75 | ||
|
|
bc24487d0e | ||
|
|
c3e0b071a2 | ||
|
|
21787234f4 | ||
|
|
a9958b19db | ||
|
|
b25d9562f2 | ||
|
|
2765c0d8d9 | ||
|
|
82a20911cb | ||
|
|
f19f7e4670 | ||
|
|
e10f5c637e | ||
|
|
4bfe562f14 | ||
|
|
5e64ef9ecb | ||
|
|
dda1be91ea | ||
|
|
4f4849b60c | ||
|
|
3b754fef5e | ||
|
|
5e295f2485 | ||
|
|
5c9258491f | ||
|
|
af87677516 | ||
|
|
a68c886ea2 | ||
|
|
b129e385cc | ||
|
|
fdc921923c | ||
|
|
476e20ae96 | ||
|
|
d63516f2ac | ||
|
|
fd522d38b0 | ||
|
|
5f0d4abf23 | ||
|
|
8e3e8b2120 | ||
|
|
72fd6808d8 | ||
|
|
2c35d04495 | ||
|
|
f704d65d5a | ||
|
|
6c6a4817e7 | ||
|
|
ef3408c1eb | ||
|
|
0ea593c50e | ||
|
|
643b972e97 | ||
|
|
93ce9e72f7 | ||
|
|
f1bafce275 | ||
|
|
75408c1a70 | ||
|
|
00fafb07ce | ||
|
|
e49a347aea | ||
|
|
2c8ca313a0 | ||
|
|
fe7dcdf637 | ||
|
|
15daa2955d | ||
|
|
03af8a53a2 | ||
|
|
c7e4e4b5b4 | ||
|
|
d477425f70 | ||
|
|
a3449f2866 | ||
|
|
2a1f98aec2 | ||
|
|
bc9bd40d03 | ||
|
|
58344b0b15 | ||
|
|
edcc8b3c97 | ||
|
|
d494ba9be4 | ||
|
|
b92f56503e | ||
|
|
5a9be79785 | ||
|
|
225c2125c6 | ||
|
|
e2a932108e | ||
|
|
ec38717702 | ||
|
|
3009f5350c | ||
|
|
a24dd3c8ee | ||
|
|
3fae26a470 | ||
|
|
a44ac01aee | ||
|
|
b09f8d0fc8 | ||
|
|
57a916bf09 | ||
|
|
15d3df2818 | ||
|
|
63a42bad98 | ||
|
|
28d3c491a0 | ||
|
|
551296813e | ||
|
|
62b99be117 | ||
|
|
6683e9e660 | ||
|
|
3b9df7df1b | ||
|
|
a9a8d7ed8c | ||
|
|
80770898c6 | ||
|
|
335cb5edc4 | ||
|
|
7259887176 | ||
|
|
0320c185b5 | ||
|
|
2f5f696b68 | ||
|
|
d33e9c8251 | ||
|
|
21c50da8ec | ||
|
|
e2a205d2e7 | ||
|
|
950e7b032a | ||
|
|
d1a55a147e | ||
|
|
1fd8b1a4b8 | ||
|
|
41ea5b195b | ||
|
|
14e152579b | ||
|
|
dcf7bb1af2 | ||
|
|
456a48b12a | ||
|
|
aceb878a64 | ||
|
|
f451e21f39 | ||
|
|
c6ac740d31 | ||
|
|
dbf98d3888 | ||
|
|
1b7bdc3ec6 | ||
|
|
d414e31f08 | ||
|
|
b2036e9d23 | ||
|
|
abe4afe152 | ||
|
|
e7ad43c993 | ||
|
|
7631600b53 | ||
|
|
530a1e8eb0 | ||
|
|
54b2c18fcf | ||
|
|
eb1a9b57c6 | ||
|
|
5b6d54555e | ||
|
|
40a174310d | ||
|
|
be0a6819ac | ||
|
|
82a7ee1416 | ||
|
|
b4feee8046 | ||
|
|
df8954869a | ||
|
|
8a552136a2 | ||
|
|
34ec627457 | ||
|
|
28dd76ebbf | ||
|
|
b639bcb5c7 | ||
|
|
7538cf5501 | ||
|
|
1112819fc8 | ||
|
|
cdd38270e9 | ||
|
|
20e309c339 | ||
|
|
5f87bde00e | ||
|
|
a4e574fa6b | ||
|
|
ec7cb00f86 | ||
|
|
ebe375dac0 | ||
|
|
4a2572d545 | ||
|
|
55db597baa | ||
|
|
c24d05173f | ||
|
|
d711982a1c | ||
|
|
8a38416e0f | ||
|
|
a784bdb0d0 | ||
|
|
dc9a7f6ad5 | ||
|
|
417798f2eb | ||
|
|
394e76eed3 | ||
|
|
9e476551be | ||
|
|
1dc421e6a4 | ||
|
|
e431bb1caa | ||
|
|
8bd517ca91 | ||
|
|
69ddf58600 | ||
|
|
1e040c9f1f | ||
|
|
11bdf592c8 | ||
|
|
f4a827ab01 | ||
|
|
827ca83cfd | ||
|
|
e9f8acd191 | ||
|
|
febfd5ab62 | ||
|
|
4ca2a8058f | ||
|
|
4acafcccfd | ||
|
|
937b719e24 | ||
|
|
2b5bfd923c | ||
|
|
249aaa5806 | ||
|
|
46f57e6a9a | ||
|
|
cfd79130de | ||
|
|
6a25c99097 | ||
|
|
95be0d87d9 | ||
|
|
6125ec3bc8 | ||
|
|
9944a8252a | ||
|
|
fd544dd414 | ||
|
|
c00777e6ea | ||
|
|
b2cea78006 | ||
|
|
79272361f0 | ||
|
|
fe4be54774 | ||
|
|
eecb8cc783 | ||
|
|
5e2e404828 | ||
|
|
96303f6570 | ||
|
|
166feefc02 | ||
|
|
cd67762bee | ||
|
|
347a0b3c0d | ||
|
|
be1698bb15 | ||
|
|
a3e9d7a397 | ||
|
|
b2dbe9de51 | ||
|
|
a31adc2823 | ||
|
|
30a33f5c3e | ||
|
|
b01a217f45 | ||
|
|
69136fce19 | ||
|
|
ee21224fff | ||
|
|
804f390064 | ||
|
|
ca2023fa80 | ||
|
|
4e562664f4 | ||
|
|
c8d3ad1d1c | ||
|
|
b7379953d5 | ||
|
|
9d7f5dd32a | ||
|
|
049ed79e7b | ||
|
|
675bf8bde2 | ||
|
|
8dc58ad469 | ||
|
|
827c963d7e | ||
|
|
2ac616b293 | ||
|
|
dcfbc08504 | ||
|
|
19f470ee8c | ||
|
|
a96d078a7a | ||
|
|
b375da6962 | ||
|
|
d17f10d80c | ||
|
|
a336e443f7 | ||
|
|
c5a1c90366 | ||
|
|
95c0aa1e98 | ||
|
|
559b801cc4 | ||
|
|
aa97ddad8b | ||
|
|
d612dc3a6d | ||
|
|
9165d4c3a1 | ||
|
|
12d0f96fc2 | ||
|
|
bec9d6f534 | ||
|
|
892c3669e0 | ||
|
|
ce13efbac9 | ||
|
|
1018b077dc | ||
|
|
9746db5129 | ||
|
|
c4de1f33ba | ||
|
|
a8a4623d24 | ||
|
|
10b51f257f | ||
|
|
52d7df06da | ||
|
|
fcc819584a | ||
|
|
4721d4c461 | ||
|
|
dbdc345d4a | ||
|
|
14c6fc3388 | ||
|
|
33419ed5b1 | ||
|
|
9ec1e24dc5 | ||
|
|
06804675be | ||
|
|
2f43f9910d | ||
|
|
ea9a72af85 | ||
|
|
9a92363e15 | ||
|
|
94389d0efd | ||
|
|
9080886c1a | ||
|
|
13ca55f34d | ||
|
|
5dbea18e30 | ||
|
|
30cfd848d8 | ||
|
|
80d08dbf3a | ||
|
|
7d4c238165 | ||
|
|
0ea9401d90 | ||
|
|
4bdfd8674d | ||
|
|
3e9e0a6447 | ||
|
|
76da41dd46 | ||
|
|
6ddf56ef15 | ||
|
|
eeec737188 | ||
|
|
119ac8f4ab | ||
|
|
bdf0d9cf22 | ||
|
|
bd58ced0e4 | ||
|
|
5af6649435 | ||
|
|
695e1fbb94 | ||
|
|
b027a92dd2 | ||
|
|
be5446b91c | ||
|
|
064ae6961b | ||
|
|
22d609ed6c | ||
|
|
315bbb74ff | ||
|
|
4e4d31b68c | ||
|
|
1a17fa6129 | ||
|
|
ca9df21258 | ||
|
|
93d7fa54fc | ||
|
|
f235d80d9f | ||
|
|
be34dd89a9 | ||
|
|
6663f23e13 | ||
|
|
f9f7ef2580 | ||
|
|
86352e9c19 | ||
|
|
8c8b31435b | ||
|
|
16b3e2780e | ||
|
|
1121f18413 | ||
|
|
96804fb4df | ||
|
|
03a6dbb405 | ||
|
|
77e8c72589 | ||
|
|
043e49a694 | ||
|
|
5169f1f6fe | ||
|
|
2bd83b26aa | ||
|
|
e6c1814122 | ||
|
|
7f2892de7e | ||
|
|
439ba462d6 | ||
|
|
7c6ae3e61e | ||
|
|
f9b894ecbf | ||
|
|
df53db351e | ||
|
|
9aa04c8036 | ||
|
|
626496cec0 | ||
|
|
022482a3bd | ||
|
|
dd228a9ac1 | ||
|
|
a6d1646591 | ||
|
|
39f9f393db | ||
|
|
d35784eb14 | ||
|
|
31fb15c88d | ||
|
|
29f175743b | ||
|
|
33499db93f | ||
|
|
84381553a9 | ||
|
|
2a7dde3d2e | ||
|
|
aa4f24c915 | ||
|
|
1d87831773 | ||
|
|
65e99f9b58 | ||
|
|
b98991dc70 | ||
|
|
435e65eb18 | ||
|
|
8211a5048a | ||
|
|
167f14f4a1 | ||
|
|
f332642409 | ||
|
|
77d41023b5 | ||
|
|
da2594289c | ||
|
|
6f3da80b5a | ||
|
|
474b47ea51 | ||
|
|
b6ce4fb066 | ||
|
|
1406f2bf1f | ||
|
|
5125775992 | ||
|
|
929c7b7a0b | ||
|
|
7bf02e7dcd | ||
|
|
9d0d249eaf | ||
|
|
c4b1df1fc7 | ||
|
|
b3f253df61 | ||
|
|
dc099069fa | ||
|
|
e80c785563 | ||
|
|
1f9611204f | ||
|
|
0120f6274d | ||
|
|
c0e74bc8a8 | ||
|
|
80feb0aeb2 | ||
|
|
f47429717d | ||
|
|
0239a736ec | ||
|
|
5c488c9007 | ||
|
|
53c039680c | ||
|
|
7379e8b9a4 | ||
|
|
2a0d9e8dac | ||
|
|
aacba8e38e | ||
|
|
f4fd1c2f16 | ||
|
|
813f3d630d | ||
|
|
76cea5a7da | ||
|
|
e33f794298 | ||
|
|
72d05d17a9 | ||
|
|
19f9b309a6 | ||
|
|
5b53616a47 | ||
|
|
5f9e6f3b56 | ||
|
|
0ad8e2c27f | ||
|
|
55f29764f8 | ||
|
|
a4f7087b92 | ||
|
|
a95b968c13 | ||
|
|
802298d99d | ||
|
|
5363dc5d99 | ||
|
|
9602c22083 | ||
|
|
17500032ae | ||
|
|
65bc41281f | ||
|
|
ba15737fe3 | ||
|
|
58f93263e2 | ||
|
|
d97f28141c | ||
|
|
0340664dbf | ||
|
|
d2cfda3fb4 | ||
|
|
48225e1bea | ||
|
|
37ea725749 | ||
|
|
733b812c7b | ||
|
|
9ab29ea8fe | ||
|
|
fe26b77e3b | ||
|
|
b8eca88f75 | ||
|
|
e039531497 | ||
|
|
9017e24b40 | ||
|
|
75570079ae | ||
|
|
e2167140db | ||
|
|
a89ce2d6f1 | ||
|
|
007cd42ec6 | ||
|
|
d16a8d6d5d | ||
|
|
69321a363e | ||
|
|
0e1ee4b1d2 | ||
|
|
cc1a9be2b4 | ||
|
|
1d7da4c595 | ||
|
|
1ac432c594 | ||
|
|
276871d5a3 | ||
|
|
8460227ddf | ||
|
|
f450d4025d | ||
|
|
93a815957d | ||
|
|
84b7cdc1cd | ||
|
|
83fee0b3d4 | ||
|
|
aeaebf5785 | ||
|
|
d88e660cbb | ||
|
|
ab949c7cca | ||
|
|
7728dde36b | ||
|
|
004ab59e6f | ||
|
|
7bfd2b8f34 | ||
|
|
f169c99348 | ||
|
|
d3d3bdc769 | ||
|
|
0a0f3232ea | ||
|
|
50d75a27e1 | ||
|
|
19f8d2a793 | ||
|
|
f173bde812 | ||
|
|
dd10933ab0 | ||
|
|
9ffa44f254 | ||
|
|
d8f41adf39 | ||
|
|
c3e84646db | ||
|
|
2094f99640 | ||
|
|
94f3bdaa69 | ||
|
|
7220e9d0b0 | ||
|
|
020102d87f | ||
|
|
f101700969 | ||
|
|
c4b148b84b | ||
|
|
b6a9274870 | ||
|
|
830d9699e3 | ||
|
|
fc68b81b21 | ||
|
|
2904772b16 | ||
|
|
e120b57032 | ||
|
|
b86b56260d | ||
|
|
b222b23557 | ||
|
|
8ec4253068 | ||
|
|
74ca88b7be | ||
|
|
a1119cd77a | ||
|
|
545723dc8c | ||
|
|
b64f4780c5 | ||
|
|
1c98b29087 | ||
|
|
33880331d2 | ||
|
|
74a43877e4 | ||
|
|
7542fbea48 | ||
|
|
2d9a1bc6f9 | ||
|
|
a57a240c13 | ||
|
|
b7fb6484d7 | ||
|
|
1a539ffebc | ||
|
|
27220a5ad8 | ||
|
|
e975fc8252 | ||
|
|
d85ea5a3b0 | ||
|
|
ccb7345084 | ||
|
|
93c00b67d9 | ||
|
|
cd393bbfdc | ||
|
|
fd045d4628 | ||
|
|
47e076071b | ||
|
|
a73e003dd3 |
No files matched your search
+9
-10
@@ -9,19 +9,24 @@
|
||||
|
||||
#idea
|
||||
/.idea
|
||||
/*/out
|
||||
/classes
|
||||
*.iml
|
||||
|
||||
#gradle
|
||||
/build
|
||||
/.gradle
|
||||
/mdk/.gradle
|
||||
/mdk/build
|
||||
/*/build
|
||||
/*/.gradle
|
||||
|
||||
#occupational hazards
|
||||
# Projects repo, either ignore it, or ignore patches.
|
||||
/projects/mcp/
|
||||
/projects/clean/
|
||||
/projects/forge/
|
||||
/projects/fmlonly/
|
||||
#/patches/*
|
||||
|
||||
#occupational hazards
|
||||
/projects/**/build/
|
||||
/projects/**/out/
|
||||
/projects/**/run/
|
||||
@@ -32,6 +37,7 @@ src/generated/resources/.cache/
|
||||
#Patch rejects
|
||||
/patches-/
|
||||
*.patch.rej
|
||||
/projects/*/rejects/
|
||||
|
||||
# FML changelog
|
||||
changelog.txt
|
||||
@@ -39,10 +45,3 @@ changelog.txt
|
||||
*.7z
|
||||
/logs/
|
||||
|
||||
gradle.properties
|
||||
!/mdk/gradle.properties
|
||||
/projects/forge/rejects/
|
||||
|
||||
# Srg2Source causes import bugs on these patches. If you intentionnally change these, remove the ignore.
|
||||
/patches/minecraft/net/minecraft/client/renderer/ViewFrustum.java.patch
|
||||
/patches/minecraft/net/minecraft/data/BlockModelDefinition.java.patch
|
||||
Vendored
+104
@@ -0,0 +1,104 @@
|
||||
<?xml version="1.0"?>
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<name>MinecraftForge_Forge Config DSL Script</name>
|
||||
<groupId>MinecraftForge_Forge</groupId>
|
||||
<artifactId>MinecraftForge_Forge_dsl</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.jetbrains.teamcity</groupId>
|
||||
<artifactId>configs-dsl-kotlin-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jetbrains-all</id>
|
||||
<url>https://download.jetbrains.com/teamcity-repository</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>teamcity-server</id>
|
||||
<url>https://teamcity.minecraftforge.net/app/dsl-plugins-repository</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>JetBrains</id>
|
||||
<url>https://download.jetbrains.com/teamcity-repository</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>${basedir}</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<version>${kotlin.version}</version>
|
||||
|
||||
<configuration/>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<phase>process-test-sources</phase>
|
||||
<goals>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.teamcity</groupId>
|
||||
<artifactId>teamcity-configs-maven-plugin</artifactId>
|
||||
<version>${teamcity.dsl.version}</version>
|
||||
<configuration>
|
||||
<format>kotlin</format>
|
||||
<dstDir>target/generated-configs</dstDir>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.teamcity</groupId>
|
||||
<artifactId>configs-dsl-kotlin</artifactId>
|
||||
<version>${teamcity.dsl.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.teamcity</groupId>
|
||||
<artifactId>configs-dsl-kotlin-plugins</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<type>pom</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-script-runtime</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
Vendored
+136
@@ -0,0 +1,136 @@
|
||||
import jetbrains.buildServer.configs.kotlin.v2019_2.*
|
||||
import jetbrains.buildServer.configs.kotlin.v2019_2.projectFeatures.githubIssues
|
||||
|
||||
/*
|
||||
The settings script is an entry point for defining a TeamCity
|
||||
project hierarchy. The script should contain a single call to the
|
||||
project() function with a Project instance or an init function as
|
||||
an argument.
|
||||
|
||||
VcsRoots, BuildTypes, Templates, and subprojects can be
|
||||
registered inside the project using the vcsRoot(), buildType(),
|
||||
template(), and subProject() methods respectively.
|
||||
|
||||
To debug settings scripts in command-line, run the
|
||||
|
||||
mvnDebug org.jetbrains.teamcity:teamcity-configs-maven-plugin:generate
|
||||
|
||||
command and attach your debugger to the port 8000.
|
||||
|
||||
To debug in IntelliJ Idea, open the 'Maven Projects' tool window (View
|
||||
-> Tool Windows -> Maven Projects), find the generate task node
|
||||
(Plugins -> teamcity-configs -> teamcity-configs:generate), the
|
||||
'Debug' option is available in the context menu for the task.
|
||||
*/
|
||||
|
||||
version = "2021.2"
|
||||
|
||||
project {
|
||||
|
||||
buildType(Build)
|
||||
buildType(BuildSecondaryBranches)
|
||||
buildType(PullRequests)
|
||||
|
||||
params {
|
||||
text("docker_jdk_version", "17", label = "Gradle version", description = "The version of the JDK to use during execution of tasks in a JDK.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
|
||||
text("docker_gradle_version", "7.3", label = "Gradle version", description = "The version of Gradle to use during execution of Gradle tasks.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
|
||||
text("git_main_branch", "1.18.x", label = "Git Main Branch", description = "The git main or default branch to use in VCS operations.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
|
||||
text("git_branch_spec", """
|
||||
+:refs/heads/(main*)
|
||||
+:refs/heads/(master*)
|
||||
+:refs/heads/(develop|release|staging|main|master)
|
||||
+:refs/heads/(1.*)
|
||||
""".trimIndent(), label = "The branch specification of the repository", description = "By default all main branches are build by the configuration. Modify this value to adapt the branches build.", display = ParameterDisplay.HIDDEN, allowEmpty = true)
|
||||
text("github_repository_name", "MinecraftForge", label = "The github repository name. Used to connect to it in VCS Roots.", description = "This is the repository slug on github. So for example `MinecraftForge` or `MinecraftForge`. It is interpolated into the global VCS Roots.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
|
||||
text("env.PUBLISHED_JAVA_ARTIFACT_ID", "forge", label = "Published artifact id", description = "The maven coordinate artifact id that has been published by this build. Can not be empty.", allowEmpty = false)
|
||||
text("env.PUBLISHED_JAVA_FML_ARTIFACT_ID", "fmlonly", label = "Published fmlonly artifact id", description = "The maven coordinate artifact id for fml only that has been published by this build. Can not be empty.", allowEmpty = false)
|
||||
text("env.PUBLISHED_JAVA_FML_ARTIFACT_VERSION", "0.0.0-SNAPSHOT", label = "Published fmlonly artifact version", description = "The version for fml only that has been published by this build. Can not be empty.", allowEmpty = false)
|
||||
text("env.PUBLISHED_JAVA_GROUP", "net.minecraftforge", label = "Published group", description = "The maven coordinate group that has been published by this build. Can not be empty.", allowEmpty = false)
|
||||
//These are references and not actually keys
|
||||
password("env.CROWDIN_KEY", "credentialsJSON:a3102dbe-805d-4177-9f54-3d2c2eb08fd5", display = ParameterDisplay.HIDDEN)
|
||||
password("env.KEYSTORE_URL", "credentialsJSON:a7ae1c82-8058-4061-8d12-7f6bc2618d2e", display = ParameterDisplay.HIDDEN)
|
||||
password("env.KEYSTORE_PASSWORD", "credentialsJSON:d7b964e3-a1fd-47a8-b892-6f601fe47479", display = ParameterDisplay.HIDDEN)
|
||||
text("additional_publishing_gradle_parameters", "-PcrowdinKey=%env.CROWDIN_KEY% -PkeystoreKeyPass=%env.KEYSTORE_PASSWORD% -PkeystoreStorePass=%env.KEYSTORE_PASSWORD% -Pkeystore=%env.KEYSTORE_URL%", label = "Additional gradle parameters for publish", description = "Contains the additional gradle parameters used during publishing.", display = ParameterDisplay.HIDDEN, allowEmpty = true)
|
||||
|
||||
checkbox("should_execute_build", "false", label = "Should build", description = "Indicates if the build task should be executed.", display = ParameterDisplay.HIDDEN,
|
||||
checked = "true", unchecked = "false")
|
||||
checkbox("should_execute_test", "false", label = "Should build", description = "Indicates if the build task should be executed.", display = ParameterDisplay.HIDDEN,
|
||||
checked = "true", unchecked = "false")
|
||||
}
|
||||
|
||||
features {
|
||||
githubIssues {
|
||||
id = "MinecraftForge_MinecraftForge__IssueTracker"
|
||||
displayName = "MinecraftForge/MinecraftForge"
|
||||
repositoryURL = "https://github.com/MinecraftForge/MinecraftForge"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Build : BuildType({
|
||||
templates(AbsoluteId("MinecraftForge_SetupGradleUtilsCiEnvironmen"), AbsoluteId("MinecraftForge_BuildWithDiscordNotifications"), AbsoluteId("MinecraftForge_BuildMainBranches"), AbsoluteId("MinecraftForge_SetupProjectUsingGradle"), AbsoluteId("MinecraftForge_BuildUsingGradle"), AbsoluteId("MinecraftForge_PublishProjectUsingGradle"), AbsoluteId("MinecraftForge_TriggersStaticFilesWebpageGenerator"))
|
||||
id("MinecraftForge_MinecraftForge__Build")
|
||||
name = "Build"
|
||||
description = "Builds and Publishes the main branches of the project."
|
||||
|
||||
features {
|
||||
feature {
|
||||
id = "trigger_fml_only_files_generator"
|
||||
type = "triggerBuildFeature"
|
||||
param("triggers", "MinecraftForge_FilesGenerator_GeneratePages")
|
||||
param("parameters", """
|
||||
env.PUBLISHED_JAVA_FML_ARTIFACT_ID~env.PUBLISHED_JAVA_ARTIFACT_ID
|
||||
env.PUBLISHED_JAVA_FML_ARTIFACT_VERSION~env.PUBLISHED_JAVA_ARTIFACT_VERSION
|
||||
env.PUBLISHED_JAVA_GROUP
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
object BuildSecondaryBranches : BuildType({
|
||||
templates(AbsoluteId("MinecraftForge_ExcludesBuildingDefaultBranch"), AbsoluteId("MinecraftForge_SetupGradleUtilsCiEnvironmen"), AbsoluteId("MinecraftForge_BuildWithDiscordNotifications"), AbsoluteId("MinecraftForge_BuildMainBranches"), AbsoluteId("MinecraftForge_SetupProjectUsingGradle"), AbsoluteId("MinecraftForge_BuildUsingGradle"))
|
||||
id("MinecraftForge_MinecraftForge__BuildSecondaryBranches")
|
||||
name = "Build - Secondary Branches"
|
||||
description = "Builds and Publishes the secondary branches of the project."
|
||||
params {
|
||||
text("git_branch_spec", """
|
||||
+:refs/heads/(*)
|
||||
-:refs/heads/noci*
|
||||
""".trimIndent(), label = "The branch specification of the repository", description = "By default all main branches are build by the configuration. Modify this value to adapt the branches build.", display = ParameterDisplay.HIDDEN, allowEmpty = true)
|
||||
}
|
||||
vcs {
|
||||
branchFilter = """
|
||||
+:*
|
||||
-:1.*
|
||||
-:<default>
|
||||
""".trimIndent()
|
||||
}
|
||||
})
|
||||
|
||||
object PullRequests : BuildType({
|
||||
templates(AbsoluteId("MinecraftForge_BuildPullRequests"), AbsoluteId("MinecraftForge_SetupGradleUtilsCiEnvironmen"), AbsoluteId("MinecraftForge_BuildWithDiscordNotifications"), AbsoluteId("MinecraftForge_SetupProjectUsingGradle"), AbsoluteId("MinecraftForge_BuildUsingGradle"))
|
||||
id("MinecraftForge_MinecraftForge__PullRequests")
|
||||
name = "Pull Requests"
|
||||
description = "Builds pull requests for the project"
|
||||
|
||||
params {
|
||||
checkbox("should_execute_build", "true", label = "Should build", description = "Indicates if the build task should be executed.", display = ParameterDisplay.HIDDEN,
|
||||
checked = "true", unchecked = "false")
|
||||
text(
|
||||
"gradle_build_task",
|
||||
"assemble",
|
||||
label = "Gradle build task to execute during build",
|
||||
description = "Determines the build task that is executed to build the project.",
|
||||
display = ParameterDisplay.HIDDEN,
|
||||
allowEmpty = false
|
||||
)
|
||||
}
|
||||
|
||||
vcs {
|
||||
branchFilter = """
|
||||
+:*
|
||||
-:1.*
|
||||
-:<default>
|
||||
""".trimIndent()
|
||||
}
|
||||
})
|
||||
Vendored
+30
-8
@@ -6,8 +6,8 @@ pipeline {
|
||||
}
|
||||
agent {
|
||||
docker {
|
||||
image 'gradle:jdk8'
|
||||
args '-v forgegc:/home/gradle/.gradle/'
|
||||
image 'gradle:7-jdk16'
|
||||
//args '-v forgegc:/home/gradle/.gradle_cache/'
|
||||
}
|
||||
}
|
||||
environment {
|
||||
@@ -34,11 +34,23 @@ pipeline {
|
||||
)
|
||||
}
|
||||
}
|
||||
/*
|
||||
stage('pull_cache') {
|
||||
steps {
|
||||
sh 'cp -r /home/gradle/.gradle_cache/jdks/ /home/gradle/.gradle/jdks/'
|
||||
sh 'cp -r /home/gradle/.gradle_cache/wrapper/ /home/gradle/.gradle/wrapper/'
|
||||
sh 'cp -r /home/gradle/.gradle_cache/caches/ /home/gradle/.gradle/caches/'
|
||||
}
|
||||
}
|
||||
*/
|
||||
stage('setup') {
|
||||
steps {
|
||||
sh './gradlew ${GRADLE_ARGS} --refresh-dependencies --continue setup'
|
||||
withGradle {
|
||||
sh './gradlew ${GRADLE_ARGS} --refresh-dependencies --continue setup'
|
||||
}
|
||||
script {
|
||||
env.MYVERSION = sh(returnStdout: true, script: './gradlew :forge:properties -q | grep "version:" | awk \'{print $2}\'').trim()
|
||||
env.MYVERSION = sh(returnStdout: true, script: './gradlew :forge:properties -q | grep "^version:" | cut -d" " -f2').trim()
|
||||
env.FMLONLY_VERSION = sh(returnStdout: true, script: './gradlew :fmlonly:properties -q | grep "^version:" | cut -d" " -f2').trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,15 +71,23 @@ pipeline {
|
||||
}
|
||||
}
|
||||
environment {
|
||||
FORGE_MAVEN = credentials('forge-maven-forge-user')
|
||||
CROWDIN = credentials('forge-crowdin')
|
||||
KEYSTORE = credentials('forge-jenkins-keystore-old')
|
||||
KEYSTORE_KEYPASS = credentials('forge-jenkins-keystore-old-keypass')
|
||||
KEYSTORE_STOREPASS = credentials('forge-jenkins-keystore-old-keypass')
|
||||
}
|
||||
steps {
|
||||
sh './gradlew ${GRADLE_ARGS} :forge:publish -PforgeMavenUser=${FORGE_MAVEN_USR} -PforgeMavenPassword=${FORGE_MAVEN_PSW} -PkeystoreKeyPass=${KEYSTORE_KEYPASS} -PkeystoreStorePass=${KEYSTORE_STOREPASS} -Pkeystore=${KEYSTORE} -PcrowdinKey=${CROWDIN}'
|
||||
sh 'curl --user ${FORGE_MAVEN} http://files.minecraftforge.net/maven/manage/promote/latest/net.minecraftforge.forge/${MYVERSION}'
|
||||
withCredentials([usernamePassword(credentialsId: 'maven-forge-user', usernameVariable: 'MAVEN_USER', passwordVariable: 'MAVEN_PASSWORD')]) {
|
||||
withGradle {
|
||||
sh './gradlew ${GRADLE_ARGS} publish -PkeystoreKeyPass=${KEYSTORE_KEYPASS} -PkeystoreStorePass=${KEYSTORE_STOREPASS} -Pkeystore=${KEYSTORE} -PcrowdinKey=${CROWDIN}'
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
success {
|
||||
build job: 'filegenerator', parameters: [string(name: 'COMMAND', value: "promote net.minecraftforge:forge ${env.MYVERSION} latest")], propagate: false, wait: false
|
||||
build job: 'filegenerator', parameters: [string(name: 'COMMAND', value: "promote net.minecraftforge:fmlonly ${env.FMLONLY_VERSION} latest")], propagate: false, wait: false
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('test_publish_pr') { //Publish to local repo to test full process, but don't include credentials so it can't sign/publish to maven
|
||||
@@ -78,7 +98,9 @@ pipeline {
|
||||
CROWDIN = credentials('forge-crowdin')
|
||||
}
|
||||
steps {
|
||||
sh './gradlew ${GRADLE_ARGS} :forge:publish -PcrowdinKey=${CROWDIN}'
|
||||
withGradle {
|
||||
sh './gradlew ${GRADLE_ARGS} publish -PcrowdinKey=${CROWDIN}'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-16
@@ -1,16 +1,2 @@
|
||||
Minecraft Forge
|
||||
Copyright (c) 2016-2020.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation version 2.1
|
||||
of the License.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Minecraft Forge - Forge Development LLC
|
||||
SPDX-License-Identifier: LGPL-2.1-only
|
||||
+1131
-633
File diff suppressed because it is too large.
Load diff
@@ -1,2 +1,3 @@
|
||||
/.gradle/
|
||||
/build/
|
||||
/out/
|
||||
@@ -1,10 +1,9 @@
|
||||
repositories {
|
||||
//mavenCentral() //TODO: Update Gradle to use HTTPS by default
|
||||
maven {
|
||||
name 'maven_central'
|
||||
url 'https://repo.maven.apache.org/maven2/'
|
||||
}
|
||||
maven { url = 'https://maven.minecraftforge.net/' }
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
implementation 'org.ow2.asm:asm:7.2'
|
||||
implementation 'org.ow2.asm:asm:9.1'
|
||||
implementation 'org.ow2.asm:asm-tree:9.1'
|
||||
implementation 'net.minecraftforge:srgutils:0.4.+'
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.objectweb.asm.ClassReader
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import org.objectweb.asm.tree.FieldNode
|
||||
import org.objectweb.asm.tree.MethodNode
|
||||
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
abstract class BytecodeFinder extends DefaultTask {
|
||||
@InputFile abstract RegularFileProperty getJar()
|
||||
@OutputFile abstract RegularFileProperty getOutput()
|
||||
|
||||
BytecodeFinder() {
|
||||
output.convention(project.layout.buildDirectory.dir(name).map { it.file("output.json") })
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
Util.init()
|
||||
|
||||
def outputFile = output.get().asFile
|
||||
if (outputFile.exists())
|
||||
outputFile.delete()
|
||||
|
||||
pre()
|
||||
|
||||
jar.get().asFile.withInputStream { i ->
|
||||
new ZipInputStream(i).withCloseable { zin ->
|
||||
ZipEntry zein
|
||||
while ((zein = zin.nextEntry) != null) {
|
||||
if (zein.name.endsWith('.class')) {
|
||||
def node = new ClassNode(Opcodes.ASM9)
|
||||
new ClassReader(zin).accept(node, 0)
|
||||
process(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post()
|
||||
outputFile.text = new JsonBuilder(getData()).toPrettyString()
|
||||
}
|
||||
|
||||
|
||||
protected process(ClassNode node) {
|
||||
if (node.fields != null) node.fields.each { process(node, it) }
|
||||
if (node.methods != null) node.methods.each { process(node, it) }
|
||||
}
|
||||
|
||||
protected pre() {}
|
||||
protected process(ClassNode parent, FieldNode node) {}
|
||||
protected process(ClassNode parent, MethodNode node) {}
|
||||
protected post() {}
|
||||
protected abstract Object getData()
|
||||
}
|
||||
@@ -1,20 +1,24 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.TreeMap
|
||||
import net.minecraftforge.srgutils.IMappingFile
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.objectweb.asm.Opcodes
|
||||
|
||||
public class CheckATs extends DefaultTask {
|
||||
@InputFile File inheritance
|
||||
@InputFiles File[] ats
|
||||
abstract class CheckATs extends DefaultTask {
|
||||
@InputFile abstract RegularFileProperty getInheritance()
|
||||
@InputFiles abstract ConfigurableFileCollection getAts()
|
||||
@InputFile @Optional abstract RegularFileProperty getMappings()
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
def mappings = mappings.map { IMappingFile.load(it.asFile) }.getOrNull()
|
||||
Util.init()
|
||||
def parse = { line ->
|
||||
def idx = line.indexOf('#')
|
||||
@@ -41,7 +45,7 @@ public class CheckATs extends DefaultTask {
|
||||
default: return -1
|
||||
}
|
||||
}
|
||||
def json = inheritance.json()
|
||||
def json = inheritance.get().asFile.json()
|
||||
|
||||
ats.each { f ->
|
||||
TreeMap lines = [:]
|
||||
@@ -51,12 +55,12 @@ public class CheckATs extends DefaultTask {
|
||||
if (line.startsWith('#group ')) {
|
||||
def (modifier, cls, desc, comment, key) = parse.call(line.substring(7))
|
||||
|
||||
if (!desc.equals('*') && !desc.equals('*()') && !desc.equals('<init>'))
|
||||
if (desc != '*' && desc != '*()' && desc != '<init>')
|
||||
throw new IllegalStateException('Invalid group: ' + line)
|
||||
|
||||
group = [modifier: modifier, cls: cls, desc: desc, comment: comment,
|
||||
'existing': [] as Set,
|
||||
'children': [] as TreeSet,
|
||||
existing: [] as Set,
|
||||
children: [] as TreeSet,
|
||||
group: true
|
||||
]
|
||||
if (lines.containsKey(key))
|
||||
@@ -93,7 +97,7 @@ public class CheckATs extends DefaultTask {
|
||||
if (jcls == null) {
|
||||
lines.remove(key)
|
||||
println('Invalid Group: ' + key)
|
||||
} else if ('*'.equals(entry['desc'])) {
|
||||
} else if ('*' == entry['desc']) {
|
||||
if (!jcls.containsKey('fields')) {
|
||||
lines.remove(key)
|
||||
println('Invalid Group, Class has no fields: ' + key)
|
||||
@@ -114,13 +118,13 @@ public class CheckATs extends DefaultTask {
|
||||
}
|
||||
entry['existing'].stream().findAll{ !entry['children'].contains(it) }.each{ println('Removed: ' + it) }
|
||||
}
|
||||
} else if ('*()'.equals(entry['desc'])) {
|
||||
} else if ('*()' == entry['desc']) {
|
||||
if (!jcls.containsKey('methods')) {
|
||||
lines.remove(key)
|
||||
println('Invalid Group, Class has no methods: ' + key)
|
||||
} else {
|
||||
jcls['methods'].each{ mtd, value ->
|
||||
if (mtd.startsWith('<clinit>'))
|
||||
if (mtd.startsWith('<clinit>') || mtd.startsWith('lambda$'))
|
||||
return
|
||||
key = cls + ' ' + mtd.replace(' ', '')
|
||||
if (accessLevel.call(value['access']) < accessStr.call(entry['modifier'])) {
|
||||
@@ -137,7 +141,7 @@ public class CheckATs extends DefaultTask {
|
||||
}
|
||||
entry['existing'].stream().findAll{ !entry['children'].contains(it) }.each{ println('Removed: ' + it) }
|
||||
}
|
||||
} else if ('<init>'.equals(entry['desc'])) { //Make all public non-abstract subclasses
|
||||
} else if ('<init>' == entry['desc']) { //Make all public non-abstract subclasses
|
||||
json.each{ tcls,value ->
|
||||
if (!value.containsKey('methods') || ((value['access'] & Opcodes.ACC_ABSTRACT) != 0))
|
||||
return
|
||||
@@ -182,7 +186,7 @@ public class CheckATs extends DefaultTask {
|
||||
lines.remove(key)
|
||||
println('Invalid: ' + key)
|
||||
} else if (entry['desc'] == '') {
|
||||
if (accessLevel.call(jcls['access']) >= accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
|
||||
if (accessLevel.call(jcls['access']) > accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
|
||||
lines.remove(key)
|
||||
println('Invalid Narrowing: ' + key)
|
||||
}
|
||||
@@ -192,7 +196,7 @@ public class CheckATs extends DefaultTask {
|
||||
println('Invalid: ' + key)
|
||||
} else {
|
||||
def value = jcls['fields'][entry['desc']]
|
||||
if (accessLevel.call(value['access']) >= accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
|
||||
if (accessLevel.call(value['access']) > accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
|
||||
lines.remove(key)
|
||||
println('Invalid Narrowing: ' + key)
|
||||
println(entry.comment)
|
||||
@@ -205,7 +209,7 @@ public class CheckATs extends DefaultTask {
|
||||
println('Invalid: ' + key)
|
||||
} else {
|
||||
def value = jcls['methods'][jdesc]
|
||||
if (accessLevel.call(value['access']) >= accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
|
||||
if (accessLevel.call(value['access']) > accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
|
||||
lines.remove(key)
|
||||
println('Invalid Narrowing: ' + key)
|
||||
}
|
||||
@@ -216,12 +220,44 @@ public class CheckATs extends DefaultTask {
|
||||
|
||||
|
||||
def data = []
|
||||
def remapComment = { entry ->
|
||||
if (!mappings || !entry || !entry.desc) return null
|
||||
def comment = entry.comment?.substring(1)?.trim()
|
||||
def jsonCls = json.get(entry.cls.replaceAll('\\.', '/'))
|
||||
def mappingsClass = mappings?.getClass(jsonCls.name)
|
||||
if (!mappingsClass) return entry.comment
|
||||
def idx = entry.desc.indexOf('(')
|
||||
def mappedName = idx == -1
|
||||
? mappingsClass.remapField(entry.desc)
|
||||
: mappingsClass.remapMethod(entry.desc.substring(0, idx), entry.desc.substring(idx))
|
||||
if (!mappedName) return entry.comment
|
||||
if (mappedName == '<init>')
|
||||
mappedName = 'constructor'
|
||||
|
||||
if (comment?.startsWith(mappedName))
|
||||
return '# ' + comment
|
||||
if (comment && comment.indexOf(' ') != -1) {
|
||||
def split = comment.split(" - ").toList()
|
||||
if (split[0].indexOf(' ') != -1)
|
||||
// The first string is more than one word, so append before it
|
||||
return "# ${mappedName} - ${comment}"
|
||||
split.remove(0)
|
||||
return "# ${mappedName} - ${String.join(' - ', split)}"
|
||||
}
|
||||
return '# ' + mappedName
|
||||
}
|
||||
lines.each { key,value ->
|
||||
if (!value.group) {
|
||||
data.add(value.modifier + ' ' + key + (value.comment == null ? '' : ' ' + value.comment))
|
||||
def comment = remapComment.call(value)
|
||||
data.add(value.modifier + ' ' + key + (comment ? ' ' + comment : ''))
|
||||
} else {
|
||||
data.add('#group ' + value.modifier + ' ' + key + (value.comment == null ? '' : ' ' + value.comment))
|
||||
value.children.each{ data.add(value.modifier + ' ' + it) }
|
||||
value.children.each {
|
||||
def line = value.modifier + ' ' + it
|
||||
def (modifier, cls, desc, comment) = parse.call(line)
|
||||
comment = remapComment.call([modifier: modifier, cls: cls, desc: desc, comment: comment])
|
||||
data.add(line + (comment ? ' ' + comment : ''))
|
||||
}
|
||||
data.add('#endgroup')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.TreeMap
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.InputFile
|
||||
@@ -17,17 +17,17 @@ import org.objectweb.asm.Type
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
public class CheckExcs extends DefaultTask {
|
||||
@InputFile File binary
|
||||
@InputFiles File[] excs
|
||||
abstract class CheckExcs extends DefaultTask {
|
||||
@InputFile abstract RegularFileProperty getBinary()
|
||||
@InputFiles abstract ConfigurableFileCollection getExcs()
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
Util.init()
|
||||
def known = []
|
||||
binary.withInputStream { i ->
|
||||
binary.get().asFile.withInputStream { i ->
|
||||
new ZipInputStream(i).withCloseable { zin ->
|
||||
def visitor = new ClassVisitor(Opcodes.ASM7) {
|
||||
def visitor = new ClassVisitor(Opcodes.ASM9) {
|
||||
private String cls
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
@@ -68,8 +68,7 @@ public class CheckExcs extends DefaultTask {
|
||||
|
||||
def (key, value) = line.split('=', 2)
|
||||
if (!known.contains(key)) {
|
||||
println(key)
|
||||
println('Invalid: ' + line)
|
||||
println('Unknown: ' + line)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
@@ -9,19 +10,19 @@ import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import java.util.regex.Pattern
|
||||
|
||||
public class CheckPatches extends DefaultTask {
|
||||
@InputDirectory File patchDir
|
||||
abstract class CheckPatches extends DefaultTask {
|
||||
@InputDirectory abstract DirectoryProperty getPatchDir()
|
||||
@Input boolean autoFix = false
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
def hasS2SArtifact = [
|
||||
Paths.get("patches/minecraft/net/minecraft/client/renderer/ViewFrustum.java.patch"),
|
||||
Paths.get("patches/minecraft/net/minecraft/data/BlockModelDefinition.java.patch")
|
||||
Paths.get("patches/minecraft/net/minecraft/client/renderer/ViewArea.java.patch"),
|
||||
Paths.get("patches/minecraft/net/minecraft/data/models/blockstates/Variant.java.patch")
|
||||
]
|
||||
|
||||
def verified = true;
|
||||
project.fileTree(patchDir).each { patch ->
|
||||
patchDir.get().asFileTree.each { patch ->
|
||||
def patchPath = project.rootDir.toPath().relativize(patch.toPath())
|
||||
verified &= verifyPatch(patch, autoFix, patchPath.toString(), hasS2SArtifact.contains(patchPath))
|
||||
}
|
||||
@@ -31,7 +32,7 @@ public class CheckPatches extends DefaultTask {
|
||||
}
|
||||
|
||||
def verifyPatch(patch, fix, patchPath, hasS2SArtifact) {
|
||||
def hunk_start_pattern = Pattern.compile('^@@ -[0-9,]* \\+[0-9,]* @@$')
|
||||
def hunk_start_pattern = Pattern.compile('^@@ -[0-9,]* \\+[0-9,_]* @@$')
|
||||
def white_space_pattern = Pattern.compile('^[+\\-]\\s*$')
|
||||
def import_pattern = Pattern.compile('^[+\\-]\\s*import.*')
|
||||
def field_pattern = Pattern.compile('^[+\\-][\\s]*((public|protected|private)[\\s]*)?(static[\\s]*)?(final)?([^=;]*)(=.*)?;\\s*$')
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.TreeMap
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.objectweb.asm.Opcodes
|
||||
|
||||
public class CheckSAS extends DefaultTask {
|
||||
@InputFile File inheritance
|
||||
@InputFiles File[] sass
|
||||
abstract class CheckSAS extends DefaultTask {
|
||||
@InputFile abstract RegularFileProperty getInheritance()
|
||||
@InputFiles abstract ConfigurableFileCollection getSass()
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
Util.init()
|
||||
def json = inheritance.json()
|
||||
def json = inheritance.get().asFile.json()
|
||||
|
||||
sass.each { f ->
|
||||
def lines = []
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import java.util.function.BiConsumer
|
||||
|
||||
public class ClosureHelper {
|
||||
BiConsumer<String, Closure> callback
|
||||
|
||||
public ClosureHelper(Closure cl, BiConsumer<String, Closure> callback) {
|
||||
this.callback = callback
|
||||
apply(this, cl)
|
||||
}
|
||||
|
||||
|
||||
def methodMissing(String name, Object args) {
|
||||
if (!args.class.isArray()) return
|
||||
Object[] aargs = (Object[])args
|
||||
|
||||
if (aargs.length == 1 && aargs[0] instanceof Closure) {
|
||||
this.callback.accept(name, (Closure)aargs[0])
|
||||
} else {
|
||||
throw new IllegalArgumentException('Unknown method: "' + name + '" with arguments ' + args + ' for ' + this)
|
||||
}
|
||||
}
|
||||
|
||||
static <T> T apply(T obj, Closure cl) {
|
||||
cl.delegate = obj
|
||||
cl.resolveStrategy = Closure.DELEGATE_FIRST
|
||||
cl()
|
||||
return obj
|
||||
}
|
||||
}
|
||||
+25
-17
@@ -1,47 +1,55 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
import java.util.zip.ZipOutputStream
|
||||
import java.net.URL
|
||||
|
||||
public class CrowdinTask extends DefaultTask {
|
||||
@Input String id = 'minecraft-forge'
|
||||
@Input @Optional String key
|
||||
abstract class Crowdin extends DefaultTask {
|
||||
@Input abstract Property<String> getId()
|
||||
@Input @Optional abstract Property<String> getKey()
|
||||
@Input boolean json = true
|
||||
@OutputFile output = project.file("build/${name}/output.zip")
|
||||
@OutputFile export = project.file("build/${name}/export.json")
|
||||
|
||||
CrowdinTask() {
|
||||
@OutputFile abstract RegularFileProperty getOutput()
|
||||
@OutputFile abstract RegularFileProperty getExport()
|
||||
|
||||
Crowdin() {
|
||||
outputs.upToDateWhen{ false }
|
||||
id.convention('minecraft-forge')
|
||||
output.convention(project.layout.buildDirectory.dir(name).map {it.file("output.zip") })
|
||||
export.convention(project.layout.buildDirectory.dir(name).map {it.file("export.json") })
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
def run() {
|
||||
if (output.exists())
|
||||
output.delete()
|
||||
File outputFile = output.get().asFile
|
||||
File exportFile = export.get().asFile
|
||||
if (outputFile.exists())
|
||||
outputFile.delete()
|
||||
|
||||
if (key == null)
|
||||
if (!key.isPresent())
|
||||
return
|
||||
String key = this.key.get()
|
||||
String id = this.id.get()
|
||||
|
||||
// Force an export
|
||||
new URL("https://api.crowdin.com/api/project/${id}/export?key=${key}").withInputStream { i ->
|
||||
export.withOutputStream { it << i }
|
||||
new URL("https://api.crowdin.com/api/project/${id}/export?key=${key}").withInputStream { i ->
|
||||
exportFile.withOutputStream { it << i }
|
||||
}
|
||||
|
||||
if (!export.text.contains('success')) {
|
||||
throw new RuntimeException("Crowdin export failed, see ${export} for more info")
|
||||
if (!exportFile.text.contains('success')) {
|
||||
throw new RuntimeException("Crowdin export failed, see ${exportFile} for more info")
|
||||
}
|
||||
|
||||
new URL("https://api.crowdin.com/api/project/${id}/download/all.zip?key=${key}").withInputStream { i ->
|
||||
new ZipInputStream(i).withCloseable { zin ->
|
||||
output.withOutputStream { out ->
|
||||
outputFile.withOutputStream { out ->
|
||||
new ZipOutputStream(out).withCloseable { zout ->
|
||||
ZipEntry zein
|
||||
while ((zein = zin.nextEntry) != null) {
|
||||
@@ -0,0 +1,54 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.OutputFiles
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
|
||||
import java.nio.file.Files
|
||||
|
||||
abstract class DownloadLibraries extends DefaultTask {
|
||||
@InputFile abstract RegularFileProperty getInput()
|
||||
@OutputDirectory abstract DirectoryProperty getOutput()
|
||||
@OutputFile abstract RegularFileProperty getLibrariesOutput()
|
||||
|
||||
DownloadLibraries() {
|
||||
output.convention(project.layout.buildDirectory.dir(name))
|
||||
librariesOutput.convention(project.layout.buildDirectory.dir(name).map(d -> d.file('libraries.txt')))
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
def run() {
|
||||
Util.init()
|
||||
File outputDir = output.get().asFile
|
||||
def libraries = new ArrayList()
|
||||
|
||||
def json = input.get().asFile.json().libraries.each { lib ->
|
||||
//TODO: Thread?
|
||||
def artifacts = [lib.downloads.artifact] + lib.downloads.get('classifiers', [:]).values()
|
||||
artifacts.each{ art ->
|
||||
def target = new File(outputDir, art.path)
|
||||
libraries.add(target.absolutePath)
|
||||
if (!target.exists() || !art.sha1.equals(target.sha1())) {
|
||||
project.logger.lifecycle("Downloading ${art.url}")
|
||||
if (!target.parentFile.exists()) {
|
||||
target.parentFile.mkdirs()
|
||||
}
|
||||
new URL(art.url).withInputStream { i ->
|
||||
target.withOutputStream { it << i }
|
||||
}
|
||||
if (!art.sha1.equals(target.sha1())) {
|
||||
throw new IllegalStateException("Failed to download ${art.url} to ${target.canonicalPath} SHA Mismatch")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Files.write(librariesOutput.get().asFile.toPath(), libraries)
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
|
||||
import java.io.File
|
||||
import java.util.HashSet
|
||||
import java.util.Set
|
||||
import java.net.URL
|
||||
|
||||
public class DownloadLibrariesTask extends DefaultTask {
|
||||
@InputFile File input
|
||||
@OutputDirectory File output = project.file("build/${name}/")
|
||||
Set<File> libraries = new HashSet<>()
|
||||
|
||||
@TaskAction
|
||||
def run() {
|
||||
Util.init()
|
||||
|
||||
def json = input.json().libraries.each { lib ->
|
||||
//TODO: Thread?
|
||||
def artifacts = [lib.downloads.artifact] + lib.downloads.get('classifiers', [:]).values()
|
||||
artifacts.each{ art ->
|
||||
def target = new File(output, art.path)
|
||||
libraries.add(target)
|
||||
if (!target.exists() || !art.sha1.equals(target.sha1())) {
|
||||
project.logger.lifecycle("Downloading ${art.url}")
|
||||
if (!target.parentFile.exists()) {
|
||||
target.parentFile.mkdirs()
|
||||
}
|
||||
new URL(art.url).withInputStream { i ->
|
||||
target.withOutputStream { it << i }
|
||||
}
|
||||
if (!art.sha1.equals(target.sha1())) {
|
||||
throw new IllegalStateException("Failed to download ${art.url} to ${target.canonicalPath} SHA Mismatch")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.HashMap
|
||||
import java.util.TreeMap
|
||||
import java.util.TreeSet
|
||||
import java.util.function.BiConsumer
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.*
|
||||
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.Type
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import org.objectweb.asm.tree.FieldNode
|
||||
import org.objectweb.asm.tree.MethodNode
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*
|
||||
|
||||
abstract class FieldCompareFinder extends BytecodeFinder {
|
||||
@Nested
|
||||
Map<String, Search> fields = [:] as HashMap
|
||||
@Internal
|
||||
Map<Search, String> fieldsReverse = [:] as HashMap
|
||||
@Internal
|
||||
Map<String, Set<ObjectTarget>> targets = [:] as TreeMap
|
||||
|
||||
@Override
|
||||
protected pre() {
|
||||
//fields.each{ k,v -> logger.lifecycle("Fields: " + k + ' ' + v) }
|
||||
}
|
||||
|
||||
@Override
|
||||
protected process(ClassNode parent, MethodNode node) {
|
||||
def last = null
|
||||
def parentInstance = new ObjectTarget(owner: parent.name, name: '', desc: '')
|
||||
for (int x = 0; x < node.instructions.size(); x++) {
|
||||
def current = node.instructions.get(x)
|
||||
if (current.opcode == IF_ACMPEQ || current.opcode == IF_ACMPNE) {
|
||||
if (last != null && (last.opcode == GETSTATIC || last.opcode == GETFIELD)) {
|
||||
def target = new Search(cls: last.owner, name: last.name)
|
||||
def wanted = fieldsReverse.get(target)
|
||||
def original = fields.get(wanted)
|
||||
def instance = new ObjectTarget(owner: parent.name, name: node.name, desc: node.desc)
|
||||
if (wanted != null && (original.blacklist == null || (!original.blacklist.contains(instance) && !original.blacklist.contains(parentInstance)))) {
|
||||
targets.computeIfAbsent(wanted, { k -> new TreeSet() }).add(instance)
|
||||
}
|
||||
}
|
||||
}
|
||||
last = current
|
||||
}
|
||||
}
|
||||
|
||||
@Internal
|
||||
@Override
|
||||
protected Object getData() {
|
||||
def ret = [:] as HashMap
|
||||
targets.forEach{ k, v ->
|
||||
def e = fields.get(k)
|
||||
ret[k] = [
|
||||
cls: e.cls,
|
||||
name: e.name,
|
||||
replacement: e.replacement,
|
||||
targets: v
|
||||
]
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@EqualsAndHashCode(excludes = ['replacement', 'blacklist'])
|
||||
public static class Search {
|
||||
@Input
|
||||
String cls
|
||||
|
||||
@Input
|
||||
String name
|
||||
|
||||
@Input
|
||||
String replacement
|
||||
|
||||
@Nested
|
||||
@Optional
|
||||
Set<ObjectTarget> blacklist
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
return cls + '.' + name
|
||||
}
|
||||
|
||||
def blacklist(def owner, def name, def desc) {
|
||||
if (blacklist == null)
|
||||
blacklist = new HashSet()
|
||||
blacklist.add(new ObjectTarget(owner: owner, name: name, desc: desc))
|
||||
}
|
||||
def blacklist(def owner) {
|
||||
blacklist(owner, '', '')
|
||||
}
|
||||
}
|
||||
|
||||
def fields(Closure cl) {
|
||||
new ClosureHelper(cl, {name, ccl ->
|
||||
def search = ClosureHelper.apply(new Search(), ccl)
|
||||
this.fields.put(name, search)
|
||||
this.fieldsReverse.put(search, name)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import org.gradle.api.tasks.bundling.Zip
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.provider.SetProperty
|
||||
|
||||
abstract class InstallerJar extends Zip {
|
||||
@Input @Optional abstract SetProperty<String> getPackedDependencies()
|
||||
|
||||
InstallerJar() {
|
||||
archiveClassifier.set('installer')
|
||||
archiveExtension.set('jar') // Needs to be Zip task to not override Manifest, so set extension
|
||||
destinationDirectory.set(project.layout.buildDirectory.dir('libs'))
|
||||
|
||||
def installerJson = project.tasks.installerJson
|
||||
def launcherJson = project.tasks.launcherJson
|
||||
def downloadInstaller = project.tasks.downloadInstaller
|
||||
|
||||
dependsOn(installerJson, launcherJson, downloadInstaller)
|
||||
from(installerJson, launcherJson)
|
||||
|
||||
from(project.rootProject.file('/src/main/resources/url.png'))
|
||||
project.afterEvaluate {
|
||||
from(project.zipTree(downloadInstaller.output)) {
|
||||
duplicatesStrategy = 'exclude'
|
||||
}
|
||||
|
||||
if (!System.env.MAVEN_USER) {
|
||||
dependsOn(project.universalJar)
|
||||
from(project.universalJar) {
|
||||
into '/maven/' + project.group.replace('.', '/') + '/' + project.universalJar.archiveBaseName.get() + '/' + project.version + '/'
|
||||
}
|
||||
|
||||
packedDependencies.get().forEach {
|
||||
def jarTask = project.rootProject.getTasks().findByPath(it)
|
||||
dependsOn(jarTask)
|
||||
from(jarTask) {
|
||||
into '/maven/' + jarTask.project.group.replace('.', '/') + '/' + jarTask.archiveBaseName.get() + '/' + jarTask.project.version + '/'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.SetProperty
|
||||
import org.gradle.api.tasks.*
|
||||
|
||||
import java.nio.file.Files
|
||||
|
||||
abstract class InstallerJson extends DefaultTask {
|
||||
@OutputFile abstract RegularFileProperty getOutput()
|
||||
@InputFiles abstract ConfigurableFileCollection getInput()
|
||||
@Input @Optional abstract SetProperty<String> getPackedDependencies()
|
||||
@Input @Optional final Map<String, Object> libraries = new LinkedHashMap<>()
|
||||
@Input Map<String, Object> json = new LinkedHashMap<>()
|
||||
@InputFile abstract RegularFileProperty getIcon()
|
||||
@Input abstract Property<String> getLauncherJsonName()
|
||||
@Input abstract Property<String> getLogo()
|
||||
@Input abstract Property<String> getMirrors()
|
||||
@Input abstract Property<String> getWelcome()
|
||||
|
||||
InstallerJson() {
|
||||
getLauncherJsonName().convention('/version.json')
|
||||
getLogo().convention('/big_logo.png')
|
||||
getMirrors().convention('https://files.minecraftforge.net/mirrors-2.0.json')
|
||||
getWelcome().convention("Welcome to the simple ${project.name.capitalize()} installer.")
|
||||
|
||||
getOutput().convention(project.layout.buildDirectory.file('install_profile.json'))
|
||||
|
||||
['client', 'server'].each { side ->
|
||||
['slim', 'extra'].each { type ->
|
||||
def tsk = project.tasks.getByName("download${side.capitalize()}${type.capitalize()}")
|
||||
dependsOn(tsk)
|
||||
input.from(tsk.output)
|
||||
}
|
||||
def tsk = project.tasks.getByName("create${side.capitalize()}SRG")
|
||||
dependsOn(tsk)
|
||||
input.from(tsk.output)
|
||||
}
|
||||
|
||||
|
||||
project.afterEvaluate {
|
||||
(packedDependencies.get().collect{ project.rootProject.tasks.findByPath(it) } + [project.universalJar]).forEach {
|
||||
dependsOn(it)
|
||||
input.from it.archiveFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
def libs = libraries
|
||||
for (def child : packedDependencies.get().collect{ project.rootProject.tasks.findByPath(it) } + [project.universalJar]) {
|
||||
def dep = Util.getMavenDep(child)
|
||||
def path = Util.getMavenPath(child)
|
||||
libs.put(dep.toString(), [
|
||||
name: dep,
|
||||
downloads: [
|
||||
artifact: [
|
||||
path: path,
|
||||
url: "https://maven.minecraftforge.net/${path}",
|
||||
sha1: child.archiveFile.get().asFile.sha1(),
|
||||
size: child.archiveFile.get().asFile.length()
|
||||
]
|
||||
]
|
||||
])
|
||||
}
|
||||
json.libraries = libs.values().sort{a,b -> a.name.compareTo(b.name)}
|
||||
json.icon = "data:image/png;base64," + new String(Base64.getEncoder().encode(Files.readAllBytes(icon.get().asFile.toPath())))
|
||||
json.json = launcherJsonName.get()
|
||||
json.logo = logo.get()
|
||||
if (!mirrors.get().isEmpty())
|
||||
json.mirrorList = mirrors.get()
|
||||
json.welcome = welcome.get()
|
||||
|
||||
Files.writeString(output.get().getAsFile().toPath(), new JsonBuilder(json).toPrettyString())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.SetProperty
|
||||
import org.gradle.api.tasks.*
|
||||
|
||||
import java.nio.file.Files
|
||||
|
||||
import static net.minecraftforge.forge.tasks.Util.getArtifacts
|
||||
import static net.minecraftforge.forge.tasks.Util.iso8601Now
|
||||
|
||||
abstract class LauncherJson extends DefaultTask {
|
||||
@OutputFile abstract RegularFileProperty getOutput()
|
||||
@InputFiles abstract ConfigurableFileCollection getInput()
|
||||
@Input Map<String, Object> json = new LinkedHashMap<>()
|
||||
@Input @Optional abstract SetProperty<String> getPackedDependencies()
|
||||
|
||||
@Internal final vanilla = project.project(':mcp').file('build/mcp/downloadJson/version.json')
|
||||
@Internal final timestamp = iso8601Now()
|
||||
@Internal final comment = [
|
||||
"Please do not automate the download and installation of Forge.",
|
||||
"Our efforts are supported by ads from the download page.",
|
||||
"If you MUST automate this, please consider supporting the project through https://www.patreon.com/LexManos/"
|
||||
]
|
||||
@Internal final id = "${project.rootProject.ext.MC_VERSION}-${project.name}${project.version.substring(project.rootProject.ext.MC_VERSION.length())}"
|
||||
|
||||
LauncherJson() {
|
||||
getOutput().convention(project.layout.buildDirectory.file('version.json'))
|
||||
|
||||
dependsOn(':fmlloader:jar', 'universalJar')
|
||||
getInput().from(project.tasks.universalJar.archiveFile,
|
||||
project.project(':fmlloader').jar.archiveFile,
|
||||
vanilla)
|
||||
|
||||
project.afterEvaluate {
|
||||
packedDependencies.get().forEach {
|
||||
def jarTask = project.rootProject.tasks.findByPath(it)
|
||||
dependsOn(jarTask)
|
||||
input.from jarTask.archiveFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
if (!json.libraries)
|
||||
json.libraries = []
|
||||
def libs = [:]
|
||||
getArtifacts(project, project.configurations.installer, false).each { key, lib -> libs[key] = lib }
|
||||
getArtifacts(project, project.configurations.moduleonly, false).each { key, lib -> libs[key] = lib }
|
||||
|
||||
packedDependencies.get().collect{ project.rootProject.tasks.findByPath(it) }.forEach {
|
||||
def path = Util.getMavenPath(it)
|
||||
def key = Util.getMavenDep(it)
|
||||
|
||||
libs[key] = [
|
||||
name: key,
|
||||
downloads: [
|
||||
artifact: [
|
||||
path: path,
|
||||
url: "https://maven.minecraftforge.net/${path}",
|
||||
sha1: it.archiveFile.get().asFile.sha1(),
|
||||
size: it.archiveFile.get().asFile.length()
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
libs.each { key, lib -> json.libraries.add(lib) }
|
||||
Files.writeString(output.get().asFile.toPath(), new JsonBuilder(json).toPrettyString())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Nested
|
||||
import org.gradle.api.tasks.Optional
|
||||
|
||||
@EqualsAndHashCode
|
||||
public class ObjectTarget implements Comparable<ObjectTarget> {
|
||||
@Input
|
||||
String owner
|
||||
|
||||
@Input
|
||||
String name
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
String desc
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
if (desc == null)
|
||||
return owner + '.' + name
|
||||
return owner + '.' + name + desc
|
||||
}
|
||||
|
||||
@Override
|
||||
int compareTo(ObjectTarget o) {
|
||||
return toString().compareTo(o.toString())
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
import java.io.File
|
||||
@@ -16,14 +17,29 @@ public class Util {
|
||||
}
|
||||
return md.digest().collect {String.format "%02x", it}.join()
|
||||
}
|
||||
File.metaClass.getSha1 = { !delegate.exists() ? null : delegate.sha1() }
|
||||
|
||||
File.metaClass.json = { -> new JsonSlurper().parseText(delegate.text) }
|
||||
File.metaClass.getJson = { return delegate.exists() ? new JsonSlurper().parse(delegate) : [:] }
|
||||
File.metaClass.setJson = { json -> delegate.text = new JsonBuilder(json).toPrettyString() }
|
||||
|
||||
Date.metaClass.iso8601 = { ->
|
||||
def format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
def result = format.format(delegate)
|
||||
return result[0..21] + ':' + result[22..-1]
|
||||
}
|
||||
|
||||
String.metaClass.rsplit = { String del, int limit = -1 ->
|
||||
def lst = new ArrayList()
|
||||
def x = 0, idx
|
||||
def tmp = delegate
|
||||
while ((idx = tmp.lastIndexOf(del)) != -1 && (limit == -1 || x++ < limit)) {
|
||||
lst.add(0, tmp.substring(idx + del.length(), tmp.length()))
|
||||
tmp = tmp.substring(0, idx)
|
||||
}
|
||||
lst.add(0, tmp)
|
||||
return lst
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] getClasspath(project, libs, artifact) {
|
||||
@@ -56,14 +72,15 @@ public class Util {
|
||||
def path = "${folder}${filename}"
|
||||
def url = "https://libraries.minecraft.net/${path}"
|
||||
if (!checkExists(url)) {
|
||||
url = "https://files.minecraftforge.net/maven/${path}"
|
||||
url = "https://maven.minecraftforge.net/${path}"
|
||||
}
|
||||
//TODO remove when Mojang launcher is updated
|
||||
if (!classifiers && art.classifier != null) { //Mojang launcher doesn't currently support classifiers, so... move it to part of the version, and force the extension to 'jar'
|
||||
if (!classifiers && art.classifier != null) {
|
||||
//Mojang launcher doesn't currently support classifiers, so... move it to part of the version, and force the extension to 'jar'
|
||||
// However, keep the path normal so that our mirror system works.
|
||||
art.version = "${art.version}-${art.classifier}"
|
||||
art.classifier = null
|
||||
art.extension = 'jar'
|
||||
path = "${art.group.replace('.', '/')}/${art.name}/${art.version}/${art.name}-${art.version}.jar"
|
||||
}
|
||||
ret[key] = [
|
||||
name: "${art.group}:${art.name}:${art.version}" + (art.classifier == null ? '' : ":${art.classifier}") + (art.extension == 'jar' ? '' : "@${art.extension}"),
|
||||
@@ -79,6 +96,17 @@ public class Util {
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
public static def getMavenPath(task) {
|
||||
def classifier = task.archiveClassifier.get()
|
||||
def dep = "${task.project.group}:${task.project.name}:${task.project.version}" + (classifier == '' ? '' : ':' + classifier)
|
||||
return "${task.project.group.replace('.', '/')}/${task.project.name}/${task.project.version}/${task.project.name}-${task.project.version}".toString() + (classifier == '' ? '' : '-' + classifier) + '.jar'
|
||||
}
|
||||
|
||||
public static def getMavenDep(task) {
|
||||
def classifier = task.archiveClassifier.get()
|
||||
return "${task.project.group}:${task.project.name}:${task.project.version}" + (classifier == '' ? '' : ':' + classifier)
|
||||
}
|
||||
|
||||
public static def iso8601Now() { new Date().iso8601() }
|
||||
|
||||
|
||||
@@ -15,8 +15,4 @@ Contributor License Agreement
|
||||
- You grant Forge a license to use your code contributed to the primary codebase (everything **not** under patches) in Forge, under the LGPLv2.1 license.
|
||||
- You assign copyright ownership of your contributions to the patches codebase (everything under patches) to Forge, where it will be licensed under the LGPLv2.1 license.
|
||||
|
||||
Additionally, while 1.9.4 is being maintained, you will be asked to acknowledge these two additional clauses.
|
||||
- You grant Forge a license to use your code contributed to the primary codebase (everything **not** under patches) in Forge, under the MinecraftForge license.
|
||||
- You grant assign copyright ownership of your contributions to the patches codebase (everything under patches) to Forge, where it will be licensed under the MinecraftForge license.
|
||||
|
||||
"Forge" is Forge Development LLC, a legally incorporated entity in Oregon, USA.
|
||||
+5
-5
@@ -2,16 +2,16 @@
|
||||
|
||||
MinecraftForge
|
||||
=============
|
||||
[](https://files.minecraftforge.net)
|
||||
[](https://files.minecraftforge.net)
|
||||
[](https://files.minecraftforge.net) [](https://discord.gg/UvedJ9m) [](https://www.patreon.com/LexManos)
|
||||
|
||||
Forge is a free, open-source modding API all of your favourite mods use!
|
||||
|
||||
| Version | Support |
|
||||
| Version | Support |
|
||||
| ------------- | ------------- |
|
||||
| 1.16.x | Active |
|
||||
| 1.15.x | LTS |
|
||||
| 1.17.x | Active |
|
||||
| 1.16.x | LTS |
|
||||
|
||||
* [Download]
|
||||
* [Forum]
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
plugins {
|
||||
id 'com.github.ben-manes.versions'
|
||||
id 'org.javamodularity.moduleplugin' version '1.8.3' apply false
|
||||
}
|
||||
apply plugin: 'java-library'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: 'org.javamodularity.moduleplugin'
|
||||
|
||||
dependencyUpdates.rejectVersionIf { isNonStable(it.candidate.version) }
|
||||
|
||||
dependencies {
|
||||
compileOnly('org.jetbrains:annotations:21.0.1')
|
||||
implementation(project(':fmlloader'))
|
||||
api('net.minecraftforge:eventbus:5.0.+')
|
||||
implementation('commons-io:commons-io:2.5')
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
archiveClassifier = 'sources'
|
||||
from sourceSets.main.allSource
|
||||
}
|
||||
|
||||
ext {
|
||||
MANIFESTS = [
|
||||
'': [
|
||||
'FMLModType': 'LIBRARY',
|
||||
'Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||
'Git-Commit': GIT_INFO.abbreviatedId,
|
||||
'Git-Branch': GIT_INFO.branch,
|
||||
'Build-Number': "${System.getenv('BUILD_NUMBER')?:0}"
|
||||
] as LinkedHashMap,
|
||||
'net/minecraftforge/fml/loading/': [
|
||||
'Specification-Title': 'FMLLoader',
|
||||
'Specification-Vendor': 'Forge Development LLC',
|
||||
'Specification-Version': '1',
|
||||
'Implementation-Title': 'FML Loader',
|
||||
'Implementation-Version': '1.0',
|
||||
'Implementation-Vendor': 'Forge'
|
||||
] as LinkedHashMap
|
||||
]
|
||||
}
|
||||
|
||||
jar.doFirst {
|
||||
MANIFESTS.each { pkg, values ->
|
||||
if (pkg == '')
|
||||
manifest.attributes(values)
|
||||
else
|
||||
manifest.attributes(values, pkg)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs << '-Xlint:unchecked'
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives jar
|
||||
archives sourcesJar
|
||||
}
|
||||
|
||||
publishing.publications.mavenJava(MavenPublication) {
|
||||
from components.java
|
||||
artifact sourcesJar
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.config.IConfigEvent;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class Bindings {
|
||||
private static final Bindings INSTANCE = new Bindings();
|
||||
|
||||
private final IBindingsProvider provider;
|
||||
|
||||
private Bindings() {
|
||||
final var providers = ServiceLoaderUtils.streamServiceLoader(()->ServiceLoader.load(FMLLoader.getGameLayer(), IBindingsProvider.class), sce->{}).toList();
|
||||
if (providers.size() != 1) {
|
||||
throw new IllegalStateException("Could not find bindings provider");
|
||||
}
|
||||
this.provider = providers.get(0);
|
||||
}
|
||||
|
||||
public static Supplier<IEventBus> getForgeBus() {
|
||||
return INSTANCE.provider.getForgeBusSupplier();
|
||||
}
|
||||
|
||||
public static Supplier<I18NParser> getMessageParser() {
|
||||
return INSTANCE.provider.getMessageParser();
|
||||
}
|
||||
|
||||
public static Supplier<IConfigEvent.ConfigConfig> getConfigConfiguration() {
|
||||
return INSTANCE.provider.getConfigConfiguration();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class CrashReportCallables {
|
||||
private static final List<ISystemReportExtender> crashCallables = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
public static void registerCrashCallable(ISystemReportExtender callable)
|
||||
{
|
||||
crashCallables.add(callable);
|
||||
}
|
||||
|
||||
public static void registerCrashCallable(String headerName, Supplier<String> reportGenerator) {
|
||||
registerCrashCallable(new ISystemReportExtender() {
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return headerName;
|
||||
}
|
||||
@Override
|
||||
public String get() {
|
||||
return reportGenerator.get();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static List<ISystemReportExtender> allCrashCallables() {
|
||||
return List.copyOf(crashCallables);
|
||||
}
|
||||
}
|
||||
+26
-45
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -21,29 +21,26 @@ package net.minecraftforge.fml;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.minecraftforge.fml.event.lifecycle.ParallelDispatchEvent;
|
||||
import org.apache.commons.lang3.time.StopWatch;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
|
||||
/**
|
||||
* Utility for running code on the main launch thread at the next available
|
||||
* opportunity. There is no guaranteed order that work from various mods will be
|
||||
* run, but your own work will be run sequentially.
|
||||
* <p>
|
||||
* <strong>Use of this class after startup is not possible.</strong> At that
|
||||
* point, {@link IThreadListener} should be used instead.
|
||||
* point, {@code ReentrantBlockableEventLoop} should be used instead.
|
||||
* <p>
|
||||
* Exceptions from tasks will be handled gracefully, causing a mod loading
|
||||
* error. Tasks that take egregiously long times to run will be logged.
|
||||
@@ -52,32 +49,39 @@ public class DeferredWorkQueue
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
private static Map<Class<? extends ParallelDispatchEvent>, DeferredWorkQueue> workQueues = new HashMap<>();
|
||||
private static final Map<ModLoadingStage, DeferredWorkQueue> workQueues = new HashMap<>();
|
||||
|
||||
private final ModLoadingStage modLoadingStage;
|
||||
private final ConcurrentLinkedDeque<TaskInfo> tasks = new ConcurrentLinkedDeque<>();
|
||||
private final ModLoadingStage modLoadingStage;
|
||||
|
||||
public DeferredWorkQueue(final ModLoadingStage modLoadingStage, Class<? extends ParallelDispatchEvent> eventClass) {
|
||||
public DeferredWorkQueue(ModLoadingStage modLoadingStage) {
|
||||
this.modLoadingStage = modLoadingStage;
|
||||
workQueues.put(eventClass, this);
|
||||
workQueues.put(modLoadingStage, this);
|
||||
}
|
||||
|
||||
public static Optional<DeferredWorkQueue> lookup(Optional<Class<? extends ParallelDispatchEvent>> parallelClass) {
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public static Optional<DeferredWorkQueue> lookup(Optional<ModLoadingStage> parallelClass) {
|
||||
return Optional.ofNullable(workQueues.get(parallelClass.orElse(null)));
|
||||
}
|
||||
|
||||
void runTasks() {
|
||||
public void runTasks() {
|
||||
if (tasks.isEmpty()) return;
|
||||
LOGGER.debug(LOADING, "Dispatching synchronous work after {}: {} jobs", modLoadingStage, tasks.size());
|
||||
StopWatch globalTimer = StopWatch.createStarted();
|
||||
LOGGER.debug(LOADING, "Dispatching synchronous work for work queue {}: {} jobs", modLoadingStage, tasks.size());
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
tasks.forEach(t->makeRunnable(t, Runnable::run));
|
||||
LOGGER.debug(LOADING, "Synchronous work queue completed in {}", globalTimer);
|
||||
timer.stop();
|
||||
LOGGER.debug(LOADING, "Synchronous work queue completed in {}", timer);
|
||||
}
|
||||
|
||||
private static void makeRunnable(TaskInfo ti, Executor executor) {
|
||||
executor.execute(() -> {
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
ti.task.run();
|
||||
ModLoadingContext.get().setActiveContainer(ti.owner);
|
||||
try {
|
||||
ti.task.run();
|
||||
} finally {
|
||||
ModLoadingContext.get().setActiveContainer(null);
|
||||
}
|
||||
timer.stop();
|
||||
if (timer.elapsed(TimeUnit.SECONDS) >= 1) {
|
||||
LOGGER.warn(LOADING, "Mod '{}' took {} to run a deferred task.", ti.owner.getModId(), timer);
|
||||
@@ -85,36 +89,13 @@ public class DeferredWorkQueue
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> enqueueWork(final IModInfo modInfo, final Runnable work) {
|
||||
public CompletableFuture<Void> enqueueWork(final ModContainer modInfo, final Runnable work) {
|
||||
return CompletableFuture.runAsync(work, r->tasks.add(new TaskInfo(modInfo, r)));
|
||||
}
|
||||
|
||||
public <T> CompletableFuture<T> enqueueWork(final IModInfo modInfo, final Supplier<T> work) {
|
||||
public <T> CompletableFuture<T> enqueueWork(final ModContainer modInfo, final Supplier<T> work) {
|
||||
return CompletableFuture.supplyAsync(work, r->tasks.add(new TaskInfo(modInfo, r)));
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED FOR REMOVAL. Use {@link ParallelDispatchEvent#enqueueWork(Runnable)} or {@link ParallelDispatchEvent#enqueueWork(Supplier)}
|
||||
*
|
||||
* @param workToEnqueue Runnable to execute later
|
||||
* @return a completable future
|
||||
*/
|
||||
@Deprecated
|
||||
public static CompletableFuture<Void> runLater(Runnable workToEnqueue) {
|
||||
return
|
||||
Optional.ofNullable(ModLoadingContext.get().getActiveContainer().modLoadingStage.getDeferredWorkQueue())
|
||||
.map(wq->wq.enqueueWork(ModLoadingContext.get().getActiveContainer().modInfo, workToEnqueue))
|
||||
.orElseGet(()->CompletableFuture.completedFuture(null));
|
||||
}
|
||||
|
||||
static class TaskInfo
|
||||
{
|
||||
public final IModInfo owner;
|
||||
public final Runnable task;
|
||||
|
||||
private TaskInfo(IModInfo owner, Runnable task) {
|
||||
this.owner = owner;
|
||||
this.task = task;
|
||||
}
|
||||
}
|
||||
record TaskInfo(ModContainer owner, Runnable task) {}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -46,7 +46,7 @@ public final class DistExecutor
|
||||
private DistExecutor() {}
|
||||
|
||||
/**
|
||||
* Run the callable in the supplier only on the specified {@link Side}.
|
||||
* Run the callable in the supplier only on the specified {@link Dist}.
|
||||
* This method is NOT sided-safe and special care needs to be taken in code using this method that implicit class
|
||||
* loading is not triggered by the Callable.
|
||||
*
|
||||
@@ -0,0 +1,6 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
public interface I18NParser {
|
||||
String parseMessage(String i18nMessage, Object... args);
|
||||
String stripControlCodes(String toStrip);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.config.IConfigEvent;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface IBindingsProvider {
|
||||
Supplier<IEventBus> getForgeBusSupplier();
|
||||
Supplier<I18NParser> getMessageParser();
|
||||
Supplier<IConfigEvent.ConfigConfig> getConfigConfiguration();
|
||||
}
|
||||
Whitespace-only changes.
+14
-30
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -19,60 +19,44 @@
|
||||
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.resources.IResourcePack;
|
||||
import net.minecraftforge.fml.packs.ModFileResourcePack;
|
||||
|
||||
public class ExtensionPoint<T>
|
||||
public interface IExtensionPoint<T extends Record>
|
||||
{
|
||||
public static final ExtensionPoint<BiFunction<Minecraft, Screen, Screen>> CONFIGGUIFACTORY = new ExtensionPoint<>();
|
||||
public static final ExtensionPoint<BiFunction<Minecraft, ModFileResourcePack, IResourcePack>> RESOURCEPACK = new ExtensionPoint<>();
|
||||
/**
|
||||
* Compatibility display test for the mod.
|
||||
* Used for displaying compatibility with remote servers with the same mod, and on disk saves.
|
||||
*
|
||||
* The supplier provides my "local" version for sending across the network or writing to disk
|
||||
* The predicate tests the version from a remote instance or save for acceptability (Boolean is true for network, false for local save)
|
||||
* The supplier provides my "local" version for sending across the impl or writing to disk
|
||||
* The predicate tests the version from a remote instance or save for acceptability (Boolean is true for impl, false for local save)
|
||||
* and returns true if the version is compatible.
|
||||
*
|
||||
* <p>Return {@link net.minecraftforge.fml.network.FMLNetworkConstants#IGNORESERVERONLY} in the supplier, if you wish to be ignored
|
||||
* <p>Return {@code net.minecraftforge.impl.impl.FMLNetworkConstants#IGNORESERVERONLY} in the supplier, if you wish to be ignored
|
||||
* as a server side only mod.</p>
|
||||
* <p>Return true in the predicate for all values of the input string (when network boolean is true) if you are client side,
|
||||
* <p>Return true in the predicate for all values of the input string (when impl boolean is true) if you are client side,
|
||||
* and don't care about matching any potential server version.</p>
|
||||
*
|
||||
* <p>
|
||||
* Examples: A server only mod
|
||||
*
|
||||
* <code><pre>
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* registerExtensionPoint(DISPLAYTEST, ()->Pair.of(
|
||||
* ()->FMLNetworkConstants.IGNORESERVERONLY, // ignore me, I'm a server only mod
|
||||
* (s,b)->true // i accept anything from the server or the save, if I'm asked
|
||||
* )
|
||||
* </pre></code>
|
||||
* </p>
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Examples: A client only mod
|
||||
* <code><pre>
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* registerExtensionPoint(DISPLAYTEST, ()->Pair.of(
|
||||
* ()->"anything. i don't care", // if i'm actually on the server, this string is sent but i'm a client only mod, so it won't be
|
||||
* (remoteversionstring,networkbool)->networkbool // i accept anything from the server, by returning true if it's asking about the server
|
||||
* )
|
||||
* </pre></code>
|
||||
* </p>
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
public static final ExtensionPoint<Pair<Supplier<String>, BiPredicate<String, Boolean>>> DISPLAYTEST = new ExtensionPoint<>();
|
||||
|
||||
private Class<T> type;
|
||||
|
||||
private ExtensionPoint() {
|
||||
}
|
||||
|
||||
record DisplayTest(Supplier<String> suppliedVersion, BiPredicate<String, Boolean> remoteVersionTest) implements IExtensionPoint<DisplayTest> {}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.event.IModBusEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface IModLoadingState {
|
||||
String name();
|
||||
String previous();
|
||||
ModLoadingPhase phase();
|
||||
Function<ModList, String> message();
|
||||
Optional<Consumer<ModList>> inlineRunnable();
|
||||
|
||||
default <T extends Event & IModBusEvent> Optional<CompletableFuture<List<Throwable>>> buildTransition(final Executor syncExecutor, final Executor parallelExecutor) {
|
||||
return buildTransition(syncExecutor, parallelExecutor, e->CompletableFuture.runAsync(()->{}, e), e->CompletableFuture.runAsync(()->{}, e));
|
||||
}
|
||||
|
||||
<T extends Event & IModBusEvent> Optional<CompletableFuture<List<Throwable>>> buildTransition(Executor syncExecutor, Executor parallelExecutor, Function<Executor, CompletableFuture<Void>> preSyncTask, Function<Executor, CompletableFuture<Void>> postSyncTask);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IModStateProvider {
|
||||
List<IModLoadingState> getAllStates();
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.event.IModBusEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public interface IModStateTransition {
|
||||
static IModStateTransition buildNoopTransition() {
|
||||
return new NoopTransition();
|
||||
}
|
||||
|
||||
default <T extends Event & IModBusEvent> CompletableFuture<List<Throwable>> build(Executor syncExecutor, Executor parallelExecutor, Function<Executor, CompletableFuture<Void>> preSyncTask, Function<Executor, CompletableFuture<Void>> postSyncTask) {
|
||||
List<CompletableFuture<List<Throwable>>> cfs = new ArrayList<>();
|
||||
this.eventFunctionStream().get()
|
||||
.map(f->(EventGenerator<T>)f)
|
||||
.reduce((head, tail)-> addCompletableFutureTaskForModDispatch(syncExecutor, parallelExecutor, cfs, head, ModLoadingStage::currentState, tail))
|
||||
.ifPresent(last-> addCompletableFutureTaskForModDispatch(syncExecutor, parallelExecutor, cfs, last, nextModLoadingStage(), null));
|
||||
final CompletableFuture<Void> preSyncTaskCF = preSyncTask.apply(syncExecutor);
|
||||
final CompletableFuture<List<Throwable>> eventDispatchCF = ModList.gather(cfs).thenCompose(ModList::completableFutureFromExceptionList);
|
||||
final CompletableFuture<List<Throwable>> postEventDispatchCF = preSyncTaskCF.thenComposeAsync(n -> eventDispatchCF, parallelExecutor).thenApply(r -> {
|
||||
postSyncTask.apply(syncExecutor);
|
||||
return r;
|
||||
});
|
||||
return this.finalActivityGenerator().apply(syncExecutor, postEventDispatchCF);
|
||||
}
|
||||
|
||||
default BiFunction<ModLoadingStage, Throwable, ModLoadingStage> nextModLoadingStage() {
|
||||
return ModLoadingStage::nextState;
|
||||
}
|
||||
|
||||
private <T extends Event & IModBusEvent> EventGenerator<T> addCompletableFutureTaskForModDispatch(final Executor syncExecutor, final Executor parallelExecutor, final List<CompletableFuture<List<Throwable>>> completeableFutures, final EventGenerator<T> eventGenerator, BiFunction<ModLoadingStage, Throwable, ModLoadingStage> nextState, final EventGenerator<T> nextGenerator) {
|
||||
completeableFutures.add(((BiFunction<Executor, EventGenerator<T>, CompletableFuture<List<Throwable>>>)preDispatchHook()).apply(threadSelector().apply(syncExecutor, parallelExecutor), eventGenerator));
|
||||
completeableFutures.add(ModList.get().futureVisitor(eventGenerator, nextState).apply(threadSelector().apply(syncExecutor, parallelExecutor)));
|
||||
completeableFutures.add(((BiFunction<Executor, EventGenerator<T>, CompletableFuture<List<Throwable>>>)postDispatchHook()).apply(threadSelector().apply(syncExecutor, parallelExecutor), eventGenerator));
|
||||
return nextGenerator;
|
||||
}
|
||||
|
||||
Supplier<Stream<EventGenerator<?>>> eventFunctionStream();
|
||||
ThreadSelector threadSelector();
|
||||
BiFunction<Executor, CompletableFuture<List<Throwable>>, CompletableFuture<List<Throwable>>> finalActivityGenerator();
|
||||
BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<List<Throwable>>> preDispatchHook();
|
||||
BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<List<Throwable>>> postDispatchHook();
|
||||
|
||||
interface EventGenerator<T extends Event & IModBusEvent> extends Function<ModContainer, T> {
|
||||
static <FN extends Event & IModBusEvent> EventGenerator<FN> fromFunction(Function<ModContainer, FN> fn) {
|
||||
return fn::apply;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
record NoopTransition() implements IModStateTransition {
|
||||
|
||||
@Override
|
||||
public Supplier<Stream<EventGenerator<?>>> eventFunctionStream() {
|
||||
return Stream::of;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreadSelector threadSelector() {
|
||||
return ThreadSelector.SYNC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiFunction<Executor, CompletableFuture<List<Throwable>>, CompletableFuture<List<Throwable>>> finalActivityGenerator() {
|
||||
return (e, t) -> t.thenApplyAsync(Function.identity(), e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<List<Throwable>>> preDispatchHook() {
|
||||
return (t, f)-> CompletableFuture.completedFuture(Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<List<Throwable>>> postDispatchHook() {
|
||||
return (t, f)-> CompletableFuture.completedFuture(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,11 +17,11 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.common;
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import net.minecraft.crash.ICrashReportDetail;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface ICrashCallable extends ICrashReportDetail<String>
|
||||
public interface ISystemReportExtender extends Supplier<String>
|
||||
{
|
||||
String getLabel();
|
||||
}
|
||||
+11
-15
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -33,38 +33,32 @@ import java.util.stream.StreamSupport;
|
||||
|
||||
public class InterModComms
|
||||
{
|
||||
public static final class IMCMessage {
|
||||
private final String modId;
|
||||
private final String method;
|
||||
private final String senderModId;
|
||||
private final Supplier<?> thing;
|
||||
|
||||
IMCMessage(String senderModId, String modId, String method, Supplier<?> thing)
|
||||
{
|
||||
this.senderModId = senderModId;
|
||||
this.modId = modId;
|
||||
this.method = method;
|
||||
this.thing = thing;
|
||||
}
|
||||
public record IMCMessage(String senderModId, String modId, String method, Supplier<?> messageSupplier) {
|
||||
|
||||
/**
|
||||
* Deprecated: use {@link #senderModId()}
|
||||
* @return The modid of the sender. This is supplied by the caller, or by the active mod container context.
|
||||
* Consider it unreliable.
|
||||
*/
|
||||
@Deprecated
|
||||
public final String getSenderModId() {
|
||||
return this.senderModId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated: use {@link #modId()}
|
||||
* @return The modid being sent to.
|
||||
*/
|
||||
@Deprecated
|
||||
public final String getModId() {
|
||||
return this.modId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated: use {@link #method()}
|
||||
* @return The method being sent to.
|
||||
*/
|
||||
@Deprecated
|
||||
public final String getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
@@ -72,10 +66,12 @@ public class InterModComms
|
||||
/**
|
||||
* @param <T> The type of the message.
|
||||
* @return A {@link Supplier} of the message.
|
||||
* Use {@link #messageSupplier()}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
public final <T> Supplier<T> getMessageSupplier() {
|
||||
return (Supplier<T>)this.thing;
|
||||
return (Supplier<T>) this.messageSupplier;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -31,6 +31,7 @@ public class Logging
|
||||
public static final Marker SPLASH = MarkerManager.getMarker("SPLASH");
|
||||
public static final Marker CAPABILITIES = MarkerManager.getMarker("CAPABILITIES");
|
||||
public static final Marker MODELLOADING = MarkerManager.getMarker("MODELLOADING");
|
||||
public static final Marker FORGEMOD = MarkerManager.getMarker("FORGEMOD").addParents(LOADING);
|
||||
|
||||
// --log CORE:+DEBUG,SCAN:-OFF
|
||||
// forge log debug 5
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+12
-15
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -20,10 +20,10 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.config.IConfigEvent;
|
||||
import net.minecraftforge.fml.config.ModConfig;
|
||||
import net.minecraftforge.fml.event.lifecycle.IModBusEvent;
|
||||
import net.minecraftforge.fml.event.IModBusEvent;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
@@ -58,10 +58,10 @@ public abstract class ModContainer
|
||||
protected ModLoadingStage modLoadingStage;
|
||||
protected Supplier<?> contextExtension;
|
||||
protected final Map<ModLoadingStage, Runnable> activityMap = new HashMap<>();
|
||||
protected final Map<ExtensionPoint, Supplier<?>> extensionPoints = new IdentityHashMap<>();
|
||||
protected final Map<Class<? extends IExtensionPoint<?>>, Supplier<?>> extensionPoints = new IdentityHashMap<>();
|
||||
protected final EnumMap<ModConfig.Type, ModConfig> configs = new EnumMap<>(ModConfig.Type.class);
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
protected Optional<Consumer<ModConfig.ModConfigEvent>> configHandler = Optional.empty();
|
||||
protected Optional<Consumer<IConfigEvent>> configHandler = Optional.empty();
|
||||
|
||||
public ModContainer(IModInfo info)
|
||||
{
|
||||
@@ -71,7 +71,7 @@ public abstract class ModContainer
|
||||
this.modInfo = info;
|
||||
this.modLoadingStage = ModLoadingStage.CONSTRUCT;
|
||||
// default displaytest extension checks for version string match
|
||||
registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(()->this.modInfo.getVersion().toString(),
|
||||
registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(()->this.modInfo.getVersion().toString(),
|
||||
(incoming, isNetwork)->Objects.equals(incoming, this.modInfo.getVersion().toString())));
|
||||
}
|
||||
|
||||
@@ -111,35 +111,32 @@ public abstract class ModContainer
|
||||
|
||||
public static <T extends Event & IModBusEvent> CompletableFuture<Void> buildTransitionHandler(
|
||||
final ModContainer target,
|
||||
final ModLoadingStage.EventGenerator<T> eventGenerator,
|
||||
final IModStateTransition.EventGenerator<T> eventGenerator,
|
||||
final BiFunction<ModLoadingStage, Throwable, ModLoadingStage> stateChangeHandler,
|
||||
final Executor executor) {
|
||||
return CompletableFuture
|
||||
.runAsync(() -> {
|
||||
ModLoadingContext.get().setActiveContainer(target, target.contextExtension.get());
|
||||
ModLoadingContext.get().setActiveContainer(target);
|
||||
target.activityMap.getOrDefault(target.modLoadingStage, ()->{}).run();
|
||||
target.acceptEvent(eventGenerator.apply(target));
|
||||
}, executor)
|
||||
.whenComplete((mc, exception) -> {
|
||||
target.modLoadingStage = stateChangeHandler.apply(target.modLoadingStage, exception);
|
||||
ModLoadingContext.get().setActiveContainer(null, null);
|
||||
ModLoadingContext.get().setActiveContainer(null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the modinfo used to create this mod instance
|
||||
*/
|
||||
public IModInfo getModInfo()
|
||||
{
|
||||
return modInfo;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Optional<T> getCustomExtension(ExtensionPoint<T> point) {
|
||||
public <T extends Record> Optional<T> getCustomExtension(Class<? extends IExtensionPoint<T>> point) {
|
||||
return Optional.ofNullable((T)extensionPoints.getOrDefault(point,()-> null).get());
|
||||
}
|
||||
|
||||
public <T> void registerExtensionPoint(ExtensionPoint<T> point, Supplier<T> extension)
|
||||
public <T extends Record & IExtensionPoint<T>> void registerExtensionPoint(Class<? extends IExtensionPoint<T>> point, Supplier<T> extension)
|
||||
{
|
||||
extensionPoints.put(point, extension);
|
||||
}
|
||||
@@ -148,7 +145,7 @@ public abstract class ModContainer
|
||||
configs.put(modConfig.getType(), modConfig);
|
||||
}
|
||||
|
||||
public void dispatchConfigEvent(ModConfig.ModConfigEvent event) {
|
||||
public void dispatchConfigEvent(IConfigEvent event) {
|
||||
configHandler.ifPresent(configHandler->configHandler.accept(event));
|
||||
}
|
||||
|
||||
+23
-19
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2022.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -20,11 +20,14 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.event.lifecycle.IModBusEvent;
|
||||
import net.minecraftforge.fml.event.IModBusEvent;
|
||||
import net.minecraftforge.forgespi.language.IModFileInfo;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import net.minecraftforge.forgespi.language.ModFileScanData;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -34,6 +37,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@@ -58,8 +62,8 @@ public class ModList
|
||||
{
|
||||
private static Logger LOGGER = LogManager.getLogger();
|
||||
private static ModList INSTANCE;
|
||||
private final List<ModFileInfo> modFiles;
|
||||
private final List<ModInfo> sortedList;
|
||||
private final List<IModFileInfo> modFiles;
|
||||
private final List<IModInfo> sortedList;
|
||||
private final Map<String, ModFileInfo> fileById;
|
||||
private List<ModContainer> mods;
|
||||
private Map<String, ModContainer> indexedMods;
|
||||
@@ -71,18 +75,18 @@ public class ModList
|
||||
this.sortedList = sortedList.stream().
|
||||
map(ModInfo.class::cast).
|
||||
collect(Collectors.toList());
|
||||
this.fileById = this.modFiles.stream().map(ModFileInfo::getMods).flatMap(Collection::stream).
|
||||
this.fileById = this.modFiles.stream().map(IModFileInfo::getMods).flatMap(Collection::stream).
|
||||
map(ModInfo.class::cast).
|
||||
collect(Collectors.toMap(ModInfo::getModId, ModInfo::getOwningFile));
|
||||
CrashReportExtender.registerCrashCallable("Mod List", this::crashReport);
|
||||
CrashReportCallables.registerCrashCallable("Mod List", this::crashReport);
|
||||
}
|
||||
|
||||
private String getModContainerState(String modId) {
|
||||
return getModContainerById(modId).map(ModContainer::getCurrentState).map(Object::toString).orElse("NONE");
|
||||
}
|
||||
|
||||
private String fileToLine(ModFile mf) {
|
||||
return String.format("%-50.50s|%-30.30s|%-30.30s|%-20.20s|%-10.10s|%s", mf.getFileName(),
|
||||
private String fileToLine(IModFile mf) {
|
||||
return String.format(Locale.ENGLISH, "%-50.50s|%-30.30s|%-30.30s|%-20.20s|%-10.10s|Manifest: %s", mf.getFileName(),
|
||||
mf.getModInfos().get(0).getDisplayName(),
|
||||
mf.getModInfos().get(0).getModId(),
|
||||
mf.getModInfos().get(0).getVersion(),
|
||||
@@ -111,18 +115,18 @@ public class ModList
|
||||
return thread;
|
||||
}
|
||||
|
||||
public List<ModFileInfo> getModFiles()
|
||||
public List<IModFileInfo> getModFiles()
|
||||
{
|
||||
return modFiles;
|
||||
}
|
||||
|
||||
public ModFileInfo getModFileById(String modid)
|
||||
public IModFileInfo getModFileById(String modid)
|
||||
{
|
||||
return this.fileById.get(modid);
|
||||
}
|
||||
|
||||
<T extends Event & IModBusEvent> Function<Executor, CompletableFuture<List<Throwable>>> futureVisitor(
|
||||
final ModLoadingStage.EventGenerator<T> eventGenerator,
|
||||
final IModStateTransition.EventGenerator<T> eventGenerator,
|
||||
final BiFunction<ModLoadingStage, Throwable, ModLoadingStage> stateChange) {
|
||||
return executor -> gather(
|
||||
this.mods.stream()
|
||||
@@ -185,7 +189,7 @@ public class ModList
|
||||
return mods.stream().filter(mc -> mc.getMod() == obj).findFirst();
|
||||
}
|
||||
|
||||
public List<ModInfo> getMods()
|
||||
public List<IModInfo> getMods()
|
||||
{
|
||||
return this.sortedList;
|
||||
}
|
||||
@@ -205,24 +209,24 @@ public class ModList
|
||||
if (modFileScanData == null)
|
||||
{
|
||||
modFileScanData = this.sortedList.stream().
|
||||
map(ModInfo::getOwningFile).
|
||||
map(IModInfo::getOwningFile).
|
||||
filter(Objects::nonNull).
|
||||
map(ModFileInfo::getFile).
|
||||
map(IModFileInfo::getFile).
|
||||
distinct().
|
||||
map(ModFile::getScanResult).
|
||||
map(IModFile::getScanResult).
|
||||
collect(Collectors.toList());
|
||||
}
|
||||
return modFileScanData;
|
||||
|
||||
}
|
||||
|
||||
public void forEachModFile(Consumer<ModFile> fileConsumer)
|
||||
public void forEachModFile(Consumer<IModFile> fileConsumer)
|
||||
{
|
||||
modFiles.stream().map(ModFileInfo::getFile).forEach(fileConsumer);
|
||||
modFiles.stream().map(IModFileInfo::getFile).forEach(fileConsumer);
|
||||
}
|
||||
|
||||
public <T> Stream<T> applyForEachModFile(Function<ModFile, T> function) {
|
||||
return modFiles.stream().map(ModFileInfo::getFile).map(function);
|
||||
public <T> Stream<T> applyForEachModFile(Function<IModFile, T> function) {
|
||||
return modFiles.stream().map(IModFileInfo::getFile).map(function);
|
||||
}
|
||||
|
||||
public void forEachModContainer(BiConsumer<String, ModContainer> modContainerConsumer) {
|
||||
+65
-93
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -20,32 +20,25 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import cpw.mods.modlauncher.TransformingClassLoader;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.config.ConfigTracker;
|
||||
import net.minecraftforge.fml.config.ModConfig;
|
||||
import net.minecraftforge.fml.event.lifecycle.IModBusEvent;
|
||||
import net.minecraftforge.fml.event.IModBusEvent;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.loading.FMLPaths;
|
||||
import net.minecraftforge.fml.loading.LoadingModList;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.InvalidModIdentifier;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
|
||||
import net.minecraftforge.fml.network.FMLNetworkConstants;
|
||||
import net.minecraftforge.fml.network.NetworkRegistry;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import net.minecraftforge.forgespi.language.IModLanguageProvider;
|
||||
import net.minecraftforge.registries.GameData;
|
||||
import net.minecraftforge.registries.ObjectHolderRegistry;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -59,7 +52,7 @@ import static net.minecraftforge.fml.Logging.LOADING;
|
||||
/**
|
||||
* Loads mods.
|
||||
*
|
||||
* Dispatch cycle is seen in {@link #loadMods()} and {@link #finishMods()}
|
||||
* Dispatch cycle is seen in {@code #loadMods()} and {@code #finishMods()}
|
||||
*
|
||||
* Overall sequence for loadMods is:
|
||||
* <dl>
|
||||
@@ -67,28 +60,28 @@ import static net.minecraftforge.fml.Logging.LOADING;
|
||||
* <dd>Constructs the mod instance. Mods can typically setup basic environment such as Event listeners
|
||||
* and Configuration specifications here.</dd>
|
||||
* <dt>Automated dispatches</dt>
|
||||
* <dd>Dispatches automated elements : {@link net.minecraftforge.fml.common.Mod.EventBusSubscriber},
|
||||
* {@link net.minecraftforge.event.RegistryEvent}, {@link net.minecraftforge.common.capabilities.CapabilityInject}
|
||||
* <dd>Dispatches automated elements : {@code net.minecraftforge.fml.common.Mod.EventBusSubscriber},
|
||||
* {@code net.minecraftforge.event.RegistryEvent}, {@code net.minecraftforge.common.capabilities.CapabilityInject}
|
||||
* and others</dd>
|
||||
* <dt>CONFIG_LOAD</dt>
|
||||
* <dd>Dispatches ConfigLoadEvent to mods</dd>
|
||||
* <dt>COMMON_SETUP</dt>
|
||||
* <dd>Dispatches {@link net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent} to mods</dd>
|
||||
* <dd>Dispatches {@code net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent} to mods</dd>
|
||||
* <dt>SIDED_SETUP</dt>
|
||||
* <dd>Dispatches {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent} or
|
||||
* {@link net.minecraftforge.fml.event.lifecycle.FMLDedicatedServerSetupEvent} to mods</dd>
|
||||
* <dd>Dispatches {@code net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent} or
|
||||
* {@code net.minecraftforge.fml.event.lifecycle.FMLDedicatedServerSetupEvent} to mods</dd>
|
||||
* </dl>
|
||||
*
|
||||
* Overall sequence for finishMods is:
|
||||
* <dl>
|
||||
* <dt>ENQUEUE_IMC</dt>
|
||||
* <dd>Dispatches {@link net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent} to mods,
|
||||
* <dd>Dispatches {@code net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent} to mods,
|
||||
* for enqueuing {@link InterModComms} messages for other mods to receive subsequently</dd>
|
||||
* <dt>PROCESS_IMC</dt>
|
||||
* <dd>Dispatches {@link net.minecraftforge.fml.event.lifecycle.InterModProcessEvent} to mods,
|
||||
* <dd>Dispatches {@code net.minecraftforge.fml.event.lifecycle.InterModProcessEvent} to mods,
|
||||
* for processing {@link InterModComms} messages received from other mods prior to this event</dd>
|
||||
* <dt>COMPLETE</dt>
|
||||
* <dd>Dispatches {@link net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent} to mods,
|
||||
* <dd>Dispatches {@code net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent} to mods,
|
||||
* and completes the mod loading sequence.</dd>
|
||||
* </dl>
|
||||
*/
|
||||
@@ -96,38 +89,37 @@ public class ModLoader
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static ModLoader INSTANCE;
|
||||
private final TransformingClassLoader launchClassLoader;
|
||||
private final LoadingModList loadingModList;
|
||||
|
||||
private final List<ModLoadingException> loadingExceptions;
|
||||
private final List<ModLoadingWarning> loadingWarnings;
|
||||
private final ModStateManager stateManager;
|
||||
private boolean loadingStateValid;
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
private final Optional<Consumer<String>> statusConsumer = StartupMessageManager.modLoaderConsumer();
|
||||
private ModList modList;
|
||||
|
||||
private ModLoader()
|
||||
{
|
||||
INSTANCE = this;
|
||||
this.launchClassLoader = FMLLoader.getLaunchClassLoader();
|
||||
this.loadingModList = FMLLoader.getLoadingModList();
|
||||
this.loadingExceptions = FMLLoader.getLoadingModList().
|
||||
getErrors().stream().flatMap(ModLoadingException::fromEarlyException).collect(Collectors.toList());
|
||||
this.loadingWarnings = FMLLoader.getLoadingModList().
|
||||
getBrokenFiles().stream().map(file -> new ModLoadingWarning(null, ModLoadingStage.VALIDATE,
|
||||
InvalidModIdentifier.identifyJarProblem(file.getFilePath()).orElse("fml.modloading.brokenfile"), file.getFileName())).collect(Collectors.toList());
|
||||
FMLLoader.getLoadingModList()
|
||||
.getModFiles().stream().filter(ModFileInfo::missingLicense) //Search for files with missing licenses
|
||||
this.loadingExceptions = FMLLoader.getLoadingModList().getErrors().stream()
|
||||
.flatMap(ModLoadingException::fromEarlyException)
|
||||
.collect(Collectors.toList());
|
||||
this.loadingWarnings = FMLLoader.getLoadingModList().getBrokenFiles().stream()
|
||||
.map(file -> new ModLoadingWarning(null, ModLoadingStage.VALIDATE, InvalidModIdentifier.identifyJarProblem(file.getFilePath()).orElse("fml.modloading.brokenfile"), file.getFileName()))
|
||||
.collect(Collectors.toList());
|
||||
FMLLoader.getLoadingModList().getModFiles().stream()
|
||||
.filter(ModFileInfo::missingLicense) //Search for files with missing licenses
|
||||
.filter(modFileInfo -> modFileInfo.getMods().stream().noneMatch(thisModInfo -> this.loadingExceptions.stream().map(ModLoadingException::getModInfo).anyMatch(otherInfo -> otherInfo == thisModInfo))) //Ignore files where any other mod already encountered an error
|
||||
.map(modFileInfo -> new ModLoadingException(null, ModLoadingStage.VALIDATE, "fml.modloading.missinglicense", null, modFileInfo.getFile()))
|
||||
.forEach(this.loadingExceptions::add);
|
||||
LOGGER.debug(CORE, "Loading Network data for FML net version: {}", FMLNetworkConstants.init());
|
||||
CrashReportExtender.registerCrashCallable("ModLauncher", FMLLoader::getLauncherInfo);
|
||||
CrashReportExtender.registerCrashCallable("ModLauncher launch target", FMLLoader::launcherHandlerName);
|
||||
CrashReportExtender.registerCrashCallable("ModLauncher naming", FMLLoader::getNaming);
|
||||
CrashReportExtender.registerCrashCallable("ModLauncher services", this::computeModLauncherServiceList);
|
||||
CrashReportExtender.registerCrashCallable("FML", ForgeVersion::getSpec);
|
||||
CrashReportExtender.registerCrashCallable("Forge", ()->ForgeVersion.getGroup()+":"+ForgeVersion.getVersion());
|
||||
CrashReportExtender.registerCrashCallable("FML Language Providers", this::computeLanguageList);
|
||||
this.stateManager = new ModStateManager();
|
||||
CrashReportCallables.registerCrashCallable("ModLauncher", FMLLoader::getLauncherInfo);
|
||||
CrashReportCallables.registerCrashCallable("ModLauncher launch target", FMLLoader::launcherHandlerName);
|
||||
CrashReportCallables.registerCrashCallable("ModLauncher naming", FMLLoader::getNaming);
|
||||
CrashReportCallables.registerCrashCallable("ModLauncher services", this::computeModLauncherServiceList);
|
||||
CrashReportCallables.registerCrashCallable("FML Language Providers", this::computeLanguageList);
|
||||
}
|
||||
|
||||
private String computeLanguageList() {
|
||||
@@ -159,11 +151,7 @@ public class ModLoader
|
||||
statusConsumer.ifPresent(c->c.accept("Waiting for scan to complete"));
|
||||
FMLLoader.backgroundScanHandler.waitForScanToComplete(periodicTask);
|
||||
statusConsumer.ifPresent(c->c.accept("Loading mods"));
|
||||
final ModList modList = ModList.of(loadingModList
|
||||
.getModFiles()
|
||||
.stream()
|
||||
.map(ModFileInfo::getFile)
|
||||
.collect(Collectors.toList()),
|
||||
final ModList modList = ModList.of(loadingModList.getModFiles().stream().map(ModFileInfo::getFile).toList(),
|
||||
loadingModList.getMods());
|
||||
if (!this.loadingExceptions.isEmpty()) {
|
||||
LOGGER.fatal(CORE, "Error during pre-loading phase", loadingExceptions.get(0));
|
||||
@@ -172,11 +160,11 @@ public class ModLoader
|
||||
throw new LoadingFailedException(loadingExceptions);
|
||||
}
|
||||
statusConsumer.ifPresent(c->c.accept("Building Mod List"));
|
||||
final List<ModContainer> modContainers = loadingModList.getModFiles().stream().
|
||||
map(ModFileInfo::getFile).
|
||||
map(mf -> buildMods(mf, launchClassLoader)).
|
||||
flatMap(Collection::stream).
|
||||
collect(Collectors.toList());
|
||||
final List<ModContainer> modContainers = loadingModList.getModFiles().stream()
|
||||
.map(ModFileInfo::getFile)
|
||||
.map(this::buildMods)
|
||||
.<ModContainer>mapMulti(Iterable::forEach)
|
||||
.toList();
|
||||
if (!loadingExceptions.isEmpty()) {
|
||||
LOGGER.fatal(CORE, "Failed to initialize mod containers", loadingExceptions.get(0));
|
||||
modList.setLoadedMods(Collections.emptyList());
|
||||
@@ -184,61 +172,45 @@ public class ModLoader
|
||||
throw new LoadingFailedException(loadingExceptions);
|
||||
}
|
||||
modList.setLoadedMods(modContainers);
|
||||
statusConsumer.ifPresent(c->c.accept(String.format("Constructing %d mods", modList.size())));
|
||||
dispatchAndHandleError(ModLoadingStage.CONSTRUCT, syncExecutor, parallelExecutor, periodicTask);
|
||||
statusConsumer.ifPresent(c->c.accept("Creating registries"));
|
||||
dispatchAndHandleError(ModLoadingStage.CREATE_REGISTRIES, syncExecutor, parallelExecutor, periodicTask);
|
||||
ObjectHolderRegistry.findObjectHolders();
|
||||
CapabilityManager.INSTANCE.injectCapabilities(modList.getAllScanData());
|
||||
statusConsumer.ifPresent(c->c.accept("Adding custom tag types"));
|
||||
GameData.setCustomTagTypesFromRegistries();
|
||||
statusConsumer.ifPresent(c->c.accept("Populating registries"));
|
||||
dispatchAndHandleError(ModLoadingStage.LOAD_REGISTRIES, syncExecutor, parallelExecutor, periodicTask);
|
||||
statusConsumer.ifPresent(c->c.accept("Early mod loading complete"));
|
||||
this.modList = modList;
|
||||
statusConsumer.ifPresent(c->c.accept("Dispatching gathering events"));
|
||||
stateManager.getStates(ModLoadingPhase.GATHER).forEach(mls->dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask));
|
||||
statusConsumer.ifPresent(c->c.accept("Gathering phase complete"));
|
||||
}
|
||||
|
||||
public void loadMods(final ModWorkManager.DrivenExecutor syncExecutor, final Executor parallelExecutor, final Function<Executor, CompletableFuture<Void>> beforeSidedEvent, final Function<Executor, CompletableFuture<Void>> afterSidedEvent, final Runnable periodicTask) {
|
||||
statusConsumer.ifPresent(c->c.accept("Loading mod config"));
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, ()->()-> ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.CLIENT, FMLPaths.CONFIGDIR.get()));
|
||||
ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.COMMON, FMLPaths.CONFIGDIR.get());
|
||||
statusConsumer.ifPresent(c->c.accept("Mod setup: SETUP"));
|
||||
dispatchAndHandleError(ModLoadingStage.COMMON_SETUP, syncExecutor, parallelExecutor, periodicTask);
|
||||
statusConsumer.ifPresent(c->c.accept("Mod setup: SIDED SETUP"));
|
||||
dispatchAndHandleError(ModLoadingStage.SIDED_SETUP, syncExecutor, parallelExecutor, periodicTask, beforeSidedEvent, afterSidedEvent);
|
||||
public void loadMods(final ModWorkManager.DrivenExecutor syncExecutor, final Executor parallelExecutor, final Runnable periodicTask) {
|
||||
statusConsumer.ifPresent(c->c.accept("Performing load phase"));
|
||||
stateManager.getStates(ModLoadingPhase.LOAD).forEach(mls->dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask));
|
||||
statusConsumer.ifPresent(c->c.accept("Mod setup complete"));
|
||||
}
|
||||
|
||||
public void finishMods(final ModWorkManager.DrivenExecutor syncExecutor, final Executor parallelExecutor, final Runnable periodicTask)
|
||||
{
|
||||
statusConsumer.ifPresent(c->c.accept("Mod setup: ENQUEUE IMC"));
|
||||
dispatchAndHandleError(ModLoadingStage.ENQUEUE_IMC, syncExecutor, parallelExecutor, periodicTask);
|
||||
statusConsumer.ifPresent(c->c.accept("Mod setup: PROCESS IMC"));
|
||||
dispatchAndHandleError(ModLoadingStage.PROCESS_IMC, syncExecutor, parallelExecutor, periodicTask);
|
||||
statusConsumer.ifPresent(c->c.accept("Mod setup: Final completion"));
|
||||
dispatchAndHandleError(ModLoadingStage.COMPLETE, syncExecutor, parallelExecutor, periodicTask);
|
||||
statusConsumer.ifPresent(c->c.accept("Freezing data"));
|
||||
GameData.freezeData();
|
||||
NetworkRegistry.lock();
|
||||
statusConsumer.ifPresent(c->c.accept(String.format("Mod loading complete - %d mods loaded", ModList.get().size())));
|
||||
public void finishMods(final ModWorkManager.DrivenExecutor syncExecutor, final Executor parallelExecutor, final Runnable periodicTask) {
|
||||
statusConsumer.ifPresent(c->c.accept("Performing completion phase"));
|
||||
stateManager.getStates(ModLoadingPhase.COMPLETE).forEach(mls->dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask));
|
||||
statusConsumer.ifPresent(c->c.accept(String.format("Mod loading complete - %d mods loaded", this.modList.size())));
|
||||
}
|
||||
|
||||
private void dispatchAndHandleError(ModLoadingStage state, ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor, final Runnable ticker) {
|
||||
private void dispatchAndHandleError(IModLoadingState state, ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor, final Runnable ticker) {
|
||||
if (!isLoadingStateValid()) {
|
||||
LOGGER.error("Cowardly refusing to process mod state change request from {}", state);
|
||||
return;
|
||||
}
|
||||
waitForTransition(state, syncExecutor, ticker, state.buildTransition(syncExecutor, parallelExecutor));
|
||||
statusConsumer.ifPresent(c->c.accept(state.message().apply(this.modList)));
|
||||
state.inlineRunnable().ifPresent(a->a.accept(this.modList));
|
||||
state.buildTransition(syncExecutor, parallelExecutor).ifPresent(t->waitForTransition(state, syncExecutor, ticker, t));
|
||||
}
|
||||
|
||||
private void dispatchAndHandleError(ModLoadingStage state, ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor, final Runnable ticker, Function<Executor, CompletableFuture<Void>> preSyncTask, Function<Executor, CompletableFuture<Void>> postSyncTask) {
|
||||
private void dispatchAndHandleError(IModLoadingState state, ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor, final Runnable ticker, Function<Executor, CompletableFuture<Void>> preSyncTask, Function<Executor, CompletableFuture<Void>> postSyncTask) {
|
||||
if (!isLoadingStateValid()) {
|
||||
LOGGER.error("Cowardly refusing to process mod state change request from {}", state);
|
||||
return;
|
||||
}
|
||||
waitForTransition(state, syncExecutor, ticker, state.buildTransition(syncExecutor, parallelExecutor, preSyncTask, postSyncTask));
|
||||
statusConsumer.ifPresent(c->c.accept(state.message().apply(this.modList)));
|
||||
state.inlineRunnable().ifPresent(a->a.accept(this.modList));
|
||||
state.buildTransition(syncExecutor, parallelExecutor, preSyncTask, postSyncTask).ifPresent(t->waitForTransition(state, syncExecutor, ticker, t));
|
||||
}
|
||||
|
||||
private void waitForTransition(final ModLoadingStage state, final ModWorkManager.DrivenExecutor syncExecutor, final Runnable ticker, final CompletableFuture<List<Throwable>> transition) {
|
||||
private void waitForTransition(final IModLoadingState state, final ModWorkManager.DrivenExecutor syncExecutor, final Runnable ticker, final CompletableFuture<List<Throwable>> transition) {
|
||||
while (!transition.isDone()) {
|
||||
syncExecutor.drive(ticker);
|
||||
}
|
||||
@@ -259,20 +231,20 @@ public class ModLoader
|
||||
.filter(ModLoadingException.class::isInstance)
|
||||
.map(ModLoadingException.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
LOGGER.fatal(LOADING,"Failed to complete lifecycle event {}, {} errors found", state, modLoadingExceptions.size());
|
||||
LOGGER.fatal(LOADING,"Failed to complete lifecycle event {}, {} errors found", state.name(), modLoadingExceptions.size());
|
||||
throw new LoadingFailedException(modLoadingExceptions);
|
||||
}
|
||||
}
|
||||
|
||||
private List<ModContainer> buildMods(final ModFile modFile, final TransformingClassLoader modClassLoader)
|
||||
private List<ModContainer> buildMods(final ModFile modFile)
|
||||
{
|
||||
final Map<String, IModInfo> modInfoMap = modFile.getModFileInfo().getMods().stream().collect(Collectors.toMap(IModInfo::getModId, Function.identity()));
|
||||
|
||||
LOGGER.debug(LOADING, "ModContainer is {}", ModContainer.class.getClassLoader());
|
||||
LOGGER.trace(LOADING, "ModContainer is {}", ModContainer.class.getClassLoader());
|
||||
final List<ModContainer> containers = modFile.getScanResult().getTargets()
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(e -> buildModContainerFromTOML(modFile, modClassLoader, modInfoMap, e))
|
||||
.map(e -> buildModContainerFromTOML(modFile, modInfoMap, e))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
if (containers.size() != modInfoMap.size()) {
|
||||
@@ -286,14 +258,14 @@ public class ModLoader
|
||||
return containers.stream().filter(mc -> mc.modLoadingStage != ModLoadingStage.ERROR).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ModContainer buildModContainerFromTOML(final ModFile modFile, final TransformingClassLoader modClassLoader, final Map<String, IModInfo> modInfoMap, final Map.Entry<String, ? extends IModLanguageProvider.IModLanguageLoader> idToProviderEntry) {
|
||||
private ModContainer buildModContainerFromTOML(final ModFile modFile, final Map<String, IModInfo> modInfoMap, final Map.Entry<String, ? extends IModLanguageProvider.IModLanguageLoader> idToProviderEntry) {
|
||||
try {
|
||||
final String modId = idToProviderEntry.getKey();
|
||||
final IModLanguageProvider.IModLanguageLoader languageLoader = idToProviderEntry.getValue();
|
||||
IModInfo info = Optional.ofNullable(modInfoMap.get(modId)).
|
||||
// throw a missing metadata error if there is no matching modid in the modInfoMap from the mods.toml file
|
||||
orElseThrow(()->new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingmetadata", null, modId));
|
||||
return languageLoader.loadMod(info, modClassLoader, modFile.getScanResult());
|
||||
return languageLoader.loadMod(info, modFile.getScanResult(), FMLLoader.getGameLayer());
|
||||
} catch (ModLoadingException mle) {
|
||||
// exceptions are caught and added to the error list for later handling
|
||||
loadingExceptions.add(mle);
|
||||
+9
-9
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -19,14 +19,14 @@
|
||||
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import net.minecraftforge.common.ForgeConfigSpec;
|
||||
import net.minecraftforge.fml.config.IConfigSpec;
|
||||
import net.minecraftforge.fml.config.ModConfig;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ModLoadingContext
|
||||
{
|
||||
private static ThreadLocal<ModLoadingContext> context = ThreadLocal.withInitial(ModLoadingContext::new);
|
||||
private static final ThreadLocal<ModLoadingContext> context = ThreadLocal.withInitial(ModLoadingContext::new);
|
||||
private Object languageExtension;
|
||||
private ModLoadingStage stage;
|
||||
|
||||
@@ -36,9 +36,9 @@ public class ModLoadingContext
|
||||
|
||||
private ModContainer activeContainer;
|
||||
|
||||
public void setActiveContainer(final ModContainer container, final Object languageExtension) {
|
||||
public void setActiveContainer(final ModContainer container) {
|
||||
this.activeContainer = container;
|
||||
this.languageExtension = languageExtension;
|
||||
this.languageExtension = container == null ? null : container.contextExtension.get();
|
||||
}
|
||||
|
||||
public ModContainer getActiveContainer() {
|
||||
@@ -50,20 +50,20 @@ public class ModLoadingContext
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an {@link ExtensionPoint} with the mod container.
|
||||
* Register an {@link IExtensionPoint} with the mod container.
|
||||
* @param point The extension point to register
|
||||
* @param extension An extension operator
|
||||
* @param <T> The type signature of the extension operator
|
||||
*/
|
||||
public <T> void registerExtensionPoint(ExtensionPoint<T> point, Supplier<T> extension) {
|
||||
public <T extends Record & IExtensionPoint<T>> void registerExtensionPoint(Class<? extends IExtensionPoint<T>> point, Supplier<T> extension) {
|
||||
getActiveContainer().registerExtensionPoint(point, extension);
|
||||
}
|
||||
|
||||
public void registerConfig(ModConfig.Type type, ForgeConfigSpec spec) {
|
||||
public void registerConfig(ModConfig.Type type, IConfigSpec<?> spec) {
|
||||
getActiveContainer().addConfig(new ModConfig(type, spec, getActiveContainer()));
|
||||
}
|
||||
|
||||
public void registerConfig(ModConfig.Type type, ForgeConfigSpec spec, String fileName) {
|
||||
public void registerConfig(ModConfig.Type type, IConfigSpec<?> spec, String fileName) {
|
||||
getActiveContainer().addConfig(new ModConfig(type, spec, getActiveContainer(), fileName));
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -73,7 +73,7 @@ public class ModLoadingException extends RuntimeException
|
||||
}
|
||||
|
||||
public String formatToString() {
|
||||
return ForgeI18n.parseMessage(i18nMessage, Streams.concat(Stream.of(modInfo, errorStage, getCause()), context.stream()).toArray());
|
||||
return Bindings.getMessageParser().get().parseMessage(i18nMessage, Streams.concat(Stream.of(modInfo, errorStage, getCause()), context.stream()).toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,6 +85,6 @@ public class ModLoadingException extends RuntimeException
|
||||
return modInfo;
|
||||
}
|
||||
public String getCleanMessage() {
|
||||
return ForgeI18n.stripControlCodes(formatToString());
|
||||
return Bindings.getMessageParser().get().stripControlCodes(formatToString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
public enum ModLoadingPhase {
|
||||
ERROR, // Special state for error handling
|
||||
GATHER,
|
||||
LOAD,
|
||||
COMPLETE,
|
||||
DONE;
|
||||
}
|
||||
+24
-22
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,33 +17,35 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.server.permission.context;
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class WorldContext extends Context
|
||||
public enum ModLoadingStage
|
||||
{
|
||||
private final World world;
|
||||
ERROR,
|
||||
VALIDATE,
|
||||
CONSTRUCT,
|
||||
COMMON_SETUP,
|
||||
SIDED_SETUP,
|
||||
ENQUEUE_IMC,
|
||||
PROCESS_IMC,
|
||||
COMPLETE,
|
||||
DONE;
|
||||
|
||||
public WorldContext(World w)
|
||||
{
|
||||
world = Preconditions.checkNotNull(w, "World can't be null in WorldContext!");
|
||||
private final DeferredWorkQueue deferredWorkQueue;
|
||||
|
||||
ModLoadingStage() {
|
||||
deferredWorkQueue = new DeferredWorkQueue(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getWorld()
|
||||
{
|
||||
return world;
|
||||
ModLoadingStage nextState(Throwable exception) {
|
||||
return exception != null ? ERROR : values()[this.ordinal()+1];
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PlayerEntity getPlayer()
|
||||
{
|
||||
return null;
|
||||
public ModLoadingStage currentState(Throwable exception) {
|
||||
return exception != null ? ERROR : this;
|
||||
}
|
||||
|
||||
public DeferredWorkQueue getDeferredWorkQueue() {
|
||||
return deferredWorkQueue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.event.IModBusEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public record ModLoadingState(String name, String previous, Function<ModList, String> message, ModLoadingPhase phase, Optional<Consumer<ModList>> inlineRunnable, Optional<IModStateTransition> transition) implements IModLoadingState {
|
||||
@Override
|
||||
public <T extends Event & IModBusEvent> Optional<CompletableFuture<List<Throwable>>> buildTransition(final Executor syncExecutor, final Executor parallelExecutor, Function<Executor, CompletableFuture<Void>> preSyncTask, Function<Executor, CompletableFuture<Void>> postSyncTask) {
|
||||
return transition.map(t->t.build(syncExecutor, parallelExecutor, preSyncTask, postSyncTask));
|
||||
}
|
||||
|
||||
public static ModLoadingState empty(final String name, final String previous, final ModLoadingPhase phase) {
|
||||
return new ModLoadingState(name, previous, ml->"", phase, Optional.empty(), Optional.empty());
|
||||
}
|
||||
|
||||
public static ModLoadingState withTransition(final String name, final String previous, final ModLoadingPhase phase, IModStateTransition transition) {
|
||||
return new ModLoadingState(name, previous, ml->"Processing transition "+name, phase, Optional.empty(), Optional.of(transition));
|
||||
}
|
||||
|
||||
public static ModLoadingState withTransition(final String name, final String previous, final Function<ModList, String> message, final ModLoadingPhase phase, IModStateTransition transition) {
|
||||
return new ModLoadingState(name, previous, message, phase, Optional.empty(), Optional.of(transition));
|
||||
}
|
||||
public static ModLoadingState withInline(final String name, final String previous, final ModLoadingPhase phase, Consumer<ModList> inline) {
|
||||
return new ModLoadingState(name, previous, ml->"Processing work "+name, phase, Optional.of(inline), Optional.empty());
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -55,6 +55,6 @@ public class ModLoadingWarning
|
||||
}
|
||||
|
||||
public String formatToString() {
|
||||
return ForgeI18n.parseMessage(i18nMessage, Streams.concat(Stream.of(modInfo, warningStage), context.stream()).toArray());
|
||||
return Bindings.getMessageParser().get().parseMessage(i18nMessage, Streams.concat(Stream.of(modInfo, warningStage), context.stream()).toArray());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import com.google.common.graph.GraphBuilder;
|
||||
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.loading.toposort.TopologicalSort;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public class ModStateManager {
|
||||
static ModStateManager INSTANCE;
|
||||
private final EnumMap<ModLoadingPhase, List<IModLoadingState>> stateMap;
|
||||
|
||||
public ModStateManager() {
|
||||
INSTANCE = this;
|
||||
final var sp = ServiceLoader.load(FMLLoader.getGameLayer(), IModStateProvider.class);
|
||||
this.stateMap = ServiceLoaderUtils.streamWithErrorHandling(sp, sce->{})
|
||||
.map(IModStateProvider::getAllStates)
|
||||
.<IModLoadingState>mapMulti(Iterable::forEach)
|
||||
.collect(Collectors.groupingBy(IModLoadingState::phase, ()->new EnumMap<>(ModLoadingPhase.class), Collectors.toUnmodifiableList()));
|
||||
}
|
||||
|
||||
public List<IModLoadingState> getStates(final ModLoadingPhase phase) {
|
||||
var nodes = stateMap.get(phase);
|
||||
var lookup = nodes.stream().collect(Collectors.toMap(IModLoadingState::name, Function.identity()));
|
||||
|
||||
var graph = GraphBuilder.directed().allowsSelfLoops(false).<IModLoadingState>build();
|
||||
var dummy = ModLoadingState.empty("", "", phase);
|
||||
nodes.forEach(graph::addNode);
|
||||
graph.addNode(dummy);
|
||||
nodes.forEach(n->graph.putEdge(lookup.getOrDefault(n.previous(), dummy), n));
|
||||
return TopologicalSort.topologicalSort(graph, Comparator.comparingInt(nodes::indexOf)).stream().filter(st->st!=dummy).toList();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+12
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -19,8 +19,19 @@
|
||||
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class StartupMessageManager {
|
||||
public static void addModMessage(final String message) {
|
||||
net.minecraftforge.fml.loading.progress.StartupMessageManager.addModMessage(message);
|
||||
}
|
||||
|
||||
public static Optional<Consumer<String>> modLoaderConsumer() {
|
||||
return net.minecraftforge.fml.loading.progress.StartupMessageManager.modLoaderConsumer();
|
||||
}
|
||||
|
||||
public static Optional<Consumer<String>> mcLoaderConsumer() {
|
||||
return net.minecraftforge.fml.loading.progress.StartupMessageManager.mcLoaderConsumer();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.BinaryOperator;
|
||||
|
||||
public enum ThreadSelector implements BinaryOperator<Executor> {
|
||||
SYNC((sync, parallel) -> sync),
|
||||
PARALLEL((sync, parallel) -> parallel);
|
||||
|
||||
private final BinaryOperator<Executor> selector;
|
||||
|
||||
ThreadSelector(final BinaryOperator<Executor> selector) {
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor apply(final Executor sync, final Executor parallel) {
|
||||
return this.selector.apply(sync, parallel);
|
||||
}
|
||||
}
|
||||
+51
-58
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -19,21 +19,24 @@
|
||||
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.gson.Gson;
|
||||
import net.minecraftforge.fml.loading.FMLConfig;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import net.minecraftforge.versions.mcp.MCPVersion;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.maven.artifact.versioning.ComparableVersion;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -41,8 +44,8 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import static net.minecraftforge.fml.VersionChecker.Status.*;
|
||||
|
||||
@@ -50,6 +53,7 @@ public class VersionChecker
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final int MAX_HTTP_REDIRECTS = Integer.getInteger("http.maxRedirects", 20);
|
||||
private static final int HTTP_TIMEOUT_SECS = Integer.getInteger("http.timeoutSecs", 15);
|
||||
|
||||
public enum Status
|
||||
{
|
||||
@@ -103,30 +107,14 @@ public class VersionChecker
|
||||
|
||||
}
|
||||
|
||||
public static class CheckResult
|
||||
{
|
||||
@Nonnull
|
||||
public final Status status;
|
||||
@Nullable
|
||||
public final ComparableVersion target;
|
||||
@Nullable
|
||||
public final Map<ComparableVersion, String> changes;
|
||||
@Nullable
|
||||
public final String url;
|
||||
|
||||
private CheckResult(@Nonnull Status status, @Nullable ComparableVersion target, @Nullable Map<ComparableVersion, String> changes, @Nullable String url)
|
||||
{
|
||||
this.status = status;
|
||||
this.target = target;
|
||||
this.changes = changes == null ? Collections.<ComparableVersion, String>emptyMap() : Collections.unmodifiableMap(changes);
|
||||
this.url = url;
|
||||
}
|
||||
}
|
||||
public record CheckResult(VersionChecker.Status status, ComparableVersion target, Map<ComparableVersion, String> changes, String url) {}
|
||||
|
||||
public static void startVersionCheck()
|
||||
{
|
||||
new Thread("Forge Version Check")
|
||||
{
|
||||
private HttpClient client;
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
@@ -136,39 +124,46 @@ public class VersionChecker
|
||||
return;
|
||||
}
|
||||
|
||||
client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(HTTP_TIMEOUT_SECS)).build();
|
||||
gatherMods().forEach(this::process);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens stream for given URL while following redirects
|
||||
* Returns the response body as a String for the given URL while following redirects
|
||||
*/
|
||||
private InputStream openUrlStream(URL url) throws IOException
|
||||
{
|
||||
private String openUrlString(URL url) throws IOException, URISyntaxException, InterruptedException {
|
||||
URL currentUrl = url;
|
||||
for (int redirects = 0; redirects < MAX_HTTP_REDIRECTS; redirects++)
|
||||
{
|
||||
URLConnection c = currentUrl.openConnection();
|
||||
if (c instanceof HttpURLConnection)
|
||||
var request = HttpRequest.newBuilder()
|
||||
.uri(currentUrl.toURI())
|
||||
.timeout(Duration.ofSeconds(HTTP_TIMEOUT_SECS))
|
||||
.setHeader("Accept-Encoding", "gzip")
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
final HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
|
||||
int responseCode = response.statusCode();
|
||||
if (responseCode >= 300 && responseCode <= 399)
|
||||
{
|
||||
HttpURLConnection huc = (HttpURLConnection) c;
|
||||
huc.setInstanceFollowRedirects(false);
|
||||
int responseCode = huc.getResponseCode();
|
||||
if (responseCode >= 300 && responseCode <= 399)
|
||||
{
|
||||
try
|
||||
{
|
||||
String loc = huc.getHeaderField("Location");
|
||||
currentUrl = new URL(currentUrl, loc);
|
||||
continue;
|
||||
}
|
||||
finally
|
||||
{
|
||||
huc.disconnect();
|
||||
}
|
||||
}
|
||||
String newLocation = response.headers().firstValue("Location")
|
||||
.orElseThrow(() -> new IOException("Got a 3xx response code but Location header was null while trying to fetch " + url));
|
||||
currentUrl = new URL(currentUrl, newLocation);
|
||||
continue;
|
||||
}
|
||||
|
||||
return c.getInputStream();
|
||||
final boolean isGzipEncoded = response.headers().firstValue("Content-Encoding").orElse("").equals("gzip");
|
||||
|
||||
final String bodyStr;
|
||||
try (InputStream inStream = isGzipEncoded ? new GZIPInputStream(response.body()) : response.body())
|
||||
{
|
||||
try (var bufferedReader = new BufferedReader(new InputStreamReader(inStream)))
|
||||
{
|
||||
bodyStr = bufferedReader.lines().collect(Collectors.joining("\n"));
|
||||
}
|
||||
}
|
||||
return bodyStr;
|
||||
}
|
||||
throw new IOException("Too many redirects while trying to fetch " + url);
|
||||
}
|
||||
@@ -181,12 +176,11 @@ public class VersionChecker
|
||||
String display_url = null;
|
||||
try
|
||||
{
|
||||
URL url = mod.getUpdateURL();
|
||||
if (mod.getUpdateURL().isEmpty()) return;
|
||||
URL url = mod.getUpdateURL().get();
|
||||
LOGGER.info("[{}] Starting version check at {}", mod.getModId(), url.toString());
|
||||
|
||||
InputStream con = openUrlStream(url);
|
||||
String data = new String(ByteStreams.toByteArray(con), StandardCharsets.UTF_8);
|
||||
con.close();
|
||||
String data = openUrlString(url);
|
||||
|
||||
LOGGER.debug("[{}] Received version check data:\n{}", mod.getModId(), data);
|
||||
|
||||
@@ -197,7 +191,7 @@ public class VersionChecker
|
||||
Map<String, String> promos = (Map<String, String>)json.get("promos");
|
||||
display_url = (String)json.get("homepage");
|
||||
|
||||
String mcVersion = MCPVersion.getMCVersion();
|
||||
var mcVersion = FMLLoader.versionInfo().mcVersion();
|
||||
String rec = promos.get(mcVersion + "-recommended");
|
||||
String lat = promos.get(mcVersion + "-latest");
|
||||
ComparableVersion current = new ComparableVersion(mod.getVersion().toString());
|
||||
@@ -278,9 +272,8 @@ public class VersionChecker
|
||||
private static List<IModInfo> gatherMods()
|
||||
{
|
||||
List<IModInfo> ret = new LinkedList<>();
|
||||
for (ModInfo info : ModList.get().getMods()) {
|
||||
URL url = info.getUpdateURL();
|
||||
if (url != null)
|
||||
for (IModInfo info : ModList.get().getMods()) {
|
||||
if (info.getUpdateURL().isPresent())
|
||||
ret.add(info);
|
||||
}
|
||||
return ret;
|
||||
+44
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -26,6 +26,7 @@ import com.electronwill.nightconfig.core.io.ParsingException;
|
||||
import com.electronwill.nightconfig.core.io.WritingMode;
|
||||
import net.minecraftforge.fml.loading.FMLConfig;
|
||||
import net.minecraftforge.fml.loading.FMLPaths;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -80,6 +81,7 @@ public class ConfigFileTypeHandler {
|
||||
}
|
||||
|
||||
private boolean setupConfigFile(final ModConfig modConfig, final Path file, final ConfigFormat<?> conf) throws IOException {
|
||||
Files.createDirectories(file.getParent());
|
||||
Path p = defaultConfigPath.resolve(modConfig.getFileName());
|
||||
if (Files.exists(p)) {
|
||||
LOGGER.info(CONFIG, "Loading default config file from path {}", p);
|
||||
@@ -91,6 +93,38 @@ public class ConfigFileTypeHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void backUpConfig(final CommentedFileConfig commentedFileConfig)
|
||||
{
|
||||
backUpConfig(commentedFileConfig, 5); //TODO: Think of a way for mods to set their own preference (include a sanity check as well, no disk stuffing)
|
||||
}
|
||||
|
||||
public static void backUpConfig(final CommentedFileConfig commentedFileConfig, final int maxBackups)
|
||||
{
|
||||
Path bakFileLocation = commentedFileConfig.getNioPath().getParent();
|
||||
String bakFileName = FilenameUtils.removeExtension(commentedFileConfig.getFile().getName());
|
||||
String bakFileExtension = FilenameUtils.getExtension(commentedFileConfig.getFile().getName()) + ".bak";
|
||||
Path bakFile = bakFileLocation.resolve(bakFileName + "-1" + "." + bakFileExtension);
|
||||
try
|
||||
{
|
||||
for(int i = maxBackups; i > 0; i--)
|
||||
{
|
||||
Path oldBak = bakFileLocation.resolve(bakFileName + "-" + i + "." + bakFileExtension);
|
||||
if(Files.exists(oldBak))
|
||||
{
|
||||
if(i >= maxBackups)
|
||||
Files.delete(oldBak);
|
||||
else
|
||||
Files.move(oldBak, bakFileLocation.resolve(bakFileName + "-" + (i + 1) + "." + bakFileExtension));
|
||||
}
|
||||
}
|
||||
Files.copy(commentedFileConfig.getNioPath(), bakFile);
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
LOGGER.warn(CONFIG, "Failed to back up config file {}", commentedFileConfig.getNioPath(), exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConfigWatcher implements Runnable {
|
||||
private final ModConfig modConfig;
|
||||
private final CommentedFileConfig commentedFileConfig;
|
||||
@@ -110,13 +144,21 @@ public class ConfigFileTypeHandler {
|
||||
try
|
||||
{
|
||||
this.commentedFileConfig.load();
|
||||
if(!this.modConfig.getSpec().isCorrect(commentedFileConfig))
|
||||
{
|
||||
LOGGER.warn(CONFIG, "Configuration file {} is not correct. Correcting", commentedFileConfig.getFile().getAbsolutePath());
|
||||
ConfigFileTypeHandler.backUpConfig(commentedFileConfig);
|
||||
this.modConfig.getSpec().correct(commentedFileConfig);
|
||||
commentedFileConfig.save();
|
||||
}
|
||||
}
|
||||
catch (ParsingException ex)
|
||||
{
|
||||
throw new ConfigLoadingException(modConfig, ex);
|
||||
}
|
||||
LOGGER.debug(CONFIG, "Config file {} changed, sending notifies", this.modConfig.getFileName());
|
||||
this.modConfig.fireEvent(new ModConfig.Reloading(this.modConfig));
|
||||
this.modConfig.getSpec().afterReload();
|
||||
this.modConfig.fireEvent(IConfigEvent.reloading(this.modConfig));
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-44
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -21,33 +21,14 @@ package net.minecraftforge.fml.config;
|
||||
|
||||
import com.electronwill.nightconfig.core.CommentedConfig;
|
||||
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
||||
import com.electronwill.nightconfig.toml.TomlFormat;
|
||||
import it.unimi.dsi.fastutil.bytes.Byte2ByteOpenCustomHashMap;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraftforge.fml.network.FMLHandshakeMessages;
|
||||
import net.minecraftforge.fml.network.NetworkEvent;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.Marker;
|
||||
import org.apache.logging.log4j.MarkerManager;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.rethrowFunction;
|
||||
|
||||
public class ConfigTracker {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
@@ -55,7 +36,7 @@ public class ConfigTracker {
|
||||
public static final ConfigTracker INSTANCE = new ConfigTracker();
|
||||
private final ConcurrentHashMap<String, ModConfig> fileMap;
|
||||
private final EnumMap<ModConfig.Type, Set<ModConfig>> configSets;
|
||||
private ConcurrentHashMap<String, Map<ModConfig.Type, ModConfig>> configsByMod;
|
||||
private final ConcurrentHashMap<String, Map<ModConfig.Type, ModConfig>> configsByMod;
|
||||
|
||||
private ConfigTracker() {
|
||||
this.fileMap = new ConcurrentHashMap<>();
|
||||
@@ -88,22 +69,11 @@ public class ConfigTracker {
|
||||
this.configSets.get(type).forEach(config -> closeConfig(config, configBasePath));
|
||||
}
|
||||
|
||||
public List<Pair<String, FMLHandshakeMessages.S2CConfigData>> syncConfigs(boolean isLocal) {
|
||||
final Map<String, byte[]> configData = configSets.get(ModConfig.Type.SERVER).stream().collect(Collectors.toMap(ModConfig::getFileName, mc -> { //TODO: Test cpw's LambdaExceptionUtils on Oracle javac.
|
||||
try {
|
||||
return Files.readAllBytes(mc.getFullPath());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}));
|
||||
return configData.entrySet().stream().map(e->Pair.of("Config "+e.getKey(), new FMLHandshakeMessages.S2CConfigData(e.getKey(), e.getValue()))).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void openConfig(final ModConfig config, final Path configBasePath) {
|
||||
LOGGER.trace(CONFIG, "Loading config file type {} at {} for {}", config.getType(), config.getFileName(), config.getModId());
|
||||
final CommentedFileConfig configData = config.getHandler().reader(configBasePath).apply(config);
|
||||
config.setConfigData(configData);
|
||||
config.fireEvent(new ModConfig.Loading(config));
|
||||
config.fireEvent(IConfigEvent.loading(config));
|
||||
config.save();
|
||||
}
|
||||
|
||||
@@ -116,21 +86,12 @@ public class ConfigTracker {
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveSyncedConfig(final FMLHandshakeMessages.S2CConfigData s2CConfigData, final Supplier<NetworkEvent.Context> contextSupplier) {
|
||||
if (!Minecraft.getInstance().isIntegratedServerRunning()) {
|
||||
Optional.ofNullable(fileMap.get(s2CConfigData.getFileName())).ifPresent(mc-> {
|
||||
mc.setConfigData(TomlFormat.instance().createParser().parse(new ByteArrayInputStream(s2CConfigData.getBytes())));
|
||||
mc.fireEvent(new ModConfig.Reloading(mc));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void loadDefaultServerConfigs() {
|
||||
configSets.get(ModConfig.Type.SERVER).forEach(modConfig -> {
|
||||
final CommentedConfig commentedConfig = CommentedConfig.inMemory();
|
||||
modConfig.getSpec().correct(commentedConfig);
|
||||
modConfig.setConfigData(commentedConfig);
|
||||
modConfig.fireEvent(new ModConfig.Loading(modConfig));
|
||||
modConfig.fireEvent(IConfigEvent.loading(modConfig));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -138,4 +99,12 @@ public class ConfigTracker {
|
||||
return Optional.ofNullable(configsByMod.getOrDefault(modId, Collections.emptyMap()).getOrDefault(type, null)).
|
||||
map(ModConfig::getFullPath).map(Object::toString).orElse(null);
|
||||
}
|
||||
|
||||
public Map<ModConfig.Type, Set<ModConfig>> configSets() {
|
||||
return configSets;
|
||||
}
|
||||
|
||||
public ConcurrentHashMap<String, ModConfig> fileMap() {
|
||||
return fileMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package net.minecraftforge.fml.config;
|
||||
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.Bindings;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface IConfigEvent {
|
||||
record ConfigConfig(Function<ModConfig, IConfigEvent> loading, Function<ModConfig, IConfigEvent> reloading) {}
|
||||
ConfigConfig CONFIGCONFIG = Bindings.getConfigConfiguration().get();
|
||||
|
||||
static IConfigEvent reloading(ModConfig modConfig) {
|
||||
return CONFIGCONFIG.reloading().apply(modConfig);
|
||||
}
|
||||
static IConfigEvent loading(ModConfig modConfig) {
|
||||
return CONFIGCONFIG.loading().apply(modConfig);
|
||||
}
|
||||
ModConfig getConfig();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
default <T extends Event & IConfigEvent> T self() {
|
||||
return (T) this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package net.minecraftforge.fml.config;
|
||||
|
||||
import com.electronwill.nightconfig.core.CommentedConfig;
|
||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||
|
||||
public interface IConfigSpec<T extends IConfigSpec<T>> extends UnmodifiableConfig {
|
||||
@SuppressWarnings("unchecked")
|
||||
default T self() {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
void acceptConfig(CommentedConfig data);
|
||||
|
||||
boolean isCorrecting();
|
||||
|
||||
boolean isCorrect(CommentedConfig commentedFileConfig);
|
||||
|
||||
int correct(CommentedConfig commentedFileConfig);
|
||||
|
||||
void afterReload();
|
||||
}
|
||||
+18
-36
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2022.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -21,26 +21,26 @@ package net.minecraftforge.fml.config;
|
||||
|
||||
import com.electronwill.nightconfig.core.CommentedConfig;
|
||||
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
||||
import net.minecraftforge.common.ForgeConfigSpec;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import com.electronwill.nightconfig.toml.TomlFormat;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.event.lifecycle.IModBusEvent;
|
||||
import net.minecraftforge.fml.loading.StringUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class ModConfig
|
||||
{
|
||||
private final Type type;
|
||||
private final ForgeConfigSpec spec;
|
||||
private final IConfigSpec<?> spec;
|
||||
private final String fileName;
|
||||
private final ModContainer container;
|
||||
private final ConfigFileTypeHandler configHandler;
|
||||
private CommentedConfig configData;
|
||||
private Callable<Void> saveHandler;
|
||||
|
||||
public ModConfig(final Type type, final ForgeConfigSpec spec, final ModContainer container, final String fileName) {
|
||||
public ModConfig(final Type type, final IConfigSpec<?> spec, final ModContainer container, final String fileName) {
|
||||
this.type = type;
|
||||
this.spec = spec;
|
||||
this.fileName = fileName;
|
||||
@@ -49,13 +49,13 @@ public class ModConfig
|
||||
ConfigTracker.INSTANCE.trackConfig(this);
|
||||
}
|
||||
|
||||
public ModConfig(final Type type, final ForgeConfigSpec spec, final ModContainer activeContainer) {
|
||||
public ModConfig(final Type type, final IConfigSpec<?> spec, final ModContainer activeContainer) {
|
||||
this(type, spec, activeContainer, defaultConfigName(type, activeContainer.getModId()));
|
||||
}
|
||||
|
||||
private static String defaultConfigName(Type type, String modId) {
|
||||
// config file name would be "forge-client.toml" and "forge-server.toml"
|
||||
return String.format("%s-%s.toml", modId, type.extension());
|
||||
return String.format(Locale.ROOT, "%s-%s.toml", modId, type.extension());
|
||||
}
|
||||
public Type getType() {
|
||||
return type;
|
||||
@@ -69,8 +69,9 @@ public class ModConfig
|
||||
return configHandler;
|
||||
}
|
||||
|
||||
public ForgeConfigSpec getSpec() {
|
||||
return spec;
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends IConfigSpec<T>> IConfigSpec<T> getSpec() {
|
||||
return (IConfigSpec<T>) spec;
|
||||
}
|
||||
|
||||
public String getModId() {
|
||||
@@ -83,10 +84,10 @@ public class ModConfig
|
||||
|
||||
void setConfigData(final CommentedConfig configData) {
|
||||
this.configData = configData;
|
||||
this.spec.setConfig(this.configData);
|
||||
this.spec.acceptConfig(this.configData);
|
||||
}
|
||||
|
||||
void fireEvent(final ModConfigEvent configEvent) {
|
||||
void fireEvent(final IConfigEvent configEvent) {
|
||||
this.container.dispatchConfigEvent(configEvent);
|
||||
}
|
||||
|
||||
@@ -98,6 +99,11 @@ public class ModConfig
|
||||
return ((CommentedFileConfig)this.configData).getNioPath();
|
||||
}
|
||||
|
||||
public void acceptSyncedConfig(byte[] bytes) {
|
||||
setConfigData(TomlFormat.instance().createParser().parse(new ByteArrayInputStream(bytes)));
|
||||
fireEvent(IConfigEvent.reloading(this));
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
/**
|
||||
* Common mod config for configuration that needs to be loaded on both environments.
|
||||
@@ -133,28 +139,4 @@ public class ModConfig
|
||||
return StringUtils.toLowerCase(name());
|
||||
}
|
||||
}
|
||||
|
||||
public static class ModConfigEvent extends Event implements IModBusEvent {
|
||||
private final ModConfig config;
|
||||
|
||||
ModConfigEvent(final ModConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public ModConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Loading extends ModConfigEvent {
|
||||
Loading(final ModConfig config) {
|
||||
super(config);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Reloading extends ModConfigEvent {
|
||||
Reloading(final ModConfig config) {
|
||||
super(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.event.lifecycle;
|
||||
package net.minecraftforge.fml.event;
|
||||
|
||||
/**
|
||||
* Marker interface for events dispatched on the ModLifecycle event bus instead of the primary event bus
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.common;
|
||||
package net.minecraftforge.fml.util;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.common;
|
||||
package net.minecraftforge.fml.util;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
+2
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,8 +17,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.common;
|
||||
import net.minecraftforge.fml.common.EnhancedRuntimeException.WrappedPrintStream;
|
||||
package net.minecraftforge.fml.util;
|
||||
|
||||
|
||||
public class LoaderException extends EnhancedRuntimeException
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.common;
|
||||
package net.minecraftforge.fml.util;
|
||||
|
||||
/**
|
||||
* Prevent LoaderException from adding its own stack trace to the wrapped throwable's stack trace.
|
||||
+15
-16
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,15 +17,12 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.common;
|
||||
package net.minecraftforge.fml.util;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import cpw.mods.modlauncher.api.INameMappingService;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -34,6 +31,8 @@ import org.apache.logging.log4j.Marker;
|
||||
import org.apache.logging.log4j.MarkerManager;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Some reflection helper code.
|
||||
@@ -58,7 +57,7 @@ public class ObfuscationReflectionHelper
|
||||
* @param name The name to try and remap.
|
||||
* @return The remapped name, or the original name if it couldn't be remapped.
|
||||
*/
|
||||
@Nonnull
|
||||
@NotNull
|
||||
public static String remapName(INameMappingService.Domain domain, String name)
|
||||
{
|
||||
return FMLLoader.getNameFunction("srg").map(f->f.apply(domain, name)).orElse(name);
|
||||
@@ -72,7 +71,7 @@ public class ObfuscationReflectionHelper
|
||||
*
|
||||
* @param classToAccess The class to find the field on.
|
||||
* @param instance The instance of the {@code classToAccess}.
|
||||
* @param fieldName The SRG (unmapped) name of the field to find (e.g. "field_181725_a").
|
||||
* @param fieldName The SRG (unmapped) name of the field to find (e.g. "f_46443_").
|
||||
* @param <T> The type of the value.
|
||||
* @param <E> The type of the {@code classToAccess}.
|
||||
* @return The value of the field with the specified name in the {@code classToAccess}.
|
||||
@@ -113,7 +112,7 @@ public class ObfuscationReflectionHelper
|
||||
* @throws UnableToFindFieldException If there was a problem getting the field.
|
||||
* @throws UnableToAccessFieldException If there was a problem setting the value of the field.
|
||||
*/
|
||||
public static <T, E> void setPrivateValue(@Nonnull final Class<? super T> classToAccess, @Nonnull final T instance, @Nullable final E value, @Nonnull final String fieldName)
|
||||
public static <T, E> void setPrivateValue(@NotNull final Class<? super T> classToAccess, @NotNull final T instance, @Nullable final E value, @NotNull final String fieldName)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -138,7 +137,7 @@ public class ObfuscationReflectionHelper
|
||||
* Throws an exception if the method is not found.
|
||||
*
|
||||
* @param clazz The class to find the method on.
|
||||
* @param methodName The SRG (unmapped) name of the method to find (e.g. "func_12820_D").
|
||||
* @param methodName The SRG (unmapped) name of the method to find (e.g. "m_5776_").
|
||||
* @param parameterTypes The parameter types of the method to find.
|
||||
* @return The method with the specified name and parameters in the given class.
|
||||
* @throws NullPointerException If {@code clazz} is null.
|
||||
@@ -147,8 +146,8 @@ public class ObfuscationReflectionHelper
|
||||
* @throws NullPointerException If {@code parameterTypes} is null.
|
||||
* @throws UnableToFindMethodException If the method could not be found.
|
||||
*/
|
||||
@Nonnull
|
||||
public static Method findMethod(@Nonnull final Class<?> clazz, @Nonnull final String methodName, @Nonnull final Class<?>... parameterTypes)
|
||||
@NotNull
|
||||
public static Method findMethod(@NotNull final Class<?> clazz, @NotNull final String methodName, @NotNull final Class<?>... parameterTypes)
|
||||
{
|
||||
Preconditions.checkNotNull(clazz, "Class to find method on cannot be null.");
|
||||
Preconditions.checkNotNull(methodName, "Name of method to find cannot be null.");
|
||||
@@ -181,8 +180,8 @@ public class ObfuscationReflectionHelper
|
||||
* @throws NullPointerException If {@code parameterTypes} is null.
|
||||
* @throws UnknownConstructorException If the constructor could not be found.
|
||||
*/
|
||||
@Nonnull
|
||||
public static <T> Constructor<T> findConstructor(@Nonnull final Class<T> clazz, @Nonnull final Class<?>... parameterTypes)
|
||||
@NotNull
|
||||
public static <T> Constructor<T> findConstructor(@NotNull final Class<T> clazz, @NotNull final Class<?>... parameterTypes)
|
||||
{
|
||||
Preconditions.checkNotNull(clazz, "Class to find constructor on cannot be null.");
|
||||
Preconditions.checkNotNull(parameterTypes, "Parameter types of constructor to find cannot be null.");
|
||||
@@ -216,7 +215,7 @@ public class ObfuscationReflectionHelper
|
||||
* Throws an exception if the field is not found.
|
||||
*
|
||||
* @param clazz The class to find the field on.
|
||||
* @param fieldName The SRG (unmapped) name of the field to find (e.g. "field_181725_a").
|
||||
* @param fieldName The SRG (unmapped) name of the field to find (e.g. "f_46443_").
|
||||
* @param <T> The type.
|
||||
* @return The constructor with the specified parameters in the given class.
|
||||
* @throws NullPointerException If {@code clazz} is null.
|
||||
@@ -224,8 +223,8 @@ public class ObfuscationReflectionHelper
|
||||
* @throws IllegalArgumentException If {@code fieldName} is empty.
|
||||
* @throws UnableToFindFieldException If the field could not be found.
|
||||
*/
|
||||
@Nonnull
|
||||
public static <T> Field findField(@Nonnull final Class<? super T> clazz, @Nonnull final String fieldName)
|
||||
@NotNull
|
||||
public static <T> Field findField(@NotNull final Class<? super T> clazz, @NotNull final String fieldName)
|
||||
{
|
||||
Preconditions.checkNotNull(clazz, "Class to find field on cannot be null.");
|
||||
Preconditions.checkNotNull(fieldName, "Name of field to find cannot be null.");
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.common.thread;
|
||||
package net.minecraftforge.fml.util.thread;
|
||||
|
||||
import net.minecraftforge.fml.LogicalSide;
|
||||
|
||||
+4
-5
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,14 +17,13 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.common.thread;
|
||||
package net.minecraftforge.fml.util.thread;
|
||||
|
||||
import net.minecraftforge.fml.LogicalSide;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* A thread group and factory combination which belongs to a {@link LogicalSide}.
|
||||
*/
|
||||
@@ -49,7 +48,7 @@ public final class SidedThreadGroup extends ThreadGroup implements ThreadFactory
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(@Nonnull final Runnable runnable)
|
||||
public Thread newThread(@NotNull final Runnable runnable)
|
||||
{
|
||||
return new Thread(this, runnable);
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.common.thread;
|
||||
package net.minecraftforge.fml.util.thread;
|
||||
|
||||
import net.minecraftforge.fml.LogicalSide;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
plugins {
|
||||
id 'com.github.ben-manes.versions'
|
||||
id 'org.javamodularity.moduleplugin' version '1.8.3' apply false
|
||||
}
|
||||
apply plugin: 'java-library'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: 'org.javamodularity.moduleplugin'
|
||||
|
||||
dependencyUpdates.rejectVersionIf { isNonStable(it.candidate.version) }
|
||||
configurations.forEach{ it.transitive = false }
|
||||
|
||||
dependencies {
|
||||
implementation('net.sf.jopt-simple:jopt-simple:5.0.4')
|
||||
compileOnly('org.jetbrains:annotations:21.0.0')
|
||||
api("org.ow2.asm:asm:${ASM_VERSION}")
|
||||
api("org.ow2.asm:asm-tree:${ASM_VERSION}")
|
||||
api("org.ow2.asm:asm-commons:${ASM_VERSION}")
|
||||
api('net.minecraftforge:forgespi:4.0.+')
|
||||
api('org.apache.logging.log4j:log4j-api:2.14.1')
|
||||
api('com.google.guava:guava:21.0')
|
||||
api('com.google.code.gson:gson:2.8.0')
|
||||
api('org.apache.maven:maven-artifact:3.8.1')
|
||||
api('org.apache.commons:commons-lang3:3.8.1')
|
||||
api('com.electronwill.night-config:core:3.6.3')
|
||||
api('com.electronwill.night-config:toml:3.6.3')
|
||||
api('cpw.mods:modlauncher:9.0.+')
|
||||
api('net.minecraftforge:coremods:5.0.+')
|
||||
implementation("cpw.mods:securejarhandler:${SECUREJARHANDLER_VERSION}")
|
||||
implementation('org.apache.logging.log4j:log4j-core:2.14.1')
|
||||
annotationProcessor('org.apache.logging.log4j:log4j-core:2.14.1')
|
||||
implementation('net.minecraftforge:accesstransformers:8.0.4')
|
||||
implementation('net.minecrell:terminalconsoleappender:1.2.0')
|
||||
// implementation('org.jline:jline:3.12.+')
|
||||
testCompileOnly('org.jetbrains:annotations:21.0.0')
|
||||
testRuntimeOnly("cpw.mods:bootstraplauncher:${BOOTSTRAPLAUNCHER_VERSION}")
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
archiveClassifier = 'sources'
|
||||
from sourceSets.main.allSource
|
||||
}
|
||||
|
||||
ext {
|
||||
MANIFESTS = [
|
||||
'/': [
|
||||
'Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||
'Git-Commit': GIT_INFO.abbreviatedId,
|
||||
'Git-Branch': GIT_INFO.branch,
|
||||
'Build-Number': "${System.getenv('BUILD_NUMBER')?:0}",
|
||||
] as LinkedHashMap,
|
||||
'net/minecraftforge/fml/loading/': [
|
||||
'Specification-Title': 'FMLLoader',
|
||||
'Specification-Vendor': 'Forge Development LLC',
|
||||
'Specification-Version': '1',
|
||||
'Implementation-Title': 'FML Loader',
|
||||
'Implementation-Version': '1.0',
|
||||
'Implementation-Vendor': 'Forge'
|
||||
] as LinkedHashMap
|
||||
]
|
||||
}
|
||||
|
||||
jar.doFirst {
|
||||
MANIFESTS.each { pkg, values ->
|
||||
manifest.attributes(values, pkg)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs << '-Xlint:unchecked'
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives jar
|
||||
archives sourcesJar
|
||||
}
|
||||
|
||||
publishing.publications.mavenJava(MavenPublication) {
|
||||
from components.java
|
||||
artifact sourcesJar
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.common.asm;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.signature.SignatureReader;
|
||||
import org.objectweb.asm.signature.SignatureVisitor;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import cpw.mods.modlauncher.serviceapi.ILaunchPluginService;
|
||||
|
||||
/**
|
||||
* Implements getType() in CapabilityToken subclasses.
|
||||
*
|
||||
* Using the class's signature to determine the generic type of TypeToken, and then implements getType() using that value.
|
||||
* <pre>
|
||||
* Example:
|
||||
*
|
||||
* <code>new CapabilityToken<String>(){}</code>
|
||||
* Has the signature <code>"CapabilityToken<Ljava/lang/String;>"</code>
|
||||
*
|
||||
* Implements the method:
|
||||
* <code>public String getType() {
|
||||
* return "java/lang/String";
|
||||
* }</code>
|
||||
* </pre>
|
||||
*/
|
||||
public class CapabilityTokenSubclass implements ILaunchPluginService {
|
||||
|
||||
private final String FUNC_NAME = "getType";
|
||||
private final String FUNC_DESC = "()Ljava/lang/String;";
|
||||
private final String CAP_INJECT = "net/minecraftforge/common/capabilities/CapabilityToken"; //Don't directly reference this to prevent class loading.
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "capability_token_subclass";
|
||||
}
|
||||
|
||||
private static final EnumSet<Phase> YAY = EnumSet.of(Phase.AFTER);
|
||||
private static final EnumSet<Phase> NAY = EnumSet.noneOf(Phase.class);
|
||||
|
||||
@Override
|
||||
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty)
|
||||
{
|
||||
return isEmpty ? NAY : YAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int processClassWithFlags(final Phase phase, final ClassNode classNode, final Type classType, final String reason)
|
||||
{
|
||||
if (CAP_INJECT.equals(classNode.name))
|
||||
{
|
||||
for (MethodNode mtd : classNode.methods)
|
||||
{
|
||||
if (FUNC_NAME.equals(mtd.name) && FUNC_DESC.equals(mtd.desc))
|
||||
{
|
||||
mtd.access &= ~Opcodes.ACC_FINAL; // We have it final in code so people don't override it, cuz that'd be stupid, and make our transformer more complicated.
|
||||
}
|
||||
}
|
||||
return ComputeFlags.SIMPLE_REWRITE;
|
||||
}
|
||||
else if (CAP_INJECT.equals(classNode.superName))
|
||||
{
|
||||
Holder cls = new Holder();
|
||||
|
||||
SignatureReader reader = new SignatureReader(classNode.signature); // Having a node version of this would probably be useful.
|
||||
reader.accept(new SignatureVisitor(Opcodes.ASM9)
|
||||
{
|
||||
Deque<String> stack = new ArrayDeque<>();
|
||||
|
||||
@Override
|
||||
public void visitClassType(final String name)
|
||||
{
|
||||
stack.push(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClassType(final String name)
|
||||
{
|
||||
stack.push(stack.pop() + '$' + name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd()
|
||||
{
|
||||
var val = stack.pop();
|
||||
if (!stack.isEmpty() && CAP_INJECT.equals(stack.peek()))
|
||||
cls.value = val;
|
||||
}
|
||||
});
|
||||
|
||||
if (cls.value == null)
|
||||
throw new IllegalStateException("Could not find signature for CapabilityToken on " + classNode.name + " from " + classNode.signature);
|
||||
|
||||
var mtd = classNode.visitMethod(Opcodes.ACC_PUBLIC, FUNC_NAME, FUNC_DESC, null, new String[0]);
|
||||
mtd.visitLdcInsn(cls.value);
|
||||
mtd.visitInsn(Opcodes.ARETURN);
|
||||
mtd.visitEnd();
|
||||
return ComputeFlags.COMPUTE_MAXS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ComputeFlags.NO_REWRITE;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Holder {
|
||||
String value;
|
||||
}
|
||||
|
||||
}
|
||||
+2
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,9 +17,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common.asm;
|
||||
package net.minecraftforge.fml.common.asm;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
+2
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,9 +17,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common.asm;
|
||||
package net.minecraftforge.fml.common.asm;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+8
-9
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -21,16 +21,15 @@ package net.minecraftforge.fml.loading;
|
||||
|
||||
import com.electronwill.nightconfig.core.ConfigSpec;
|
||||
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
||||
import com.electronwill.nightconfig.core.file.FileNotFoundAction;
|
||||
import com.electronwill.nightconfig.core.io.ParsingException;
|
||||
import com.electronwill.nightconfig.core.io.WritingMode;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Objects;
|
||||
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
@@ -50,11 +49,11 @@ public class FMLConfig
|
||||
|
||||
private void loadFrom(final Path configFile)
|
||||
{
|
||||
configData = CommentedFileConfig.builder(configFile).sync().
|
||||
defaultResource("/META-INF/defaultfmlconfig.toml").
|
||||
autosave().autoreload().
|
||||
writingMode(WritingMode.REPLACE).
|
||||
build();
|
||||
configData = CommentedFileConfig.builder(configFile).sync()
|
||||
.onFileNotFound(FileNotFoundAction.copyData(Objects.requireNonNull(getClass().getResourceAsStream("/META-INF/defaultfmlconfig.toml"))))
|
||||
.autosave().autoreload()
|
||||
.writingMode(WritingMode.REPLACE)
|
||||
.build();
|
||||
try
|
||||
{
|
||||
configData.load();
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+49
-87
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -20,42 +20,28 @@
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import cpw.mods.modlauncher.Launcher;
|
||||
import cpw.mods.modlauncher.ServiceLoaderStreamUtils;
|
||||
import cpw.mods.modlauncher.TransformingClassLoader;
|
||||
import cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ILaunchHandlerService;
|
||||
import cpw.mods.modlauncher.api.INameMappingService;
|
||||
import cpw.mods.modlauncher.api.ITransformationService;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
import cpw.mods.modlauncher.api.IncompatibleEnvironmentException;
|
||||
import cpw.mods.modlauncher.api.*;
|
||||
import cpw.mods.modlauncher.serviceapi.ILaunchPluginService;
|
||||
import net.minecraftforge.accesstransformer.service.AccessTransformerService;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModDiscoverer;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModValidator;
|
||||
import net.minecraftforge.accesstransformer.service.AccessTransformerService;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.loading.progress.EarlyProgressVisualization;
|
||||
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
|
||||
import net.minecraftforge.fml.loading.targets.CommonLaunchHandler;
|
||||
import net.minecraftforge.forgespi.Environment;
|
||||
import net.minecraftforge.forgespi.coremod.ICoreModProvider;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
@@ -72,21 +58,16 @@ public class FMLLoader
|
||||
private static Dist dist;
|
||||
private static String naming;
|
||||
private static LoadingModList loadingModList;
|
||||
private static TransformingClassLoader launchClassLoader;
|
||||
private static RuntimeDistCleaner runtimeDistCleaner;
|
||||
private static Path gamePath;
|
||||
private static Path forgePath;
|
||||
private static Path[] mcPaths;
|
||||
static String mcVersion;
|
||||
private static String mcpVersion;
|
||||
static String forgeVersion;
|
||||
private static String forgeGroup;
|
||||
private static Predicate<String> classLoaderExclusions;
|
||||
private static VersionInfo versionInfo;
|
||||
private static String launchHandlerName;
|
||||
private static FMLCommonLaunchHandler commonLaunchHandler;
|
||||
private static CommonLaunchHandler commonLaunchHandler;
|
||||
public static Runnable progressWindowTick;
|
||||
private static ModValidator modValidator;
|
||||
public static BackgroundScanHandler backgroundScanHandler;
|
||||
private static boolean production;
|
||||
private static IModuleLayerManager moduleLayerManager;
|
||||
|
||||
static void onInitialLoad(IEnvironment environment, Set<String> otherServices) throws IncompatibleEnvironmentException
|
||||
{
|
||||
@@ -98,8 +79,6 @@ public class FMLLoader
|
||||
LOGGER.fatal(CORE,"Found incompatible ModLauncher specification : {}, version {} from {}", modLauncherPackage.getSpecificationVersion(), modLauncherPackage.getImplementationVersion(), modLauncherPackage.getImplementationVendor());
|
||||
throw new IncompatibleEnvironmentException("Incompatible modlauncher found "+modLauncherPackage.getSpecificationVersion());
|
||||
}
|
||||
LOGGER.debug(CORE, "Initializing modjar URL handler");
|
||||
URL.setURLStreamHandlerFactory(p->p.equals("modjar") ? new ModJarURLHandler() : null);
|
||||
|
||||
accessTransformer = (AccessTransformerService) environment.findLaunchPlugin("accesstransformer").orElseThrow(()-> {
|
||||
LOGGER.fatal(CORE,"Access Transformer library is missing, we need this to run");
|
||||
@@ -131,8 +110,7 @@ public class FMLLoader
|
||||
});
|
||||
LOGGER.debug(CORE, "Found Runtime Dist Cleaner");
|
||||
|
||||
final ArrayList<ICoreModProvider> coreModProviders = new ArrayList<>();
|
||||
ServiceLoaderStreamUtils.errorHandlingServiceLoader(ICoreModProvider.class, serviceConfigurationError -> LOGGER.fatal(CORE, "Failed to load a coremod library, expect problems", serviceConfigurationError)).forEach(coreModProviders::add);
|
||||
var coreModProviders = ServiceLoaderUtils.streamWithErrorHandling(ServiceLoader.load(FMLLoader.class.getModule().getLayer(), ICoreModProvider.class), sce -> LOGGER.fatal(CORE, "Failed to load a coremod library, expect problems", sce)).toList();
|
||||
|
||||
if (coreModProviders.isEmpty()) {
|
||||
LOGGER.fatal(CORE, "Found no coremod provider. Cannot run");
|
||||
@@ -161,62 +139,56 @@ public class FMLLoader
|
||||
LOGGER.fatal(CORE, "Failed to load NightConfig");
|
||||
throw new IncompatibleEnvironmentException("Missing NightConfig");
|
||||
}
|
||||
FixSSL.fixup();
|
||||
}
|
||||
|
||||
static void setupLaunchHandler(final IEnvironment environment, final Map<String, ?> arguments)
|
||||
static void setupLaunchHandler(final IEnvironment environment, final Map<String, Object> arguments)
|
||||
{
|
||||
final String launchTarget = environment.getProperty(IEnvironment.Keys.LAUNCHTARGET.get()).orElse("MISSING");
|
||||
arguments.put("launchTarget", launchTarget);
|
||||
final Optional<ILaunchHandlerService> launchHandler = environment.findLaunchHandler(launchTarget);
|
||||
LOGGER.debug(CORE, "Using {} as launch service", launchTarget);
|
||||
if (!launchHandler.isPresent()) {
|
||||
if (launchHandler.isEmpty()) {
|
||||
LOGGER.fatal(CORE,"Missing LaunchHandler {}, cannot continue", launchTarget);
|
||||
throw new RuntimeException("Missing launch handler");
|
||||
throw new RuntimeException("Missing launch handler: " + launchTarget);
|
||||
}
|
||||
|
||||
if (!(launchHandler.get() instanceof FMLCommonLaunchHandler)) {
|
||||
if (!(launchHandler.get() instanceof CommonLaunchHandler)) {
|
||||
LOGGER.fatal(CORE, "Incompatible Launch handler found - type {}, cannot continue", launchHandler.get().getClass().getName());
|
||||
throw new RuntimeException("Incompatible launch handler found");
|
||||
}
|
||||
commonLaunchHandler = (CommonLaunchHandler)launchHandler.get();
|
||||
launchHandlerName = launchHandler.get().name();
|
||||
gamePath = environment.getProperty(IEnvironment.Keys.GAMEDIR.get()).orElse(Paths.get(".").toAbsolutePath());
|
||||
|
||||
commonLaunchHandler = (FMLCommonLaunchHandler)launchHandler.get();
|
||||
naming = commonLaunchHandler.getNaming();
|
||||
dist = commonLaunchHandler.getDist();
|
||||
production = commonLaunchHandler.isProduction();
|
||||
progressWindowTick = EarlyProgressVisualization.INSTANCE.accept(dist, commonLaunchHandler.isData());
|
||||
|
||||
versionInfo = new VersionInfo(arguments);
|
||||
|
||||
StartupMessageManager.modLoaderConsumer().ifPresent(c->c.accept("Early Loading!"));
|
||||
accessTransformer.getExtension().accept(Pair.of(naming, "srg"));
|
||||
|
||||
mcVersion = (String) arguments.get("mcVersion");
|
||||
mcpVersion = (String) arguments.get("mcpVersion");
|
||||
forgeVersion = (String) arguments.get("forgeVersion");
|
||||
forgeGroup = (String) arguments.get("forgeGroup");
|
||||
|
||||
LOGGER.debug(CORE,"Received command line version data : MC Version: '{}' MCP Version: '{}' Forge Version: '{}' Forge group: '{}'", mcVersion, mcpVersion, forgeVersion, forgeGroup);
|
||||
forgePath = commonLaunchHandler.getForgePath(mcVersion, forgeVersion, forgeGroup);
|
||||
mcPaths = commonLaunchHandler.getMCPaths(mcVersion, mcpVersion, forgeVersion, forgeGroup);
|
||||
|
||||
commonLaunchHandler.validatePaths(forgePath, mcPaths, forgeVersion, mcVersion, mcpVersion);
|
||||
commonLaunchHandler.setup(environment, arguments);
|
||||
classLoaderExclusions = commonLaunchHandler.getPackagePredicate();
|
||||
|
||||
languageLoadingProvider = new LanguageLoadingProvider();
|
||||
languageLoadingProvider.addForgeLanguage(forgePath);
|
||||
LOGGER.debug(CORE,"Received command line version data : {}", versionInfo);
|
||||
|
||||
runtimeDistCleaner.getExtension().accept(dist);
|
||||
progressWindowTick.run();
|
||||
}
|
||||
public static Map<IModFile.Type, List<ModFile>> beginModScan(final Map<String,?> arguments)
|
||||
public static List<ITransformationService.Resource> beginModScan(final Map<String,?> arguments)
|
||||
{
|
||||
LOGGER.debug(SCAN,"Scanning for Mod Locators");
|
||||
modDiscoverer = new ModDiscoverer(arguments);
|
||||
backgroundScanHandler = modDiscoverer.discoverMods();
|
||||
modValidator = modDiscoverer.discoverMods();
|
||||
var pluginResources = modValidator.getPluginResources();
|
||||
return List.of(pluginResources);
|
||||
}
|
||||
|
||||
public static List<ITransformationService.Resource> completeScan(IModuleLayerManager layerManager) {
|
||||
progressWindowTick = EarlyProgressVisualization.INSTANCE.accept(dist, commonLaunchHandler.isData(), versionInfo.mcVersion());
|
||||
moduleLayerManager = layerManager;
|
||||
languageLoadingProvider = new LanguageLoadingProvider();
|
||||
backgroundScanHandler = modValidator.stage2Validation();
|
||||
loadingModList = backgroundScanHandler.getLoadingModList();
|
||||
commonLaunchHandler.addLibraries(backgroundScanHandler.getModFiles().getOrDefault(IModFile.Type.LIBRARY, Collections.emptyList()));
|
||||
progressWindowTick.run();
|
||||
return loadingModList.getModFiles().stream().map(ModFileInfo::getFile).collect(Collectors.groupingBy(ModFile::getType));
|
||||
return List.of(modValidator.getModResources());
|
||||
}
|
||||
|
||||
public static ICoreModProvider getCoreModProvider() {
|
||||
@@ -232,6 +204,10 @@ public class FMLLoader
|
||||
return modDiscoverer;
|
||||
}
|
||||
|
||||
public static CommonLaunchHandler getLaunchHandler() {
|
||||
return commonLaunchHandler;
|
||||
}
|
||||
|
||||
public static void addAccessTransformer(Path atPath, ModFile modName)
|
||||
{
|
||||
LOGGER.debug(SCAN, "Adding Access Transformer in {}", modName.getFilePath());
|
||||
@@ -243,9 +219,8 @@ public class FMLLoader
|
||||
return dist;
|
||||
}
|
||||
|
||||
public static void beforeStart(ITransformingClassLoader launchClassLoader)
|
||||
public static void beforeStart(ClassLoader launchClassLoader)
|
||||
{
|
||||
FMLLoader.launchClassLoader = (TransformingClassLoader) launchClassLoader.getInstance();
|
||||
StartupMessageManager.modLoaderConsumer().ifPresent(c->c.accept("Launching minecraft"));
|
||||
progressWindowTick.run();
|
||||
}
|
||||
@@ -255,28 +230,11 @@ public class FMLLoader
|
||||
return loadingModList;
|
||||
}
|
||||
|
||||
public static TransformingClassLoader getLaunchClassLoader()
|
||||
{
|
||||
return launchClassLoader;
|
||||
}
|
||||
|
||||
public static Path getGamePath()
|
||||
{
|
||||
return gamePath;
|
||||
}
|
||||
|
||||
public static Path getForgePath() {
|
||||
return forgePath;
|
||||
}
|
||||
|
||||
public static Path[] getMCPaths() {
|
||||
return mcPaths;
|
||||
}
|
||||
|
||||
public static Predicate<String> getClassLoaderExclusions() {
|
||||
return classLoaderExclusions;
|
||||
}
|
||||
|
||||
public static String getNaming() {
|
||||
return naming;
|
||||
}
|
||||
@@ -285,10 +243,6 @@ public class FMLLoader
|
||||
return Launcher.INSTANCE.environment().findNameMapping(naming);
|
||||
}
|
||||
|
||||
public static String getMcpVersion() {
|
||||
return mcpVersion;
|
||||
}
|
||||
|
||||
public static String getLauncherInfo() {
|
||||
return Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.MLIMPL_VERSION.get()).orElse("MISSING");
|
||||
}
|
||||
@@ -306,6 +260,14 @@ public class FMLLoader
|
||||
}
|
||||
|
||||
public static boolean isSecureJarEnabled() {
|
||||
return Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.SECURED_JARS_ENABLED.get()).orElse(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ModuleLayer getGameLayer() {
|
||||
return moduleLayerManager.getLayer(IModuleLayerManager.Layer.GAME).orElseThrow();
|
||||
}
|
||||
|
||||
public static VersionInfo versionInfo() {
|
||||
return versionInfo;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+21
-30
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -19,35 +19,27 @@
|
||||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ITransformationService;
|
||||
import cpw.mods.modlauncher.api.ITransformer;
|
||||
import cpw.mods.modlauncher.api.IncompatibleEnvironmentException;
|
||||
import cpw.mods.modlauncher.api.*;
|
||||
import joptsimple.ArgumentAcceptingOptionSpec;
|
||||
import joptsimple.OptionSpecBuilder;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.forgespi.Environment;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.nio.file.Path;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public class FMLServiceProvider implements ITransformationService
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private ArgumentAcceptingOptionSpec<String> modsOption;
|
||||
private ArgumentAcceptingOptionSpec<String> modListsOption;
|
||||
@@ -67,6 +59,12 @@ public class FMLServiceProvider implements ITransformationService
|
||||
private String targetForgeGroup;
|
||||
private Map<String, Object> arguments;
|
||||
|
||||
public FMLServiceProvider()
|
||||
{
|
||||
final String markerselection = System.getProperty("forge.logging.markers", "");
|
||||
Arrays.stream(markerselection.split(",")).forEach(marker -> System.setProperty("forge.logging.marker." + marker.toLowerCase(Locale.ROOT), "ACCEPT"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
@@ -80,7 +78,7 @@ public class FMLServiceProvider implements ITransformationService
|
||||
LOGGER.debug(CORE, "Loading configuration");
|
||||
FMLConfig.load();
|
||||
LOGGER.debug(CORE, "Preparing ModFile");
|
||||
environment.computePropertyIfAbsent(Environment.Keys.MODFILEFACTORY.get(), k->ModFile.buildFactory());
|
||||
environment.computePropertyIfAbsent(Environment.Keys.MODFILEFACTORY.get(), k->ModFile::new);
|
||||
arguments = new HashMap<>();
|
||||
arguments.put("modLists", modListsArgumentList);
|
||||
arguments.put("mods", modsArgumentList);
|
||||
@@ -97,28 +95,22 @@ public class FMLServiceProvider implements ITransformationService
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginScanning(final IEnvironment environment) {
|
||||
throw new IllegalStateException("WHY ARE YOU HERE??????");
|
||||
public List<Resource> beginScanning(final IEnvironment environment) {
|
||||
LOGGER.debug(CORE,"Initiating mod scan");
|
||||
return FMLLoader.beginModScan(arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map.Entry<String, Path>> runScan(final IEnvironment environment) {
|
||||
LOGGER.debug(CORE,"Initiating mod scan");
|
||||
final Map<IModFile.Type, List<ModFile>> foundFiles = FMLLoader.beginModScan(arguments);
|
||||
return foundFiles
|
||||
.values()
|
||||
.stream()
|
||||
.flatMap(Collection::stream)
|
||||
.map(modFile -> new AbstractMap.SimpleImmutableEntry<>(modFile.getFileName(), modFile.getFilePath()))
|
||||
.collect(Collectors.toList());
|
||||
public List<Resource> completeScan(final IModuleLayerManager layerManager) {
|
||||
return FMLLoader.completeScan(layerManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad(IEnvironment environment, Set<String> otherServices) throws IncompatibleEnvironmentException
|
||||
{
|
||||
LOGGER.debug("Injecting tracing printstreams for STDOUT/STDERR.");
|
||||
System.setOut(new TracingPrintStream(LogManager.getLogger("STDOUT"), System.out));
|
||||
System.setErr(new TracingPrintStream(LogManager.getLogger("STDERR"), System.err));
|
||||
// LOGGER.debug("Injecting tracing printstreams for STDOUT/STDERR.");
|
||||
// System.setOut(new TracingPrintStream(LogManager.getLogger("STDOUT"), System.out));
|
||||
// System.setErr(new TracingPrintStream(LogManager.getLogger("STDERR"), System.err));
|
||||
FMLLoader.onInitialLoad(environment, otherServices);
|
||||
}
|
||||
|
||||
@@ -148,9 +140,8 @@ public class FMLServiceProvider implements ITransformationService
|
||||
targetMcpMappings = option.value(mappingsOption);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<ITransformer> transformers()
|
||||
public @NotNull List<ITransformer> transformers()
|
||||
{
|
||||
LOGGER.debug(CORE, "Loading coremod transformers");
|
||||
return new ArrayList<>(FMLLoader.getCoreModProvider().getCoreModTransformers());
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+12
-28
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -19,7 +19,9 @@
|
||||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import cpw.mods.modlauncher.ServiceLoaderStreamUtils;
|
||||
import cpw.mods.modlauncher.Launcher;
|
||||
import cpw.mods.modlauncher.api.IModuleLayerManager;
|
||||
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
|
||||
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
|
||||
import net.minecraftforge.forgespi.language.IModLanguageProvider;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ExplodedDirectoryLocator;
|
||||
@@ -30,11 +32,7 @@ import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@@ -49,13 +47,12 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.rethrowFunction;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
|
||||
|
||||
public class LanguageLoadingProvider
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final LanguageClassLoader languageClassLoader;
|
||||
private final List<IModLanguageProvider> languageProviders = new ArrayList<>();
|
||||
private final ServiceLoader<IModLanguageProvider> serviceLoader;
|
||||
private final Map<String, ModLanguageWrapper> languageProviderMap = new HashMap<>();
|
||||
@@ -71,7 +68,6 @@ public class LanguageLoadingProvider
|
||||
}
|
||||
|
||||
private static class ModLanguageWrapper {
|
||||
|
||||
private final IModLanguageProvider modLanguageProvider;
|
||||
|
||||
private final ArtifactVersion version;
|
||||
@@ -92,26 +88,14 @@ public class LanguageLoadingProvider
|
||||
|
||||
|
||||
}
|
||||
private static class LanguageClassLoader extends URLClassLoader
|
||||
{
|
||||
public LanguageClassLoader() {
|
||||
super(new URL[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(final URL url) {
|
||||
LOGGER.debug(CORE, "Adding {} to languageloader classloader", url);
|
||||
super.addURL(url);
|
||||
}
|
||||
|
||||
}
|
||||
LanguageLoadingProvider() {
|
||||
languageClassLoader = new LanguageClassLoader();
|
||||
serviceLoader = ServiceLoader.load(IModLanguageProvider.class, languageClassLoader);
|
||||
var sl = Launcher.INSTANCE.environment().findModuleLayerManager().flatMap(lm->lm.getLayer(IModuleLayerManager.Layer.PLUGIN)).orElseThrow();
|
||||
serviceLoader = ServiceLoader.load(sl, IModLanguageProvider.class);
|
||||
loadLanguageProviders();
|
||||
}
|
||||
private void loadLanguageProviders() {
|
||||
LOGGER.debug(CORE, "Found {} language providers", ServiceLoaderStreamUtils.toList(serviceLoader).size());
|
||||
LOGGER.debug(CORE, "Found {} language providers", ServiceLoaderUtils.streamServiceLoader(()->serviceLoader, sce->LOGGER.fatal("Problem with language loaders")).count());
|
||||
serviceLoader.forEach(languageProviders::add);
|
||||
|
||||
languageProviders.forEach(lp -> {
|
||||
@@ -122,7 +106,7 @@ public class LanguageLoadingProvider
|
||||
throw new RuntimeException("Huh?", e);
|
||||
}
|
||||
Optional<String> implementationVersion = JarVersionLookupHandler.getImplementationVersion(lp.getClass());
|
||||
String impl = implementationVersion.orElse(Files.isDirectory(lpPath) ? FMLLoader.forgeVersion.split("\\.")[0] : null);
|
||||
String impl = implementationVersion.orElse(Files.isDirectory(lpPath) ? FMLLoader.versionInfo().forgeVersion().split("\\.")[0] : null);
|
||||
if (impl == null) {
|
||||
LOGGER.fatal(CORE, "Found unversioned language provider {}", lp.name());
|
||||
throw new RuntimeException("Failed to find implementation version for language provider "+ lp.name());
|
||||
@@ -147,7 +131,7 @@ public class LanguageLoadingProvider
|
||||
private void addLanguagePaths(final Stream<Path> langPaths) {
|
||||
languageProviders.clear();
|
||||
languageProviderMap.clear();
|
||||
langPaths.peek(languagePaths::add).map(Path::toFile).map(File::toURI).map(rethrowFunction(URI::toURL)).forEach(languageClassLoader::addURL);
|
||||
// langPaths.peek(languagePaths::add).map(Path::toFile).map(File::toURI).map(rethrowFunction(URI::toURL)).forEach(languageClassLoader::addURL);
|
||||
}
|
||||
|
||||
public void addAdditionalLanguages(List<ModFile> modFiles)
|
||||
@@ -167,11 +151,11 @@ public class LanguageLoadingProvider
|
||||
final String languageFileName = mf.getLocator() instanceof ExplodedDirectoryLocator ? "in-development" : mf.getFileName();
|
||||
final ModLanguageWrapper mlw = languageProviderMap.get(modLoader);
|
||||
if (mlw == null) {
|
||||
LOGGER.error("Missing language {} version {} wanted by {}", modLoader, modLoaderVersion, languageFileName);
|
||||
LOGGER.error(LOADING,"Missing language {} version {} wanted by {}", modLoader, modLoaderVersion, languageFileName);
|
||||
throw new EarlyLoadingException("Missing language "+modLoader, null, Collections.singletonList(new EarlyLoadingException.ExceptionData("fml.language.missingversion", modLoader, modLoaderVersion, languageFileName, "null")));
|
||||
}
|
||||
if (!VersionSupportMatrix.testVersionSupportMatrix(modLoaderVersion, modLoader, "languageloader", (llid, range) -> range.containsVersion(mlw.getVersion()))) {
|
||||
LOGGER.error("Missing language {} version {} wanted by {}, found {}", modLoader, modLoaderVersion, languageFileName, mlw.getVersion());
|
||||
LOGGER.error(LOADING,"Missing language {} version {} wanted by {}, found {}", modLoader, modLoaderVersion, languageFileName, mlw.getVersion());
|
||||
throw new EarlyLoadingException("Missing language "+ modLoader + " matching range "+modLoaderVersion + " found "+mlw.getVersion(), null, Collections.singletonList(new EarlyLoadingException.ExceptionData("fml.language.missingversion", modLoader, modLoaderVersion, languageFileName, mlw.getVersion())));
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+16
-38
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -22,54 +22,25 @@ package net.minecraftforge.fml.loading;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public class LibraryFinder {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static Path libsPath;
|
||||
static Path findLibsPath() {
|
||||
if (libsPath == null) {
|
||||
final Path asm = findJarPathFor("org/objectweb/asm/Opcodes.class", "asm");
|
||||
// go up SIX parents to find the libs dir
|
||||
final Path libs = asm.getParent().getParent().getParent().getParent().getParent().getParent();
|
||||
LOGGER.debug(CORE, "Found probable library path {}", libs);
|
||||
libsPath = libs;
|
||||
libsPath = Path.of(System.getProperty("libraryDirectory","crazysnowmannonsense/cheezwhizz"));
|
||||
if (!Files.isDirectory(libsPath)) {
|
||||
throw new IllegalStateException("Missing libraryDirectory system property, cannot continue");
|
||||
}
|
||||
}
|
||||
return libsPath;
|
||||
}
|
||||
|
||||
public static Path findJarPathFor(final String className, final String jarName) {
|
||||
final URL resource = LibraryFinder.class.getClassLoader().getResource(className);
|
||||
return findJarPathFor(className, jarName, resource);
|
||||
}
|
||||
|
||||
public static Path findJarPathFor(final String resourceName, final String jarName, final URL resource) {
|
||||
try {
|
||||
Path path;
|
||||
final URI uri = resource.toURI();
|
||||
if (uri.getRawSchemeSpecificPart().contains("!")) {
|
||||
path = Paths.get(new URI(uri.getRawSchemeSpecificPart().split("!")[0]));
|
||||
} else {
|
||||
path = Paths.get(new URI("file://"+uri.getRawSchemeSpecificPart().substring(0, uri.getRawSchemeSpecificPart().length()-resourceName.length())));
|
||||
}
|
||||
LOGGER.debug(CORE, "Found JAR {} at path {}", jarName, path.toString());
|
||||
return path;
|
||||
} catch (NullPointerException | URISyntaxException e) {
|
||||
LOGGER.fatal(CORE, "Failed to find JAR for class {} - {}", resourceName, jarName);
|
||||
throw new RuntimeException("Unable to locate "+resourceName+" - "+jarName, e);
|
||||
}
|
||||
}
|
||||
|
||||
static Path getForgeLibraryPath(final String mcVersion, final String forgeVersion, final String forgeGroup) {
|
||||
Path forgePath = findLibsPath().resolve(MavenCoordinateResolver.get(forgeGroup, "forge", "", "universal", mcVersion+"-"+forgeVersion));
|
||||
LOGGER.debug(CORE, "Found forge path {} is {}", forgePath, pathStatus(forgePath));
|
||||
LOGGER.debug(LogMarkers.CORE, "Found forge path {} is {}", forgePath, pathStatus(forgePath));
|
||||
return forgePath;
|
||||
}
|
||||
|
||||
@@ -81,9 +52,16 @@ public class LibraryFinder {
|
||||
Path srgMcPath = findLibsPath().resolve(MavenCoordinateResolver.get("net.minecraft", type, "", "srg", mcVersion+"-"+mcpVersion));
|
||||
Path mcExtrasPath = findLibsPath().resolve(MavenCoordinateResolver.get("net.minecraft", type, "", "extra", mcVersion+"-"+mcpVersion));
|
||||
Path patchedBinariesPath = findLibsPath().resolve(MavenCoordinateResolver.get(forgeGroup, "forge", "", type, mcVersion+"-"+forgeVersion));
|
||||
LOGGER.debug(CORE,"SRG MC at {} is {}", srgMcPath.toString(), pathStatus(srgMcPath));
|
||||
LOGGER.debug(CORE,"MC Extras at {} is {}", mcExtrasPath.toString(), pathStatus(mcExtrasPath));
|
||||
LOGGER.debug(CORE,"Forge patches at {} is {}", patchedBinariesPath.toString(), pathStatus(patchedBinariesPath));
|
||||
LOGGER.debug(LogMarkers.CORE,"SRG MC at {} is {}", srgMcPath.toString(), pathStatus(srgMcPath));
|
||||
LOGGER.debug(LogMarkers.CORE,"MC Extras at {} is {}", mcExtrasPath.toString(), pathStatus(mcExtrasPath));
|
||||
LOGGER.debug(LogMarkers.CORE,"Forge patches at {} is {}", patchedBinariesPath.toString(), pathStatus(patchedBinariesPath));
|
||||
return new Path[] { patchedBinariesPath, mcExtrasPath, srgMcPath };
|
||||
}
|
||||
|
||||
public static Path findPathForMaven(final String group, final String artifact, final String extension, final String classifier, final String version) {
|
||||
return findLibsPath().resolve(MavenCoordinateResolver.get(group, artifact, extension, classifier, version));
|
||||
}
|
||||
public static Path findPathForMaven(final String maven) {
|
||||
return findLibsPath().resolve(MavenCoordinateResolver.get(maven));
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -41,8 +41,6 @@ public class LoadingModList
|
||||
private final List<ModFileInfo> modFiles;
|
||||
private final List<ModInfo> sortedList;
|
||||
private final Map<String, ModFileInfo> fileById;
|
||||
@SuppressWarnings("unused")
|
||||
private BackgroundScanHandler scanner;
|
||||
private final List<EarlyLoadingException> preLoadErrors;
|
||||
private List<ModFile> brokenFiles;
|
||||
|
||||
@@ -94,7 +92,6 @@ public class LoadingModList
|
||||
|
||||
public void addForScanning(BackgroundScanHandler backgroundScanHandler)
|
||||
{
|
||||
this.scanner = backgroundScanHandler;
|
||||
backgroundScanHandler.setLoadingModList(this);
|
||||
modFiles.stream()
|
||||
.map(ModFileInfo::getFile)
|
||||
+1
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -27,5 +27,4 @@ public class LogMarkers {
|
||||
public static final Marker LOADING = MarkerManager.getMarker("LOADING");
|
||||
public static final Marker SCAN = MarkerManager.getMarker("SCAN");
|
||||
public static final Marker SPLASH = MarkerManager.getMarker("SPLASH");
|
||||
public static final Marker FORGEMOD = MarkerManager.getMarker("FORGEMOD").addParents(LOADING);
|
||||
}
|
||||
+9
-35
@@ -1,23 +1,4 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.userdev;
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import cpw.mods.modlauncher.api.INameMappingService;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
@@ -33,8 +14,6 @@ import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public class MCPNamingService implements INameMappingService {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private HashMap<String, String> methods;
|
||||
@@ -47,7 +26,7 @@ public class MCPNamingService implements INameMappingService {
|
||||
|
||||
@Override
|
||||
public String mappingVersion() {
|
||||
return "1234";
|
||||
return "1234"; //TODO: Minecraft Version?
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,7 +56,7 @@ public class MCPNamingService implements INameMappingService {
|
||||
HashMap<String,String> tmpmethods = new HashMap<>(1000);
|
||||
loadMappings("methods.csv", tmpmethods::put);
|
||||
methods = tmpmethods;
|
||||
LOGGER.debug(CORE, "Loaded {} method mappings from methods.csv", methods.size());
|
||||
LOGGER.debug(LogMarkers.CORE, "Loaded {} method mappings from methods.csv", methods.size());
|
||||
}
|
||||
return methods.getOrDefault(origin, origin);
|
||||
}
|
||||
@@ -87,25 +66,20 @@ public class MCPNamingService implements INameMappingService {
|
||||
HashMap<String,String> tmpfields = new HashMap<>(1000);
|
||||
loadMappings("fields.csv", tmpfields::put);
|
||||
fields = tmpfields;
|
||||
LOGGER.debug(CORE, "Loaded {} field mappings from fields.csv", fields.size());
|
||||
LOGGER.debug(LogMarkers.CORE, "Loaded {} field mappings from fields.csv", fields.size());
|
||||
}
|
||||
return fields.getOrDefault(origin, origin);
|
||||
}
|
||||
|
||||
|
||||
private static void loadMappings(final String mappingFileName, BiConsumer<String, String> mapStore)
|
||||
{
|
||||
URL path = ClassLoader.getSystemResource(mappingFileName); //We EXPLICITLY go throught the SystemClassLoader here because this is dev-time only. And will be on the root classpath.
|
||||
private static void loadMappings(final String mappingFileName, BiConsumer<String, String> mapStore) {
|
||||
URL path = ClassLoader.getSystemResource(mappingFileName); //We EXPLICITLY go through the SystemClassLoader here because this is dev-time only. And will be on the root classpath.
|
||||
if (path == null)
|
||||
return;
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(path.openStream())))
|
||||
{
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(path.openStream()))) {
|
||||
reader.lines().skip(1).map(e -> e.split(",")).forEach(e -> mapStore.accept(e[0], e[1]));
|
||||
}
|
||||
catch (IOException e1)
|
||||
{
|
||||
LOGGER.error(CORE, "Error reading mappings", e1);
|
||||
} catch (IOException e1) {
|
||||
LOGGER.error(LogMarkers.CORE, "Error reading mappings", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
+10
-20
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -20,6 +20,7 @@
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
|
||||
import cpw.mods.modlauncher.api.NamedPath;
|
||||
import cpw.mods.modlauncher.serviceapi.ITransformerDiscoveryService;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
@@ -33,36 +34,25 @@ import java.util.zip.ZipFile;
|
||||
|
||||
public class ModDirTransformerDiscoverer implements ITransformerDiscoveryService {
|
||||
@Override
|
||||
public List<Path> candidates(final Path gameDirectory) {
|
||||
public List<NamedPath> candidates(final Path gameDirectory) {
|
||||
ModDirTransformerDiscoverer.scan(gameDirectory);
|
||||
return ModDirTransformerDiscoverer.transformers;
|
||||
return List.copyOf(found);
|
||||
}
|
||||
|
||||
private static List<Path> transformers = new ArrayList<>();
|
||||
private static List<Path> locators = new ArrayList<>();
|
||||
private final static List<NamedPath> found = new ArrayList<>();
|
||||
|
||||
public static List<Path> allExcluded() {
|
||||
ArrayList<Path> paths = new ArrayList<>();
|
||||
paths.addAll(transformers);
|
||||
paths.addAll(locators);
|
||||
return paths;
|
||||
}
|
||||
|
||||
public static List<Path> getExtraLocators() {
|
||||
return locators;
|
||||
return found.stream().map(np->np.paths()[0]).toList();
|
||||
}
|
||||
|
||||
private static void scan(final Path gameDirectory) {
|
||||
final Path modsDir = gameDirectory.resolve(FMLPaths.MODSDIR.relative()).toAbsolutePath().normalize();
|
||||
transformers = new ArrayList<>();
|
||||
locators = new ArrayList<>();
|
||||
if (!Files.exists(modsDir)) {
|
||||
// Skip if the mods dir doesn't exist yet.
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Files.createDirectories(modsDir);
|
||||
Files.walk(modsDir, 1).forEach(ModDirTransformerDiscoverer::visitFile);
|
||||
try (var walk = Files.walk(modsDir, 1)){
|
||||
walk.forEach(ModDirTransformerDiscoverer::visitFile);
|
||||
} catch (IOException | IllegalStateException ioe) {
|
||||
LogManager.getLogger().error("Error during early discovery", ioe);
|
||||
}
|
||||
@@ -74,9 +64,9 @@ public class ModDirTransformerDiscoverer implements ITransformerDiscoveryService
|
||||
if (LamdbaExceptionUtils.uncheck(() -> Files.size(path)) == 0) return;
|
||||
try (ZipFile zf = new ZipFile(new File(path.toUri()))) {
|
||||
if (zf.getEntry("META-INF/services/cpw.mods.modlauncher.api.ITransformationService") != null) {
|
||||
transformers.add(path);
|
||||
found.add(new NamedPath(zf.getName(), path));
|
||||
} else if (zf.getEntry("META-INF/services/net.minecraftforge.forgespi.locating.IModLocator") != null) {
|
||||
locators.add(path);
|
||||
found.add(new NamedPath(zf.getName(), path));
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
LogManager.getLogger().error("Zip Error when loading jar file {}", path, ioe);
|
||||
+8
-8
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -70,13 +70,13 @@ public class ModJarURLHandler extends URLStreamHandler
|
||||
@Override
|
||||
public void connect()
|
||||
{
|
||||
if (resource == null) {
|
||||
modid = url.getHost();
|
||||
// trim first char
|
||||
modpath = url.getPath().substring(1);
|
||||
resource = FMLLoader.getLoadingModList().getModFileById(modid).getFile().findResource(modpath);
|
||||
manifest = FMLLoader.getLoadingModList().getModFileById(modid).getManifest();
|
||||
}
|
||||
// if (resource == null) {
|
||||
// modid = url.getHost();
|
||||
// // trim first char
|
||||
// modpath = url.getPath().substring(1);
|
||||
// resource = FMLLoader.getLoadingModList().getModFileById(modid).getFile().findResource(modpath);
|
||||
// manifest = FMLLoader.getLoadingModList().getModFileById(modid).getManifest();
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
+83
-105
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -32,7 +32,6 @@ import net.minecraftforge.fml.loading.toposort.TopologicalSort;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.util.StringBuilderFormattable;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
|
||||
@@ -42,6 +41,7 @@ import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.stream.Collectors.*;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
|
||||
|
||||
public class ModSorter
|
||||
@@ -57,22 +57,20 @@ public class ModSorter
|
||||
this.modFiles = modFiles;
|
||||
}
|
||||
|
||||
public static LoadingModList sort(List<ModFile> mods)
|
||||
public static LoadingModList sort(List<ModFile> mods, final List<ExceptionData> errors)
|
||||
{
|
||||
final ModSorter ms = new ModSorter(mods);
|
||||
try {
|
||||
ms.buildUniqueList();
|
||||
} catch (EarlyLoadingException e) {
|
||||
// We cannot build any list with duped mods. We have to abort immediately and report it
|
||||
return LoadingModList.of(ms.forgeAndMC, ms.forgeAndMC.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).collect(Collectors.toList()), e);
|
||||
return LoadingModList.of(ms.forgeAndMC, ms.forgeAndMC.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).collect(toList()), e);
|
||||
}
|
||||
// try and locate languages and validate dependencies
|
||||
List<EarlyLoadingException.ExceptionData> missingLangs = ms.findLanguages();
|
||||
List<EarlyLoadingException.ExceptionData> missingDeps = ms.verifyDependencyVersions();
|
||||
final List<ExceptionData> failedList = Stream.concat(missingLangs.stream(), missingDeps.stream()).collect(Collectors.toList());
|
||||
// try and validate dependencies
|
||||
final List<ExceptionData> failedList = Stream.concat(ms.verifyDependencyVersions().stream(), errors.stream()).toList();
|
||||
// if we miss one or the other, we abort now
|
||||
if (!failedList.isEmpty()) {
|
||||
return LoadingModList.of(ms.forgeAndMC, ms.forgeAndMC.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).collect(Collectors.toList()), new EarlyLoadingException("failure to validate mod list", null, failedList));
|
||||
return LoadingModList.of(ms.forgeAndMC, ms.forgeAndMC.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).collect(toList()), new EarlyLoadingException("failure to validate mod list", null, failedList));
|
||||
} else {
|
||||
// Otherwise, lets try and sort the modlist and proceed
|
||||
EarlyLoadingException earlyLoadingException = null;
|
||||
@@ -85,35 +83,22 @@ public class ModSorter
|
||||
}
|
||||
}
|
||||
|
||||
private List<EarlyLoadingException.ExceptionData> findLanguages() {
|
||||
List<EarlyLoadingException.ExceptionData> errorData = new ArrayList<>();
|
||||
modFiles.forEach(modFile -> {
|
||||
try {
|
||||
modFile.identifyLanguage();
|
||||
} catch (EarlyLoadingException e) {
|
||||
errorData.addAll(e.getAllData());
|
||||
}
|
||||
});
|
||||
return errorData;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
private void sort()
|
||||
{
|
||||
// lambdas are identity based, so sorting them is impossible unless you hold reference to them
|
||||
final MutableGraph<ModFileInfo> graph = GraphBuilder.directed().build();
|
||||
AtomicInteger counter = new AtomicInteger();
|
||||
Map<IModFileInfo, Integer> infos = modFiles
|
||||
.stream()
|
||||
Map<IModFileInfo, Integer> infos = modFiles.stream()
|
||||
.map(ModFile::getModFileInfo)
|
||||
.collect(Collectors.toMap(Function.identity(), e -> counter.incrementAndGet()));
|
||||
.filter(ModFileInfo.class::isInstance)
|
||||
.collect(toMap(Function.identity(), e -> counter.incrementAndGet()));
|
||||
infos.keySet().forEach(i -> graph.addNode((ModFileInfo) i));
|
||||
modFiles
|
||||
.stream()
|
||||
modFiles.stream()
|
||||
.map(ModFile::getModInfos)
|
||||
.flatMap(Collection::stream)
|
||||
.<IModInfo>mapMulti(Iterable::forEach)
|
||||
.map(IModInfo::getDependencies)
|
||||
.flatMap(Collection::stream)
|
||||
.<IModInfo.ModVersion>mapMulti(Iterable::forEach)
|
||||
.forEach(dep -> addDependency(graph, dep));
|
||||
|
||||
final List<ModFileInfo> sorted;
|
||||
@@ -124,33 +109,27 @@ public class ModSorter
|
||||
catch (CyclePresentException e)
|
||||
{
|
||||
Set<Set<ModFileInfo>> cycles = e.getCycles();
|
||||
LOGGER.error(LOADING, () -> ((StringBuilderFormattable) (buffer -> {
|
||||
buffer.append("Mod Sorting failed.\n");
|
||||
buffer.append("Detected Cycles: ");
|
||||
buffer.append(cycles);
|
||||
buffer.append('\n');
|
||||
})));
|
||||
List<ExceptionData> dataList = cycles.stream()
|
||||
.map(Set::stream)
|
||||
.map(stream -> stream
|
||||
.flatMap(modFileInfo -> modFileInfo.getMods()
|
||||
.stream()
|
||||
.map(IModInfo::getModId))
|
||||
.collect(Collectors.toList()))
|
||||
LOGGER.error(LOADING, () -> new AdvancedLogMessageAdapter(buffer ->
|
||||
buffer.append("Mod Sorting failed.\n")
|
||||
.append("Detected Cycles: ")
|
||||
.append(cycles)
|
||||
.append('\n')));
|
||||
var dataList = cycles.stream()
|
||||
.<ModFileInfo>mapMulti(Iterable::forEach)
|
||||
.<IModInfo>mapMulti((mf,c)->mf.getMods().forEach(c))
|
||||
.map(IModInfo::getModId)
|
||||
.map(list -> new ExceptionData("fml.modloading.cycle", list))
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
throw new EarlyLoadingException("Sorting error", e, dataList);
|
||||
}
|
||||
this.sortedList = sorted
|
||||
.stream()
|
||||
this.sortedList = sorted.stream()
|
||||
.map(ModFileInfo::getMods)
|
||||
.flatMap(Collection::stream)
|
||||
.<IModInfo>mapMulti(Iterable::forEach)
|
||||
.map(ModInfo.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
this.modFiles = sorted
|
||||
.stream()
|
||||
.collect(toList());
|
||||
this.modFiles = sorted.stream()
|
||||
.map(ModFileInfo::getFile)
|
||||
.collect(Collectors.toList());
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@@ -164,63 +143,59 @@ public class ModSorter
|
||||
if (self == target)
|
||||
return; // in case a jar has two mods that have dependencies between
|
||||
switch (dep.getOrdering()) {
|
||||
case BEFORE:
|
||||
topoGraph.putEdge(self, target);
|
||||
break;
|
||||
case AFTER:
|
||||
topoGraph.putEdge(target, self);
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
case BEFORE -> topoGraph.putEdge(self, target);
|
||||
case AFTER -> topoGraph.putEdge(target, self);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildUniqueList()
|
||||
{
|
||||
// Collect mod files by first modid in the file. This will be used for deduping purposes
|
||||
final Map<String, List<IModFile>> modFilesByFirstId = modFiles
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(mf -> mf.getModInfos().get(0).getModId()));
|
||||
// Collect mod files by module name. This will be used for deduping purposes
|
||||
final Map<String, List<IModFile>> modFilesByFirstId = modFiles.stream()
|
||||
.collect(groupingBy(mf -> mf.getModFileInfo().moduleName()));
|
||||
|
||||
// Capture forge and MC here, so we can keep them for later
|
||||
forgeAndMC = new ArrayList<>();
|
||||
forgeAndMC.add((ModFile)modFilesByFirstId.get("minecraft").get(0));
|
||||
forgeAndMC.add((ModFile)modFilesByFirstId.get("forge").get(0));
|
||||
var mc = modFilesByFirstId.get("minecraft");
|
||||
if (mc != null && !mc.isEmpty())
|
||||
forgeAndMC.add((ModFile) mc.get(0));
|
||||
else
|
||||
throw new IllegalStateException("Failed to find minecraft somehow?");
|
||||
// TODO: remove this hardcoding and make it more flexible
|
||||
var forge = modFilesByFirstId.get("forge");
|
||||
if (forge != null && !forge.isEmpty())
|
||||
forgeAndMC.add((ModFile) forge.get(0)); // Silently ignore if Forge isn't present
|
||||
|
||||
// Select the newest by artifact version sorting of non-unique files thus identified
|
||||
this.modFiles = modFilesByFirstId.entrySet().stream()
|
||||
.map(this::selectNewestModInfo)
|
||||
.map(Map.Entry::getValue)
|
||||
.map(ModFile.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
.collect(toList());
|
||||
|
||||
// Transform to the full mod id list
|
||||
final Map<String, List<ModInfo>> modIds = modFiles.stream()
|
||||
.map(ModFile::getModInfos)
|
||||
.flatMap(Collection::stream)
|
||||
.map(ModInfo.class::cast)
|
||||
.collect(Collectors.groupingBy(IModInfo::getModId));
|
||||
.collect(groupingBy(IModInfo::getModId));
|
||||
|
||||
// Its theoretically possible that some mod has somehow moved an id to a secondary place, thus causing a dupe.
|
||||
// We can't handle this
|
||||
final List<Map.Entry<String, List<ModInfo>>> dupedMods = modIds
|
||||
.entrySet()
|
||||
.stream()
|
||||
.filter(e -> e.getValue().size() > 1)
|
||||
.collect(Collectors.toList());
|
||||
final List<ModInfo> dupedMods = modIds.values().stream()
|
||||
.filter(modInfos -> modInfos.size() > 1)
|
||||
.map(modInfos -> modInfos.get(0))
|
||||
.toList();
|
||||
|
||||
if (!dupedMods.isEmpty()) {
|
||||
final List<EarlyLoadingException.ExceptionData> duplicateModErrors = dupedMods
|
||||
.stream()
|
||||
.map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedmod", dm.getValue().get(0), Objects.toString(dm.getValue().get(0))))
|
||||
.collect(Collectors.toList());
|
||||
final List<EarlyLoadingException.ExceptionData> duplicateModErrors = dupedMods.stream()
|
||||
.map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedmod",
|
||||
dm, Objects.toString(dm))).toList();
|
||||
throw new EarlyLoadingException("Duplicate mods found", null, duplicateModErrors);
|
||||
}
|
||||
|
||||
modIdNameLookup = modIds
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
|
||||
modIdNameLookup = modIds.entrySet().stream()
|
||||
.collect(toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
|
||||
}
|
||||
|
||||
private Map.Entry<String, IModFile> selectNewestModInfo(Map.Entry<String, List<IModFile>> fullList) {
|
||||
@@ -230,44 +205,47 @@ public class ModSorter
|
||||
modInfoList.sort(Comparator.<IModFile, ArtifactVersion>comparing(mf -> mf.getModInfos().get(0).getVersion()).reversed());
|
||||
LOGGER.debug("Selected file {} for modid {} with version {}", modInfoList.get(0).getFileName(), fullList.getKey(), modInfoList.get(0).getModInfos().get(0).getVersion());
|
||||
}
|
||||
return new AbstractMap.SimpleImmutableEntry<>(fullList.getKey(), modInfoList.get(0));
|
||||
return Map.entry(fullList.getKey(), modInfoList.get(0));
|
||||
}
|
||||
|
||||
private List<EarlyLoadingException.ExceptionData> verifyDependencyVersions()
|
||||
{
|
||||
final Map<String, ArtifactVersion> modVersions = modFiles
|
||||
.stream()
|
||||
final var modVersions = modFiles.stream()
|
||||
.map(ModFile::getModInfos)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toMap(IModInfo::getModId, IModInfo::getVersion));
|
||||
.<IModInfo>mapMulti(Iterable::forEach)
|
||||
.collect(toMap(IModInfo::getModId, IModInfo::getVersion));
|
||||
|
||||
final Map<IModInfo, List<IModInfo.ModVersion>> modVersionDependencies = modFiles
|
||||
.stream()
|
||||
final var modVersionDependencies = modFiles.stream()
|
||||
.map(ModFile::getModInfos)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.groupingBy(Function.identity(), Java9BackportUtils.flatMapping(e -> e.getDependencies().stream(), Collectors.toList())));
|
||||
.<IModInfo>mapMulti(Iterable::forEach)
|
||||
.collect(groupingBy(Function.identity(), flatMapping(e -> e.getDependencies().stream(), toList())));
|
||||
|
||||
final Set<IModInfo.ModVersion> mandatoryModVersions = modVersionDependencies
|
||||
.values()
|
||||
.stream()
|
||||
.flatMap(Collection::stream)
|
||||
.filter(mv -> mv.isMandatory() && mv.getSide().isCorrectSide())
|
||||
.collect(Collectors.toSet());
|
||||
final var modRequirements = modVersionDependencies.values().stream()
|
||||
.<IModInfo.ModVersion>mapMulti(Iterable::forEach)
|
||||
.filter(mv -> mv.getSide().isCorrectSide())
|
||||
.collect(toSet());
|
||||
|
||||
LOGGER.debug(LOADING, "Found {} mandatory requirements", mandatoryModVersions.size());
|
||||
final Set<IModInfo.ModVersion> missingVersions = mandatoryModVersions
|
||||
.stream()
|
||||
.filter(mv->this.modVersionNotContained(mv, modVersions))
|
||||
.collect(Collectors.toSet());
|
||||
LOGGER.debug(LOADING, "Found {} mandatory mod requirements missing", missingVersions.size());
|
||||
final long mandatoryRequired = modRequirements.stream().filter(IModInfo.ModVersion::isMandatory).count();
|
||||
LOGGER.debug(LOADING, "Found {} mod requirements ({} mandatory, {} optional)", modRequirements.size(), mandatoryRequired, modRequirements.size() - mandatoryRequired);
|
||||
final var missingVersions = modRequirements.stream()
|
||||
.filter(mv -> (mv.isMandatory() || modVersions.containsKey(mv.getModId())) && this.modVersionNotContained(mv, modVersions))
|
||||
.collect(toSet());
|
||||
final long mandatoryMissing = missingVersions.stream().filter(IModInfo.ModVersion::isMandatory).count();
|
||||
LOGGER.debug(LOADING, "Found {} mod requirements missing ({} mandatory, {} optional)", missingVersions.size(), mandatoryMissing, missingVersions.size() - mandatoryMissing);
|
||||
|
||||
if (!missingVersions.isEmpty()) {
|
||||
return missingVersions
|
||||
.stream()
|
||||
.map(mv -> new ExceptionData("fml.modloading.missingdependency", mv.getOwner(),
|
||||
mv.getModId(), mv.getOwner().getModId(), mv.getVersionRange(),
|
||||
if (mandatoryMissing > 0) {
|
||||
LOGGER.error(LOADING, "Missing mandatory dependencies: {}", missingVersions.stream().filter(IModInfo.ModVersion::isMandatory).map(IModInfo.ModVersion::getModId).collect(Collectors.joining(", ")));
|
||||
}
|
||||
if (missingVersions.size() - mandatoryMissing > 0) {
|
||||
LOGGER.error(LOADING, "Unsupported installed optional dependencies: {}", missingVersions.stream().filter(ver -> !ver.isMandatory()).map(IModInfo.ModVersion::getModId).collect(Collectors.joining(", ")));
|
||||
}
|
||||
|
||||
return missingVersions.stream()
|
||||
.map(mv -> new ExceptionData(mv.isMandatory() ? "fml.modloading.missingdependency" : "fml.modloading.missingdependency.optional",
|
||||
mv.getOwner(), mv.getModId(), mv.getOwner().getModId(), mv.getVersionRange(),
|
||||
modVersions.getOrDefault(mv.getModId(), new DefaultArtifactVersion("null"))))
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -275,6 +253,6 @@ public class ModSorter
|
||||
private boolean modVersionNotContained(final IModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions)
|
||||
{
|
||||
return !(VersionSupportMatrix.testVersionSupportMatrix(mv.getVersionRange(), mv.getModId(), "mod", (modId, range) -> modVersions.containsKey(modId) &&
|
||||
(range.containsVersion(modVersions.get(modId)) || modVersions.get(modId).toString().equals("NONE"))));
|
||||
(range.containsVersion(modVersions.get(modId)) || modVersions.get(modId).toString().equals("0.0NONE"))));
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -196,7 +196,7 @@ public class RuntimeDistCleaner implements ILaunchPluginService
|
||||
private final List<Handle> dynamicLambdaHandles = new ArrayList<>();
|
||||
|
||||
public LambdaGatherer() {
|
||||
super(Opcodes.ASM7);
|
||||
super(Opcodes.ASM9);
|
||||
}
|
||||
|
||||
public void accept(MethodNode method) {
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -30,8 +30,8 @@ import java.util.Map;
|
||||
public class StringSubstitutor
|
||||
{
|
||||
private static final Map<String,String> globals = ImmutableMap.of(
|
||||
"mcVersion", FMLLoader.mcVersion,
|
||||
"forgeVersion", FMLLoader.forgeVersion
|
||||
"mcVersion", FMLLoader.versionInfo().mcVersion(),
|
||||
"forgeVersion", FMLLoader.versionInfo().forgeVersion()
|
||||
);
|
||||
|
||||
public static String replace(final String in, final ModFile file) {
|
||||
+8
-9
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -26,8 +26,7 @@ import java.net.URL;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class StringUtils
|
||||
{
|
||||
public class StringUtils {
|
||||
public static String toLowerCase(final String str) {
|
||||
return str.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
@@ -42,12 +41,12 @@ public class StringUtils
|
||||
}
|
||||
|
||||
public static URL toURL(final String string) {
|
||||
try
|
||||
{
|
||||
return new URL(string);
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
if (string == null || string.trim().isEmpty() || string.contains("myurl.me") || string.contains("example.invalid"))
|
||||
return null;
|
||||
|
||||
try {
|
||||
return new URL(string); }
|
||||
catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -0,0 +1,17 @@
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public record VersionInfo(String forgeVersion, String mcVersion, String mcpVersion, String forgeGroup) {
|
||||
VersionInfo(Map<String, ?> arguments) {
|
||||
this((String) arguments.get("forgeVersion"), (String) arguments.get("mcVersion"), (String) arguments.get("mcpVersion"), (String) arguments.get("forgeGroup"));
|
||||
}
|
||||
|
||||
public String mcAndForgeVersion() {
|
||||
return mcVersion+"-"+forgeVersion;
|
||||
}
|
||||
|
||||
public String mcAndMCPVersion() {
|
||||
return mcVersion + "-" + mcpVersion;
|
||||
}
|
||||
}
|
||||
Loaded 100 of 2375 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user