Compare commits

..
Author SHA1 Message Date
Eldrinn-Elantey 334ec81f9b Font rendering: configurable shadow & glyph fix (#1011) 2025-09-03 08:53:39 -07:00
Alexdoru 86c726e50b Revert "Port FIX_BLOCK_CRACK from FalseTweaks (#999)" (#1005)
This reverts commit dce5013ffb.
2025-08-16 19:09:18 -07:00
AlexdoruandJason Mitchell e6d778dad3 ASM Housekeeping (#1003)
Co-authored-by: Jason Mitchell <[email protected]>
2025-08-16 17:29:50 -07:00
Kotmatross dce5013ffb Port FIX_BLOCK_CRACK from FalseTweaks (#999) 2025-08-16 22:10:55 +00:00
glowredman 6eef63619c Update BatchingFontRenderer.java (#1002) 2025-08-10 22:27:29 +02:00
Alexdoru a8153fa0f7 remove access transformer to invoke EntityRenderer#getNightVisionBrightness (#1001) 2025-08-10 16:31:30 +00:00
Niclas Klugmann 49c04cf776 German translation (#997) 2025-07-27 20:02:26 +07:00
Alexdoru 85b0277a66 use EnumChatFormatting and not Realms enum to avoid crash (#996) 2025-07-21 10:59:04 +02:00
Alexdoru 0525b31262 Cache Tessellator#instance in local var (#995) 2025-07-18 12:44:03 -07:00
boubou19 fdb2053c50 Speed up BlockError event registration (#993) 2025-07-17 20:38:13 +02:00
Alexdoru 31abbcce32 Convert to new IMixins and MixinsBuilder system (#991) 2025-07-15 08:54:06 -07:00
063b2242e8 Initial FluidLogged compat (#985)
* Initial FluidLogged compat

* FluidLogged works(probably mostly)

* Make FluidLogged optional

* Remove a leftover print

* Fix fluidlogged fluids rendering incorrectly with shaders on

* Rmemove unused code

* Cleanup unused imports

---------

Co-authored-by: embeddedt <[email protected]>
Co-authored-by: Jason Mitchell <[email protected]>
2025-07-09 10:31:45 -04:00
Rad 577f905dc5 Update README.MD (#981) 2025-07-06 13:56:20 -07:00
Jason MitchellandAlexdoru 071d2d4a39 Add a guard to only init once (#984)
Co-authored-by: Alexdoru <[email protected]>
2025-07-01 10:33:49 -07:00
Alexdoru 891715b113 limit the amount of dropped items rendered exactly to the config value (#973) 2025-06-16 07:55:28 +02:00
jss2a98aj 30a35ef25e Misc. CTM resource tweaks 2025-06-13 18:04:31 -07:00
jss2a98aj 33453b3b8c Fix crash with OpenAutism
Brandyyn says this fixes the crash but I have not tested it myself.
2025-06-13 18:04:31 -07:00
jss2a98aj 62e699f6d0 Remove unneeded debug print 2025-06-13 18:04:31 -07:00
Jason Mitchell f107d173b7 Stop loading HoloInventory too early in the compat class, which was causing fake fluids to not render properly. 2025-06-09 14:22:12 -07:00
glowredman d0948b36f3 No longer use Reflection for SplashProgress.fontRenderer (#966)
* Access SplashProgress font renderer via mixins

* Use AT
2025-06-07 12:07:14 +02:00
YannickMG ae1211f280 Battlegear 2 for Backhand compat 2025-05-31 08:01:28 -07:00
David Lindström 3d76cb3073 Use instanceof instead of direct cast to protect against scenarios where mods like FMB use the same rendering code for world, inventory and preview, where the two latter happens in passes that are not rendered using a CapturingTesselator 2025-05-27 14:10:07 -07:00
kotmatross28729 45fb120223 Fix COLOR_BUFFER_BIT leak in ShaderPackScreen 2025-05-25 08:25:59 -07:00
Jason Mitchell d7a196eb5c Use invokeExact instead of invoke 2025-05-25 08:25:05 -07:00
Jason Mitchell 4d53e2af9b Holoinventory compat via reflection 2025-05-25 08:25:05 -07:00
Jason Mitchell cb6336a365 Backhand Compat via Reflection 2025-05-25 08:25:05 -07:00
Jason Mitchell 5095021e0e Capture shader outline 2025-05-16 18:08:27 -07:00
Caedis f88ecbf68d Replace Baubles with Baubles Expanded (#949) 2025-05-13 10:26:50 -04:00
Darren Eberly 7da9b9eb1c Compat for security craft (#948) 2025-05-12 23:34:15 -04:00
Pxx500 02c394108f enable ctm, disable everything unnecessary 2025-05-05 12:44:46 -07:00
Fabian Maurer 720aaca1b7 Add functionality to fake blockId for shaders 2025-04-24 14:11:24 -07:00
Midnight145 1e71b1c4d8 liteloader docs update 2025-04-17 17:41:58 -07:00
くぁーりぃ df4c423e93 fix config load (#914) 2025-04-07 19:10:39 +00:00
JuliaandJason Mitchell 78e0074e5a Apply linear filter to unifont glyphs at odd scale factors (#907)
* Apply linear filter to unifont glyphs at odd scale factors

* Prevent glyph texture bleeding by adjusting UV coordinates with a slight offset

* Tiny bit of tuning

---------

Co-authored-by: Jason Mitchell <[email protected]>
2025-04-07 17:37:46 +02:00
くぁーりぃ 0350ea2cb6 fix stencil buffer does not exist (#912) 2025-03-20 07:53:27 -07:00
Darren Eberly bed724ba59 Support for custom uniforms (#902)
* wip backport of custom uniforms

* Functioning custom uniforms maybe?

* Workon separating dynamic/non-dynamic uniforms and making variables available to custom uniforms (currently the JVM dies horribly)

* wip

* It no longer crashes horrifically

* star imports
2025-03-18 10:04:31 -07:00
Jason Mitchell 6fa973dbc8 Adds two new overloads (#906) 2025-03-13 08:24:57 -07:00
RecursivePineapple c4ad460f34 Update (#899) 2025-03-09 23:04:46 +00:00
Glease 2a8404c6c2 add an API to retrieve world instance from WorldSlice (#897) 2025-03-08 23:00:58 -08:00
ah-OOG-ah 108db9031b Add an option to disable terrain fog (#896)
* Add an option to disable terrain fog

* forgot a remap = false
2025-03-09 05:38:30 +00:00
amyandJason Mitchell d6d8a5dad6 Catch CancellationException while building chunks (#889)
Co-authored-by: Jason Mitchell <[email protected]>
2025-03-08 20:45:10 -08:00
RecursivePineappleandJason Mitchell ad2b73edf9 Fix hologlasses crash (#891)
Co-authored-by: Jason Mitchell <[email protected]>
2025-03-08 20:44:36 -08:00
glowredman bb5526598e Various Mixin-related Fixes (#890)
* Update deps

* Remove dead code

* Add missing `@Override` annotations

* Fix generics

* Add `serialVersionUID`s

* Address deprecation warnings

* Use `@WrapWithCondition` v2

* Misc cleanup

* Use AccessTransformers if possible

* Fix mixin conflicts

* Add `@Mutable` annotations

* Fix injection targets

* Update deps
2025-03-08 20:41:47 -08:00
RecursivePineapple 611bbf02c8 Optimize NEI rendering 2025-02-28 11:32:26 -08:00
OBlankenship ca16036604 Update GTNHLib dependency version in README (#885) 2025-02-27 09:22:04 +01:00
Caedis f118211257 Fix IC2 universal cell rendering w/offhand (#876) 2025-02-18 10:49:29 -08:00
RecursivePineapple 81d03ea552 Fix PBR specular & normal textures getting ignored (#874)
* Fix PBR textures not loading

- Stack was being overfilled by MemoryStack
- Added tons of logging for ignored important exceptions
- Added missing interface on mixin (should it be moved to gtnhlib?)

* Move PBR debug to angelica config

* Free malloc'd memory
2025-02-18 18:34:38 +00:00
RecursivePineapple 67c8628aeb Fix a handful of broken animations (#868)
* Fix warning

* Improve animated sprite tracking

* Fix NPE in animation code

* Fix animations for abnormally rendered items

* Swap Stack for ArrayDeque
2025-02-18 18:28:54 +00:00
embeddedt f9b9873637 Avoid checking frustum visibility of infinite bounding boxes 2025-02-18 10:24:09 -08:00
DarkShadow44 c66bf8658e Fix issue with dynamic lights world mixin not respecting opaque blocks (#872) 2025-02-17 10:36:34 -06:00
DarkShadow44 052824017d Fix crash when keycode is negative (#871) 2025-02-16 21:43:15 +00:00
Caedis 6a5d914a43 add offhand support via Backhand (up required version to 1.6.9) (#859) 2025-02-04 12:41:47 -05:00
Calvin Reveraster 208373deaa Fix any dimension without a sky getting flagged as the nether (#857)
* fix crash when connected textures are disabled, but custom colors are enabled.

* Dimension Check Fix

Dimension check set any dimension with no sky as the nether; this includes the end, and several custom dims such as Witchery's mirror dim, etc.
2025-02-01 09:18:29 -08:00
TotallyNotOndre f22a3f612b Fix slider dragging in iris options (#858) 2025-02-01 09:17:26 -08:00
TotallyNotOndre 9ff1015d19 Fix shadow render distance reset to 32 (#856) 2025-01-31 11:18:09 -08:00
Calvin Reveraster 0023fe3da2 fix crash when connected textures are disabled, but custom colors are enabled. (#855) 2025-01-29 08:19:50 -08:00
Raven Szewczyk 7e2399714c Use GTNHLib MemoryUtils instead of the builtin compat ones (#853) 2025-01-26 11:20:43 -08:00
George Paton 9029182353 Fix Hodgepodge animation speedup breaking animated textures (#850) 2025-01-25 15:34:51 -08:00
Caedis e6039691b5 Remove forced even unicode gui scaling (#840) 2025-01-15 14:39:21 -06:00
paulzzh 5db1edba33 fix MC-76356 Bold unicode characters appear doubled (#834) 2025-01-05 15:24:16 +00:00
Martin Robertz d450461726 update bs + deps (#823) 2025-01-04 13:50:46 -08:00
embeddedt 95f8afc0f3 Remove use of empty build tasks, submit empty data directly to result queue (#821) 2024-12-27 21:39:05 -08:00
Caedis 19635e20ec Disable optimizeInWorldItemRendering by default for now (#820) 2024-12-25 23:25:42 -06:00
BucketBrigade ead4e11376 Expose texture updates to API (#805)
* Expose texture updates to API

* Expose for blocks as well

* Fix mistake

* Fixed API
2024-12-19 19:04:24 -08:00
FM Bellomy b0ceb5306a the most boring typo PR of all time (#810) 2024-12-19 13:25:56 -08:00
embeddedt 99a81369f0 fix origin weirdness (#799) 2024-12-17 10:09:22 -08:00
nshepperd e2ee822948 Only clear the translucency sorting render queue when we're not rendering shadows. (#798) 2024-12-16 13:30:20 -08:00
nshepperd 9fe7e800f6 Remove broken reflection in ChunkBufferSorter. (#797) 2024-12-16 21:11:05 +00:00
embeddedt debfcdfda0 Properly prevent block face culling when TS is active (#796) 2024-12-16 13:07:00 -08:00
embeddedt df662188f4 Fix terrain rendering incorrectly when far from origin (#790) 2024-12-13 18:14:00 +00:00
embeddedt 842916405f Fix rebuild check being wrong when shaders are on (#788) 2024-12-13 16:55:58 +00:00
embeddedt 09afe81290 Fix chunk render manager state not swapping, causing lower render distance with shaders on 2024-12-13 08:52:32 -08:00
Caedis 292809d8e8 Actually fix xaero's crosshair (#781) 2024-12-11 21:50:04 +00:00
Caedis 47503ce254 Fix invisible crosshair with Xaero's Minimap (#775) 2024-12-11 16:32:49 -05:00
ah-OOG-ah f738adbdef Frametime exploration (#742)
* Sleep before swap

* Add a config

* I think this is slightly less jittery
2024-12-06 09:09:26 -08:00
Alexdoru 70d15f2383 Set render distance for mob inside mod spawner to 16 blocks (#761)
* set render distance for mob inside mod spawner to 16 blocks

* add config in angelica

* add slider in video setting menu
2024-12-02 15:20:44 -10:00
kurrycatandDarren Eberly d66b5577f4 add missing GL calls in GLStateManager (#767)
Co-authored-by: Darren Eberly <[email protected]>
2024-12-02 09:12:44 -05:00
ah-OOG-ah e293f12fb8 Refresh Notfine options on world load (#760) 2024-12-01 00:03:21 +00:00
kurrycat b69eca6749 add missing Pipeline::syncProgram for glCallList (#762) 2024-11-30 10:38:00 -10:00
Jason Mitchell 03342f08c6 Update README.MD 2024-11-27 09:03:01 -08:00
ah-OOG-ah b85614f983 Null check (#756) 2024-11-26 22:19:05 +00:00
369 changed files with 7586 additions and 5548 deletions

No files matched your search

-2
View File
@@ -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 -6
View File
@@ -8,19 +8,19 @@
* 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
* 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.6.20
* 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
@@ -29,13 +29,14 @@
* 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
@@ -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
+2
View File
@@ -4,6 +4,8 @@ plugins {
minecraft {
extraRunJvmArguments.add("-Dangelica.enableTestBlocks=true")
extraRunJvmArguments.add("-Dangelica.dumpClass=true")
//extraRunJvmArguments.add("-Dangelica.redirectorLogspam=true")
}
tasks.test {
+19 -23
View File
@@ -49,19 +49,19 @@ configurations {
}
dependencies {
compileOnly("com.github.GTNewHorizons:Hodgepodge:2.5.78")
compileOnly("com.github.GTNewHorizons:Hodgepodge:2.6.97")
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.39: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.72-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.9-GTNH:dev")
compileOnly("com.github.GTNewHorizons:twilightforest:2.7.9: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.48-GTNH:dev") { transitive = false }
compileOnly("com.github.GTNewHorizons:Natura:2.8.8:dev")
compileOnly("com.github.GTNewHorizons:ThaumicHorizons:1.6.4:dev")
compileOnly("com.github.GTNewHorizons:ThaumicHorizons:1.7.6: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,13 +93,12 @@ 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"))
@@ -111,12 +109,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
View File
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -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.
Binary file not shown.
+1 -1
View File
@@ -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
Vendored
+2 -3
View File
@@ -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.
+7
View File
@@ -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
View File
@@ -16,5 +16,5 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.29'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.41'
}
-120
View File
@@ -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, "");
}
}
-135
View File
@@ -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,16 +1,18 @@
package com.gtnewhorizons.angelica.client.font;
import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil;
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.*;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.mixins.interfaces.FontRendererAccessor;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import it.unimi.dsi.fastutil.chars.Char2ShortOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import jss.util.RandomXoshiro256StarStar;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.util.MathHelper;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import java.nio.ByteBuffer;
@@ -42,13 +44,11 @@ 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 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 static final short[] MCFONT_ASCII_LUT = new short[512];
private static final Char2ShortOpenHashMap MCFONT_UNI_LUT = new Char2ShortOpenHashMap();
@@ -74,14 +74,13 @@ public class BatchingFontRenderer {
}
public BatchingFontRenderer(FontRenderer underlying, ResourceLocation[] unicodePageLocations, int[] charWidth,
byte[] glyphWidth, int[] colorCode, ResourceLocation locationFontTexture, TextureManager renderEngine) {
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());
@@ -97,10 +96,10 @@ 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 final ObjectArrayList<FontDrawCmd> batchCommands = ObjectArrayList.wrap(new FontDrawCmd[64], 0);
private final ObjectArrayList<FontDrawCmd> batchCommandPool = ObjectArrayList.wrap(new FontDrawCmd[64], 0);
@@ -109,12 +108,12 @@ public class BatchingFontRenderer {
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);
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;
@@ -153,7 +152,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 +168,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 +176,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
@@ -283,7 +284,21 @@ public class BatchingFontRenderer {
}
batchIndices.limit(cmd.startVtx + cmd.idxCount);
batchIndices.position(cmd.startVtx);
Minecraft mc = Minecraft.getMinecraft();
int scaleFactor = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight).getScaleFactor();
boolean shouldApplyFilter = cmd.isUnicode && scaleFactor % 2 != 0;
if (shouldApplyFilter) {
GLStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GLStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
}
GL11.glDrawElements(GL11.GL_TRIANGLES, batchIndices);
if (shouldApplyFilter) {
GLStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GLStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
}
}
GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
@@ -370,7 +385,7 @@ public class BatchingFontRenderer {
if (curUnderline && underlineStartX != underlineEndX) {
final int ulIdx = idxWriterIndex;
pushUntexRect(underlineStartX, underlineY, underlineEndX - underlineStartX, 1.0f, curColor);
pushDrawCmd(ulIdx, 6, null);
pushDrawCmd(ulIdx, 6, null, false);
underlineStartX = underlineEndX;
}
if (curStrikethrough && strikethroughStartX != strikethroughEndX) {
@@ -381,7 +396,7 @@ public class BatchingFontRenderer {
strikethroughEndX - strikethroughStartX,
1.0f,
curColor);
pushDrawCmd(ulIdx, 6, null);
pushDrawCmd(ulIdx, 6, null, false);
strikethroughStartX = strikethroughEndX;
}
@@ -437,8 +452,6 @@ public class BatchingFontRenderer {
chr = MCFONT_CHARS.charAt(lutIndex);
}
final float shadowOffset = unicodeFlag ? 0.5F : 1.0F;
// Check ASCII space, NBSP, NNBSP
if (chr == ' ' || chr == '\u00A0' || chr == '\u202F') {
curX += 4;
@@ -452,6 +465,7 @@ public class BatchingFontRenderer {
final float uSz;
final float vSz;
final float itOff = curItalic ? 1.0F : 0.0F; // italic offset
final float shadowOffset;
final ResourceLocation texture;
if (lutIndex == -1 || unicodeFlag) {
@@ -459,22 +473,24 @@ public class BatchingFontRenderer {
continue;
}
// Draw unicode char
shadowOffset = AngelicaConfig.shadowOffsetFontUC;
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;
uStart = ((float) (chr % 16 * 16) + startColumnF + 0.21f) / 256.0f;
vStart = ((float) ((chr & 255) / 16 * 16) + 0.21f) / 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;
uSz = (chrWidth - 0.42f) / 256.0f;
vSz = (16.0f - 0.42f) / 256.0f;
} else {
// Draw "ASCII" char
shadowOffset = 1.0F;
uStart = ((lutIndex % 16) * 8) / 128.0F;
vStart = (float) ((lutIndex / 16) * 8) / 128.0F;
xAdvance = this.charWidth[lutIndex];
@@ -558,7 +574,7 @@ public class BatchingFontRenderer {
vtxCount += 4;
}
pushDrawCmd(idxId, vtxCount / 2 * 3, texture);
pushDrawCmd(idxId, vtxCount / 2 * 3, texture, chr > 255);
curX += xAdvance + (curBold ? shadowOffset : 0.0f);
underlineEndX = curX;
strikethroughEndX = curX;
@@ -567,7 +583,7 @@ public class BatchingFontRenderer {
if (curUnderline && underlineStartX != underlineEndX) {
final int ulIdx = idxWriterIndex;
pushUntexRect(underlineStartX, underlineY, underlineEndX - underlineStartX, 1.0f, curColor);
pushDrawCmd(ulIdx, 6, null);
pushDrawCmd(ulIdx, 6, null, false);
}
if (curStrikethrough && strikethroughStartX != strikethroughEndX) {
final int ulIdx = idxWriterIndex;
@@ -577,7 +593,7 @@ public class BatchingFontRenderer {
strikethroughEndX - strikethroughStartX,
1.0f,
curColor);
pushDrawCmd(ulIdx, 6, null);
pushDrawCmd(ulIdx, 6, null, false);
}
} finally {
@@ -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;
}
@@ -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();
}
}
@@ -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);
}
}
}
@@ -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;
@@ -87,6 +87,11 @@ public class AngelicaConfig {
@Config.RequiresMcRestart
public static boolean enableFontRenderer;
@Config.Comment("OffSet fonts shadows draw")
@Config.DefaultFloat(0.5F)
@Config.RangeFloat(min = 0.5F, max = 1F)
public static float shadowOffsetFontUC;
@Config.Comment("Enable Dynamic Lights")
@Config.DefaultBoolean(true)
@Config.RequiresMcRestart
@@ -133,19 +138,37 @@ 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
public static boolean enableZoom;
@Config.Comment("Optimizes in-world item rendering")
@Config.DefaultBoolean(true)
@Config.Comment("Optimizes in-world item rendering [Experimental]")
@Config.DefaultBoolean(false)
@Config.RequiresMcRestart
public static boolean optimizeInWorldItemRendering;
public static boolean optimizeInWorldItemRendering_WIP;
@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("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;
}
@@ -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;
}
@@ -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,21 +21,25 @@ 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<>();
@@ -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,11 +67,16 @@ 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;
@@ -133,11 +140,21 @@ 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);
}
try {
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 +166,18 @@ public class GLStateManager {
while(!attribs.isEmpty()) {
attribs.popInt();
}
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);
while(!stack.isEmpty()) {
stack.pop();
}
}
modelViewMatrix.clear();
projectionMatrix.clear();
}
@@ -180,6 +204,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;
@@ -398,6 +425,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 +449,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 +863,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);
@@ -960,32 +1004,52 @@ public class GLStateManager {
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 +1255,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 +1312,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 +1325,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();
}
}
@@ -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);
}
@@ -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;
@@ -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,21 @@
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.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 +26,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,17 +42,17 @@ 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);
@@ -67,39 +67,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 +107,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 +143,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;
}
}
@@ -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;
@@ -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() {
@@ -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");
}
}
@@ -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");
}
}
@@ -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() {
@@ -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() {
@@ -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,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,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;
@@ -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) {
@@ -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;
}
@@ -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;
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
@@ -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];
}
}
@@ -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];
}
}
@@ -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)
};
}
}
@@ -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;
@@ -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 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,242 @@
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_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_DISPLAY_LIST_OPTIMIZATION(new MixinBuilder("Optimized item rendering by wrapping them with display lists")
.setPhase(Phase.EARLY)
.addClientMixins("angelica.itemrenderer.MixinItemRenderer")
.setApplyIf(() -> AngelicaConfig.optimizeInWorldItemRendering_WIP)),
// 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 +247,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 +329,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 +344,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 +483,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 +501,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 +537,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);
}
}
@@ -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);
}
@@ -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();
}
@@ -1,7 +0,0 @@
package com.gtnewhorizons.angelica.mixins.interfaces;
import net.minecraft.util.ResourceLocation;
public interface SimpleTextureAccessor {
ResourceLocation getLocation();
}
@@ -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();
}
@@ -1,12 +1,10 @@
package com.gtnewhorizons.angelica.rendering;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import lombok.Getter;
import lombok.Setter;
import org.joml.Matrix4f;
import org.joml.Vector3d;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import java.nio.FloatBuffer;
@@ -1,13 +0,0 @@
package com.gtnewhorizons.angelica.transform;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
public class AsmUtil {
public static String obf(String deobf, String obf) {
if (AngelicaTweaker.isObfEnv()) {
return obf;
}
return deobf;
}
}
@@ -1,80 +0,0 @@
package com.gtnewhorizons.angelica.transform.compat;
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import com.gtnewhorizons.angelica.transform.compat.handlers.CompatHandler;
import com.gtnewhorizons.angelica.transform.compat.transformers.generic.FieldLevelTessellatorTransformer;
import com.gtnewhorizons.angelica.transform.compat.transformers.generic.HUDCachingEarlyReturnTransformer;
import com.gtnewhorizons.angelica.transform.compat.transformers.generic.ThreadSafeISBRHAnnotationTransformer;
import com.gtnewhorizons.angelica.transform.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 static final Map<String, List<String>> fieldLevelTessellator = new Object2ObjectOpenHashMap<>();
private static final Map<String, List<String>> tileEntityNullGuard = new Object2ObjectOpenHashMap<>();
private static final Map<String, Boolean> threadSafeIBSRH = new Object2BooleanOpenHashMap<>();
private static final Map<String, List<String>> hudCachingEarlyReturn = new Object2ObjectOpenHashMap<>();
private static final Set<String> transformedClasses = new ObjectOpenHashSet<>();
@Override
public byte[] transform(String name, String transformedName, byte[] basicClass) {
if (basicClass == null) return null;
if (!transformedClasses.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();
AngelicaTweaker.dumpClass(transformedName, basicClass, bytes, this);
return bytes;
}
public static void register(CompatHandler 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());
}
public static void build() {
transformedClasses.addAll(fieldLevelTessellator.keySet());
transformedClasses.addAll(tileEntityNullGuard.keySet());
transformedClasses.addAll(threadSafeIBSRH.keySet());
transformedClasses.addAll(hudCachingEarlyReturn.keySet());
}
}
@@ -1,40 +0,0 @@
package com.gtnewhorizons.angelica.transform.compat.handlers;
import com.gtnewhorizons.angelica.config.CompatConfig;
import lombok.Getter;
import java.util.ArrayList;
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 CompatHandler handler;
CompatHandlers(Supplier<Boolean> applyIf, CompatHandler handler) {
this.applyIf = applyIf;
this.handler = handler;
}
private static List<CompatHandler> compatHandlers = null;
public static List<CompatHandler> getHandlers() {
if (compatHandlers != null) {
return compatHandlers;
}
compatHandlers = new ArrayList<>();
for (CompatHandlers value : values()) {
if (value.applyIf.get()) {
compatHandlers.add(value.handler);
}
}
return compatHandlers;
}
}
@@ -1,5 +1,7 @@
package com.gtnewhorizons.angelica.utils;
import java.util.ArrayDeque;
import com.gtnewhorizons.angelica.mixins.interfaces.IPatchedTextureAtlasSprite;
import com.gtnewhorizons.angelica.mixins.interfaces.ITexturesCache;
import net.minecraft.client.Minecraft;
@@ -28,4 +30,26 @@ public class AnimationsRenderUtils {
}
}
}
private final static ThreadLocal<ArrayDeque<ITexturesCache>> TEXTURE_CACHE_STACK = ThreadLocal.withInitial(ArrayDeque::new);
public static void onSpriteUsed(IPatchedTextureAtlasSprite sprite) {
ArrayDeque<ITexturesCache> stack = TEXTURE_CACHE_STACK.get();
if (stack == null || stack.isEmpty()) {
// icon was used outside of chunk building, it's probably an item in an inventory or something
sprite.markNeedsAnimationUpdate();
return;
}
stack.peek().track(sprite);
}
public static void pushCache(ITexturesCache cache) {
TEXTURE_CACHE_STACK.get().push(cache);
}
public static void popCache() {
TEXTURE_CACHE_STACK.get().pop();
}
}
@@ -172,6 +172,8 @@ public class MCLogger {
private static class ErrorLevel extends Level {
private static final long serialVersionUID = 3987750897854233321L;
protected ErrorLevel() {
super("ERROR", (Level.WARNING.intValue() + Level.SEVERE.intValue()) / 2);
}
@@ -4,6 +4,7 @@ import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import com.gtnewhorizons.angelica.mixins.interfaces.EntityRendererAccessor;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.potion.Potion;
@@ -83,9 +84,8 @@ public final class Lightmap {
}
private float getNightVisionStrength(EntityRenderer renderer, float n) {
if (Minecraft.getMinecraft().thePlayer.isPotionActive(Potion.nightVision)) {
return renderer.getNightVisionBrightness(Minecraft.getMinecraft().thePlayer, n);
return ((EntityRendererAccessor) renderer).invokeGetNightVisionBrightness(Minecraft.getMinecraft().thePlayer, n);
}
return 0.0f;
}
@@ -221,7 +221,7 @@ public class CITUtils {
List<T> list = overrides.get(item);
if (list != null) {
int[] enchantmentLevels = getEnchantmentLevels(item, itemStack.getTagCompound());
boolean hasEffect = itemStack.hasEffect();
boolean hasEffect = itemStack.hasEffect(0);
for (T override : list) {
if (override.match(itemStack, enchantmentLevels, hasEffect)) {
return override;
@@ -117,12 +117,13 @@ final class Enchantment extends OverrideBase {
return;
}
begin(intensity);
Tessellator.instance.startDrawingQuads();
Tessellator.instance.addVertexWithUV(x0, y0, z, 0.0f, 0.0f);
Tessellator.instance.addVertexWithUV(x0, y1, z, 0.0f, 1.0f);
Tessellator.instance.addVertexWithUV(x1, y1, z, 1.0f, 1.0f);
Tessellator.instance.addVertexWithUV(x1, y0, z, 1.0f, 0.0f);
Tessellator.instance.draw();
final Tessellator tess = Tessellator.instance;
tess.startDrawingQuads();
tess.addVertexWithUV(x0, y0, z, 0.0f, 0.0f);
tess.addVertexWithUV(x0, y1, z, 0.0f, 1.0f);
tess.addVertexWithUV(x1, y1, z, 1.0f, 1.0f);
tess.addVertexWithUV(x1, y0, z, 1.0f, 0.0f);
tess.draw();
end();
}
@@ -49,7 +49,7 @@ final class EnchantmentList {
Map<Integer, Layer> tmpLayers = new HashMap<>();
Item item = itemStack.getItem();
int[] enchantmentLevels = CITUtils.getEnchantmentLevels(item, itemStack.getTagCompound());
boolean hasEffect = itemStack.hasEffect();
boolean hasEffect = itemStack.hasEffect(0);
List<Enchantment> list = enchantments.get(item);
if (list == null) {
list = allItemEnchantments;
@@ -32,8 +32,6 @@ abstract class TileOverride implements Comparable<TileOverride> {
private static final MCLogger logger = MCLogger.getLogger(MCLogger.Category.CONNECTED_TEXTURES, "CTM");
private static final int META_MASK = 0xffff;
private final PropertiesFile properties;
private final String baseFilename;
private final TileLoader tileLoader;
@@ -41,7 +39,6 @@ abstract class TileOverride implements Comparable<TileOverride> {
private final int weight;
private final List<BlockStateMatcher> matchBlocks;
private final Set<String> matchTiles;
private final int defaultMetaMask;
private final BlockFaceMatcher faceMatcher;
private final int connectType;
private final boolean innerSeams;
@@ -50,7 +47,6 @@ abstract class TileOverride implements Comparable<TileOverride> {
private final List<ResourceLocation> tileNames = new ArrayList<>();
protected IIcon[] icons;
private int matchMetadata = META_MASK;
static TileOverride create(ResourceLocation propertiesFile, TileLoader tileLoader) {
if (propertiesFile == null) {
@@ -133,11 +129,6 @@ abstract class TileOverride implements Comparable<TileOverride> {
if (matchBlocks.isEmpty() && matchTiles.isEmpty()) {
matchTiles.add(baseFilename);
}
int bits = 0;
for (int i : properties.getIntList("metadata", 0, 15, "0-15")) {
bits |= 1 << i;
}
defaultMetaMask = bits;
faceMatcher = BlockFaceMatcher.create(properties.getString("faces", ""));
@@ -170,6 +170,7 @@ public class FancyDial {
static void registerAnimations() {
ITextureObject texture = TexturePackAPI.getTextureObject(TexturePackAPI.ITEMS_PNG);
if (texture instanceof TextureMap map) {
@SuppressWarnings("unchecked")
List<TextureAtlasSprite> animations = map.listAnimatedSprites;
for (FancyDial instance : instances.values()) {
instance.registerAnimation(animations);
@@ -32,7 +32,6 @@ abstract public class ColorMap implements IColorMap {
private static final int BIOME_HEIGHT = 2;
private static final int COLORMAP_WIDTH = 256;
private static final int COLORMAP_HEIGHT = 256;
public static final String BLOCK_COLORMAP_DIR = TexturePackAPI.MCPATCHER_SUBDIR + "colormap/blocks";
public static final List<ResourceLocation> unusedPNGs = new ArrayList<>();
@@ -10,8 +10,6 @@ import java.util.Map;
import java.util.Set;
import net.minecraft.block.Block;
import net.minecraft.util.IIcon;
import net.minecraft.world.IBlockAccess;
import com.prupe.mcpatcher.MCPatcherUtils;
import com.prupe.mcpatcher.mal.resource.PropertiesFile;
@@ -21,6 +19,7 @@ import cpw.mods.fml.common.registry.GameData;
public class BlockAPI {
@SuppressWarnings("unchecked")
BlockAPI(FMLControlledNamespacedRegistry<Block> registry) {
File outputFile = new File("blocks17.txt");
if (outputFile.isFile()) {
@@ -61,6 +61,7 @@ public class BlockStateMatcher {
threadLocal.set(data);
}
@Override
final public String toString() {
return fullString;
}
@@ -13,6 +13,7 @@ import cpw.mods.fml.common.registry.GameData;
public class ItemAPI {
@SuppressWarnings("unchecked")
ItemAPI() {
File outputFile = new File("items17.txt");
if (outputFile.isFile()) {
@@ -120,7 +120,7 @@ final public class PropertiesFile {
@SuppressWarnings("unchecked")
public Set<Map.Entry<String, String>> entrySet() {
return (Set<Map.Entry<String, String>>) (Set) properties.entrySet();
return (Set<Map.Entry<String, String>>) (Set<?>) properties.entrySet();
}
public ResourceLocation getResource() {
Loaded 100 of 369 files, more files were not shown because too many files have changed in this diff. Show more