mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-15 01:34:48 +00:00
Compare commits
111
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06bf71126f | ||
|
|
4c0f2f2685 | ||
|
|
78334717e7 | ||
|
|
a77765a2c9 | ||
|
|
1a9fe45ee9 | ||
|
|
21ef5905c8 | ||
|
|
5b67eaa474 | ||
|
|
c9d59c3b90 | ||
|
|
fa7ff74fec | ||
|
|
a34a3ebd39 | ||
|
|
2e7476d287 | ||
|
|
3244071012 | ||
|
|
7035dbde02 | ||
|
|
97ae04c2fa | ||
|
|
e7fa7f62d0 | ||
|
|
ea39712749 | ||
|
|
66dd3eaa94 | ||
|
|
270697cd10 | ||
|
|
2b53a851ef | ||
|
|
34b6efde7b | ||
|
|
86edb721da | ||
|
|
39c5f4bf7b | ||
|
|
5dc54bb1da | ||
|
|
7924769ab1 | ||
|
|
8afe2e2ccf | ||
|
|
e8dd60e088 | ||
|
|
9a621405ba | ||
|
|
45a677030d | ||
|
|
4d531022d2 | ||
|
|
48ba2160ad | ||
|
|
334ec81f9b | ||
|
|
86c726e50b | ||
|
|
e6d778dad3 | ||
|
|
dce5013ffb | ||
|
|
6eef63619c | ||
|
|
a8153fa0f7 | ||
|
|
49c04cf776 | ||
|
|
85b0277a66 | ||
|
|
0525b31262 | ||
|
|
fdb2053c50 | ||
|
|
31abbcce32 | ||
|
|
063b2242e8 | ||
|
|
577f905dc5 | ||
|
|
071d2d4a39 | ||
|
|
891715b113 | ||
|
|
30a35ef25e | ||
|
|
33453b3b8c | ||
|
|
62e699f6d0 | ||
|
|
f107d173b7 | ||
|
|
d0948b36f3 | ||
|
|
ae1211f280 | ||
|
|
3d76cb3073 | ||
|
|
45fb120223 | ||
|
|
d7a196eb5c | ||
|
|
4d53e2af9b | ||
|
|
cb6336a365 | ||
|
|
5095021e0e | ||
|
|
f88ecbf68d | ||
|
|
7da9b9eb1c | ||
|
|
02c394108f | ||
|
|
720aaca1b7 | ||
|
|
1e71b1c4d8 | ||
|
|
df4c423e93 | ||
|
|
78e0074e5a | ||
|
|
0350ea2cb6 | ||
|
|
bed724ba59 | ||
|
|
6fa973dbc8 | ||
|
|
c4ad460f34 | ||
|
|
2a8404c6c2 | ||
|
|
108db9031b | ||
|
|
d6d8a5dad6 | ||
|
|
ad2b73edf9 | ||
|
|
bb5526598e | ||
|
|
611bbf02c8 | ||
|
|
ca16036604 | ||
|
|
f118211257 | ||
|
|
81d03ea552 | ||
|
|
67c8628aeb | ||
|
|
f9b9873637 | ||
|
|
c66bf8658e | ||
|
|
052824017d | ||
|
|
6a5d914a43 | ||
|
|
208373deaa | ||
|
|
f22a3f612b | ||
|
|
9ff1015d19 | ||
|
|
0023fe3da2 | ||
|
|
7e2399714c | ||
|
|
9029182353 | ||
|
|
e6039691b5 | ||
|
|
5db1edba33 | ||
|
|
d450461726 | ||
|
|
95f8afc0f3 | ||
|
|
19635e20ec | ||
|
|
ead4e11376 | ||
|
|
b0ceb5306a | ||
|
|
99a81369f0 | ||
|
|
e2ee822948 | ||
|
|
9fe7e800f6 | ||
|
|
debfcdfda0 | ||
|
|
df662188f4 | ||
|
|
842916405f | ||
|
|
09afe81290 | ||
|
|
292809d8e8 | ||
|
|
47503ce254 | ||
|
|
f738adbdef | ||
|
|
70d15f2383 | ||
|
|
d66b5577f4 | ||
|
|
e293f12fb8 | ||
|
|
b69eca6749 | ||
|
|
03342f08c6 | ||
|
|
b85614f983 |
No files matched your search
@@ -36,5 +36,3 @@ addon.local.gradle
|
||||
addon.local.gradle.kts
|
||||
addon.late.local.gradle
|
||||
addon.late.local.gradle.kts
|
||||
/*.csv
|
||||
!gl_functions.csv
|
||||
@@ -7,40 +7,41 @@
|
||||
* It's a cute angle -mitchej123
|
||||
* It's the angel that pulls you out of OptiFine's hell -Roadhog360
|
||||
|
||||
## **Beta Quality - Here there be Dragons**
|
||||
* Shaders sneak preview - Please don't report issues yet, but please do submit fixes
|
||||
## **Beta Quality - Here there be Dragons**
|
||||
* Shaders - Beta
|
||||
* Complementary & BSL mostly function, but have some bugs
|
||||
* Sildurs, Seus, and any other shader probably doesn't work
|
||||
|
||||
|
||||
# Required Dependencies
|
||||
* [UniMixins](https://github.com/LegacyModdingMC/UniMixins/releases) >= 0.1.14
|
||||
* [GTNHLib](https://github.com/GTNewHorizons/GTNHLib/releases) >= 0.4.2
|
||||
* [UniMixins](https://github.com/LegacyModdingMC/UniMixins/releases) >= 0.1.19
|
||||
* [GTNHLib](https://github.com/GTNewHorizons/GTNHLib/releases) >= 0.7.0
|
||||
* NOTE: Some mods are not required, but a specific version is required if present - see: `Permanent Incompatibilities` below.
|
||||
|
||||
# Known (temporary) Incompatibilities
|
||||
* Forge Relocation - Currently non Thread Safe; safe if not in use
|
||||
* ProjectRed Frames - Currently non Thread Safe; safe if not in use'
|
||||
* ProjectRed Frames - Currently non Thread Safe; safe if not in use
|
||||
|
||||
# Potential Incompatibilities
|
||||
* EndlessIDs - Compat commits have been made, might work, might not - not fully tested
|
||||
|
||||
# Known Incompatibilities
|
||||
* FalseTweaks - Not currently planned (Looking for volunteers) [Might work if you effectively disable most of the mod]
|
||||
* SmoothFont - Not currently planned (Looking for volunteers)
|
||||
* RPLE - Not currently planned (Looking for volunteers)
|
||||
* LiteLoader - Install [LiteloaderLoader](https://github.com/Midnight145/LiteloaderLoader)
|
||||
|
||||
# Permanent Incompatibilities
|
||||
* OptiFine [Disabled, won't fix]
|
||||
* FastCraft [Disabled, won't fix]
|
||||
* BetterFPS [Disabled, won't fix]
|
||||
* OptimizationsAndTweaks [Disabled, won't fix]
|
||||
* [Amazing Trophies 1.2.1 and below](https://github.com/GTNewHorizons/Amazing-Trophies/releases) - use 1.2.2+
|
||||
* [Amazing Trophies 1.2.1 and below](https://github.com/GTNewHorizons/Amazing-Trophies/releases) - Use 1.2.2+
|
||||
* [LWJGL3ify 1.5.4 and below](https://github.com/GTNewHorizons/lwjgl3ify/releases/) - Use the latest version available, 1.5.7+
|
||||
* [ArchaicFix 0.6.2 and below](https://www.curseforge.com/minecraft/mc-mods/archaicfix/files/all?page=1&pageSize=20) - Use 0.7.0 or above
|
||||
* [Hodgepodge 2.4.3 and below](https://github.com/GTNewHorizons/Hodgepodge/releases) - Use 0.4.5 or above
|
||||
* CodeChicken[Core](https://github.com/GTNewHorizons/CodeChickenCore/releases)/[Lib](https://github.com/GTNewHorizons/CodeChickenLib/releases) <1.2.0 - Threading issues, use 1.3.0+
|
||||
* Neodymium - Untested, but unlikely to be compatible. (Chunk Meshing is definitely incompatible, other features might work depending on config)
|
||||
* SmoothFont - Equivalent functionality added
|
||||
|
||||
# Credits
|
||||
* ShadersMod
|
||||
@@ -64,7 +65,7 @@
|
||||
* Makamys for [Neodymium](https://github.com/makamys/Neodymium) - Various Tessellator -> Quad functionality taken under the LGPL 3
|
||||
* MCPatcherForge
|
||||
* Original [MCPatcher](https://bitbucket.org/prupe/mcpatcher/src/master/): Paul Rupe
|
||||
* [Forge version](https://bitbucket.org/prupe/mcpatcher/src/master/): Mist475 under LGPL 3.0 with default ctm textures for glass and bookshelves by DarkBum under CC-BY-SA
|
||||
* [Forge version](https://github.com/mist475/MCPatcherForge): Mist475 under LGPL 3.0 with default ctm textures for glass and bookshelves by DarkBum under CC-BY-SA
|
||||
* HUDCaching
|
||||
* Created by [Moulberry](https://github.com/Moulberry/MCHUDCaching), backported from [Patcher](https://github.com/Sk1erLLC/Patcher) mod by Alexdoru under the CC-BY-SA-NC 4.0 license
|
||||
* Angelica
|
||||
|
||||
@@ -4,6 +4,8 @@ plugins {
|
||||
|
||||
minecraft {
|
||||
extraRunJvmArguments.add("-Dangelica.enableTestBlocks=true")
|
||||
extraRunJvmArguments.add("-Dangelica.dumpClass=true")
|
||||
//extraRunJvmArguments.add("-Dangelica.redirectorLogspam=true")
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
|
||||
+21
-23
@@ -49,19 +49,19 @@ configurations {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("com.github.GTNewHorizons:Hodgepodge:2.5.78")
|
||||
compileOnly("com.github.GTNewHorizons:Hodgepodge:2.6.107")
|
||||
|
||||
compileOnly("com.gtnewhorizons.retrofuturabootstrap:RetroFuturaBootstrap:0.4.0") { transitive = false }
|
||||
compileOnly("com.gtnewhorizons.retrofuturabootstrap:RetroFuturaBootstrap:1.0.7") { transitive = false }
|
||||
|
||||
compileOnly("org.projectlombok:lombok:1.18.22") { transitive = false }
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.22")
|
||||
compileOnly("org.projectlombok:lombok:1.18.34") { transitive = false }
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.34")
|
||||
|
||||
// Use modern models+textures to inject QuadProviders
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:TX-Loader:1.7.2:dev')
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:TX-Loader:1.8.5:dev')
|
||||
|
||||
// Iris Shaders
|
||||
compileOnly('org.jetbrains:annotations:24.0.1')
|
||||
api("com.github.GTNewHorizons:GTNHLib:0.5.20:dev")
|
||||
compileOnly('org.jetbrains:annotations:26.0.2')
|
||||
api("com.github.GTNewHorizons:GTNHLib:0.6.40:dev")
|
||||
shadowImplementation("org.anarres:jcpp:1.4.14") // Apache 2.0
|
||||
shadowImplementation("org.taumc:glsl-transformation-lib:0.2.0-4.g6b42bca") {
|
||||
exclude module: "antlr4" // we only want to shadow the runtime module
|
||||
@@ -70,21 +70,20 @@ dependencies {
|
||||
compileOnly "org.apache.ant:ant:1.8.2"
|
||||
|
||||
// Because who doesn't want NEI
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:NotEnoughItems:2.6.45-GTNH:dev')
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:CodeChickenCore:1.3.10:dev')
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:NotEnoughItems:2.7.90-GTNH:dev')
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:CodeChickenCore:1.4.7:dev')
|
||||
|
||||
// Notfine Deps
|
||||
compileOnly("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev")
|
||||
devOnlyNonPublishable("com.github.GTNewHorizons:Baubles:1.0.4:dev")
|
||||
compileOnly("com.github.GTNewHorizons:twilightforest:2.6.35:dev") { transitive = false }
|
||||
devOnlyNonPublishable("com.github.GTNewHorizons:Baubles-Expanded:2.1.15-GTNH:dev")
|
||||
compileOnly("com.github.GTNewHorizons:twilightforest:2.7.13:dev") { transitive = false }
|
||||
compileOnly(rfg.deobf('curse.maven:witchery-69673:2234410'))
|
||||
compileOnly("com.github.GTNewHorizons:TinkersConstruct:1.12.14-GTNH:dev") { transitive = false }
|
||||
compileOnly("com.github.GTNewHorizons:Natura:2.7.5:dev")
|
||||
compileOnly("com.github.GTNewHorizons:TinkersConstruct:1.13.54-GTNH:dev") { transitive = false }
|
||||
compileOnly("com.github.GTNewHorizons:Natura:2.8.9:dev")
|
||||
|
||||
compileOnly("com.github.GTNewHorizons:ThaumicHorizons:1.6.4:dev")
|
||||
compileOnly("com.github.GTNewHorizons:ThaumicHorizons:1.7.8:dev")
|
||||
|
||||
compileOnly("com.github.GTNewHorizons:Battlegear2:1.4.1:dev") { transitive = false }
|
||||
compileOnly(rfg.deobf('maven.modrinth:backhand:1.4.1')) { transitive = false }
|
||||
compileOnly("com.github.GTNewHorizons:Battlegear2:1.4.3:dev") { transitive = false }
|
||||
|
||||
compileOnly("com.falsepattern:chunkapi-mc1.7.10:0.5.1:api") { transitive = false }
|
||||
compileOnly("com.falsepattern:endlessids-mc1.7.10:1.5-beta0003:dev") { transitive = false }
|
||||
@@ -94,15 +93,16 @@ dependencies {
|
||||
|
||||
compileOnly("curse.maven:minefactory-reloaded-66672:2277486")
|
||||
|
||||
compileOnly("com.github.GTNewHorizons:NotEnoughIds:2.1.6:dev") // Mixin Version
|
||||
compileOnly("com.github.GTNewHorizons:NotEnoughIds:2.1.10:dev") // Mixin Version
|
||||
compileOnly("com.github.GTNewHorizons:NotEnoughIds-Legacy:1.4.7:dev") // ASM Version
|
||||
|
||||
compileOnly(rfg.deobf("curse.maven:campfirebackport-387444:4611675"))
|
||||
compileOnly(rfg.deobf("curse.maven:xaeros-minimap-263420:5060684"))
|
||||
|
||||
compileOnly("com.github.GTNewHorizons:HoloInventory:2.4.13-GTNH:dev")
|
||||
compileOnly(rfg.deobf("curse.maven:security-craft-64760:2818228"))
|
||||
|
||||
runtimeOnlyNonPublishable(rfg.deobf("CoreTweaks:CoreTweaks:0.3.3.2"))
|
||||
// For testing alternative splash screens, can be sourced from https://github.com/MalTeeez/ModernSplash/releases
|
||||
//runtimeOnly(rfg.deobf(files("dependencies/modernsplash-1.7.10-1.2.2-dev.jar")))
|
||||
|
||||
// Hodgepodge
|
||||
transformedMod("net.industrial-craft:industrialcraft-2:2.2.828-experimental:dev")
|
||||
@@ -111,12 +111,10 @@ dependencies {
|
||||
compileOnly("com.github.GTNewHorizons:BetterCrashes:1.4.0-GTNH:dev")
|
||||
|
||||
// Tests
|
||||
testImplementation(platform('org.junit:junit-bom:5.9.2'))
|
||||
testImplementation(platform('org.junit:junit-bom:5.11.4'))
|
||||
testImplementation('org.junit.jupiter:junit-jupiter')
|
||||
testImplementation("org.mockito:mockito-core:3.+")
|
||||
testImplementation("org.lwjgl.lwjgl:lwjgl:2.9.4-nightly-20150209")
|
||||
|
||||
devOnlyNonPublishable("com.github.javaparser:javaparser-symbol-solver-core:3.26.2") {
|
||||
exclude module: "guava"
|
||||
}
|
||||
compileOnly("mega:fluidlogged-mc1.7.10:0.1.2")
|
||||
}
|
||||
-2084
File diff suppressed because it is too large.
Load diff
+2
-2
@@ -14,7 +14,7 @@ modId = angelica
|
||||
modGroup = com.gtnewhorizons.angelica
|
||||
|
||||
# Whether to use modGroup as the maven publishing group.
|
||||
# Due to a history of using JitPack, the default is com.github.GTNewHorizons for all mods.
|
||||
# When false, com.github.GTNewHorizons is used.
|
||||
useModGroupForPublishing = false
|
||||
|
||||
# Updates your build.gradle and settings.gradle automatically whenever an update is available.
|
||||
@@ -151,7 +151,7 @@ modrinthProjectId = angelica
|
||||
# type can be one of [project, version],
|
||||
# and the name is the Modrinth project or version slug/id of the other mod.
|
||||
# Example: required-project:fplib;optional-project:gasstation;incompatible-project:gregtech
|
||||
# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true
|
||||
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
|
||||
modrinthRelations = required-project\:gtnhlib
|
||||
|
||||
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -86,8 +86,7 @@ done
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -206,7 +205,7 @@ fi
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
@@ -8,6 +8,13 @@ repositories {
|
||||
includeGroup 'com.falsepattern'
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = 'mega'
|
||||
url = 'https://mvn.falsepattern.com/gtmega_releases/'
|
||||
content {
|
||||
includeGroup 'mega'
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
ivy {
|
||||
|
||||
+1
-1
@@ -16,5 +16,5 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.29'
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.41'
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
import com.github.javaparser.StaticJavaParser;
|
||||
import com.github.javaparser.ast.CompilationUnit;
|
||||
import com.github.javaparser.ast.Node;
|
||||
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
|
||||
import com.github.javaparser.ast.body.MethodDeclaration;
|
||||
import com.github.javaparser.ast.body.Parameter;
|
||||
import com.github.javaparser.ast.visitor.VoidVisitorWithDefaults;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Used to generate gl_functions.csv. Which contains a mapping of OpenGL functions provided by LWJGL
|
||||
* corresponding to the earliest GL version they appear in.
|
||||
*/
|
||||
public class GLFunctionParser {
|
||||
final static String glPath = "util/gl"; // Path to LWJGL OpenGL bindings source code
|
||||
|
||||
public static void main(String[] args) throws FileNotFoundException {
|
||||
HashMap<String, Set<String>> byFunction = new HashMap<>();
|
||||
File dir = new File(glPath);
|
||||
for (File file : dir.listFiles()) {
|
||||
final String filename = file.getName();
|
||||
if (filename.endsWith(".java") && filename.startsWith("GL") && Character.isDigit(filename.charAt(2))) {
|
||||
Path p = Paths.get(filename);
|
||||
|
||||
String parsedFile = removeFileExtension(p.getFileName().toString());
|
||||
|
||||
CompilationUnit cu = StaticJavaParser.parse(file);
|
||||
cu.accept(new VoidVisitorWithDefaults<>() {
|
||||
|
||||
@Override
|
||||
public void defaultAction(Node n, Object arg) {
|
||||
for( Node child : n.getChildNodes()) {
|
||||
if(child instanceof ClassOrInterfaceDeclaration cd) {
|
||||
for (MethodDeclaration md : cd.getMethods()) {
|
||||
String methodName = md.getNameAsString() + "(";
|
||||
for (Parameter p : md.getParameters()) {
|
||||
methodName = methodName + p.getTypeAsString();
|
||||
}
|
||||
methodName = methodName + ")";
|
||||
if(methodName.startsWith("n")) continue;
|
||||
|
||||
Set<String> functionSet = byFunction.computeIfAbsent(methodName, k -> new HashSet<>());
|
||||
functionSet.add(parsedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> functionVersionMap = new HashMap<>();
|
||||
|
||||
for(String function : byFunction.keySet()) {
|
||||
|
||||
Set<String> versionsForFunction = byFunction.get(function);
|
||||
int lowestInt = 46;
|
||||
String lowestString = "GL46";
|
||||
for(String version : versionsForFunction) {
|
||||
int i = Integer.parseInt(version.substring(2, 4));
|
||||
if (i < lowestInt) {
|
||||
lowestInt = i;
|
||||
lowestString = version;
|
||||
}
|
||||
}
|
||||
functionVersionMap.put(function, lowestString);
|
||||
}
|
||||
|
||||
List<String[]> outputLines = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<String, String> entry : functionVersionMap.entrySet()) {
|
||||
outputLines.add(new String[] {entry.getKey(), entry.getValue()});
|
||||
}
|
||||
|
||||
File output = new File("output.csv");
|
||||
try (PrintWriter writer = new PrintWriter(output)) {
|
||||
outputLines.stream().map(GLSMFunctionComparison::convertToCSV).forEach(writer::println);
|
||||
}
|
||||
}
|
||||
|
||||
public static String convertToCSV(String[] data) {
|
||||
return Stream.of(data).map(GLSMFunctionComparison::escapeSpecialCharacters).collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
public static String escapeSpecialCharacters(String data) {
|
||||
if (data == null) {
|
||||
throw new IllegalArgumentException("Input data cannot be null");
|
||||
}
|
||||
String escapedData = data.replaceAll("\\R", " ");
|
||||
if (data.contains(",") || data.contains("\"") || data.contains("'")) {
|
||||
data = data.replace("\"", "\"\"");
|
||||
escapedData = "\"" + data + "\"";
|
||||
}
|
||||
return escapedData;
|
||||
}
|
||||
|
||||
public static String removeFileExtension(String filename) {
|
||||
if (filename == null || filename.isEmpty()) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
String extPattern = "(?<!^)[.]" + "[^.]*$";
|
||||
return filename.replaceAll(extPattern, "");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
import com.github.javaparser.ParserConfiguration;
|
||||
import com.github.javaparser.StaticJavaParser;
|
||||
import com.github.javaparser.ast.CompilationUnit;
|
||||
import com.github.javaparser.ast.Node;
|
||||
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
|
||||
import com.github.javaparser.ast.body.MethodDeclaration;
|
||||
import com.github.javaparser.ast.body.Parameter;
|
||||
import com.github.javaparser.ast.visitor.VoidVisitorWithDefaults;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Used to compare OpenGL functions from gl_functions.csv to current GLStateManager
|
||||
* source code to determine what functions have an implementation in GLSM, and what ones don't.
|
||||
* Only considers functions which appear in GL 2.1 and lower
|
||||
*/
|
||||
public class GLSMFunctionComparison {
|
||||
|
||||
/**
|
||||
* If set to true, then the outputted CSV will show functions which do have an implementation in GLSM
|
||||
*/
|
||||
final static boolean INCLUDE_TRUE = false;
|
||||
|
||||
final static String glFunctionsCsvPath = "gl_functions.csv";
|
||||
final static String glsmPath = "src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java";
|
||||
|
||||
public static Map<String, String> parseGLFunctions() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(glFunctionsCsvPath))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
String[] values = line.split(",");
|
||||
if (values.length == 2) {
|
||||
String key = values[0].trim();
|
||||
String value = values[1].trim();
|
||||
int versionInt = Integer.parseInt(value.substring(2, 4));
|
||||
if (versionInt < 30) map.put(key, value);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws FileNotFoundException {
|
||||
//GLSM will fail to parse without increasing language level
|
||||
StaticJavaParser.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_17);
|
||||
|
||||
Map<String, String> functionMap = parseGLFunctions();
|
||||
Set<String> glsmFunctions = new HashSet<>();
|
||||
|
||||
File glsmFile = new File(glsmPath);
|
||||
CompilationUnit cu = StaticJavaParser.parse(glsmFile);
|
||||
cu.accept(new VoidVisitorWithDefaults<>() {
|
||||
|
||||
@Override
|
||||
public void defaultAction(Node n, Object arg) {
|
||||
for (Node child : n.getChildNodes()) {
|
||||
if (child instanceof ClassOrInterfaceDeclaration cd) {
|
||||
for (MethodDeclaration md : cd.getMethods()) {
|
||||
String methodName = md.getNameAsString() + "(";
|
||||
for (Parameter p : md.getParameters()) {
|
||||
methodName = methodName + p.getTypeAsString();
|
||||
}
|
||||
methodName = methodName + ")";
|
||||
glsmFunctions.add(methodName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
|
||||
Map<String, String> functionGLSMMap = new HashMap<>();
|
||||
|
||||
for(String function : functionMap.keySet()) {
|
||||
if (!glsmFunctions.contains(function)) {
|
||||
functionGLSMMap.put(function, "false");
|
||||
} else if (INCLUDE_TRUE) {
|
||||
functionGLSMMap.put(function, "true");
|
||||
}
|
||||
}
|
||||
|
||||
List<String[]> outputLines = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<String, String> entry : functionGLSMMap.entrySet()) {
|
||||
outputLines.add(new String[] {entry.getKey(), functionMap.get(entry.getKey()), entry.getValue()});
|
||||
}
|
||||
|
||||
File output = new File("glsm_function_comparison.csv");
|
||||
try (PrintWriter writer = new PrintWriter(output)) {
|
||||
outputLines.stream().map(GLSMFunctionComparison::convertToCSV).forEach(writer::println);
|
||||
}
|
||||
}
|
||||
|
||||
public static String convertToCSV(String[] data) {
|
||||
return Stream.of(data).map(GLSMFunctionComparison::escapeSpecialCharacters).collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
public static String escapeSpecialCharacters(String data) {
|
||||
if (data == null) {
|
||||
throw new IllegalArgumentException("Input data cannot be null");
|
||||
}
|
||||
String escapedData = data.replaceAll("\\R", " ");
|
||||
if (data.contains(",") || data.contains("\"") || data.contains("'")) {
|
||||
data = data.replace("\"", "\"\"");
|
||||
escapedData = "\"" + data + "\"";
|
||||
}
|
||||
return escapedData;
|
||||
}
|
||||
|
||||
public static String removeFileExtension(String filename) {
|
||||
if (filename == null || filename.isEmpty()) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
String extPattern = "(?<!^)[.]" + "[^.]*$";
|
||||
return filename.replaceAll(extPattern, "");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.gtnewhorizons.angelica;
|
||||
|
||||
import com.gtnewhorizon.gtnhmixins.ILateMixinLoader;
|
||||
import com.gtnewhorizon.gtnhmixins.LateMixin;
|
||||
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
|
||||
import com.gtnewhorizons.angelica.mixins.Mixins;
|
||||
|
||||
import java.util.List;
|
||||
@@ -9,6 +10,7 @@ import java.util.Set;
|
||||
|
||||
@LateMixin
|
||||
public class AngelicaLateMixins implements ILateMixinLoader {
|
||||
|
||||
@Override
|
||||
public String getMixinConfig() {
|
||||
return "mixins.angelica.late.json";
|
||||
@@ -16,7 +18,6 @@ public class AngelicaLateMixins implements ILateMixinLoader {
|
||||
|
||||
@Override
|
||||
public List<String> getMixins(Set<String> loadedMods) {
|
||||
return Mixins.getLateMixins(loadedMods);
|
||||
return IMixins.getLateMixins(Mixins.class, loadedMods);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,8 +15,13 @@ import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
modid = "angelica",
|
||||
name = "Angelica",
|
||||
version = Tags.VERSION,
|
||||
dependencies = " before:lwjgl3ify@[1.5.3,);" + " after:hodgepodge@[2.4.4,);" + " after:CodeChickenCore@[1.2.0,);"
|
||||
+ " after:archaicfix@[0.7.0,);" + " required-after:gtnhlib@[0.4.2,);",
|
||||
dependencies = """
|
||||
required-after:gtnhlib@[0.6.6,);\
|
||||
before:lwjgl3ify@[1.5.3,);\
|
||||
after:hodgepodge@[2.4.4,);\
|
||||
after:CodeChickenCore@[1.2.0,);\
|
||||
after:archaicfix@[0.7.0,);\
|
||||
""",
|
||||
acceptedMinecraftVersions = "[1.7.10]",
|
||||
acceptableRemoteVersions = "*",
|
||||
guiFactory = "com.gtnewhorizons.angelica.config.AngelicaGuiConfigFactory")
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.gtnewhorizons.angelica.api;
|
||||
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IBlockAccessExtended extends IBlockAccess {
|
||||
World getWorld();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.gtnewhorizons.angelica.api;
|
||||
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.IPatchedTextureAtlasSprite;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.ITexturesCache;
|
||||
import net.minecraft.client.renderer.RenderBlocks;
|
||||
import net.minecraft.util.IIcon;
|
||||
|
||||
/**
|
||||
* Exposes a method to the API that allow mods to add texture update compat
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class TextureServices {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void updateBlockTextureAnimation(IIcon icon, RenderBlocks renderBlocks) {
|
||||
if (renderBlocks instanceof ITexturesCache texturesCache) {
|
||||
texturesCache.getRenderedTextures().add(icon);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void updateTextureAnimation(IIcon icon) {
|
||||
if(icon instanceof IPatchedTextureAtlasSprite patchedSprite) {
|
||||
patchedSprite.markNeedsAnimationUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,30 @@
|
||||
package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.FontRendererAccessor;
|
||||
import it.unimi.dsi.fastutil.chars.Char2ShortOpenHashMap;
|
||||
import cpw.mods.fml.client.SplashProgress;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import jss.util.RandomXoshiro256StarStar;
|
||||
import net.coderbot.iris.gl.program.Program;
|
||||
import net.coderbot.iris.gl.program.ProgramBuilder;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.*;
|
||||
|
||||
/**
|
||||
* A batching replacement for {@code FontRenderer}
|
||||
*
|
||||
@@ -29,8 +34,6 @@ public class BatchingFontRenderer {
|
||||
|
||||
/** The underlying FontRenderer object that's being accelerated */
|
||||
protected FontRenderer underlying;
|
||||
/** Cached locations for each unicode page atlas */
|
||||
private final ResourceLocation[] unicodePageLocations;
|
||||
/** Array of width of all the characters in default.png */
|
||||
protected int[] charWidth = new int[256];
|
||||
/** Array of the start/end column (in upper/lower nibble) for every glyph in the /font directory. */
|
||||
@@ -42,50 +45,59 @@ public class BatchingFontRenderer {
|
||||
private int[] colorCode;
|
||||
/** Location of the primary font atlas to bind. */
|
||||
protected final ResourceLocation locationFontTexture;
|
||||
/** The RenderEngine used to load and setup glyph textures. */
|
||||
private final TextureManager renderEngine;
|
||||
private final RandomXoshiro256StarStar fontRandom = new RandomXoshiro256StarStar();
|
||||
|
||||
/** The full list of characters present in the default Minecraft font, excluding the Unicode font */
|
||||
@SuppressWarnings("UnnecessaryUnicodeEscape")
|
||||
private static final String MCFONT_CHARS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
|
||||
private final int AAMode;
|
||||
private final int AAStrength;
|
||||
private final int texBoundAttrLocation;
|
||||
private final int fontShaderId;
|
||||
|
||||
private static final short[] MCFONT_ASCII_LUT = new short[512];
|
||||
private static final Char2ShortOpenHashMap MCFONT_UNI_LUT = new Char2ShortOpenHashMap();
|
||||
final boolean isSGA;
|
||||
final boolean isSplash;
|
||||
|
||||
static {
|
||||
Arrays.fill(MCFONT_ASCII_LUT, (short) -1);
|
||||
for (short i = 0; i < MCFONT_CHARS.length(); i++) {
|
||||
char ch = MCFONT_CHARS.charAt(i);
|
||||
if (ch < MCFONT_ASCII_LUT.length) {
|
||||
MCFONT_ASCII_LUT[ch] = i;
|
||||
} else {
|
||||
MCFONT_UNI_LUT.put(ch, i);
|
||||
private static class FontAAShader {
|
||||
|
||||
private static Program fontShader = null;
|
||||
public static Program getProgram() {
|
||||
if (fontShader == null) {
|
||||
String vsh, fsh;
|
||||
try {
|
||||
fsh = new String(IOUtils.toByteArray(Objects.requireNonNull(FontAAShader.class.getResourceAsStream("/assets/angelica/shaders/fontFilter.fsh"))), StandardCharsets.UTF_8);
|
||||
vsh = new String(IOUtils.toByteArray(Objects.requireNonNull(FontAAShader.class.getResourceAsStream("/assets/angelica/shaders/fontFilter.vsh"))), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
ProgramBuilder builder = ProgramBuilder.begin("fontFilter", vsh, null, fsh, ImmutableSet.of(0));
|
||||
fontShader = builder.build();
|
||||
}
|
||||
return fontShader;
|
||||
}
|
||||
}
|
||||
|
||||
public static int lookupMcFontPosition(char ch) {
|
||||
if (ch < MCFONT_ASCII_LUT.length) {
|
||||
return MCFONT_ASCII_LUT[ch];
|
||||
} else {
|
||||
return MCFONT_UNI_LUT.getOrDefault(ch, (short) -1);
|
||||
}
|
||||
}
|
||||
|
||||
public BatchingFontRenderer(FontRenderer underlying, ResourceLocation[] unicodePageLocations, int[] charWidth,
|
||||
byte[] glyphWidth, int[] colorCode, ResourceLocation locationFontTexture, TextureManager renderEngine) {
|
||||
public BatchingFontRenderer(FontRenderer underlying, int[] charWidth, byte[] glyphWidth,
|
||||
int[] colorCode, ResourceLocation locationFontTexture) {
|
||||
this.underlying = underlying;
|
||||
this.unicodePageLocations = unicodePageLocations;
|
||||
this.charWidth = charWidth;
|
||||
this.glyphWidth = glyphWidth;
|
||||
this.colorCode = colorCode;
|
||||
this.locationFontTexture = locationFontTexture;
|
||||
this.renderEngine = renderEngine;
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
batchCommandPool.add(new FontDrawCmd());
|
||||
}
|
||||
|
||||
this.isSGA = Objects.equals(this.locationFontTexture.getResourcePath(), "textures/font/ascii_sga.png");
|
||||
this.isSplash = FontStrategist.isSplashFontRendererActive(underlying);
|
||||
|
||||
FontProviderMC.get(this.isSGA).charWidth = this.charWidth;
|
||||
FontProviderMC.get(this.isSGA).locationFontTexture = this.locationFontTexture;
|
||||
FontProviderUnicode.get().glyphWidth = this.glyphWidth;
|
||||
|
||||
//noinspection deprecation
|
||||
fontShaderId = FontAAShader.getProgram().getProgramId();
|
||||
AAMode = GL20.glGetUniformLocation(fontShaderId, "aaMode");
|
||||
AAStrength = GL20.glGetUniformLocation(fontShaderId, "strength");
|
||||
texBoundAttrLocation = GL20.glGetAttribLocation(fontShaderId, "texBounds");
|
||||
}
|
||||
|
||||
// === Batched rendering
|
||||
@@ -97,24 +109,29 @@ public class BatchingFontRenderer {
|
||||
private static final int INITIAL_BATCH_SIZE = 256;
|
||||
private static final ResourceLocation DUMMY_RESOURCE_LOCATION = new ResourceLocation("angelica$dummy",
|
||||
"this is invalid!");
|
||||
private FloatBuffer batchVtxPositions = BufferUtils.createFloatBuffer(INITIAL_BATCH_SIZE * 2);
|
||||
private ByteBuffer batchVtxColors = BufferUtils.createByteBuffer(INITIAL_BATCH_SIZE * 4);
|
||||
private FloatBuffer batchVtxTexCoords = BufferUtils.createFloatBuffer(INITIAL_BATCH_SIZE * 2);
|
||||
private IntBuffer batchIndices = BufferUtils.createIntBuffer(INITIAL_BATCH_SIZE / 2 * 3);
|
||||
private FloatBuffer batchVtxPositions = memAllocFloat(INITIAL_BATCH_SIZE * 2);
|
||||
private ByteBuffer batchVtxColors = memAlloc(INITIAL_BATCH_SIZE * 4);
|
||||
private FloatBuffer batchVtxTexCoords = memAllocFloat(INITIAL_BATCH_SIZE * 2);
|
||||
private IntBuffer batchIndices = memAllocInt(INITIAL_BATCH_SIZE / 2 * 3);
|
||||
private FloatBuffer batchVtxTexBounds = memAllocFloat(INITIAL_BATCH_SIZE * 4);
|
||||
private final ObjectArrayList<FontDrawCmd> batchCommands = ObjectArrayList.wrap(new FontDrawCmd[64], 0);
|
||||
private final ObjectArrayList<FontDrawCmd> batchCommandPool = ObjectArrayList.wrap(new FontDrawCmd[64], 0);
|
||||
|
||||
private int blendSrcRGB = GL11.GL_SRC_ALPHA;
|
||||
private int blendDstRGB = GL11.GL_ONE_MINUS_SRC_ALPHA;
|
||||
|
||||
/** */
|
||||
private void pushVtx(float x, float y, int rgba, float u, float v) {
|
||||
private void pushVtx(float x, float y, int rgba, float u, float v, float uMin, float uMax, float vMin, float vMax) {
|
||||
final int oldCap = batchVtxPositions.capacity() / 2;
|
||||
if (vtxWriterIndex >= oldCap) {
|
||||
final int newCap = oldCap * 2;
|
||||
batchVtxPositions = CompatMemoryUtil.memReallocDirect(batchVtxPositions, newCap * 2);
|
||||
batchVtxColors = CompatMemoryUtil.memReallocDirect(batchVtxColors, newCap * 4);
|
||||
batchVtxTexCoords = CompatMemoryUtil.memReallocDirect(batchVtxTexCoords, newCap * 2);
|
||||
batchVtxPositions = memRealloc(batchVtxPositions, newCap * 2);
|
||||
batchVtxColors = memRealloc(batchVtxColors, newCap * 4);
|
||||
batchVtxTexCoords = memRealloc(batchVtxTexCoords, newCap * 2);
|
||||
batchVtxTexBounds = memRealloc(batchVtxTexBounds, newCap * 4);
|
||||
final int oldIdxCap = batchIndices.capacity();
|
||||
final int newIdxCap = oldIdxCap * 2;
|
||||
batchIndices = CompatMemoryUtil.memReallocDirect(batchIndices, newIdxCap);
|
||||
batchIndices = memRealloc(batchIndices, newIdxCap);
|
||||
}
|
||||
final int idx = vtxWriterIndex;
|
||||
final int idx2 = idx * 2;
|
||||
@@ -128,15 +145,19 @@ public class BatchingFontRenderer {
|
||||
batchVtxColors.put(idx4 + 3, (byte) ((rgba >> 24) & 0xFF));
|
||||
batchVtxTexCoords.put(idx2, u);
|
||||
batchVtxTexCoords.put(idx2 + 1, v);
|
||||
batchVtxTexBounds.put(idx4, uMin);
|
||||
batchVtxTexBounds.put(idx4 + 1, uMax);
|
||||
batchVtxTexBounds.put(idx4 + 2, vMin);
|
||||
batchVtxTexBounds.put(idx4 + 3, vMax);
|
||||
vtxWriterIndex++;
|
||||
}
|
||||
|
||||
private void pushUntexRect(float x, float y, float w, float h, int rgba) {
|
||||
final int vtxId = vtxWriterIndex;
|
||||
pushVtx(x, y, rgba, 0, 0);
|
||||
pushVtx(x, y + h, rgba, 0, 0);
|
||||
pushVtx(x + w, y, rgba, 0, 0);
|
||||
pushVtx(x + w, y + h, rgba, 0, 0);
|
||||
pushVtx(x, y, rgba, 0, 0, 0, 0, 0, 0);
|
||||
pushVtx(x, y + h, rgba, 0, 0, 0, 0, 0, 0);
|
||||
pushVtx(x + w, y, rgba, 0, 0, 0, 0, 0, 0);
|
||||
pushVtx(x + w, y + h, rgba, 0, 0, 0, 0, 0, 0);
|
||||
pushQuadIdx(vtxId);
|
||||
}
|
||||
|
||||
@@ -153,7 +174,7 @@ public class BatchingFontRenderer {
|
||||
return idx;
|
||||
}
|
||||
|
||||
private void pushDrawCmd(int startIdx, int idxCount, ResourceLocation texture) {
|
||||
private void pushDrawCmd(int startIdx, int idxCount, ResourceLocation texture, boolean isUnicode) {
|
||||
if (!batchCommands.isEmpty()) {
|
||||
final FontDrawCmd lastCmd = batchCommands.get(batchCommands.size() - 1);
|
||||
final int prevEndVtx = lastCmd.startVtx + lastCmd.idxCount;
|
||||
@@ -169,7 +190,7 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
}
|
||||
final FontDrawCmd cmd = batchCommandPool.pop();
|
||||
cmd.reset(startIdx, idxCount, texture);
|
||||
cmd.reset(startIdx, idxCount, texture, isUnicode);
|
||||
batchCommands.add(cmd);
|
||||
}
|
||||
|
||||
@@ -177,12 +198,14 @@ public class BatchingFontRenderer {
|
||||
|
||||
public int startVtx;
|
||||
public int idxCount;
|
||||
public boolean isUnicode;
|
||||
public ResourceLocation texture;
|
||||
|
||||
public void reset(int startVtx, int vtxCount, ResourceLocation texture) {
|
||||
public void reset(int startVtx, int vtxCount, ResourceLocation texture, boolean isUnicode) {
|
||||
this.startVtx = startVtx;
|
||||
this.idxCount = vtxCount;
|
||||
this.texture = texture;
|
||||
this.isUnicode = isUnicode;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -241,6 +264,9 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
int lastActiveProgram;
|
||||
int fontAAModeLast = -1;
|
||||
int fontAAStrengthLast = -1;
|
||||
private void flushBatch() {
|
||||
// Sort&Draw
|
||||
batchCommands.sort(FontDrawCmd.DRAW_ORDER_COMPARATOR);
|
||||
@@ -253,9 +279,23 @@ public class BatchingFontRenderer {
|
||||
GLStateManager.enableTexture();
|
||||
GLStateManager.enableAlphaTest();
|
||||
GLStateManager.enableBlend();
|
||||
GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
GLStateManager.tryBlendFuncSeparate(blendSrcRGB, blendDstRGB, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
GLStateManager.glShadeModel(GL11.GL_FLAT);
|
||||
|
||||
if (FontConfig.fontAAMode != 0) {
|
||||
GL20.glVertexAttribPointer(texBoundAttrLocation, 4, false, 0, batchVtxTexBounds);
|
||||
GL20.glEnableVertexAttribArray(texBoundAttrLocation);
|
||||
lastActiveProgram = GLStateManager.getActiveProgram();
|
||||
GLStateManager.glUseProgram(fontShaderId);
|
||||
if (FontConfig.fontAAMode != fontAAModeLast) {
|
||||
fontAAModeLast = FontConfig.fontAAMode;
|
||||
GL20.glUniform1i(AAMode, FontConfig.fontAAMode);
|
||||
}
|
||||
if (FontConfig.fontAAStrength != fontAAStrengthLast) {
|
||||
fontAAStrengthLast = FontConfig.fontAAStrength;
|
||||
GL20.glUniform1f(AAStrength, FontConfig.fontAAStrength / 120.f);
|
||||
}
|
||||
}
|
||||
GL11.glTexCoordPointer(2, 0, batchVtxTexCoords);
|
||||
GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
GL11.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, 0, batchVtxColors);
|
||||
@@ -283,8 +323,13 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
batchIndices.limit(cmd.startVtx + cmd.idxCount);
|
||||
batchIndices.position(cmd.startVtx);
|
||||
|
||||
GL11.glDrawElements(GL11.GL_TRIANGLES, batchIndices);
|
||||
}
|
||||
if (FontConfig.fontAAMode != 0) {
|
||||
GLStateManager.glUseProgram(lastActiveProgram);
|
||||
GL20.glDisableVertexAttribArray(texBoundAttrLocation);
|
||||
}
|
||||
|
||||
GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
|
||||
@@ -312,17 +357,28 @@ public class BatchingFontRenderer {
|
||||
return (what >= fromInclusive) && (what <= toInclusive);
|
||||
}
|
||||
|
||||
private ResourceLocation getUnicodePageLocation(int page) {
|
||||
final ResourceLocation lookup = unicodePageLocations[page];
|
||||
if (lookup == null) {
|
||||
final ResourceLocation rl = new ResourceLocation(String.format(
|
||||
"textures/font/unicode_page_%02x.png",
|
||||
page));
|
||||
unicodePageLocations[page] = rl;
|
||||
return rl;
|
||||
} else {
|
||||
return lookup;
|
||||
}
|
||||
public boolean forceDefaults() {
|
||||
return this.isSGA || this.isSplash;
|
||||
}
|
||||
|
||||
public float getGlyphScaleX() {
|
||||
return forceDefaults() ? 1 : (float) (FontConfig.glyphScale * Math.pow(2, FontConfig.glyphAspect)) * (FontStrategist.customFontInUse ? 1.5f : 1);
|
||||
}
|
||||
|
||||
public float getGlyphScaleY() {
|
||||
return forceDefaults() ? 1 : (float) (FontConfig.glyphScale / Math.pow(2, FontConfig.glyphAspect)) * (FontStrategist.customFontInUse ? 1.5f : 1);
|
||||
}
|
||||
|
||||
public float getGlyphSpacing() {
|
||||
return forceDefaults() ? 0 : FontConfig.glyphSpacing;
|
||||
}
|
||||
|
||||
public float getWhitespaceScale() {
|
||||
return forceDefaults() ? 1 : FontConfig.whitespaceScale;
|
||||
}
|
||||
|
||||
public float getShadowOffset() {
|
||||
return forceDefaults() ? 1 : FontConfig.fontShadowOffset;
|
||||
}
|
||||
|
||||
private static final char FORMATTING_CHAR = 167; // §
|
||||
@@ -335,6 +391,9 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
final int shadowColor = (color & 0xfcfcfc) >> 2 | color & 0xff000000;
|
||||
|
||||
FontProviderMC.get(this.isSGA).charWidth = this.charWidth;
|
||||
FontProviderMC.get(this.isSGA).locationFontTexture = this.locationFontTexture;
|
||||
|
||||
this.beginBatch();
|
||||
float curX = anchorX;
|
||||
try {
|
||||
@@ -354,10 +413,14 @@ public class BatchingFontRenderer {
|
||||
boolean curStrikethrough = false;
|
||||
boolean curUnderline = false;
|
||||
|
||||
final float underlineY = anchorY + underlying.FONT_HEIGHT - 1.0f;
|
||||
final float glyphScaleY = getGlyphScaleY();
|
||||
final float heightNorth = anchorY + (underlying.FONT_HEIGHT - 1.0f) * (0.5f - glyphScaleY / 2);
|
||||
final float heightSouth = (underlying.FONT_HEIGHT - 1.0f) * glyphScaleY;
|
||||
|
||||
final float underlineY = heightNorth + (underlying.FONT_HEIGHT - 1.0f) * glyphScaleY;
|
||||
float underlineStartX = 0.0f;
|
||||
float underlineEndX = 0.0f;
|
||||
final float strikethroughY = anchorY + (float) (underlying.FONT_HEIGHT / 2) - 1.0F;
|
||||
final float strikethroughY = heightNorth + ((float) (underlying.FONT_HEIGHT / 2) - 1.0f) * glyphScaleY;
|
||||
float strikethroughStartX = 0.0f;
|
||||
float strikethroughEndX = 0.0f;
|
||||
|
||||
@@ -369,8 +432,8 @@ public class BatchingFontRenderer {
|
||||
|
||||
if (curUnderline && underlineStartX != underlineEndX) {
|
||||
final int ulIdx = idxWriterIndex;
|
||||
pushUntexRect(underlineStartX, underlineY, underlineEndX - underlineStartX, 1.0f, curColor);
|
||||
pushDrawCmd(ulIdx, 6, null);
|
||||
pushUntexRect(underlineStartX, underlineY, underlineEndX - underlineStartX, glyphScaleY, curColor);
|
||||
pushDrawCmd(ulIdx, 6, null, false);
|
||||
underlineStartX = underlineEndX;
|
||||
}
|
||||
if (curStrikethrough && strikethroughStartX != strikethroughEndX) {
|
||||
@@ -379,9 +442,9 @@ public class BatchingFontRenderer {
|
||||
strikethroughStartX,
|
||||
strikethroughY,
|
||||
strikethroughEndX - strikethroughStartX,
|
||||
1.0f,
|
||||
glyphScaleY,
|
||||
curColor);
|
||||
pushDrawCmd(ulIdx, 6, null);
|
||||
pushDrawCmd(ulIdx, 6, null, false);
|
||||
strikethroughStartX = strikethroughEndX;
|
||||
}
|
||||
|
||||
@@ -426,66 +489,27 @@ public class BatchingFontRenderer {
|
||||
continue;
|
||||
}
|
||||
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
if (curRandom && lutIndex != -1) {
|
||||
int randomReplacementIndex;
|
||||
do {
|
||||
randomReplacementIndex = fontRandom.nextInt(this.charWidth.length);
|
||||
} while (this.charWidth[lutIndex] != this.charWidth[randomReplacementIndex]);
|
||||
|
||||
lutIndex = randomReplacementIndex;
|
||||
chr = MCFONT_CHARS.charAt(lutIndex);
|
||||
if (curRandom) {
|
||||
chr = FontProviderMC.get(this.isSGA).getRandomReplacement(chr);
|
||||
}
|
||||
|
||||
final float shadowOffset = unicodeFlag ? 0.5F : 1.0F;
|
||||
FontProvider fontProvider = FontStrategist.getFontProvider(this, chr, FontConfig.enableCustomFont, unicodeFlag);
|
||||
|
||||
// Check ASCII space, NBSP, NNBSP
|
||||
if (chr == ' ' || chr == '\u00A0' || chr == '\u202F') {
|
||||
curX += 4;
|
||||
curX += 4 * this.getWhitespaceScale();
|
||||
continue;
|
||||
}
|
||||
|
||||
final float uStart;
|
||||
final float vStart;
|
||||
final float xAdvance;
|
||||
final float glyphW;
|
||||
final float uSz;
|
||||
final float vSz;
|
||||
final float uStart = fontProvider.getUStart(chr);
|
||||
final float vStart = fontProvider.getVStart(chr);
|
||||
final float xAdvance = fontProvider.getXAdvance(chr) * getGlyphScaleX();
|
||||
final float glyphW = fontProvider.getGlyphW(chr) * getGlyphScaleX();
|
||||
final float uSz = fontProvider.getUSize(chr);
|
||||
final float vSz = fontProvider.getVSize(chr);
|
||||
final float itOff = curItalic ? 1.0F : 0.0F; // italic offset
|
||||
final ResourceLocation texture;
|
||||
|
||||
if (lutIndex == -1 || unicodeFlag) {
|
||||
if (glyphWidth[chr] == 0) {
|
||||
continue;
|
||||
}
|
||||
// Draw unicode char
|
||||
final int uniPage = chr / 256;
|
||||
texture = getUnicodePageLocation(uniPage);
|
||||
final int startColumn = this.glyphWidth[chr] >>> 4;
|
||||
final int endColumn = this.glyphWidth[chr] & 15;
|
||||
final float startColumnF = (float) startColumn;
|
||||
final float endColumnF = (float) (endColumn + 1);
|
||||
uStart = ((float) (chr % 16 * 16) + startColumnF) / 256.0f;
|
||||
vStart = ((float) ((chr & 255) / 16 * 16)) / 256.0f;
|
||||
final float chrWidth = endColumnF - startColumnF - 0.02F;
|
||||
glyphW = chrWidth / 2.0f + 1.0f;
|
||||
xAdvance = (endColumnF - startColumnF) / 2.0F + 1.0F;
|
||||
uSz = chrWidth / 256.0f;
|
||||
vSz = 15.98f / 256.0f;
|
||||
|
||||
} else {
|
||||
// Draw "ASCII" char
|
||||
uStart = ((lutIndex % 16) * 8) / 128.0F;
|
||||
vStart = (float) ((lutIndex / 16) * 8) / 128.0F;
|
||||
xAdvance = this.charWidth[lutIndex];
|
||||
if (xAdvance == 0) {
|
||||
continue;
|
||||
}
|
||||
glyphW = xAdvance - 0.01F;
|
||||
uSz = (glyphW - 1.0F) / 128.0F;
|
||||
vSz = 7.99F / 128.0F;
|
||||
texture = locationFontTexture;
|
||||
}
|
||||
final float shadowOffset = fontProvider.getShadowOffset();
|
||||
final ResourceLocation texture = fontProvider.getTexture(chr);
|
||||
|
||||
final int vtxId = vtxWriterIndex;
|
||||
final int idxId = idxWriterIndex;
|
||||
@@ -493,81 +517,50 @@ public class BatchingFontRenderer {
|
||||
int vtxCount = 0;
|
||||
|
||||
if (enableShadow) {
|
||||
pushVtx(curX + itOff + shadowOffset, anchorY + shadowOffset, curShadowColor, uStart, vStart);
|
||||
pushVtx(
|
||||
curX - itOff + shadowOffset,
|
||||
anchorY + 7.99F + shadowOffset,
|
||||
curShadowColor,
|
||||
uStart,
|
||||
vStart + vSz);
|
||||
pushVtx(curX + glyphW - 1.0F + itOff + shadowOffset,
|
||||
anchorY + shadowOffset,
|
||||
curShadowColor,
|
||||
uStart + uSz,
|
||||
vStart);
|
||||
pushVtx(curX + glyphW - 1.0F - itOff + shadowOffset,
|
||||
anchorY + 7.99F + shadowOffset,
|
||||
curShadowColor,
|
||||
uStart + uSz,
|
||||
vStart + vSz);
|
||||
pushVtx(curX + itOff + shadowOffset, heightNorth + shadowOffset, curShadowColor, uStart, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(curX - itOff + shadowOffset, heightNorth + heightSouth + shadowOffset, curShadowColor, uStart, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(curX + glyphW - 1.0F + itOff + shadowOffset, heightNorth + shadowOffset, curShadowColor, uStart + uSz, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(curX + glyphW - 1.0F - itOff + shadowOffset, heightNorth + heightSouth + shadowOffset, curShadowColor, uStart + uSz, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushQuadIdx(vtxId + vtxCount);
|
||||
vtxCount += 4;
|
||||
|
||||
if (curBold) {
|
||||
final float shadowOffset2 = 2.0f * shadowOffset;
|
||||
pushVtx(curX + itOff + shadowOffset2, anchorY + shadowOffset, curShadowColor, uStart, vStart);
|
||||
pushVtx(
|
||||
curX - itOff + shadowOffset2,
|
||||
anchorY + 7.99F + shadowOffset,
|
||||
curShadowColor,
|
||||
uStart,
|
||||
vStart + vSz);
|
||||
pushVtx(
|
||||
curX + glyphW - 1.0F + itOff + shadowOffset2,
|
||||
anchorY + shadowOffset,
|
||||
curShadowColor,
|
||||
uStart + uSz,
|
||||
vStart);
|
||||
pushVtx(curX + glyphW - 1.0F - itOff + shadowOffset2,
|
||||
anchorY + 7.99F + shadowOffset,
|
||||
curShadowColor,
|
||||
uStart + uSz,
|
||||
vStart + vSz);
|
||||
pushVtx(curX + itOff + shadowOffset2, heightNorth + shadowOffset, curShadowColor, uStart, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(curX - itOff + shadowOffset2, heightNorth + heightSouth + shadowOffset, curShadowColor, uStart, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(curX + glyphW - 1.0F + itOff + shadowOffset2, heightNorth + shadowOffset, curShadowColor, uStart + uSz, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(curX + glyphW - 1.0F - itOff + shadowOffset2, heightNorth + heightSouth + shadowOffset, curShadowColor, uStart + uSz, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushQuadIdx(vtxId + vtxCount);
|
||||
vtxCount += 4;
|
||||
}
|
||||
}
|
||||
|
||||
pushVtx(curX + itOff, anchorY, curColor, uStart, vStart);
|
||||
pushVtx(curX - itOff, anchorY + 7.99F, curColor, uStart, vStart + vSz);
|
||||
pushVtx(curX + glyphW - 1.0F + itOff, anchorY, curColor, uStart + uSz, vStart);
|
||||
pushVtx(curX + glyphW - 1.0F - itOff, anchorY + 7.99F, curColor, uStart + uSz, vStart + vSz);
|
||||
pushVtx(curX + itOff, heightNorth, curColor, uStart, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(curX - itOff, heightNorth + heightSouth, curColor, uStart, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(curX + glyphW - 1.0F + itOff, heightNorth, curColor, uStart + uSz, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(curX + glyphW - 1.0F - itOff, heightNorth + heightSouth, curColor, uStart + uSz, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushQuadIdx(vtxId + vtxCount);
|
||||
vtxCount += 4;
|
||||
|
||||
if (curBold) {
|
||||
pushVtx(shadowOffset + curX + itOff, anchorY, curColor, uStart, vStart);
|
||||
pushVtx(shadowOffset + curX - itOff, anchorY + 7.99F, curColor, uStart, vStart + vSz);
|
||||
pushVtx(shadowOffset + curX + glyphW - 1.0F + itOff, anchorY, curColor, uStart + uSz, vStart);
|
||||
pushVtx(shadowOffset + curX + glyphW - 1.0F - itOff,
|
||||
anchorY + 7.99F,
|
||||
curColor,
|
||||
uStart + uSz,
|
||||
vStart + vSz);
|
||||
pushVtx(shadowOffset + curX + itOff, heightNorth, curColor, uStart, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(shadowOffset + curX - itOff, heightNorth + heightSouth, curColor, uStart, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(shadowOffset + curX + glyphW - 1.0F + itOff, heightNorth, curColor, uStart + uSz, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(shadowOffset + curX + glyphW - 1.0F - itOff, heightNorth + heightSouth, curColor, uStart + uSz, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushQuadIdx(vtxId + vtxCount);
|
||||
vtxCount += 4;
|
||||
}
|
||||
|
||||
pushDrawCmd(idxId, vtxCount / 2 * 3, texture);
|
||||
curX += xAdvance + (curBold ? shadowOffset : 0.0f);
|
||||
pushDrawCmd(idxId, vtxCount / 2 * 3, texture, chr > 255);
|
||||
curX += (xAdvance + (curBold ? shadowOffset : 0.0f)) + getGlyphSpacing();
|
||||
underlineEndX = curX;
|
||||
strikethroughEndX = curX;
|
||||
}
|
||||
|
||||
if (curUnderline && underlineStartX != underlineEndX) {
|
||||
final int ulIdx = idxWriterIndex;
|
||||
pushUntexRect(underlineStartX, underlineY, underlineEndX - underlineStartX, 1.0f, curColor);
|
||||
pushDrawCmd(ulIdx, 6, null);
|
||||
pushUntexRect(underlineStartX, underlineY, underlineEndX - underlineStartX, glyphScaleY, curColor);
|
||||
pushDrawCmd(ulIdx, 6, null, false);
|
||||
}
|
||||
if (curStrikethrough && strikethroughStartX != strikethroughEndX) {
|
||||
final int ulIdx = idxWriterIndex;
|
||||
@@ -575,9 +568,9 @@ public class BatchingFontRenderer {
|
||||
strikethroughStartX,
|
||||
strikethroughY,
|
||||
strikethroughEndX - strikethroughStartX,
|
||||
1.0f,
|
||||
glyphScaleY,
|
||||
curColor);
|
||||
pushDrawCmd(ulIdx, 6, null);
|
||||
pushDrawCmd(ulIdx, 6, null, false);
|
||||
}
|
||||
|
||||
} finally {
|
||||
@@ -586,4 +579,25 @@ public class BatchingFontRenderer {
|
||||
return curX + (enableShadow ? 1.0f : 0.0f);
|
||||
}
|
||||
|
||||
public float getCharWidthFine(char chr) {
|
||||
if (chr == FORMATTING_CHAR) { return -1; }
|
||||
|
||||
if (chr == ' ' || chr == '\u00A0' || chr == '\u202F') {
|
||||
return 4 * this.getWhitespaceScale();
|
||||
}
|
||||
|
||||
FontProvider fp = FontStrategist.getFontProvider(this, chr, FontConfig.enableCustomFont, underlying.getUnicodeFlag());
|
||||
|
||||
return fp.getXAdvance(chr) * this.getGlyphScaleX();
|
||||
}
|
||||
|
||||
public void overrideBlendFunc(int srcRgb, int dstRgb) {
|
||||
blendSrcRGB = srcRgb;
|
||||
blendDstRGB = dstRgb;
|
||||
}
|
||||
|
||||
public void resetBlendFunc() {
|
||||
blendSrcRGB = GL11.GL_SRC_ALPHA;
|
||||
blendDstRGB = GL11.GL_ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public interface FontProvider {
|
||||
|
||||
/**
|
||||
* For use with §k. Should fetch a character of the same width as provided.
|
||||
*/
|
||||
char getRandomReplacement(char chr);
|
||||
boolean isGlyphAvailable(char chr);
|
||||
float getUStart(char chr);
|
||||
float getVStart(char chr);
|
||||
float getXAdvance(char chr);
|
||||
float getGlyphW(char chr);
|
||||
float getUSize(char chr);
|
||||
float getVSize(char chr);
|
||||
float getShadowOffset();
|
||||
ResourceLocation getTexture(char chr);
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.config.ConfigurationManager;
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import lombok.Setter;
|
||||
import lombok.Value;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.ITextureObject;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.renderer.texture.TextureUtil;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class FontProviderCustom implements FontProvider {
|
||||
|
||||
public static final Logger LOGGER = LogManager.getLogger("Angelica");
|
||||
public static final String FONT_DIR = "fonts/custom/";
|
||||
static final int ATLAS_SIZE = 128;
|
||||
static final int ATLAS_COUNT = 512;
|
||||
private final byte id; // 0 - primary font, 1 - fallback font
|
||||
private FontAtlas[] fontAtlases = new FontAtlas[ATLAS_COUNT];
|
||||
private float currentFontQuality = FontConfig.customFontQuality;
|
||||
@Setter
|
||||
private Font font;
|
||||
|
||||
private FontProviderCustom(byte id) {
|
||||
this.id = id;
|
||||
Font[] availableFonts = FontStrategist.getAvailableFonts();
|
||||
if (availableFonts.length == 0) {
|
||||
LOGGER.fatal("There seem to be no fonts available on this system! Disabling custom font and throwing an exception in an attempt to restore the session.");
|
||||
FontConfig.enableCustomFont = false;
|
||||
ConfigurationManager.save(FontConfig.class);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
String myFontName = switch (this.id) {
|
||||
case 0 -> FontConfig.customFontNamePrimary;
|
||||
case 1 -> FontConfig.customFontNameFallback;
|
||||
default -> null;
|
||||
};
|
||||
if (Objects.equals(myFontName, "(none)")) {
|
||||
font = null;
|
||||
return;
|
||||
}
|
||||
int fontPos = -1;
|
||||
for (int i = 0; i < availableFonts.length; i++) {
|
||||
if (Objects.equals(myFontName, availableFonts[i].getFontName())) {
|
||||
fontPos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fontPos == -1) {
|
||||
LOGGER.info("Could not find previously set font \"{}\". ", myFontName);
|
||||
font = null;
|
||||
return;
|
||||
}
|
||||
font = availableFonts[fontPos].deriveFont(currentFontQuality);
|
||||
}
|
||||
private static class InstLoader {
|
||||
static final FontProviderCustom instance0 = new FontProviderCustom((byte)0);
|
||||
static final FontProviderCustom instance1 = new FontProviderCustom((byte)1);
|
||||
}
|
||||
public static FontProviderCustom getPrimary() { return InstLoader.instance0; }
|
||||
public static FontProviderCustom getFallback() { return InstLoader.instance1; }
|
||||
|
||||
public void reloadFont(int fontID) {
|
||||
currentFontQuality = FontConfig.customFontQuality;
|
||||
font = FontStrategist.getAvailableFonts()[fontID].deriveFont(currentFontQuality);
|
||||
|
||||
File[] files = new File(getFontDir()).listFiles();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
if (!Files.isSymbolicLink(f.toPath())) {
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextureManager tm = Minecraft.getMinecraft().getTextureManager();
|
||||
Map mapTextureObjects = tm.mapTextureObjects;
|
||||
for (int i = 0; i < ATLAS_COUNT; i++) {
|
||||
ResourceLocation key = new ResourceLocation(getAtlasResourceName(i));
|
||||
if (mapTextureObjects.containsKey(key)) {
|
||||
ITextureObject obj = (ITextureObject) mapTextureObjects.get(key);
|
||||
TextureUtil.deleteTexture(obj.getGlTextureId());
|
||||
mapTextureObjects.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
fontAtlases = new FontAtlas[ATLAS_COUNT];
|
||||
}
|
||||
|
||||
private String getFontDir() {
|
||||
return FONT_DIR + "f" + this.id + "/";
|
||||
}
|
||||
|
||||
private String getAtlasFilename(int atlasId) {
|
||||
return "f" + this.id + "p" + atlasId;
|
||||
}
|
||||
|
||||
String getAtlasResourceName(int atlasId) {
|
||||
return "minecraft:angelica_c" + getAtlasFilename(atlasId);
|
||||
}
|
||||
|
||||
String getAtlasFullPath(int atlasId) {
|
||||
return getFontDir() + getAtlasFilename(atlasId) + ".png";
|
||||
}
|
||||
|
||||
@Value
|
||||
private class GlyphData {
|
||||
float uStart;
|
||||
float vStart;
|
||||
float xAdvance;
|
||||
float glyphW;
|
||||
float uSz;
|
||||
float vSz;
|
||||
}
|
||||
|
||||
private class FontAtlas {
|
||||
|
||||
GlyphData[] glyphData = new GlyphData[ATLAS_SIZE];
|
||||
private ResourceLocation texture;
|
||||
private final int id;
|
||||
|
||||
FontAtlas(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
void construct(Font font) {
|
||||
float separator = currentFontQuality / 3f;
|
||||
|
||||
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = image.createGraphics();
|
||||
g2d.setFont(font);
|
||||
FontMetrics fm = g2d.getFontMetrics();
|
||||
g2d.dispose();
|
||||
int width = 0;
|
||||
int actualChars = 0;
|
||||
for (int i = 0; i < ATLAS_SIZE; i++) {
|
||||
final char ch = (char)(i + ATLAS_SIZE * this.id);
|
||||
if (font.canDisplay(ch)) {
|
||||
width += (int) (separator + fm.charWidth(ch));
|
||||
actualChars++;
|
||||
}
|
||||
}
|
||||
if (actualChars == 0) {
|
||||
return;
|
||||
}
|
||||
final int atlasTilesX = (int) Math.ceil(Math.sqrt(actualChars) * 1.5f);
|
||||
final int atlasTilesY = (int) Math.ceil((double) actualChars / atlasTilesX);
|
||||
LOGGER.info("constructing custom font atlas (ID {}) of nominal size {} chars, actual: {}, {} rows by {} columns",
|
||||
this.id, ATLAS_SIZE, actualChars, atlasTilesX, atlasTilesY);
|
||||
width = 0;
|
||||
actualChars = 0;
|
||||
int maxRowWidth = 0;
|
||||
for (int i = 0; i < ATLAS_SIZE; i++) {
|
||||
if (actualChars % atlasTilesX == 0) {
|
||||
maxRowWidth = Math.max(maxRowWidth, width);
|
||||
width = 0;
|
||||
}
|
||||
final char ch = (char)(i + ATLAS_SIZE * this.id);
|
||||
if (font.canDisplay(ch)) {
|
||||
width += (int) (separator + fm.charWidth(ch));
|
||||
actualChars++;
|
||||
}
|
||||
}
|
||||
maxRowWidth = Math.max(maxRowWidth, width);
|
||||
|
||||
final int lineHeight = fm.getHeight();
|
||||
final float desc = fm.getDescent();
|
||||
|
||||
final int imageWidth = (int) (maxRowWidth + separator);
|
||||
final int imageHeight = (int) ((separator + lineHeight) * atlasTilesY + separator);
|
||||
|
||||
image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
g2d = image.createGraphics();
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
g2d.setFont(font);
|
||||
fm = g2d.getFontMetrics();
|
||||
|
||||
int tileX = 0, tileY = 0; // position in atlas tiles
|
||||
int imgX = (int) separator; // position in pixels
|
||||
|
||||
for (int i = 0; i < ATLAS_SIZE; i++) {
|
||||
final char ch = (char)(i + ATLAS_SIZE * this.id);
|
||||
if (!font.canDisplay(ch)) { continue; }
|
||||
|
||||
if (tileX >= atlasTilesX) {
|
||||
tileX = 0;
|
||||
imgX = (int) separator;
|
||||
tileY++;
|
||||
}
|
||||
|
||||
final int charWidth = fm.charWidth(ch);
|
||||
final float charAspectRatio = (float) charWidth / lineHeight;
|
||||
final float inset = currentFontQuality / 16;
|
||||
g2d.drawString(Character.toString(ch), imgX, (lineHeight + separator) * (tileY + 1) - desc);
|
||||
final float uStart = (float) (imgX - inset * charAspectRatio) / imageWidth;
|
||||
final float vStart = ((lineHeight + separator) * (tileY + 1) - lineHeight - inset) / imageHeight;
|
||||
final float xAdvance = charAspectRatio * 8 * charWidth / (charWidth + 2 * inset * charAspectRatio);
|
||||
final float glyphW = charAspectRatio * 8 + 1;
|
||||
final float uSz = (float) (charWidth + 2 * inset * charAspectRatio) / imageWidth;
|
||||
final float vSz = (float) (lineHeight + 2 * inset) / imageHeight;
|
||||
glyphData[i] = new GlyphData(uStart, vStart, xAdvance, glyphW, uSz, vSz);
|
||||
imgX += (int) (charWidth + separator);
|
||||
tileX++;
|
||||
}
|
||||
g2d.dispose();
|
||||
try {
|
||||
LOGGER.info("writing custom font atlas texture ({}x{} px) to {}", imageWidth, imageHeight, getAtlasFullPath(this.id));
|
||||
Files.createDirectories(Paths.get(getFontDir()));
|
||||
ImageIO.write(image, "png", new File(getAtlasFullPath(this.id)));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.texture = new ResourceLocation(getAtlasResourceName(this.id));
|
||||
}
|
||||
}
|
||||
|
||||
private FontAtlas getAtlas(char chr) {
|
||||
int id = chr / ATLAS_SIZE;
|
||||
FontAtlas fa = fontAtlases[id];
|
||||
if (fa == null) {
|
||||
fa = new FontAtlas(id);
|
||||
fa.construct(font);
|
||||
}
|
||||
fontAtlases[id] = fa;
|
||||
return fa;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGlyphAvailable(char chr) {
|
||||
if (font == null) { return false; }
|
||||
return (getAtlas(chr).glyphData[chr % ATLAS_SIZE] != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getRandomReplacement(char chr) {
|
||||
return chr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUStart(char chr) {
|
||||
return getAtlas(chr).glyphData[chr % ATLAS_SIZE].uStart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVStart(char chr) {
|
||||
return getAtlas(chr).glyphData[chr % ATLAS_SIZE].vStart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getXAdvance(char chr) {
|
||||
return getAtlas(chr).glyphData[chr % ATLAS_SIZE].xAdvance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getGlyphW(char chr) {
|
||||
return getAtlas(chr).glyphData[chr % ATLAS_SIZE].glyphW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUSize(char chr) {
|
||||
return getAtlas(chr).glyphData[chr % ATLAS_SIZE].uSz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVSize(char chr) {
|
||||
return getAtlas(chr).glyphData[chr % ATLAS_SIZE].vSz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getShadowOffset() {
|
||||
return FontConfig.fontShadowOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTexture(char chr) {
|
||||
return getAtlas(chr).texture;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import it.unimi.dsi.fastutil.chars.Char2ShortOpenHashMap;
|
||||
import jss.util.RandomXoshiro256StarStar;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public final class FontProviderMC implements FontProvider {
|
||||
|
||||
/**
|
||||
* The full list of characters present in the default Minecraft font, excluding the Unicode font
|
||||
*/
|
||||
@SuppressWarnings("UnnecessaryUnicodeEscape")
|
||||
private static final String MCFONT_CHARS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u2302\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
|
||||
|
||||
private FontProviderMC() {}
|
||||
private static class InstLoader {
|
||||
static final FontProviderMC instance = new FontProviderMC();
|
||||
static final FontProviderMC instanceSGA = new FontProviderMC();
|
||||
}
|
||||
public static FontProviderMC get(boolean isSGA) {
|
||||
return (isSGA ? InstLoader.instanceSGA : InstLoader.instance);
|
||||
}
|
||||
|
||||
private static final Char2ShortOpenHashMap MCFONT_ASCII_MAP = new Char2ShortOpenHashMap();
|
||||
ResourceLocation locationFontTexture = null;
|
||||
private final RandomXoshiro256StarStar fontRandom = new RandomXoshiro256StarStar();
|
||||
public int[] charWidth;
|
||||
|
||||
static {
|
||||
for (short i = 0; i < MCFONT_CHARS.length(); i++) {
|
||||
MCFONT_ASCII_MAP.put(MCFONT_CHARS.charAt(i), i);
|
||||
}
|
||||
}
|
||||
|
||||
public int lookupMcFontPosition(char ch) {
|
||||
if (isGlyphAvailable(ch)) {
|
||||
return MCFONT_ASCII_MAP.get(ch);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGlyphAvailable(char chr) {
|
||||
return MCFONT_ASCII_MAP.containsKey(chr);
|
||||
}
|
||||
|
||||
public char getRandomReplacement(char chr){
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
if (lutIndex != -1) {
|
||||
int randomReplacementIndex;
|
||||
do {
|
||||
randomReplacementIndex = fontRandom.nextInt(this.charWidth.length);
|
||||
} while (this.charWidth[lutIndex] != this.charWidth[randomReplacementIndex]);
|
||||
|
||||
lutIndex = randomReplacementIndex;
|
||||
return MCFONT_CHARS.charAt(lutIndex);
|
||||
}
|
||||
return chr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUStart(char chr) {
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
return ((lutIndex % 16) * 8) / 128.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVStart(char chr) {
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
return (float) ((lutIndex / 16) * 8) / 128.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getXAdvance(char chr) {
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
return charWidth[lutIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getGlyphW(char chr) {
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
return charWidth[lutIndex] - 0.01F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUSize(char chr) {
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
return (charWidth[lutIndex] - 1.01F) / 128.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVSize(char chr) {
|
||||
return 7.99F / 128.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getShadowOffset() {
|
||||
return FontConfig.fontShadowOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTexture(char chr) {
|
||||
return locationFontTexture;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public final class FontProviderUnicode implements FontProvider {
|
||||
|
||||
private FontProviderUnicode() {}
|
||||
private static class InstLoader { static final FontProviderUnicode instance = new FontProviderUnicode(); }
|
||||
public static FontProviderUnicode get() { return FontProviderUnicode.InstLoader.instance; }
|
||||
|
||||
private static final ResourceLocation[] unicodePageLocations = new ResourceLocation[256];
|
||||
public byte[] glyphWidth;
|
||||
|
||||
private ResourceLocation getUnicodePageLocation(int page) {
|
||||
final ResourceLocation lookup = unicodePageLocations[page];
|
||||
if (lookup == null) {
|
||||
final ResourceLocation rl = new ResourceLocation(String.format(
|
||||
"textures/font/unicode_page_%02x.png",
|
||||
page));
|
||||
unicodePageLocations[page] = rl;
|
||||
return rl;
|
||||
} else {
|
||||
return lookup;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGlyphAvailable(char chr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getRandomReplacement(char chr) {
|
||||
return chr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUStart(char chr) {
|
||||
final float startColumnF = (float)(this.glyphWidth[chr] >>> 4);
|
||||
return ((float) (chr % 16 * 16) + startColumnF + 0.21f) / 256.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVStart(char chr) {
|
||||
return ((float) ((chr & 255) / 16 * 16) + 0.21f) / 256.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getXAdvance(char chr) {
|
||||
final int startColumn = this.glyphWidth[chr] >>> 4;
|
||||
final int endColumn = this.glyphWidth[chr] & 15;
|
||||
final float startColumnF = (float) startColumn;
|
||||
final float endColumnF = (float) (endColumn + 1);
|
||||
return (endColumnF - startColumnF) / 2.0F + 1.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getGlyphW(char chr) {
|
||||
final int startColumn = this.glyphWidth[chr] >>> 4;
|
||||
final int endColumn = this.glyphWidth[chr] & 15;
|
||||
final float startColumnF = (float) startColumn;
|
||||
final float endColumnF = (float) (endColumn + 1);
|
||||
final float chrWidth = endColumnF - startColumnF - 0.02F;
|
||||
return chrWidth / 2.0f + 1.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUSize(char chr) {
|
||||
final int startColumn = this.glyphWidth[chr] >>> 4;
|
||||
final int endColumn = this.glyphWidth[chr] & 15;
|
||||
final float startColumnF = (float) startColumn;
|
||||
final float endColumnF = (float) (endColumn + 1);
|
||||
final float chrWidth = endColumnF - startColumnF - 0.02F;
|
||||
return (chrWidth - 0.42f) / 256.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVSize(char chr) {
|
||||
return (16.0f - 0.42f) / 256.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getShadowOffset() {
|
||||
return FontConfig.fontShadowOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTexture(char chr) {
|
||||
final int uniPage = chr / 256;
|
||||
return getUnicodePageLocation(uniPage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.ResourceAccessor;
|
||||
import cpw.mods.fml.client.SplashProgress;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.resources.DefaultResourcePack;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.io.File;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class FontStrategist {
|
||||
|
||||
@Getter
|
||||
private static final Font[] availableFonts;
|
||||
public static final Logger LOGGER = LogManager.getLogger("Angelica");
|
||||
public static boolean customFontInUse;
|
||||
|
||||
static {
|
||||
// get available fonts without duplicates (250 copies of dialog.plain need not apply)
|
||||
Font[] availableFontsDirty = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
|
||||
HashMap<String, Font> fontSet = new HashMap<>();
|
||||
HashMultiset<String> duplicates = HashMultiset.create(); // for debugging
|
||||
|
||||
for (Font font : availableFontsDirty) {
|
||||
String fontName = font.getFontName();
|
||||
if (fontSet.containsKey(fontName)) {
|
||||
duplicates.add(fontName);
|
||||
} else {
|
||||
fontSet.put(fontName, font);
|
||||
}
|
||||
}
|
||||
|
||||
if (!duplicates.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder(duplicates.size() + " duplicate font(s) found in the list reported by Java: ");
|
||||
for (Iterator<String> iter = duplicates.stream().distinct().iterator(); iter.hasNext(); ) {
|
||||
String dupe = iter.next();
|
||||
sb.append(duplicates.count(dupe)).append("x ").append(dupe);
|
||||
if (iter.hasNext()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append(". Some fonts may be missing from the font selection menu.");
|
||||
LOGGER.warn(sb.toString());
|
||||
}
|
||||
|
||||
availableFonts = fontSet.values().stream().sorted(Comparator.comparing(Font::getFontName)).toArray(Font[]::new);
|
||||
|
||||
// create and add the resource pack that provides fonts
|
||||
HashMap<String, File> packMap = new HashMap<>();
|
||||
for (int i = 0; i < FontProviderCustom.ATLAS_COUNT; i++) {
|
||||
packMap.put(FontProviderCustom.getPrimary().getAtlasResourceName(i), new File(FontProviderCustom.getPrimary().getAtlasFullPath(i)));
|
||||
packMap.put(FontProviderCustom.getFallback().getAtlasResourceName(i), new File(FontProviderCustom.getFallback().getAtlasFullPath(i)));
|
||||
}
|
||||
|
||||
DefaultResourcePack fontResourcePack = new DefaultResourcePack(packMap);
|
||||
List defaultResourcePacks = ((ResourceAccessor) Minecraft.getMinecraft()).angelica$getDefaultResourcePacks();
|
||||
defaultResourcePacks.add(fontResourcePack);
|
||||
Minecraft.getMinecraft().refreshResources();
|
||||
|
||||
// determine if a custom font is in use based on config values
|
||||
boolean primaryFontFound = false;
|
||||
boolean fallbackFontFound = false;
|
||||
for (Font availableFont : availableFonts) {
|
||||
if (Objects.equals(FontConfig.customFontNamePrimary, availableFont.getFontName())) {
|
||||
primaryFontFound = true;
|
||||
break;
|
||||
}
|
||||
if (Objects.equals(FontConfig.customFontNameFallback, availableFont.getFontName())) {
|
||||
fallbackFontFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
customFontInUse = (FontConfig.enableCustomFont && (primaryFontFound || fallbackFontFound));
|
||||
}
|
||||
|
||||
/**
|
||||
Lets you get a FontProvider per char while respecting font priority and fallbacks, the unicode flag, whether or not
|
||||
SGA is on, if we're in a splash screen, if a font can even display a character in the first place, etc.
|
||||
*/
|
||||
public static FontProvider getFontProvider(BatchingFontRenderer me, char chr, boolean customFontEnabled, boolean forceUnicode) {
|
||||
if (me.isSGA && FontProviderMC.get(true).isGlyphAvailable(chr)) {
|
||||
return FontProviderMC.get(true);
|
||||
}
|
||||
if (customFontEnabled && !me.isSplash) {
|
||||
FontProvider fp;
|
||||
fp = FontProviderCustom.getPrimary();
|
||||
if (fp.isGlyphAvailable(chr)) { return fp; }
|
||||
fp = FontProviderCustom.getFallback();
|
||||
if (fp.isGlyphAvailable(chr)) { return fp; }
|
||||
return FontProviderUnicode.get();
|
||||
} else {
|
||||
if (!forceUnicode && FontProviderMC.get(false).isGlyphAvailable(chr)) {
|
||||
return FontProviderMC.get(false);
|
||||
} else {
|
||||
return FontProviderUnicode.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void reloadCustomFontProviders() {
|
||||
FontProviderCustom.getPrimary().setFont(null);
|
||||
FontProviderCustom.getFallback().setFont(null);
|
||||
boolean primaryFontFound = false;
|
||||
boolean fallbackFontFound = false;
|
||||
for (int i = 0; i < availableFonts.length; i++) {
|
||||
if (Objects.equals(FontConfig.customFontNamePrimary, availableFonts[i].getFontName())) {
|
||||
FontProviderCustom.getPrimary().reloadFont(i);
|
||||
primaryFontFound = true;
|
||||
}
|
||||
if (Objects.equals(FontConfig.customFontNameFallback, availableFonts[i].getFontName())) {
|
||||
FontProviderCustom.getFallback().reloadFont(i);
|
||||
fallbackFontFound = true;
|
||||
}
|
||||
if (primaryFontFound && fallbackFontFound) { break; }
|
||||
}
|
||||
customFontInUse = (FontConfig.enableCustomFont && (primaryFontFound || fallbackFontFound));
|
||||
}
|
||||
|
||||
public static boolean isSplashFontRendererActive(FontRenderer fontRenderer) {
|
||||
// noinspection deprecation
|
||||
boolean active = fontRenderer instanceof SplashProgress.SplashFontRenderer;
|
||||
|
||||
try {
|
||||
Class<?> customSplashClass = Class.forName("gkappa.modernsplash.CustomSplash$SplashFontRenderer");
|
||||
active = active || customSplashClass.isInstance(fontRenderer);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
|
||||
return active;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
package com.gtnewhorizons.angelica.client.gui;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.config.ConfigException;
|
||||
import com.gtnewhorizon.gtnhlib.config.ConfigurationManager;
|
||||
import com.gtnewhorizons.angelica.client.font.FontStrategist;
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import net.coderbot.iris.gui.element.widget.IrisButton;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.GuiSlot;
|
||||
import net.minecraft.client.gui.GuiTextField;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class FontConfigScreen extends GuiScreen {
|
||||
|
||||
private static final Font[] availableFonts = FontStrategist.getAvailableFonts();
|
||||
private final GuiScreen parent;
|
||||
private final String title;
|
||||
private final String searchPrompt;
|
||||
private String currentPrimaryFontName;
|
||||
private String currentFallbackFontName;
|
||||
private FontList fontList;
|
||||
private int selectedPrimaryFontListPos = -1;
|
||||
private int selectedFallbackFontListPos = -1;
|
||||
private ArrayList<Font> displayedFonts;
|
||||
private GuiTextField searchBox;
|
||||
|
||||
public FontConfigScreen(GuiScreen parent) {
|
||||
this.title = I18n.format("options.angelica.fontconfig.title");
|
||||
this.searchPrompt = I18n.format("options.angelica.fontconfig.searchprompt");
|
||||
this.parent = parent;
|
||||
this.currentPrimaryFontName = FontConfig.customFontNamePrimary;
|
||||
this.currentFallbackFontName = FontConfig.customFontNameFallback;
|
||||
this.displayedFonts = new ArrayList<>(Arrays.asList(availableFonts));
|
||||
for (int i = 0; i < availableFonts.length; i++) {
|
||||
if (Objects.equals(this.currentPrimaryFontName, availableFonts[i].getFontName())) {
|
||||
selectedPrimaryFontListPos = i;
|
||||
}
|
||||
if (Objects.equals(this.currentFallbackFontName, availableFonts[i].getFontName())) {
|
||||
selectedFallbackFontListPos = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SliderClone.Option optFontQuality = new SliderClone.Option(6, 72, 6);
|
||||
SliderClone.Option optShadowOffset = new SliderClone.Option(0, 2, 0.05f);
|
||||
SliderClone.Option optGlyphAspect = new SliderClone.Option(-1, 1, 0.05f);
|
||||
SliderClone.Option optGlyphScale = new SliderClone.Option(0.1f, 3, 0.05f);
|
||||
SliderClone.Option optWhitespaceScale = new SliderClone.Option(0.1f, 3, 0.05f);
|
||||
SliderClone.Option optGlyphSpacing = new SliderClone.Option(-2f, 2f, 0.05f);
|
||||
SliderClone.Option optFontAAMode = new SliderClone.Option(0, 2, 1);
|
||||
SliderClone.Option optFontAAStrength = new SliderClone.Option(1, 24, 1);
|
||||
|
||||
public void initGui() {
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
searchBox = new GuiTextField(this.fontRendererObj, this.width / 2 - 120, 24, 240, 20);
|
||||
searchBox.setMaxStringLength(64);
|
||||
fontList = new FontList();
|
||||
initButtons();
|
||||
}
|
||||
|
||||
private void initButtons() {
|
||||
this.buttonList.add(new IrisButton(this.width / 2 - 81 - 165, this.height - 20 - 7, 162, 20,
|
||||
FontConfig.enableCustomFont ? I18n.format("options.angelica.fontconfig.disable_custom_font") :
|
||||
I18n.format("options.angelica.fontconfig.enable_custom_font"), this::toggleCustomFont));
|
||||
this.buttonList.add(new IrisButton(this.width / 2 - 80, this.height - 20 - 7, 160, 20,
|
||||
I18n.format("options.angelica.fontconfig.reset_values"), this::resetValues));
|
||||
this.buttonList.add(new IrisButton(this.width / 2 - 81 + 165, this.height - 20 - 7, 162, 20,
|
||||
I18n.format("gui.done"), button -> this.onClose()));
|
||||
|
||||
// might refactor later, feeling too lazy at the moment
|
||||
this.buttonList.add(new SliderClone( this.width / 2 - 60 - 186, this.height - 40 - 11, 120, 20,
|
||||
optFontQuality, FontConfig.customFontQuality, this::setFontQuality,
|
||||
value -> I18n.format("options.angelica.fontconfig.font_quality", String.format("%2.0f", value)),
|
||||
"options.angelica.fontconfig.font_quality.tooltip"));
|
||||
this.buttonList.add(new SliderClone( this.width / 2 - 60 - 186, this.height - 60 - 15, 120, 20,
|
||||
optShadowOffset, FontConfig.fontShadowOffset, value -> FontConfig.fontShadowOffset = value,
|
||||
value -> I18n.format("options.angelica.fontconfig.shadow_offset", String.format("x%3.2f", value)),
|
||||
"options.angelica.fontconfig.shadow_offset.tooltip"));
|
||||
this.buttonList.add(new SliderClone( this.width / 2 - 60 - 62, this.height - 40 - 11, 120, 20,
|
||||
optGlyphAspect, FontConfig.glyphAspect, value -> FontConfig.glyphAspect = value,
|
||||
value -> I18n.format("options.angelica.fontconfig.glyph_aspect", String.format("%3.2f", value)),
|
||||
"options.angelica.fontconfig.glyph_aspect.tooltip"));
|
||||
this.buttonList.add(new SliderClone( this.width / 2 - 60 - 62, this.height - 60 - 15, 120, 20,
|
||||
optGlyphScale, FontConfig.glyphScale, value -> FontConfig.glyphScale = value,
|
||||
value -> I18n.format("options.angelica.fontconfig.glyph_scale", String.format("x%3.2f", value)),
|
||||
"options.angelica.fontconfig.glyph_scale.tooltip"));
|
||||
this.buttonList.add(new SliderClone( this.width / 2 - 60 + 62, this.height - 40 - 11, 120, 20,
|
||||
optWhitespaceScale, FontConfig.whitespaceScale, value -> FontConfig.whitespaceScale = value,
|
||||
value -> I18n.format("options.angelica.fontconfig.whitespace_scale", String.format("x%3.2f", value)),
|
||||
"options.angelica.fontconfig.whitespace_scale.tooltip"));
|
||||
this.buttonList.add(new SliderClone( this.width / 2 - 60 + 62, this.height - 60 - 15, 120, 20,
|
||||
optGlyphSpacing, FontConfig.glyphSpacing, value -> FontConfig.glyphSpacing = value,
|
||||
value -> I18n.format("options.angelica.fontconfig.glyph_spacing", String.format("%3.2f", value)),
|
||||
"options.angelica.fontconfig.glyph_spacing.tooltip"));
|
||||
this.buttonList.add(new SliderClone( this.width / 2 - 60 + 186, this.height - 40 - 11, 120, 20,
|
||||
optFontAAStrength, FontConfig.fontAAStrength, value -> FontConfig.fontAAStrength = value.intValue(),
|
||||
value -> I18n.format("options.angelica.fontconfig.font_aa_strength", String.format("%.0f", value)),
|
||||
"options.angelica.fontconfig.font_aa_strength.tooltip"));
|
||||
this.buttonList.add(new SliderClone( this.width / 2 - 60 + 186, this.height - 60 - 15, 120, 20,
|
||||
optFontAAMode, FontConfig.fontAAMode, value -> FontConfig.fontAAMode = value.intValue(),
|
||||
this::fontAAModeFormat,
|
||||
"options.angelica.fontconfig.aamode.tooltip"));
|
||||
}
|
||||
|
||||
private void onClose() {
|
||||
applyChanges(true);
|
||||
this.mc.displayGuiScreen(parent);
|
||||
}
|
||||
|
||||
private void applyChanges(boolean finalApply) {
|
||||
int pos;
|
||||
pos = selectedPrimaryFontListPos;
|
||||
if (pos >= 0 && pos < displayedFonts.size()) {
|
||||
FontConfig.customFontNamePrimary = displayedFonts.get(pos).getFontName();
|
||||
}
|
||||
pos = selectedFallbackFontListPos;
|
||||
if (pos >= 0 && pos < displayedFonts.size()) {
|
||||
FontConfig.customFontNameFallback = displayedFonts.get(pos).getFontName();
|
||||
}
|
||||
|
||||
FontStrategist.reloadCustomFontProviders();
|
||||
|
||||
if (finalApply) {
|
||||
ConfigurationManager.save(FontConfig.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void resetValues(IrisButton button) {
|
||||
try {
|
||||
ConfigurationManager.getConfigElements(FontConfig.class).forEach(elem -> elem.set(elem.getDefault()));
|
||||
} catch (ConfigException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
selectedPrimaryFontListPos = -1;
|
||||
selectedFallbackFontListPos = -1;
|
||||
FontStrategist.customFontInUse = false;
|
||||
super.buttonList.clear();
|
||||
this.initButtons();
|
||||
}
|
||||
|
||||
private void toggleCustomFont(IrisButton button) {
|
||||
FontConfig.enableCustomFont = !FontConfig.enableCustomFont;
|
||||
applyChanges(false);
|
||||
button.displayString = FontConfig.enableCustomFont ?
|
||||
I18n.format("options.angelica.fontconfig.disable_custom_font") :
|
||||
I18n.format("options.angelica.fontconfig.enable_custom_font");
|
||||
}
|
||||
|
||||
private int qualityLast = FontConfig.customFontQuality;
|
||||
|
||||
private void setFontQuality(float quality) {
|
||||
FontConfig.customFontQuality = (int) quality;
|
||||
if (qualityLast != (int) quality) {
|
||||
applyChanges(false);
|
||||
}
|
||||
qualityLast = (int) quality;
|
||||
}
|
||||
|
||||
private String fontAAModeFormat(float AAmode) {
|
||||
return switch ((int) AAmode) {
|
||||
case 2 -> I18n.format("options.angelica.fontconfig.aamode.aa_16x");
|
||||
case 1 -> I18n.format("options.angelica.fontconfig.aamode.aa_4x");
|
||||
default -> I18n.format("options.angelica.fontconfig.aamode.aa_none");
|
||||
};
|
||||
}
|
||||
|
||||
private float lastMouseX = 0;
|
||||
private float lastMouseY = 0;
|
||||
private long lastStillTime = 0;
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float delta) {
|
||||
super.drawDefaultBackground();
|
||||
fontList.drawScreen(mouseX, mouseY, delta);
|
||||
searchBox.drawTextBox();
|
||||
// I bet you thought this was drawn inside the search box, not on top of it.
|
||||
if (!this.searchBox.isFocused() && this.searchBox.getText().isEmpty()) {
|
||||
this.drawCenteredString(this.fontRendererObj, this.searchPrompt,
|
||||
this.searchBox.xPosition + this.fontRendererObj.getStringWidth(this.searchPrompt) / 2 + 4,
|
||||
this.searchBox.yPosition + this.searchBox.height / 2 - 4, 0xFFFFFF);
|
||||
}
|
||||
drawCenteredString(this.fontRendererObj, this.title, (int) (this.width * 0.5), 8, 0xFFFFFF);
|
||||
drawCenteredString(this.fontRendererObj, I18n.format("options.angelica.fontconfig.currentfonts",
|
||||
FontConfig.customFontNamePrimary, FontConfig.customFontNameFallback), (int) (this.width * 0.5), this.height - 92, 0xFFFFFF);
|
||||
super.drawScreen(mouseX, mouseY, delta);
|
||||
|
||||
for (GuiButton guiButton : buttonList) {
|
||||
if (!(guiButton instanceof SliderClone slider)) { continue; }
|
||||
final int top = slider.yPosition;
|
||||
final int bot = slider.yPosition + slider.height;
|
||||
final int left = slider.xPosition;
|
||||
final int right = slider.xPosition + slider.width;
|
||||
if (mouseY < top || mouseY >= bot || mouseX < left || mouseX >= right) { continue; }
|
||||
if (mouseX == lastMouseX && mouseY == lastMouseY) {
|
||||
if (lastStillTime == 0) {
|
||||
lastStillTime = System.currentTimeMillis();
|
||||
}
|
||||
if (lastStillTime + 500L < System.currentTimeMillis()) {
|
||||
displayTooltip(mouseX, mouseY, slider.tooltipKey);
|
||||
}
|
||||
} else {
|
||||
lastStillTime = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
lastMouseX = mouseX;
|
||||
lastMouseY = mouseY;
|
||||
}
|
||||
|
||||
private void displayTooltip(int x, int y, String langKey) {
|
||||
List<String> lines = this.fontRendererObj.listFormattedStringToWidth(I18n.format(langKey), this.width / 2);
|
||||
this.drawHoveringText(lines, x, y, this.fontRendererObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(GuiButton guiButton) {
|
||||
if (guiButton.enabled) {
|
||||
if (guiButton instanceof IrisButton irisButton) {
|
||||
irisButton.onPress();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void keyTyped(char typedChar, int keyCode) {
|
||||
if (this.searchBox.isFocused()) {
|
||||
if (keyCode == Keyboard.KEY_ESCAPE) {
|
||||
this.searchBox.setFocused(false);
|
||||
}
|
||||
this.searchBox.textboxKeyTyped(typedChar, keyCode);
|
||||
this.displayedFonts = filterFonts(this.searchBox.getText().toLowerCase());
|
||||
}
|
||||
if (keyCode == Keyboard.KEY_ESCAPE) {
|
||||
this.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
this.searchBox.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
this.fontList.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen() {
|
||||
this.searchBox.updateCursorCounter();
|
||||
}
|
||||
|
||||
// this could be more efficient, but it's good enough as is
|
||||
private ArrayList<Font> filterFonts(String search) {
|
||||
ArrayList<Font> results;
|
||||
if (search == null || search.isEmpty()) {
|
||||
results = new ArrayList<>(Arrays.asList(availableFonts));
|
||||
} else {
|
||||
results = Arrays.stream(availableFonts).filter((font -> font.getFontName().toLowerCase().contains(search))).collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
selectedPrimaryFontListPos = -1;
|
||||
selectedFallbackFontListPos = -1;
|
||||
for (int i = 0; i < results.size(); i++) {
|
||||
if (Objects.equals(currentPrimaryFontName, results.get(i).getFontName())) {
|
||||
selectedPrimaryFontListPos = i;
|
||||
}
|
||||
if (Objects.equals(currentFallbackFontName, results.get(i).getFontName())) {
|
||||
selectedFallbackFontListPos = i;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
class FontList extends GuiSlot {
|
||||
|
||||
public FontList() {
|
||||
super(FontConfigScreen.this.mc, FontConfigScreen.this.width, FontConfigScreen.this.height, 52, FontConfigScreen.this.height - 100, 18);
|
||||
}
|
||||
|
||||
private void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
if (mouseY < this.top || mouseY > this.bottom) { return; }
|
||||
|
||||
int listLeftBound = this.width / 2 - this.getListWidth() / 2;
|
||||
int listRightBound = this.width / 2 + this.getListWidth() / 2;
|
||||
if (mouseX < listLeftBound || mouseX > listRightBound) { return; }
|
||||
|
||||
int mousePosInList = mouseY - this.top - this.headerPadding + (int)this.amountScrolled - 4;
|
||||
int slotIndex = mousePosInList / this.slotHeight;
|
||||
if (slotIndex < 0 || slotIndex >= this.getSize()) { return; }
|
||||
|
||||
if (mouseButton == 0) {
|
||||
onElemClicked(slotIndex, false);
|
||||
} else if (mouseButton == 1) {
|
||||
onElemClicked(slotIndex, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onElemClicked(int index, boolean rightClick) {
|
||||
if (!rightClick) {
|
||||
selectedPrimaryFontListPos = index;
|
||||
currentPrimaryFontName = displayedFonts.get(index).getFontName();
|
||||
} else {
|
||||
selectedFallbackFontListPos = index;
|
||||
currentFallbackFontName = displayedFonts.get(index).getFontName();
|
||||
}
|
||||
applyChanges(false);
|
||||
}
|
||||
|
||||
protected boolean isSelected(int index) {
|
||||
return (index == selectedPrimaryFontListPos || index == selectedFallbackFontListPos);
|
||||
}
|
||||
|
||||
protected int getSize() {
|
||||
return displayedFonts.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getContentHeight() {
|
||||
return this.getSize() * 18;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getScrollBarX() {
|
||||
return this.width * 11 / 12 - 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getListWidth() {
|
||||
return this.width * 2 / 3;
|
||||
}
|
||||
|
||||
// see onElemClicked for the proper version that supports right-clicking
|
||||
protected void elementClicked(int index, boolean doubleClicked, int mouseX, int mouseY) {}
|
||||
|
||||
protected void drawBackground() {
|
||||
drawDefaultBackground();
|
||||
}
|
||||
|
||||
protected void drawSlot(int index, int x, int y, int p_148126_4_, Tessellator tessellator, int p_148126_6_, int p_148126_7_) {
|
||||
int color = 0xffffff;
|
||||
if (index == selectedPrimaryFontListPos) {
|
||||
color &= 0xffff55;
|
||||
}
|
||||
if (index == selectedFallbackFontListPos) {
|
||||
color &= 0x55ffff;
|
||||
}
|
||||
drawCenteredString(fontRendererObj, displayedFonts.get(index).getFontName(), this.width / 2, y + 1, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package com.gtnewhorizons.angelica.client.gui;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class SliderClone extends GuiButton {
|
||||
|
||||
private final Function<Float, String> displayStringFormatter;
|
||||
private final Consumer<Float> valueSetter;
|
||||
private final Option option;
|
||||
private float sliderPercentage;
|
||||
public final String tooltipKey;
|
||||
public boolean mouseDragging;
|
||||
|
||||
@AllArgsConstructor
|
||||
public static class Option {
|
||||
float min;
|
||||
float max;
|
||||
float step;
|
||||
|
||||
float denormalize(float alpha) {
|
||||
float lerp = min * (1 - alpha) + max * alpha;
|
||||
return Math.round(lerp / step) * step;
|
||||
}
|
||||
float normalize(float value) {
|
||||
return (value - min) / (max - min);
|
||||
}
|
||||
}
|
||||
|
||||
public SliderClone(int x, int y, int width, int height, Option option, float initialValue,
|
||||
Consumer<Float> setter, Function<Float, String> formatter, String tooltipKey) {
|
||||
super(0, x, y, width, height, "");
|
||||
this.option = option;
|
||||
this.sliderPercentage = option.normalize(initialValue);
|
||||
this.displayString = formatter.apply(initialValue);
|
||||
this.valueSetter = setter;
|
||||
this.displayStringFormatter = formatter;
|
||||
this.tooltipKey = tooltipKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 0 if the button is disabled, 1 if the mouse is NOT hovering over this button and 2 if it IS hovering over
|
||||
* this button.
|
||||
*/
|
||||
public int getHoverState(boolean mouseOver) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when the mouse button is dragged. Equivalent of MouseListener.mouseDragged(MouseEvent e).
|
||||
*/
|
||||
protected void mouseDragged(Minecraft mc, int mouseX, int mouseY) {
|
||||
if (this.visible) {
|
||||
if (this.mouseDragging) {
|
||||
this.sliderPercentage = (float)(mouseX - (this.xPosition + 4)) / (float)(this.width - 8);
|
||||
|
||||
if (this.sliderPercentage < 0.0F) {
|
||||
this.sliderPercentage = 0.0F;
|
||||
}
|
||||
|
||||
if (this.sliderPercentage > 1.0F) {
|
||||
this.sliderPercentage = 1.0F;
|
||||
}
|
||||
|
||||
float f = this.option.denormalize(this.sliderPercentage);
|
||||
valueSetter.accept(f);
|
||||
this.sliderPercentage = this.option.normalize(f);
|
||||
this.displayString = displayStringFormatter.apply(f);
|
||||
}
|
||||
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
this.drawTexturedModalRect(this.xPosition + (int)(this.sliderPercentage * (float)(this.width - 8)), this.yPosition, 0, 66, 4, 20);
|
||||
this.drawTexturedModalRect(this.xPosition + (int)(this.sliderPercentage * (float)(this.width - 8)) + 4, this.yPosition, 196, 66, 4, 20);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the mouse has been pressed on this control. Equivalent of MouseListener.mousePressed(MouseEvent e).
|
||||
*/
|
||||
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
|
||||
if (super.mousePressed(mc, mouseX, mouseY)) {
|
||||
this.sliderPercentage = (float)(mouseX - (this.xPosition + 4)) / (float)(this.width - 8);
|
||||
|
||||
if (this.sliderPercentage < 0.0F) {
|
||||
this.sliderPercentage = 0.0F;
|
||||
}
|
||||
|
||||
if (this.sliderPercentage > 1.0F) {
|
||||
this.sliderPercentage = 1.0F;
|
||||
}
|
||||
|
||||
float f = this.option.denormalize(this.sliderPercentage);
|
||||
valueSetter.accept(f);
|
||||
this.sliderPercentage = this.option.normalize(f);
|
||||
this.displayString = displayStringFormatter.apply(f);
|
||||
this.mouseDragging = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when the mouse button is released. Equivalent of MouseListener.mouseReleased(MouseEvent e).
|
||||
*/
|
||||
public void mouseReleased(int mouseX, int mouseY) {
|
||||
this.mouseDragging = false;
|
||||
}
|
||||
}
|
||||
@@ -26,17 +26,7 @@ public class BlockError extends Block {
|
||||
public BlockError() {
|
||||
super(Material.rock);
|
||||
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onTextureStitch(TextureStitchEvent.Pre event) {
|
||||
if (event.map.getTextureType() == 0) {
|
||||
for (int i = 0; i < icons.length; i++) {
|
||||
icons[i] = event.map.registerIcon("angelica:error_block_" + i);
|
||||
}
|
||||
}
|
||||
MinecraftForge.EVENT_BUS.register(new EventHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,4 +35,15 @@ public class BlockError extends Block {
|
||||
return meta >= 0 && meta < icons.length ? icons[meta] : null;
|
||||
}
|
||||
|
||||
public static class EventHandler{
|
||||
@SubscribeEvent
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onTextureStitch(TextureStitchEvent.Pre event) {
|
||||
if (event.map.getTextureType() == 0) {
|
||||
for (int i = 0; i < icons.length; i++) {
|
||||
icons[i] = event.map.registerIcon("angelica:error_block_" + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.compat;
|
||||
|
||||
import com.falsepattern.chunk.api.DataRegistry;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedBlockStorageAccessor;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedNibbleArray;
|
||||
import com.gtnewhorizons.neid.mixins.interfaces.IExtendedBlockStorageMixin;
|
||||
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
@@ -19,7 +17,7 @@ public class ExtendedBlockStorageExt extends ExtendedBlockStorage {
|
||||
}
|
||||
|
||||
public ExtendedBlockStorageExt(Chunk chunk, ExtendedBlockStorage storage) {
|
||||
super(((ExtendedBlockStorageAccessor) storage).getYBase(), storage.getSkylightArray() != null);
|
||||
super(storage.yBase, storage.getSkylightArray() != null);
|
||||
|
||||
if (ModStatus.isChunkAPILoaded) {
|
||||
if (storage.getSkylightArray() != null) {
|
||||
@@ -33,7 +31,7 @@ public class ExtendedBlockStorageExt extends ExtendedBlockStorage {
|
||||
System.arraycopy(((IExtendedBlockStorageMixin)(Object)storage).getBlock16BArray(), 0, block16BArray, 0, block16BArray.length);
|
||||
if(storage.getBlockMSBArray() != null) {
|
||||
this.setBlockMSBArray(new NibbleArray(block16BArray.length, 4));
|
||||
copyNibbleArray((ExtendedNibbleArray) storage.getBlockMSBArray(), (ExtendedNibbleArray) this.getBlockMSBArray());
|
||||
copyNibbleArray(storage.getBlockMSBArray(), this.getBlockMSBArray());
|
||||
}
|
||||
arrayLen = block16BArray.length;
|
||||
if (ModStatus.isNEIDMetadataExtended) {
|
||||
@@ -52,31 +50,31 @@ public class ExtendedBlockStorageExt extends ExtendedBlockStorage {
|
||||
System.arraycopy(storage.getBlockLSBArray(), 0, blockLSBArray, 0, blockLSBArray.length);
|
||||
if(storage.getBlockMSBArray() != null) {
|
||||
this.setBlockMSBArray(new NibbleArray(blockLSBArray.length, 4));
|
||||
copyNibbleArray((ExtendedNibbleArray) storage.getBlockMSBArray(), (ExtendedNibbleArray) this.getBlockMSBArray());
|
||||
copyNibbleArray(storage.getBlockMSBArray(), this.getBlockMSBArray());
|
||||
}
|
||||
arrayLen = blockLSBArray.length;
|
||||
}
|
||||
|
||||
|
||||
if (!ModStatus.isNEIDMetadataExtended) copyNibbleArray((ExtendedNibbleArray) storage.getMetadataArray(), (ExtendedNibbleArray)this.getMetadataArray());
|
||||
copyNibbleArray((ExtendedNibbleArray) storage.getBlocklightArray(), (ExtendedNibbleArray)this.getBlocklightArray());
|
||||
if (!ModStatus.isNEIDMetadataExtended) copyNibbleArray(storage.getMetadataArray(), this.getMetadataArray());
|
||||
copyNibbleArray(storage.getBlocklightArray(), this.getBlocklightArray());
|
||||
if(storage.getSkylightArray() != null) {
|
||||
hasSky = true;
|
||||
if(this.getSkylightArray() == null) {
|
||||
this.setSkylightArray(new NibbleArray(arrayLen, 4));
|
||||
}
|
||||
copyNibbleArray((ExtendedNibbleArray) storage.getSkylightArray(), (ExtendedNibbleArray) this.getSkylightArray());
|
||||
copyNibbleArray(storage.getSkylightArray(), this.getSkylightArray());
|
||||
}
|
||||
}
|
||||
((ExtendedBlockStorageAccessor) this).setBlockRefCount(((ExtendedBlockStorageAccessor) storage).getBlockRefCount());
|
||||
this.blockRefCount = storage.blockRefCount;
|
||||
}
|
||||
|
||||
|
||||
private static void copyNibbleArray(ExtendedNibbleArray srcArray, ExtendedNibbleArray dstArray) {
|
||||
private static void copyNibbleArray(NibbleArray srcArray, NibbleArray dstArray) {
|
||||
if (srcArray == null || dstArray == null) {
|
||||
throw new RuntimeException("NibbleArray is null src: " + (srcArray == null) + " dst: " + (dstArray == null));
|
||||
}
|
||||
final byte[] data = srcArray.getData();
|
||||
System.arraycopy(data, 0, dstArray.getData(), 0, data.length);
|
||||
final byte[] data = srcArray.data;
|
||||
System.arraycopy(data, 0, dstArray.data, 0, data.length);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
package com.gtnewhorizons.angelica.compat;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.backhand.BackhandReflectionCompat;
|
||||
import com.gtnewhorizons.angelica.helpers.LoadControllerHelper;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.versioning.ArtifactVersion;
|
||||
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
|
||||
import mods.battlegear2.Battlegear;
|
||||
import net.dries007.holoInventory.HoloInventory;
|
||||
import xonin.backhand.Backhand;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class ModStatus {
|
||||
public static final Logger LOGGER = LogManager.getLogger("ModCompat");
|
||||
|
||||
public static BackhandReflectionCompat backhandCompat;
|
||||
/**
|
||||
* Mixin Version
|
||||
*/
|
||||
@@ -17,7 +20,6 @@ public class ModStatus {
|
||||
* ASM Version
|
||||
*/
|
||||
public static boolean isOldNEIDLoaded;
|
||||
|
||||
public static boolean isBetterCrashesLoaded;
|
||||
public static boolean isNEIDMetadataExtended;
|
||||
public static boolean isLotrLoaded;
|
||||
@@ -30,8 +32,14 @@ public class ModStatus {
|
||||
public static boolean isThaumcraftLoaded;
|
||||
public static boolean isThaumicHorizonsLoaded;
|
||||
public static boolean isBaublesLoaded;
|
||||
public static boolean isFluidLoggedLoaded;
|
||||
|
||||
public static void preInit(){
|
||||
isBackhandLoaded = Loader.isModLoaded("backhand");
|
||||
if(isBackhandLoaded) {
|
||||
isBackhandLoaded = BackhandReflectionCompat.isBackhandLoaded();
|
||||
}
|
||||
|
||||
isBetterCrashesLoaded = Loader.isModLoaded("bettercrashes");
|
||||
isNEIDLoaded = Loader.isModLoaded("neid");
|
||||
isOldNEIDLoaded = Loader.isModLoaded("notenoughIDs");
|
||||
@@ -41,17 +49,12 @@ public class ModStatus {
|
||||
isXaerosMinimapLoaded = Loader.isModLoaded("XaeroMinimap");
|
||||
isHoloInventoryLoaded = Loader.isModLoaded("holoinventory");
|
||||
isBattlegearLoaded = Loader.isModLoaded("battlegear2");
|
||||
isBackhandLoaded = Loader.isModLoaded("backhand");
|
||||
isThaumcraftLoaded = Loader.isModLoaded("Thaumcraft");
|
||||
isThaumicHorizonsLoaded = Loader.isModLoaded("ThaumicHorizons");
|
||||
isBaublesLoaded = Loader.isModLoaded("Baubles");
|
||||
isFluidLoggedLoaded = Loader.isModLoaded("fluidlogged");
|
||||
|
||||
if (isHoloInventoryLoaded){
|
||||
isHoloInventoryLoaded = new DefaultArtifactVersion("2.4.4-GTNH")
|
||||
.compareTo(
|
||||
LoadControllerHelper.getOwningMod(HoloInventory.class).getProcessedVersion()
|
||||
) <= 0;
|
||||
}
|
||||
isHoloInventoryLoaded = Loader.isModLoaded("holoinventory");
|
||||
|
||||
// remove compat with original release of BG2
|
||||
if (isBattlegearLoaded){
|
||||
@@ -61,17 +64,9 @@ public class ModStatus {
|
||||
) <= 0;
|
||||
}
|
||||
|
||||
if (isBackhandLoaded){
|
||||
isBackhandLoaded = new DefaultArtifactVersion("1.4.1")
|
||||
.compareTo(
|
||||
LoadControllerHelper.getOwningMod(Backhand.class).getProcessedVersion()
|
||||
) <= 0;
|
||||
}
|
||||
|
||||
|
||||
isNEIDMetadataExtended = false;
|
||||
if (isNEIDLoaded) {
|
||||
int majorVersion = Integer.parseInt(Loader.instance().getIndexedModList().get("neid").getVersion().split("\\.")[0]);
|
||||
final int majorVersion = Integer.parseInt(Loader.instance().getIndexedModList().get("neid").getVersion().split("\\.")[0]);
|
||||
if (majorVersion >= 2) {
|
||||
isNEIDMetadataExtended = true;
|
||||
}
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package com.gtnewhorizons.angelica.compat.backhand;
|
||||
|
||||
import com.gtnewhorizons.angelica.helpers.LoadControllerHelper;
|
||||
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
import static com.gtnewhorizons.angelica.compat.ModStatus.LOGGER;
|
||||
|
||||
public class BackhandReflectionCompat {
|
||||
private static final String BACKHAND_CLASS = "xonin.backhand.Backhand";
|
||||
private static final String ITEM_RENDERER_HOOKS_CLASS = "xonin.backhand.client.hooks.ItemRendererHooks";
|
||||
private static final String BACKHAND_UTILS_CLASS = "xonin.backhand.api.core.BackhandUtils";
|
||||
|
||||
private static boolean isLoaded;
|
||||
private static final MethodHandle renderOffhandReturn;
|
||||
private static final MethodHandle getOffhandItem;
|
||||
|
||||
static {
|
||||
MethodHandle renderOffhandReturnTemp = null;
|
||||
MethodHandle getOffhandItemTemp = null;
|
||||
|
||||
try {
|
||||
final Class<?> backhandClass = ReflectionHelper.getClass(BackhandReflectionCompat.class.getClassLoader(), BACKHAND_CLASS);
|
||||
final boolean versionCheck = new DefaultArtifactVersion("1.6.9").compareTo(LoadControllerHelper.getOwningMod(backhandClass).getProcessedVersion()) <= 0;
|
||||
|
||||
if (versionCheck) {
|
||||
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final Class<?> itemRendererHooksClass = ReflectionHelper.getClass(BackhandReflectionCompat.class.getClassLoader(), ITEM_RENDERER_HOOKS_CLASS);
|
||||
final Class<?> backhandUtilsClass = ReflectionHelper.getClass(BackhandReflectionCompat.class.getClassLoader(), BACKHAND_UTILS_CLASS);
|
||||
|
||||
renderOffhandReturnTemp = lookup.findStatic(itemRendererHooksClass, "renderOffhandReturn", MethodType.methodType(void.class, float.class));
|
||||
getOffhandItemTemp = lookup.findStatic(backhandUtilsClass, "getOffhandItem", MethodType.methodType(ItemStack.class, EntityPlayer.class));
|
||||
isLoaded = true;
|
||||
LOGGER.info("Backhand compat loaded");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to load Backhand compat", e);
|
||||
isLoaded = false;
|
||||
}
|
||||
|
||||
renderOffhandReturn = renderOffhandReturnTemp;
|
||||
getOffhandItem = getOffhandItemTemp;
|
||||
}
|
||||
|
||||
public static boolean isBackhandLoaded() {
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
public static void renderOffhand(float partialTicks) {
|
||||
if (isLoaded && renderOffhandReturn != null) {
|
||||
try {
|
||||
renderOffhandReturn.invokeExact(partialTicks);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Failed to invoke Backhand renderOffhandReturn", e);
|
||||
isLoaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ItemStack getOffhandItem(EntityPlayer player) {
|
||||
if (isLoaded && getOffhandItem != null) {
|
||||
try {
|
||||
return (ItemStack) getOffhandItem.invokeExact(player);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Failed to invoke Backhand getOffhandItem", e);
|
||||
isLoaded = false;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.gtnewhorizons.angelica.compat.battlegear2;
|
||||
|
||||
import mods.battlegear2.api.core.IInventoryPlayerBattle;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* This class exists to isolate classes that exist in Battlegear 2 but not
|
||||
* in Battlegear 2 for Backhand in order to avoid class loading exceptions.
|
||||
*/
|
||||
public class Battlegear2Compat {
|
||||
public static ItemStack getBattlegear2Offhand(EntityPlayer player) {
|
||||
return ((IInventoryPlayerBattle) player.inventory).battlegear2$getCurrentOffhandWeapon();
|
||||
}
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package com.gtnewhorizons.angelica.compat.holoinventory;
|
||||
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static com.gtnewhorizons.angelica.compat.ModStatus.LOGGER;
|
||||
|
||||
public class HoloInventoryReflectionCompat {
|
||||
private static final String RENDERER_CLASS = "net.dries007.holoInventory.client.Renderer";
|
||||
|
||||
private static boolean isLoaded;
|
||||
private static final MethodHandle renderEventPostMethod;
|
||||
private static final MethodHandle renderEventMethod;
|
||||
private static final MethodHandle angelicaOverrideSetter;
|
||||
|
||||
static {
|
||||
MethodHandle renderEventPostMethodTemp = null;
|
||||
MethodHandle renderEventMethodTemp = null;
|
||||
MethodHandle angelicaOverrideSetterTemp = null;
|
||||
final Object rendererInstance;
|
||||
final Class<?> rendererClass;
|
||||
|
||||
try {
|
||||
rendererClass = Class.forName(RENDERER_CLASS);
|
||||
|
||||
// Get and cache the Renderer.INSTANCE
|
||||
final Field instanceField = rendererClass.getDeclaredField("INSTANCE");
|
||||
instanceField.setAccessible(true);
|
||||
rendererInstance = instanceField.get(null);
|
||||
|
||||
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
try {
|
||||
renderEventPostMethodTemp = lookup.findVirtual(rendererClass, "renderEvent", MethodType.methodType(void.class, RenderGameOverlayEvent.Post.class));
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Fallback for 2.5.0-GTNH and earlier
|
||||
renderEventMethodTemp = lookup.findVirtual(rendererClass, "renderEvent", MethodType.methodType(void.class, RenderGameOverlayEvent.class));
|
||||
}
|
||||
|
||||
final Field angelicaOverrideField = rendererClass.getDeclaredField("angelicaOverride");
|
||||
angelicaOverrideField.setAccessible(true);
|
||||
angelicaOverrideSetterTemp = lookup.unreflectSetter(angelicaOverrideField);
|
||||
|
||||
// Bind the method handles to the instance
|
||||
if (rendererInstance != null) {
|
||||
if (renderEventPostMethodTemp != null) {
|
||||
renderEventPostMethodTemp = renderEventPostMethodTemp.bindTo(rendererInstance);
|
||||
}
|
||||
if (renderEventMethodTemp != null) {
|
||||
renderEventMethodTemp = renderEventMethodTemp.bindTo(rendererInstance);
|
||||
}
|
||||
angelicaOverrideSetterTemp = angelicaOverrideSetterTemp.bindTo(rendererInstance);
|
||||
}
|
||||
|
||||
isLoaded = true;
|
||||
LOGGER.info("Successfully initialized HoloInventory compatibility layer");
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("Failed to initialize HoloInventory compatibility layer", e);
|
||||
isLoaded = false;
|
||||
}
|
||||
|
||||
renderEventPostMethod = renderEventPostMethodTemp;
|
||||
renderEventMethod = renderEventMethodTemp;
|
||||
angelicaOverrideSetter = angelicaOverrideSetterTemp;
|
||||
}
|
||||
|
||||
public static void renderEvent(RenderGameOverlayEvent event) {
|
||||
if (!isLoaded) return;
|
||||
try {
|
||||
if (event instanceof RenderGameOverlayEvent.Post && renderEventPostMethod != null) {
|
||||
renderEventPostMethod.invokeExact((RenderGameOverlayEvent.Post) event);
|
||||
} else {
|
||||
renderEventMethod.invokeExact(event);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Failed to invoke HoloInventory renderEvent", e);
|
||||
isLoaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setAngelicaOverride(boolean value) {
|
||||
if (!isLoaded) return;
|
||||
try {
|
||||
angelicaOverrideSetter.invokeExact(value);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Failed to set HoloInventory angelicaOverride", e);
|
||||
isLoaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,327 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.compat.lwjgl;
|
||||
|
||||
import static com.gtnewhorizons.angelica.compat.lwjgl.Pointer.BITS64;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongPredicate;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import org.lwjgl.BufferUtils;
|
||||
|
||||
/**
|
||||
* Backported from LWJGL3 under the BSD 3-Clause "New" or "Revised" License license
|
||||
*
|
||||
* <p>This class provides functionality for managing native memory.
|
||||
*
|
||||
* <p>All methods in this class will make use of {@link sun.misc.Unsafe} if it's available, for performance. If Unsafe is not available, the fallback
|
||||
* implementations make use of reflection and, in the worst-case, JNI.</p>
|
||||
*
|
||||
* <p>Method names in this class are prefixed with {@code mem} to avoid ambiguities when used with static imports.</p>
|
||||
*/
|
||||
public class CompatMemoryUtil {
|
||||
public static final long NULL = 0;
|
||||
|
||||
static final sun.misc.Unsafe UNSAFE;
|
||||
|
||||
private static final Class<? extends ByteBuffer> BUFFER_BYTE;
|
||||
private static final Class<? extends IntBuffer> BUFFER_INT;
|
||||
private static final Class<? extends FloatBuffer> BUFFER_FLOAT;
|
||||
|
||||
private static final long MARK;
|
||||
private static final long POSITION;
|
||||
private static final long LIMIT;
|
||||
private static final long CAPACITY;
|
||||
|
||||
private static final long ADDRESS;
|
||||
|
||||
static {
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(0).order(ByteOrder.nativeOrder());
|
||||
BUFFER_BYTE = bb.getClass();
|
||||
BUFFER_INT = bb.asIntBuffer().getClass();
|
||||
BUFFER_FLOAT = bb.asFloatBuffer().getClass();
|
||||
|
||||
UNSAFE = getUnsafeInstance();
|
||||
|
||||
MARK = getMarkOffset();
|
||||
POSITION = getPositionOffset();
|
||||
LIMIT = getLimitOffset();
|
||||
CAPACITY = getCapacityOffset();
|
||||
|
||||
ADDRESS = getAddressOffset();
|
||||
}
|
||||
|
||||
public static ByteBuffer memReallocDirect(ByteBuffer old, int capacity) {
|
||||
ByteBuffer newBuf = BufferUtils.createByteBuffer(capacity);
|
||||
int oldPos = old.position();
|
||||
old.rewind();
|
||||
newBuf.put(old);
|
||||
newBuf.position(Math.min(capacity, oldPos));
|
||||
return newBuf;
|
||||
}
|
||||
|
||||
public static IntBuffer memReallocDirect(IntBuffer old, int capacity) {
|
||||
IntBuffer newBuf = BufferUtils.createIntBuffer(capacity);
|
||||
int oldPos = old.position();
|
||||
old.rewind();
|
||||
newBuf.put(old);
|
||||
newBuf.position(Math.min(capacity, oldPos));
|
||||
return newBuf;
|
||||
}
|
||||
|
||||
public static FloatBuffer memReallocDirect(FloatBuffer old, int capacity) {
|
||||
FloatBuffer newBuf = BufferUtils.createFloatBuffer(capacity);
|
||||
int oldPos = old.position();
|
||||
old.rewind();
|
||||
newBuf.put(old);
|
||||
newBuf.position(Math.min(capacity, oldPos));
|
||||
return newBuf;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
-------------------------------------
|
||||
UNSAFE MEMORY ACCESS API
|
||||
-------------------------------------
|
||||
------------------------------------- */
|
||||
|
||||
private static final int FILL_PATTERN_32 = Integer.divideUnsigned(-1, 255);
|
||||
private static final long FILL_PATTERN_64 = Long.divideUnsigned(-1L, 255L);
|
||||
|
||||
/**
|
||||
* Sets all bytes in a specified block of memory to a fixed value (usually zero).
|
||||
*
|
||||
* @param ptr the starting memory address
|
||||
* @param value the value to set (memSet will convert it to unsigned byte)
|
||||
* @param bytes the number of bytes to set
|
||||
*/
|
||||
public static void memSet(long ptr, int value, long bytes) {
|
||||
if (/*DEBUG*/ false && (ptr == NULL || bytes < 0)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
/*
|
||||
- Unsafe.setMemory is very slow.
|
||||
- A custom Java loop is fastest at small sizes, approximately up to 256 bytes.
|
||||
- The native memset becomes fastest at bigger sizes, when the JNI overhead becomes negligible.
|
||||
TODO: verify this
|
||||
*/
|
||||
|
||||
//UNSAFE.setMemory(ptr, bytes, (byte)(value & 0xFF));
|
||||
//if (bytes < 256L) {
|
||||
int p = (int)ptr;
|
||||
if (BITS64) {
|
||||
if ((p & 7) == 0) {
|
||||
memSet64(ptr, value, (int)bytes & 0xFF);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ((p & 3) == 0) {
|
||||
memSet32(p, value, (int)bytes & 0xFF);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//}
|
||||
//nmemset(ptr, value, bytes);
|
||||
}
|
||||
private static void memSet64(long ptr, int value, int bytes) {
|
||||
int aligned = bytes & ~7;
|
||||
|
||||
// Aligned body
|
||||
long valuel = (value & 0xFF) * FILL_PATTERN_64;
|
||||
for (int i = 0; i < aligned; i += 8) {
|
||||
UNSAFE.putLong(null, ptr + i, valuel);
|
||||
}
|
||||
|
||||
// Unaligned tail
|
||||
byte valueb = (byte)(value & 0xFF);
|
||||
for (int i = aligned; i < bytes; i++) {
|
||||
UNSAFE.putByte(null, ptr + i, valueb);
|
||||
}
|
||||
}
|
||||
private static void memSet32(int ptr, int value, int bytes) {
|
||||
int aligned = bytes & ~3;
|
||||
|
||||
// Aligned body
|
||||
int vi = (value & 0xFF) * FILL_PATTERN_32;
|
||||
for (int i = 0; i < aligned; i += 4) {
|
||||
UNSAFE.putInt(null, (ptr + i) & 0xFFFF_FFFFL, vi);
|
||||
}
|
||||
|
||||
// Unaligned tail
|
||||
byte vb = (byte)(value & 0xFF);
|
||||
for (int i = aligned; i < bytes; i++) {
|
||||
UNSAFE.putByte(null, (ptr + i) & 0xFFFF_FFFFL, vb);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean memGetBoolean(long ptr) { return UNSAFE.getByte(null, ptr) != 0; }
|
||||
public static byte memGetByte(long ptr) { return UNSAFE.getByte(null, ptr); }
|
||||
public static short memGetShort(long ptr) { return UNSAFE.getShort(null, ptr); }
|
||||
public static int memGetInt(long ptr) { return UNSAFE.getInt(null, ptr); }
|
||||
public static long memGetLong(long ptr) { return UNSAFE.getLong(null, ptr); }
|
||||
public static float memGetFloat(long ptr) { return UNSAFE.getFloat(null, ptr); }
|
||||
public static double memGetDouble(long ptr) { return UNSAFE.getDouble(null, ptr); }
|
||||
|
||||
public static void memPutByte(long ptr, byte value) { UNSAFE.putByte(null, ptr, value); }
|
||||
public static void memPutShort(long ptr, short value) { UNSAFE.putShort(null, ptr, value); }
|
||||
public static void memPutInt(long ptr, int value) { UNSAFE.putInt(null, ptr, value); }
|
||||
public static void memPutLong(long ptr, long value) { UNSAFE.putLong(null, ptr, value); }
|
||||
public static void memPutFloat(long ptr, float value) { UNSAFE.putFloat(null, ptr, value); }
|
||||
public static void memPutDouble(long ptr, double value) { UNSAFE.putDouble(null, ptr, value); }
|
||||
|
||||
// -------------------------------------------------
|
||||
// -------------------------------------------------
|
||||
// -------------------------------------------------
|
||||
|
||||
private static sun.misc.Unsafe getUnsafeInstance() {
|
||||
java.lang.reflect.Field[] fields = sun.misc.Unsafe.class.getDeclaredFields();
|
||||
|
||||
/*
|
||||
Different runtimes use different names for the Unsafe singleton,
|
||||
so we cannot use .getDeclaredField and we scan instead. For example:
|
||||
|
||||
Oracle: theUnsafe
|
||||
PERC : m_unsafe_instance
|
||||
Android: THE_ONE
|
||||
*/
|
||||
for (java.lang.reflect.Field field : fields) {
|
||||
if (!field.getType().equals(sun.misc.Unsafe.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int modifiers = field.getModifiers();
|
||||
if (!(java.lang.reflect.Modifier.isStatic(modifiers) && java.lang.reflect.Modifier.isFinal(modifiers))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
return (sun.misc.Unsafe)field.get(null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("LWJGL requires sun.misc.Unsafe to be available.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively searches an object and its superclasses for a field with the same name and type. If the field isn't
|
||||
* public, it may not be stable across library/JVM versions, and these calls are likely not portable. You have been
|
||||
* warned!
|
||||
*/
|
||||
private static long getFieldOffset(Class<?> containerType, Class<?> fieldType, String name) {
|
||||
Class<?> c = containerType;
|
||||
while (c != Object.class) {
|
||||
Field[] fields = c.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if (!field.getType().isAssignableFrom(fieldType) || Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
long offset = UNSAFE.objectFieldOffset(field);
|
||||
if (field.getName().equals(name)) {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
c = c.getSuperclass();
|
||||
}
|
||||
throw new UnsupportedOperationException("Failed to find field offset in class.");
|
||||
}
|
||||
|
||||
private static long getFieldOffset(Class<?> containerType, Class<?> fieldType, LongPredicate predicate) {
|
||||
Class<?> c = containerType;
|
||||
while (c != Object.class) {
|
||||
Field[] fields = c.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if (!field.getType().isAssignableFrom(fieldType) || Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
long offset = UNSAFE.objectFieldOffset(field);
|
||||
if (predicate.test(offset)) {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
c = c.getSuperclass();
|
||||
}
|
||||
throw new UnsupportedOperationException("Failed to find field offset in class.");
|
||||
}
|
||||
|
||||
private static long getFieldOffsetInt(Object container, int value) {
|
||||
return getFieldOffset(container.getClass(), int.class, offset -> UNSAFE.getInt(container, offset) == value);
|
||||
}
|
||||
|
||||
private static long getAddressOffset() {
|
||||
final ByteBuffer bb = ByteBuffer.allocateDirect(0);
|
||||
return getFieldOffset(bb.getClass(), long.class, "address");
|
||||
|
||||
// TODO: do this portably
|
||||
// long MAGIC_ADDRESS = 0xDEADBEEF8BADF00DL & (BITS32 ? 0xFFFF_FFFFL : 0xFFFF_FFFF_FFFF_FFFFL);
|
||||
// ByteBuffer bb = Objects.requireNonNull(NewDirectByteBuffer(MAGIC_ADDRESS, 0));
|
||||
//return getFieldOffset(bb.getClass(), long.class, offset -> UNSAFE.getLong(bb, offset) == MAGIC_ADDRESS);
|
||||
}
|
||||
|
||||
private static final int MAGIC_CAPACITY = 0x0D15EA5E;
|
||||
private static final int MAGIC_POSITION = 0x00FACADE;
|
||||
|
||||
private static long getMarkOffset() {
|
||||
// TODO: is this actually reliable without NewDirectByteBuffer?
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(0);
|
||||
return getFieldOffsetInt(bb, -1);
|
||||
// ByteBuffer bb = Objects.requireNonNull(NewDirectByteBuffer(1L, 0));
|
||||
// return getFieldOffsetInt(bb, -1);
|
||||
}
|
||||
|
||||
private static long getPositionOffset() {
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(MAGIC_CAPACITY);
|
||||
bb.position(MAGIC_POSITION);
|
||||
return getFieldOffsetInt(bb, MAGIC_POSITION);
|
||||
}
|
||||
|
||||
private static long getLimitOffset() {
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(MAGIC_CAPACITY);
|
||||
bb.limit(MAGIC_POSITION);
|
||||
return getFieldOffsetInt(bb, MAGIC_POSITION);
|
||||
}
|
||||
|
||||
private static long getCapacityOffset() {
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(MAGIC_CAPACITY);
|
||||
bb.limit(0);
|
||||
return getFieldOffsetInt(bb, MAGIC_CAPACITY);
|
||||
}
|
||||
|
||||
static IntBuffer wrapBufferInt(long address, int capacity) {
|
||||
IntBuffer buffer;
|
||||
try {
|
||||
buffer = (IntBuffer)UNSAFE.allocateInstance(BUFFER_INT);
|
||||
} catch (InstantiationException e) {
|
||||
throw new UnsupportedOperationException(e);
|
||||
}
|
||||
|
||||
UNSAFE.putLong(buffer, ADDRESS, address);
|
||||
UNSAFE.putInt(buffer, MARK, -1);
|
||||
UNSAFE.putInt(buffer, LIMIT, capacity);
|
||||
UNSAFE.putInt(buffer, CAPACITY, capacity);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static FloatBuffer wrapBufferFloat(long address, int capacity) {
|
||||
FloatBuffer buffer;
|
||||
try {
|
||||
buffer = (FloatBuffer)UNSAFE.allocateInstance(BUFFER_FLOAT);
|
||||
} catch (InstantiationException e) {
|
||||
throw new UnsupportedOperationException(e);
|
||||
}
|
||||
|
||||
UNSAFE.putLong(buffer, ADDRESS, address);
|
||||
UNSAFE.putInt(buffer, MARK, -1);
|
||||
UNSAFE.putInt(buffer, LIMIT, capacity);
|
||||
UNSAFE.putInt(buffer, CAPACITY, capacity);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
@@ -1,382 +0,0 @@
|
||||
/*
|
||||
* This class is backported from LWJGL3 under the BSD 3-clause "New" or "Revised" License
|
||||
*/
|
||||
|
||||
package com.gtnewhorizons.angelica.compat.lwjgl;
|
||||
|
||||
|
||||
import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutDouble;
|
||||
import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutFloat;
|
||||
import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutInt;
|
||||
import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutLong;
|
||||
import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutShort;
|
||||
import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memSet;
|
||||
import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.wrapBufferFloat;
|
||||
import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.wrapBufferInt;
|
||||
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.Arrays;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.MemoryUtil;
|
||||
|
||||
/**
|
||||
* An off-heap memory stack.
|
||||
*
|
||||
* <p>This class should be used in a thread-local manner for stack allocations.</p>
|
||||
*
|
||||
* @ see Configuration#STACK_SIZE
|
||||
* @ see Configuration#DEBUG_STACK
|
||||
*/
|
||||
@SuppressWarnings("LombokGetterMayBeUsed")
|
||||
public class MemoryStack extends Pointer.Default implements AutoCloseable {
|
||||
|
||||
private static final int DEFAULT_STACK_SIZE = /*Configuration.STACK_SIZE.get(64)*/ 64 * 1024;
|
||||
private static final int DEFAULT_STACK_FRAMES = 8;
|
||||
|
||||
private static final ThreadLocal<MemoryStack> TLS = ThreadLocal.withInitial(MemoryStack::create);
|
||||
|
||||
static {
|
||||
if (DEFAULT_STACK_SIZE < 0) {
|
||||
throw new IllegalStateException("Invalid stack size.");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
||||
private final @Nullable ByteBuffer container;
|
||||
|
||||
private final int size;
|
||||
|
||||
private int pointer;
|
||||
|
||||
private int[] frames;
|
||||
protected int frameIndex;
|
||||
|
||||
/**
|
||||
* Creates a new {@code MemoryStack} backed by the specified memory region.
|
||||
*
|
||||
* <p>In the initial state, there is no active stack frame. The {@link #push} method must be used before any allocations.</p>
|
||||
*
|
||||
* @param container the backing memory buffer, may be null
|
||||
* @param address the backing memory address
|
||||
* @param size the backing memory size
|
||||
*/
|
||||
protected MemoryStack(@Nullable ByteBuffer container, long address, int size) {
|
||||
super(address);
|
||||
this.container = container;
|
||||
|
||||
this.size = size;
|
||||
this.pointer = size;
|
||||
|
||||
this.frames = new int[DEFAULT_STACK_FRAMES];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code MemoryStack} with the default size.
|
||||
*
|
||||
* <p>In the initial state, there is no active stack frame. The {@link #push} method must be used before any allocations.</p>
|
||||
*/
|
||||
public static MemoryStack create() {
|
||||
return create(DEFAULT_STACK_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code MemoryStack} with the specified size.
|
||||
*
|
||||
* <p>In the initial state, there is no active stack frame. The {@link #push} method must be used before any allocations.</p>
|
||||
*
|
||||
* @param capacity the maximum number of bytes that may be allocated on the stack
|
||||
*/
|
||||
public static MemoryStack create(int capacity) {
|
||||
return create(BufferUtils.createByteBuffer(capacity));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code MemoryStack} backed by the specified memory buffer.
|
||||
*
|
||||
* <p>In the initial state, there is no active stack frame. The {@link #push} method must be used before any allocations.</p>
|
||||
*
|
||||
* @param buffer the backing memory buffer
|
||||
*/
|
||||
public static MemoryStack create(ByteBuffer buffer) {
|
||||
long address = MemoryUtil.getAddress(buffer);
|
||||
int size = buffer.remaining();
|
||||
return new MemoryStack(buffer, address, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code MemoryStack} backed by the specified memory region.
|
||||
*
|
||||
* <p>In the initial state, there is no active stack frame. The {@link #push} method must be used before any allocations.</p>
|
||||
*
|
||||
* @param address the backing memory address
|
||||
* @param size the backing memory size
|
||||
*/
|
||||
public static MemoryStack ncreate(long address, int size) {
|
||||
return new MemoryStack(null, address, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the current stack pointer and pushes a new frame to the stack.
|
||||
*
|
||||
* <p>This method should be called when entering a method, before doing any stack allocations. When exiting a method, call the {@link #pop} method to
|
||||
* restore the previous stack frame.</p>
|
||||
*
|
||||
* <p>Pairs of push/pop calls may be nested. Care must be taken to:</p>
|
||||
* <ul>
|
||||
* <li>match every push with a pop</li>
|
||||
* <li>not call pop before push has been called at least once</li>
|
||||
* <li>not nest push calls to more than the maximum supported depth</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return this stack
|
||||
*/
|
||||
public MemoryStack push() {
|
||||
if (frameIndex == frames.length) {
|
||||
frameOverflow();
|
||||
}
|
||||
|
||||
frames[frameIndex++] = pointer;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void frameOverflow() {
|
||||
if (/*DEBUG*/ false) {
|
||||
AngelicaTweaker.LOGGER.warn("[WARNING] Out of frame stack space (" + frames.length + ") in thread: " + Thread.currentThread());
|
||||
}
|
||||
frames = Arrays.copyOf(frames, frames.length * 3 / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops the current stack frame and moves the stack pointer to the end of the previous stack frame.
|
||||
*
|
||||
* @return this stack
|
||||
*/
|
||||
public MemoryStack pop() {
|
||||
pointer = frames[--frameIndex];
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #pop} on this {@code MemoryStack}.
|
||||
*
|
||||
* <p>This method should not be used directly. It is called automatically when the {@code MemoryStack} is used as a resource in a try-with-resources
|
||||
* statement.</p>
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
//noinspection resource
|
||||
pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address of the backing off-heap memory.
|
||||
*
|
||||
* <p>The stack grows "downwards", so the bottom of the stack is at {@code address + size}, while the top is at {@code address}.</p>
|
||||
*/
|
||||
public long getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the backing off-heap memory.
|
||||
*
|
||||
* <p>This is the maximum number of bytes that may be allocated on the stack.</p>
|
||||
*/
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current frame index.
|
||||
*
|
||||
* <p>This is the current number of nested {@link #push} calls.</p>
|
||||
*/
|
||||
public int getFrameIndex() {
|
||||
return frameIndex;
|
||||
}
|
||||
|
||||
/** Returns the memory address at the current stack pointer. */
|
||||
public long getPointerAddress() {
|
||||
return address + (pointer & 0xFFFF_FFFFL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current stack pointer.
|
||||
*
|
||||
* <p>The stack grows "downwards", so when the stack is empty {@code pointer} is equal to {@code size}. On every allocation {@code pointer} is reduced by
|
||||
* the allocated size (after alignment) and {@code address + pointer} points to the first byte of the last allocation.</p>
|
||||
*
|
||||
* <p>Effectively, this methods returns how many more bytes may be allocated on the stack.</p>
|
||||
*/
|
||||
public int getPointer() {
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current stack pointer.
|
||||
*
|
||||
* <p>This method directly manipulates the stack pointer. Using it irresponsibly may break the internal state of the stack. It should only be used in rare
|
||||
* cases or in auto-generated code.</p>
|
||||
*/
|
||||
public void setPointer(int pointer) {
|
||||
if (/*CHECKS*/ false) {
|
||||
checkPointer(pointer);
|
||||
}
|
||||
|
||||
this.pointer = pointer;
|
||||
}
|
||||
|
||||
private void checkPointer(int pointer) {
|
||||
if (pointer < 0 || size < pointer) {
|
||||
throw new IndexOutOfBoundsException("Invalid stack pointer");
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkAlignment(int alignment) {
|
||||
if (Integer.bitCount(alignment) != 1) {
|
||||
throw new IllegalArgumentException("Alignment must be a power-of-two value.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #nmalloc(int, int)} with {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.
|
||||
*
|
||||
* @param size the allocation size
|
||||
*
|
||||
* @return the memory address on the stack for the requested allocation
|
||||
*/
|
||||
public long nmalloc(int size) {
|
||||
return nmalloc(POINTER_SIZE, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a block of {@code size} bytes of memory on the stack. The content of the newly allocated block of memory is not initialized, remaining with
|
||||
* indeterminate values.
|
||||
*
|
||||
* @param alignment the required alignment
|
||||
* @param size the allocation size
|
||||
*
|
||||
* @return the memory address on the stack for the requested allocation
|
||||
*/
|
||||
public long nmalloc(int alignment, int size) {
|
||||
// Align address to the specified alignment
|
||||
long address = (this.address + pointer - size) & ~Integer.toUnsignedLong(alignment - 1);
|
||||
|
||||
pointer = (int)(address - this.address);
|
||||
if (/*CHECKS*/ false && pointer < 0) {
|
||||
throw new OutOfMemoryError("Out of stack space.");
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a block of memory on the stack for an array of {@code num} elements, each of them {@code size} bytes long, and initializes all its bits to
|
||||
* zero.
|
||||
*
|
||||
* @param alignment the required element alignment
|
||||
* @param num num the number of elements to allocate
|
||||
* @param size the size of each element
|
||||
*
|
||||
* @return the memory address on the stack for the requested allocation
|
||||
*/
|
||||
public long ncalloc(int alignment, int num, int size) {
|
||||
int bytes = num * size;
|
||||
long address = nmalloc(alignment, bytes);
|
||||
memSet(address, 0, bytes);
|
||||
return address;
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
/** Unsafe version of {@link #shorts(short)}. */
|
||||
public long nshort(short value) {
|
||||
long a = nmalloc(2, 2);
|
||||
memPutShort(a, value);
|
||||
return a;
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
/** Int version of {@link #malloc(int)}. */
|
||||
public IntBuffer mallocInt(int size) { return wrapBufferInt(nmalloc(4, size << 2), size); }
|
||||
|
||||
/** Unsafe version of {@link #ints(int)}. */
|
||||
public long nint(int value) {
|
||||
long a = nmalloc(4, 4);
|
||||
memPutInt(a, value);
|
||||
return a;
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
/** Unsafe version of {@link #longs(long)}. */
|
||||
public long nlong(long value) {
|
||||
long a = nmalloc(8, 8);
|
||||
memPutLong(a, value);
|
||||
return a;
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
/** Float version of {@link #malloc(int)}. */
|
||||
public FloatBuffer mallocFloat(int size) { return wrapBufferFloat(nmalloc(4, size << 2), size); }
|
||||
|
||||
/** Unsafe version of {@link #floats(float)}. */
|
||||
public long nfloat(float value) {
|
||||
long a = nmalloc(4, 4);
|
||||
memPutFloat(a, value);
|
||||
return a;
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
/** Unsafe version of {@link #doubles(double)}. */
|
||||
public long ndouble(double value) {
|
||||
long a = nmalloc(8, 8);
|
||||
memPutDouble(a, value);
|
||||
return a;
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
// -------------------------------------------------
|
||||
// -------------------------------------------------
|
||||
|
||||
|
||||
/** Returns the stack of the current thread. */
|
||||
public static MemoryStack stackGet() {
|
||||
return TLS.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #push} on the stack of the current thread.
|
||||
*
|
||||
* @return the stack of the current thread.
|
||||
*/
|
||||
public static MemoryStack stackPush() {
|
||||
return stackGet().push();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #pop} on the stack of the current thread.
|
||||
*
|
||||
* @return the stack of the current thread.
|
||||
*/
|
||||
public static MemoryStack stackPop() {
|
||||
return stackGet().pop();
|
||||
}
|
||||
|
||||
/** Thread-local version of {@link #nmalloc(int)}. */
|
||||
public static long nstackMalloc(int size) { return stackGet().nmalloc(size); }
|
||||
/** Thread-local version of {@link #nmalloc(int, int)}. */
|
||||
public static long nstackMalloc(int alignment, int size) { return stackGet().nmalloc(alignment, size); }
|
||||
/** Thread-local version of {@link #ncalloc}. */
|
||||
public static long nstackCalloc(int alignment, int num, int size) { return stackGet().ncalloc(alignment, num, size); }
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* This class is backported from LWJGL3 under the BSD 3-clause "New" or "Revised" License
|
||||
*/
|
||||
package com.gtnewhorizons.angelica.compat.lwjgl;
|
||||
|
||||
|
||||
import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.NULL;
|
||||
import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.UNSAFE;
|
||||
import static org.lwjgl.LWJGLUtil.CHECKS;
|
||||
|
||||
import net.minecraft.util.Util;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Pointer interface.
|
||||
*
|
||||
* <p>LWJGL can run on both 32bit and 64bit architectures. Since LWJGL applications deal with native memory directly, this interface provides necessary
|
||||
* information about the underlying architecture of the running JVM process.</p>
|
||||
*
|
||||
* <p>When interacting with native functions, pointer values are mapped to Java {@code long}. LWJGL automatically converts long values to the correct pointer
|
||||
* addresses when used in native code. Native functions sometimes require arrays of pointer values; the {@link PointerBuffer} class may be used for that
|
||||
* purpose. It has an API similar to a {@link java.nio.LongBuffer} but handles pointer casts automatically.</p>
|
||||
*/
|
||||
public interface Pointer {
|
||||
|
||||
/** The pointer size in bytes. Will be 4 on a 32bit JVM and 8 on a 64bit one. */
|
||||
int POINTER_SIZE = UNSAFE.addressSize();
|
||||
|
||||
/** The pointer size power-of-two. Will be 2 on a 32bit JVM and 3 on a 64bit one. */
|
||||
int POINTER_SHIFT = POINTER_SIZE == 8 ? 3 : 2;
|
||||
|
||||
/** The value of {@code sizeof(long)} for the current platform. */
|
||||
int CLONG_SIZE = POINTER_SIZE == 8 && Util.getOSType() == Util.EnumOS.WINDOWS ? 4 : POINTER_SIZE;
|
||||
|
||||
/** The value of {@code sizeof(long)} as a power-of-two. */
|
||||
int CLONG_SHIFT = CLONG_SIZE == 8 ? 3 : 2;
|
||||
|
||||
/** Will be true on a 32bit JVM. */
|
||||
boolean BITS32 = POINTER_SIZE * 8 == 32;
|
||||
|
||||
/** Will be true on a 64bit JVM. */
|
||||
boolean BITS64 = POINTER_SIZE * 8 == 64;
|
||||
|
||||
/**
|
||||
* Returns the raw pointer address as a {@code long} value.
|
||||
*
|
||||
* @return the pointer address
|
||||
*/
|
||||
long address();
|
||||
|
||||
/** Default {@link Pointer} implementation. */
|
||||
abstract class Default implements Pointer {
|
||||
|
||||
// Removed final due to JDK-8139758. TODO: Restore if the fix is backported to JDK 8.
|
||||
protected long address;
|
||||
|
||||
protected Default(long address) {
|
||||
if (CHECKS && address == NULL) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long address() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof Pointer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Pointer that = (Pointer)o;
|
||||
|
||||
return address == that.address();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return (int)(address ^ (address >>> 32));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s pointer [0x%X]", getClass().getSimpleName(), address);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -15,6 +15,7 @@ public class ByteBufferBackedInputStream extends InputStream {
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (!buf.hasRemaining()) {
|
||||
return -1;
|
||||
|
||||
@@ -40,6 +40,7 @@ public class ChunkPos {
|
||||
return (long)x & 4294967295L | ((long)z & 4294967295L) << 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int i = 1664525 * this.x + 1013904223;
|
||||
@@ -47,6 +48,7 @@ public class ChunkPos {
|
||||
return i ^ j;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.ModStatus;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public enum InteractionHand {
|
||||
MAIN_HAND,
|
||||
OFF_HAND;
|
||||
|
||||
InteractionHand() {
|
||||
}
|
||||
|
||||
public ItemStack getItemInHand(EntityPlayer player){
|
||||
if (ModStatus.isBackhandLoaded && this == InteractionHand.OFF_HAND){ // off hand (requires backhand)
|
||||
return ModStatus.backhandCompat.getOffhandItem(player);
|
||||
}
|
||||
else { // main hand
|
||||
return player.getHeldItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.lwjgl.MemoryStack;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -8,6 +7,8 @@ import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities;
|
||||
import lombok.Getter;
|
||||
import net.coderbot.iris.Iris;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -58,15 +59,20 @@ public class NativeImage extends BufferedImage {
|
||||
|
||||
// final int width = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, level, GL11.GL_TEXTURE_WIDTH);
|
||||
// final int height = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, level, GL11.GL_TEXTURE_HEIGHT);
|
||||
try (final MemoryStack stack = MemoryStack.stackPush()) {
|
||||
final IntBuffer buffer = stack.mallocInt(size);
|
||||
|
||||
final IntBuffer buffer = MemoryUtilities.memAllocInt(size);
|
||||
|
||||
try {
|
||||
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, level, format.glFormat, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
|
||||
|
||||
int[] data = new int[size];
|
||||
buffer.get(data);
|
||||
setRGB(0, 0, width, height, data, 0, width);
|
||||
} finally {
|
||||
MemoryUtilities.memFree(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeToFile(File file) throws IOException{
|
||||
try {
|
||||
ImageIO.write(this, "png", file);
|
||||
@@ -104,18 +110,15 @@ public class NativeImage extends BufferedImage {
|
||||
|
||||
|
||||
public enum Format {
|
||||
RGBA(4, GL11.GL_RGBA, BufferedImage.TYPE_INT_ARGB),
|
||||
RGB(3, GL11.GL_RGB, BufferedImage.TYPE_INT_RGB);
|
||||
RGBA(4, GL11.GL_RGBA),
|
||||
RGB(3, GL11.GL_RGB);
|
||||
|
||||
private final int components;
|
||||
private final int glFormat;
|
||||
private final int imageType;
|
||||
|
||||
|
||||
Format(int components, int glFormat, int imageType) {
|
||||
Format(int components, int glFormat) {
|
||||
this.components = components;
|
||||
this.glFormat = glFormat;
|
||||
this.imageType = imageType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
|
||||
private final MultiPhaseParameters phases;
|
||||
private final int hash;
|
||||
private final Optional<RenderLayer> affectedOutline;
|
||||
private final boolean outline;
|
||||
|
||||
private MultiPhase(String name, VertexFormat vertexFormat, int drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, MultiPhaseParameters phases) {
|
||||
super(name, vertexFormat, drawMode, expectedBufferSize, () -> {
|
||||
@@ -84,7 +83,6 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
|
||||
this.affectedOutline = phases.outlineMode == RenderLayer.OutlineMode.AFFECTS_OUTLINE ? phases.texture.getId().map((arg2) -> {
|
||||
return getOutline(arg2, phases.cull);
|
||||
}) : Optional.empty();
|
||||
this.outline = phases.outlineMode == RenderLayer.OutlineMode.IS_OUTLINE;
|
||||
this.hash = Objects.hash(new Object[]{super.hashCode(), phases});
|
||||
}
|
||||
|
||||
@@ -97,20 +95,23 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
|
||||
return this.affectedOutline;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
return this == object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RenderType[" + this.phases + ']';
|
||||
}
|
||||
|
||||
static {
|
||||
CACHE = new ObjectOpenCustomHashSet(RenderLayer.MultiPhase.HashStrategy.INSTANCE);
|
||||
CACHE = new ObjectOpenCustomHashSet<>(RenderLayer.MultiPhase.HashStrategy.INSTANCE);
|
||||
}
|
||||
|
||||
static enum HashStrategy implements Hash.Strategy<MultiPhase> {
|
||||
@@ -168,6 +169,7 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
|
||||
this.phases = ImmutableList.of(this.texture, this.transparency, this.diffuseLighting, this.shadeModel, this.alpha, this.depthTest, this.cull, this.lightmap, this.fog, this.layering, this.target, this.texturing, this.writeMaskState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
@@ -179,10 +181,12 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(new Object[]{this.phases, this.outlineMode});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CompositeState[" + this.phases + ", outlineProperty=" + this.outlineMode + ']';
|
||||
}
|
||||
@@ -293,6 +297,7 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import org.lwjgl.opengl.GL11;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalDouble;
|
||||
|
||||
|
||||
public abstract class RenderPhase {
|
||||
@@ -98,6 +97,7 @@ public abstract class RenderPhase {
|
||||
this.endAction.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
@@ -109,10 +109,12 @@ public abstract class RenderPhase {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class AngelicaConfig {
|
||||
public static boolean enableIris;
|
||||
|
||||
@Config.Comment("Enable MCPatcherForge features, still in Alpha. Individual features are toggled in mcpatcher.json")
|
||||
@Config.DefaultBoolean(false)
|
||||
@Config.DefaultBoolean(true)
|
||||
@Config.RequiresMcRestart
|
||||
public static boolean enableMCPatcherForgeFeatures;
|
||||
|
||||
@@ -133,6 +133,11 @@ public class AngelicaConfig {
|
||||
@Config.RequiresMcRestart
|
||||
public static boolean enableDebugLogging;
|
||||
|
||||
@Config.Comment("Enables PBR atlas dumping")
|
||||
@Config.DefaultBoolean(false)
|
||||
@Config.Name("Enable PBR Debug")
|
||||
public static boolean enablePBRDebug;
|
||||
|
||||
@Config.Comment("Enable Zoom")
|
||||
@Config.DefaultBoolean(true)
|
||||
@Config.RequiresMcRestart
|
||||
@@ -143,9 +148,26 @@ public class AngelicaConfig {
|
||||
@Config.RequiresMcRestart
|
||||
public static boolean optimizeInWorldItemRendering;
|
||||
|
||||
@Config.Comment("Max amount of display lists to cache for optimized item rendering. Higher number will use more VRAM")
|
||||
@Config.DefaultInt(256)
|
||||
@Config.RangeInt(min = 64, max = 1024)
|
||||
public static int itemRendererDisplayListCacheSize;
|
||||
@Config.Comment("Upper limit for the amount of VBO's to cache for optimized item rendering. Higher number can potentially use more VRAM.")
|
||||
@Config.DefaultInt(512)
|
||||
@Config.RangeInt(min = 256, max = 1024)
|
||||
public static int itemRendererCacheSize;
|
||||
|
||||
@Config.Comment("Render distance for the spinning mob inside mod spawners")
|
||||
@Config.DefaultDouble(16D)
|
||||
@Config.RangeDouble(min = 16D, max = 64D)
|
||||
public static double mobSpawnerRenderDistance;
|
||||
|
||||
@Config.Comment("Switches to an alternate FPS limiter that gives more stable frametimes, in exchange for slightly " +
|
||||
"more latency. Will never introduce more than one frame of latency, and has a lower impact at higher framerates.")
|
||||
@Config.DefaultBoolean(false)
|
||||
public static boolean sleepBeforeSwap;
|
||||
|
||||
@Config.Comment("Allows unicode languages to use an odd gui scale")
|
||||
@Config.DefaultBoolean(true)
|
||||
public static boolean removeUnicodeEvenScaling;
|
||||
|
||||
@Config.Comment("Register HardcodedCustomUniforms in Iris Shaders. May help with compatibility in certain shader packs")
|
||||
@Config.DefaultBoolean(false)
|
||||
public static boolean enableHardcodedCustomUniforms;
|
||||
}
|
||||
@@ -6,6 +6,12 @@ import net.minecraft.client.gui.GuiScreen;
|
||||
|
||||
public class AngelicaGuiConfig extends SimpleGuiConfig {
|
||||
public AngelicaGuiConfig(GuiScreen parent) throws ConfigException {
|
||||
super(parent, AngelicaConfig.class, "angelica", "Angelica");
|
||||
super(parent,
|
||||
"angelica",
|
||||
"Angelica",
|
||||
true,
|
||||
AngelicaConfig.class,
|
||||
FontConfig.class
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -39,4 +39,9 @@ public class CompatConfig {
|
||||
@Config.DefaultBoolean(true)
|
||||
@Config.RequiresMcRestart
|
||||
public static boolean fixImmersiveEngineering;
|
||||
|
||||
@Config.Comment("Apply fixes to Security Craft")
|
||||
@Config.DefaultBoolean(true)
|
||||
@Config.RequiresMcRestart
|
||||
public static boolean fixSecurityCraft;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.gtnewhorizons.angelica.config;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.config.Config;
|
||||
|
||||
@Config(modid = "angelica", category = "customfont")
|
||||
public class FontConfig {
|
||||
@Config.Comment("Whether or not to use custom fonts when drawing text.")
|
||||
@Config.DefaultBoolean(false)
|
||||
public static boolean enableCustomFont;
|
||||
|
||||
@Config.Comment("Name of the primary custom font. Best not to set it from here.")
|
||||
@Config.DefaultString("(none)")
|
||||
public static String customFontNamePrimary;
|
||||
|
||||
@Config.Comment("Name of the fallback custom font. Best not to set it from here.")
|
||||
@Config.DefaultString("(none)")
|
||||
public static String customFontNameFallback;
|
||||
|
||||
@Config.Comment("The quality at which custom fonts are rendered, making them less pixelated but increasing memory usage.")
|
||||
@Config.DefaultInt(30)
|
||||
@Config.RangeInt(min = 6, max = 72)
|
||||
public static int customFontQuality;
|
||||
|
||||
@Config.Comment("Controls the distance at which the font's shadow is drawn.")
|
||||
@Config.DefaultFloat(1F)
|
||||
@Config.RangeFloat(min = 0F, max = 2F)
|
||||
public static float fontShadowOffset;
|
||||
|
||||
@Config.Comment("Influences the aspect ratio of each glyph.")
|
||||
@Config.DefaultFloat(0F)
|
||||
@Config.RangeFloat(min = -1F, max = 1F)
|
||||
public static float glyphAspect;
|
||||
|
||||
@Config.Comment("Scale of each glyph, whitespace excluded.")
|
||||
@Config.DefaultFloat(1F)
|
||||
@Config.RangeFloat(min = 0.1F, max = 3F)
|
||||
public static float glyphScale;
|
||||
|
||||
@Config.Comment("Whitespace scale.")
|
||||
@Config.DefaultFloat(1F)
|
||||
@Config.RangeFloat(min = 0.1F, max = 3F)
|
||||
public static float whitespaceScale;
|
||||
|
||||
@Config.Comment("Adds extra spacing between glyphs.")
|
||||
@Config.DefaultFloat(0F)
|
||||
@Config.RangeFloat(min = -2F, max = 2F)
|
||||
public static float glyphSpacing;
|
||||
|
||||
@Config.Comment("Controls font antialiasing. 0 = none, 1 = 4x MSAA, 2 = 16x MSAA.")
|
||||
@Config.DefaultInt(2)
|
||||
@Config.RangeInt(min = 0, max = 2)
|
||||
public static int fontAAMode;
|
||||
|
||||
@Config.Comment("Affects font antialiasing sample spacing. Higher values increase blur.")
|
||||
@Config.DefaultInt(7)
|
||||
@Config.RangeInt(min = 1, max = 24)
|
||||
public static int fontAAStrength;
|
||||
}
|
||||
@@ -28,9 +28,10 @@ import static org.lwjgl.opengl.GL20.glUniform1;
|
||||
import static org.lwjgl.opengl.GL20.glUniform1f;
|
||||
import static org.lwjgl.opengl.GL20.glUniform1i;
|
||||
import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryStack.*;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.bytebuf.MemoryStack;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.shader.ShaderProgram;
|
||||
import com.gtnewhorizons.angelica.compat.lwjgl.MemoryStack;
|
||||
import java.nio.FloatBuffer;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
@@ -131,7 +132,7 @@ public abstract class F3Graph {
|
||||
// Load vertex buffer
|
||||
vertBuf = glGenBuffers();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertBuf);
|
||||
try (final MemoryStack stack = MemoryStack.stackPush()) {
|
||||
try (final MemoryStack stack = stackPush()) {
|
||||
final FloatBuffer vertices = stack.mallocFloat(VERT_COUNT * VERT_FLOATS);
|
||||
// Since we use a triangle strip, we only need 4 vertices. The quad extends to the top of the screen so spikes
|
||||
// don't get truncated. The max height is replaced in the vert shader, no need to be precise.
|
||||
|
||||
@@ -6,19 +6,18 @@ import com.gtnewhorizon.gtnhlib.blockpos.IBlockPos;
|
||||
import com.gtnewhorizon.gtnhlib.util.CoordinatePacker;
|
||||
import com.gtnewhorizons.angelica.api.IDynamicLightProducer;
|
||||
import com.gtnewhorizons.angelica.compat.ModStatus;
|
||||
import com.gtnewhorizons.angelica.compat.battlegear2.Battlegear2Compat;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer;
|
||||
import mods.battlegear2.api.core.IBattlePlayer;
|
||||
import mods.battlegear2.api.core.IInventoryPlayerBattle;
|
||||
import net.irisshaders.iris.api.v0.IrisApi;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.monster.EntityCreeper;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
@@ -28,7 +27,6 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xonin.backhand.api.core.BackhandUtils;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
@@ -378,13 +376,13 @@ public class DynamicLights {
|
||||
player instanceof IBattlePlayer battlePlayer &&
|
||||
battlePlayer.battlegear2$isBattlemode()
|
||||
) {
|
||||
ItemStack offhand = ((IInventoryPlayerBattle) player.inventory).battlegear2$getCurrentOffhandWeapon();
|
||||
ItemStack offhand = Battlegear2Compat.getBattlegear2Offhand(player);
|
||||
if (offhand != null) {
|
||||
luminance = Math.max(luminance, getLuminanceFromItemStack(offhand, inWater));
|
||||
}
|
||||
}
|
||||
else if (ModStatus.isBackhandLoaded && living instanceof EntityPlayer player){
|
||||
ItemStack offhand = BackhandUtils.getOffhandItem(player);
|
||||
ItemStack offhand = ModStatus.backhandCompat.getOffhandItem(player);
|
||||
if (offhand != null) {
|
||||
luminance = Math.max(luminance, getLuminanceFromItemStack(offhand, inWater));
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -19,24 +21,42 @@ public class Feature {
|
||||
GL13.GL_MULTISAMPLE_BIT, GL11.GL_PIXEL_MODE_BIT, GL11.GL_POINT_BIT, GL11.GL_POLYGON_BIT, GL11.GL_POLYGON_STIPPLE_BIT, GL11.GL_SCISSOR_BIT,
|
||||
GL11.GL_STENCIL_BUFFER_BIT, GL11.GL_TEXTURE_BIT, GL11.GL_TRANSFORM_BIT, GL11.GL_VIEWPORT_BIT };
|
||||
|
||||
static final Int2ObjectMap<Set<IStateStack<?>>> maskToFeaturesMap = new Int2ObjectOpenHashMap<>();
|
||||
static final Int2ObjectMap<List<IStateStack<?>>> maskToFeaturesMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
static Set<IStateStack<?>> maskToFeatures(int mask) {
|
||||
static List<IStateStack<?>> maskToFeatures(int mask) {
|
||||
if(maskToFeaturesMap.containsKey(mask)) {
|
||||
return maskToFeaturesMap.get(mask);
|
||||
}
|
||||
|
||||
final Set<IStateStack<?>> features = new HashSet<>();
|
||||
|
||||
for(int attrib : Feature.supportedAttribs) {
|
||||
if((mask & attrib) == attrib) {
|
||||
features.addAll(getFeatures(attrib));
|
||||
}
|
||||
}
|
||||
maskToFeaturesMap.put(mask, features);
|
||||
return features;
|
||||
|
||||
final List<IStateStack<?>> asList = new ArrayList<>(features);
|
||||
|
||||
maskToFeaturesMap.put(mask, asList);
|
||||
return asList;
|
||||
}
|
||||
|
||||
private static final Map<Integer, Set<IStateStack<?>>> attribToFeatures = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Helper method to add all texture gen states (S, T, R, Q) for all texture units to a collection.
|
||||
* Used by both GL_ENABLE_BIT and GL_TEXTURE_BIT.
|
||||
*/
|
||||
private static void addTextureGenStates(Set<IStateStack<?>> collection) {
|
||||
for(int i = 0 ; i < GLStateManager.MAX_TEXTURE_UNITS; i++) {
|
||||
collection.add(GLStateManager.textures.getTexGenSStates(i));
|
||||
collection.add(GLStateManager.textures.getTexGenTStates(i));
|
||||
collection.add(GLStateManager.textures.getTexGenRStates(i));
|
||||
collection.add(GLStateManager.textures.getTexGenQStates(i));
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
attribToFeatures.put(GL11.GL_COLOR_BUFFER_BIT, ImmutableSet.of(
|
||||
GLStateManager.alphaTest // GL_ALPHA_TEST enable bit
|
||||
@@ -45,10 +65,10 @@ public class Feature {
|
||||
, GLStateManager.blendState // Blending source and destination functions
|
||||
// Constant blend color
|
||||
// Blending equation
|
||||
// GL_DITHER enable bit
|
||||
// GL_DRAW_BUFFER setting
|
||||
// GL_COLOR_LOGIC_OP enable bit
|
||||
// GL_INDEX_LOGIC_OP enable bit
|
||||
, GLStateManager.colorLogicOpState // GL_COLOR_LOGIC_OP enable bit
|
||||
, GLStateManager.ditherState // GL_DITHER enable bit
|
||||
, GLStateManager.drawBuffer // GL_DRAW_BUFFER setting
|
||||
, GLStateManager.indexLogicOpState // GL_INDEX_LOGIC_OP enable bit
|
||||
// Logic op function
|
||||
, GLStateManager.colorMask // Color-mode and index-mode writemasks
|
||||
, GLStateManager.clearColor // Color-mode and index-mode clear values
|
||||
@@ -74,14 +94,15 @@ public class Feature {
|
||||
|
||||
final HashSet<IStateStack<?>> enableBits = new HashSet<>(ImmutableSet.of(
|
||||
GLStateManager.alphaTest // GL_ALPHA_TEST flag
|
||||
// GL_AUTO_NORMAL flag
|
||||
, GLStateManager.autoNormalState // GL_AUTO_NORMAL flag
|
||||
, GLStateManager.blendMode // GL_BLEND flag
|
||||
// Enable bits for the user-definable clipping planes
|
||||
, GLStateManager.colorLogicOpState // GL_COLOR_LOGIC_OP flag
|
||||
, GLStateManager.colorMaterial // GL_COLOR_MATERIAL
|
||||
, GLStateManager.cullState // GL_CULL_FACE flag
|
||||
, GLStateManager.depthTest // GL_DEPTH_TEST flag
|
||||
// GL_DITHER flag
|
||||
, GLStateManager.ditherState // GL_DITHER flag
|
||||
, GLStateManager.fogMode // GL_FOG flag
|
||||
, GLStateManager.indexLogicOpState // GL_INDEX_LOGIC_OP flag
|
||||
, GLStateManager.lightStates[0] // GL_LIGHT0
|
||||
, GLStateManager.lightStates[1] // GL_LIGHT1
|
||||
, GLStateManager.lightStates[2] // GL_LIGHT2
|
||||
@@ -91,36 +112,57 @@ public class Feature {
|
||||
, GLStateManager.lightStates[6] // GL_LIGHT6
|
||||
, GLStateManager.lightStates[7] // GL_LIGHT7
|
||||
, GLStateManager.lightingState // GL_LIGHTING flag
|
||||
// GL_LINE_SMOOTH flag
|
||||
// GL_LINE_STIPPLE flag
|
||||
// GL_INDEX_LOGIC_OP flag
|
||||
// GL_COLOR_LOGIC_OP flag
|
||||
// GL_MAP1_x where x is a map type
|
||||
// GL_MAP2_x where x is a map type
|
||||
// GL_MULTISAMPLE flag
|
||||
// GL_NORMALIZE flag
|
||||
// GL_POINT_SMOOTH flag
|
||||
// GL_POLYGON_OFFSET_LINE flag
|
||||
// GL_POLYGON_OFFSET_FILL flag
|
||||
// GL_POLYGON_OFFSET_POINT flag
|
||||
// GL_POLYGON_SMOOTH flag
|
||||
// GL_POLYGON_STIPPLE flag
|
||||
// GL_SAMPLE_ALPHA_TO_COVERAGE flag
|
||||
// GL_SAMPLE_ALPHA_TO_ONE flag
|
||||
// GL_SAMPLE_COVERAGE flag
|
||||
, GLStateManager.lineSmoothState // GL_LINE_SMOOTH flag
|
||||
, GLStateManager.lineStippleState // GL_LINE_STIPPLE flag
|
||||
, GLStateManager.map1Color4State // GL_MAP1_COLOR_4
|
||||
, GLStateManager.map1IndexState // GL_MAP1_INDEX
|
||||
, GLStateManager.map1NormalState // GL_MAP1_NORMAL
|
||||
, GLStateManager.map1TextureCoord1State // GL_MAP1_TEXTURE_COORD_1
|
||||
, GLStateManager.map1TextureCoord2State // GL_MAP1_TEXTURE_COORD_2
|
||||
, GLStateManager.map1TextureCoord3State // GL_MAP1_TEXTURE_COORD_3
|
||||
, GLStateManager.map1TextureCoord4State // GL_MAP1_TEXTURE_COORD_4
|
||||
, GLStateManager.map1Vertex3State // GL_MAP1_VERTEX_3
|
||||
, GLStateManager.map1Vertex4State // GL_MAP1_VERTEX_4
|
||||
, GLStateManager.map2Color4State // GL_MAP2_COLOR_4
|
||||
, GLStateManager.map2IndexState // GL_MAP2_INDEX
|
||||
, GLStateManager.map2NormalState // GL_MAP2_NORMAL
|
||||
, GLStateManager.map2TextureCoord1State // GL_MAP2_TEXTURE_COORD_1
|
||||
, GLStateManager.map2TextureCoord2State // GL_MAP2_TEXTURE_COORD_2
|
||||
, GLStateManager.map2TextureCoord3State // GL_MAP2_TEXTURE_COORD_3
|
||||
, GLStateManager.map2TextureCoord4State // GL_MAP2_TEXTURE_COORD_4
|
||||
, GLStateManager.map2Vertex3State // GL_MAP2_VERTEX_3
|
||||
, GLStateManager.map2Vertex4State // GL_MAP2_VERTEX_4
|
||||
, GLStateManager.multisampleState // GL_MULTISAMPLE flag
|
||||
, GLStateManager.normalizeState // GL_NORMALIZE flag
|
||||
, GLStateManager.pointSmoothState // GL_POINT_SMOOTH flag
|
||||
, GLStateManager.polygonOffsetPointState // GL_POLYGON_OFFSET_POINT flag
|
||||
, GLStateManager.polygonOffsetLineState // GL_POLYGON_OFFSET_LINE flag
|
||||
, GLStateManager.polygonOffsetFillState // GL_POLYGON_OFFSET_FILL flag
|
||||
, GLStateManager.polygonSmoothState // GL_POLYGON_SMOOTH flag
|
||||
, GLStateManager.polygonStippleState // GL_POLYGON_STIPPLE flag
|
||||
, GLStateManager.rescaleNormalState // GL_RESCALE_NORMAL flag
|
||||
, GLStateManager.sampleAlphaToCoverageState // GL_SAMPLE_ALPHA_TO_COVERAGE flag
|
||||
, GLStateManager.sampleAlphaToOneState // GL_SAMPLE_ALPHA_TO_ONE flag
|
||||
, GLStateManager.sampleCoverageState // GL_SAMPLE_COVERAGE flag
|
||||
, GLStateManager.scissorTest // GL_SCISSOR_TEST flag
|
||||
// GL_STENCIL_TEST flag
|
||||
// GL_TEXTURE_1D flag
|
||||
// GL_TEXTURE_2D flag - Below
|
||||
// GL_TEXTURE_3D flag
|
||||
// Flags GL_TEXTURE_GEN_x where x is S, T, R, or Q
|
||||
, GLStateManager.stencilTest // GL_STENCIL_TEST flag
|
||||
));
|
||||
|
||||
// GL_TEXTURE_2D flag
|
||||
for(int i = 0 ; i < GLStateManager.MAX_TEXTURE_UNITS; i++) {
|
||||
enableBits.add(GLStateManager.textures.getTextureUnitStates(i));
|
||||
// Enable bits for the user-definable clipping planes
|
||||
for(int i = 0; i < GLStateManager.clipPlaneStates.length; i++) {
|
||||
enableBits.add(GLStateManager.clipPlaneStates[i]);
|
||||
}
|
||||
|
||||
// GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D flags
|
||||
for(int i = 0 ; i < GLStateManager.MAX_TEXTURE_UNITS; i++) {
|
||||
enableBits.add(GLStateManager.textures.getTexture1DStates(i));
|
||||
enableBits.add(GLStateManager.textures.getTextureUnitStates(i));
|
||||
enableBits.add(GLStateManager.textures.getTexture3DStates(i));
|
||||
}
|
||||
|
||||
// Flags GL_TEXTURE_GEN_x where x is S, T, R, or Q
|
||||
addTextureGenStates(enableBits);
|
||||
|
||||
attribToFeatures.put(GL11.GL_ENABLE_BIT, enableBits);
|
||||
attribToFeatures.put(GL11.GL_EVAL_BIT, ImmutableSet.of(
|
||||
// GL_MAP1_x enable bits, where x is a map type
|
||||
@@ -262,13 +304,16 @@ public class Feature {
|
||||
// textureAttribs.add(GLStateManager.textures.getInfo(i))
|
||||
}
|
||||
|
||||
// Enable bits GL_TEXTURE_GEN_x where x is S, T, R, or Q
|
||||
addTextureGenStates(textureAttribs);
|
||||
|
||||
attribToFeatures.put(GL11.GL_TEXTURE_BIT, textureAttribs);
|
||||
|
||||
attribToFeatures.put(GL11.GL_TRANSFORM_BIT, ImmutableSet.of(
|
||||
// Coefficients of the six clipping planes
|
||||
// Enable bits for the user-definable clipping planes
|
||||
GLStateManager.matrixMode
|
||||
// GL_NORMALIZE flag
|
||||
, GLStateManager.normalizeState // GL_NORMALIZE flag
|
||||
, GLStateManager.rescaleNormalState // GL_RESCALE_NORMAL flag
|
||||
));
|
||||
attribToFeatures.put(GL11.GL_VIEWPORT_BIT, ImmutableSet.of(
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.gtnewhorizons.angelica.glsm.texture.TextureInfoCache;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.TextureTracker;
|
||||
import com.gtnewhorizons.angelica.hudcaching.HUDCaching;
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
@@ -35,6 +36,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArraySet;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gbuffer_overrides.state.StateTracker;
|
||||
import net.coderbot.iris.gl.blending.AlphaTestStorage;
|
||||
@@ -65,17 +67,37 @@ import org.lwjgl.opengl.GLContext;
|
||||
import org.lwjgl.opengl.KHRDebug;
|
||||
|
||||
import java.lang.Math;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
import static com.gtnewhorizons.angelica.glsm.Vendor.AMD;
|
||||
import static com.gtnewhorizons.angelica.glsm.Vendor.INTEL;
|
||||
import static com.gtnewhorizons.angelica.glsm.Vendor.MESA;
|
||||
import static com.gtnewhorizons.angelica.glsm.Vendor.NVIDIA;
|
||||
import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.LOGGER;
|
||||
|
||||
/**
|
||||
* OpenGL State Manager - Provides cached state tracking and management for OpenGL operations.
|
||||
*
|
||||
* <p><b>IMPORTANT INITIALIZATION ORDER:</b></p>
|
||||
* <ul>
|
||||
* <li>This class performs GL queries in static initializers (MAX_CLIP_PLANES, MAX_TEXTURE_UNITS, etc.)</li>
|
||||
* <li>The class MUST NOT be loaded until after the GL context has been created and made current</li>
|
||||
* <li>Violating this requirement will cause crashes with "No current context" or return invalid values</li>
|
||||
* <li>Call {@link #preInit()} after GL context creation to initialize runtime state</li>
|
||||
* </ul>
|
||||
*/
|
||||
@SuppressWarnings("unused") // Used in ASM
|
||||
public class GLStateManager {
|
||||
public static ContextCapabilities capabilities;
|
||||
@@ -87,13 +109,14 @@ public class GLStateManager {
|
||||
public static final int MAX_PROJECTION_STACK_DEPTH = GL11.glGetInteger(GL11.GL_MAX_PROJECTION_STACK_DEPTH);
|
||||
public static final int MAX_TEXTURE_STACK_DEPTH = GL11.glGetInteger(GL11.GL_MAX_TEXTURE_STACK_DEPTH);
|
||||
public static final int MAX_TEXTURE_UNITS = GL11.glGetInteger(GL20.GL_MAX_TEXTURE_IMAGE_UNITS);
|
||||
public static final int MAX_CLIP_PLANES = GL11.glGetInteger(GL11.GL_MAX_CLIP_PLANES);
|
||||
|
||||
public static final GLFeatureSet HAS_MULTIPLE_SET = new GLFeatureSet();
|
||||
|
||||
@Getter protected static boolean NVIDIA;
|
||||
@Getter protected static boolean AMD;
|
||||
@Getter protected static boolean INTEL;
|
||||
@Getter protected static boolean MESA;
|
||||
@Getter private static Vendor VENDOR;
|
||||
|
||||
// This setting varies depending on driver, so it gets queried at runtime
|
||||
public static final int DEFAULT_DRAW_BUFFER = GL11.glGetInteger(GL11.GL_DRAW_BUFFER);
|
||||
|
||||
// GLStateManager State Trackers
|
||||
private static final IntStack attribs = new IntArrayList(MAX_ATTRIB_STACK_DEPTH);
|
||||
@@ -112,12 +135,58 @@ public class GLStateManager {
|
||||
@Getter protected static final Color4Stack color = new Color4Stack();
|
||||
@Getter protected static final Color4Stack clearColor = new Color4Stack(new Color4(0.0F, 0.0F, 0.0F, 0.0F));
|
||||
@Getter protected static final ColorMaskStack colorMask = new ColorMaskStack();
|
||||
@Getter protected static final IntegerStateStack drawBuffer = new IntegerStateStack(DEFAULT_DRAW_BUFFER);
|
||||
@Getter protected static final BooleanStateStack cullState = new BooleanStateStack(GL11.GL_CULL_FACE);
|
||||
@Getter protected static final AlphaStateStack alphaState = new AlphaStateStack();
|
||||
@Getter protected static final BooleanStateStack alphaTest = new BooleanStateStack(GL11.GL_ALPHA_TEST);
|
||||
|
||||
@Getter protected static final BooleanStateStack lightingState = new BooleanStateStack(GL11.GL_LIGHTING);
|
||||
@Getter protected static final BooleanStateStack rescaleNormalState = new BooleanStateStack(GL12.GL_RESCALE_NORMAL);
|
||||
@Getter protected static final BooleanStateStack normalizeState = new BooleanStateStack(GL11.GL_NORMALIZE);
|
||||
|
||||
// Additional enable bit states tracked by GL_ENABLE_BIT
|
||||
@Getter protected static final BooleanStateStack ditherState = new BooleanStateStack(GL11.GL_DITHER, true); // Defaults to true per OpenGL spec
|
||||
@Getter protected static final BooleanStateStack stencilTest = new BooleanStateStack(GL11.GL_STENCIL_TEST);
|
||||
@Getter protected static final BooleanStateStack lineSmoothState = new BooleanStateStack(GL11.GL_LINE_SMOOTH);
|
||||
@Getter protected static final BooleanStateStack lineStippleState = new BooleanStateStack(GL11.GL_LINE_STIPPLE);
|
||||
@Getter protected static final BooleanStateStack pointSmoothState = new BooleanStateStack(GL11.GL_POINT_SMOOTH);
|
||||
@Getter protected static final BooleanStateStack polygonSmoothState = new BooleanStateStack(GL11.GL_POLYGON_SMOOTH);
|
||||
@Getter protected static final BooleanStateStack polygonStippleState = new BooleanStateStack(GL11.GL_POLYGON_STIPPLE);
|
||||
@Getter protected static final BooleanStateStack multisampleState = new BooleanStateStack(GL13.GL_MULTISAMPLE, true); // Defaults to true per OpenGL spec
|
||||
@Getter protected static final BooleanStateStack sampleAlphaToCoverageState = new BooleanStateStack(GL13.GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||
@Getter protected static final BooleanStateStack sampleAlphaToOneState = new BooleanStateStack(GL13.GL_SAMPLE_ALPHA_TO_ONE);
|
||||
@Getter protected static final BooleanStateStack sampleCoverageState = new BooleanStateStack(GL13.GL_SAMPLE_COVERAGE);
|
||||
@Getter protected static final BooleanStateStack colorLogicOpState = new BooleanStateStack(GL11.GL_COLOR_LOGIC_OP);
|
||||
@Getter protected static final BooleanStateStack indexLogicOpState = new BooleanStateStack(GL11.GL_INDEX_LOGIC_OP);
|
||||
|
||||
// Polygon offset states
|
||||
@Getter protected static final BooleanStateStack polygonOffsetPointState = new BooleanStateStack(GL11.GL_POLYGON_OFFSET_POINT);
|
||||
@Getter protected static final BooleanStateStack polygonOffsetLineState = new BooleanStateStack(GL11.GL_POLYGON_OFFSET_LINE);
|
||||
@Getter protected static final BooleanStateStack polygonOffsetFillState = new BooleanStateStack(GL11.GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
// Evaluator states
|
||||
@Getter protected static final BooleanStateStack autoNormalState = new BooleanStateStack(GL11.GL_AUTO_NORMAL);
|
||||
@Getter protected static final BooleanStateStack map1Color4State = new BooleanStateStack(GL11.GL_MAP1_COLOR_4);
|
||||
@Getter protected static final BooleanStateStack map1IndexState = new BooleanStateStack(GL11.GL_MAP1_INDEX);
|
||||
@Getter protected static final BooleanStateStack map1NormalState = new BooleanStateStack(GL11.GL_MAP1_NORMAL);
|
||||
@Getter protected static final BooleanStateStack map1TextureCoord1State = new BooleanStateStack(GL11.GL_MAP1_TEXTURE_COORD_1);
|
||||
@Getter protected static final BooleanStateStack map1TextureCoord2State = new BooleanStateStack(GL11.GL_MAP1_TEXTURE_COORD_2);
|
||||
@Getter protected static final BooleanStateStack map1TextureCoord3State = new BooleanStateStack(GL11.GL_MAP1_TEXTURE_COORD_3);
|
||||
@Getter protected static final BooleanStateStack map1TextureCoord4State = new BooleanStateStack(GL11.GL_MAP1_TEXTURE_COORD_4);
|
||||
@Getter protected static final BooleanStateStack map1Vertex3State = new BooleanStateStack(GL11.GL_MAP1_VERTEX_3);
|
||||
@Getter protected static final BooleanStateStack map1Vertex4State = new BooleanStateStack(GL11.GL_MAP1_VERTEX_4);
|
||||
@Getter protected static final BooleanStateStack map2Color4State = new BooleanStateStack(GL11.GL_MAP2_COLOR_4);
|
||||
@Getter protected static final BooleanStateStack map2IndexState = new BooleanStateStack(GL11.GL_MAP2_INDEX);
|
||||
@Getter protected static final BooleanStateStack map2NormalState = new BooleanStateStack(GL11.GL_MAP2_NORMAL);
|
||||
@Getter protected static final BooleanStateStack map2TextureCoord1State = new BooleanStateStack(GL11.GL_MAP2_TEXTURE_COORD_1);
|
||||
@Getter protected static final BooleanStateStack map2TextureCoord2State = new BooleanStateStack(GL11.GL_MAP2_TEXTURE_COORD_2);
|
||||
@Getter protected static final BooleanStateStack map2TextureCoord3State = new BooleanStateStack(GL11.GL_MAP2_TEXTURE_COORD_3);
|
||||
@Getter protected static final BooleanStateStack map2TextureCoord4State = new BooleanStateStack(GL11.GL_MAP2_TEXTURE_COORD_4);
|
||||
@Getter protected static final BooleanStateStack map2Vertex3State = new BooleanStateStack(GL11.GL_MAP2_VERTEX_3);
|
||||
@Getter protected static final BooleanStateStack map2Vertex4State = new BooleanStateStack(GL11.GL_MAP2_VERTEX_4);
|
||||
|
||||
// Clip plane states
|
||||
@Getter protected static final BooleanStateStack[] clipPlaneStates = new BooleanStateStack[MAX_CLIP_PLANES];
|
||||
|
||||
@Getter protected static final MatrixModeStack matrixMode = new MatrixModeStack();
|
||||
@Getter protected static final Matrix4fStack modelViewMatrix = new Matrix4fStack(MAX_MODELVIEW_STACK_DEPTH);
|
||||
@@ -133,11 +202,25 @@ public class GLStateManager {
|
||||
@Getter protected static final MaterialStateStack frontMaterial = new MaterialStateStack(GL11.GL_FRONT);
|
||||
@Getter protected static final MaterialStateStack backMaterial = new MaterialStateStack(GL11.GL_BACK);
|
||||
|
||||
private static final MethodHandle MAT4_STACK_CURR_DEPTH;
|
||||
|
||||
static {
|
||||
for (int i = 0; i < lightStates.length; i ++) {
|
||||
lightStates[i] = new BooleanStateStack(GL11.GL_LIGHT0 + i);
|
||||
lightDataStates[i] = new LightStateStack(GL11.GL_LIGHT0 + i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_CLIP_PLANES; i++) {
|
||||
clipPlaneStates[i] = new BooleanStateStack(GL11.GL_CLIP_PLANE0 + i);
|
||||
}
|
||||
|
||||
try {
|
||||
final Field curr = ReflectionHelper.findField(Matrix4fStack.class, "curr");
|
||||
curr.setAccessible(true);
|
||||
MAT4_STACK_CURR_DEPTH = MethodHandles.lookup().unreflectGetter(curr);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Getter protected static final ViewPortStateStack viewportState = new ViewPortStateStack();
|
||||
@@ -149,11 +232,18 @@ public class GLStateManager {
|
||||
while(!attribs.isEmpty()) {
|
||||
attribs.popInt();
|
||||
}
|
||||
for(IStateStack<?> stack : Feature.maskToFeatures(GL11.GL_ALL_ATTRIB_BITS)) {
|
||||
|
||||
final List<IStateStack<?>> stacks = Feature.maskToFeatures(GL11.GL_ALL_ATTRIB_BITS);
|
||||
final int size = stacks.size();
|
||||
|
||||
for(int i = 0; i < size; i++) {
|
||||
final IStateStack<?> stack = stacks.get(i);
|
||||
|
||||
while(!stack.isEmpty()) {
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
modelViewMatrix.clear();
|
||||
projectionMatrix.clear();
|
||||
}
|
||||
@@ -180,6 +270,9 @@ public class GLStateManager {
|
||||
|
||||
|
||||
public static class GLFeatureSet extends IntOpenHashSet {
|
||||
|
||||
private static final long serialVersionUID = 8558779940775721010L;
|
||||
|
||||
public GLFeatureSet addFeature(int feature) {
|
||||
super.add(feature);
|
||||
return this;
|
||||
@@ -218,16 +311,12 @@ public class GLStateManager {
|
||||
.addFeature(GL11.GL_VIEWPORT);
|
||||
|
||||
String glVendor = GL11.glGetString(GL11.GL_VENDOR);
|
||||
NVIDIA = glVendor.toLowerCase().contains("nvidia");
|
||||
AMD = glVendor.toLowerCase().contains("ati") || glVendor.toLowerCase().contains("amd");
|
||||
INTEL = glVendor.toLowerCase().contains("intel");
|
||||
MESA = glVendor.toLowerCase().contains("mesa");
|
||||
VENDOR = Vendor.getVendor(glVendor.toLowerCase());
|
||||
|
||||
if(AMD) {
|
||||
if (vendorIsAMD()) {
|
||||
// AMD Drivers seem to default to 0 for the matrix mode, so we need to set it to the default
|
||||
GL11.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
@@ -273,12 +362,23 @@ public class GLStateManager {
|
||||
|
||||
// LWJGL Overrides
|
||||
public static void glEnable(int cap) {
|
||||
// Handle clip planes dynamically (supports up to MAX_CLIP_PLANES)
|
||||
if (cap >= GL11.GL_CLIP_PLANE0 && cap < GL11.GL_CLIP_PLANE0 + MAX_CLIP_PLANES) {
|
||||
clipPlaneStates[cap - GL11.GL_CLIP_PLANE0].enable();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cap) {
|
||||
case GL11.GL_ALPHA_TEST -> enableAlphaTest();
|
||||
case GL11.GL_AUTO_NORMAL -> autoNormalState.enable();
|
||||
case GL11.GL_BLEND -> enableBlend();
|
||||
case GL11.GL_COLOR_MATERIAL -> enableColorMaterial();
|
||||
case GL11.GL_COLOR_LOGIC_OP -> colorLogicOpState.enable();
|
||||
case GL11.GL_CULL_FACE -> enableCull();
|
||||
case GL11.GL_DEPTH_TEST -> enableDepthTest();
|
||||
case GL11.GL_DITHER -> ditherState.enable();
|
||||
case GL11.GL_FOG -> enableFog();
|
||||
case GL11.GL_INDEX_LOGIC_OP -> indexLogicOpState.enable();
|
||||
case GL11.GL_LIGHTING -> enableLighting();
|
||||
case GL11.GL_LIGHT0 -> enableLight(0);
|
||||
case GL11.GL_LIGHT1 -> enableLight(1);
|
||||
@@ -288,21 +388,69 @@ public class GLStateManager {
|
||||
case GL11.GL_LIGHT5 -> enableLight(5);
|
||||
case GL11.GL_LIGHT6 -> enableLight(6);
|
||||
case GL11.GL_LIGHT7 -> enableLight(7);
|
||||
case GL11.GL_COLOR_MATERIAL -> enableColorMaterial();
|
||||
case GL11.GL_SCISSOR_TEST -> enableScissorTest();
|
||||
case GL11.GL_TEXTURE_2D -> enableTexture();
|
||||
case GL11.GL_LINE_SMOOTH -> lineSmoothState.enable();
|
||||
case GL11.GL_LINE_STIPPLE -> lineStippleState.enable();
|
||||
case GL11.GL_MAP1_COLOR_4 -> map1Color4State.enable();
|
||||
case GL11.GL_MAP1_INDEX -> map1IndexState.enable();
|
||||
case GL11.GL_MAP1_NORMAL -> map1NormalState.enable();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_1 -> map1TextureCoord1State.enable();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_2 -> map1TextureCoord2State.enable();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_3 -> map1TextureCoord3State.enable();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_4 -> map1TextureCoord4State.enable();
|
||||
case GL11.GL_MAP1_VERTEX_3 -> map1Vertex3State.enable();
|
||||
case GL11.GL_MAP1_VERTEX_4 -> map1Vertex4State.enable();
|
||||
case GL11.GL_MAP2_COLOR_4 -> map2Color4State.enable();
|
||||
case GL11.GL_MAP2_INDEX -> map2IndexState.enable();
|
||||
case GL11.GL_MAP2_NORMAL -> map2NormalState.enable();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_1 -> map2TextureCoord1State.enable();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_2 -> map2TextureCoord2State.enable();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_3 -> map2TextureCoord3State.enable();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_4 -> map2TextureCoord4State.enable();
|
||||
case GL11.GL_MAP2_VERTEX_3 -> map2Vertex3State.enable();
|
||||
case GL11.GL_MAP2_VERTEX_4 -> map2Vertex4State.enable();
|
||||
case GL13.GL_MULTISAMPLE -> multisampleState.enable();
|
||||
case GL11.GL_NORMALIZE -> normalizeState.enable();
|
||||
case GL11.GL_POINT_SMOOTH -> pointSmoothState.enable();
|
||||
case GL11.GL_POLYGON_OFFSET_POINT -> polygonOffsetPointState.enable();
|
||||
case GL11.GL_POLYGON_OFFSET_LINE -> polygonOffsetLineState.enable();
|
||||
case GL11.GL_POLYGON_OFFSET_FILL -> polygonOffsetFillState.enable();
|
||||
case GL11.GL_POLYGON_SMOOTH -> polygonSmoothState.enable();
|
||||
case GL11.GL_POLYGON_STIPPLE -> polygonStippleState.enable();
|
||||
case GL12.GL_RESCALE_NORMAL -> enableRescaleNormal();
|
||||
case GL13.GL_SAMPLE_ALPHA_TO_COVERAGE -> sampleAlphaToCoverageState.enable();
|
||||
case GL13.GL_SAMPLE_ALPHA_TO_ONE -> sampleAlphaToOneState.enable();
|
||||
case GL13.GL_SAMPLE_COVERAGE -> sampleCoverageState.enable();
|
||||
case GL11.GL_SCISSOR_TEST -> enableScissorTest();
|
||||
case GL11.GL_STENCIL_TEST -> stencilTest.enable();
|
||||
case GL11.GL_TEXTURE_1D -> textures.getTexture1DStates(activeTextureUnit.getValue()).enable();
|
||||
case GL11.GL_TEXTURE_2D -> enableTexture();
|
||||
case GL12.GL_TEXTURE_3D -> textures.getTexture3DStates(activeTextureUnit.getValue()).enable();
|
||||
case GL11.GL_TEXTURE_GEN_S -> textures.getTexGenSStates(activeTextureUnit.getValue()).enable();
|
||||
case GL11.GL_TEXTURE_GEN_T -> textures.getTexGenTStates(activeTextureUnit.getValue()).enable();
|
||||
case GL11.GL_TEXTURE_GEN_R -> textures.getTexGenRStates(activeTextureUnit.getValue()).enable();
|
||||
case GL11.GL_TEXTURE_GEN_Q -> textures.getTexGenQStates(activeTextureUnit.getValue()).enable();
|
||||
default -> GL11.glEnable(cap);
|
||||
}
|
||||
}
|
||||
|
||||
public static void glDisable(int cap) {
|
||||
// Handle clip planes dynamically (supports up to MAX_CLIP_PLANES)
|
||||
if (cap >= GL11.GL_CLIP_PLANE0 && cap < GL11.GL_CLIP_PLANE0 + MAX_CLIP_PLANES) {
|
||||
clipPlaneStates[cap - GL11.GL_CLIP_PLANE0].disable();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cap) {
|
||||
case GL11.GL_ALPHA_TEST -> disableAlphaTest();
|
||||
case GL11.GL_AUTO_NORMAL -> autoNormalState.disable();
|
||||
case GL11.GL_BLEND -> disableBlend();
|
||||
case GL11.GL_COLOR_MATERIAL -> disableColorMaterial();
|
||||
case GL11.GL_COLOR_LOGIC_OP -> colorLogicOpState.disable();
|
||||
case GL11.GL_CULL_FACE -> disableCull();
|
||||
case GL11.GL_DEPTH_TEST -> disableDepthTest();
|
||||
case GL11.GL_DITHER -> ditherState.disable();
|
||||
case GL11.GL_FOG -> disableFog();
|
||||
case GL11.GL_INDEX_LOGIC_OP -> indexLogicOpState.disable();
|
||||
case GL11.GL_LIGHTING -> disableLighting();
|
||||
case GL11.GL_LIGHT0 -> disableLight(0);
|
||||
case GL11.GL_LIGHT1 -> disableLight(1);
|
||||
@@ -312,10 +460,47 @@ public class GLStateManager {
|
||||
case GL11.GL_LIGHT5 -> disableLight(5);
|
||||
case GL11.GL_LIGHT6 -> disableLight(6);
|
||||
case GL11.GL_LIGHT7 -> disableLight(7);
|
||||
case GL11.GL_COLOR_MATERIAL -> disableColorMaterial();
|
||||
case GL11.GL_SCISSOR_TEST -> disableScissorTest();
|
||||
case GL11.GL_TEXTURE_2D -> disableTexture();
|
||||
case GL11.GL_LINE_SMOOTH -> lineSmoothState.disable();
|
||||
case GL11.GL_LINE_STIPPLE -> lineStippleState.disable();
|
||||
case GL11.GL_MAP1_COLOR_4 -> map1Color4State.disable();
|
||||
case GL11.GL_MAP1_INDEX -> map1IndexState.disable();
|
||||
case GL11.GL_MAP1_NORMAL -> map1NormalState.disable();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_1 -> map1TextureCoord1State.disable();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_2 -> map1TextureCoord2State.disable();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_3 -> map1TextureCoord3State.disable();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_4 -> map1TextureCoord4State.disable();
|
||||
case GL11.GL_MAP1_VERTEX_3 -> map1Vertex3State.disable();
|
||||
case GL11.GL_MAP1_VERTEX_4 -> map1Vertex4State.disable();
|
||||
case GL11.GL_MAP2_COLOR_4 -> map2Color4State.disable();
|
||||
case GL11.GL_MAP2_INDEX -> map2IndexState.disable();
|
||||
case GL11.GL_MAP2_NORMAL -> map2NormalState.disable();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_1 -> map2TextureCoord1State.disable();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_2 -> map2TextureCoord2State.disable();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_3 -> map2TextureCoord3State.disable();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_4 -> map2TextureCoord4State.disable();
|
||||
case GL11.GL_MAP2_VERTEX_3 -> map2Vertex3State.disable();
|
||||
case GL11.GL_MAP2_VERTEX_4 -> map2Vertex4State.disable();
|
||||
case GL13.GL_MULTISAMPLE -> multisampleState.disable();
|
||||
case GL11.GL_NORMALIZE -> normalizeState.disable();
|
||||
case GL11.GL_POINT_SMOOTH -> pointSmoothState.disable();
|
||||
case GL11.GL_POLYGON_OFFSET_POINT -> polygonOffsetPointState.disable();
|
||||
case GL11.GL_POLYGON_OFFSET_LINE -> polygonOffsetLineState.disable();
|
||||
case GL11.GL_POLYGON_OFFSET_FILL -> polygonOffsetFillState.disable();
|
||||
case GL11.GL_POLYGON_SMOOTH -> polygonSmoothState.disable();
|
||||
case GL11.GL_POLYGON_STIPPLE -> polygonStippleState.disable();
|
||||
case GL12.GL_RESCALE_NORMAL -> disableRescaleNormal();
|
||||
case GL13.GL_SAMPLE_ALPHA_TO_COVERAGE -> sampleAlphaToCoverageState.disable();
|
||||
case GL13.GL_SAMPLE_ALPHA_TO_ONE -> sampleAlphaToOneState.disable();
|
||||
case GL13.GL_SAMPLE_COVERAGE -> sampleCoverageState.disable();
|
||||
case GL11.GL_SCISSOR_TEST -> disableScissorTest();
|
||||
case GL11.GL_STENCIL_TEST -> stencilTest.disable();
|
||||
case GL11.GL_TEXTURE_1D -> textures.getTexture1DStates(activeTextureUnit.getValue()).disable();
|
||||
case GL11.GL_TEXTURE_2D -> disableTexture();
|
||||
case GL12.GL_TEXTURE_3D -> textures.getTexture3DStates(activeTextureUnit.getValue()).disable();
|
||||
case GL11.GL_TEXTURE_GEN_S -> textures.getTexGenSStates(activeTextureUnit.getValue()).disable();
|
||||
case GL11.GL_TEXTURE_GEN_T -> textures.getTexGenTStates(activeTextureUnit.getValue()).disable();
|
||||
case GL11.GL_TEXTURE_GEN_R -> textures.getTexGenRStates(activeTextureUnit.getValue()).disable();
|
||||
case GL11.GL_TEXTURE_GEN_Q -> textures.getTexGenQStates(activeTextureUnit.getValue()).disable();
|
||||
default -> GL11.glDisable(cap);
|
||||
}
|
||||
}
|
||||
@@ -324,12 +509,22 @@ public class GLStateManager {
|
||||
if(shouldBypassCache()) {
|
||||
return GL11.glIsEnabled(cap);
|
||||
}
|
||||
// Handle clip planes dynamically (supports up to MAX_CLIP_PLANES)
|
||||
if (cap >= GL11.GL_CLIP_PLANE0 && cap < GL11.GL_CLIP_PLANE0 + MAX_CLIP_PLANES) {
|
||||
return clipPlaneStates[cap - GL11.GL_CLIP_PLANE0].isEnabled();
|
||||
}
|
||||
|
||||
return switch (cap) {
|
||||
case GL11.GL_ALPHA_TEST -> alphaTest.isEnabled();
|
||||
case GL11.GL_AUTO_NORMAL -> autoNormalState.isEnabled();
|
||||
case GL11.GL_BLEND -> blendMode.isEnabled();
|
||||
case GL11.GL_COLOR_MATERIAL -> colorMaterial.isEnabled();
|
||||
case GL11.GL_COLOR_LOGIC_OP -> colorLogicOpState.isEnabled();
|
||||
case GL11.GL_CULL_FACE -> cullState.isEnabled();
|
||||
case GL11.GL_DEPTH_TEST -> depthTest.isEnabled();
|
||||
case GL11.GL_DITHER -> ditherState.isEnabled();
|
||||
case GL11.GL_FOG -> fogMode.isEnabled();
|
||||
case GL11.GL_INDEX_LOGIC_OP -> indexLogicOpState.isEnabled();
|
||||
case GL11.GL_LIGHTING -> lightingState.isEnabled();
|
||||
case GL11.GL_LIGHT0 -> lightStates[0].isEnabled();
|
||||
case GL11.GL_LIGHT1 -> lightStates[1].isEnabled();
|
||||
@@ -339,10 +534,47 @@ public class GLStateManager {
|
||||
case GL11.GL_LIGHT5 -> lightStates[5].isEnabled();
|
||||
case GL11.GL_LIGHT6 -> lightStates[6].isEnabled();
|
||||
case GL11.GL_LIGHT7 -> lightStates[7].isEnabled();
|
||||
case GL11.GL_COLOR_MATERIAL -> colorMaterial.isEnabled();
|
||||
case GL11.GL_SCISSOR_TEST -> scissorTest.isEnabled();
|
||||
case GL11.GL_TEXTURE_2D -> textures.getTextureUnitStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL11.GL_LINE_SMOOTH -> lineSmoothState.isEnabled();
|
||||
case GL11.GL_LINE_STIPPLE -> lineStippleState.isEnabled();
|
||||
case GL11.GL_MAP1_COLOR_4 -> map1Color4State.isEnabled();
|
||||
case GL11.GL_MAP1_INDEX -> map1IndexState.isEnabled();
|
||||
case GL11.GL_MAP1_NORMAL -> map1NormalState.isEnabled();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_1 -> map1TextureCoord1State.isEnabled();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_2 -> map1TextureCoord2State.isEnabled();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_3 -> map1TextureCoord3State.isEnabled();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_4 -> map1TextureCoord4State.isEnabled();
|
||||
case GL11.GL_MAP1_VERTEX_3 -> map1Vertex3State.isEnabled();
|
||||
case GL11.GL_MAP1_VERTEX_4 -> map1Vertex4State.isEnabled();
|
||||
case GL11.GL_MAP2_COLOR_4 -> map2Color4State.isEnabled();
|
||||
case GL11.GL_MAP2_INDEX -> map2IndexState.isEnabled();
|
||||
case GL11.GL_MAP2_NORMAL -> map2NormalState.isEnabled();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_1 -> map2TextureCoord1State.isEnabled();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_2 -> map2TextureCoord2State.isEnabled();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_3 -> map2TextureCoord3State.isEnabled();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_4 -> map2TextureCoord4State.isEnabled();
|
||||
case GL11.GL_MAP2_VERTEX_3 -> map2Vertex3State.isEnabled();
|
||||
case GL11.GL_MAP2_VERTEX_4 -> map2Vertex4State.isEnabled();
|
||||
case GL13.GL_MULTISAMPLE -> multisampleState.isEnabled();
|
||||
case GL11.GL_NORMALIZE -> normalizeState.isEnabled();
|
||||
case GL11.GL_POINT_SMOOTH -> pointSmoothState.isEnabled();
|
||||
case GL11.GL_POLYGON_OFFSET_POINT -> polygonOffsetPointState.isEnabled();
|
||||
case GL11.GL_POLYGON_OFFSET_LINE -> polygonOffsetLineState.isEnabled();
|
||||
case GL11.GL_POLYGON_OFFSET_FILL -> polygonOffsetFillState.isEnabled();
|
||||
case GL11.GL_POLYGON_SMOOTH -> polygonSmoothState.isEnabled();
|
||||
case GL11.GL_POLYGON_STIPPLE -> polygonStippleState.isEnabled();
|
||||
case GL12.GL_RESCALE_NORMAL -> rescaleNormalState.isEnabled();
|
||||
case GL13.GL_SAMPLE_ALPHA_TO_COVERAGE -> sampleAlphaToCoverageState.isEnabled();
|
||||
case GL13.GL_SAMPLE_ALPHA_TO_ONE -> sampleAlphaToOneState.isEnabled();
|
||||
case GL13.GL_SAMPLE_COVERAGE -> sampleCoverageState.isEnabled();
|
||||
case GL11.GL_SCISSOR_TEST -> scissorTest.isEnabled();
|
||||
case GL11.GL_STENCIL_TEST -> stencilTest.isEnabled();
|
||||
case GL11.GL_TEXTURE_1D -> textures.getTexture1DStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL11.GL_TEXTURE_2D -> textures.getTextureUnitStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL12.GL_TEXTURE_3D -> textures.getTexture3DStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL11.GL_TEXTURE_GEN_S -> textures.getTexGenSStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL11.GL_TEXTURE_GEN_T -> textures.getTexGenTStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL11.GL_TEXTURE_GEN_R -> textures.getTexGenRStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL11.GL_TEXTURE_GEN_Q -> textures.getTexGenQStates(activeTextureUnit.getValue()).isEnabled();
|
||||
default -> GL11.glIsEnabled(cap);
|
||||
};
|
||||
}
|
||||
@@ -351,13 +583,23 @@ public class GLStateManager {
|
||||
if(shouldBypassCache()) {
|
||||
return GL11.glGetBoolean(pname);
|
||||
}
|
||||
// Handle clip planes dynamically (supports up to MAX_CLIP_PLANES)
|
||||
if (pname >= GL11.GL_CLIP_PLANE0 && pname < GL11.GL_CLIP_PLANE0 + MAX_CLIP_PLANES) {
|
||||
return clipPlaneStates[pname - GL11.GL_CLIP_PLANE0].isEnabled();
|
||||
}
|
||||
|
||||
return switch (pname) {
|
||||
case GL11.GL_ALPHA_TEST -> alphaTest.isEnabled();
|
||||
case GL11.GL_AUTO_NORMAL -> autoNormalState.isEnabled();
|
||||
case GL11.GL_BLEND -> blendMode.isEnabled();
|
||||
case GL11.GL_COLOR_MATERIAL -> colorMaterial.isEnabled();
|
||||
case GL11.GL_COLOR_LOGIC_OP -> colorLogicOpState.isEnabled();
|
||||
case GL11.GL_CULL_FACE -> cullState.isEnabled();
|
||||
case GL11.GL_DEPTH_TEST -> depthTest.isEnabled();
|
||||
case GL11.GL_DEPTH_WRITEMASK -> depthState.isEnabled();
|
||||
case GL11.GL_DITHER -> ditherState.isEnabled();
|
||||
case GL11.GL_FOG -> fogMode.isEnabled();
|
||||
case GL11.GL_INDEX_LOGIC_OP -> indexLogicOpState.isEnabled();
|
||||
case GL11.GL_LIGHTING -> lightingState.isEnabled();
|
||||
case GL11.GL_LIGHT0 -> lightStates[0].isEnabled();
|
||||
case GL11.GL_LIGHT1 -> lightStates[1].isEnabled();
|
||||
@@ -367,10 +609,47 @@ public class GLStateManager {
|
||||
case GL11.GL_LIGHT5 -> lightStates[5].isEnabled();
|
||||
case GL11.GL_LIGHT6 -> lightStates[6].isEnabled();
|
||||
case GL11.GL_LIGHT7 -> lightStates[7].isEnabled();
|
||||
case GL11.GL_COLOR_MATERIAL -> colorMaterial.isEnabled();
|
||||
case GL11.GL_SCISSOR_TEST -> scissorTest.isEnabled();
|
||||
case GL11.GL_TEXTURE_2D -> textures.getTextureUnitStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL11.GL_LINE_SMOOTH -> lineSmoothState.isEnabled();
|
||||
case GL11.GL_LINE_STIPPLE -> lineStippleState.isEnabled();
|
||||
case GL11.GL_MAP1_COLOR_4 -> map1Color4State.isEnabled();
|
||||
case GL11.GL_MAP1_INDEX -> map1IndexState.isEnabled();
|
||||
case GL11.GL_MAP1_NORMAL -> map1NormalState.isEnabled();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_1 -> map1TextureCoord1State.isEnabled();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_2 -> map1TextureCoord2State.isEnabled();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_3 -> map1TextureCoord3State.isEnabled();
|
||||
case GL11.GL_MAP1_TEXTURE_COORD_4 -> map1TextureCoord4State.isEnabled();
|
||||
case GL11.GL_MAP1_VERTEX_3 -> map1Vertex3State.isEnabled();
|
||||
case GL11.GL_MAP1_VERTEX_4 -> map1Vertex4State.isEnabled();
|
||||
case GL11.GL_MAP2_COLOR_4 -> map2Color4State.isEnabled();
|
||||
case GL11.GL_MAP2_INDEX -> map2IndexState.isEnabled();
|
||||
case GL11.GL_MAP2_NORMAL -> map2NormalState.isEnabled();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_1 -> map2TextureCoord1State.isEnabled();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_2 -> map2TextureCoord2State.isEnabled();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_3 -> map2TextureCoord3State.isEnabled();
|
||||
case GL11.GL_MAP2_TEXTURE_COORD_4 -> map2TextureCoord4State.isEnabled();
|
||||
case GL11.GL_MAP2_VERTEX_3 -> map2Vertex3State.isEnabled();
|
||||
case GL11.GL_MAP2_VERTEX_4 -> map2Vertex4State.isEnabled();
|
||||
case GL13.GL_MULTISAMPLE -> multisampleState.isEnabled();
|
||||
case GL11.GL_NORMALIZE -> normalizeState.isEnabled();
|
||||
case GL11.GL_POINT_SMOOTH -> pointSmoothState.isEnabled();
|
||||
case GL11.GL_POLYGON_OFFSET_POINT -> polygonOffsetPointState.isEnabled();
|
||||
case GL11.GL_POLYGON_OFFSET_LINE -> polygonOffsetLineState.isEnabled();
|
||||
case GL11.GL_POLYGON_OFFSET_FILL -> polygonOffsetFillState.isEnabled();
|
||||
case GL11.GL_POLYGON_SMOOTH -> polygonSmoothState.isEnabled();
|
||||
case GL11.GL_POLYGON_STIPPLE -> polygonStippleState.isEnabled();
|
||||
case GL12.GL_RESCALE_NORMAL -> rescaleNormalState.isEnabled();
|
||||
case GL13.GL_SAMPLE_ALPHA_TO_COVERAGE -> sampleAlphaToCoverageState.isEnabled();
|
||||
case GL13.GL_SAMPLE_ALPHA_TO_ONE -> sampleAlphaToOneState.isEnabled();
|
||||
case GL13.GL_SAMPLE_COVERAGE -> sampleCoverageState.isEnabled();
|
||||
case GL11.GL_SCISSOR_TEST -> scissorTest.isEnabled();
|
||||
case GL11.GL_STENCIL_TEST -> stencilTest.isEnabled();
|
||||
case GL11.GL_TEXTURE_1D -> textures.getTexture1DStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL11.GL_TEXTURE_2D -> textures.getTextureUnitStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL12.GL_TEXTURE_3D -> textures.getTexture3DStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL11.GL_TEXTURE_GEN_S -> textures.getTexGenSStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL11.GL_TEXTURE_GEN_T -> textures.getTexGenTStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL11.GL_TEXTURE_GEN_R -> textures.getTexGenRStates(activeTextureUnit.getValue()).isEnabled();
|
||||
case GL11.GL_TEXTURE_GEN_Q -> textures.getTexGenQStates(activeTextureUnit.getValue()).isEnabled();
|
||||
default -> GL11.glGetBoolean(pname);
|
||||
};
|
||||
}
|
||||
@@ -398,6 +677,11 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static int getMatrixStackDepth(Matrix4fStack stack) {
|
||||
return (int) MAT4_STACK_CURR_DEPTH.invokeExact(stack);
|
||||
}
|
||||
|
||||
public static int glGetInteger(int pname) {
|
||||
if(shouldBypassCache()) {
|
||||
return GL11.glGetInteger(pname);
|
||||
@@ -417,6 +701,8 @@ public class GLStateManager {
|
||||
case GL11.GL_COLOR_MATERIAL_FACE -> colorMaterialFace.getValue();
|
||||
case GL11.GL_COLOR_MATERIAL_PARAMETER -> colorMaterialParameter.getValue();
|
||||
case GL20.GL_CURRENT_PROGRAM -> activeProgram;
|
||||
case GL11.GL_MODELVIEW_STACK_DEPTH -> getMatrixStackDepth(modelViewMatrix);
|
||||
case GL11.GL_PROJECTION_STACK_DEPTH -> getMatrixStackDepth(projectionMatrix);
|
||||
|
||||
default -> GL11.glGetInteger(pname);
|
||||
};
|
||||
@@ -829,6 +1115,16 @@ public class GLStateManager {
|
||||
GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
}
|
||||
|
||||
public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, FloatBuffer pixels) {
|
||||
TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
}
|
||||
|
||||
public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, DoubleBuffer pixels) {
|
||||
TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
}
|
||||
|
||||
public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, ByteBuffer pixels) {
|
||||
TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels != null ? pixels.asIntBuffer() : (IntBuffer) null);
|
||||
GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
@@ -953,39 +1249,59 @@ public class GLStateManager {
|
||||
i = mipmap ? GL11.GL_LINEAR_MIPMAP_LINEAR : GL11.GL_LINEAR;
|
||||
j = GL11.GL_LINEAR;
|
||||
} else {
|
||||
i = mipmap ? GL11.GL_NEAREST_MIPMAP_LINEAR : GL11.GL_NEAREST;
|
||||
i = mipmap ? GL11.GL_LINEAR_MIPMAP_LINEAR : GL11.GL_NEAREST;
|
||||
j = GL11.GL_NEAREST;
|
||||
}
|
||||
glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, i);
|
||||
glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, j);
|
||||
}
|
||||
|
||||
public static void glDrawArrays(int mode, int first, int count) {
|
||||
// Iris -- TODO: This doesn't seem to work and is related to matchPass()
|
||||
if(AngelicaConfig.enableIris) {
|
||||
Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram);
|
||||
}
|
||||
GL11.glDrawArrays(mode, first, count);
|
||||
}
|
||||
|
||||
public static void glDrawBuffer(int mode) {
|
||||
GL11.glDrawBuffer(mode);
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, IntBuffer indices) {
|
||||
if(AngelicaConfig.enableIris) {
|
||||
Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram);
|
||||
}
|
||||
GL11.glDrawElements(mode, indices);
|
||||
}
|
||||
|
||||
public static void glBegin(int mode) {
|
||||
public static void trySyncProgram() {
|
||||
if (AngelicaConfig.enableIris) {
|
||||
Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram);
|
||||
}
|
||||
}
|
||||
|
||||
public static void glBegin(int mode) {
|
||||
trySyncProgram();
|
||||
GL11.glBegin(mode);
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, ByteBuffer indices) {
|
||||
trySyncProgram();
|
||||
GL11.glDrawElements(mode, indices);
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, IntBuffer indices) {
|
||||
trySyncProgram();
|
||||
GL11.glDrawElements(mode, indices);
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, ShortBuffer indices) {
|
||||
trySyncProgram();
|
||||
GL11.glDrawElements(mode, indices);
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, int indices_count, int type, long indices_buffer_offset) {
|
||||
trySyncProgram();
|
||||
GL11.glDrawElements(mode, indices_count, type, indices_buffer_offset);
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, int count, int type, ByteBuffer indices) {
|
||||
trySyncProgram();
|
||||
GL11.glDrawElements(mode, count, type, indices);
|
||||
}
|
||||
|
||||
public static void glDrawBuffer(int mode) {
|
||||
trySyncProgram();
|
||||
GL11.glDrawBuffer(mode);
|
||||
}
|
||||
|
||||
public static void glDrawArrays(int mode, int first, int count) {
|
||||
trySyncProgram();
|
||||
GL11.glDrawArrays(mode, first, count);
|
||||
}
|
||||
|
||||
public static void glLogicOp(int opcode) {
|
||||
GL11.glLogicOp(opcode);
|
||||
}
|
||||
@@ -1191,13 +1507,21 @@ public class GLStateManager {
|
||||
glListNesting += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
glListId = list;
|
||||
glListMode = mode;
|
||||
GL11.glNewList(list, mode);
|
||||
for(IStateStack<?> stack : Feature.maskToFeatures(GL11.GL_ALL_ATTRIB_BITS)) {
|
||||
|
||||
List<IStateStack<?>> stacks = Feature.maskToFeatures(GL11.GL_ALL_ATTRIB_BITS);
|
||||
int size = stacks.size();
|
||||
|
||||
for(int i = 0; i < size; i++) {
|
||||
IStateStack<?> stack = stacks.get(i);
|
||||
|
||||
// Feature Stack, copy of current feature state
|
||||
glListStates.put(stack, (ISettableState<?>) ((ISettableState<?>)stack).copy());
|
||||
}
|
||||
|
||||
if(glListMode == GL11.GL_COMPILE) {
|
||||
pushState(GL11.GL_ALL_ATTRIB_BITS);
|
||||
}
|
||||
@@ -1240,6 +1564,7 @@ public class GLStateManager {
|
||||
if(list < 0) {
|
||||
VBOManager.get(list).render();
|
||||
} else {
|
||||
trySyncProgram();
|
||||
GL11.glCallList(list);
|
||||
if(glListChanges.containsKey(list)) {
|
||||
for(Map.Entry<IStateStack<?>, ISettableState<?>> entry : glListChanges.get(list)) {
|
||||
@@ -1252,15 +1577,23 @@ public class GLStateManager {
|
||||
|
||||
public static void pushState(int mask) {
|
||||
attribs.push(mask);
|
||||
for(IStateStack<?> stack : Feature.maskToFeatures(mask)) {
|
||||
stack.push();
|
||||
}
|
||||
|
||||
List<IStateStack<?>> stacks = Feature.maskToFeatures(mask);
|
||||
int size = stacks.size();
|
||||
|
||||
for(int i = 0; i < size; i++) {
|
||||
stacks.get(i).push();
|
||||
}
|
||||
}
|
||||
|
||||
public static void popState() {
|
||||
final int mask = attribs.popInt();
|
||||
for(IStateStack<?> stack : Feature.maskToFeatures(mask)) {
|
||||
stack.pop();
|
||||
|
||||
List<IStateStack<?>> stacks = Feature.maskToFeatures(mask);
|
||||
int size = stacks.size();
|
||||
|
||||
for(int i = 0; i < size; i++) {
|
||||
stacks.get(i).pop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1804,6 +2137,20 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean vendorIsAMD() {
|
||||
return VENDOR == AMD;
|
||||
}
|
||||
|
||||
public static boolean vendorIsIntel() {
|
||||
return VENDOR == INTEL;
|
||||
}
|
||||
|
||||
public static boolean vendorIsMesa() {
|
||||
return VENDOR == MESA;
|
||||
}
|
||||
|
||||
public static boolean vendorIsNVIDIA() {
|
||||
return VENDOR == NVIDIA;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,7 +30,6 @@ import java.nio.IntBuffer;
|
||||
public class RenderSystem {
|
||||
private static final Logger LOGGER = LogManager.getLogger("RenderSystem");
|
||||
private static DSAAccess dsaState;
|
||||
private static boolean hasMultibind;
|
||||
private static boolean supportsCompute;
|
||||
|
||||
private RenderSystem() {}
|
||||
@@ -41,7 +40,6 @@ public class RenderSystem {
|
||||
dsaState = new DSACore();
|
||||
LOGGER.info("OpenGL 4.5 detected, enabling DSA.");
|
||||
}
|
||||
hasMultibind = GLStateManager.capabilities.OpenGL45;
|
||||
|
||||
} catch (NoSuchFieldError ignored) {}
|
||||
try {
|
||||
@@ -55,10 +53,6 @@ public class RenderSystem {
|
||||
LOGGER.info("No DSA support detected, falling back to legacy OpenGL.");
|
||||
}
|
||||
|
||||
try {
|
||||
hasMultibind |= GLStateManager.capabilities.GL_ARB_multi_bind;
|
||||
} catch (NoSuchFieldError ignored) {}
|
||||
|
||||
supportsCompute = supportsCompute();
|
||||
}
|
||||
|
||||
@@ -103,6 +97,8 @@ public class RenderSystem {
|
||||
GL20.glUniform3f(location, v0, v1, v2);
|
||||
}
|
||||
|
||||
public static void uniform3i(int location, int v0, int v1, int v2) { GL20.glUniform3i(location, v0, v1, v2); }
|
||||
|
||||
public static void uniform4f(int location, float v0, float v1, float v2, float v3) {
|
||||
GL20.glUniform4f(location, v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
/// Matches
|
||||
public enum Vendor {
|
||||
AMD("amd"),
|
||||
INTEL("intel"),
|
||||
MESA("mesa"),
|
||||
NVIDIA("nvidia"),
|
||||
UNKNOWN("");
|
||||
|
||||
final String[] names;
|
||||
|
||||
Vendor(String... names) {
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
public static Vendor getVendor(String vendorString) {
|
||||
for (var v : values()) {
|
||||
for (var name : v.names) {
|
||||
if (vendorString.contains(name)) return v;
|
||||
}
|
||||
}
|
||||
|
||||
// Shouldn't be needed as "" matches everything, but sanity checks good.
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,20 @@ public class BooleanStateStack extends BooleanState implements IStateStack<Boole
|
||||
protected int pointer;
|
||||
|
||||
public BooleanStateStack(int glCap) {
|
||||
// Most booleans default to false
|
||||
this(glCap, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a BooleanStateStack with a custom initial state.
|
||||
* Useful for GL states that default to true (e.g., GL_DITHER, GL_MULTISAMPLE).
|
||||
*
|
||||
* @param glCap GL capability constant
|
||||
* @param initialState initial enabled state
|
||||
*/
|
||||
public BooleanStateStack(int glCap, boolean initialState) {
|
||||
super(glCap);
|
||||
this.enabled = initialState;
|
||||
stack = new BooleanState[GLStateManager.MAX_ATTRIB_STACK_DEPTH];
|
||||
for (int i = 0; i < GLStateManager.MAX_ATTRIB_STACK_DEPTH; i++) {
|
||||
stack[i] = new BooleanState(glCap);
|
||||
@@ -34,7 +47,7 @@ public class BooleanStateStack extends BooleanState implements IStateStack<Boole
|
||||
}
|
||||
|
||||
set(stack[--pointer]);
|
||||
if (GLStateManager.isAMD() && glCap == GL11.GL_BLEND) {
|
||||
if (GLStateManager.vendorIsAMD() && glCap == GL11.GL_BLEND) {
|
||||
setEnabled(enabled);
|
||||
}
|
||||
return this;
|
||||
|
||||
@@ -22,7 +22,7 @@ public class BooleanState implements ISettableState<BooleanState> {
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (GLStateManager.shouldBypassCache() || enabled != this.enabled || (this.glCap == GL11.GL_BLEND && GLStateManager.isAMD() && GLStateManager.isPoppingAttributes())) {
|
||||
if (GLStateManager.shouldBypassCache() || enabled != this.enabled || (this.glCap == GL11.GL_BLEND && GLStateManager.vendorIsAMD() && GLStateManager.isPoppingAttributes())) {
|
||||
this.enabled = enabled;
|
||||
if (enabled) {
|
||||
GL11.glEnable(this.glCap);
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.gtnewhorizons.angelica.glsm.states;
|
||||
|
||||
public interface ISettableState<T> extends Cloneable {
|
||||
T set(T state);
|
||||
@SuppressWarnings("unchecked")
|
||||
default void set(ISettableState<?> value) {
|
||||
set((T) value);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ public class LightState implements ISettableState<LightState> {
|
||||
private static final Vector4i vector4i = new Vector4i();
|
||||
private static final Vector4f vector4f = new Vector4f();
|
||||
private static final Vector3i vector3i = new Vector3i();
|
||||
private static final Vector3f vector3f = new Vector3f();
|
||||
private static final Matrix3f matrix3f = new Matrix3f();
|
||||
|
||||
public int light;
|
||||
|
||||
@@ -124,7 +124,7 @@ public class MaterialState implements ISettableState<MaterialState> {
|
||||
// glMaterial specifically for GL_COLOR_INDEXES. Other drivers do not do this.
|
||||
// This probably breaks things but who knows, GLSM is setup to track to what the
|
||||
// driver is doing for it right now.
|
||||
if (GLStateManager.isNVIDIA()) {
|
||||
if (GLStateManager.vendorIsNVIDIA()) {
|
||||
vector3f.set(newBuffer.get(0), newBuffer.get(2), newBuffer.get(1));
|
||||
} else {
|
||||
vector3f.set(newBuffer);
|
||||
|
||||
@@ -6,21 +6,40 @@ import com.gtnewhorizons.angelica.glsm.stacks.TextureBindingStack;
|
||||
import lombok.Getter;
|
||||
import org.joml.Matrix4fStack;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
|
||||
public class TextureUnitArray {
|
||||
private final TextureBindingStack[] bindings;
|
||||
private final BooleanStateStack[] states;
|
||||
private final BooleanStateStack[] texture1DStates;
|
||||
private final BooleanStateStack[] texture3DStates;
|
||||
private final BooleanStateStack[] texGenSStates;
|
||||
private final BooleanStateStack[] texGenTStates;
|
||||
private final BooleanStateStack[] texGenRStates;
|
||||
private final BooleanStateStack[] texGenQStates;
|
||||
@Getter
|
||||
public final Matrix4fStack[] textureMatricies;
|
||||
|
||||
public TextureUnitArray() {
|
||||
bindings = new TextureBindingStack[GLStateManager.MAX_TEXTURE_UNITS];
|
||||
states = new BooleanStateStack[GLStateManager.MAX_TEXTURE_UNITS];
|
||||
texture1DStates = new BooleanStateStack[GLStateManager.MAX_TEXTURE_UNITS];
|
||||
texture3DStates = new BooleanStateStack[GLStateManager.MAX_TEXTURE_UNITS];
|
||||
texGenSStates = new BooleanStateStack[GLStateManager.MAX_TEXTURE_UNITS];
|
||||
texGenTStates = new BooleanStateStack[GLStateManager.MAX_TEXTURE_UNITS];
|
||||
texGenRStates = new BooleanStateStack[GLStateManager.MAX_TEXTURE_UNITS];
|
||||
texGenQStates = new BooleanStateStack[GLStateManager.MAX_TEXTURE_UNITS];
|
||||
textureMatricies = new Matrix4fStack[GLStateManager.MAX_TEXTURE_UNITS];
|
||||
|
||||
for (int i = 0; i < GLStateManager.MAX_TEXTURE_UNITS; i++) {
|
||||
bindings[i] = new TextureBindingStack();
|
||||
states[i] = new BooleanStateStack(GL11.GL_TEXTURE_2D);
|
||||
texture1DStates[i] = new BooleanStateStack(GL11.GL_TEXTURE_1D);
|
||||
texture3DStates[i] = new BooleanStateStack(GL12.GL_TEXTURE_3D);
|
||||
texGenSStates[i] = new BooleanStateStack(GL11.GL_TEXTURE_GEN_S);
|
||||
texGenTStates[i] = new BooleanStateStack(GL11.GL_TEXTURE_GEN_T);
|
||||
texGenRStates[i] = new BooleanStateStack(GL11.GL_TEXTURE_GEN_R);
|
||||
texGenQStates[i] = new BooleanStateStack(GL11.GL_TEXTURE_GEN_Q);
|
||||
textureMatricies[i] = new Matrix4fStack(GLStateManager.MAX_TEXTURE_STACK_DEPTH);
|
||||
}
|
||||
}
|
||||
@@ -33,6 +52,30 @@ public class TextureUnitArray {
|
||||
return states[index];
|
||||
}
|
||||
|
||||
public BooleanStateStack getTexture1DStates(int index) {
|
||||
return texture1DStates[index];
|
||||
}
|
||||
|
||||
public BooleanStateStack getTexture3DStates(int index) {
|
||||
return texture3DStates[index];
|
||||
}
|
||||
|
||||
public BooleanStateStack getTexGenSStates(int index) {
|
||||
return texGenSStates[index];
|
||||
}
|
||||
|
||||
public BooleanStateStack getTexGenTStates(int index) {
|
||||
return texGenTStates[index];
|
||||
}
|
||||
|
||||
public BooleanStateStack getTexGenRStates(int index) {
|
||||
return texGenRStates[index];
|
||||
}
|
||||
|
||||
public BooleanStateStack getTexGenQStates(int index) {
|
||||
return texGenQStates[index];
|
||||
}
|
||||
|
||||
public Matrix4fStack getTextureUnitMatrix(int index) {
|
||||
return textureMatricies[index];
|
||||
}
|
||||
@@ -44,6 +87,12 @@ public class TextureUnitArray {
|
||||
for (int i = 0; i < GLStateManager.MAX_TEXTURE_UNITS; i++) {
|
||||
if (!bindings[i].sameAs(textureUnitArray.bindings[i])) return false;
|
||||
if (!states[i].sameAs(textureUnitArray.states[i])) return false;
|
||||
if (!texture1DStates[i].sameAs(textureUnitArray.texture1DStates[i])) return false;
|
||||
if (!texture3DStates[i].sameAs(textureUnitArray.texture3DStates[i])) return false;
|
||||
if (!texGenSStates[i].sameAs(textureUnitArray.texGenSStates[i])) return false;
|
||||
if (!texGenTStates[i].sameAs(textureUnitArray.texGenTStates[i])) return false;
|
||||
if (!texGenRStates[i].sameAs(textureUnitArray.texGenRStates[i])) return false;
|
||||
if (!texGenQStates[i].sameAs(textureUnitArray.texGenQStates[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ public class TextureInfo {
|
||||
protected int width = -1;
|
||||
protected int height = -1;
|
||||
|
||||
@Getter @Setter protected int minFilter = GL11.GL_NEAREST_MIPMAP_LINEAR;
|
||||
@Getter @Setter protected int minFilter = GL11.GL_LINEAR_MIPMAP_LINEAR;
|
||||
@Getter @Setter protected int magFilter = GL11.GL_LINEAR;
|
||||
@Getter @Setter protected int wrapS = GL11.GL_REPEAT;
|
||||
@Getter @Setter protected int wrapT = GL11.GL_REPEAT;
|
||||
|
||||
@@ -6,7 +6,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.Buffer;
|
||||
|
||||
public class TextureInfoCache {
|
||||
/**
|
||||
@@ -25,7 +25,7 @@ public class TextureInfoCache {
|
||||
return cache.computeIfAbsent(id, TextureInfo::new);
|
||||
}
|
||||
|
||||
public void onTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable IntBuffer pixels) {
|
||||
public void onTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable Buffer pixels) {
|
||||
if (target == GL11.GL_TEXTURE_2D && level == 0) {
|
||||
final TextureInfo info = getInfo(GLStateManager.getBoundTexture());
|
||||
if(info == null) return;
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
package com.gtnewhorizons.angelica.hudcaching;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.TessellatorManager;
|
||||
import com.gtnewhorizons.angelica.compat.ModStatus;
|
||||
import com.gtnewhorizons.angelica.compat.holoinventory.HoloInventoryReflectionCompat;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.GuiIngameAccessor;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.GuiIngameForgeAccessor;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.RenderGameOverlayEventAccessor;
|
||||
import com.kentington.thaumichorizons.common.ThaumicHorizons;
|
||||
import cpw.mods.fml.common.eventhandler.EventPriority;
|
||||
import net.dries007.holoInventory.client.Renderer;
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -34,7 +31,7 @@ import xaero.common.core.XaeroMinimapCore;
|
||||
|
||||
import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.LOGGER;
|
||||
|
||||
// See LICENSE+HUDCaching.md for license information.
|
||||
// See LICENSE-HUDCaching.md for license information.
|
||||
|
||||
public class HUDCaching {
|
||||
|
||||
@@ -59,11 +56,10 @@ public class HUDCaching {
|
||||
public static boolean renderCrosshairsCaptured;
|
||||
|
||||
private final static RenderGameOverlayEvent fakeTextEvent = new RenderGameOverlayEvent.Text(new RenderGameOverlayEvent(0, null, 0, 0), null, null);
|
||||
private final static RenderGameOverlayEvent fakePreEvent = new RenderGameOverlayEvent.Pre(new RenderGameOverlayEvent(0, null, 0, 0), RenderGameOverlayEvent.ElementType.HELMET);
|
||||
private final static RenderGameOverlayEvent.Post fakePostEvent = new RenderGameOverlayEvent.Post(new RenderGameOverlayEvent(0, null, 0, 0), RenderGameOverlayEvent.ElementType.HELMET);
|
||||
|
||||
public static final HUDCaching INSTANCE = new HUDCaching();
|
||||
|
||||
|
||||
private HUDCaching() {}
|
||||
|
||||
// highest so it runs before the GLSM load event
|
||||
@@ -102,7 +98,7 @@ public class HUDCaching {
|
||||
renderingCacheOverride = false;
|
||||
mc.getFramebuffer().bindFramebuffer(false);
|
||||
} else {
|
||||
renderer.setupOverlayRendering();
|
||||
renderer.setupOverlayRendering();
|
||||
}
|
||||
|
||||
ScaledResolution resolution = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
|
||||
@@ -115,48 +111,50 @@ public class HUDCaching {
|
||||
|
||||
// render bits that were captured when rendering into cache
|
||||
GuiIngameAccessor gui = (GuiIngameAccessor) ingame;
|
||||
if (renderVignetteCaptured)
|
||||
{
|
||||
if (renderVignetteCaptured) {
|
||||
gui.callRenderVignette(mc.thePlayer.getBrightness(partialTicks), width, height);
|
||||
} else {
|
||||
GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0);
|
||||
GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0);
|
||||
}
|
||||
|
||||
if (ingame instanceof GuiIngameForge) {
|
||||
GuiIngameForgeAccessor guiForge = ((GuiIngameForgeAccessor) ingame);
|
||||
if (renderHelmetCaptured) {
|
||||
guiForge.callRenderHelmet(resolution, partialTicks, hasScreen, mouseX, mouseY);
|
||||
if (ModStatus.isHoloInventoryLoaded){
|
||||
Renderer.INSTANCE.angelicaOverride = false;
|
||||
GuiIngameForgeAccessor guiForge = ((GuiIngameForgeAccessor) ingame);
|
||||
if (renderHelmetCaptured) {
|
||||
guiForge.callRenderHelmet(resolution, partialTicks, hasScreen, mouseX, mouseY);
|
||||
if (ModStatus.isHoloInventoryLoaded) {
|
||||
HoloInventoryReflectionCompat.setAngelicaOverride(false);
|
||||
// only settings the partial ticks as mouseX and mouseY are not used in renderEvent
|
||||
((RenderGameOverlayEventAccessor) fakePreEvent).setPartialTicks(partialTicks);
|
||||
Renderer.INSTANCE.renderEvent(fakePreEvent);
|
||||
((RenderGameOverlayEventAccessor) fakePostEvent).setPartialTicks(partialTicks);
|
||||
HoloInventoryReflectionCompat.renderEvent(fakePostEvent);
|
||||
}
|
||||
}
|
||||
if (renderPortalCapturedTicks > 0) {
|
||||
guiForge.callRenderPortal(width, height, partialTicks);
|
||||
}
|
||||
if (renderCrosshairsCaptured) {
|
||||
guiForge.callRenderCrosshairs(width, height);
|
||||
}
|
||||
if (ModStatus.isThaumcraftLoaded || ModStatus.isThaumicHorizonsLoaded){
|
||||
}
|
||||
if (renderPortalCapturedTicks > 0) {
|
||||
guiForge.callRenderPortal(width, height, partialTicks);
|
||||
}
|
||||
if (renderCrosshairsCaptured) {
|
||||
if (ModStatus.isXaerosMinimapLoaded) {
|
||||
// this fixes the crosshair going invisible when no lines are being drawn under the minimap
|
||||
GLStateManager.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
}
|
||||
guiForge.callRenderCrosshairs(width, height);
|
||||
}
|
||||
if (ModStatus.isThaumcraftLoaded || ModStatus.isThaumicHorizonsLoaded) {
|
||||
((RenderGameOverlayEventAccessor) fakeTextEvent).setPartialTicks(partialTicks);
|
||||
((RenderGameOverlayEventAccessor) fakeTextEvent).setResolution(resolution);
|
||||
((RenderGameOverlayEventAccessor) fakeTextEvent).setMouseX(mouseX);
|
||||
((RenderGameOverlayEventAccessor) fakeTextEvent).setMouseY(mouseY);
|
||||
if (ModStatus.isThaumcraftLoaded){
|
||||
if (ModStatus.isThaumcraftLoaded) {
|
||||
Thaumcraft.instance.renderEventHandler.renderOverlay(fakeTextEvent);
|
||||
}
|
||||
if (ModStatus.isThaumicHorizonsLoaded){
|
||||
if (ModStatus.isThaumicHorizonsLoaded) {
|
||||
ThaumicHorizons.instance.renderEventHandler.renderOverlay(fakeTextEvent);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (renderHelmetCaptured)
|
||||
{
|
||||
if (renderHelmetCaptured) {
|
||||
gui.callRenderPumpkinBlur(width, height);
|
||||
}
|
||||
if (renderPortalCapturedTicks > 0)
|
||||
{
|
||||
if (renderPortalCapturedTicks > 0) {
|
||||
gui.callRenderPortal(renderPortalCapturedTicks, width, height);
|
||||
}
|
||||
}
|
||||
@@ -179,19 +177,19 @@ public class HUDCaching {
|
||||
* the state before we start rendering
|
||||
*/
|
||||
public static void fixGLStateBeforeRenderingCache() {
|
||||
GLStateManager.glDepthMask(true);
|
||||
GLStateManager.enableDepthTest();
|
||||
GLStateManager.enableAlphaTest();
|
||||
GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
GLStateManager.disableBlend();
|
||||
GLStateManager.glDepthMask(true);
|
||||
GLStateManager.enableDepthTest();
|
||||
GLStateManager.enableAlphaTest();
|
||||
GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
GLStateManager.disableBlend();
|
||||
}
|
||||
|
||||
private static void resetFramebuffer(int width, int height) {
|
||||
if (framebuffer.framebufferWidth != width || framebuffer.framebufferHeight != height) {
|
||||
framebuffer.createBindFramebuffer(width, height);
|
||||
framebuffer.createBindFramebuffer(width, height);
|
||||
framebuffer.setFramebufferFilter(GL11.GL_NEAREST);
|
||||
} else {
|
||||
framebuffer.framebufferClear();
|
||||
framebuffer.framebufferClear();
|
||||
}
|
||||
// copy depth buffer from MC
|
||||
OpenGlHelper.func_153171_g(GL30.GL_READ_FRAMEBUFFER, mc.getFramebuffer().framebufferObject);
|
||||
@@ -213,10 +211,9 @@ public class HUDCaching {
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
}
|
||||
|
||||
// moved to here due to the method being called from a mixin
|
||||
public static void disableHoloInventory() {
|
||||
if (ModStatus.isHoloInventoryLoaded) {
|
||||
Renderer.INSTANCE.angelicaOverride = true;
|
||||
HoloInventoryReflectionCompat.setAngelicaOverride(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
package com.gtnewhorizons.angelica.loading;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.gtnewhorizon.gtnhlib.asm.ASMUtil;
|
||||
import com.gtnewhorizon.gtnhlib.config.ConfigException;
|
||||
import com.gtnewhorizon.gtnhlib.config.ConfigurationManager;
|
||||
import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader;
|
||||
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
|
||||
import com.gtnewhorizon.gtnhmixins.builders.ITransformers;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.config.CompatConfig;
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import com.gtnewhorizons.angelica.mixins.Mixins;
|
||||
import com.gtnewhorizons.angelica.mixins.TargetedMod;
|
||||
import com.gtnewhorizons.angelica.transform.compat.GenericCompatTransformer;
|
||||
import com.gtnewhorizons.angelica.transform.compat.handlers.CompatHandler;
|
||||
import com.gtnewhorizons.angelica.transform.compat.handlers.CompatHandlers;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.CompatHandlers;
|
||||
import cpw.mods.fml.relauncher.FMLLaunchHandler;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||
import jss.notfine.asm.AsmTransformers;
|
||||
import jss.notfine.asm.mappings.Namer;
|
||||
import jss.notfine.config.MCPatcherForgeConfig;
|
||||
import jss.notfine.config.NotFineConfig;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -26,7 +27,7 @@ import org.spongepowered.asm.launch.GlobalProperties;
|
||||
import org.spongepowered.asm.service.mojang.MixinServiceLaunchWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -42,21 +43,22 @@ import java.util.Set;
|
||||
//@IFMLLoadingPlugin.SortingIndex(Integer.MAX_VALUE - 5)
|
||||
@IFMLLoadingPlugin.MCVersion("1.7.10")
|
||||
@IFMLLoadingPlugin.TransformerExclusions({
|
||||
"com.gtnewhorizons.angelica.transform.RedirectorTransformer",
|
||||
"com.gtnewhorizons.angelica.glsm.GLStateManager"})
|
||||
"jss.notfine.asm",
|
||||
"com.gtnewhorizons.angelica.loading",
|
||||
"com.gtnewhorizons.angelica.glsm.GLStateManager"})
|
||||
public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader {
|
||||
|
||||
private static final boolean DUMP_CLASSES = Boolean.parseBoolean(System.getProperty("angelica.dumpClass", "false"));
|
||||
private static boolean OBF_ENV;
|
||||
private static Boolean OBF_ENV;
|
||||
public static final Logger LOGGER = LogManager.getLogger("Angelica");
|
||||
|
||||
private String[] transformerClasses;
|
||||
|
||||
static {
|
||||
public AngelicaTweaker() {
|
||||
try {
|
||||
// Angelica Config
|
||||
ConfigurationManager.registerConfig(AngelicaConfig.class);
|
||||
ConfigurationManager.registerConfig(CompatConfig.class);
|
||||
ConfigurationManager.registerConfig(FontConfig.class);
|
||||
MCPatcherForgeConfig.registerConfig();
|
||||
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
|
||||
final Configuration config = ctx.getConfiguration();
|
||||
@@ -67,39 +69,29 @@ public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader {
|
||||
ctx.updateLoggers();
|
||||
|
||||
// Debug features
|
||||
AngelicaConfig.enableTestBlocks = Boolean.parseBoolean(System.getProperty("angelica.enableTestBlocks", "false"));
|
||||
AngelicaConfig.enableTestBlocks = Boolean.getBoolean("angelica.enableTestBlocks");
|
||||
|
||||
} catch (ConfigException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
verifyDependencies();
|
||||
}
|
||||
|
||||
private static void verifyDependencies() {
|
||||
if (AngelicaTweaker.class.getResource("/it/unimi/dsi/fastutil/ints/Int2ObjectMap.class") == null) {
|
||||
throw new RuntimeException("Missing dependency: Angelica requires GTNHLib 0.2.1 or newer! Download: https://modrinth.com/mod/gtnhlib");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getASMTransformerClass() {
|
||||
// Directly add this to the MixinServiceLaunchWrapper tweaker's list of Tweak Classes
|
||||
final List<String> mixinTweakClasses = GlobalProperties.get(MixinServiceLaunchWrapper.BLACKBOARD_KEY_TWEAKCLASSES);
|
||||
if (mixinTweakClasses != null) {
|
||||
mixinTweakClasses.add(MixinCompatHackTweaker.class.getName());
|
||||
}
|
||||
if (transformerClasses == null) {
|
||||
final List<String> transformers = new ArrayList<>();
|
||||
|
||||
// Regsiter compat handlers, and add extra specific transformers, then build and register the generic transformer
|
||||
for (CompatHandler handler : CompatHandlers.getHandlers()) {
|
||||
GenericCompatTransformer.register(handler);
|
||||
if (handler.extraTransformers() != null) {
|
||||
transformers.addAll(handler.extraTransformers());
|
||||
}
|
||||
}
|
||||
|
||||
GenericCompatTransformer.build();
|
||||
transformers.add(GenericCompatTransformer.class.getName());
|
||||
|
||||
transformers.addAll(CompatHandlers.getTransformers());
|
||||
// Add NotFine transformers
|
||||
final List<String> notFineTransformers = AsmTransformers.getTransformers();
|
||||
final List<String> notFineTransformers = Arrays.asList(ITransformers.getTransformers(AsmTransformers.class));
|
||||
if (!notFineTransformers.isEmpty()) Namer.initNames();
|
||||
transformers.addAll(notFineTransformers);
|
||||
|
||||
transformerClasses = transformers.toArray(new String[0]);
|
||||
}
|
||||
return transformerClasses;
|
||||
@@ -117,7 +109,28 @@ public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader {
|
||||
|
||||
@Override
|
||||
public void injectData(Map<String, Object> data) {
|
||||
OBF_ENV = (boolean) data.get("runtimeDeobfuscationEnabled");
|
||||
OBF_ENV = (Boolean) data.get("runtimeDeobfuscationEnabled");
|
||||
// Directly add this to the MixinServiceLaunchWrapper tweaker's list of Tweak Classes
|
||||
final List<String> tweaks = GlobalProperties.get(MixinServiceLaunchWrapper.BLACKBOARD_KEY_TWEAKCLASSES);
|
||||
if (tweaks != null) {
|
||||
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.IncompatibleModsDisablerTweaker");
|
||||
if (AngelicaConfig.enableHudCaching) {
|
||||
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.XaerosTransformerDisablerTweaker");
|
||||
}
|
||||
if (FMLLaunchHandler.side().isClient()) {
|
||||
// We register ITweakers that will run last in order to register
|
||||
// specific IClassTransformers that will run last in the transformer chain.
|
||||
// If we were to register them normally in getASMTransformerClass(),
|
||||
// they would be sorted at index 0 which we do not want.
|
||||
boolean rfbLoaded = Launch.blackboard.getOrDefault("angelica.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE;
|
||||
if (!rfbLoaded) {
|
||||
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.AngelicaLateTweaker");
|
||||
}
|
||||
if (AngelicaConfig.enableSodium) {
|
||||
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.SodiumLateTweaker");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,39 +145,34 @@ public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader {
|
||||
|
||||
@Override
|
||||
public List<String> getMixins(Set<String> loadedCoreMods) {
|
||||
return Mixins.getEarlyMixins(loadedCoreMods);
|
||||
}
|
||||
|
||||
public static boolean DUMP_CLASSES() {
|
||||
return DUMP_CLASSES || !OBF_ENV;
|
||||
NotFineConfig.loadSettings();
|
||||
//This may be possible to handle differently or fix.
|
||||
if (loadedCoreMods.contains("cofh.asm.LoadingPlugin")) {
|
||||
MCPatcherForgeConfig.ExtendedHD.hdFont = false;
|
||||
}
|
||||
return IMixins.getEarlyMixins(Mixins.class, loadedCoreMods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if we are in an obfuscated environment, returns false in dev environment.
|
||||
*/
|
||||
public static boolean isObfEnv() {
|
||||
if (OBF_ENV == null) {
|
||||
throw new IllegalStateException("Obfuscation state has been accessed too early!");
|
||||
}
|
||||
return OBF_ENV;
|
||||
}
|
||||
|
||||
public static void dumpClass(String className, byte[] originalBytes, byte[] transformedBytes, Object transformer) {
|
||||
if (AngelicaTweaker.DUMP_CLASSES()) {
|
||||
ASMUtil.saveAsRawClassFile(originalBytes, className + "_PRE", transformer);
|
||||
ASMUtil.saveAsRawClassFile(transformedBytes, className + "_POST", transformer);
|
||||
/**
|
||||
* Returns the appropriate name according to current environment's obfuscation
|
||||
*/
|
||||
public static String obf(String deobf, String obf) {
|
||||
if (OBF_ENV == null) {
|
||||
throw new IllegalStateException("Obfuscation state has been accessed too early!");
|
||||
}
|
||||
if (OBF_ENV) {
|
||||
return obf;
|
||||
}
|
||||
return deobf;
|
||||
}
|
||||
|
||||
private static final ImmutableMap<String, TargetedMod> MODS_BY_CLASS = ImmutableMap.<String, TargetedMod>builder()
|
||||
.put("optifine.OptiFineForgeTweaker", TargetedMod.OPTIFINE)
|
||||
.put("fastcraft.Tweaker", TargetedMod.FASTCRAFT)
|
||||
.put("cofh.asm.LoadingPlugin", TargetedMod.COFHCORE)
|
||||
.build();
|
||||
public static final Set<TargetedMod> coreMods = new HashSet<>();
|
||||
|
||||
private static void detectCoreMods(Set<String> loadedCoreMods) {
|
||||
MODS_BY_CLASS.forEach((key, value) -> {
|
||||
if (loadedCoreMods.contains(key))
|
||||
coreMods.add(value);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.CompatConfig;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.handlers.ExtraUtilsCompatHandler;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.handlers.ImmersiveEngineeringCompatHandler;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.handlers.StacksOnStacksCompatHandler;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.handlers.ThaumcraftCompatHandler;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.handlers.ThaumicHorizonsCompatHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public enum CompatHandlers {
|
||||
|
||||
STACKS_ON_STACKS(() -> CompatConfig.fixStacksOnStacks, new StacksOnStacksCompatHandler()),
|
||||
EXTRA_UTILS(() -> CompatConfig.fixExtraUtils, new ExtraUtilsCompatHandler()),
|
||||
IMMERSIVE_ENGINEERING(() -> CompatConfig.fixImmersiveEngineering, new ImmersiveEngineeringCompatHandler()),
|
||||
THAUMCRAFT(() -> CompatConfig.fixThaumcraft, new ThaumcraftCompatHandler()),
|
||||
THAUMIC_HORIZONS(() -> CompatConfig.fixThaumicHorizons, new ThaumicHorizonsCompatHandler());
|
||||
|
||||
private final Supplier<Boolean> applyIf;
|
||||
private final ICompatHandler handler;
|
||||
|
||||
CompatHandlers(Supplier<Boolean> applyIf, ICompatHandler handler) {
|
||||
this.applyIf = applyIf;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
private static List<ICompatHandler> compatHandlers = null;
|
||||
|
||||
public static List<ICompatHandler> getHandlers() {
|
||||
if (compatHandlers != null) {
|
||||
return compatHandlers;
|
||||
}
|
||||
compatHandlers = new ArrayList<>();
|
||||
for (CompatHandlers value : values()) {
|
||||
if (value.applyIf.get()) {
|
||||
compatHandlers.add(value.handler);
|
||||
}
|
||||
}
|
||||
return compatHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns extra transformers as well as the main transformer.
|
||||
* Returns an empty list if no handlers registered.
|
||||
*/
|
||||
public static List<String> getTransformers() {
|
||||
final List<ICompatHandler> handlers = getHandlers();
|
||||
if (handlers.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> transformers = new ArrayList<>();
|
||||
for (ICompatHandler handler : handlers) {
|
||||
if (handler.extraTransformers() != null) {
|
||||
transformers.addAll(handler.extraTransformers());
|
||||
}
|
||||
}
|
||||
transformers.add("com.gtnewhorizons.angelica.loading.fml.transformers.GenericCompatTransformer");
|
||||
return transformers;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
package com.gtnewhorizons.angelica.transform.compat.handlers;
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface CompatHandler {
|
||||
public interface ICompatHandler {
|
||||
|
||||
default Map<String, List<String>> getFieldLevelTessellator() {
|
||||
return null;
|
||||
+3
-2
@@ -1,10 +1,11 @@
|
||||
package com.gtnewhorizons.angelica.transform.compat.handlers;
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat.handlers;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.ICompatHandler;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ExtraUtilsCompatHandler implements CompatHandler {
|
||||
public class ExtraUtilsCompatHandler implements ICompatHandler {
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> getThreadSafeISBRHAnnotations() {
|
||||
+4
-4
@@ -1,13 +1,13 @@
|
||||
package com.gtnewhorizons.angelica.transform.compat.handlers;
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat.handlers;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.gtnewhorizons.angelica.transform.compat.transformers.specific.ImmersiveEngineeringTransformer;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.ICompatHandler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ImmersiveEngineeringCompatHandler implements CompatHandler {
|
||||
public class ImmersiveEngineeringCompatHandler implements ICompatHandler {
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getTileEntityNullGuard() {
|
||||
@@ -38,7 +38,7 @@ public class ImmersiveEngineeringCompatHandler implements CompatHandler {
|
||||
|
||||
@Override
|
||||
public List<String> extraTransformers() {
|
||||
return ImmutableList.of(ImmersiveEngineeringTransformer.class.getName());
|
||||
return ImmutableList.of("com.gtnewhorizons.angelica.loading.fml.compat.transformers.specific.ImmersiveEngineeringTransformer");
|
||||
}
|
||||
|
||||
}
|
||||
+4
-4
@@ -1,13 +1,13 @@
|
||||
package com.gtnewhorizons.angelica.transform.compat.handlers;
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat.handlers;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.gtnewhorizons.angelica.transform.compat.transformers.specific.StacksOnStacksTransformer;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.ICompatHandler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class StacksOnStacksCompatHandler implements CompatHandler {
|
||||
public class StacksOnStacksCompatHandler implements ICompatHandler {
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getFieldLevelTessellator() {
|
||||
@@ -28,6 +28,6 @@ public class StacksOnStacksCompatHandler implements CompatHandler {
|
||||
|
||||
@Override
|
||||
public List<String> extraTransformers() {
|
||||
return ImmutableList.of(StacksOnStacksTransformer.class.getName());
|
||||
return ImmutableList.of("com.gtnewhorizons.angelica.loading.fml.compat.transformers.specific.StacksOnStacksTransformer");
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -1,12 +1,13 @@
|
||||
package com.gtnewhorizons.angelica.transform.compat.handlers;
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat.handlers;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.ICompatHandler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ThaumcraftCompatHandler implements CompatHandler {
|
||||
public class ThaumcraftCompatHandler implements ICompatHandler {
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getHUDCachingEarlyReturn() {
|
||||
+3
-2
@@ -1,12 +1,13 @@
|
||||
package com.gtnewhorizons.angelica.transform.compat.handlers;
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat.handlers;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.ICompatHandler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ThaumicHorizonsCompatHandler implements CompatHandler {
|
||||
public class ThaumicHorizonsCompatHandler implements ICompatHandler {
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getHUDCachingEarlyReturn() {
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.transform.compat.transformers.generic;
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat.transformers.generic;
|
||||
|
||||
import com.gtnewhorizons.angelica.transform.AsmUtil;
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
|
||||
import org.spongepowered.asm.lib.Opcodes;
|
||||
import org.spongepowered.asm.lib.tree.AbstractInsnNode;
|
||||
import org.spongepowered.asm.lib.tree.ClassNode;
|
||||
@@ -62,7 +62,7 @@ public class FieldLevelTessellatorTransformer {
|
||||
new FieldInsnNode(
|
||||
Opcodes.GETSTATIC,
|
||||
"net/minecraft/client/renderer/Tessellator",
|
||||
AsmUtil.obf("instance", "field_78398_a"),
|
||||
AngelicaTweaker.obf("instance", "field_78398_a"),
|
||||
"Lnet/minecraft/client/renderer/Tessellator;"));
|
||||
list.add(new VarInsnNode(Opcodes.ASTORE, localIndex));
|
||||
mn.instructions.insert(list);
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.gtnewhorizons.angelica.transform.compat.transformers.generic;
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat.transformers.generic;
|
||||
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
|
||||
import org.spongepowered.asm.lib.Opcodes;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.gtnewhorizons.angelica.transform.compat.transformers.generic;
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat.transformers.generic;
|
||||
|
||||
import org.spongepowered.asm.lib.tree.AnnotationNode;
|
||||
import org.spongepowered.asm.lib.tree.ClassNode;
|
||||
+2
-3
@@ -1,7 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.transform.compat.transformers.generic;
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat.transformers.generic;
|
||||
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
|
||||
import com.gtnewhorizons.angelica.transform.AsmUtil;
|
||||
import org.spongepowered.asm.lib.Opcodes;
|
||||
import org.spongepowered.asm.lib.tree.AbstractInsnNode;
|
||||
import org.spongepowered.asm.lib.tree.ClassNode;
|
||||
@@ -60,7 +59,7 @@ public class TileEntityNullGuardTransformer {
|
||||
AbstractInsnNode in = mn.instructions.get(i);
|
||||
if (in instanceof MethodInsnNode min) {
|
||||
if (min.getOpcode() == Opcodes.INVOKEINTERFACE
|
||||
&& min.name.equals(AsmUtil.obf("getTileEntity", "func_147438_o"))
|
||||
&& min.name.equals(AngelicaTweaker.obf("getTileEntity", "func_147438_o"))
|
||||
&& min.owner.equals("net/minecraft/world/IBlockAccess")) {
|
||||
AbstractInsnNode castNodeAbstract = min.getNext();
|
||||
if (castNodeAbstract instanceof TypeInsnNode castNodeType) {
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
package com.gtnewhorizons.angelica.transform.compat.transformers.specific;
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat.transformers.specific;
|
||||
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
|
||||
import com.gtnewhorizons.angelica.loading.shared.AngelicaClassDump;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import org.spongepowered.asm.lib.ClassReader;
|
||||
import org.spongepowered.asm.lib.Opcodes;
|
||||
@@ -60,7 +61,7 @@ public class ImmersiveEngineeringTransformer implements IClassTransformer {
|
||||
cn.accept(cw);
|
||||
final byte[] bytes = cw.toByteArray();
|
||||
AngelicaTweaker.LOGGER.info("[AngelicaCompat]Extra Transformers: Applied ImmersiveEngineeringTransformer");
|
||||
AngelicaTweaker.dumpClass(transformedName, basicClass, bytes, this);
|
||||
AngelicaClassDump.dumpClass(transformedName, basicClass, bytes, this);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
package com.gtnewhorizons.angelica.transform.compat.transformers.specific;
|
||||
package com.gtnewhorizons.angelica.loading.fml.compat.transformers.specific;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
|
||||
import com.gtnewhorizons.angelica.loading.shared.AngelicaClassDump;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import org.spongepowered.asm.lib.ClassReader;
|
||||
import org.spongepowered.asm.lib.ClassWriter;
|
||||
@@ -47,7 +48,7 @@ public class StacksOnStacksTransformer implements IClassTransformer {
|
||||
cn.accept(cw);
|
||||
final byte[] bytes = cw.toByteArray();
|
||||
AngelicaTweaker.LOGGER.info("[AngelicaCompat]Extra Transformers: Applied StacksOnStacksTransformer");
|
||||
AngelicaTweaker.dumpClass(transformedName, basicClass, bytes, this);
|
||||
AngelicaClassDump.dumpClass(transformedName, basicClass, bytes, this);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.gtnewhorizons.angelica.loading.fml.transformers;
|
||||
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
|
||||
import com.gtnewhorizons.angelica.loading.shared.AngelicaClassDump;
|
||||
import com.gtnewhorizons.angelica.loading.shared.transformers.AngelicaRedirector;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
/** IClassTransformer wrapper for {@link AngelicaRedirector} */
|
||||
public class AngelicaRedirectorTransformer implements IClassTransformer {
|
||||
|
||||
private final AngelicaRedirector inner;
|
||||
private final String[] exclusions;
|
||||
|
||||
public AngelicaRedirectorTransformer() {
|
||||
inner = new AngelicaRedirector(AngelicaTweaker.isObfEnv());
|
||||
exclusions = inner.getTransformerExclusions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(final String className, String transformedName, byte[] basicClass) {
|
||||
if (basicClass == null) return null;
|
||||
|
||||
// Ignore classes that are excluded from transformation - Doesn't fully work without the
|
||||
// TransformerExclusions due to some nested classes
|
||||
for (String exclusion : exclusions) {
|
||||
if (transformedName.startsWith(exclusion)) return basicClass;
|
||||
}
|
||||
|
||||
if (!inner.shouldTransform(basicClass)) {
|
||||
return basicClass;
|
||||
}
|
||||
|
||||
final ClassReader cr = new ClassReader(basicClass);
|
||||
final ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, 0);
|
||||
final boolean changed = inner.transformClassNode(transformedName, cn);
|
||||
if (changed) {
|
||||
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
cn.accept(cw);
|
||||
final byte[] bytes = cw.toByteArray();
|
||||
AngelicaClassDump.dumpClass(transformedName, basicClass, bytes, this);
|
||||
return bytes;
|
||||
}
|
||||
return basicClass;
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package com.gtnewhorizons.angelica.loading.fml.transformers;
|
||||
|
||||
import com.gtnewhorizons.angelica.loading.shared.AngelicaClassDump;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.ICompatHandler;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.CompatHandlers;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.transformers.generic.FieldLevelTessellatorTransformer;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.transformers.generic.HUDCachingEarlyReturnTransformer;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.transformers.generic.ThreadSafeISBRHAnnotationTransformer;
|
||||
import com.gtnewhorizons.angelica.loading.fml.compat.transformers.generic.TileEntityNullGuardTransformer;
|
||||
import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import org.spongepowered.asm.lib.ClassReader;
|
||||
import org.spongepowered.asm.lib.tree.ClassNode;
|
||||
import org.spongepowered.asm.transformers.MixinClassWriter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class GenericCompatTransformer implements IClassTransformer {
|
||||
|
||||
private final Map<String, List<String>> fieldLevelTessellator = new Object2ObjectOpenHashMap<>();
|
||||
private final Map<String, List<String>> tileEntityNullGuard = new Object2ObjectOpenHashMap<>();
|
||||
private final Map<String, Boolean> threadSafeIBSRH = new Object2BooleanOpenHashMap<>();
|
||||
private final Map<String, List<String>> hudCachingEarlyReturn = new Object2ObjectOpenHashMap<>();
|
||||
private final Set<String> targetedClasses = new ObjectOpenHashSet<>();
|
||||
|
||||
public GenericCompatTransformer() {
|
||||
for (ICompatHandler handler : CompatHandlers.getHandlers()) {
|
||||
registerHandler(handler);
|
||||
}
|
||||
buildTargetClassSet();
|
||||
}
|
||||
|
||||
private void registerHandler(ICompatHandler handler) {
|
||||
if (handler.getFieldLevelTessellator() != null) {
|
||||
fieldLevelTessellator.putAll(handler.getFieldLevelTessellator());
|
||||
}
|
||||
if (handler.getTileEntityNullGuard() != null) {
|
||||
tileEntityNullGuard.putAll(handler.getTileEntityNullGuard());
|
||||
}
|
||||
if (handler.getThreadSafeISBRHAnnotations() != null) {
|
||||
threadSafeIBSRH.putAll(handler.getThreadSafeISBRHAnnotations());
|
||||
}
|
||||
if (handler.getHUDCachingEarlyReturn() != null) {
|
||||
hudCachingEarlyReturn.putAll(handler.getHUDCachingEarlyReturn());
|
||||
}
|
||||
}
|
||||
|
||||
private void buildTargetClassSet() {
|
||||
targetedClasses.addAll(fieldLevelTessellator.keySet());
|
||||
targetedClasses.addAll(tileEntityNullGuard.keySet());
|
||||
targetedClasses.addAll(threadSafeIBSRH.keySet());
|
||||
targetedClasses.addAll(hudCachingEarlyReturn.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(String name, String transformedName, byte[] basicClass) {
|
||||
if (basicClass == null) return null;
|
||||
|
||||
if (!targetedClasses.contains(transformedName)) return basicClass;
|
||||
|
||||
ClassReader cr = new ClassReader(basicClass);
|
||||
ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, 0);
|
||||
|
||||
if (fieldLevelTessellator.containsKey(transformedName)) {
|
||||
FieldLevelTessellatorTransformer.transform(cn, fieldLevelTessellator.get(transformedName));
|
||||
}
|
||||
|
||||
if (tileEntityNullGuard.containsKey(transformedName)) {
|
||||
TileEntityNullGuardTransformer.transform(cn, tileEntityNullGuard.get(transformedName));
|
||||
}
|
||||
|
||||
if (threadSafeIBSRH.containsKey(transformedName)) {
|
||||
ThreadSafeISBRHAnnotationTransformer.transform(cn, threadSafeIBSRH.get(transformedName));
|
||||
}
|
||||
|
||||
if (hudCachingEarlyReturn.containsKey(transformedName)) {
|
||||
HUDCachingEarlyReturnTransformer.transform(cn, hudCachingEarlyReturn.get(transformedName));
|
||||
}
|
||||
|
||||
MixinClassWriter cw = new MixinClassWriter(MixinClassWriter.COMPUTE_MAXS | MixinClassWriter.COMPUTE_FRAMES);
|
||||
cn.accept(cw);
|
||||
final byte[] bytes = cw.toByteArray();
|
||||
AngelicaClassDump.dumpClass(transformedName, basicClass, bytes, this);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
+9
-8
@@ -1,7 +1,8 @@
|
||||
package com.gtnewhorizons.angelica.transform;
|
||||
package com.gtnewhorizons.angelica.loading.fml.transformers;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
|
||||
import com.gtnewhorizons.angelica.loading.shared.AngelicaClassDump;
|
||||
import com.gtnewhorizons.angelica.loading.shared.transformers.AngelicaRedirector;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
@@ -10,10 +11,9 @@ import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BlockTransformer implements IClassTransformer {
|
||||
public class SodiumBlockTransformer implements IClassTransformer {
|
||||
|
||||
private static final String BlockClassFriendly = "net.minecraft.block.Block";
|
||||
public static final List<Pair<String, String>> BlockBoundsFields = ImmutableList.of(
|
||||
private static final List<Pair<String, String>> BlockBoundsFields = ImmutableList.of(
|
||||
Pair.of("minX", "field_149759_B"),
|
||||
Pair.of("minY", "field_149760_C"),
|
||||
Pair.of("minZ", "field_149754_D"),
|
||||
@@ -23,12 +23,13 @@ public class BlockTransformer implements IClassTransformer {
|
||||
);
|
||||
|
||||
/**
|
||||
* Delete the global vanilla bounding box fields off the Block object. {@link RedirectorTransformer}
|
||||
* Delete the global vanilla bounding box fields off the Block object. {@link AngelicaRedirector}
|
||||
* replaces these with a thread-safe alternative.
|
||||
*/
|
||||
@Override
|
||||
public byte[] transform(String name, String transformedName, byte[] basicClass) {
|
||||
if (basicClass != null && BlockClassFriendly.equals(transformedName)) {
|
||||
if (basicClass == null) return null;
|
||||
if ("net.minecraft.block.Block".equals(transformedName)) {
|
||||
final ClassReader cr = new ClassReader(basicClass);
|
||||
final ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, 0);
|
||||
@@ -36,7 +37,7 @@ public class BlockTransformer implements IClassTransformer {
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
cn.accept(cw);
|
||||
final byte[] bytes = cw.toByteArray();
|
||||
AngelicaTweaker.dumpClass(transformedName, basicClass, bytes, this);
|
||||
AngelicaClassDump.dumpClass(transformedName, basicClass, bytes, this);
|
||||
return bytes;
|
||||
}
|
||||
return basicClass;
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.gtnewhorizons.angelica.loading.fml.tweakers;
|
||||
|
||||
import cpw.mods.fml.relauncher.FMLRelaunchLog;
|
||||
import net.minecraft.launchwrapper.ITweaker;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class AngelicaLateTweaker implements ITweaker {
|
||||
|
||||
@Override
|
||||
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLaunchTarget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getLaunchArguments() {
|
||||
// Run after Mixins, but before LWJGl3ify
|
||||
String transformer = "com.gtnewhorizons.angelica.loading.fml.transformers.AngelicaRedirectorTransformer";
|
||||
FMLRelaunchLog.finer("Registering transformer %s", transformer);
|
||||
Launch.classLoader.registerTransformer(transformer);
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
+30
-77
@@ -1,11 +1,7 @@
|
||||
package com.gtnewhorizons.angelica.loading;
|
||||
package com.gtnewhorizons.angelica.loading.fml.tweakers;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.transform.BlockTransformer;
|
||||
import com.gtnewhorizons.angelica.transform.RedirectorTransformer;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.relauncher.CoreModManager;
|
||||
import cpw.mods.fml.relauncher.FMLLaunchHandler;
|
||||
import cpw.mods.fml.relauncher.FMLRelaunchLog;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.ITweaker;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
@@ -23,61 +19,44 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.LOGGER;
|
||||
public class IncompatibleModsDisablerTweaker implements ITweaker {
|
||||
|
||||
private static final boolean DISABLE_OPTIFINE_FASTCRAFT_BETTERFPS = true;
|
||||
|
||||
public class MixinCompatHackTweaker implements ITweaker {
|
||||
public static final boolean DISABLE_OPTIFINE_FASTCRAFT_BETTERFPS = true;
|
||||
@Override
|
||||
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
|
||||
verifyDependencies();
|
||||
// no-op
|
||||
}
|
||||
|
||||
if(DISABLE_OPTIFINE_FASTCRAFT_BETTERFPS) {
|
||||
LOGGER.info("Disabling Optifine, Fastcraft, BetterFPS, and other incompatible mods (if present)");
|
||||
disableIncompatibleMods();
|
||||
}
|
||||
|
||||
if (AngelicaConfig.enableHudCaching){
|
||||
disableXaerosMinimapWaypointTransformer();
|
||||
@Override
|
||||
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
|
||||
if (DISABLE_OPTIFINE_FASTCRAFT_BETTERFPS) {
|
||||
FMLRelaunchLog.info("[Angelica/IncompatibleModsDisablerTweaker] Disabling Optifine, Fastcraft, BetterFPS, and other incompatible mods (if present)");
|
||||
disableIncompatibleMods(classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyDependencies() {
|
||||
if(MixinCompatHackTweaker.class.getResource("/it/unimi/dsi/fastutil/ints/Int2ObjectMap.class") == null) {
|
||||
throw new RuntimeException("Missing dependency: Angelica requires GTNHLib 0.2.1 or newer! Download: https://modrinth.com/mod/gtnhlib");
|
||||
}
|
||||
@Override
|
||||
public String getLaunchTarget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void disableXaerosMinimapWaypointTransformer(){
|
||||
try {
|
||||
final LaunchClassLoader lcl = Launch.classLoader;
|
||||
final Field xformersField = lcl.getClass().getDeclaredField("transformers");
|
||||
xformersField.setAccessible(true);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<IClassTransformer> xformers = (List<IClassTransformer>) xformersField.get(lcl);
|
||||
for (int idx = xformers.size() - 1; idx >= 0; idx--) {
|
||||
final String name = xformers.get(idx).getClass().getName();
|
||||
if (name.startsWith("xaero.common.core.transformer.GuiIngameForgeTransformer")) {
|
||||
LOGGER.info("Removing transformer " + name);
|
||||
xformers.remove(idx);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@Override
|
||||
public String[] getLaunchArguments() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void disableIncompatibleMods() {
|
||||
private void disableIncompatibleMods(LaunchClassLoader lcl) {
|
||||
// Remove transformers, Mod Containers, and mixins for Optifine, Fastcraft, BetterFPS and other incompatible mods
|
||||
try {
|
||||
final LaunchClassLoader lcl = Launch.classLoader;
|
||||
final Field xformersField = lcl.getClass().getDeclaredField("transformers");
|
||||
xformersField.setAccessible(true);
|
||||
final List<IClassTransformer> xformers = (List<IClassTransformer>) xformersField.get(lcl);
|
||||
for (int idx = xformers.size() - 1; idx >= 0; idx--) {
|
||||
final String name = xformers.get(idx).getClass().getName();
|
||||
if (name.startsWith("optifine") || name.startsWith("fastcraft") || name.startsWith("me.guichaguri.betterfps")) {
|
||||
LOGGER.info("Removing transformer " + name);
|
||||
FMLRelaunchLog.info("[Angelica/IncompatibleModsDisablerTweaker] Removing transformer " + name);
|
||||
xformers.remove(idx);
|
||||
}
|
||||
}
|
||||
@@ -85,13 +64,14 @@ public class MixinCompatHackTweaker implements ITweaker {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
try {
|
||||
final Field injectedContainersField = Loader.class.getDeclaredField("injectedContainers");
|
||||
final Class<?> loaderClass = Class.forName("cpw.mods.fml.common.Loader", true, lcl);
|
||||
final Field injectedContainersField = loaderClass.getDeclaredField("injectedContainers");
|
||||
injectedContainersField.setAccessible(true);
|
||||
final List<String> containers = (List<String> ) injectedContainersField.get(Loader.class);
|
||||
final List<String> containers = (List<String>) injectedContainersField.get(loaderClass);
|
||||
for (int idx = containers.size() - 1; idx >= 0; idx--) {
|
||||
final String name = containers.get(idx);
|
||||
final String name = containers.get(idx);
|
||||
if (name.startsWith("optifine") || name.startsWith("fastcraft")) {
|
||||
LOGGER.info("Removing mod container " + name);
|
||||
FMLRelaunchLog.info("[Angelica/IncompatibleModsDisablerTweaker] Removing mod container " + name);
|
||||
containers.remove(idx);
|
||||
}
|
||||
}
|
||||
@@ -105,7 +85,7 @@ public class MixinCompatHackTweaker implements ITweaker {
|
||||
for (int idx = reparsedCoremods.size() - 1; idx >= 0; idx--) {
|
||||
final String coreMod = reparsedCoremods.get(idx);
|
||||
if (coreMod.startsWith("optimizationsandtweaks")) {
|
||||
LOGGER.info("Removing reparsed coremod " + coreMod);
|
||||
FMLRelaunchLog.info("[Angelica/IncompatibleModsDisablerTweaker] Removing reparsed coremod " + coreMod);
|
||||
// Fool the CoreModManager into not checking for a mod container again later
|
||||
loadedCoremods.add(reparsedCoremods.remove(idx));
|
||||
|
||||
@@ -120,7 +100,7 @@ public class MixinCompatHackTweaker implements ITweaker {
|
||||
for (int idx = mixinConfigsDefault.size() - 1; idx >= 0; idx--) {
|
||||
final String name = mixinConfigsDefault.get(idx);
|
||||
if (name != null && name.contains("optimizationsandtweaks")) {
|
||||
LOGGER.info("Removing mixin config " + name);
|
||||
FMLRelaunchLog.info("[Angelica/IncompatibleModsDisablerTweaker] Removing mixin config " + name);
|
||||
mixinConfigsDefault.remove(idx);
|
||||
}
|
||||
}
|
||||
@@ -131,7 +111,7 @@ public class MixinCompatHackTweaker implements ITweaker {
|
||||
for (Config config : mixinConfigs) {
|
||||
final String name = config.getName();
|
||||
if (name != null && name.contains("optimizationsandtweaks")) {
|
||||
LOGGER.info("Removing queued mixin config " + config.getName());
|
||||
FMLRelaunchLog.info("[Angelica/IncompatibleModsDisablerTweaker] Removing queued mixin config " + config.getName());
|
||||
toRemove.add(config);
|
||||
}
|
||||
}
|
||||
@@ -144,8 +124,8 @@ public class MixinCompatHackTweaker implements ITweaker {
|
||||
final Map<IContainerHandle, MixinContainer> containers = (Map<IContainerHandle, MixinContainer>) containersField.get(platformManager);
|
||||
for (Map.Entry<IContainerHandle, MixinContainer> entry : containers.entrySet()) {
|
||||
final String attribute = entry.getKey().getAttribute("MixinConfigs");
|
||||
if(attribute != null && attribute.contains("optimizationsandtweaks")) {
|
||||
LOGGER.info("Removing mixin container " + entry.getKey().toString());
|
||||
if (attribute != null && attribute.contains("optimizationsandtweaks")) {
|
||||
FMLRelaunchLog.info("[Angelica/IncompatibleModsDisablerTweaker] Removing mixin container " + entry.getKey().toString());
|
||||
containers.remove(entry.getKey());
|
||||
}
|
||||
}
|
||||
@@ -155,31 +135,4 @@ public class MixinCompatHackTweaker implements ITweaker {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLaunchTarget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getLaunchArguments() {
|
||||
if (FMLLaunchHandler.side().isClient()) {
|
||||
final boolean rfbLoaded = Launch.blackboard.getOrDefault("angelica.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE;
|
||||
|
||||
if (!rfbLoaded) {
|
||||
// Run after Mixins, but before LWJGl3ify
|
||||
Launch.classLoader.registerTransformer(RedirectorTransformer.class.getName());
|
||||
}
|
||||
if(AngelicaConfig.enableSodium) {
|
||||
Launch.classLoader.registerTransformer(BlockTransformer.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.gtnewhorizons.angelica.loading.fml.tweakers;
|
||||
|
||||
import cpw.mods.fml.relauncher.FMLRelaunchLog;
|
||||
import net.minecraft.launchwrapper.ITweaker;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class SodiumLateTweaker implements ITweaker {
|
||||
|
||||
@Override
|
||||
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLaunchTarget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getLaunchArguments() {
|
||||
String transformer = "com.gtnewhorizons.angelica.loading.fml.transformers.SodiumBlockTransformer";
|
||||
FMLRelaunchLog.finer("Registering transformer %s", transformer);
|
||||
Launch.classLoader.registerTransformer(transformer);
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.gtnewhorizons.angelica.loading.fml.tweakers;
|
||||
|
||||
import cpw.mods.fml.relauncher.FMLRelaunchLog;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.ITweaker;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
public class XaerosTransformerDisablerTweaker implements ITweaker {
|
||||
|
||||
@Override
|
||||
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
|
||||
try {
|
||||
final Field xformersField = classLoader.getClass().getDeclaredField("transformers");
|
||||
xformersField.setAccessible(true);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<IClassTransformer> transformers = (List<IClassTransformer>) xformersField.get(classLoader);
|
||||
for (int idx = transformers.size() - 1; idx >= 0; idx--) {
|
||||
final String name = transformers.get(idx).getClass().getName();
|
||||
if (name.startsWith("xaero.common.core.transformer.GuiIngameForgeTransformer")) {
|
||||
transformers.remove(idx);
|
||||
FMLRelaunchLog.info("[Angelica/XaerosTransformerDisablerTweaker] Removed transformer " + name);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLaunchTarget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getLaunchArguments() {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* ITweaker needs to be in a standalone package
|
||||
* because FML adds the whole package to the class
|
||||
* loader exclusions and that causes really hard to
|
||||
* find bugs. ITweakers also get class loaded
|
||||
* by the parent class loader and not LaunchClassLoader,
|
||||
* as a result the ITweakers should not reference any
|
||||
* class otherwise it will load them (maybe a second time)
|
||||
* on the parent class loader.
|
||||
*/
|
||||
package com.gtnewhorizons.angelica.loading.fml.tweakers;
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.loading.rfb;
|
||||
|
||||
import com.gtnewhorizons.angelica.loading.rfb.transformers.RFBAngelicaRedirector;
|
||||
import com.gtnewhorizons.retrofuturabootstrap.api.PluginContext;
|
||||
import com.gtnewhorizons.retrofuturabootstrap.api.RetroFuturaBootstrap;
|
||||
import com.gtnewhorizons.retrofuturabootstrap.api.RfbClassTransformer;
|
||||
@@ -21,8 +22,10 @@ public class AngelicaRfbPlugin implements RfbPlugin {
|
||||
if (isServer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final boolean isObf = RetroFuturaBootstrap.API.launchClassLoader().findClassMetadata("net.minecraft.world.World") == null;
|
||||
return new RfbClassTransformer[] {
|
||||
new RedirectorTransformerWrapper()
|
||||
new RFBAngelicaRedirector(isObf)
|
||||
};
|
||||
}
|
||||
}
|
||||
+13
-7
@@ -1,6 +1,7 @@
|
||||
package com.gtnewhorizons.angelica.loading.rfb;
|
||||
package com.gtnewhorizons.angelica.loading.rfb.transformers;
|
||||
|
||||
import com.gtnewhorizons.angelica.transform.RedirectorTransformer;
|
||||
import com.gtnewhorizons.angelica.loading.shared.AngelicaClassDump;
|
||||
import com.gtnewhorizons.angelica.loading.shared.transformers.AngelicaRedirector;
|
||||
import com.gtnewhorizons.retrofuturabootstrap.api.ClassNodeHandle;
|
||||
import com.gtnewhorizons.retrofuturabootstrap.api.ExtensibleClassLoader;
|
||||
import com.gtnewhorizons.retrofuturabootstrap.api.RfbClassTransformer;
|
||||
@@ -10,10 +11,14 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/** RFB wrapper for {@link com.gtnewhorizons.angelica.transform.RedirectorTransformer} */
|
||||
public class RedirectorTransformerWrapper implements RfbClassTransformer {
|
||||
/** RfbClassTransformer wrapper for {@link AngelicaRedirector} */
|
||||
public class RFBAngelicaRedirector implements RfbClassTransformer {
|
||||
|
||||
public final RedirectorTransformer inner = new RedirectorTransformer();
|
||||
private final AngelicaRedirector inner;
|
||||
|
||||
public RFBAngelicaRedirector(boolean isObf) {
|
||||
inner = new AngelicaRedirector(isObf);
|
||||
}
|
||||
|
||||
@Pattern("[a-z0-9-]+")
|
||||
@Override
|
||||
@@ -33,7 +38,7 @@ public class RedirectorTransformerWrapper implements RfbClassTransformer {
|
||||
|
||||
@Override
|
||||
public @NotNull String @Nullable [] additionalExclusions() {
|
||||
return RedirectorTransformer.getTransformerExclusions().toArray(new String[0]);
|
||||
return inner.getTransformerExclusions();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,7 +52,7 @@ public class RedirectorTransformerWrapper implements RfbClassTransformer {
|
||||
// If a class is already a transformed ClassNode, conservatively continue processing.
|
||||
return true;
|
||||
}
|
||||
return inner.shouldRfbTransform(classNode.getOriginalBytes());
|
||||
return inner.shouldTransform(classNode.getOriginalBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,6 +61,7 @@ public class RedirectorTransformerWrapper implements RfbClassTransformer {
|
||||
final boolean changed = inner.transformClassNode(className, classNode.getNode());
|
||||
if (changed) {
|
||||
classNode.computeMaxs();
|
||||
AngelicaClassDump.dumpRFBClass(className, classNode, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.gtnewhorizons.angelica.loading.shared;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.asm.ASMUtil;
|
||||
import com.gtnewhorizons.retrofuturabootstrap.api.ClassNodeHandle;
|
||||
|
||||
public class AngelicaClassDump {
|
||||
|
||||
private static final boolean DUMP_CLASS = Boolean.getBoolean("angelica.dumpClass");
|
||||
|
||||
public static void dumpClass(String className, byte[] originalBytes, byte[] transformedBytes, Object transformer) {
|
||||
if (DUMP_CLASS) {
|
||||
ASMUtil.saveAsRawClassFile(originalBytes, className + "_PRE", transformer);
|
||||
ASMUtil.saveAsRawClassFile(transformedBytes, className + "_POST", transformer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void dumpRFBClass(String className, ClassNodeHandle classNode, Object transformer) {
|
||||
if (DUMP_CLASS) {
|
||||
final byte[] originalBytes = classNode.getOriginalBytes();
|
||||
final byte[] transformedBytes = classNode.computeBytes();
|
||||
ASMUtil.saveAsRawClassFile(originalBytes, className + "_PRE", transformer);
|
||||
ASMUtil.saveAsRawClassFile(transformedBytes, className + "_POST", transformer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Package that contains classes that may be loaded both by RFB and FML classloaders, the code contained in this package
|
||||
* should not reference any code from outside of this package to avoid causing hard to debug classloading issues unless
|
||||
* the code is known to be safe with different classloaders.
|
||||
*/
|
||||
package com.gtnewhorizons.angelica.loading.shared;
|
||||
+66
-81
@@ -1,14 +1,12 @@
|
||||
package com.gtnewhorizons.angelica.transform;
|
||||
package com.gtnewhorizons.angelica.loading.shared.transformers;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.gtnewhorizon.gtnhlib.asm.ClassConstantPoolParser;
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
|
||||
import net.coderbot.iris.IrisLogging;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
@@ -22,7 +20,6 @@ import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -33,10 +30,25 @@ import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* This transformer redirects many GL calls to our custom GLStateManager
|
||||
* <p>
|
||||
* THIS CLASS MIGHT BE LOADED ON A DIFFERENT CLASS LOADER,
|
||||
* IT SHOULD NOT CALL ANY CODE FROM THE MAIN MOD
|
||||
*/
|
||||
public class RedirectorTransformer implements IClassTransformer {
|
||||
public final class AngelicaRedirector {
|
||||
// TODO(Alexdoru) properly split this class in two because currently this class is doing
|
||||
// two very different things :
|
||||
// - redirect the GL calls to our GL manager class
|
||||
// - replace the block fields with a thread safe replacement (only if Sodium is enabled)
|
||||
|
||||
private static final boolean ASSERT_MAIN_THREAD = Boolean.parseBoolean(System.getProperty("angelica.assertMainThread", "false"));
|
||||
public AngelicaRedirector(boolean isObf) {
|
||||
IS_OBF = isObf;
|
||||
}
|
||||
|
||||
private final boolean IS_OBF;
|
||||
|
||||
private static final boolean ASSERT_MAIN_THREAD = Boolean.getBoolean("angelica.assertMainThread");
|
||||
private static final boolean LOG_SPAM = Boolean.getBoolean("angelica.redirectorLogspam");
|
||||
private static final Logger LOGGER = LogManager.getLogger("AngelicaRedirector");
|
||||
private static final String Drawable = "org/lwjgl/opengl/Drawable";
|
||||
private static final String GLStateManager = "com/gtnewhorizons/angelica/glsm/GLStateManager";
|
||||
private static final String GL11 = "org/lwjgl/opengl/GL11";
|
||||
@@ -58,25 +70,26 @@ public class RedirectorTransformer implements IClassTransformer {
|
||||
"startGame", "func_71384_a",
|
||||
"initializeTextures", "func_77474_a"
|
||||
);
|
||||
private static final List<Pair<String, String>> BlockBoundsFields = ImmutableList.of(
|
||||
Pair.of("minX", "field_149759_B"),
|
||||
Pair.of("minY", "field_149760_C"),
|
||||
Pair.of("minZ", "field_149754_D"),
|
||||
Pair.of("maxX", "field_149755_E"),
|
||||
Pair.of("maxY", "field_149756_F"),
|
||||
Pair.of("maxZ", "field_149757_G")
|
||||
);
|
||||
/** All classes in <tt>net.minecraft.block.*</tt> are the block subclasses save for these. */
|
||||
private static final List<String> VanillaBlockExclusions = Arrays.asList(
|
||||
private static final String[] VanillaBlockExclusions = {
|
||||
"net/minecraft/block/IGrowable",
|
||||
"net/minecraft/block/ITileEntityProvider",
|
||||
"net/minecraft/block/BlockEventData",
|
||||
"net/minecraft/block/BlockSourceImpl",
|
||||
"net/minecraft/block/material/"
|
||||
);
|
||||
};
|
||||
|
||||
private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, OpenGlHelper, EXTBlendFunc, ARBMultiTexture, BlockPackage, Project);
|
||||
private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, GL20, OpenGlHelper, EXTBlendFunc, ARBMultiTexture, BlockPackage, Project);
|
||||
private static final Map<String, Map<String, String>> methodRedirects = new HashMap<>();
|
||||
private static final Map<Integer, String> glCapRedirects = new HashMap<>();
|
||||
private static final List<String> TransformerExclusions = Arrays.asList(
|
||||
"org.lwjgl",
|
||||
"com.gtnewhorizons.angelica.glsm.",
|
||||
"com.gtnewhorizons.angelica.transform",
|
||||
"me.eigenraven.lwjgl3ify"
|
||||
);
|
||||
private static int remaps = 0;
|
||||
|
||||
private static final Set<String> moddedBlockSubclasses = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
// Block owners we *shouldn't* redirect because they shadow one of our fields
|
||||
@@ -210,8 +223,7 @@ public class RedirectorTransformer implements IClassTransformer {
|
||||
|
||||
try {
|
||||
final Class<?> angelicaConfig = Class.forName("com.gtnewhorizons.angelica.config.AngelicaConfig", true, Launch.classLoader);
|
||||
final MethodHandle sodiumGetter = MethodHandles.lookup().findStaticGetter(angelicaConfig, "enableSodium", boolean.class);
|
||||
angelicaConfigSodiumEnabledGetter = sodiumGetter;
|
||||
angelicaConfigSodiumEnabledGetter = MethodHandles.lookup().findStaticGetter(angelicaConfig, "enableSodium", boolean.class);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -241,45 +253,23 @@ public class RedirectorTransformer implements IClassTransformer {
|
||||
return isVanillaBlockSubclass(className) || moddedBlockSubclasses.contains(className);
|
||||
}
|
||||
|
||||
public static List<String> getTransformerExclusions() {
|
||||
return Collections.unmodifiableList(TransformerExclusions);
|
||||
private String getFieldName(Pair<String, String> fieldPair) {
|
||||
return IS_OBF ? fieldPair.getRight() : fieldPair.getLeft();
|
||||
}
|
||||
|
||||
public boolean shouldRfbTransform(byte[] basicClass) {
|
||||
public String[] getTransformerExclusions() {
|
||||
return new String[]{
|
||||
"org.lwjgl",
|
||||
"com.gtnewhorizons.angelica.glsm.",
|
||||
"com.gtnewhorizons.angelica.transform",
|
||||
"me.eigenraven.lwjgl3ify"
|
||||
};
|
||||
}
|
||||
|
||||
public boolean shouldTransform(byte[] basicClass) {
|
||||
return cstPoolParser.find(basicClass, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(final String className, String transformedName, byte[] basicClass) {
|
||||
if (basicClass == null) return null;
|
||||
|
||||
// Ignore classes that are excluded from transformation - Doesn't fully work without the
|
||||
// TransformerExclusions due to some nested classes
|
||||
for (String exclusion : TransformerExclusions) {
|
||||
if (className.startsWith(exclusion)) {
|
||||
return basicClass;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cstPoolParser.find(basicClass, true)) {
|
||||
return basicClass;
|
||||
}
|
||||
|
||||
// Keep in sync with com.gtnewhorizons.angelica.loading.rfb.RedirectorTransformerWrapper
|
||||
final ClassReader cr = new ClassReader(basicClass);
|
||||
final ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, 0);
|
||||
final boolean changed = transformClassNode(transformedName, cn);
|
||||
if (changed) {
|
||||
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
cn.accept(cw);
|
||||
final byte[] bytes = cw.toByteArray();
|
||||
AngelicaTweaker.dumpClass(transformedName, basicClass, bytes, this);
|
||||
return bytes;
|
||||
}
|
||||
return basicClass;
|
||||
}
|
||||
|
||||
/** @return Was the class changed? */
|
||||
public boolean transformClassNode(String transformedName, ClassNode cn) {
|
||||
if (cn == null) {
|
||||
@@ -293,19 +283,19 @@ public class RedirectorTransformer implements IClassTransformer {
|
||||
}
|
||||
|
||||
// Check if this class shadows any fields of the parent class
|
||||
if(moddedBlockSubclasses.contains(cn.name)) {
|
||||
if (moddedBlockSubclasses.contains(cn.name)) {
|
||||
// If a superclass shadows, then so do we, because JVM will resolve a reference on our class to that
|
||||
// superclass
|
||||
boolean doWeShadow;
|
||||
if(blockOwnerExclusions.contains(cn.superName)) {
|
||||
if (blockOwnerExclusions.contains(cn.superName)) {
|
||||
doWeShadow = true;
|
||||
} else {
|
||||
// Check if we declare any known field names
|
||||
Set<String> fieldsDeclaredByClass = cn.fields.stream().map(f -> f.name).collect(Collectors.toSet());
|
||||
doWeShadow = BlockTransformer.BlockBoundsFields.stream().anyMatch(pair -> fieldsDeclaredByClass.contains(pair.getLeft()) || fieldsDeclaredByClass.contains(pair.getRight()));
|
||||
doWeShadow = BlockBoundsFields.stream().anyMatch(pair ->
|
||||
cn.fields.stream().anyMatch(field -> field.name.equals(getFieldName(pair))));
|
||||
}
|
||||
if (doWeShadow) {
|
||||
AngelicaTweaker.LOGGER.info("Class '{}' shadows one or more block bounds fields, these accesses won't be redirected!", cn.name);
|
||||
LOGGER.info("Class '{}' shadows one or more block bounds fields, these accesses won't be redirected!", cn.name);
|
||||
blockOwnerExclusions.add(cn.name);
|
||||
}
|
||||
}
|
||||
@@ -333,11 +323,11 @@ public class RedirectorTransformer implements IClassTransformer {
|
||||
name = "disable" + name;
|
||||
}
|
||||
}
|
||||
if (IrisLogging.ENABLE_SPAM) {
|
||||
if (LOG_SPAM) {
|
||||
if (name == null) {
|
||||
AngelicaTweaker.LOGGER.info("Redirecting call in {} from GL11.{}(I)V to GLStateManager.{}(I)V", transformedName, mNode.name, mNode.name);
|
||||
LOGGER.info("Redirecting call in {} from GL11.{}(I)V to GLStateManager.{}(I)V", transformedName, mNode.name, mNode.name);
|
||||
} else {
|
||||
AngelicaTweaker.LOGGER.info("Redirecting call in {} from GL11.{}(I)V to GLStateManager.{}()V", transformedName, mNode.name, name);
|
||||
LOGGER.info("Redirecting call in {} from GL11.{}(I)V to GLStateManager.{}()V", transformedName, mNode.name, name);
|
||||
}
|
||||
}
|
||||
mNode.owner = GLStateManager;
|
||||
@@ -348,43 +338,37 @@ public class RedirectorTransformer implements IClassTransformer {
|
||||
}
|
||||
changed = true;
|
||||
redirectInMethod = true;
|
||||
remaps++;
|
||||
} else if (mNode.owner.startsWith(Drawable) && mNode.name.equals("makeCurrent")) {
|
||||
mNode.setOpcode(Opcodes.INVOKESTATIC);
|
||||
mNode.owner = GLStateManager;
|
||||
mNode.desc = "(L" + Drawable + ";)V";
|
||||
mNode.itf = false;
|
||||
changed = true;
|
||||
if (IrisLogging.ENABLE_SPAM) {
|
||||
AngelicaTweaker.LOGGER.info("Redirecting call in {} to GLStateManager.makeCurrent()", transformedName);
|
||||
if (LOG_SPAM) {
|
||||
LOGGER.info("Redirecting call in {} to GLStateManager.makeCurrent()", transformedName);
|
||||
}
|
||||
} else {
|
||||
final Map<String, String> redirects = methodRedirects.get(mNode.owner);
|
||||
if (redirects != null && redirects.containsKey(mNode.name)) {
|
||||
if (IrisLogging.ENABLE_SPAM) {
|
||||
if (LOG_SPAM) {
|
||||
final String shortOwner = mNode.owner.substring(mNode.owner.lastIndexOf("/") + 1);
|
||||
AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", transformedName, shortOwner, mNode.name, mNode.desc, redirects.get(mNode.name), mNode.desc);
|
||||
LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", transformedName, shortOwner, mNode.name, mNode.desc, redirects.get(mNode.name), mNode.desc);
|
||||
}
|
||||
mNode.owner = GLStateManager;
|
||||
mNode.name = redirects.get(mNode.name);
|
||||
changed = true;
|
||||
redirectInMethod = true;
|
||||
remaps++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((node.getOpcode() == Opcodes.GETFIELD || node.getOpcode() == Opcodes.PUTFIELD) && node instanceof FieldInsnNode fNode) {
|
||||
if(!blockOwnerExclusions.contains(fNode.owner) && isBlockSubclass(fNode.owner) && isSodiumEnabled()) {
|
||||
Pair<String, String> fieldToRedirect = null;
|
||||
for(Pair<String, String> blockPairs : BlockTransformer.BlockBoundsFields) {
|
||||
if(fNode.name.equals(blockPairs.getLeft()) || fNode.name.equals(blockPairs.getRight())) {
|
||||
fieldToRedirect = blockPairs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if ((node.getOpcode() == Opcodes.GETFIELD || node.getOpcode() == Opcodes.PUTFIELD) && node instanceof FieldInsnNode fNode) {
|
||||
if (!blockOwnerExclusions.contains(fNode.owner) && isBlockSubclass(fNode.owner) && isSodiumEnabled()) {
|
||||
Pair<String, String> fieldToRedirect = BlockBoundsFields.stream()
|
||||
.filter(pair -> fNode.name.equals(getFieldName(pair)))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (fieldToRedirect != null) {
|
||||
if (IrisLogging.ENABLE_SPAM) {
|
||||
AngelicaTweaker.LOGGER.info("Redirecting Block.{} in {} to thread-safe wrapper", fNode.name, transformedName);
|
||||
if (LOG_SPAM) {
|
||||
LOGGER.info("Redirecting Block.{} in {} to thread-safe wrapper", fNode.name, transformedName);
|
||||
}
|
||||
// Perform the redirect
|
||||
fNode.name = fieldToRedirect.getLeft(); // use unobfuscated name
|
||||
@@ -423,6 +407,7 @@ public class RedirectorTransformer implements IClassTransformer {
|
||||
}
|
||||
|
||||
private static class RedirectMap<K> extends HashMap<K, K> {
|
||||
|
||||
public static RedirectMap<String> newMap() {
|
||||
return new RedirectMap<>();
|
||||
}
|
||||
@@ -1,213 +1,243 @@
|
||||
package com.gtnewhorizons.angelica.mixins;
|
||||
|
||||
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
|
||||
import com.gtnewhorizon.gtnhmixins.builders.MixinBuilder;
|
||||
import com.gtnewhorizons.angelica.AngelicaMod;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.config.CompatConfig;
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
|
||||
import cpw.mods.fml.relauncher.FMLLaunchHandler;
|
||||
import jss.notfine.config.MCPatcherForgeConfig;
|
||||
import jss.notfine.config.NotFineConfig;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public enum Mixins {
|
||||
ANGELICA_STARTUP(new Builder("Angelica Startup").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).addMixinClasses(
|
||||
"angelica.startup.MixinInitGLStateManager"
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum Mixins implements IMixins {
|
||||
|
||||
ANGELICA_STARTUP(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.addClientMixins(
|
||||
"angelica.startup.MixinInitGLStateManager"
|
||||
)
|
||||
),
|
||||
|
||||
ANGELICA(new Builder("Angelica").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).addMixinClasses(
|
||||
"angelica.MixinActiveRenderInfo"
|
||||
,"angelica.MixinEntityRenderer"
|
||||
,"angelica.MixinGameSettings"
|
||||
,"angelica.MixinMinecraft"
|
||||
,"angelica.MixinMinecraftServer"
|
||||
,"angelica.optimizations.MixinRendererLivingEntity"
|
||||
,"angelica.MixinFMLClientHandler"
|
||||
,"angelica.bugfixes.MixinRenderGlobal_DestroyBlock"
|
||||
ANGELICA(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.addClientMixins(
|
||||
"angelica.MixinActiveRenderInfo"
|
||||
, "angelica.MixinEntityRenderer"
|
||||
, "angelica.MixinGameSettings"
|
||||
, "angelica.MixinMinecraft"
|
||||
, "angelica.MixinMinecraftServer"
|
||||
, "angelica.optimizations.MixinRendererLivingEntity"
|
||||
, "angelica.MixinFMLClientHandler"
|
||||
, "angelica.bugfixes.MixinRenderGlobal_DestroyBlock"
|
||||
)
|
||||
),
|
||||
ANGELICA_VBO(
|
||||
new Builder("Angelica VBO").addTargetedMod(TargetedMod.VANILLA).setApplyIf(() -> AngelicaConfig.enableVBO).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).addMixinClasses(
|
||||
"angelica.vbo.MixinGLAllocation"
|
||||
,"angelica.vbo.MixinModelRenderer"
|
||||
,"angelica.vbo.MixinRenderGlobal"
|
||||
,"angelica.vbo.MixinWavefrontObject"
|
||||
)
|
||||
new MixinBuilder()
|
||||
.setApplyIf(() -> AngelicaConfig.enableVBO)
|
||||
.setPhase(Phase.EARLY)
|
||||
.addClientMixins(
|
||||
"angelica.vbo.MixinGLAllocation"
|
||||
, "angelica.vbo.MixinModelRenderer"
|
||||
, "angelica.vbo.MixinRenderGlobal"
|
||||
, "angelica.vbo.MixinWavefrontObject"
|
||||
)
|
||||
),
|
||||
ANGELICA_FONT_RENDERER(new Builder("Angelica Font Renderer").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableFontRenderer).addMixinClasses(
|
||||
"angelica.fontrenderer.MixinGuiIngameForge"
|
||||
,"angelica.fontrenderer.MixinFontRenderer"
|
||||
ANGELICA_FONT_RENDERER(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableFontRenderer)
|
||||
.addClientMixins(
|
||||
"angelica.fontrenderer.MixinGuiIngameForge"
|
||||
, "angelica.fontrenderer.MixinFontRenderer"
|
||||
, "angelica.fontrenderer.MixinMCResourceAccessor"
|
||||
)
|
||||
),
|
||||
|
||||
ANGELICA_ENABLE_DEBUG(new Builder("Angelica Debug").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).setApplyIf(() -> AngelicaMod.lwjglDebug).addMixinClasses(
|
||||
"angelica.debug.MixinProfiler"
|
||||
,"angelica.debug.MixinSplashProgress"
|
||||
,"angelica.debug.MixinTextureManager"
|
||||
ANGELICA_ENABLE_DEBUG(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaMod.lwjglDebug)
|
||||
.addClientMixins(
|
||||
"angelica.debug.MixinProfiler"
|
||||
, "angelica.debug.MixinSplashProgress"
|
||||
, "angelica.debug.MixinTextureManager"
|
||||
)
|
||||
),
|
||||
ANGELICA_DYNAMIC_LIGHTS(new Builder("Angelica Dynamic Lights").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableDynamicLights).addMixinClasses(
|
||||
ANGELICA_DYNAMIC_LIGHTS(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableDynamicLights)
|
||||
.addClientMixins(
|
||||
"angelica.dynamiclights.MixinEntityRenderer"
|
||||
,"angelica.dynamiclights.MixinEntity"
|
||||
,"angelica.dynamiclights.MixinWorld"
|
||||
,"angelica.dynamiclights.MixinItemRenderer"
|
||||
, "angelica.dynamiclights.MixinEntity"
|
||||
, "angelica.dynamiclights.MixinWorld"
|
||||
, "angelica.dynamiclights.MixinItemRenderer"
|
||||
)
|
||||
),
|
||||
|
||||
ANGELICA_FIX_FLUID_RENDERER_CHECKING_BLOCK_AGAIN(
|
||||
new Builder("Fix RenderBlockFluid reading the block type from the world access multiple times")
|
||||
.setPhase(Phase.EARLY).addMixinClasses("angelica.bugfixes.MixinRenderBlockFluid").setSide(Side.BOTH)
|
||||
.setApplyIf(() -> AngelicaConfig.fixFluidRendererCheckingBlockAgain)
|
||||
.addTargetedMod(TargetedMod.VANILLA)),
|
||||
new MixinBuilder("Fix RenderBlockFluid reading the block type from the world access multiple times")
|
||||
.setPhase(Phase.EARLY)
|
||||
.addClientMixins("angelica.bugfixes.MixinRenderBlockFluid")
|
||||
.setApplyIf(() -> AngelicaConfig.fixFluidRendererCheckingBlockAgain)),
|
||||
|
||||
ANGELICA_LIMIT_DROPPED_ITEM_ENTITIES(new Builder("Dynamically modifies the render distance of dropped items entities to preserve performance")
|
||||
.setPhase(Phase.EARLY).addMixinClasses("angelica.optimizations.MixinRenderGlobal_ItemRenderDist").setSide(Side.CLIENT)
|
||||
.setApplyIf(() -> AngelicaConfig.dynamicItemRenderDistance)
|
||||
.addTargetedMod(TargetedMod.VANILLA)),
|
||||
ANGELICA_LIMIT_DROPPED_ITEM_ENTITIES(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.addClientMixins("angelica.optimizations.MixinRenderGlobal_ItemRenderDist")
|
||||
.setApplyIf(() -> AngelicaConfig.dynamicItemRenderDistance)),
|
||||
|
||||
ANGELICA_ITEM_DISPLAY_LIST_OPTIMIZATION(new Builder("Optimized item rendering by wrapping them with display lists")
|
||||
.setPhase(Phase.EARLY).addMixinClasses("angelica.itemrenderer.MixinItemRenderer").setSide(Side.CLIENT)
|
||||
.setApplyIf(() -> AngelicaConfig.optimizeInWorldItemRendering)
|
||||
.addTargetedMod(TargetedMod.VANILLA)),
|
||||
ANGELICA_ITEM_RENDERER_OPTIMIZATION(new MixinBuilder("Optimizes in-world item rendering")
|
||||
.setPhase(Phase.EARLY)
|
||||
.addClientMixins("angelica.itemrenderer.MixinItemRenderer")
|
||||
.setApplyIf(() -> AngelicaConfig.optimizeInWorldItemRendering)),
|
||||
|
||||
// Not compatible with the lwjgl debug callbacks, so disable if that's enabled
|
||||
ARCHAIC_SPLASH(new Builder("ArchaicFix Splash").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.showSplashMemoryBar && !AngelicaMod.lwjglDebug).addMixinClasses(
|
||||
"angelica.archaic.MixinSplashProgress"
|
||||
,"angelica.archaic.AccessorSplashProgress"
|
||||
ARCHAIC_SPLASH(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.showSplashMemoryBar && !AngelicaMod.lwjglDebug)
|
||||
.addClientMixins(
|
||||
"angelica.archaic.MixinSplashProgress$3",
|
||||
"angelica.archaic.AccessorSplashProgress"
|
||||
)
|
||||
),
|
||||
|
||||
ARCHAIC_CORE(new Builder("Archaic Core").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).addMixinClasses(
|
||||
"angelica.archaic.MixinBlockFence"
|
||||
,"angelica.archaic.MixinFMLClientHandler"
|
||||
,"angelica.archaic.MixinGuiIngameForge"
|
||||
,"angelica.archaic.MixinNetHandlerPlayClient"
|
||||
,"angelica.archaic.MixinThreadDownloadImageData"
|
||||
ARCHAIC_CORE(new MixinBuilder()
|
||||
.addExcludedMod(TargetedMod.ARCHAICFIX)
|
||||
.setPhase(Phase.EARLY)
|
||||
.addClientMixins(
|
||||
"angelica.archaic.MixinBlockFence"
|
||||
, "angelica.archaic.MixinFMLClientHandler"
|
||||
, "angelica.archaic.MixinGuiIngameForge"
|
||||
, "angelica.archaic.MixinNetHandlerPlayClient"
|
||||
, "angelica.archaic.MixinThreadDownloadImageData"
|
||||
)
|
||||
),
|
||||
|
||||
IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses(
|
||||
"shaders.startup.MixinGameSettings"
|
||||
,"shaders.startup.MixinGuiMainMenu"
|
||||
,"shaders.startup.MixinInitRenderer"
|
||||
,"shaders.startup.MixinAbstractTexture"
|
||||
,"shaders.startup.MixinTextureAtlasSprite"
|
||||
,"shaders.startup.MixinTextureMap"
|
||||
IRIS_STARTUP(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addClientMixins(
|
||||
"shaders.startup.MixinGameSettings"
|
||||
, "shaders.startup.MixinMinecraft"
|
||||
, "shaders.startup.MixinInitRenderer"
|
||||
, "shaders.startup.MixinAbstractTexture"
|
||||
, "shaders.startup.MixinTextureAtlasSprite"
|
||||
, "shaders.startup.MixinTextureMap"
|
||||
)
|
||||
),
|
||||
|
||||
SODIUM(new Builder("Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodium).addMixinClasses(
|
||||
"sodium.MixinBlock"
|
||||
,"sodium.MixinBlockFluidBase"
|
||||
,"sodium.AccessorBiomeColorEvent"
|
||||
,"sodium.MixinBiomeGenBase"
|
||||
,"sodium.MixinChunk"
|
||||
,"sodium.MixinChunkProviderServer"
|
||||
,"sodium.MixinClientRegistry"
|
||||
,"sodium.MixinEntity_RenderDist"
|
||||
,"sodium.MixinEntityItem_RenderDist"
|
||||
,"sodium.MixinRenderManager"
|
||||
,"sodium.MixinExtendedBlockStorage"
|
||||
,"sodium.MixinEntityRenderer"
|
||||
,"sodium.MixinFMLClientHandler"
|
||||
,"sodium.MixinForgeHooksClient"
|
||||
,"sodium.MixinGameSettings"
|
||||
,"sodium.MixinFrustrum"
|
||||
,"sodium.MixinMaterial"
|
||||
,"sodium.MixinMinecraft"
|
||||
,"sodium.MixinNibbleArray"
|
||||
,"sodium.MixinRenderBlocks"
|
||||
,"sodium.MixinRenderGlobal"
|
||||
,"sodium.MixinWorldClient"
|
||||
,"sodium.MixinTileEntity"
|
||||
,"sodium.MixinEffectRenderer"
|
||||
,"sodium.MixinTileEntityRendererDispatcher"
|
||||
,"sodium.MixinLongHashMap"
|
||||
,"sodium.MixinRenderingRegistry"
|
||||
,"sodium.MixinPlayerManager"
|
||||
SODIUM(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableSodium)
|
||||
.addClientMixins(
|
||||
"sodium.MixinBlock"
|
||||
, "sodium.MixinBlockFluidBase"
|
||||
, "sodium.AccessorBiomeColorEvent"
|
||||
, "sodium.MixinBiomeGenBase"
|
||||
, "sodium.MixinChunk"
|
||||
, "sodium.MixinChunkProviderServer"
|
||||
, "sodium.MixinClientRegistry"
|
||||
, "sodium.MixinEntity_RenderDist"
|
||||
, "sodium.MixinEntityItem_RenderDist"
|
||||
, "sodium.MixinRenderManager"
|
||||
, "sodium.MixinEntityRenderer"
|
||||
, "sodium.MixinFMLClientHandler"
|
||||
, "sodium.MixinForgeHooksClient"
|
||||
, "sodium.MixinGameSettings"
|
||||
, "sodium.MixinFrustrum"
|
||||
, "sodium.MixinMinecraft"
|
||||
, "sodium.MixinRenderBlocks"
|
||||
, "sodium.MixinRenderGlobal"
|
||||
, "sodium.MixinWorldClient"
|
||||
, "sodium.MixinTileEntity"
|
||||
, "sodium.MixinTileEntityMobSpawner"
|
||||
, "sodium.MixinEffectRenderer"
|
||||
, "sodium.MixinTileEntityRendererDispatcher"
|
||||
, "sodium.MixinLongHashMap"
|
||||
, "sodium.MixinRenderingRegistry"
|
||||
, "sodium.MixinPlayerManager"
|
||||
)
|
||||
),
|
||||
|
||||
IRIS_RENDERING(new Builder("Iris Shaders").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses(
|
||||
"shaders.MixinEntityRenderer"
|
||||
,"shaders.MixinGuiIngameForge"
|
||||
,"shaders.MixinFramebuffer"
|
||||
,"shaders.MixinItem"
|
||||
,"shaders.MixinItemRenderer"
|
||||
,"shaders.MixinLocale"
|
||||
,"shaders.MixinOpenGlHelper"
|
||||
,"shaders.MixinRender"
|
||||
,"shaders.MixinRendererLivingEntity"
|
||||
,"shaders.MixinRenderGlobal"
|
||||
,"shaders.MixinTileEntityBeaconRenderer"
|
||||
IRIS_SHADERS(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addClientMixins(
|
||||
"shaders.MixinEntityRenderer"
|
||||
, "shaders.MixinGuiIngameForge"
|
||||
, "shaders.MixinFramebuffer"
|
||||
, "shaders.MixinItem"
|
||||
, "shaders.MixinLocale"
|
||||
, "shaders.MixinOpenGlHelper"
|
||||
, "shaders.MixinRender"
|
||||
, "shaders.MixinRendererLivingEntity"
|
||||
, "shaders.MixinRenderGlobal"
|
||||
, "shaders.MixinTileEntityBeaconRenderer"
|
||||
)
|
||||
),
|
||||
|
||||
IRIS_ACCESSORS(new Builder("Iris Accessors").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses(
|
||||
"shaders.accessors.MixinMinecraft"
|
||||
,"shaders.accessors.MixinEntityRenderer"
|
||||
,"shaders.accessors.MixinSimpleTexture"
|
||||
,"shaders.accessors.MixinTextureAtlasSprite"
|
||||
,"shaders.accessors.MixinTextureMap"
|
||||
,"shaders.accessors.MixinAnimationMetadataSection"
|
||||
IRIS_RENDERING_NOBACKHAND(new MixinBuilder("Iris Hand Shaders")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addExcludedMod(TargetedMod.BACKHAND)
|
||||
.addClientMixins(
|
||||
"shaders.MixinItemRenderer"
|
||||
)
|
||||
),
|
||||
|
||||
ANGELICA_TEXTURE(new Builder("Textures").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris || AngelicaConfig.enableSodium).addMixinClasses(
|
||||
"angelica.textures.MixinTextureAtlasSprite"
|
||||
,"angelica.textures.MixinTextureUtil"
|
||||
IRIS_RENDERING_BACKHAND(new MixinBuilder("Iris Hand Shaders (Backhand)")
|
||||
.addRequiredMod(TargetedMod.BACKHAND)
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addClientMixins(
|
||||
"shaders.MixinItemRendererBackhand"
|
||||
)
|
||||
),
|
||||
|
||||
ANGELICA_TEXTURE(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris || AngelicaConfig.enableSodium)
|
||||
.addClientMixins(
|
||||
"angelica.textures.MixinTextureAtlasSprite"
|
||||
, "angelica.textures.MixinTextureUtil"
|
||||
)),
|
||||
|
||||
ANGELICA_ZOOM(new Builder("Zoom").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
|
||||
.setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableZoom)
|
||||
.addMixinClasses(
|
||||
ANGELICA_ZOOM(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableZoom)
|
||||
.addClientMixins(
|
||||
"angelica.zoom.MixinEntityRenderer_Zoom",
|
||||
"angelica.zoom.MixinMinecraft_Zoom",
|
||||
"angelica.zoom.MixinMouseFilter"
|
||||
)),
|
||||
|
||||
HUD_CACHING(new Builder("Renders the HUD elements 20 times per second maximum to improve performance")
|
||||
.addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableHudCaching).addMixinClasses(
|
||||
"angelica.hudcaching.MixinGuiIngame",
|
||||
"angelica.hudcaching.MixinGuiIngameForge",
|
||||
HUD_CACHING(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableHudCaching)
|
||||
.addClientMixins(
|
||||
"angelica.hudcaching.MixinGuiIngame",
|
||||
"angelica.hudcaching.MixinGuiIngameForge",
|
||||
"angelica.hudcaching.MixinRenderGameOverlayEvent",
|
||||
"angelica.hudcaching.MixinEntityRenderer_HUDCaching",
|
||||
"angelica.hudcaching.MixinFramebuffer_HUDCaching",
|
||||
"angelica.hudcaching.MixinGuiIngame_HUDCaching",
|
||||
"angelica.hudcaching.MixinGuiIngameForge_HUDCaching",
|
||||
"angelica.hudcaching.MixinRenderItem")
|
||||
|
||||
),
|
||||
|
||||
OPTIMIZE_WORLD_UPDATE_LIGHT(new Builder("Optimize world updateLightByType method").setPhase(Phase.EARLY)
|
||||
.setSide(Side.BOTH).addTargetedMod(TargetedMod.VANILLA).addExcludedMod(TargetedMod.ARCHAICFIX).setApplyIf(() -> AngelicaConfig.optimizeWorldUpdateLight)
|
||||
.addMixinClasses("angelica.lighting.MixinWorld_FixLightUpdateLag")),
|
||||
OPTIMIZE_WORLD_UPDATE_LIGHT(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.addExcludedMod(TargetedMod.ARCHAICFIX)
|
||||
.setApplyIf(() -> AngelicaConfig.optimizeWorldUpdateLight)
|
||||
.addCommonMixins("angelica.lighting.MixinWorld_FixLightUpdateLag")),
|
||||
|
||||
|
||||
SPEEDUP_VANILLA_ANIMATIONS(new Builder("Speedup Vanilla Animations").setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.speedupAnimations).setSide(Side.CLIENT).addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses(
|
||||
SPEEDUP_VANILLA_ANIMATIONS(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.speedupAnimations)
|
||||
.addClientMixins(
|
||||
"angelica.animation.MixinTextureAtlasSprite",
|
||||
"angelica.animation.MixinTextureMap",
|
||||
"angelica.animation.MixinBlockFire",
|
||||
@@ -218,38 +248,57 @@ public enum Mixins {
|
||||
"angelica.animation.MixinWorldRenderer",
|
||||
"angelica.animation.MixinRenderItem")),
|
||||
|
||||
EXTRA_UTILITIES_THREAD_SAFETY(new Builder("Enable thread safety fixes in Extra Utilities").setPhase(Phase.LATE)
|
||||
.addTargetedMod(TargetedMod.EXTRAUTILS).setSide(Side.CLIENT)
|
||||
SCALED_RESOUTION_UNICODE_FIX(new MixinBuilder("Removes unicode languages gui scaling being forced to even values")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.removeUnicodeEvenScaling)
|
||||
.addClientMixins("angelica.bugfixes.MixinScaledResolution_UnicodeFix")),
|
||||
|
||||
SECURITYCRAFT_COMPAT(new MixinBuilder("Fix reflection in SecurityCraft for compat with Angelica")
|
||||
.setPhase(Phase.LATE)
|
||||
.addRequiredMod(TargetedMod.SECURITYCRAFT)
|
||||
.setApplyIf(() -> CompatConfig.fixSecurityCraft)
|
||||
.addClientMixins(
|
||||
"client.securitycraft.MixinBlockReinforcedFenceGate",
|
||||
"client.securitycraft.MixinBlockReinforcedIronBars"
|
||||
)),
|
||||
|
||||
EXTRA_UTILITIES_THREAD_SAFETY(new MixinBuilder("Enable thread safety fixes in Extra Utilities")
|
||||
.setPhase(Phase.LATE)
|
||||
.addRequiredMod(TargetedMod.EXTRAUTILS)
|
||||
.setApplyIf(() -> CompatConfig.fixExtraUtils)
|
||||
.addMixinClasses(
|
||||
.addClientMixins(
|
||||
"client.extrautils.MixinRenderBlockConnectedTextures",
|
||||
"client.extrautils.MixinRenderBlockConnectedTexturesEthereal",
|
||||
"client.extrautils.MixinIconConnectedTexture")),
|
||||
|
||||
MFR_THREAD_SAFETY(new Builder("Enable thread safety fixes for MineFactory Reloaded").setPhase(Phase.LATE)
|
||||
.addTargetedMod(TargetedMod.MINEFACTORY_RELOADED).setSide(Side.CLIENT)
|
||||
.setApplyIf(() -> CompatConfig.fixMinefactoryReloaded)
|
||||
.addMixinClasses("client.minefactoryreloaded.MixinRedNetCableRenderer")),
|
||||
MFR_THREAD_SAFETY(new MixinBuilder("Enable thread safety fixes for MineFactory Reloaded")
|
||||
.setPhase(Phase.LATE)
|
||||
.addRequiredMod(TargetedMod.MINEFACTORY_RELOADED)
|
||||
.setApplyIf(() -> CompatConfig.fixMinefactoryReloaded)
|
||||
.addClientMixins("client.minefactoryreloaded.MixinRedNetCableRenderer")),
|
||||
|
||||
SPEEDUP_CAMPFIRE_BACKPORT_ANIMATIONS(new Builder("Add animation speedup support to Campfire Backport").setPhase(Phase.LATE)
|
||||
.addTargetedMod(TargetedMod.CAMPFIRE_BACKPORT).setSide(Side.CLIENT)
|
||||
.setApplyIf(() -> AngelicaConfig.speedupAnimations)
|
||||
.addMixinClasses("client.campfirebackport.MixinRenderBlockCampfire")),
|
||||
SPEEDUP_CAMPFIRE_BACKPORT_ANIMATIONS(new MixinBuilder("Add animation speedup support to Campfire Backport")
|
||||
.setPhase(Phase.LATE)
|
||||
.addRequiredMod(TargetedMod.CAMPFIRE_BACKPORT)
|
||||
.setApplyIf(() -> AngelicaConfig.speedupAnimations)
|
||||
.addClientMixins("client.campfirebackport.MixinRenderBlockCampfire")),
|
||||
|
||||
IC2_FLUID_RENDER_FIX(new Builder("IC2 Fluid Render Fix").setPhase(Phase.EARLY).setSide(Side.CLIENT)
|
||||
.addTargetedMod(TargetedMod.IC2).setApplyIf(() -> AngelicaConfig.speedupAnimations)
|
||||
.addMixinClasses("angelica.textures.ic2.MixinRenderLiquidCell")),
|
||||
IC2_FLUID_RENDER_FIX(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.addRequiredMod(TargetedMod.IC2)
|
||||
.setApplyIf(() -> AngelicaConfig.speedupAnimations)
|
||||
.addClientMixins("angelica.textures.ic2.MixinRenderLiquidCell")),
|
||||
|
||||
OPTIMIZE_TEXTURE_LOADING(new Builder("Optimize Texture Loading").setPhase(Phase.EARLY)
|
||||
.addMixinClasses("angelica.textures.MixinTextureUtil_OptimizeMipmap").addTargetedMod(TargetedMod.VANILLA)
|
||||
.setApplyIf(() -> AngelicaConfig.optimizeTextureLoading).setSide(Side.CLIENT)),
|
||||
OPTIMIZE_TEXTURE_LOADING(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.addClientMixins("angelica.textures.MixinTextureUtil_OptimizeMipmap")
|
||||
.setApplyIf(() -> AngelicaConfig.optimizeTextureLoading)),
|
||||
|
||||
//From NotFine
|
||||
NOTFINE_BASE_MOD(new Builder("NotFine")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
NOTFINE_BASE_MOD(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableNotFineFeatures)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses(addPrefix("notfine.",
|
||||
.addClientMixins(addPrefix("notfine.",
|
||||
"clouds.MixinEntityRenderer",
|
||||
"clouds.MixinGameSettings",
|
||||
//"clouds.MixinRenderGlobal",
|
||||
@@ -281,11 +330,10 @@ public enum Mixins {
|
||||
"interpolatedtexturemap.MixinTextureMap"
|
||||
))
|
||||
),
|
||||
BETTER_FACE_CULLING(new Builder("Better face culling")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
BETTER_FACE_CULLING(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> NotFineConfig.betterBlockFaceCulling)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses(addPrefix("notfine.faceculling.",
|
||||
.addClientMixins(addPrefix("notfine.faceculling.",
|
||||
"MixinBlock",
|
||||
"MixinBlockCactus",
|
||||
"MixinBlockCarpet",
|
||||
@@ -297,103 +345,94 @@ public enum Mixins {
|
||||
"MixinRenderBlocks"
|
||||
))
|
||||
),
|
||||
NOTFINE_NO_DYNAMIC_SURROUNDINGS(new Builder("NotFine no Dynamic Surroundings")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> true)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
NOTFINE_NO_DYNAMIC_SURROUNDINGS(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.addExcludedMod(TargetedMod.DYNAMIC_SURROUNDINGS_MIST)
|
||||
.addExcludedMod(TargetedMod.DYNAMIC_SURROUNDINGS_ORIGINAL)
|
||||
.addMixinClasses("notfine.toggle.MixinEntityRenderer$RenderRainSnow")
|
||||
.addClientMixins("notfine.toggle.MixinEntityRenderer$RenderRainSnow")
|
||||
),
|
||||
NOTFINE_NO_CUSTOM_ITEM_TEXTURES(new Builder("NotFine no Custom Item Textures")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
NOTFINE_NO_CUSTOM_ITEM_TEXTURES(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> !AngelicaConfig.enableMCPatcherForgeFeatures || !MCPatcherForgeConfig.CustomItemTextures.enabled)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses(addPrefix("notfine.glint.",
|
||||
.addClientMixins(addPrefix("notfine.glint.",
|
||||
"MixinItemRenderer",
|
||||
"MixinRenderItem"
|
||||
))
|
||||
),
|
||||
NOTFINE_NATURA(new Builder("NotFine Natura compat")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.LATE)
|
||||
NOTFINE_NATURA_COMPAT(new MixinBuilder()
|
||||
.setPhase(Phase.LATE)
|
||||
.setApplyIf(() -> AngelicaConfig.enableNotFineFeatures)
|
||||
.addTargetedMod(TargetedMod.NATURA)
|
||||
.addMixinClasses(addPrefix("notfine.leaves.natura.",
|
||||
.addRequiredMod(TargetedMod.NATURA)
|
||||
.addClientMixins(addPrefix("notfine.leaves.natura.",
|
||||
"MixinBerryBush",
|
||||
"MixinNetherBerryBush"
|
||||
))
|
||||
),
|
||||
NOTFINE_THAUMCRAFT(new Builder("NotFine Thaumcraft compat")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.LATE)
|
||||
NOTFINE_THAUMCRAFT_COMPAT(new MixinBuilder()
|
||||
.setPhase(Phase.LATE)
|
||||
.setApplyIf(() -> AngelicaConfig.enableNotFineFeatures)
|
||||
.addTargetedMod(TargetedMod.THAUMCRAFT)
|
||||
.addMixinClasses("notfine.leaves.thaumcraft.MixinBlockMagicalLeaves")
|
||||
.addRequiredMod(TargetedMod.THAUMCRAFT)
|
||||
.addClientMixins("notfine.leaves.thaumcraft.MixinBlockMagicalLeaves")
|
||||
),
|
||||
THAUMCRAFT_BETTER_FACE_CULLING(new Builder("Better face culling Thaumcraft compat")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.LATE)
|
||||
THAUMCRAFT_BETTER_FACE_CULLING(new MixinBuilder()
|
||||
.setPhase(Phase.LATE)
|
||||
.setApplyIf(() -> NotFineConfig.betterBlockFaceCulling)
|
||||
.addTargetedMod(TargetedMod.THAUMCRAFT)
|
||||
.addMixinClasses(addPrefix("notfine.faceculling.thaumcraft.",
|
||||
.addRequiredMod(TargetedMod.THAUMCRAFT)
|
||||
.addClientMixins(addPrefix("notfine.faceculling.thaumcraft.",
|
||||
"MixinBlockWoodenDevice",
|
||||
"MixinBlockStoneDevice",
|
||||
"MixinBlockTable"
|
||||
))
|
||||
),
|
||||
NOTFINE_TINKERS_CONSTRUCT(new Builder("NotFine Tinker's Construct compat")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.LATE)
|
||||
NOTFINE_TINKERS_CONSTRUCT_COMPAT(new MixinBuilder()
|
||||
.setPhase(Phase.LATE)
|
||||
.setApplyIf(() -> AngelicaConfig.enableNotFineFeatures)
|
||||
.addTargetedMod(TargetedMod.TINKERS_CONSTRUCT)
|
||||
.addMixinClasses("notfine.leaves.tconstruct.MixinOreberryBush")
|
||||
.addRequiredMod(TargetedMod.TINKERS_CONSTRUCT)
|
||||
.addClientMixins("notfine.leaves.tconstruct.MixinOreberryBush")
|
||||
),
|
||||
NOTFINE_WITCHERY(new Builder("NotFine Witchery compat")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.LATE)
|
||||
NOTFINE_WITCHERY_COMPAT(new MixinBuilder()
|
||||
.setPhase(Phase.LATE)
|
||||
.setApplyIf(() -> AngelicaConfig.enableNotFineFeatures)
|
||||
.addTargetedMod(TargetedMod.WITCHERY)
|
||||
.addMixinClasses("notfine.leaves.witchery.MixinBlockWitchLeaves")
|
||||
.addRequiredMod(TargetedMod.WITCHERY)
|
||||
.addClientMixins("notfine.leaves.witchery.MixinBlockWitchLeaves")
|
||||
),
|
||||
NOTFINE_TWILIGHT_FOREST(new Builder("NotFine Twilight Forest compat")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.LATE)
|
||||
NOTFINE_TWILIGHT_FOREST_COMPAT(new MixinBuilder()
|
||||
.setPhase(Phase.LATE)
|
||||
.setApplyIf(() -> AngelicaConfig.enableNotFineFeatures)
|
||||
.addTargetedMod(TargetedMod.TWILIGHT_FOREST)
|
||||
.addMixinClasses(addPrefix("notfine.leaves.twilightforest.",
|
||||
.addRequiredMod(TargetedMod.TWILIGHT_FOREST)
|
||||
.addClientMixins(addPrefix("notfine.leaves.twilightforest.",
|
||||
"MixinBlockTFLeaves",
|
||||
"MixinBlockTFLeaves3",
|
||||
// TODO: Verify 2.3.8.18 or later to support non NH builds?
|
||||
"MixinBlockTFMagicLeaves"
|
||||
))
|
||||
),
|
||||
MCPATCHER_FORGE(new Builder("MCPatcher Forge")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
MCPATCHER_FORGE(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses(addPrefix("mcpatcherforge.",
|
||||
.addClientMixins(addPrefix("mcpatcherforge.",
|
||||
"base.MixinBlockGrass",
|
||||
"base.MixinBlockMycelium",
|
||||
|
||||
"base.MixinAbstractTexture",
|
||||
"base.MixinTextureAtlasSprite",
|
||||
|
||||
"base.MixinSimpleReloadableResourceManager",
|
||||
|
||||
"base.MixinMinecraft"
|
||||
))
|
||||
),
|
||||
MCPATCHER_FORGE_RENDERPASS(new Builder("MCPatcher Forge Renderpass")
|
||||
MCPATCHER_FORGE_RENDERPASS(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> NotFineConfig.renderPass)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses(addPrefix("mcpatcherforge.",
|
||||
.addClientMixins(addPrefix("mcpatcherforge.",
|
||||
"renderpass.MixinEntityRenderer",
|
||||
"renderpass.MixinRenderBlocks",
|
||||
"renderpass.MixinRenderGlobal",
|
||||
"renderpass.MixinWorldRenderer"
|
||||
))
|
||||
),
|
||||
MCPATCHER_FORGE_CUSTOM_COLORS(new Builder("MCP:F Custom Colors")
|
||||
.setSide(Mixins.Side.CLIENT).setPhase(Phase.EARLY)
|
||||
MCPATCHER_FORGE_CUSTOM_COLORS(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures && MCPatcherForgeConfig.CustomColors.enabled)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses(addPrefix("mcpatcherforge.cc.",
|
||||
.addClientMixins(addPrefix("mcpatcherforge.cc.",
|
||||
"block.material.MixinMapColor",
|
||||
|
||||
"block.MixinBlock",
|
||||
@@ -445,11 +484,10 @@ public enum Mixins {
|
||||
"world.MixinWorldProviderHell"
|
||||
))
|
||||
),
|
||||
MCPATCHER_FORGE_CUSTOM_ITEM_TEXTURES(new Builder("MCP:F Custom Item Textures")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
MCPATCHER_FORGE_CUSTOM_ITEM_TEXTURES(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures && MCPatcherForgeConfig.CustomItemTextures.enabled)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses(addPrefix("mcpatcherforge.cit.",
|
||||
.addClientMixins(addPrefix("mcpatcherforge.cit.",
|
||||
"client.renderer.entity.MixinRenderBiped",
|
||||
"client.renderer.entity.MixinRenderEntityLiving",
|
||||
"client.renderer.entity.MixinRenderItem",
|
||||
@@ -464,34 +502,30 @@ public enum Mixins {
|
||||
"world.MixinWorld"
|
||||
))
|
||||
),
|
||||
MCPATCHER_FORGE_CONNECTED_TEXTURES(new Builder("MCP:F Connected Textures")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
MCPATCHER_FORGE_CONNECTED_TEXTURES(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures && MCPatcherForgeConfig.ConnectedTextures.enabled)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses("mcpatcherforge.ctm.MixinRenderBlocks")
|
||||
.addClientMixins("mcpatcherforge.ctm.MixinRenderBlocks")
|
||||
),
|
||||
MCPATCHER_FORGE_EXTENDED_HD(new Builder("MCP:F Extended hd")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
MCPATCHER_FORGE_EXTENDED_HD(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures && MCPatcherForgeConfig.ExtendedHD.enabled)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses(addPrefix("mcpatcherforge.hd.",
|
||||
.addClientMixins(addPrefix("mcpatcherforge.hd.",
|
||||
"MixinTextureClock",
|
||||
"MixinTextureCompass",
|
||||
"MixinTextureManager"
|
||||
))
|
||||
),
|
||||
MCPATCHER_FORGE_EXTENDED_HD_FONT(new Builder("MCP:F Extended HD Font")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
MCPATCHER_FORGE_EXTENDED_HD_FONT(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> (AngelicaConfig.enableMCPatcherForgeFeatures && MCPatcherForgeConfig.ExtendedHD.enabled && MCPatcherForgeConfig.ExtendedHD.hdFont))
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addExcludedMod(TargetedMod.COFHCORE)
|
||||
.addMixinClasses("mcpatcherforge.hd.MixinFontRenderer")
|
||||
.addClientMixins("mcpatcherforge.hd.MixinFontRenderer")
|
||||
),
|
||||
MCPATCHER_FORGE_RANDOM_MOBS(new Builder("MCP:F Random Mobs")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
MCPATCHER_FORGE_RANDOM_MOBS(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures && MCPatcherForgeConfig.RandomMobs.enabled)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses(addPrefix("mcpatcherforge.mob.",
|
||||
.addClientMixins(addPrefix("mcpatcherforge.mob.",
|
||||
"MixinRender",
|
||||
"MixinRenderEnderman",
|
||||
"MixinRenderFish",
|
||||
@@ -504,220 +538,59 @@ public enum Mixins {
|
||||
"MixinEntityLivingBase"
|
||||
))
|
||||
),
|
||||
MCPATCHER_FORGE_SKY(new Builder("MCP:F Sky")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
MCPATCHER_FORGE_SKY(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures && MCPatcherForgeConfig.BetterSkies.enabled)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses(addPrefix("mcpatcherforge.sky.",
|
||||
.addClientMixins(addPrefix("mcpatcherforge.sky.",
|
||||
"MixinEffectRenderer",
|
||||
"MixinRenderGlobal"
|
||||
))
|
||||
),
|
||||
MCPATCHER_FORGE_CC_NO_CTM(new Builder("MCP:F Custom Colors, no Connected Textures")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
MCPATCHER_FORGE_CC_NO_CTM(new MixinBuilder("MCP:F Custom Colors, no Connected Textures")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures
|
||||
&& !MCPatcherForgeConfig.ConnectedTextures.enabled
|
||||
&& MCPatcherForgeConfig.CustomColors.enabled)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses("mcpatcherforge.cc_ctm.MixinRenderBlocksNoCTM")
|
||||
&& !MCPatcherForgeConfig.ConnectedTextures.enabled
|
||||
&& MCPatcherForgeConfig.CustomColors.enabled)
|
||||
.addClientMixins("mcpatcherforge.ctm_cc.MixinRenderBlocksNoCTM")
|
||||
),
|
||||
MCPATCHER_FORGE_CTM_NO_CC(new Builder("MCP:F Connected Textures, no Custom Colours")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
MCPATCHER_FORGE_CTM_NO_CC(new MixinBuilder("MCP:F Connected Textures, no Custom Colours")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures
|
||||
&& MCPatcherForgeConfig.ConnectedTextures.enabled
|
||||
&& !MCPatcherForgeConfig.CustomColors.enabled)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses("mcpatcherforge.ctm_cc.MixinRenderBlocksNoCC")
|
||||
&& MCPatcherForgeConfig.ConnectedTextures.enabled
|
||||
&& !MCPatcherForgeConfig.CustomColors.enabled)
|
||||
.addClientMixins("mcpatcherforge.ctm_cc.MixinRenderBlocksNoCC")
|
||||
),
|
||||
MCPATCHER_FORGE_CTM_AND_CC(new Builder("MCP:F Connected Textures and Custom Colors")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
MCPATCHER_FORGE_CTM_AND_CC(new MixinBuilder("MCP:F Connected Textures and Custom Colors")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures
|
||||
&& MCPatcherForgeConfig.ConnectedTextures.enabled
|
||||
&& MCPatcherForgeConfig.CustomColors.enabled)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses("mcpatcherforge.ctm_cc.MixinRenderBlocks")
|
||||
&& MCPatcherForgeConfig.ConnectedTextures.enabled
|
||||
&& MCPatcherForgeConfig.CustomColors.enabled)
|
||||
.addClientMixins("mcpatcherforge.ctm_cc.MixinRenderBlocks")
|
||||
),
|
||||
MCPATCHER_FORGE_CTM_OR_CC(new Builder("MCP:F Connected Textures or Custom Colors")
|
||||
.setSide(Side.CLIENT).setPhase(Phase.EARLY)
|
||||
MCPATCHER_FORGE_CTM_OR_CC(new MixinBuilder("MCP:F Connected Textures or Custom Colors")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures
|
||||
&& MCPatcherForgeConfig.ConnectedTextures.enabled
|
||||
|| MCPatcherForgeConfig.CustomColors.enabled)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses("mcpatcherforge.ctm_cc.MixinTextureMap")
|
||||
&& MCPatcherForgeConfig.ConnectedTextures.enabled
|
||||
|| MCPatcherForgeConfig.CustomColors.enabled)
|
||||
.addClientMixins("mcpatcherforge.ctm_cc.MixinTextureMap")
|
||||
),
|
||||
//End from NotFine
|
||||
|
||||
QPR(new Builder("Adds a QuadProvider field to blocks without populating it")
|
||||
.setSide(Side.CLIENT)
|
||||
QPR(new MixinBuilder("Adds a QuadProvider field to blocks without populating it")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> true)
|
||||
.addTargetedMod(TargetedMod.VANILLA)
|
||||
.addMixinClasses(
|
||||
.addClientMixins(
|
||||
"angelica.models.MixinBlock",
|
||||
"angelica.models.MixinBlockOldLeaf")),
|
||||
|
||||
;
|
||||
|
||||
private final List<String> mixinClasses;
|
||||
private final Supplier<Boolean> applyIf;
|
||||
private final Phase phase;
|
||||
private final Side side;
|
||||
private final List<TargetedMod> targetedMods;
|
||||
private final List<TargetedMod> excludedMods;
|
||||
private final MixinBuilder builder;
|
||||
|
||||
Mixins(Builder builder) {
|
||||
this.mixinClasses = builder.mixinClasses;
|
||||
this.applyIf = builder.applyIf;
|
||||
this.side = builder.side;
|
||||
this.targetedMods = builder.targetedMods;
|
||||
this.excludedMods = builder.excludedMods;
|
||||
this.phase = builder.phase;
|
||||
if (this.targetedMods.isEmpty()) {
|
||||
throw new RuntimeException("No targeted mods specified for " + this.name());
|
||||
}
|
||||
if (this.applyIf == null) {
|
||||
throw new RuntimeException("No ApplyIf function specified for " + this.name());
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getEarlyMixins(Set<String> loadedCoreMods) {
|
||||
NotFineConfig.loadSettings();
|
||||
//This may be possible to handle differently or fix.
|
||||
if(loadedCoreMods.contains("cofh.asm.LoadingPlugin")) {
|
||||
MCPatcherForgeConfig.ExtendedHD.hdFont = false;
|
||||
}
|
||||
final List<String> mixins = new ArrayList<>();
|
||||
final List<String> notLoading = new ArrayList<>();
|
||||
for (Mixins mixin : Mixins.values()) {
|
||||
if (mixin.phase == Mixins.Phase.EARLY) {
|
||||
if (mixin.shouldLoad(loadedCoreMods, Collections.emptySet())) {
|
||||
mixins.addAll(mixin.mixinClasses);
|
||||
} else {
|
||||
notLoading.addAll(mixin.mixinClasses);
|
||||
}
|
||||
}
|
||||
}
|
||||
AngelicaTweaker.LOGGER.info("Not loading the following EARLY mixins: {}", notLoading);
|
||||
return mixins;
|
||||
}
|
||||
|
||||
public static List<String> getLateMixins(Set<String> loadedMods) {
|
||||
final List<String> mixins = new ArrayList<>();
|
||||
final List<String> notLoading = new ArrayList<>();
|
||||
for (Mixins mixin : Mixins.values()) {
|
||||
if (mixin.phase == Mixins.Phase.LATE) {
|
||||
if (mixin.shouldLoad(Collections.emptySet(), loadedMods)) {
|
||||
mixins.addAll(mixin.mixinClasses);
|
||||
} else {
|
||||
notLoading.addAll(mixin.mixinClasses);
|
||||
}
|
||||
}
|
||||
}
|
||||
AngelicaTweaker.LOGGER.info("Not loading the following LATE mixins: {}", notLoading.toString());
|
||||
return mixins;
|
||||
}
|
||||
|
||||
private boolean shouldLoadSide() {
|
||||
return side == Side.BOTH || (side == Side.SERVER && FMLLaunchHandler.side().isServer())
|
||||
|| (side == Side.CLIENT && FMLLaunchHandler.side().isClient());
|
||||
}
|
||||
|
||||
private boolean allModsLoaded(List<TargetedMod> targetedMods, Set<String> loadedCoreMods, Set<String> loadedMods) {
|
||||
if (targetedMods.isEmpty()) return false;
|
||||
|
||||
for (TargetedMod target : targetedMods) {
|
||||
if (target == TargetedMod.VANILLA) continue;
|
||||
|
||||
// Check coremod first
|
||||
if (!loadedCoreMods.isEmpty() && target.coreModClass != null
|
||||
&& !loadedCoreMods.contains(target.coreModClass))
|
||||
return false;
|
||||
else if (!loadedMods.isEmpty() && target.modId != null && !loadedMods.contains(target.modId)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean noModsLoaded(List<TargetedMod> targetedMods, Set<String> loadedCoreMods, Set<String> loadedMods) {
|
||||
if (targetedMods.isEmpty()) return true;
|
||||
|
||||
for (TargetedMod target : targetedMods) {
|
||||
if (target == TargetedMod.VANILLA) continue;
|
||||
|
||||
// Check coremod first
|
||||
if (!loadedCoreMods.isEmpty() && target.coreModClass != null
|
||||
&& loadedCoreMods.contains(target.coreModClass))
|
||||
return false;
|
||||
else if (!loadedMods.isEmpty() && target.modId != null && loadedMods.contains(target.modId)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean shouldLoad(Set<String> loadedCoreMods, Set<String> loadedMods) {
|
||||
return (shouldLoadSide() && applyIf.get()
|
||||
&& allModsLoaded(targetedMods, loadedCoreMods, loadedMods)
|
||||
&& noModsLoaded(excludedMods, loadedCoreMods, loadedMods));
|
||||
}
|
||||
|
||||
private static class Builder {
|
||||
|
||||
private final List<String> mixinClasses = new ArrayList<>();
|
||||
private Supplier<Boolean> applyIf = () -> true;
|
||||
private Side side = Side.BOTH;
|
||||
private Phase phase = Phase.LATE;
|
||||
private final List<TargetedMod> targetedMods = new ArrayList<>();
|
||||
private final List<TargetedMod> excludedMods = new ArrayList<>();
|
||||
|
||||
public Builder(@SuppressWarnings("unused") String description) {}
|
||||
|
||||
public Builder addMixinClasses(String... mixinClasses) {
|
||||
this.mixinClasses.addAll(Arrays.asList(mixinClasses));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPhase(Phase phase) {
|
||||
this.phase = phase;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSide(Side side) {
|
||||
this.side = side;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setApplyIf(Supplier<Boolean> applyIf) {
|
||||
this.applyIf = applyIf;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addTargetedMod(TargetedMod mod) {
|
||||
this.targetedMods.add(mod);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addExcludedMod(TargetedMod mod) {
|
||||
this.excludedMods.add(mod);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("SimplifyStreamApiCallChains")
|
||||
private static String[] addPrefix(String prefix, String... values) {
|
||||
return Arrays.stream(values)
|
||||
.map(s -> prefix + s)
|
||||
.collect(Collectors.toList())
|
||||
.toArray(new String[values.length]);
|
||||
}
|
||||
|
||||
private enum Side {
|
||||
BOTH,
|
||||
CLIENT,
|
||||
SERVER
|
||||
}
|
||||
|
||||
private enum Phase {
|
||||
EARLY,
|
||||
LATE,
|
||||
List<String> list = new ArrayList<>(values.length);
|
||||
for (String s : values) {
|
||||
list.add(prefix + s);
|
||||
}
|
||||
return list.toArray(new String[values.length]);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,31 @@
|
||||
package com.gtnewhorizons.angelica.mixins;
|
||||
|
||||
import com.gtnewhorizon.gtnhmixins.builders.ITargetMod;
|
||||
import com.gtnewhorizon.gtnhmixins.builders.TargetModBuilder;
|
||||
import lombok.Getter;
|
||||
|
||||
public enum TargetedMod {
|
||||
@Getter
|
||||
public enum TargetedMod implements ITargetMod {
|
||||
|
||||
VANILLA("Minecraft", null)
|
||||
, FASTCRAFT("FastCraft", "fastcraft.Tweaker")
|
||||
, OPTIFINE("Optifine", "optifine.OptiFineForgeTweaker", "Optifine")
|
||||
, ARCHAICFIX("ArchaicFix", "org.embeddedt.archaicfix.ArchaicCore", "archaicfix")
|
||||
, BOTANIA("Botania", null, "Botania")
|
||||
, CAMPFIRE_BACKPORT("CampfireBackport", null, "campfirebackport")
|
||||
, CHICKENCHUNKS("ChickenChunks", null, "ChickenChunks")
|
||||
, COFHCORE("CoFHCore", "cofh.asm.LoadingPlugin", "CoFHCore")
|
||||
, DYNAMIC_SURROUNDINGS_MIST("Dynamic Surroundings", "org.blockartistry.mod.DynSurround.mixinplugin.DynamicSurroundingsEarlyMixins", "dsurround")
|
||||
, DYNAMIC_SURROUNDINGS_ORIGINAL("Dynamic Surroundings", "org.blockartistry.mod.DynSurround.asm.TransformLoader", "dsurround")
|
||||
, EXTRAUTILS("ExtraUtilities", null, "ExtraUtilities")
|
||||
, MINEFACTORY_RELOADED("MineFactory Reloaded", null, "MineFactoryReloaded")
|
||||
, GTNHLIB("GTNHLib", "com.gtnewhorizon.gtnhlib.core.GTNHLibCore", "gtnhlib")
|
||||
, IC2("IC2", "ic2.core.coremod.IC2core", "IC2")
|
||||
, JABBA("JABBA", null, "JABBA")
|
||||
, JOURNEYMAP("JourneyMap", null, "journeymap")
|
||||
, LWJGL3IFY("lwjgl3ify", "me.eigenraven.lwjgl3ify.core.Lwjgl3ifyCoremod", "lwjgl3ify")
|
||||
, MRTJPCORE("MrTJPCore", null, "MrTJPCoreMod")
|
||||
, NATURA("Natura", null, "Natura")
|
||||
, PROJECTRED_ILLUMINATION("ProjectRed Illumination", null, "ProjRed|Illumination")
|
||||
, SMART_RENDER("Smart Render", null, "SmartRender")
|
||||
, THAUMCRAFT("Thaumcraft", null, "Thaumcraft")
|
||||
, TINKERS_CONSTRUCT("Tinker's Construct", null, "TConstruct")
|
||||
, TWILIGHT_FOREST("TwilightForest", null, "TwilightForest")
|
||||
, WITCHERY("Witchery", null, "witchery")
|
||||
;
|
||||
ARCHAICFIX("org.embeddedt.archaicfix.ArchaicCore", "archaicfix"),
|
||||
BACKHAND("xonin.backhand.coremod.BackhandLoadingPlugin", "backhand"),
|
||||
CAMPFIRE_BACKPORT(null, "campfirebackport"),
|
||||
COFHCORE( "cofh.asm.LoadingPlugin", "CoFHCore"),
|
||||
DYNAMIC_SURROUNDINGS_MIST("org.blockartistry.mod.DynSurround.mixinplugin.DynamicSurroundingsEarlyMixins", "dsurround"),
|
||||
DYNAMIC_SURROUNDINGS_ORIGINAL("org.blockartistry.mod.DynSurround.asm.TransformLoader", "dsurround"),
|
||||
EXTRAUTILS(null, "ExtraUtilities"),
|
||||
MINEFACTORY_RELOADED(null, "MineFactoryReloaded"),
|
||||
IC2("ic2.core.coremod.IC2core", "IC2"),
|
||||
NATURA(null, "Natura"),
|
||||
SECURITYCRAFT(null, "securitycraft"),
|
||||
THAUMCRAFT(null, "Thaumcraft"),
|
||||
TINKERS_CONSTRUCT(null, "TConstruct"),
|
||||
TWILIGHT_FOREST(null, "TwilightForest"),
|
||||
WITCHERY(null, "witchery");
|
||||
|
||||
private final TargetModBuilder builder;
|
||||
|
||||
/** The "name" in the @Mod annotation */
|
||||
@Getter
|
||||
public final String modName;
|
||||
/** Class that implements the IFMLLoadingPlugin interface */
|
||||
@Getter
|
||||
public final String coreModClass;
|
||||
/** The "modid" in the @Mod annotation */
|
||||
@Getter
|
||||
public final String modId;
|
||||
|
||||
TargetedMod(String modName, String coreModClass) {
|
||||
this(modName, coreModClass, null);
|
||||
}
|
||||
|
||||
TargetedMod(String modName, String coreModClass, String modId) {
|
||||
this.modName = modName;
|
||||
this.coreModClass = coreModClass;
|
||||
this.modId = modId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TargetedMod{modName='" + modName + "', coreModClass='" + coreModClass + "', modId='" + modId + "'}";
|
||||
TargetedMod(String coreModClass, String modId) {
|
||||
this.builder = new TargetModBuilder().setCoreModClass(coreModClass).setModId(modId);
|
||||
}
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.mixins.interfaces;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
public interface AnimationMetadataSectionAccessor {
|
||||
int getFrameWidth();
|
||||
|
||||
void setFrameWidth(int frameWidth);
|
||||
|
||||
int getFrameHeight();
|
||||
|
||||
void setFrameHeight(int frameHeight);
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.mixins.interfaces;
|
||||
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
public interface ExtendedBlockStorageAccessor {
|
||||
int getYBase();
|
||||
int getBlockRefCount();
|
||||
void setBlockRefCount(int blockRefCount);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.mixins.interfaces;
|
||||
|
||||
public interface ExtendedNibbleArray {
|
||||
public byte[] getData();
|
||||
public int getDepthBits();
|
||||
public int getDepthBitsPlusFour();
|
||||
}
|
||||
@@ -8,4 +8,5 @@ public interface ITexturesCache {
|
||||
|
||||
Set<IIcon> getRenderedTextures();
|
||||
void enableTextureTracking();
|
||||
void track(IPatchedTextureAtlasSprite sprite);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.mixins.interfaces;
|
||||
|
||||
import net.minecraft.util.Timer;
|
||||
|
||||
public interface MinecraftAccessor {
|
||||
Timer getTimer();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.gtnewhorizons.angelica.mixins.interfaces;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ResourceAccessor {
|
||||
List angelica$getDefaultResourcePacks();
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.mixins.interfaces;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public interface SimpleTextureAccessor {
|
||||
ResourceLocation getLocation();
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.mixins.interfaces;
|
||||
|
||||
import net.minecraft.client.resources.data.AnimationMetadataSection;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TextureAtlasSpriteAccessor {
|
||||
AnimationMetadataSection getMetadata();
|
||||
|
||||
List<int[][]> getFramesTextureData();
|
||||
|
||||
int getFrame();
|
||||
|
||||
void setFrame(int frame);
|
||||
|
||||
int getSubFrame();
|
||||
|
||||
void setSubFrame(int subFrame);
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.mixins.interfaces;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface TextureMapAccessor {
|
||||
Map getMapUploadedSprites();
|
||||
|
||||
int getAnisotropicFiltering();
|
||||
|
||||
int getMipmapLevels();
|
||||
|
||||
ResourceLocation getLocationBlocksTexture();
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.gtnewhorizons.angelica.models;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.blockpos.BlockPos;
|
||||
import com.gtnewhorizon.gtnhlib.blockpos.IBlockPos;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.ModelLoader;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.Variant;
|
||||
|
||||
@@ -47,6 +47,7 @@ import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.network.NetHandlerPlayClient;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
import net.minecraft.server.integrated.IntegratedServer;
|
||||
import net.minecraft.util.Direction;
|
||||
@@ -152,7 +153,7 @@ public class ClientProxy extends CommonProxy {
|
||||
|
||||
@SubscribeEvent
|
||||
public void onKeypress(TickEvent.ClientTickEvent event) {
|
||||
final boolean isPressed = glsmKeyBinding.getKeyCode() != 0 && Keyboard.isKeyDown(glsmKeyBinding.getKeyCode());
|
||||
final boolean isPressed = glsmKeyBinding.getKeyCode() != 0 && GameSettings.isKeyDown(glsmKeyBinding);
|
||||
if (isPressed && !wasGLSMKeyPressed) {
|
||||
OpenGLDebugging.checkGLSM();
|
||||
}
|
||||
@@ -307,9 +308,14 @@ public class ClientProxy extends CommonProxy {
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||
public void onGuiOpen(GuiOpenEvent event) {
|
||||
if (!event.isCanceled() && event.gui instanceof GuiMainMenu && gameStartTime == -1) {
|
||||
gameStartTime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000f;
|
||||
LOGGER.info("The game loaded in {} seconds.", gameStartTime);
|
||||
if (!event.isCanceled()) {
|
||||
if (event.gui instanceof GuiMainMenu && gameStartTime == -1 ) {
|
||||
gameStartTime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000f;
|
||||
LOGGER.info("The game loaded in {} seconds.", gameStartTime);
|
||||
}
|
||||
|
||||
// force reset zoom when a GUI is opened
|
||||
if (AngelicaConfig.enableZoom && event.gui != null) Zoom.resetZoom();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -242,7 +242,8 @@ public class CloudRenderer implements IResourceManagerReloadListener {
|
||||
GraphicsQualityOff cloudGraphicsQuality = (GraphicsQualityOff)Settings.MODE_CLOUDS.option.getStore();
|
||||
final int cloudQualitySetting = cloudGraphicsQuality == GraphicsQualityOff.FANCY
|
||||
|| cloudGraphicsQuality == GraphicsQualityOff.DEFAULT && mc.gameSettings.fancyGraphics ? 2 : 1;
|
||||
final boolean newEnabled = mc.gameSettings.shouldRenderClouds()
|
||||
final boolean newEnabled = cloudGraphicsQuality != GraphicsQualityOff.OFF
|
||||
&& mc.gameSettings.shouldRenderClouds()
|
||||
&& mc.theWorld != null
|
||||
&& mc.theWorld.provider.isSurfaceWorld();
|
||||
final int targetDistance = Math.max(mc.gameSettings.renderDistanceChunks, (int)Settings.RENDER_DISTANCE_CLOUDS.option.getStore());
|
||||
|
||||
Loaded 100 of 406 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user