├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── build-extensions.kt ├── fabric ├── build.gradle.kts ├── gradle.properties └── src │ └── main │ ├── java │ └── mod │ │ └── crend │ │ └── autohud │ │ ├── compat │ │ ├── DehydrationCompat.java │ │ ├── EnvironmentZCompat.java │ │ ├── MicroDurabilityCompat.java │ │ ├── OneBarCompat.java │ │ └── mixin │ │ │ ├── appleskin │ │ │ └── HUDOverlayHandlerMixin.java │ │ │ ├── armor_hud │ │ │ └── ArmorHudMixin.java │ │ │ ├── armorchroma │ │ │ └── GuiArmorMixin.java │ │ │ ├── dehydration │ │ │ ├── DehydrationMixin.java │ │ │ └── ThirstManagerMixin.java │ │ │ ├── detailab │ │ │ ├── ArmorBarRendererMixin.java │ │ │ └── InGameDrawerMixin.java │ │ │ ├── environmentz │ │ │ └── TemperatureHudRenderingMixin.java │ │ │ ├── farmersdelight │ │ │ ├── ComfortHealthOverlayMixin.java │ │ │ ├── HUDOverlaysMixin.java │ │ │ └── NourishmentHungerOverlayMixin.java │ │ │ ├── onebar │ │ │ └── OneBarElementsMixin.java │ │ │ └── statuseffectbars │ │ │ └── StatusEffectBarRendererMixin.java │ │ └── fabric │ │ ├── AutoHudFabric.java │ │ ├── mixin │ │ └── gui │ │ │ ├── ChatHudMixin.java │ │ │ ├── InGameHudMixin.java │ │ │ └── StatusEffectTimerMixin.java │ │ └── screen │ │ └── ModMenuIntegration.java │ └── resources │ ├── autohud-fabric-compat.mixins.json │ ├── autohud-fabric.mixins.json │ └── fabric.mod.json ├── forge ├── build.gradle.kts ├── gradle.properties └── src │ └── main │ ├── java │ └── mod │ │ └── crend │ │ └── autohud │ │ └── forge │ │ ├── AutoHudForge.java │ │ ├── AutoHudGui.java │ │ ├── AutoHudModEvents.java │ │ ├── compat │ │ ├── ColdSweatCompat.java │ │ ├── QuarkCompat.java │ │ └── legendarysurvivaloverhaul │ │ │ ├── LSOCompat.java │ │ │ ├── LSOComponentRenderer.java │ │ │ ├── LSOComponents.java │ │ │ └── TemperatureState.java │ │ └── mixin │ │ └── gui │ │ ├── ChatHudMixin.java │ │ ├── ForgeGuiMixin.java │ │ ├── InGameHudMixin.java │ │ └── StatusEffectTimerMixin.java │ └── resources │ ├── META-INF │ └── mods.toml │ ├── autohud-forge-compat.mixins.json │ ├── autohud-forge.mixins.json │ └── pack.mcmeta ├── gradle.properties ├── icon_large.png ├── neoforge ├── build.gradle.kts ├── gradle.properties └── src │ └── main │ ├── java │ └── mod │ │ └── crend │ │ └── autohud │ │ └── neoforge │ │ ├── AutoHudGui.java │ │ ├── AutoHudModEvents.java │ │ ├── AutoHudNeoForge.java │ │ ├── compat │ │ └── ColdSweatCompat.java │ │ └── mixin │ │ └── gui │ │ ├── InGameHudMixin.java │ │ └── StatusEffectTimerMixin.java │ └── resources │ ├── META-INF │ ├── mods.toml │ └── neoforge.mods.toml │ ├── autohud-neoforge.mixins.json │ └── pack.mcmeta ├── screenshot1.png ├── screenshot2.png ├── settings.gradle.kts ├── src └── main │ ├── java │ └── mod │ │ └── crend │ │ └── autohud │ │ ├── AutoHud.java │ │ ├── AutoHudCompatMixinPlugin.java │ │ ├── ModKeyBindings.java │ │ ├── api │ │ └── AutoHudApi.java │ │ ├── compat │ │ ├── HotbarSlotCyclingCompat.java │ │ └── RaisedCompat.java │ │ ├── component │ │ ├── Component.java │ │ ├── Components.java │ │ ├── EventHandler.java │ │ ├── Hud.java │ │ ├── ScoreboardHelper.java │ │ ├── State.java │ │ └── state │ │ │ ├── BooleanComponentState.java │ │ │ ├── ComponentState.java │ │ │ ├── EnhancedPolicyComponentState.java │ │ │ ├── ItemStackComponentState.java │ │ │ ├── PolicyComponentState.java │ │ │ ├── ScoreboardComponentState.java │ │ │ └── ValueComponentState.java │ │ ├── config │ │ ├── Config.java │ │ ├── ConfigHandler.java │ │ ├── EventPolicy.java │ │ ├── RevealPolicy.java │ │ ├── RevealType.java │ │ └── ScrollDirection.java │ │ ├── mixin │ │ ├── ClientPlayNetworkHandlerMixin.java │ │ ├── ScoreboardMixin.java │ │ └── TeamMixinAccessor.java │ │ └── render │ │ ├── AutoHudRenderLayer.java │ │ ├── AutoHudRenderer.java │ │ ├── ChatMessageIndicator.java │ │ └── ComponentRenderer.java │ └── resources │ ├── architectury.common.json │ ├── assets │ └── autohud │ │ └── lang │ │ ├── en_us.json │ │ ├── it_it.json │ │ ├── ru_ru.json │ │ ├── zh_cn.json │ │ └── zh_tw.json │ ├── autohud-common-compat.mixins.json │ ├── autohud-common.mixins.json │ ├── autohud.accesswidener │ └── autohud.png ├── stonecutter.gradle.kts └── versions ├── 1.20.1 └── gradle.properties ├── 1.20.4 └── gradle.properties ├── 1.20.6 └── gradle.properties ├── 1.21.1 └── gradle.properties └── 1.21.3 └── gradle.properties /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | gradle 4 | gradlew 5 | .gradle/ 6 | build/ 7 | out/ 8 | classes/ 9 | .kotlin 10 | 11 | # eclipse 12 | 13 | *.launch 14 | 15 | # idea 16 | 17 | .idea/ 18 | *.iml 19 | *.ipr 20 | *.iws 21 | 22 | # vscode 23 | 24 | .settings/ 25 | .vscode/ 26 | bin/ 27 | .classpath 28 | .project 29 | 30 | # macos 31 | 32 | *.DS_Store 33 | 34 | # fabric 35 | 36 | run/ 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Auto HUD 2 | 3 | Auto HUD is a Minecraft mod for the Fabric launcher which hides parts of the user 4 | interface (HUD) that are currently not interesting. 5 | 6 | It is inspired by similar mods ("immersive hud") for other games. 7 | I personally really like the clean view of no visible HUD, but get frustrated by the 8 | limitations of using F1 mode. 9 | 10 | This is an opinionated rewrite of [Head-down Display](https://github.com/jadc/headdowndisplay/) that never got updated. 11 | 12 | ## Features 13 | * Toggle the whole HUD with a key binding. 14 | * Have parts of the HUD that haven't changed hide away. 15 | * Hide persistent, unchanging status effects, such as water breathing from the turtle helmet. 16 | * Show remaining time of status effects. 17 | * Highly configurable. 18 | 19 | ### Visual differences to F1 mode 20 | * Player hand / equipped items remain visible 21 | * Player names remain visible 22 | * The vignette remains active 23 | * Incoming chat messages still pop up 24 | * Crosshair remains visible (see my other mod Dynamic Crosshair for that) 25 | * Configurable what elements are hidden 26 | 27 | ## Screenshots 28 | All HUD elements are hidden except for the currently active status effect: 29 | ![Example for hiding HUD](screenshot1.png) 30 | 31 | Possible look with shaders installed: 32 | ![Example with shaders](screenshot2.png) 33 | 34 | ## Installation 35 | This mod has been written for Fabric for Minecraft 1.18.2. 36 | 37 | Get packaged versions from [Modrinth](https://modrinth.com/mod/autohud) or [Curseforge](https://www.curseforge.com/minecraft/mc-mods/auto-hud)! 38 | 39 | * requires [Fabric API](https://modrinth.com/mod/fabric-api) 40 | * requires [ClothConfig](https://modrinth.com/mod/cloth-config) 41 | * not required: [Mod Menu](https://modrinth.com/mod/modmenu) for ingame configuration screen 42 | 43 | ## Mod Compatibility 44 | This mod includes a modified version of magicus' [Status Effect Timers](https://modrinth.com/mod/statuseffecttimer), 45 | because I could not figure out how to dynamically insert my modifications into it. 46 | Since this mod allows for status effect icons to be hidden individually, 47 | the non-modified version will draw the timers in the wrong place. 48 | 49 | Known to be compatible: 50 | * [Dynamic Crosshair](https://modrinth.com/mod/dynamiccrosshair) augments this mod by allowing to hide/change the crosshair based on context. 51 | * [Raised](https://modrinth.com/mod/raised) works perfectly. 52 | * [HUDTweaks](https://modrinth.com/mod/hudtweaks) mostly works. 53 | Vertical status effects bar does not work with the timer overlay. 54 | Animation direction and offset may have to be tweaked in AutoHud's settings manually. 55 | * [AppleSkin](https://modrinth.com/mod/appleskin) appears to work fine. 56 | * [DetailArmorBar](https://modrinth.com/mod/detail-armor-bar) is supported. 57 | * [BerdinskiyBears Armor Hud](https://www.curseforge.com/minecraft/mc-mods/berdinskiybears-armor-hud) is supported in "hotbar" configuration 58 | * [Dehydration](https://www.curseforge.com/minecraft/mc-mods/dehydration) is supported (hydration bar follows hunger bar settings). 59 | * [OneBar](https://modrinth.com/mod/onebar) is supported. 60 | * [Inventory Profiles Next](https://modrinth.com/mod/inventory-profiles-next)' lock symbol is supported (but not in "fade" setting). 61 | * [Micro Durability](https://modrinth.com/mod/microdurability) is supported (but does not get dynamically shown) 62 | 63 | Known to be incompatible: 64 | * OptiFabric crashes due to mixin conflicts. 65 | * Any other mod that draws status effect timers should have that functionality disabled. 66 | * HUD elements created by other mods will most likely not be moved. 67 | * Bedrockify overwrites the status effect modifications. To get them working, disable the `screenSafeArea` mixin. 68 | * "Fade" mode is more likely to cause issues with any mods that alter the GUI. 69 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("dev.architectury.loom") 3 | id("architectury-plugin") 4 | } 5 | 6 | val minecraft = stonecutter.current.version 7 | 8 | version = "${mod.version}+$minecraft" 9 | group = "${mod.group}.common" 10 | base { 11 | archivesName.set("${mod.id}-common") 12 | } 13 | 14 | architectury.common(stonecutter.tree.branches.mapNotNull { 15 | if (stonecutter.current.project !in it) null 16 | else it.prop("loom.platform") 17 | }) 18 | 19 | repositories { 20 | } 21 | 22 | dependencies { 23 | minecraft("com.mojang:minecraft:$minecraft") 24 | mappings("net.fabricmc:yarn:$minecraft+build.${mod.dep("yarn_build")}:v2") 25 | modImplementation("net.fabricmc:fabric-loader:${mod.dep("fabric_loader")}") 26 | 27 | modImplementation(name="libbamboo", group="mod.crend", version="${mod.dep("libbamboo")}-fabric") 28 | modImplementation("dev.isxander:yet-another-config-lib:${mod.dep("yacl")}-fabric") 29 | 30 | mapOf( 31 | "appleskin" to "squeek.appleskin:appleskin-fabric:${mod.dep("appleskin_artifact")}-{}", 32 | "armorchroma" to "maven.modrinth:armor-chroma-for-fabric:{}", 33 | "detailab" to "maven.modrinth:detail-armor-bar:{}", 34 | "dehydration" to "maven.modrinth:dehydration:{}", 35 | "environmentz" to "maven.modrinth:environmentz:{}", 36 | "farmers_delight_refabricated" to "maven.modrinth:farmers-delight-refabricated:{}", 37 | "hotbarslotcycling" to "fuzs.hotbarslotcycling:hotbarslotcycling-fabric:{}", 38 | "onebar" to "maven.modrinth:onebar:{}", 39 | "raised" to "maven.modrinth:raised:Fabric-${mod.dep("raised_artifact")}-{}", 40 | "statuseffectbars" to "maven.modrinth:status-effect-bars:{}" 41 | ).map { (modName, url) -> 42 | mod.dep(modName) to url.replace("{}", mod.dep(modName)) 43 | }.filterNot { (version, _) -> 44 | version.startsWith("[") 45 | }.forEach { (_, url) -> 46 | modCompileOnly(url) 47 | } 48 | } 49 | 50 | loom { 51 | accessWidenerPath = rootProject.file("src/main/resources/autohud.accesswidener") 52 | 53 | decompilers { 54 | get("vineflower").apply { // Adds names to lambdas - useful for mixins 55 | options.put("mark-corresponding-synthetics", "1") 56 | } 57 | } 58 | } 59 | 60 | java { 61 | withSourcesJar() 62 | val java = if (stonecutter.eval(minecraft, ">=1.20.5")) 63 | JavaVersion.VERSION_21 else JavaVersion.VERSION_17 64 | targetCompatibility = java 65 | sourceCompatibility = java 66 | } 67 | 68 | tasks.build { 69 | group = "versioned" 70 | description = "Must run through 'chiseledBuild'" 71 | } -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | kotlin("jvm") version "2.0.20" 4 | } 5 | 6 | repositories { 7 | mavenCentral() 8 | } -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/build-extensions.kt: -------------------------------------------------------------------------------- 1 | import org.gradle.api.Project 2 | import org.gradle.api.artifacts.dsl.RepositoryHandler 3 | import org.gradle.kotlin.dsl.maven 4 | import org.gradle.language.jvm.tasks.ProcessResources 5 | 6 | val Project.mod: ModData get() = ModData(this) 7 | fun Project.prop(key: String): String? = findProperty(key)?.toString() 8 | fun String.upperCaseFirst() = replaceFirstChar { if (it.isLowerCase()) it.uppercaseChar() else it } 9 | 10 | fun RepositoryHandler.strictMaven(url: String, alias: String, vararg groups: String) = exclusiveContent { 11 | forRepository { maven(url) { name = alias } } 12 | filter { groups.forEach(::includeGroup) } 13 | } 14 | 15 | fun ProcessResources.properties(files: Iterable, vararg properties: Pair) { 16 | for ((name, value) in properties) inputs.property(name, value) 17 | filesMatching(files) { 18 | expand(properties.toMap()) 19 | } 20 | } 21 | 22 | @JvmInline 23 | value class ModData(private val project: Project) { 24 | val id: String get() = requireNotNull(project.prop("mod.id")) { "Missing 'mod.id'" } 25 | val name: String get() = requireNotNull(project.prop("mod.name")) { "Missing 'mod.name'" } 26 | val version: String get() = requireNotNull(project.prop("mod.version")) { "Missing 'mod.version'" } 27 | val group: String get() = requireNotNull(project.prop("mod.group")) { "Missing 'mod.group'" } 28 | 29 | fun prop(key: String) = requireNotNull(project.prop("mod.$key")) { "Missing 'mod.$key'" } 30 | fun dep(key: String) = requireNotNull(project.prop("deps.$key")) { "Missing 'deps.$key'" } 31 | fun dep(platformName: String, key: String) = requireNotNull(project.prop("deps.${key}_${platformName}") ?: project.prop("deps.$key")) { "Missing 'deps.$key'" } 32 | } -------------------------------------------------------------------------------- /fabric/build.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | 4 | plugins { 5 | id("dev.architectury.loom") 6 | id("architectury-plugin") 7 | id("com.github.johnrengelman.shadow") 8 | id("maven-publish") 9 | id("me.modmuss50.mod-publish-plugin") 10 | } 11 | 12 | val loader = prop("loom.platform")!! 13 | val minecraft: String = stonecutter.current.version 14 | val common: Project = requireNotNull(stonecutter.node.sibling("")) { 15 | "No common project for $project" 16 | } 17 | 18 | version = "${mod.version}+$minecraft" 19 | group = "${mod.group}.$loader" 20 | base { 21 | archivesName.set(mod.id) 22 | } 23 | architectury { 24 | platformSetupLoomIde() 25 | fabric() 26 | } 27 | 28 | val commonBundle: Configuration by configurations.creating { 29 | isCanBeConsumed = false 30 | isCanBeResolved = true 31 | } 32 | 33 | val shadowBundle: Configuration by configurations.creating { 34 | isCanBeConsumed = false 35 | isCanBeResolved = true 36 | } 37 | 38 | configurations { 39 | compileClasspath.get().extendsFrom(commonBundle) 40 | runtimeClasspath.get().extendsFrom(commonBundle) 41 | get("developmentFabric").extendsFrom(commonBundle) 42 | } 43 | 44 | repositories { 45 | } 46 | 47 | dependencies { 48 | minecraft("com.mojang:minecraft:$minecraft") 49 | mappings("net.fabricmc:yarn:$minecraft+build.${common.mod.dep("yarn_build")}:v2") 50 | modImplementation("net.fabricmc:fabric-loader:${mod.dep("fabric_loader")}") 51 | 52 | listOf( 53 | "fabric-key-binding-api-v1", 54 | "fabric-lifecycle-events-v1", 55 | "fabric-rendering-v1" 56 | ).forEach { 57 | modImplementation(fabricApi.module(it, common.mod.dep("fabric_api"))) 58 | } 59 | modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:${common.mod.dep("fabric_api")}") 60 | 61 | modImplementation(name="libbamboo", group="mod.crend", version="${common.mod.dep("libbamboo")}-fabric") 62 | include(name="libbamboo", group="mod.crend", version="${common.mod.dep("libbamboo")}-fabric") 63 | 64 | modImplementation("com.terraformersmc:modmenu:${common.mod.dep("modmenu")}") 65 | modRuntimeOnly("dev.isxander:yet-another-config-lib:${common.mod.dep("yacl")}-fabric") 66 | 67 | mapOf( 68 | "appleskin" to "squeek.appleskin:appleskin-fabric:${common.mod.dep("appleskin_artifact")}-{}", 69 | "armorchroma" to "maven.modrinth:armor-chroma-for-fabric:{}", 70 | "detailab" to "maven.modrinth:detail-armor-bar:{}", 71 | "dehydration" to "maven.modrinth:dehydration:{}", 72 | "environmentz" to "maven.modrinth:environmentz:{}", 73 | "farmers_delight_refabricated" to "maven.modrinth:farmers-delight-refabricated:{}", 74 | "hotbarslotcycling" to "fuzs.hotbarslotcycling:hotbarslotcycling-fabric:{}", 75 | "onebar" to "maven.modrinth:onebar:{}", 76 | "raised" to "maven.modrinth:raised:Fabric-${common.mod.dep("raised_artifact")}-{}", 77 | "statuseffectbars" to "maven.modrinth:status-effect-bars:{}" 78 | ).map { (modName, url) -> 79 | common.mod.dep(modName) to url.replace("{}", common.mod.dep("fabric", modName)) 80 | }.filterNot { (version, _) -> 81 | version.startsWith("[") 82 | }.forEach { (_, url) -> 83 | modCompileOnly(url) 84 | } 85 | 86 | commonBundle(project(common.path, "namedElements")) { isTransitive = false } 87 | shadowBundle(project(common.path, "transformProductionFabric")) { isTransitive = false } 88 | } 89 | 90 | loom { 91 | decompilers { 92 | get("vineflower").apply { // Adds names to lambdas - useful for mixins 93 | options.put("mark-corresponding-synthetics", "1") 94 | } 95 | } 96 | 97 | runConfigs.all { 98 | isIdeConfigGenerated = true 99 | runDir = "../../../run" 100 | vmArgs("-Dmixin.debug.export=true") 101 | } 102 | } 103 | 104 | java { 105 | withSourcesJar() 106 | val java = if (stonecutter.eval(minecraft, ">=1.20.5")) 107 | JavaVersion.VERSION_21 else JavaVersion.VERSION_17 108 | targetCompatibility = java 109 | sourceCompatibility = java 110 | } 111 | 112 | tasks.shadowJar { 113 | configurations = listOf(shadowBundle) 114 | archiveClassifier = "dev-shadow" 115 | } 116 | 117 | tasks.remapJar { 118 | injectAccessWidener = true 119 | input = tasks.shadowJar.get().archiveFile 120 | archiveClassifier = loader 121 | dependsOn(tasks.shadowJar) 122 | } 123 | 124 | tasks.jar { 125 | archiveClassifier = "dev" 126 | } 127 | 128 | tasks.processResources { 129 | properties(listOf("fabric.mod.json"), 130 | "id" to mod.id, 131 | "name" to mod.name, 132 | "version" to mod.version, 133 | "minecraft" to common.mod.prop("mc_dep_fabric") 134 | ) 135 | } 136 | 137 | tasks.build { 138 | group = "versioned" 139 | description = "Must run through 'chiseledBuild'" 140 | } 141 | 142 | tasks.register("buildAndCollect") { 143 | group = "versioned" 144 | description = "Must run through 'chiseledBuild'" 145 | from(tasks.remapJar.get().archiveFile, tasks.remapSourcesJar.get().archiveFile) 146 | into(rootProject.layout.buildDirectory.file("libs/${mod.version}/$loader")) 147 | dependsOn("build") 148 | } 149 | 150 | publishing { 151 | publications { 152 | create("maven") { 153 | groupId = mod.prop("group") 154 | artifactId = mod.prop("id") 155 | version = "${mod.version}+${minecraft}-${loader}" 156 | 157 | artifact(tasks.remapJar.get().archiveFile) 158 | artifact(tasks.remapSourcesJar.get().archiveFile) { 159 | classifier = "sources" 160 | } 161 | } 162 | } 163 | } 164 | 165 | publishMods { 166 | displayName = "[Fabric ${common.mod.prop("mc_title")}] ${mod.name} ${mod.version}" 167 | 168 | val modrinthToken = providers.gradleProperty("MODRINTH_TOKEN").orNull 169 | val curseforgeToken = providers.gradleProperty("CURSEFORGE_TOKEN").orNull 170 | dryRun = modrinthToken == null || curseforgeToken == null 171 | 172 | file = tasks.remapJar.get().archiveFile 173 | version = "${mod.version}+$minecraft-$loader" 174 | changelog = mod.prop("changelog") 175 | type = STABLE 176 | modLoaders.add(loader) 177 | 178 | val supportedVersions = common.mod.prop("mc_targets").split(" ") 179 | 180 | modrinth { 181 | projectId = property("publish.modrinth").toString() 182 | accessToken = modrinthToken 183 | minecraftVersions.addAll(supportedVersions) 184 | 185 | requires("fabric-api") 186 | optional("yacl") 187 | optional("modmenu") 188 | } 189 | curseforge { 190 | projectId = property("publish.curseforge").toString() 191 | projectSlug = property("publish.curseforge_slug").toString() 192 | accessToken = curseforgeToken 193 | minecraftVersions.addAll(supportedVersions) 194 | clientRequired = true 195 | serverRequired = false 196 | 197 | requires("fabric-api") 198 | optional("yacl") 199 | optional("modmenu") 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /fabric/gradle.properties: -------------------------------------------------------------------------------- 1 | loom.platform=fabric -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/DehydrationCompat.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat; 2 | 3 | //? if dehydration { 4 | 5 | import mod.crend.autohud.AutoHud; 6 | import mod.crend.autohud.api.AutoHudApi; 7 | import mod.crend.autohud.component.Component; 8 | import mod.crend.autohud.component.Components; 9 | import mod.crend.autohud.component.state.PolicyComponentState; 10 | import mod.crend.autohud.render.ComponentRenderer; 11 | import net.dehydration.access.ThirstManagerAccess; 12 | import net.dehydration.init.EffectInit; 13 | import net.dehydration.misc.ThirstTooltipData; 14 | import net.dehydration.thirst.ThirstManager; 15 | import net.minecraft.client.network.ClientPlayerEntity; 16 | 17 | public class DehydrationCompat implements AutoHudApi { 18 | public static final String DEHYDRATION_MOD_ID = "dehydration"; 19 | 20 | @Override 21 | public String modId() { 22 | return DEHYDRATION_MOD_ID; 23 | } 24 | 25 | // We bind this to the hunger config, as that is the most closely related one. 26 | public static Component Thirst = Component.builder(DEHYDRATION_MOD_ID, "thirst") 27 | .config(AutoHud.config.hunger()) 28 | .stackComponents(Components.Air) 29 | .inMainHud() 30 | .state(player -> { 31 | ThirstManager thirstManager = ((ThirstManagerAccess) player).getThirstManager(); 32 | if (thirstManager.hasThirst()) { 33 | return new PolicyComponentState(DehydrationCompat.Thirst, thirstManager::getThirstLevel, 20); 34 | } 35 | return null; 36 | }) 37 | .build(); 38 | public static ComponentRenderer THIRST_WRAPPER = ComponentRenderer.builder(Thirst) 39 | .move() 40 | .fade() 41 | .withCustomFramebuffer(false) 42 | .build(); 43 | static { 44 | // Fake this API being inserted via entry point 45 | AutoHud.addApi(new DehydrationCompat()); 46 | } 47 | 48 | @Override 49 | public void init() { 50 | Components.Hunger.addStackComponent(Thirst); 51 | } 52 | 53 | @Override 54 | public void tickState(ClientPlayerEntity player) { 55 | if (player.hasStatusEffect(EffectInit.THIRST)) { 56 | Thirst.reveal(); 57 | } else if (((ThirstManagerAccess) player).getThirstManager().isNotFull()) { 58 | if (!player.getMainHandStack().isEmpty() && player.getMainHandStack().getTooltipData().isPresent() && player.getMainHandStack().getTooltipData().get() instanceof ThirstTooltipData) { 59 | Thirst.reveal(); 60 | } else if (!player.getOffHandStack().isEmpty() && player.getOffHandStack().getTooltipData().isPresent() && player.getOffHandStack().getTooltipData().get() instanceof ThirstTooltipData) { 61 | Thirst.reveal(); 62 | } 63 | } 64 | } 65 | } 66 | //?} else { 67 | /*public class DehydrationCompat { } 68 | *///?} 69 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/EnvironmentZCompat.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat; 2 | 3 | //? if environmentz { 4 | import mod.crend.autohud.AutoHud; 5 | import mod.crend.autohud.api.AutoHudApi; 6 | import mod.crend.autohud.component.Component; 7 | import mod.crend.autohud.component.state.ValueComponentState; 8 | import mod.crend.autohud.config.ConfigHandler; 9 | import mod.crend.autohud.render.ComponentRenderer; 10 | import net.environmentz.access.TemperatureManagerAccess; 11 | import net.environmentz.temperature.TemperatureManager; 12 | import net.environmentz.temperature.Temperatures; 13 | import net.minecraft.client.MinecraftClient; 14 | import net.minecraft.client.network.ClientPlayerEntity; 15 | 16 | import java.util.function.Supplier; 17 | 18 | public class EnvironmentZCompat implements AutoHudApi { 19 | public static final String ENVIRONMENTZ_MOD_ID = "environmentz"; 20 | @Override 21 | public String modId() { 22 | return ENVIRONMENTZ_MOD_ID; 23 | } 24 | 25 | public static Component Temperature = Component.builder(ENVIRONMENTZ_MOD_ID, "temperature") 26 | .config(ConfigHandler.DummyPolicyComponent) 27 | .inMainHud() 28 | .state(player -> new EnvironmentZState(EnvironmentZCompat.Temperature, EnvironmentZCompat::temperatureState)) 29 | .build(); 30 | public static Component Thermometer = Component.builder(ENVIRONMENTZ_MOD_ID, "thermometer") 31 | .config(ConfigHandler.DummyPolicyComponent) 32 | .inMainHud() 33 | .state(player -> new EnvironmentZState(EnvironmentZCompat.Thermometer, EnvironmentZCompat::thermometerState)) 34 | .build(); 35 | public static ComponentRenderer TEMPERATURE_WRAPPER = ComponentRenderer.of(Temperature); 36 | public static ComponentRenderer THERMOMETER_WRAPPER = ComponentRenderer.of(Thermometer); 37 | 38 | static { 39 | // Fake this API being inserted via entry point 40 | AutoHud.addApi(new EnvironmentZCompat()); 41 | } 42 | 43 | static int temperatureState() { 44 | TemperatureManager temperatureManager = ((TemperatureManagerAccess) MinecraftClient.getInstance().player).getTemperatureManager(); 45 | int playerTemperature = temperatureManager.getPlayerTemperature(); 46 | if (playerTemperature < Temperatures.getBodyTemperatures(2)) { 47 | // cold 48 | if (playerTemperature < Temperatures.getBodyTemperatures(1)) { 49 | // very cold 50 | return -2; 51 | } 52 | return -1; 53 | } else if (playerTemperature > Temperatures.getBodyTemperatures(4)) { 54 | // hot 55 | if (playerTemperature > Temperatures.getBodyTemperatures(5)) { 56 | // very hot 57 | return 2; 58 | } 59 | return 1; 60 | } 61 | return 0; 62 | } 63 | 64 | static int thermometerState() { 65 | TemperatureManager temperatureManager = ((TemperatureManagerAccess) MinecraftClient.getInstance().player).getTemperatureManager(); 66 | int thermometerTemperature = temperatureManager.getThermometerTemperature(); 67 | if (thermometerTemperature <= Temperatures.getThermometerTemperatures(0)) { 68 | return -2; // very cold 69 | } else if (thermometerTemperature <= Temperatures.getThermometerTemperatures(1)) { 70 | return -1; // cold 71 | } else if (thermometerTemperature <= Temperatures.getThermometerTemperatures(2)) { 72 | return 0; // medium 73 | } else if (thermometerTemperature <= Temperatures.getThermometerTemperatures(3)) { 74 | return 1; // hot 75 | } else { 76 | return 2; // very hot 77 | } 78 | } 79 | 80 | static class EnvironmentZState extends ValueComponentState { 81 | public EnvironmentZState(Component component, Supplier newValueSupplier) { 82 | super(component, newValueSupplier, true); 83 | } 84 | 85 | @Override 86 | protected boolean doReveal(Integer newValue) { 87 | return newValue < -1 || newValue > 1 || super.doReveal(newValue); 88 | } 89 | } 90 | 91 | 92 | @Override 93 | public void tickState(ClientPlayerEntity player) { 94 | TemperatureManager temperatureManager = ((TemperatureManagerAccess) player).getTemperatureManager(); 95 | 96 | if (temperatureManager.getThermometerCalm() > 0) { 97 | Thermometer.reveal(); 98 | } 99 | } 100 | } 101 | //?} else { 102 | /*public class EnvironmentZCompat { 103 | } 104 | *///?} 105 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/MicroDurabilityCompat.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat; 2 | 3 | import mod.crend.autohud.AutoHud; 4 | import mod.crend.autohud.api.AutoHudApi; 5 | import mod.crend.autohud.component.Component; 6 | import mod.crend.autohud.component.Components; 7 | import mod.crend.autohud.component.state.ComponentState; 8 | import net.minecraft.client.network.ClientPlayerEntity; 9 | 10 | public class MicroDurabilityCompat implements AutoHudApi { 11 | public static final String MICRODURABILITY_MOD_ID = "microdurability"; 12 | 13 | @Override 14 | public String modId() { 15 | return MICRODURABILITY_MOD_ID; 16 | } 17 | 18 | // We bind this to the hotbar config, as that is the most closely related one. 19 | public static Component MicroDurabilityComponent = Component.builder(MICRODURABILITY_MOD_ID, "microdurability") 20 | .config(AutoHud.config.hotbar()) 21 | .inMainHud() 22 | .state(player -> new ComponentState(MicroDurabilityCompat.MicroDurabilityComponent)) 23 | .build(); 24 | 25 | static { 26 | // Fake this API being inserted via entry point 27 | AutoHud.addApi(new MicroDurabilityCompat()); 28 | } 29 | 30 | @Override 31 | public void init() { 32 | Components.ExperienceBar.addStackComponent(MicroDurabilityComponent); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/OneBarCompat.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat; 2 | 3 | //? if onebar { 4 | import mod.crend.autohud.AutoHud; 5 | import mod.crend.autohud.api.AutoHudApi; 6 | import mod.crend.autohud.component.Component; 7 | import mod.crend.autohud.component.Components; 8 | import mod.crend.autohud.component.state.ComponentState; 9 | import mod.crend.autohud.render.ComponentRenderer; 10 | import net.minecraft.client.network.ClientPlayerEntity; 11 | 12 | public class OneBarCompat implements AutoHudApi { 13 | public static final String ONEBAR_MOD_ID = "onebar"; 14 | @Override 15 | public String modId() { 16 | return ONEBAR_MOD_ID; 17 | } 18 | 19 | public static Component OneBarComponent = Component.builder(ONEBAR_MOD_ID, "onebar") 20 | .config(AutoHud.config.health()) 21 | .inMainHud() 22 | .state(player -> new ComponentState(OneBarCompat.OneBarComponent)) 23 | .build(); 24 | public static final ComponentRenderer ONE_BAR_WRAPPER = ComponentRenderer.of(OneBarComponent); 25 | 26 | static { 27 | // Fake this API being inserted via entry point 28 | AutoHud.addApi(new OneBarCompat()); 29 | } 30 | 31 | @Override 32 | public void init() { 33 | // Disable vanilla elements that are handled by OneBar 34 | AutoHud.targetExperienceBar = false; 35 | AutoHud.targetStatusBars = false; 36 | 37 | Components.ExperienceBar.addStackComponent(OneBarComponent); 38 | } 39 | 40 | @Override 41 | public void initState(ClientPlayerEntity player) { 42 | OneBarComponent.hideNow(); 43 | } 44 | 45 | @Override 46 | public void tickState(ClientPlayerEntity player) { 47 | OneBarComponent.synchronizeFromHidden( 48 | Components.Health, 49 | Components.Hunger, 50 | Components.Air, 51 | Components.Armor 52 | ); 53 | } 54 | } 55 | //?} else { 56 | /*public class OneBarCompat { } 57 | *///?} 58 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/appleskin/HUDOverlayHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.appleskin; 2 | 3 | import mod.crend.autohud.AutoHud; 4 | import mod.crend.autohud.component.Components; 5 | import mod.crend.autohud.render.AutoHudRenderer; 6 | import mod.crend.autohud.render.ComponentRenderer; 7 | import net.minecraft.client.gui.DrawContext; 8 | //? if >=1.20.5 9 | /*import net.minecraft.entity.player.PlayerEntity;*/ 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | import squeek.appleskin.client.HUDOverlayHandler; 16 | 17 | @Mixin(value = HUDOverlayHandler.class, remap = false) 18 | public class HUDOverlayHandlerMixin { 19 | 20 | @Inject( 21 | //? if <1.20.5 { 22 | method = "onPreRender", 23 | //?} else 24 | /*method = "onPreRenderFood",*/ 25 | at = @At("TAIL") 26 | ) 27 | void autoHud$injectTransparency( 28 | DrawContext context, 29 | //? if >=1.20.5 30 | /*PlayerEntity player, int top, int right,*/ 31 | CallbackInfo ci 32 | ) { 33 | ComponentRenderer.HUNGER.beginFade(context); 34 | } 35 | 36 | //? if <1.21.2 { 37 | @ModifyVariable(method = "enableAlpha", at=@At("HEAD"), argsOnly = true) 38 | float autoHud$modifyAlpha(float alpha) { 39 | return AutoHudRenderer.inRender ? AutoHudRenderer.alpha * alpha : alpha; 40 | } 41 | //?} 42 | } 43 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/armor_hud/ArmorHudMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.armor_hud; 2 | 3 | import mod.crend.autohud.render.ComponentRenderer; 4 | import net.minecraft.client.gui.DrawContext; 5 | import net.minecraft.client.gui.hud.InGameHud; 6 | import org.spongepowered.asm.mixin.Dynamic; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Mixin(value = InGameHud.class, priority = 1200, remap = false) 13 | public class ArmorHudMixin { 14 | @Dynamic("added by BerdinskiyBears Armor Hud") 15 | @Inject(method="drawSlots1", at=@At("HEAD")) 16 | private void autoHud$preDrawSlots1(DrawContext context, int y, int x, int w, int l, CallbackInfo ci) { 17 | ComponentRenderer.HOTBAR.beginRender(context); 18 | } 19 | @Dynamic("added by BerdinskiyBears Armor Hud") 20 | @Inject(method="drawSlots1", at=@At("TAIL")) 21 | private void autoHud$postDrawSlots1(DrawContext context, int y, int x, int w, int l, CallbackInfo ci) { 22 | ComponentRenderer.HOTBAR.endRender(context); 23 | } 24 | 25 | @Dynamic("added by BerdinskiyBears Armor Hud") 26 | @Inject(method="drawSlots2", at=@At("HEAD")) 27 | private void autoHud$preDrawSlots2(DrawContext context, int y, int x, int w, int l, CallbackInfo ci) { 28 | ComponentRenderer.HOTBAR.beginRender(context); 29 | } 30 | @Dynamic("added by BerdinskiyBears Armor Hud") 31 | @Inject(method="drawSlots2", at=@At("TAIL")) 32 | private void autoHud$postDrawSlots2(DrawContext context, int y, int x, int w, int l, CallbackInfo ci) { 33 | ComponentRenderer.HOTBAR.endRender(context); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/armorchroma/GuiArmorMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.armorchroma; 2 | 3 | //? if armorchroma && armorchroma: <=1.2.6 { 4 | import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; 5 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 6 | import mod.crend.autohud.render.ComponentRenderer; 7 | import net.minecraft.client.gui.DrawContext; 8 | import nukeduck.armorchroma.GuiArmor; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | 11 | @Mixin(value = GuiArmor.class, remap = false) 12 | public class GuiArmorMixin { 13 | 14 | @WrapMethod(method = "draw") 15 | void autoHud$wrapArmor(DrawContext context, int left, int top, Operation original) { 16 | ComponentRenderer.ARMOR_FADE.wrap(context, () -> original.call(context, left, top)); 17 | } 18 | 19 | } 20 | //?} else { 21 | /*import mod.crend.libbamboo.VersionUtils; 22 | import org.spongepowered.asm.mixin.Mixin; 23 | 24 | @Mixin(VersionUtils.class) 25 | public class GuiArmorMixin { 26 | } 27 | *///?} 28 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/dehydration/DehydrationMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.dehydration; 2 | 3 | //? if dehydration { 4 | import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; 5 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 6 | import mod.crend.autohud.compat.DehydrationCompat; 7 | import net.dehydration.thirst.ThirstHudRender; 8 | import net.minecraft.client.MinecraftClient; 9 | import net.minecraft.client.gui.DrawContext; 10 | import net.minecraft.entity.player.PlayerEntity; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | 13 | @Mixin(value = ThirstHudRender.class, remap = false) 14 | public class DehydrationMixin { 15 | @WrapMethod( 16 | method = "renderThirstHud" 17 | ) 18 | private static void autoHud$test( 19 | DrawContext context, MinecraftClient client, PlayerEntity playerEntity, int scaledWidth, int scaledHeight, int ticks, 20 | //? if dehydration: <=1.3.6 21 | int vehicleHeartCount, float flashAlpha, float otherFlashAlpha, 22 | Operation original 23 | ) { 24 | 25 | DehydrationCompat.THIRST_WRAPPER.wrap(context, () -> 26 | original.call( 27 | context, client, playerEntity, scaledWidth, scaledHeight, ticks 28 | //? if dehydration: <=1.3.6 29 | , vehicleHeartCount, flashAlpha, otherFlashAlpha 30 | ) 31 | ); 32 | 33 | } 34 | } 35 | //?} else { 36 | 37 | /*import mod.crend.libbamboo.VersionUtils; 38 | import org.spongepowered.asm.mixin.Mixin; 39 | 40 | @Mixin(value = VersionUtils.class, remap = false) 41 | public class DehydrationMixin { 42 | } 43 | *///?} 44 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/dehydration/ThirstManagerMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.dehydration; 2 | 3 | //? if dehydration { 4 | import mod.crend.autohud.compat.DehydrationCompat; 5 | import net.dehydration.thirst.ThirstManager; 6 | import net.minecraft.entity.player.PlayerEntity; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Mixin(value = ThirstManager.class, remap = false) 13 | public class ThirstManagerMixin { 14 | @Inject(method="setThirstLevel", at=@At("TAIL")) 15 | private void autoHud$setThirstLevel(int thirstLevel, CallbackInfo ci) { 16 | DehydrationCompat.Thirst.updateState(); 17 | } 18 | 19 | @Inject(method = "update", at=@At("TAIL")) 20 | private void autoHud$update(PlayerEntity player, CallbackInfo ci) { 21 | DehydrationCompat.Thirst.updateState(); 22 | } 23 | } 24 | //?} else { 25 | 26 | /*import mod.crend.libbamboo.VersionUtils; 27 | import org.spongepowered.asm.mixin.Mixin; 28 | @Mixin(VersionUtils.class) 29 | public class ThirstManagerMixin { 30 | } 31 | *///?} 32 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/detailab/ArmorBarRendererMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.detailab; 2 | 3 | //? if detailab { 4 | import com.redlimerl.detailab.render.ArmorBarRenderer; 5 | import mod.crend.autohud.render.ComponentRenderer; 6 | import net.minecraft.client.gui.DrawContext; 7 | import net.minecraft.entity.player.PlayerEntity; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | @Mixin(value = ArmorBarRenderer.class, remap = false) 14 | public class ArmorBarRendererMixin { 15 | @Inject(method = "render", at = @At("HEAD")) 16 | void autoHud$preRender(DrawContext context, PlayerEntity player, CallbackInfo ci) { 17 | ComponentRenderer.ARMOR_FADE.beginRender(context); 18 | } 19 | @Inject(method = "render", at = @At("TAIL")) 20 | void autoHud$postRender(DrawContext context, PlayerEntity player, CallbackInfo ci) { 21 | ComponentRenderer.ARMOR_FADE.endRender(context); 22 | } 23 | } 24 | //?} else { 25 | /*import mod.crend.libbamboo.VersionUtils; 26 | import org.spongepowered.asm.mixin.Mixin; 27 | 28 | @Mixin(VersionUtils.class) 29 | public class ArmorBarRendererMixin { 30 | } 31 | *///?} 32 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/detailab/InGameDrawerMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.detailab; 2 | 3 | import com.redlimerl.detailab.render.InGameDrawer; 4 | import mod.crend.autohud.render.AutoHudRenderer; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.ModifyArg; 8 | 9 | @Mixin(value = InGameDrawer.class, remap = false) 10 | public class InGameDrawerMixin { 11 | @ModifyArg( 12 | //? if <1.21 { 13 | method = "drawTexture(Lnet/minecraft/client/gui/DrawContext;IIFFIIIILjava/awt/Color;Z)V", 14 | //?} else 15 | /*method = "Lcom/redlimerl/detailab/render/InGameDrawer;drawTexture(Lnet/minecraft/util/Identifier;Lnet/minecraft/client/gui/DrawContext;IIFFIIIILjava/awt/Color;Z)V",*/ 16 | at = @At( 17 | value = "INVOKE", 18 | target = "Lcom/mojang/blaze3d/systems/RenderSystem;setShaderColor(FFFF)V" 19 | ), 20 | index = 3 21 | ) 22 | private static float autoHud$injectAlpha(float alpha) { 23 | return (AutoHudRenderer.inRender ? AutoHudRenderer.alpha * alpha : alpha); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/environmentz/TemperatureHudRenderingMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.environmentz; 2 | 3 | //? if environmentz { 4 | import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; 5 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 6 | import mod.crend.autohud.compat.EnvironmentZCompat; 7 | import mod.crend.autohud.render.AutoHudRenderer; 8 | import net.environmentz.temperature.TemperatureHudRendering; 9 | import net.minecraft.client.MinecraftClient; 10 | import net.minecraft.client.gui.DrawContext; 11 | import net.minecraft.entity.player.PlayerEntity; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.ModifyArg; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 17 | 18 | @Mixin(value = TemperatureHudRendering.class, remap = false) 19 | public class TemperatureHudRenderingMixin { 20 | @WrapMethod(method = "renderPlayerTemperatureIcon") 21 | private static void autoHud$wrapTemperatureIcon(DrawContext context, MinecraftClient client, PlayerEntity playerEntity, boolean heat, int xValue, int yValue, int extra, int intensity, int scaledWidth, int scaledHeight, Operation original) { 22 | EnvironmentZCompat.TEMPERATURE_WRAPPER.wrap(context, () -> 23 | original.call(context, client, playerEntity, heat, xValue, yValue, extra, intensity, scaledWidth, scaledHeight) 24 | ); 25 | } 26 | 27 | @WrapMethod(method = "renderThermometerIcon") 28 | private static void autoHud$wrapThermometerIcon(DrawContext context, MinecraftClient client, PlayerEntity playerEntity, int xValue, int yValue, int scaledWidth, int scaledHeight, Operation original) { 29 | EnvironmentZCompat.THERMOMETER_WRAPPER.wrap(context, () -> 30 | original.call(context, client, playerEntity, xValue, yValue, scaledWidth, scaledHeight) 31 | ); 32 | } 33 | 34 | @ModifyArg( 35 | method = {"renderPlayerTemperatureIcon", "renderThermometerIcon"}, 36 | at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;setShaderColor(FFFF)V"), 37 | index = 3 38 | ) 39 | private static float autoHud$transparentPlayerTemperatureIcon(float alpha) { 40 | return (AutoHudRenderer.inRender ? AutoHudRenderer.alpha * alpha : alpha); 41 | } 42 | 43 | } 44 | //?} else { 45 | /*import mod.crend.libbamboo.VersionUtils; 46 | import org.spongepowered.asm.mixin.Mixin; 47 | 48 | @Mixin(value = VersionUtils.class, remap = false) 49 | public class TemperatureHudRenderingMixin { 50 | } 51 | *///?} -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/farmersdelight/ComfortHealthOverlayMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.farmersdelight; 2 | 3 | //? if farmers_delight_refabricated && 1.20.1 { 4 | import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; 5 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 6 | import mod.crend.autohud.render.ComponentRenderer; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.gui.DrawContext; 9 | import net.minecraft.entity.player.PlayerEntity; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import vectorwing.farmersdelight.client.gui.ComfortHealthOverlay; 12 | 13 | @Mixin(value = ComfortHealthOverlay.class, remap = false) 14 | public class ComfortHealthOverlayMixin { 15 | @WrapMethod( 16 | method = "drawComfortOverlay" 17 | ) 18 | private static void autoHud$wrap(PlayerEntity player, MinecraftClient minecraft, DrawContext context, int left, int top, Operation original) { 19 | ComponentRenderer.HEALTH.wrap(context, () -> original.call(player, minecraft, context, left, top)); 20 | } 21 | } 22 | //?} else { 23 | /*import mod.crend.libbamboo.VersionUtils; 24 | import org.spongepowered.asm.mixin.Mixin; 25 | 26 | @Mixin(value = VersionUtils.class, remap = false) 27 | public class ComfortHealthOverlayMixin { 28 | } 29 | *///?} 30 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/farmersdelight/HUDOverlaysMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.farmersdelight; 2 | 3 | //? if farmers_delight_refabricated && >=1.21 { 4 | /*import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; 5 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 6 | import mod.crend.autohud.render.ComponentRenderer; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.gui.DrawContext; 9 | import net.minecraft.entity.player.HungerManager; 10 | import net.minecraft.entity.player.PlayerEntity; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import vectorwing.farmersdelight.client.gui.HUDOverlays; 13 | 14 | @Mixin(value = HUDOverlays.class, remap = false) 15 | public class HUDOverlaysMixin { 16 | @WrapMethod( 17 | method = "drawComfortOverlay" 18 | ) 19 | private static void autoHud$wrapComfortOverlay(PlayerEntity player, MinecraftClient minecraft, DrawContext context, int left, int top, Operation original) { 20 | ComponentRenderer.HEALTH.wrap(context, () -> original.call(player, minecraft, context, left, top)); 21 | } 22 | 23 | @WrapMethod( 24 | method = "drawNourishmentOverlay" 25 | ) 26 | private static void autoHud$wrapNourishmentOverlay(HungerManager foodData, MinecraftClient minecraft, DrawContext context, int right, int top, boolean naturalHealing, Operation original) { 27 | ComponentRenderer.HEALTH.wrap(context, () -> original.call(foodData, minecraft, context, right, top, naturalHealing)); 28 | } 29 | } 30 | *///?} else { 31 | import mod.crend.libbamboo.VersionUtils; 32 | import org.spongepowered.asm.mixin.Mixin; 33 | 34 | @Mixin(value = VersionUtils.class, remap = false) 35 | public class HUDOverlaysMixin { 36 | } 37 | //?} 38 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/farmersdelight/NourishmentHungerOverlayMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.farmersdelight; 2 | 3 | //? if farmers_delight_refabricated && 1.20.1 { 4 | import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; 5 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 6 | import mod.crend.autohud.render.ComponentRenderer; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.gui.DrawContext; 9 | import net.minecraft.entity.player.HungerManager; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import vectorwing.farmersdelight.client.gui.NourishmentHungerOverlay; 12 | 13 | @Mixin(value = NourishmentHungerOverlay.class, remap = false) 14 | public class NourishmentHungerOverlayMixin { 15 | @WrapMethod( 16 | method = "drawNourishmentOverlay" 17 | ) 18 | private static void autoHud$wrap(HungerManager stats, MinecraftClient mc, DrawContext context, int left, int top, boolean naturalHealing, Operation original) { 19 | ComponentRenderer.HUNGER.wrap(context, () -> original.call(stats, mc, context, left, top, naturalHealing)); 20 | } 21 | } 22 | //?} else { 23 | /*import mod.crend.libbamboo.VersionUtils; 24 | import org.spongepowered.asm.mixin.Mixin; 25 | 26 | @Mixin(value = VersionUtils.class, remap = false) 27 | public class NourishmentHungerOverlayMixin { 28 | } 29 | *///?} 30 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/onebar/OneBarElementsMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.onebar; 2 | 3 | //? if onebar { 4 | import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; 5 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 6 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 7 | import io.github.madis0.OneBarElements; 8 | import mod.crend.autohud.compat.OneBarCompat; 9 | import mod.crend.autohud.render.AutoHudRenderer; 10 | import mod.crend.autohud.render.ComponentRenderer; 11 | import net.minecraft.client.gui.DrawContext; 12 | import org.spongepowered.asm.mixin.Final; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.Shadow; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | import org.spongepowered.asm.mixin.injection.ModifyArg; 17 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 18 | 19 | @Mixin(value = OneBarElements.class, remap = false) 20 | public abstract class OneBarElementsMixin { 21 | @Shadow 22 | @Final 23 | private DrawContext drawContext; 24 | 25 | @WrapMethod(method = "renderOneBar") 26 | private void autoHud$wrapOneBar(Operation original) { 27 | /* 28 | // In 1.20.1, mixin order makes it so we have to reset the context. 29 | // Presumably, something is getting canceled before we can clean up. 30 | //? if onebar: <4.1.0 31 | AutoHudRenderer.postInject(drawContext); 32 | */ 33 | OneBarCompat.ONE_BAR_WRAPPER.wrap(drawContext, () -> original.call()); 34 | } 35 | 36 | @WrapOperation(method = "renderOneBar", at = @At(value = "INVOKE", target = "Lio/github/madis0/OneBarElements;xpBar()V")) 37 | private void autoHud$wrapXpBar(OneBarElements instance, Operation original) { 38 | OneBarCompat.ONE_BAR_WRAPPER.endRender(drawContext); 39 | ComponentRenderer.EXPERIENCE_BAR.wrap(drawContext, () -> original.call(instance)); 40 | OneBarCompat.ONE_BAR_WRAPPER.beginRender(drawContext); 41 | } 42 | 43 | @ModifyVariable(method = "renderBar", at = @At("HEAD"), ordinal = 4, argsOnly = true) 44 | private int autoHud$alpha(int color) { 45 | return AutoHudRenderer.modifyArgb(color); 46 | } 47 | 48 | @ModifyArg( 49 | method = "barText", 50 | at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawText(Lnet/minecraft/client/font/TextRenderer;Ljava/lang/String;IIIZ)I"), 51 | index = 4 52 | ) 53 | private int autoHud$barTextAlpha(int color) { 54 | return AutoHudRenderer.modifyArgb(color); 55 | } 56 | @ModifyArg( 57 | method = "xpBar", 58 | at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTextWithShadow(Lnet/minecraft/client/font/TextRenderer;Ljava/lang/String;III)I"), 59 | index = 4 60 | ) 61 | private int autoHud$xpBarTextAlpha(int color) { 62 | return AutoHudRenderer.modifyArgb(color); 63 | } 64 | @ModifyArg( 65 | method = "xpBar", 66 | at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawCenteredTextWithShadow(Lnet/minecraft/client/font/TextRenderer;Ljava/lang/String;III)V"), 67 | index = 4 68 | ) 69 | private int autoHud$xpBarTextCenteredAlpha(int color) { 70 | return AutoHudRenderer.modifyArgb(color); 71 | } 72 | } 73 | //?} else { 74 | /*import mod.crend.libbamboo.VersionUtils; 75 | import org.spongepowered.asm.mixin.Mixin; 76 | 77 | @Mixin(value = VersionUtils.class, remap = false) 78 | public class OneBarElementsMixin { 79 | } 80 | *///?} 81 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/compat/mixin/statuseffectbars/StatusEffectBarRendererMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat.mixin.statuseffectbars; 2 | 3 | //? if statuseffectbars { 4 | import io.github.a5b84.statuseffectbars.StatusEffectBarRenderer; 5 | import mod.crend.autohud.component.Component; 6 | import mod.crend.autohud.render.AutoHudRenderer; 7 | import net.minecraft.client.gui.DrawContext; 8 | import net.minecraft.client.render.RenderTickCounter; 9 | import net.minecraft.entity.effect.StatusEffectInstance; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 13 | 14 | @Mixin(value = StatusEffectBarRenderer.class, remap = false) 15 | public class StatusEffectBarRendererMixin { 16 | @ModifyVariable( 17 | method = "render", 18 | at = @At("HEAD"), 19 | ordinal = 1, 20 | argsOnly = true) 21 | private static int autoHud$renderWithOffset( 22 | int y, 23 | DrawContext context, 24 | //? if >=1.21 { 25 | /*RenderTickCounter renderTickCounter, 26 | *///?} else if >=1.20.5 27 | /*float tickDelta,*/ 28 | StatusEffectInstance effect 29 | ) { 30 | if (AutoHudRenderer.inRender) { 31 | return y + (int) Component.get(effect.getEffectType()).getOffsetY(AutoHudRenderer.tickDelta); 32 | } 33 | return y; 34 | } 35 | } 36 | //?} else { 37 | /*import mod.crend.libbamboo.VersionUtils; 38 | import org.spongepowered.asm.mixin.Mixin; 39 | 40 | @Mixin(value = VersionUtils.class, remap = false) 41 | public class StatusEffectBarRendererMixin { 42 | } 43 | *///?} 44 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/fabric/AutoHudFabric.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.fabric; 2 | 3 | import mod.crend.autohud.AutoHud; 4 | import mod.crend.autohud.ModKeyBindings; 5 | import mod.crend.autohud.api.AutoHudApi; 6 | import mod.crend.autohud.compat.HotbarSlotCyclingCompat; 7 | import mod.crend.autohud.compat.RaisedCompat; 8 | import mod.crend.autohud.render.AutoHudRenderer; 9 | import net.fabricmc.api.ClientModInitializer; 10 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; 11 | import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; 12 | import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; 13 | import net.fabricmc.loader.api.FabricLoader; 14 | 15 | public class AutoHudFabric implements ClientModInitializer { 16 | 17 | @Override 18 | public void onInitializeClient() { 19 | AutoHud.loadConfig(); 20 | AutoHud.init(); 21 | 22 | ModKeyBindings.ALL.forEach(KeyBindingHelper::registerKeyBinding); 23 | ClientTickEvents.END_CLIENT_TICK.register(ModKeyBindings::clientTick); 24 | 25 | HudRenderCallback.EVENT.register(AutoHudRenderer::renderChatMessageIndicator); 26 | 27 | FabricLoader.getInstance().getEntrypointContainers(AutoHud.MOD_ID, AutoHudApi.class).forEach(entrypoint -> { 28 | AutoHud.addApi(entrypoint.getEntrypoint()); 29 | }); 30 | 31 | if (FabricLoader.getInstance().isModLoaded("raised")) { 32 | ClientTickEvents.END_CLIENT_TICK.register(RaisedCompat::tick); 33 | } 34 | 35 | if (FabricLoader.getInstance().isModLoaded("hotbarslotcycling")) { 36 | AutoHud.addApi(new HotbarSlotCyclingCompat()); 37 | } 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/fabric/mixin/gui/ChatHudMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.fabric.mixin.gui; 2 | 3 | import mod.crend.autohud.component.Components; 4 | import net.minecraft.client.gui.hud.ChatHud; 5 | import net.minecraft.client.gui.hud.MessageIndicator; 6 | import net.minecraft.network.message.MessageSignatureData; 7 | import net.minecraft.text.Text; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | @Mixin(ChatHud.class) 14 | public class ChatHudMixin { 15 | 16 | @Inject(method = "addMessage(Lnet/minecraft/text/Text;Lnet/minecraft/network/message/MessageSignatureData;Lnet/minecraft/client/gui/hud/MessageIndicator;)V", at = @At("TAIL")) 17 | private void autoHud$showChatMessageIndicator(Text message, MessageSignatureData signature, MessageIndicator indicator, CallbackInfo ci) { 18 | if (Components.Chat.config.active() && Components.ChatIndicator.config.active() && Components.Chat.isHidden()) { 19 | Components.ChatIndicator.reveal(); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/fabric/mixin/gui/StatusEffectTimerMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.fabric.mixin.gui; 2 | 3 | import com.llamalad7.mixinextras.sugar.Local; 4 | import mod.crend.autohud.AutoHud; 5 | import mod.crend.autohud.render.ComponentRenderer; 6 | import mod.crend.libbamboo.PlatformUtils; 7 | import net.fabricmc.api.EnvType; 8 | import net.fabricmc.api.Environment; 9 | import net.minecraft.client.MinecraftClient; 10 | import net.minecraft.client.gui.DrawContext; 11 | import net.minecraft.client.gui.hud.InGameHud; 12 | import net.minecraft.client.render.RenderTickCounter; 13 | import net.minecraft.client.resource.language.I18n; 14 | import net.minecraft.entity.effect.StatusEffectInstance; 15 | import net.minecraft.util.math.MathHelper; 16 | import org.spongepowered.asm.mixin.Final; 17 | import org.spongepowered.asm.mixin.Mixin; 18 | import org.spongepowered.asm.mixin.Shadow; 19 | import org.spongepowered.asm.mixin.Unique; 20 | import org.spongepowered.asm.mixin.injection.At; 21 | import org.spongepowered.asm.mixin.injection.Inject; 22 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 23 | 24 | import java.util.List; 25 | 26 | /* 27 | * This file is originally part of the StatusEffectTimer mod: 28 | * https://github.com/magicus/statuseffecttimer 29 | * 30 | * It is included here in order to be modified properly. 31 | * Changes: 32 | * - Skip timers for hidden effects by redirecting StatusEffectInstance.shouldShowIcon() 33 | * - Insert matrix push/pop for moving each timer text with its icon 34 | */ 35 | 36 | // Set priority to 500, to load before default at 1000. This is to better cooperate with HUDTweaks. 37 | @Environment(EnvType.CLIENT) 38 | @Mixin(value = InGameHud.class, priority = 500) 39 | public abstract class StatusEffectTimerMixin { 40 | @Shadow @Final 41 | private MinecraftClient client; 42 | 43 | @Inject(method = "renderStatusEffectOverlay", 44 | at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", shift = At.Shift.AFTER)) 45 | private void appendOverlayDrawing( 46 | DrawContext context, 47 | //? if >1.20.6 { 48 | /*RenderTickCounter tickDelta, 49 | *///?} else if >1.20.5 50 | /*float tickDelta,*/ 51 | CallbackInfo c, 52 | @Local List list, 53 | @Local StatusEffectInstance statusEffectInstance, 54 | @Local(ordinal = 2) int i2, 55 | @Local(ordinal = 3) int i3, 56 | @Local(ordinal = 4) int i4, 57 | @Local(ordinal = 5) int i5 58 | ) { 59 | list.add(() -> { 60 | if (AutoHud.config.statusEffectTimer()) { 61 | int x = switch (PlatformUtils.getCurrentPlatform()) { 62 | case FABRIC -> i4; 63 | case FORGE -> i5; 64 | case NEOFORGE -> i2; 65 | }; 66 | int y = switch (PlatformUtils.getCurrentPlatform()) { 67 | case FABRIC -> i5; 68 | case FORGE -> i3; 69 | case NEOFORGE -> i3; 70 | }; 71 | ComponentRenderer.getForStatusEffect(statusEffectInstance).wrap(context, () -> drawStatusEffectOverlay(context, statusEffectInstance, x, y)); 72 | } 73 | }); 74 | } 75 | 76 | @Unique 77 | private void drawStatusEffectOverlay(DrawContext context, StatusEffectInstance statusEffectInstance, int x, int y) { 78 | String duration = getDurationAsString(statusEffectInstance); 79 | int durationLength = client.textRenderer.getWidth(duration); 80 | context.drawTextWithShadow(client.textRenderer, duration, x + 13 - (durationLength / 2), y + 14, 0x99FFFFFF); 81 | 82 | int amplifier = statusEffectInstance.getAmplifier(); 83 | if (amplifier > 0) { 84 | // Convert to roman numerals if possible 85 | String amplifierString = (amplifier < 10) ? I18n.translate("enchantment.level." + (amplifier + 1)) : "**"; 86 | int amplifierLength = client.textRenderer.getWidth(amplifierString); 87 | context.drawTextWithShadow(client.textRenderer, amplifierString, x + 22 - amplifierLength, y + 3, 0x99FFFFFF); 88 | } 89 | } 90 | 91 | @Unique 92 | private String getDurationAsString(StatusEffectInstance statusEffectInstance) { 93 | if (statusEffectInstance.isInfinite()) { 94 | return I18n.translate("effect.duration.infinite"); 95 | } 96 | 97 | int ticks = MathHelper.floor((float) statusEffectInstance.getDuration()); 98 | int seconds = ticks / 20; 99 | 100 | if (seconds >= 3600) { 101 | return seconds / 3600 + "h"; 102 | } else if (seconds >= 60) { 103 | return seconds / 60 + "m"; 104 | } else { 105 | return String.valueOf(seconds); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /fabric/src/main/java/mod/crend/autohud/fabric/screen/ModMenuIntegration.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.fabric.screen; 2 | 3 | import com.terraformersmc.modmenu.api.ModMenuApi; 4 | import mod.crend.autohud.config.ConfigHandler; 5 | import net.fabricmc.api.EnvType; 6 | import net.fabricmc.api.Environment; 7 | 8 | @Environment(EnvType.CLIENT) 9 | public class ModMenuIntegration implements ModMenuApi { 10 | @Override 11 | public com.terraformersmc.modmenu.api.ConfigScreenFactory getModConfigScreenFactory() { 12 | return ConfigHandler.CONFIG_STORE::makeScreen; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /fabric/src/main/resources/autohud-fabric-compat.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "mod.crend.autohud.compat.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "client": [ 7 | "appleskin.HUDOverlayHandlerMixin", 8 | "armor_hud.ArmorHudMixin", 9 | "armorchroma.GuiArmorMixin", 10 | "dehydration.DehydrationMixin", 11 | "dehydration.ThirstManagerMixin", 12 | "detailab.ArmorBarRendererMixin", 13 | "detailab.InGameDrawerMixin", 14 | "environmentz.TemperatureHudRenderingMixin", 15 | "farmersdelight.ComfortHealthOverlayMixin", 16 | "farmersdelight.HUDOverlaysMixin", 17 | "farmersdelight.NourishmentHungerOverlayMixin", 18 | "onebar.OneBarElementsMixin", 19 | "statuseffectbars.StatusEffectBarRendererMixin" 20 | ], 21 | "injectors": { 22 | "defaultRequire": 0 23 | }, 24 | "plugin": "mod.crend.autohud.AutoHudCompatMixinPlugin" 25 | } 26 | -------------------------------------------------------------------------------- /fabric/src/main/resources/autohud-fabric.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "mod.crend.autohud.fabric.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "client": [ 7 | "gui.ChatHudMixin", 8 | "gui.InGameHudMixin", 9 | "gui.StatusEffectTimerMixin" 10 | ], 11 | "injectors": { 12 | "defaultRequire": 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /fabric/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "${id}", 4 | "version": "${version}", 5 | "name": "${name}", 6 | "description": "Dynamic HUD that hides interface elements while they are not needed.", 7 | "authors": [ 8 | "Crendgrim" 9 | ], 10 | "contributors": [ 11 | "JuggleStruggle" 12 | ], 13 | "contact": { 14 | "sources": "https://github.com/Crendgrim/AutoHUD", 15 | "issues": "https://github.com/Crendgrim/AutoHUD/issues" 16 | }, 17 | 18 | "license": "LGPL-3.0", 19 | "icon": "autohud.png", 20 | "environment": "client", 21 | "entrypoints": { 22 | "client": [ 23 | "mod.crend.autohud.fabric.AutoHudFabric" 24 | ], 25 | "modmenu": [ 26 | "mod.crend.autohud.fabric.screen.ModMenuIntegration" 27 | ] 28 | }, 29 | "mixins": [ 30 | "autohud-common.mixins.json", 31 | "autohud-common-compat.mixins.json", 32 | "autohud-fabric.mixins.json", 33 | "autohud-fabric-compat.mixins.json" 34 | ], 35 | "depends": { 36 | "fabricloader": ">=0.15", 37 | "minecraft": "${minecraft}" 38 | } 39 | } -------------------------------------------------------------------------------- /forge/build.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | plugins { 4 | id("dev.architectury.loom") 5 | id("architectury-plugin") 6 | id("com.github.johnrengelman.shadow") 7 | id("maven-publish") 8 | id("me.modmuss50.mod-publish-plugin") 9 | } 10 | 11 | val loader = prop("loom.platform")!! 12 | val minecraft: String = stonecutter.current.version 13 | val common: Project = requireNotNull(stonecutter.node.sibling("")) { 14 | "No common project for $project" 15 | } 16 | 17 | version = "${mod.version}+$minecraft" 18 | group = "${mod.group}.$loader" 19 | base { 20 | archivesName.set(mod.id) 21 | } 22 | architectury { 23 | platformSetupLoomIde() 24 | forge() 25 | } 26 | 27 | val commonBundle: Configuration by configurations.creating { 28 | isCanBeConsumed = false 29 | isCanBeResolved = true 30 | } 31 | 32 | val shadowBundle: Configuration by configurations.creating { 33 | isCanBeConsumed = false 34 | isCanBeResolved = true 35 | } 36 | 37 | configurations { 38 | compileClasspath.get().extendsFrom(commonBundle) 39 | runtimeClasspath.get().extendsFrom(commonBundle) 40 | get("developmentForge").extendsFrom(commonBundle) 41 | } 42 | 43 | repositories { 44 | maven("https://maven.minecraftforge.net") 45 | } 46 | 47 | dependencies { 48 | minecraft("com.mojang:minecraft:$minecraft") 49 | mappings("net.fabricmc:yarn:$minecraft+build.${common.mod.dep("yarn_build")}:v2") 50 | "forge"("net.minecraftforge:forge:$minecraft-${common.mod.dep("forge_loader")}") 51 | "io.github.llamalad7:mixinextras-common:${mod.dep("mixin_extras")}".let { 52 | annotationProcessor(it) 53 | implementation(it) 54 | } 55 | "io.github.llamalad7:mixinextras-forge:${mod.dep("mixin_extras")}".let { 56 | implementation(it) 57 | include(it) 58 | } 59 | 60 | mapOf( 61 | "coldsweat" to "maven.modrinth:cold-sweat:${common.mod.dep("coldsweat_artifact")}", 62 | "hotbarslotcycling" to "fuzs.hotbarslotcycling:hotbarslotcycling-forge:{}", 63 | "legendary_survival_overhaul" to "curse.maven:legendary-survival-overhaul-840254:{}", 64 | "quark" to "maven.modrinth:quark:{}", 65 | "raised" to "maven.modrinth:raised:Forge-${common.mod.dep("raised_artifact")}-{}", 66 | ).map { (modName, url) -> 67 | common.mod.dep("forge", modName) to url.replace("{}", common.mod.dep("forge", modName)) 68 | }.filterNot { (version, _) -> 69 | version.startsWith("[") 70 | }.forEach { (_, url) -> 71 | modCompileOnly(url) 72 | } 73 | 74 | modImplementation(name="libbamboo", group="mod.crend", version="${common.mod.dep("libbamboo")}-forge") 75 | include(name="libbamboo", group="mod.crend", version="${common.mod.dep("libbamboo")}-forge") 76 | 77 | commonBundle(project(common.path, "namedElements")) { isTransitive = false } 78 | shadowBundle(project(common.path, "transformProductionForge")) { isTransitive = false } 79 | } 80 | 81 | loom { 82 | decompilers { 83 | get("vineflower").apply { // Adds names to lambdas - useful for mixins 84 | options.put("mark-corresponding-synthetics", "1") 85 | } 86 | } 87 | 88 | forge.convertAccessWideners = true 89 | forge.mixinConfigs( 90 | "autohud-common.mixins.json", 91 | "autohud-common-compat.mixins.json", 92 | "autohud-forge.mixins.json", 93 | "autohud-forge-compat.mixins.json", 94 | ) 95 | 96 | runConfigs.all { 97 | isIdeConfigGenerated = true 98 | runDir = "../../../run" 99 | vmArgs("-Dmixin.debug.export=true") 100 | } 101 | } 102 | 103 | java { 104 | withSourcesJar() 105 | val java = if (stonecutter.eval(minecraft, ">=1.20.5")) 106 | JavaVersion.VERSION_21 else JavaVersion.VERSION_17 107 | targetCompatibility = java 108 | sourceCompatibility = java 109 | } 110 | 111 | tasks.jar { 112 | archiveClassifier = "dev" 113 | } 114 | 115 | tasks.remapJar { 116 | injectAccessWidener = true 117 | input = tasks.shadowJar.get().archiveFile 118 | archiveClassifier = loader 119 | dependsOn(tasks.shadowJar) 120 | } 121 | 122 | tasks.shadowJar { 123 | configurations = listOf(shadowBundle) 124 | archiveClassifier = "dev-shadow" 125 | exclude("fabric.mod.json", "architectury.common.json") 126 | } 127 | 128 | tasks.processResources { 129 | properties(listOf("META-INF/mods.toml", "pack.mcmeta"), 130 | "id" to mod.id, 131 | "name" to mod.name, 132 | "version" to mod.version, 133 | "minecraft" to common.mod.prop("mc_dep_forgelike") 134 | ) 135 | } 136 | 137 | tasks.build { 138 | group = "versioned" 139 | description = "Must run through 'chiseledBuild'" 140 | } 141 | 142 | tasks.register("buildAndCollect") { 143 | group = "versioned" 144 | description = "Must run through 'chiseledBuild'" 145 | from(tasks.remapJar.get().archiveFile, tasks.remapSourcesJar.get().archiveFile) 146 | into(rootProject.layout.buildDirectory.file("libs/${mod.version}/$loader")) 147 | dependsOn("build") 148 | } 149 | 150 | publishing { 151 | publications { 152 | create("maven") { 153 | groupId = mod.prop("group") 154 | artifactId = mod.prop("id") 155 | version = "${mod.version}+${minecraft}-${loader}" 156 | 157 | artifact(tasks.remapJar.get().archiveFile) 158 | artifact(tasks.remapSourcesJar.get().archiveFile) { 159 | classifier = "sources" 160 | } 161 | } 162 | } 163 | } 164 | 165 | publishMods { 166 | displayName = "[Forge ${common.mod.prop("mc_title")}] ${mod.name} ${mod.version}" 167 | 168 | val modrinthToken = providers.gradleProperty("MODRINTH_TOKEN").orNull 169 | val curseforgeToken = providers.gradleProperty("CURSEFORGE_TOKEN").orNull 170 | dryRun = modrinthToken == null || curseforgeToken == null 171 | 172 | file = tasks.remapJar.get().archiveFile 173 | version = "${mod.version}+$minecraft-$loader" 174 | changelog = mod.prop("changelog") 175 | type = STABLE 176 | modLoaders.add(loader) 177 | 178 | val supportedVersions = common.mod.prop("mc_targets").split(" ") 179 | 180 | modrinth { 181 | projectId = property("publish.modrinth").toString() 182 | accessToken = modrinthToken 183 | minecraftVersions.addAll(supportedVersions) 184 | 185 | optional("yacl") 186 | } 187 | curseforge { 188 | projectId = property("publish.curseforge").toString() 189 | projectSlug = property("publish.curseforge_slug").toString() 190 | accessToken = curseforgeToken 191 | minecraftVersions.addAll(supportedVersions) 192 | clientRequired = true 193 | serverRequired = false 194 | 195 | optional("yacl") 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /forge/gradle.properties: -------------------------------------------------------------------------------- 1 | loom.platform=forge -------------------------------------------------------------------------------- /forge/src/main/java/mod/crend/autohud/forge/AutoHudForge.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.forge; 2 | 3 | import mod.crend.autohud.AutoHud; 4 | import mod.crend.autohud.ModKeyBindings; 5 | //? if raised 6 | import mod.crend.autohud.compat.RaisedCompat; 7 | import mod.crend.autohud.config.ConfigHandler; 8 | import mod.crend.libbamboo.forge.ConfigScreen; 9 | import net.minecraft.client.MinecraftClient; 10 | import net.minecraftforge.event.TickEvent; 11 | import net.minecraftforge.fml.ModLoadingContext; 12 | import net.minecraftforge.fml.common.Mod; 13 | //? if >=1.21.1 14 | /*import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;*/ 15 | 16 | @Mod(AutoHud.MOD_ID) 17 | public class AutoHudForge { 18 | static boolean raisedCompat = false; 19 | 20 | public AutoHudForge(/*? if >=1.21.1 {*//*FMLJavaModLoadingContext context*//*?}*/) { 21 | AutoHud.loadConfig(); 22 | ConfigScreen.register( 23 | //? if <1.21.1 { 24 | ModLoadingContext.get(), 25 | //?} else 26 | /*context,*/ 27 | ConfigHandler.CONFIG_STORE 28 | ); 29 | } 30 | 31 | // Do not use @SubscribeEvent here because the mod "placebo" forces the game bus to run early for some reason. 32 | // This causes the key bindings to get ticked before the config is loaded... 33 | static void onClientTick(TickEvent.ClientTickEvent event) { 34 | if (event.phase == TickEvent.Phase.END) { 35 | ModKeyBindings.clientTick(MinecraftClient.getInstance()); 36 | 37 | //? if raised { 38 | if (raisedCompat) { 39 | RaisedCompat.tick(); 40 | } 41 | //?} 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /forge/src/main/java/mod/crend/autohud/forge/AutoHudGui.java: -------------------------------------------------------------------------------- 1 | //? if <1.20.5 { 2 | package mod.crend.autohud.forge; 3 | 4 | import mod.crend.autohud.render.ComponentRenderer; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.util.Identifier; 7 | import net.minecraftforge.client.event.RenderGuiOverlayEvent; 8 | import net.minecraftforge.client.gui.overlay.ForgeGui; 9 | import net.minecraftforge.eventbus.api.EventPriority; 10 | import net.minecraftforge.eventbus.api.SubscribeEvent; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.Optional; 15 | 16 | import static net.minecraftforge.client.gui.overlay.VanillaGuiOverlay.*; 17 | 18 | public class AutoHudGui extends ForgeGui { 19 | 20 | public static final Map COMPONENT_RENDERERS = new HashMap<>(); 21 | static { 22 | COMPONENT_RENDERERS.put(PLAYER_HEALTH.id(), ComponentRenderer.HEALTH); 23 | COMPONENT_RENDERERS.put(ARMOR_LEVEL.id(), ComponentRenderer.ARMOR); 24 | COMPONENT_RENDERERS.put(FOOD_LEVEL.id(), ComponentRenderer.HUNGER); 25 | COMPONENT_RENDERERS.put(AIR_LEVEL.id(), ComponentRenderer.AIR); 26 | COMPONENT_RENDERERS.put(MOUNT_HEALTH.id(), ComponentRenderer.MOUNT_HEALTH); 27 | COMPONENT_RENDERERS.put(JUMP_BAR.id(), ComponentRenderer.MOUNT_JUMP_BAR); 28 | COMPONENT_RENDERERS.put(EXPERIENCE_BAR.id(), ComponentRenderer.EXPERIENCE_BAR_FORGE); 29 | //RENDER_WRAPPERS.put(EXPERIENCE_LEVEL.id(), ComponentRenderer.EXPERIENCE_LEVEL); 30 | 31 | COMPONENT_RENDERERS.put(SCOREBOARD.id(), ComponentRenderer.SCOREBOARD); 32 | COMPONENT_RENDERERS.put(HOTBAR.id(), ComponentRenderer.HOTBAR); 33 | COMPONENT_RENDERERS.put(ITEM_NAME.id(), ComponentRenderer.TOOLTIP); 34 | COMPONENT_RENDERERS.put(CHAT_PANEL.id(), ComponentRenderer.CHAT); 35 | COMPONENT_RENDERERS.put(TITLE_TEXT.id(), ComponentRenderer.ACTION_BAR); 36 | COMPONENT_RENDERERS.put(BOSS_EVENT_PROGRESS.id(), ComponentRenderer.BOSS_BAR); 37 | } 38 | 39 | public AutoHudGui() { 40 | super(MinecraftClient.getInstance()); 41 | } 42 | 43 | @SubscribeEvent(priority = EventPriority.HIGHEST, receiveCanceled = true) 44 | public void preHudComponent(RenderGuiOverlayEvent.Pre event) { 45 | Optional.ofNullable(COMPONENT_RENDERERS.get(event.getOverlay().id())).ifPresent( 46 | wrapper -> { 47 | if (wrapper.isActive() && !wrapper.doRender()) { 48 | event.setCanceled(true); 49 | } 50 | // Forge only: need to begin render for canceled events 51 | wrapper.beginRender(event.getGuiGraphics()); 52 | } 53 | ); 54 | } 55 | @SubscribeEvent(priority = EventPriority.LOWEST, receiveCanceled = true) 56 | public void cancelHudComponent(RenderGuiOverlayEvent.Pre event) { 57 | if (event.isCanceled()) { 58 | Optional.ofNullable(COMPONENT_RENDERERS.get(event.getOverlay().id())).ifPresent( 59 | wrapper -> wrapper.endRender(event.getGuiGraphics()) 60 | ); 61 | } 62 | } 63 | @SubscribeEvent(priority = EventPriority.LOWEST, receiveCanceled = true) 64 | public void postHudComponent(RenderGuiOverlayEvent.Post event) { 65 | Optional.ofNullable(COMPONENT_RENDERERS.get(event.getOverlay().id())).ifPresent( 66 | wrapper -> wrapper.endRender(event.getGuiGraphics()) 67 | ); 68 | } 69 | } 70 | //?} 71 | -------------------------------------------------------------------------------- /forge/src/main/java/mod/crend/autohud/forge/AutoHudModEvents.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.forge; 2 | 3 | import mod.crend.autohud.AutoHud; 4 | import mod.crend.autohud.ModKeyBindings; 5 | import mod.crend.autohud.api.AutoHudApi; 6 | //? if hotbarslotcycling 7 | /*import mod.crend.autohud.compat.HotbarSlotCyclingCompat;*/ 8 | //? if coldsweat 9 | import mod.crend.autohud.forge.compat.ColdSweatCompat; 10 | //? if quark 11 | import mod.crend.autohud.forge.compat.QuarkCompat; 12 | //? if legendary_survival_overhaul 13 | import mod.crend.autohud.forge.compat.legendarysurvivaloverhaul.LSOCompat; 14 | import net.minecraftforge.api.distmarker.Dist; 15 | //? if <1.20.5 { 16 | import net.minecraftforge.client.event.RegisterGuiOverlaysEvent; 17 | import mod.crend.autohud.render.AutoHudRenderer; 18 | //?} 19 | import net.minecraftforge.client.event.CustomizeGuiOverlayEvent; 20 | import net.minecraftforge.client.event.RegisterKeyMappingsEvent; 21 | import net.minecraftforge.common.MinecraftForge; 22 | import net.minecraftforge.eventbus.api.SubscribeEvent; 23 | import net.minecraftforge.fml.InterModComms; 24 | import net.minecraftforge.fml.ModList; 25 | import net.minecraftforge.fml.common.Mod; 26 | import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; 27 | import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent; 28 | 29 | @Mod.EventBusSubscriber(modid = AutoHud.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) 30 | public class AutoHudModEvents { 31 | public static final String REGISTER_API = "register_api"; 32 | public static final String NEW_CHAT_MESSAGE_INDICATOR = "new_chat_message_indicator"; 33 | 34 | @SubscribeEvent 35 | static void onClientSetup(FMLClientSetupEvent event) { 36 | AutoHud.init(); 37 | //? if <1.20.5 38 | MinecraftForge.EVENT_BUS.register(new AutoHudGui()); 39 | ModList modList = ModList.get(); 40 | //? if hotbarslotcycling { 41 | /*if (modList.isLoaded("hotbarslotcycling")) { 42 | AutoHud.addApi(new HotbarSlotCyclingCompat()); 43 | } 44 | *///?} 45 | //? if raised { 46 | if (modList.isLoaded("raised")) { 47 | AutoHudForge.raisedCompat = true; 48 | } 49 | //?} 50 | //? if legendary_survival_overhaul { 51 | if (modList.isLoaded("legendarysurvivaloverhaul")) { 52 | AutoHud.addApi(new LSOCompat()); 53 | } 54 | //?} 55 | //? if quark { 56 | if (modList.isLoaded("quark")) { 57 | AutoHud.addApi(new QuarkCompat()); 58 | } 59 | //?} 60 | //? if coldsweat { 61 | if (modList.isLoaded("cold_sweat")) { 62 | AutoHud.addApi(new ColdSweatCompat()); 63 | } 64 | //?} 65 | // Delay initialising the client tick event, see that method. 66 | MinecraftForge.EVENT_BUS.addListener(AutoHudForge::onClientTick); 67 | } 68 | 69 | @SubscribeEvent 70 | static void onInterModProcess(InterModProcessEvent event) { 71 | InterModComms.getMessages(AutoHud.MOD_ID, REGISTER_API::equals) 72 | .map(msg -> (AutoHudApi) msg.messageSupplier().get()) 73 | .forEach(AutoHud::addApi); 74 | } 75 | 76 | @SubscribeEvent 77 | static void onKeyMappingsRegister(RegisterKeyMappingsEvent event) { 78 | ModKeyBindings.ALL.forEach(event::register); 79 | } 80 | 81 | //? if <1.20.5 { 82 | @SubscribeEvent 83 | static void onRegisterOverlaysEvent(RegisterGuiOverlaysEvent event) { 84 | event.registerAboveAll(NEW_CHAT_MESSAGE_INDICATOR, (forgeGui, context, f, i, j) -> AutoHudRenderer.renderChatMessageIndicator(context, f)); 85 | } 86 | //?} 87 | 88 | } 89 | -------------------------------------------------------------------------------- /forge/src/main/java/mod/crend/autohud/forge/compat/ColdSweatCompat.java: -------------------------------------------------------------------------------- 1 | //? if coldsweat { 2 | package mod.crend.autohud.forge.compat; 3 | 4 | import com.momosoftworks.coldsweat.ColdSweat; 5 | import com.momosoftworks.coldsweat.api.util.Temperature; 6 | import com.momosoftworks.coldsweat.client.gui.Overlays; 7 | import com.momosoftworks.coldsweat.common.capability.handler.EntityTempManager; 8 | import com.momosoftworks.coldsweat.common.capability.temperature.PlayerTempCap; 9 | import com.momosoftworks.coldsweat.config.ConfigSettings; 10 | import mod.crend.autohud.api.AutoHudApi; 11 | import mod.crend.autohud.component.Component; 12 | import mod.crend.autohud.component.state.ValueComponentState; 13 | import mod.crend.autohud.config.ConfigHandler; 14 | //? if <1.20.5 15 | import mod.crend.autohud.forge.AutoHudGui; 16 | import mod.crend.autohud.render.ComponentRenderer; 17 | import net.minecraft.client.network.ClientPlayerEntity; 18 | 19 | public class ColdSweatCompat implements AutoHudApi { 20 | @Override 21 | public String modId() { 22 | return ColdSweat.MOD_ID; 23 | } 24 | 25 | public static Component BODY_TEMP_GAUGE = Component.builder(ColdSweat.MOD_ID, "body_temp") 26 | .inMainHud() 27 | .config(ConfigHandler.DummyBooleanComponent) 28 | .state(player -> new ValueComponentState<>(ColdSweatCompat.BODY_TEMP_GAUGE, () -> Overlays.BODY_TEMP, true)) 29 | .build(); 30 | public static Component WORLD_TEMP_GAUGE = Component.builder(ColdSweat.MOD_ID, "world_temp") 31 | .inMainHud() 32 | .config(ConfigHandler.DummyBooleanComponent) 33 | .state(player -> new TemperatureState(ColdSweatCompat.WORLD_TEMP_GAUGE)) 34 | .build(); 35 | public static Component VAGUE_TEMP_GAUGE = Component.builder(ColdSweat.MOD_ID, "vague_temp") 36 | .inMainHud() 37 | .config(ConfigHandler.DummyBooleanComponent) 38 | .state(player -> new TemperatureState(ColdSweatCompat.VAGUE_TEMP_GAUGE)) 39 | .build(); 40 | 41 | static class TemperatureState extends ValueComponentState { 42 | static double PLAYER_MAX_TEMP; 43 | static double PLAYER_MIN_TEMP; 44 | 45 | public TemperatureState(Component component) { 46 | super(component, () -> { 47 | double temp = Temperature.convert(Overlays.WORLD_TEMP, ConfigSettings.CELSIUS.get() ? Temperature.Units.C : Temperature.Units.F, Temperature.Units.MC, true); 48 | return Overlays.getGaugeSeverity(temp, PLAYER_MIN_TEMP, PLAYER_MAX_TEMP); 49 | }, true); 50 | } 51 | 52 | @Override 53 | protected boolean doReveal(Integer newValue) { 54 | return super.doReveal(newValue) || newValue < -2 || newValue > 2; 55 | } 56 | } 57 | 58 | @Override 59 | public void tickState(ClientPlayerEntity player) { 60 | EntityTempManager.getTemperatureCap(player).ifPresent((icap) -> { 61 | if (icap instanceof PlayerTempCap cap) { 62 | TemperatureState.PLAYER_MAX_TEMP = cap.getTrait(Temperature.Trait.BURNING_POINT); 63 | TemperatureState.PLAYER_MIN_TEMP = cap.getTrait(Temperature.Trait.FREEZING_POINT); 64 | } 65 | }); 66 | } 67 | 68 | public static ComponentRenderer BODY_TEMP_RENDERER = ComponentRenderer.of(BODY_TEMP_GAUGE); 69 | public static ComponentRenderer WORLD_TEMP_RENDERER = ComponentRenderer.of(WORLD_TEMP_GAUGE); 70 | public static ComponentRenderer VAGUE_TEMP_RENDERER = ComponentRenderer.of(VAGUE_TEMP_GAUGE); 71 | 72 | @Override 73 | public void init() { 74 | //? if <1.20.5 { 75 | AutoHudGui.COMPONENT_RENDERERS.put(BODY_TEMP_GAUGE.identifier, BODY_TEMP_RENDERER); 76 | AutoHudGui.COMPONENT_RENDERERS.put(WORLD_TEMP_GAUGE.identifier, WORLD_TEMP_RENDERER); 77 | AutoHudGui.COMPONENT_RENDERERS.put(VAGUE_TEMP_GAUGE.identifier, VAGUE_TEMP_RENDERER); 78 | //?} 79 | } 80 | } 81 | //?} 82 | -------------------------------------------------------------------------------- /forge/src/main/java/mod/crend/autohud/forge/compat/QuarkCompat.java: -------------------------------------------------------------------------------- 1 | //? if quark { 2 | package mod.crend.autohud.forge.compat; 3 | 4 | import mod.crend.autohud.api.AutoHudApi; 5 | import mod.crend.autohud.component.Components; 6 | import net.minecraft.client.network.ClientPlayerEntity; 7 | import org.violetmoon.quark.base.Quark; 8 | import org.violetmoon.quark.content.management.module.HotbarChangerModule; 9 | 10 | public class QuarkCompat implements AutoHudApi { 11 | @Override 12 | public String modId() { 13 | return Quark.MOD_ID; 14 | } 15 | 16 | @Override 17 | public void tickState(ClientPlayerEntity player) { 18 | if (HotbarChangerModule.hotbarChangeOpen) { 19 | Components.Hotbar.reveal(); 20 | } 21 | } 22 | } 23 | //?} 24 | -------------------------------------------------------------------------------- /forge/src/main/java/mod/crend/autohud/forge/compat/legendarysurvivaloverhaul/LSOCompat.java: -------------------------------------------------------------------------------- 1 | //? if legendary_survival_overhaul { 2 | package mod.crend.autohud.forge.compat.legendarysurvivaloverhaul; 3 | 4 | import mod.crend.autohud.api.AutoHudApi; 5 | import mod.crend.autohud.component.Components; 6 | import mod.crend.autohud.forge.AutoHudGui; 7 | import sfiomn.legendarysurvivaloverhaul.LegendarySurvivalOverhaul; 8 | 9 | public class LSOCompat implements AutoHudApi { 10 | 11 | @Override 12 | public String modId() { 13 | return LegendarySurvivalOverhaul.MOD_ID; 14 | } 15 | 16 | @Override 17 | public void init() { 18 | Components.Hunger.addStackComponent(LSOComponents.THIRST); 19 | Components.ExperienceBar.addStackComponent(LSOComponents.TEMPERATURE); 20 | AutoHudGui.COMPONENT_RENDERERS.put(LSOComponents.FOOD_BAR_COLD_EFFECT.identifier, LSOComponentRenderer.FOOD_BAR_COLD_EFFECT); 21 | AutoHudGui.COMPONENT_RENDERERS.put(LSOComponents.THIRST.identifier, LSOComponentRenderer.THIRST); 22 | AutoHudGui.COMPONENT_RENDERERS.put(LSOComponents.TEMPERATURE.identifier, LSOComponentRenderer.TEMPERATURE); 23 | } 24 | } 25 | //?} 26 | -------------------------------------------------------------------------------- /forge/src/main/java/mod/crend/autohud/forge/compat/legendarysurvivaloverhaul/LSOComponentRenderer.java: -------------------------------------------------------------------------------- 1 | //? if legendary_survival_overhaul { 2 | package mod.crend.autohud.forge.compat.legendarysurvivaloverhaul; 3 | 4 | import mod.crend.autohud.render.ComponentRenderer; 5 | 6 | public class LSOComponentRenderer { 7 | public static ComponentRenderer FOOD_BAR_COLD_EFFECT = ComponentRenderer.of(LSOComponents.FOOD_BAR_COLD_EFFECT); 8 | public static ComponentRenderer THIRST = ComponentRenderer.of(LSOComponents.THIRST); 9 | public static ComponentRenderer TEMPERATURE = ComponentRenderer.of(LSOComponents.TEMPERATURE); 10 | } 11 | //?} 12 | -------------------------------------------------------------------------------- /forge/src/main/java/mod/crend/autohud/forge/compat/legendarysurvivaloverhaul/LSOComponents.java: -------------------------------------------------------------------------------- 1 | //? if legendary_survival_overhaul { 2 | package mod.crend.autohud.forge.compat.legendarysurvivaloverhaul; 3 | 4 | import mod.crend.autohud.AutoHud; 5 | import mod.crend.autohud.component.Component; 6 | import mod.crend.autohud.component.Components; 7 | import mod.crend.autohud.component.state.BooleanComponentState; 8 | import mod.crend.autohud.component.state.PolicyComponentState; 9 | import sfiomn.legendarysurvivaloverhaul.LegendarySurvivalOverhaul; 10 | import sfiomn.legendarysurvivaloverhaul.common.capabilities.thirst.ThirstCapability; 11 | import sfiomn.legendarysurvivaloverhaul.registry.MobEffectRegistry; 12 | import sfiomn.legendarysurvivaloverhaul.util.CapabilityUtil; 13 | 14 | public class LSOComponents { 15 | public static Component FOOD_BAR_COLD_EFFECT = Component.builder(LegendarySurvivalOverhaul.MOD_ID, "cold_hunger") 16 | .isTargeted(Components.TARGET_STATUS_BARS) 17 | .config(AutoHud.config.hunger()) 18 | .inMainHud() 19 | .state(player -> new BooleanComponentState(LSOComponents.FOOD_BAR_COLD_EFFECT, () -> player.hasStatusEffect(MobEffectRegistry.COLD_HUNGER.get()), true)) 20 | .build(); 21 | 22 | static ThirstCapability THIRST_CAP; 23 | public static Component THIRST = Component.builder(LegendarySurvivalOverhaul.MOD_ID, "thirst") 24 | .isTargeted(Components.TARGET_STATUS_BARS) 25 | .config(AutoHud.config.hunger()) 26 | .inMainHud() 27 | .state(player -> new PolicyComponentState(LSOComponents.THIRST, () -> { 28 | if (THIRST_CAP == null || player.age % 20 == 0) { 29 | THIRST_CAP = CapabilityUtil.getThirstCapability(player); 30 | } 31 | return THIRST_CAP.getHydrationLevel(); 32 | }, () -> 20, true)) 33 | .build(); 34 | 35 | public static Component TEMPERATURE = Component.builder(LegendarySurvivalOverhaul.MOD_ID, "temperature") 36 | .inMainHud() 37 | .state(TemperatureState::new) 38 | .build(); 39 | 40 | } 41 | //?} 42 | -------------------------------------------------------------------------------- /forge/src/main/java/mod/crend/autohud/forge/compat/legendarysurvivaloverhaul/TemperatureState.java: -------------------------------------------------------------------------------- 1 | //? if legendary_survival_overhaul { 2 | package mod.crend.autohud.forge.compat.legendarysurvivaloverhaul; 3 | 4 | import mod.crend.autohud.component.state.ComponentState; 5 | import net.minecraft.client.network.ClientPlayerEntity; 6 | import sfiomn.legendarysurvivaloverhaul.api.temperature.TemperatureEnum; 7 | import sfiomn.legendarysurvivaloverhaul.common.capabilities.temperature.TemperatureCapability; 8 | import sfiomn.legendarysurvivaloverhaul.common.capabilities.wetness.WetnessCapability; 9 | import sfiomn.legendarysurvivaloverhaul.util.CapabilityUtil; 10 | 11 | import java.util.Objects; 12 | 13 | public class TemperatureState extends ComponentState { 14 | ClientPlayerEntity player; 15 | TemperatureCapability TEMPERATURE_CAP; 16 | WetnessCapability WETNESS_CAP; 17 | TemperatureEnum oldTemperature; 18 | int oldWetness; 19 | 20 | public TemperatureState(ClientPlayerEntity player) { 21 | super(LSOComponents.TEMPERATURE, true); 22 | this.player = player; 23 | this.TEMPERATURE_CAP = CapabilityUtil.getTempCapability(player); 24 | this.WETNESS_CAP = CapabilityUtil.getWetnessCapability(player); 25 | } 26 | 27 | @Override 28 | public void update() { 29 | TemperatureEnum newTemperature = TEMPERATURE_CAP.getTemperatureEnum(); 30 | int newWetness = WETNESS_CAP.getWetness(); 31 | if (doReveal(newTemperature, newWetness)) { 32 | component.revealCombined(); 33 | } 34 | oldTemperature = newTemperature; 35 | oldWetness = newWetness; 36 | } 37 | 38 | protected boolean doReveal(TemperatureEnum newTemperature, int newWetness) { 39 | return !component.config.active() 40 | || (!Objects.equals(newTemperature, oldTemperature) || oldWetness != newWetness) 41 | || newWetness > 0 42 | || forceReveal() 43 | ; 44 | } 45 | private boolean forceReveal() { 46 | return switch (TEMPERATURE_CAP.getTemperatureEnum()) { 47 | case FROSTBITE, HEAT_STROKE -> true; 48 | case COLD, NORMAL, HOT -> false; 49 | }; 50 | } 51 | } 52 | //?} -------------------------------------------------------------------------------- /forge/src/main/java/mod/crend/autohud/forge/mixin/gui/ChatHudMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.forge.mixin.gui; 2 | 3 | import mod.crend.autohud.component.Components; 4 | import mod.crend.autohud.render.ComponentRenderer; 5 | import net.minecraft.client.gui.DrawContext; 6 | import net.minecraft.client.gui.hud.ChatHud; 7 | import net.minecraft.client.gui.hud.MessageIndicator; 8 | import net.minecraft.network.message.MessageSignatureData; 9 | import net.minecraft.text.Text; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 14 | 15 | @Mixin(ChatHud.class) 16 | public class ChatHudMixin { 17 | 18 | @Inject(method = "addMessage(Lnet/minecraft/text/Text;Lnet/minecraft/network/message/MessageSignatureData;Lnet/minecraft/client/gui/hud/MessageIndicator;)V", at = @At("TAIL")) 19 | private void autoHud$showChatMessageIndicator(Text message, MessageSignatureData signature, MessageIndicator indicator, CallbackInfo ci) { 20 | if (Components.Chat.config.active() && Components.ChatIndicator.config.active() && Components.Chat.isHidden()) { 21 | Components.ChatIndicator.reveal(); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /forge/src/main/java/mod/crend/autohud/forge/mixin/gui/ForgeGuiMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.forge.mixin.gui; 2 | 3 | //? if <1.20.5 { 4 | import mod.crend.autohud.AutoHud; 5 | import mod.crend.autohud.component.Components; 6 | import mod.crend.autohud.render.AutoHudRenderer; 7 | import mod.crend.autohud.render.ComponentRenderer; 8 | import net.minecraft.client.gui.DrawContext; 9 | import net.minecraftforge.client.gui.overlay.ForgeGui; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 14 | 15 | @Mixin(ForgeGui.class) 16 | public class ForgeGuiMixin { 17 | 18 | @Inject(method = "render", at = @At("HEAD")) 19 | private void autoHud$preRender(DrawContext context, float tickDelta, CallbackInfo ci) { 20 | AutoHudRenderer.inRender = true; 21 | AutoHudRenderer.tickDelta = tickDelta; 22 | } 23 | @Inject(method = "render", at = @At("RETURN")) 24 | private void autoHud$postRender(DrawContext context, float tickDelta, CallbackInfo ci) { 25 | AutoHudRenderer.inRender = false; 26 | } 27 | 28 | @Inject(method = "renderHealth", at = @At("HEAD")) 29 | private void autoHud$preHealth(int width, int height, DrawContext context, CallbackInfo ci) { 30 | if (AutoHud.targetStatusBars) { 31 | ComponentRenderer.HEALTH.beginFade(context); 32 | } 33 | } 34 | 35 | @Inject(method = "renderArmor", at = @At("HEAD")) 36 | private void autoHud$preArmor(DrawContext context, int width, int height, CallbackInfo ci) { 37 | if (AutoHud.targetStatusBars) { 38 | ComponentRenderer.ARMOR.beginFade(context); 39 | } 40 | } 41 | 42 | @Inject(method = "renderFood", at = @At("HEAD")) 43 | private void autoHud$preFood(int width, int height, DrawContext context, CallbackInfo ci) { 44 | if (AutoHud.targetStatusBars) { 45 | ComponentRenderer.HUNGER.beginFade(context); 46 | } 47 | } 48 | 49 | @Inject(method = "renderAir", at = @At("HEAD")) 50 | private void autoHud$preAir(int width, int height, DrawContext context, CallbackInfo ci) { 51 | if (AutoHud.targetStatusBars) { 52 | ComponentRenderer.AIR.beginFade(context); 53 | } 54 | } 55 | 56 | @Inject(method = "renderHealthMount", at = @At("HEAD")) 57 | private void autoHud$preRenderHealthMount(int width, int height, DrawContext context, CallbackInfo ci) { 58 | if (AutoHud.targetStatusBars) { 59 | ComponentRenderer.MOUNT_HEALTH.beginFade(context); 60 | } 61 | } 62 | } 63 | //?} else { 64 | 65 | /*import mod.crend.libbamboo.VersionUtils; 66 | import org.spongepowered.asm.mixin.Mixin; 67 | 68 | @Mixin(VersionUtils.class) 69 | public class ForgeGuiMixin { 70 | } 71 | *///?} -------------------------------------------------------------------------------- /forge/src/main/java/mod/crend/autohud/forge/mixin/gui/StatusEffectTimerMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.forge.mixin.gui; 2 | 3 | import com.llamalad7.mixinextras.sugar.Local; 4 | import mod.crend.autohud.AutoHud; 5 | import mod.crend.autohud.render.ComponentRenderer; 6 | import mod.crend.libbamboo.PlatformUtils; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.gui.DrawContext; 9 | import net.minecraft.client.gui.hud.InGameHud; 10 | import net.minecraft.client.render.RenderTickCounter; 11 | import net.minecraft.client.resource.language.I18n; 12 | import net.minecraft.entity.effect.StatusEffectInstance; 13 | import net.minecraft.util.math.MathHelper; 14 | import org.spongepowered.asm.mixin.Final; 15 | import org.spongepowered.asm.mixin.Mixin; 16 | import org.spongepowered.asm.mixin.Shadow; 17 | import org.spongepowered.asm.mixin.Unique; 18 | import org.spongepowered.asm.mixin.injection.At; 19 | import org.spongepowered.asm.mixin.injection.Inject; 20 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 21 | 22 | import java.util.List; 23 | 24 | /* 25 | * This file is originally part of the StatusEffectTimer mod: 26 | * https://github.com/magicus/statuseffecttimer 27 | * 28 | * It is included here in order to be modified properly. 29 | * Changes: 30 | * - Skip timers for hidden effects by redirecting StatusEffectInstance.shouldShowIcon() 31 | * - Insert matrix push/pop for moving each timer text with its icon 32 | */ 33 | 34 | // Set priority to 500, to load before default at 1000. This is to better cooperate with HUDTweaks. 35 | @Mixin(value = InGameHud.class, priority = 500) 36 | public abstract class StatusEffectTimerMixin { 37 | @Shadow @Final 38 | protected MinecraftClient client; 39 | 40 | @Inject(method = "renderStatusEffectOverlay", 41 | at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", shift = At.Shift.AFTER)) 42 | private void appendOverlayDrawing( 43 | DrawContext context, 44 | //? if >1.20.6 { 45 | /*RenderTickCounter tickDelta, 46 | *///?} else if >1.20.5 47 | /*float tickDelta,*/ 48 | CallbackInfo c, 49 | @Local List list, 50 | @Local StatusEffectInstance statusEffectInstance, 51 | @Local(ordinal = 2) int i2, 52 | @Local(ordinal = 3) int i3, 53 | @Local(ordinal = 4) int i4, 54 | @Local(ordinal = 5) int i5 55 | ) { 56 | list.add(() -> { 57 | if (AutoHud.config.statusEffectTimer()) { 58 | int x = switch (PlatformUtils.getCurrentPlatform()) { 59 | case FABRIC -> i4; 60 | case FORGE -> i5; 61 | case NEOFORGE -> i2; 62 | }; 63 | int y = switch (PlatformUtils.getCurrentPlatform()) { 64 | case FABRIC -> i5; 65 | case FORGE -> i3; 66 | case NEOFORGE -> i3; 67 | }; 68 | ComponentRenderer.getForStatusEffect(statusEffectInstance).wrap(context, () -> drawStatusEffectOverlay(context, statusEffectInstance, x, y)); 69 | } 70 | }); 71 | } 72 | 73 | @Unique 74 | private void drawStatusEffectOverlay(DrawContext context, StatusEffectInstance statusEffectInstance, int x, int y) { 75 | String duration = getDurationAsString(statusEffectInstance); 76 | int durationLength = client.textRenderer.getWidth(duration); 77 | context.drawTextWithShadow(client.textRenderer, duration, x + 13 - (durationLength / 2), y + 14, 0x99FFFFFF); 78 | 79 | int amplifier = statusEffectInstance.getAmplifier(); 80 | if (amplifier > 0) { 81 | // Convert to roman numerals if possible 82 | String amplifierString = (amplifier < 10) ? I18n.translate("enchantment.level." + (amplifier + 1)) : "**"; 83 | int amplifierLength = client.textRenderer.getWidth(amplifierString); 84 | context.drawTextWithShadow(client.textRenderer, amplifierString, x + 22 - amplifierLength, y + 3, 0x99FFFFFF); 85 | } 86 | } 87 | 88 | @Unique 89 | private String getDurationAsString(StatusEffectInstance statusEffectInstance) { 90 | if (statusEffectInstance.isInfinite()) { 91 | return I18n.translate("effect.duration.infinite"); 92 | } 93 | 94 | int ticks = MathHelper.floor((float) statusEffectInstance.getDuration()); 95 | int seconds = ticks / 20; 96 | 97 | if (seconds >= 3600) { 98 | return seconds / 3600 + "h"; 99 | } else if (seconds >= 60) { 100 | return seconds / 60 + "m"; 101 | } else { 102 | return String.valueOf(seconds); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /forge/src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | modLoader = "javafml" 2 | loaderVersion = "*" 3 | issueTrackerURL = "https://github.com/Crendgrim/AutoHUD/issues" 4 | license = "LGPL-3.0" 5 | 6 | [[mods]] 7 | modId = "${id}" 8 | version = "${version}" 9 | displayName = "${name}" 10 | authors = "Crendgrim" 11 | description = ''' 12 | Dynamic HUD that hides interface elements while they are not needed. 13 | ''' 14 | logoFile = "autohud.png" 15 | logoBlur = false 16 | displayTest = "IGNORE_ALL_VERSION" 17 | -------------------------------------------------------------------------------- /forge/src/main/resources/autohud-forge-compat.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "mod.crend.autohud.compat.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "client": [ 7 | ], 8 | "injectors": { 9 | "defaultRequire": 0 10 | }, 11 | "plugin": "mod.crend.autohud.AutoHudCompatMixinPlugin" 12 | } 13 | -------------------------------------------------------------------------------- /forge/src/main/resources/autohud-forge.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "mod.crend.autohud.forge.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "client": [ 7 | "gui.ChatHudMixin", 8 | "gui.ForgeGuiMixin", 9 | "gui.InGameHudMixin", 10 | "gui.StatusEffectTimerMixin" 11 | ], 12 | "injectors": { 13 | "defaultRequire": 1 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /forge/src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "AutoHUD", 4 | "pack_format": 9 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx6G 3 | org.gradle.parallel=false 4 | org.gradle.caching=true 5 | org.gradle.caching.debug=false 6 | #org.gradle.configureondemand=true 7 | 8 | # Mod properties 9 | mod.version=8.1 10 | mod.changelog=Fix various bugs 11 | mod.group=mod.crend 12 | mod.id=autohud 13 | mod.name=Auto HUD 14 | 15 | # Used for the mod metadata 16 | mod.mc_dep_fabric=[VERSIONED] 17 | mod.mc_dep_forgelike=[VERSIONED] 18 | # Used for the release title. I.e. '1.20.x' 19 | mod.mc_title=[VERSIONED] 20 | # Space separated versions for publishing. I.e. '1.20, 1.20.1' 21 | mod.mc_targets=[VERSIONED] 22 | 23 | # Mod setup 24 | deps.mixin_extras=0.4.1 25 | deps.fabric_loader=0.16.8 26 | deps.forge_loader=[VERSIONED] 27 | deps.neoforge_loader=[VERSIONED] 28 | deps.neoforge_patch=[VERSIONED] 29 | 30 | # Mod dependencies 31 | deps.yarn_build=[VERSIONED] 32 | deps.fabric_api=[VERSIONED] 33 | deps.libbamboo=[VERSIONED] 34 | deps.yacl=[VERSIONED] 35 | deps.modmenu=[VERSIONED] 36 | 37 | deps.appleskin=[VERSIONED] 38 | deps.appleskin_artifact=[VERSIONED] 39 | deps.armorchroma=[VERSIONED] 40 | deps.coldsweat=[VERSIONED] 41 | deps.coldsweat_artifact=[VERSIONED] 42 | deps.dehydration=[VERSIONED] 43 | deps.detailab=[VERSIONED] 44 | deps.environmentz=[VERSIONED] 45 | deps.farmers_delight_refabricated=[VERSIONED] 46 | deps.hotbarslotcycling=[VERSIONED] 47 | deps.legendary_survival_overhaul=[VERSIONED] 48 | deps.microdurability=[VERSIONED] 49 | deps.onebar=[VERSIONED] 50 | deps.quark=[VERSIONED] 51 | deps.raised=[VERSIONED] 52 | deps.raised_artifact=[VERSIONED] 53 | deps.statuseffectbars=[VERSIONED] 54 | 55 | # Publishing 56 | publish.modrinth = temczoTQ 57 | publish.curseforge = 623806 58 | publish.curseforge_slug = autohud 59 | -------------------------------------------------------------------------------- /icon_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Crendgrim/AutoHUD/e6fd1ea95c3f74646c5c73d447d89f79eeef7c95/icon_large.png -------------------------------------------------------------------------------- /neoforge/build.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | plugins { 4 | id("dev.architectury.loom") 5 | id("architectury-plugin") 6 | id("com.github.johnrengelman.shadow") 7 | id("maven-publish") 8 | id("me.modmuss50.mod-publish-plugin") 9 | } 10 | 11 | val loader = prop("loom.platform")!! 12 | val minecraft: String = stonecutter.current.version 13 | val common: Project = requireNotNull(stonecutter.node.sibling("")) { 14 | "No common project for $project" 15 | } 16 | 17 | version = "${mod.version}+$minecraft" 18 | group = "${mod.group}.$loader" 19 | base { 20 | archivesName.set(mod.id) 21 | } 22 | architectury { 23 | platformSetupLoomIde() 24 | neoForge() 25 | } 26 | 27 | val commonBundle: Configuration by configurations.creating { 28 | isCanBeConsumed = false 29 | isCanBeResolved = true 30 | } 31 | 32 | val shadowBundle: Configuration by configurations.creating { 33 | isCanBeConsumed = false 34 | isCanBeResolved = true 35 | } 36 | 37 | configurations { 38 | compileClasspath.get().extendsFrom(commonBundle) 39 | runtimeClasspath.get().extendsFrom(commonBundle) 40 | get("developmentNeoForge").extendsFrom(commonBundle) 41 | } 42 | 43 | repositories { 44 | maven("https://maven.neoforged.net/releases/") 45 | } 46 | 47 | dependencies { 48 | minecraft("com.mojang:minecraft:$minecraft") 49 | mappings(loom.layered { 50 | mappings("net.fabricmc:yarn:$minecraft+build.${common.mod.dep("yarn_build")}:v2") 51 | common.mod.dep("neoforge_patch").takeUnless { it.startsWith('[') }?.let { 52 | mappings("dev.architectury:yarn-mappings-patch-neoforge:$it") 53 | } 54 | }) 55 | "neoForge"("net.neoforged:neoforge:${common.mod.dep("neoforge_loader")}") 56 | 57 | mapOf( 58 | "coldsweat" to "maven.modrinth:cold-sweat:${common.mod.dep("coldsweat_artifact")}", 59 | "hotbarslotcycling" to "fuzs.hotbarslotcycling:hotbarslotcycling-neoforge:{}", 60 | "raised" to "maven.modrinth:raised:NeoForge-${common.mod.dep("raised_artifact")}-{}", 61 | ).map { (modName, url) -> 62 | common.mod.dep("neoforge", modName) to url.replace("{}", common.mod.dep("neoforge", modName)) 63 | }.filterNot { (version, _) -> 64 | version.startsWith("[") 65 | }.forEach { (_, url) -> 66 | modCompileOnly(url) 67 | } 68 | 69 | modImplementation(name="libbamboo", group="mod.crend", version="${common.mod.dep("libbamboo")}-neoforge") 70 | include(name="libbamboo", group="mod.crend", version="${common.mod.dep("libbamboo")}-neoforge") 71 | 72 | commonBundle(project(common.path, "namedElements")) { isTransitive = false } 73 | shadowBundle(project(common.path, "transformProductionNeoForge")) { isTransitive = false } 74 | } 75 | 76 | loom { 77 | decompilers { 78 | get("vineflower").apply { // Adds names to lambdas - useful for mixins 79 | options.put("mark-corresponding-synthetics", "1") 80 | } 81 | } 82 | 83 | runConfigs.all { 84 | isIdeConfigGenerated = true 85 | runDir = "../../../run" 86 | vmArgs("-Dmixin.debug.export=true") 87 | } 88 | } 89 | 90 | java { 91 | withSourcesJar() 92 | val java = if (stonecutter.eval(minecraft, ">=1.20.5")) 93 | JavaVersion.VERSION_21 else JavaVersion.VERSION_17 94 | targetCompatibility = java 95 | sourceCompatibility = java 96 | } 97 | 98 | tasks.jar { 99 | archiveClassifier = "dev" 100 | } 101 | 102 | tasks.remapJar { 103 | injectAccessWidener = true 104 | input = tasks.shadowJar.get().archiveFile 105 | archiveClassifier = loader 106 | dependsOn(tasks.shadowJar) 107 | } 108 | 109 | tasks.shadowJar { 110 | configurations = listOf(shadowBundle) 111 | archiveClassifier = "dev-shadow" 112 | exclude( 113 | "fabric.mod.json", 114 | "architectury.common.json", 115 | if (stonecutter.eval(minecraft, "<=1.20.4")) "META-INF/neoforge.mods.toml" else "META-INF/mods.toml" 116 | ) 117 | } 118 | 119 | tasks.processResources { 120 | properties( 121 | listOf( 122 | if (stonecutter.eval(minecraft, "<=1.20.4")) "META-INF/mods.toml" else "META-INF/neoforge.mods.toml", 123 | "pack.mcmeta" 124 | ), 125 | "id" to mod.id, 126 | "name" to mod.name, 127 | "version" to mod.version, 128 | "minecraft" to common.mod.prop("mc_dep_forgelike") 129 | ) 130 | } 131 | 132 | tasks.build { 133 | group = "versioned" 134 | description = "Must run through 'chiseledBuild'" 135 | } 136 | 137 | tasks.register("buildAndCollect") { 138 | group = "versioned" 139 | description = "Must run through 'chiseledBuild'" 140 | from(tasks.remapJar.get().archiveFile, tasks.remapSourcesJar.get().archiveFile) 141 | into(rootProject.layout.buildDirectory.file("libs/${mod.version}/$loader")) 142 | dependsOn("build") 143 | } 144 | 145 | publishing { 146 | publications { 147 | create("maven") { 148 | groupId = mod.prop("group") 149 | artifactId = mod.prop("id") 150 | version = "${mod.version}+${minecraft}-${loader}" 151 | 152 | artifact(tasks.remapJar.get().archiveFile) 153 | artifact(tasks.remapSourcesJar.get().archiveFile) { 154 | classifier = "sources" 155 | } 156 | } 157 | } 158 | } 159 | 160 | publishMods { 161 | displayName = "[NeoForge ${common.mod.prop("mc_title")}] ${mod.name} ${mod.version}" 162 | 163 | val modrinthToken = providers.gradleProperty("MODRINTH_TOKEN").orNull 164 | val curseforgeToken = providers.gradleProperty("CURSEFORGE_TOKEN").orNull 165 | dryRun = modrinthToken == null || curseforgeToken == null 166 | 167 | file = tasks.remapJar.get().archiveFile 168 | version = "${mod.version}+$minecraft-$loader" 169 | changelog = mod.prop("changelog") 170 | type = STABLE 171 | modLoaders.add(loader) 172 | 173 | val supportedVersions = common.mod.prop("mc_targets").split(" ") 174 | 175 | modrinth { 176 | projectId = property("publish.modrinth").toString() 177 | accessToken = modrinthToken 178 | minecraftVersions.addAll(supportedVersions) 179 | 180 | optional("yacl") 181 | } 182 | curseforge { 183 | projectId = property("publish.curseforge").toString() 184 | projectSlug = property("publish.curseforge_slug").toString() 185 | accessToken = curseforgeToken 186 | minecraftVersions.addAll(supportedVersions) 187 | clientRequired = true 188 | serverRequired = false 189 | 190 | optional("yacl") 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /neoforge/gradle.properties: -------------------------------------------------------------------------------- 1 | loom.platform=neoforge -------------------------------------------------------------------------------- /neoforge/src/main/java/mod/crend/autohud/neoforge/AutoHudGui.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.neoforge; 2 | 3 | import mod.crend.autohud.component.Components; 4 | import mod.crend.autohud.render.ComponentRenderer; 5 | import net.minecraft.util.Identifier; 6 | import net.neoforged.bus.api.EventPriority; 7 | import net.neoforged.bus.api.SubscribeEvent; 8 | import net.neoforged.neoforge.client.event.CustomizeGuiOverlayEvent; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.Optional; 13 | 14 | //? if <1.20.5 { 15 | import static net.neoforged.neoforge.client.gui.overlay.VanillaGuiOverlay.*; 16 | import net.neoforged.neoforge.client.event.RenderGuiOverlayEvent; 17 | //?} else { 18 | /*import static net.neoforged.neoforge.client.gui.VanillaGuiLayers.*; 19 | import net.neoforged.neoforge.client.event.RenderGuiLayerEvent; 20 | *///?} 21 | 22 | public class AutoHudGui { 23 | 24 | public static Map COMPONENT_RENDERERS = new HashMap<>(); 25 | static { 26 | COMPONENT_RENDERERS.put(PLAYER_HEALTH/*? if <1.20.5 {*/.id()/*?}*/, ComponentRenderer.HEALTH); 27 | COMPONENT_RENDERERS.put(ARMOR_LEVEL/*? if <1.20.5 {*/.id()/*?}*/, ComponentRenderer.ARMOR); 28 | COMPONENT_RENDERERS.put(FOOD_LEVEL/*? if <1.20.5 {*/.id()/*?}*/, ComponentRenderer.HUNGER); 29 | COMPONENT_RENDERERS.put(AIR_LEVEL/*? if <1.20.5 {*/.id()/*?}*/, ComponentRenderer.AIR); 30 | COMPONENT_RENDERERS.put(/*? if <1.20.5 {*/MOUNT_HEALTH.id()/*?} else {*//*VEHICLE_HEALTH*//*?}*/, ComponentRenderer.MOUNT_HEALTH); 31 | COMPONENT_RENDERERS.put(/*? if <1.20.5 {*/JUMP_BAR.id()/*?} else {*//*JUMP_METER*//*?}*/, ComponentRenderer.MOUNT_JUMP_BAR); 32 | COMPONENT_RENDERERS.put(EXPERIENCE_BAR/*? if <1.20.5 {*/.id()/*?}*/, ComponentRenderer.EXPERIENCE_BAR); 33 | //? if >=1.20.5 34 | /*COMPONENT_RENDERERS.put(EXPERIENCE_LEVEL, ComponentRenderer.EXPERIENCE_LEVEL);*/ 35 | 36 | COMPONENT_RENDERERS.put(/*? if <1.20.5 {*/SCOREBOARD.id()/*?} else {*//*SCOREBOARD_SIDEBAR*//*?}*/, ComponentRenderer.SCOREBOARD); 37 | COMPONENT_RENDERERS.put(HOTBAR/*? if <1.20.5 {*/.id()/*?}*/, ComponentRenderer.HOTBAR); 38 | COMPONENT_RENDERERS.put(/*? if <1.20.5 {*/ITEM_NAME.id()/*?} else {*//*SELECTED_ITEM_NAME*//*?}*/, ComponentRenderer.TOOLTIP); 39 | COMPONENT_RENDERERS.put(/*? if <1.20.5 {*/CHAT_PANEL.id()/*?} else {*//*CHAT*//*?}*/, ComponentRenderer.CHAT); 40 | COMPONENT_RENDERERS.put(/*? if <1.20.5 {*/TITLE_TEXT.id()/*?} else {*//*TITLE*//*?}*/, ComponentRenderer.ACTION_BAR); 41 | COMPONENT_RENDERERS.put(/*? if <1.20.5 {*/BOSS_EVENT_PROGRESS.id()/*?} else {*//*BOSS_OVERLAY*//*?}*/, ComponentRenderer.BOSS_BAR); 42 | } 43 | 44 | /* 45 | * NOTE: NeoForge before 1.21 handles events differently to Forge. 46 | * In Forge and modern NeoForge, canceling the event here would still call the handler below, so we would have to 47 | * still do the preRender step (and then immediately undo it in the other event). 48 | * In older NeoForge, this does not happen, and the second handler does not get invoked. So we can skip the matrix 49 | * translation right away. 50 | * We still keep the second event subscriber to hopefully catch any situation where another mod cancels one 51 | * of the handled overlay events. 52 | */ 53 | @SubscribeEvent(priority = EventPriority.HIGHEST, receiveCanceled = true) 54 | public void preHudComponent(/*? if <1.20.5 {*/RenderGuiOverlayEvent/*?} else {*//*RenderGuiLayerEvent*//*?}*/.Pre event) { 55 | Optional.ofNullable(COMPONENT_RENDERERS.get( 56 | //? if <1.20.5 { 57 | event.getOverlay().id() 58 | //?} else 59 | /*event.getName()*/ 60 | )).ifPresent( 61 | wrapper -> { 62 | if (wrapper.isActive() && !wrapper.doRender()) { 63 | event.setCanceled(true); 64 | } 65 | //? if <1.21 66 | else 67 | { 68 | wrapper.beginRender(event.getGuiGraphics()); 69 | } 70 | } 71 | ); 72 | } 73 | @SubscribeEvent(priority = EventPriority.LOWEST, receiveCanceled = true) 74 | public void cancelHudComponent(/*? if <1.20.5 {*/RenderGuiOverlayEvent/*?} else {*//*RenderGuiLayerEvent*//*?}*/.Pre event) { 75 | if (event.isCanceled()) { 76 | Optional.ofNullable(COMPONENT_RENDERERS.get( 77 | //? if <1.20.5 { 78 | event.getOverlay().id() 79 | //?} else 80 | /*event.getName()*/ 81 | )).ifPresent( 82 | wrapper -> wrapper.endRender(event.getGuiGraphics()) 83 | ); 84 | } 85 | } 86 | @SubscribeEvent(priority = EventPriority.LOWEST, receiveCanceled = true) 87 | public void postHudComponent(/*? if <1.20.5 {*/RenderGuiOverlayEvent/*?} else {*//*RenderGuiLayerEvent*//*?}*/.Post event) { 88 | Optional.ofNullable(COMPONENT_RENDERERS.get( 89 | //? if <1.20.5 { 90 | event.getOverlay().id() 91 | //?} else 92 | /*event.getName()*/ 93 | )).ifPresent( 94 | wrapper -> wrapper.endRender(event.getGuiGraphics()) 95 | ); 96 | } 97 | 98 | @SubscribeEvent 99 | public void preChat(CustomizeGuiOverlayEvent.Chat event) { 100 | if (Components.Chat.config.active()) { 101 | ComponentRenderer.CHAT.beginFade(event.getGuiGraphics()); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /neoforge/src/main/java/mod/crend/autohud/neoforge/AutoHudModEvents.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.neoforge; 2 | 3 | import mod.crend.autohud.AutoHud; 4 | import mod.crend.autohud.ModKeyBindings; 5 | import mod.crend.autohud.api.AutoHudApi; 6 | import mod.crend.autohud.config.ConfigHandler; 7 | import mod.crend.autohud.compat.HotbarSlotCyclingCompat; 8 | import mod.crend.autohud.neoforge.compat.ColdSweatCompat; 9 | import mod.crend.autohud.render.AutoHudRenderer; 10 | import mod.crend.libbamboo.VersionUtils; 11 | import mod.crend.libbamboo.neoforge.ConfigScreen; 12 | import net.minecraft.util.Identifier; 13 | import net.neoforged.api.distmarker.Dist; 14 | import net.neoforged.bus.api.SubscribeEvent; 15 | import net.neoforged.fml.InterModComms; 16 | import net.neoforged.fml.ModList; 17 | import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; 18 | import net.neoforged.fml.event.lifecycle.InterModProcessEvent; 19 | import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; 20 | import net.neoforged.neoforge.common.NeoForge; 21 | //? if <1.20.5 { 22 | import net.neoforged.fml.common.Mod; 23 | import net.neoforged.neoforge.client.event.RegisterGuiOverlaysEvent; 24 | //?} else { 25 | /*import net.neoforged.fml.common.EventBusSubscriber; 26 | import net.neoforged.neoforge.client.event.RegisterGuiLayersEvent; 27 | *///?} 28 | 29 | //? if <1.20.5 { 30 | @Mod.EventBusSubscriber(modid = AutoHud.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) 31 | //?} else 32 | /*@EventBusSubscriber(modid = AutoHud.MOD_ID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)*/ 33 | public class AutoHudModEvents { 34 | public static final String REGISTER_API = "register_api"; 35 | public static final Identifier NEW_CHAT_MESSAGE_INDICATOR = VersionUtils.getIdentifier(AutoHud.MOD_ID, "new_chat_message_indicator"); 36 | 37 | @SubscribeEvent 38 | static void onClientSetup(FMLClientSetupEvent event) { 39 | AutoHud.init(); 40 | ConfigScreen.register(ConfigHandler.CONFIG_STORE); 41 | NeoForge.EVENT_BUS.register(new AutoHudGui()); 42 | if (ModList.get().isLoaded("hotbarslotcycling")) { 43 | AutoHud.addApi(new HotbarSlotCyclingCompat()); 44 | } 45 | if (ModList.get().isLoaded("raised")) { 46 | AutoHudNeoForge.raisedCompat = true; 47 | } 48 | if (ModList.get().isLoaded("coldsweat")) { 49 | AutoHud.addApi(new ColdSweatCompat()); 50 | } 51 | // Delay initialising the client tick event, see that method. 52 | NeoForge.EVENT_BUS.addListener(AutoHudNeoForge::onClientTick); 53 | } 54 | 55 | @SubscribeEvent 56 | static void onInterModProcess(InterModProcessEvent event) { 57 | InterModComms.getMessages(AutoHud.MOD_ID, REGISTER_API::equals) 58 | .map(msg -> (AutoHudApi) msg.messageSupplier().get()) 59 | .forEach(AutoHud::addApi); 60 | } 61 | 62 | @SubscribeEvent 63 | static void onKeyMappingsRegister(RegisterKeyMappingsEvent event) { 64 | ModKeyBindings.ALL.forEach(event::register); 65 | } 66 | 67 | @SubscribeEvent 68 | static void onRegisterOverlaysEvent(/*? if <1.20.5 {*/RegisterGuiOverlaysEvent/*?} else {*//*RegisterGuiLayersEvent*//*?}*/ event) { 69 | event.registerAboveAll(NEW_CHAT_MESSAGE_INDICATOR, 70 | //? if <1.20.5 { 71 | (neoforgeGui, context, f, i, j) -> AutoHudRenderer.renderChatMessageIndicator(context, f) 72 | //?} else 73 | /*AutoHudRenderer::renderChatMessageIndicator*/ 74 | ); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /neoforge/src/main/java/mod/crend/autohud/neoforge/AutoHudNeoForge.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.neoforge; 2 | 3 | import mod.crend.autohud.AutoHud; 4 | import mod.crend.autohud.ModKeyBindings; 5 | import mod.crend.autohud.compat.RaisedCompat; 6 | import mod.crend.autohud.component.Components; 7 | import mod.crend.autohud.render.AutoHudRenderer; 8 | import net.minecraft.client.MinecraftClient; 9 | import net.neoforged.api.distmarker.Dist; 10 | import net.neoforged.bus.api.SubscribeEvent; 11 | import net.neoforged.fml.common.Mod; 12 | import net.neoforged.neoforge.client.event.ClientChatReceivedEvent; 13 | import net.neoforged.neoforge.client.event.RenderGuiEvent; 14 | //? if <1.20.5 { 15 | import net.neoforged.neoforge.event.TickEvent; 16 | //?} else { 17 | /*import net.neoforged.fml.common.EventBusSubscriber; 18 | import net.neoforged.neoforge.client.event.ClientTickEvent; 19 | *///?} 20 | 21 | @Mod(AutoHud.MOD_ID) 22 | //? if <1.20.5 { 23 | @Mod.EventBusSubscriber(value = Dist.CLIENT) 24 | //?} else 25 | /*@EventBusSubscriber(value = Dist.CLIENT)*/ 26 | public class AutoHudNeoForge { 27 | static boolean raisedCompat = false; 28 | 29 | public AutoHudNeoForge() { 30 | AutoHud.loadConfig(); 31 | } 32 | 33 | // Do not use @SubscribeEvent here because the mod "placebo" forces the game bus to run early for some reason. 34 | // This causes the key bindings to get ticked before the config is loaded... 35 | static void onClientTick( 36 | //? if <1.20.5 { 37 | TickEvent.ClientTickEvent event 38 | //?} else 39 | /*ClientTickEvent.Post event*/ 40 | ) { 41 | //? if <1.20.5 42 | if (event.phase == TickEvent.Phase.START) return; 43 | 44 | ModKeyBindings.clientTick(MinecraftClient.getInstance()); 45 | 46 | if (raisedCompat) { 47 | RaisedCompat.tick(); 48 | } 49 | } 50 | 51 | @SubscribeEvent 52 | static void onPreRenderGuiEvent(RenderGuiEvent.Pre event) { 53 | AutoHudRenderer.startRender(event.getGuiGraphics(), event.getPartialTick()); 54 | } 55 | @SubscribeEvent 56 | static void onPostRenderGuiEvent(RenderGuiEvent.Post event) { 57 | AutoHudRenderer.endRender(); 58 | } 59 | 60 | @SubscribeEvent 61 | static void onChatMessageReceived(ClientChatReceivedEvent event) { 62 | if (Components.Chat.config.active() && Components.ChatIndicator.config.active() && Components.Chat.isHidden()) { 63 | Components.ChatIndicator.reveal(); 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /neoforge/src/main/java/mod/crend/autohud/neoforge/compat/ColdSweatCompat.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.neoforge.compat; 2 | 3 | //? if coldsweat { 4 | /*import com.momosoftworks.coldsweat.ColdSweat; 5 | import com.momosoftworks.coldsweat.api.util.Temperature; 6 | import com.momosoftworks.coldsweat.client.gui.Overlays; 7 | import com.momosoftworks.coldsweat.common.capability.handler.EntityTempManager; 8 | import com.momosoftworks.coldsweat.common.capability.temperature.PlayerTempCap; 9 | import com.momosoftworks.coldsweat.config.ConfigSettings; 10 | import mod.crend.autohud.component.Component; 11 | import mod.crend.autohud.component.state.ValueComponentState; 12 | import mod.crend.autohud.config.ConfigHandler; 13 | import mod.crend.autohud.neoforge.AutoHudGui; 14 | import mod.crend.autohud.render.ComponentRenderer; 15 | import net.minecraft.client.network.ClientPlayerEntity; 16 | *///?} 17 | import mod.crend.autohud.api.AutoHudApi; 18 | 19 | public class ColdSweatCompat implements AutoHudApi { 20 | @Override 21 | public String modId() { 22 | return "cold_sweat"; 23 | } 24 | 25 | //? if coldsweat { 26 | /*public static Component BODY_TEMP_GAUGE = Component.builder(ColdSweat.MOD_ID, "body_temp") 27 | .inMainHud() 28 | .config(ConfigHandler.DummyBooleanComponent) 29 | .state(player -> new ValueComponentState<>(ColdSweatCompat.BODY_TEMP_GAUGE, () -> Overlays.BODY_TEMP, true)) 30 | .build(); 31 | public static Component WORLD_TEMP_GAUGE = Component.builder(ColdSweat.MOD_ID, "world_temp") 32 | .inMainHud() 33 | .config(ConfigHandler.DummyBooleanComponent) 34 | .state(player -> new TemperatureState(ColdSweatCompat.WORLD_TEMP_GAUGE)) 35 | .build(); 36 | public static Component VAGUE_TEMP_GAUGE = Component.builder(ColdSweat.MOD_ID, "vague_temp") 37 | .inMainHud() 38 | .config(ConfigHandler.DummyBooleanComponent) 39 | .state(player -> new TemperatureState(ColdSweatCompat.VAGUE_TEMP_GAUGE)) 40 | .build(); 41 | 42 | static class TemperatureState extends ValueComponentState { 43 | static double PLAYER_MAX_TEMP; 44 | static double PLAYER_MIN_TEMP; 45 | 46 | public TemperatureState(Component component) { 47 | super(component, () -> { 48 | double temp = Temperature.convert(Overlays.WORLD_TEMP, ConfigSettings.CELSIUS.get() ? Temperature.Units.C : Temperature.Units.F, Temperature.Units.MC, true); 49 | return Overlays.getGaugeSeverity(temp, PLAYER_MIN_TEMP, PLAYER_MAX_TEMP); 50 | }, true); 51 | } 52 | 53 | @Override 54 | protected boolean doReveal(Integer newValue) { 55 | return super.doReveal(newValue) || newValue < -2 || newValue > 2; 56 | } 57 | } 58 | 59 | @Override 60 | public void tickState(ClientPlayerEntity player) { 61 | EntityTempManager.getTemperatureCap(player).ifPresent((icap) -> { 62 | if (icap instanceof PlayerTempCap cap) { 63 | TemperatureState.PLAYER_MAX_TEMP = cap.getTrait(Temperature.Trait.BURNING_POINT); 64 | TemperatureState.PLAYER_MIN_TEMP = cap.getTrait(Temperature.Trait.FREEZING_POINT); 65 | } 66 | }); 67 | } 68 | 69 | public static ComponentRenderer BODY_TEMP_RENDERER = ComponentRenderer.of(BODY_TEMP_GAUGE); 70 | public static ComponentRenderer WORLD_TEMP_RENDERER = ComponentRenderer.of(WORLD_TEMP_GAUGE); 71 | public static ComponentRenderer VAGUE_TEMP_RENDERER = ComponentRenderer.of(VAGUE_TEMP_GAUGE); 72 | 73 | @Override 74 | public void init() { 75 | AutoHudGui.COMPONENT_RENDERERS.put(BODY_TEMP_GAUGE.identifier, BODY_TEMP_RENDERER); 76 | AutoHudGui.COMPONENT_RENDERERS.put(WORLD_TEMP_GAUGE.identifier, WORLD_TEMP_RENDERER); 77 | AutoHudGui.COMPONENT_RENDERERS.put(VAGUE_TEMP_GAUGE.identifier, VAGUE_TEMP_RENDERER); 78 | } 79 | *///?} 80 | } 81 | -------------------------------------------------------------------------------- /neoforge/src/main/java/mod/crend/autohud/neoforge/mixin/gui/InGameHudMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.neoforge.mixin.gui; 2 | 3 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 4 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 5 | import com.llamalad7.mixinextras.sugar.Local; 6 | import mod.crend.autohud.AutoHud; 7 | import mod.crend.autohud.component.Component; 8 | import mod.crend.autohud.component.Hud; 9 | import mod.crend.autohud.render.AutoHudRenderer; 10 | import mod.crend.autohud.render.ComponentRenderer; 11 | import net.minecraft.client.gui.DrawContext; 12 | import net.minecraft.client.gui.hud.InGameHud; 13 | //? if >=1.21 14 | /*import net.minecraft.client.render.RenderLayer;*/ 15 | import net.minecraft.client.render.RenderTickCounter; 16 | import net.minecraft.client.texture.Sprite; 17 | import net.minecraft.entity.effect.StatusEffectInstance; 18 | import net.minecraft.entity.player.PlayerEntity; 19 | import net.minecraft.item.ItemStack; 20 | import net.minecraft.util.Identifier; 21 | import net.neoforged.neoforge.client.extensions.common.IClientMobEffectExtensions; 22 | import org.spongepowered.asm.mixin.Mixin; 23 | import org.spongepowered.asm.mixin.injection.*; 24 | 25 | import java.util.concurrent.atomic.AtomicBoolean; 26 | import java.util.function.Function; 27 | 28 | @Mixin(value = InGameHud.class, priority = 800) 29 | public class InGameHudMixin { 30 | 31 | // Hotbar items 32 | @WrapOperation( 33 | //? if <1.20.5 { 34 | method = "renderHotbar", 35 | //?} else 36 | /*method = "renderHotbarVanilla",*/ 37 | at = @At( 38 | value = "INVOKE", 39 | //? if <1.21 { 40 | target = "Lnet/minecraft/client/gui/hud/InGameHud;renderHotbarItem(Lnet/minecraft/client/gui/DrawContext;IIFLnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/item/ItemStack;I)V" 41 | //?} else 42 | /*target = "Lnet/minecraft/client/gui/hud/InGameHud;renderHotbarItem(Lnet/minecraft/client/gui/DrawContext;IILnet/minecraft/client/render/RenderTickCounter;Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/item/ItemStack;I)V"*/ 43 | ) 44 | ) 45 | private void autoHud$transparentHotbarItems( 46 | InGameHud instance, 47 | DrawContext context, 48 | int x, int y, 49 | //? if <1.21 { 50 | float tickCounter, 51 | //?} else 52 | /*RenderTickCounter tickCounter,*/ 53 | PlayerEntity player, 54 | ItemStack stack, 55 | int seed, 56 | Operation original 57 | ) { 58 | ComponentRenderer.HOTBAR_ITEMS.wrap(context, () -> original.call(instance, context, x, y, tickCounter, player, stack, seed)); 59 | } 60 | 61 | 62 | // Crosshair 63 | @WrapOperation(method = "renderCrosshair", 64 | slice = @Slice( 65 | //? if <1.21.2 66 | from = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;blendFuncSeparate(Lcom/mojang/blaze3d/platform/GlStateManager$SrcFactor;Lcom/mojang/blaze3d/platform/GlStateManager$DstFactor;Lcom/mojang/blaze3d/platform/GlStateManager$SrcFactor;Lcom/mojang/blaze3d/platform/GlStateManager$DstFactor;)V"), 67 | to = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/GameOptions;getAttackIndicator()Lnet/minecraft/client/option/SimpleOption;") 68 | ), 69 | at = @At( 70 | value = "INVOKE", 71 | //? if <1.21.2 { 72 | target = "Lnet/minecraft/client/gui/DrawContext;drawGuiTexture(Lnet/minecraft/util/Identifier;IIII)V" 73 | //?} else 74 | /*target = "Lnet/minecraft/client/gui/DrawContext;drawGuiTexture(Ljava/util/function/Function;Lnet/minecraft/util/Identifier;IIII)V"*/ 75 | ) 76 | ) 77 | private void autoHud$renderCrosshair( 78 | DrawContext context, 79 | //? if >=1.21.2 80 | /*Function renderLayer,*/ 81 | Identifier texture, 82 | int x, int y, 83 | int width, int height, 84 | Operation original 85 | ) { 86 | ComponentRenderer.CROSSHAIR.wrap(context, () -> original.call( 87 | context, 88 | //? if >=1.21.2 89 | /*renderLayer,*/ 90 | texture, 91 | x, y, 92 | width, height 93 | )); 94 | } 95 | 96 | 97 | // Status Effects 98 | @WrapOperation( 99 | method = "renderStatusEffectOverlay", 100 | at = @At( 101 | value = "INVOKE", 102 | //? if <1.21.2 { 103 | target = "Lnet/minecraft/client/gui/DrawContext;drawGuiTexture(Lnet/minecraft/util/Identifier;IIII)V" 104 | //?} else 105 | /*target = "Lnet/minecraft/client/gui/DrawContext;drawGuiTexture(Ljava/util/function/Function;Lnet/minecraft/util/Identifier;IIII)V"*/ 106 | ) 107 | ) 108 | private void autoHud$statusEffectBackground( 109 | DrawContext context, 110 | //? if >=1.21.2 111 | /*Function renderLayer,*/ 112 | Identifier texture, 113 | int x, int y, 114 | int width, int height, 115 | Operation original, 116 | @Local StatusEffectInstance statusEffectInstance 117 | ) { 118 | ComponentRenderer.getForStatusEffect(statusEffectInstance).wrap(context, () -> original.call( 119 | context, 120 | //? if >=1.21.2 121 | /*renderLayer,*/ 122 | texture, 123 | x, y, 124 | width, height 125 | )); 126 | } 127 | 128 | @WrapOperation(method = "renderStatusEffectOverlay", at = @At(value = "INVOKE", target = "Lnet/neoforged/neoforge/client/extensions/common/IClientMobEffectExtensions;renderGuiIcon(Lnet/minecraft/entity/effect/StatusEffectInstance;Lnet/minecraft/client/gui/hud/InGameHud;Lnet/minecraft/client/gui/DrawContext;IIFF)Z")) 129 | private boolean autoHud$postEffect(IClientMobEffectExtensions instance, StatusEffectInstance statusEffectInstance, InGameHud gui, DrawContext context, int x, int y, float z, float alpha, Operation original) { 130 | AtomicBoolean result = new AtomicBoolean(false); 131 | ComponentRenderer.getForStatusEffect(statusEffectInstance).wrap(context, () -> 132 | result.set(original.call(instance, statusEffectInstance, gui, context, x, y, z, alpha)) 133 | ); 134 | return result.get(); 135 | } 136 | 137 | @WrapOperation( 138 | //? if <1.20.5 { 139 | method = {"m_279741_", "method_18620"}, 140 | //?} else if <1.21.2 { 141 | //method = "lambda$renderEffects$10", 142 | //?} else 143 | /*method = "lambda$renderEffects$11",*/ 144 | at = @At( 145 | value = "INVOKE", 146 | //? if <1.21.2 { 147 | target = "Lnet/minecraft/client/gui/DrawContext;drawSprite(IIIIILnet/minecraft/client/texture/Sprite;)V" 148 | //?} else 149 | /*target = "Lnet/minecraft/client/gui/DrawContext;drawSpriteStretched(Ljava/util/function/Function;Lnet/minecraft/client/texture/Sprite;IIIII)V"*/ 150 | ), 151 | require = 0 152 | ) 153 | private static void autoHud$preSprite( 154 | DrawContext context, 155 | //? if >=1.21.2 { 156 | /*Function renderLayer, 157 | Sprite sprite, 158 | *///?} 159 | int x, int y, int z, 160 | int width, int height, 161 | //? if <1.21.2 162 | Sprite sprite, 163 | Operation original 164 | ) { 165 | ComponentRenderer.getForStatusEffect(sprite).wrap(context, 166 | //? if <1.21.2 { 167 | () -> original.call(context, x, y, z, width, height, sprite) 168 | //?} else 169 | /*() -> original.call(context, renderLayer, sprite, x, y, z, width, height)*/ 170 | ); 171 | } 172 | 173 | @WrapOperation(method = "renderStatusEffectOverlay", at = @At(value = "INVOKE", target="Lnet/minecraft/entity/effect/StatusEffectInstance;shouldShowIcon()Z")) 174 | private boolean autoHud$shouldShowIconProxy(StatusEffectInstance instance, Operation original) { 175 | return (original.call(instance) || AutoHud.config.showHiddenStatusEffects()) && Hud.shouldShowIcon(instance); 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /neoforge/src/main/java/mod/crend/autohud/neoforge/mixin/gui/StatusEffectTimerMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.neoforge.mixin.gui; 2 | 3 | import com.llamalad7.mixinextras.sugar.Local; 4 | import mod.crend.autohud.AutoHud; 5 | import mod.crend.autohud.render.ComponentRenderer; 6 | import mod.crend.libbamboo.PlatformUtils; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.gui.DrawContext; 9 | import net.minecraft.client.gui.hud.InGameHud; 10 | import net.minecraft.client.render.RenderTickCounter; 11 | import net.minecraft.client.resource.language.I18n; 12 | import net.minecraft.entity.effect.StatusEffectInstance; 13 | import net.minecraft.util.math.MathHelper; 14 | import org.spongepowered.asm.mixin.Final; 15 | import org.spongepowered.asm.mixin.Mixin; 16 | import org.spongepowered.asm.mixin.Shadow; 17 | import org.spongepowered.asm.mixin.Unique; 18 | import org.spongepowered.asm.mixin.injection.At; 19 | import org.spongepowered.asm.mixin.injection.Inject; 20 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 21 | 22 | import java.util.List; 23 | 24 | /* 25 | * This file is originally part of the StatusEffectTimer mod: 26 | * https://github.com/magicus/statuseffecttimer 27 | * 28 | * It is included here in order to be modified properly. 29 | * Changes: 30 | * - Skip timers for hidden effects by redirecting StatusEffectInstance.shouldShowIcon() 31 | * - Insert matrix push/pop for moving each timer text with its icon 32 | */ 33 | 34 | // Set priority to 500, to load before default at 1000. This is to better cooperate with HUDTweaks. 35 | @Mixin(value = InGameHud.class, priority = 500) 36 | public abstract class StatusEffectTimerMixin { 37 | @Shadow @Final 38 | private MinecraftClient client; 39 | 40 | @Inject(method = "renderStatusEffectOverlay", 41 | at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", shift = At.Shift.AFTER)) 42 | private void appendOverlayDrawing( 43 | DrawContext context, 44 | //? if >1.20.6 { 45 | /*RenderTickCounter tickDelta, 46 | *///?} else if >1.20.5 47 | /*float tickDelta,*/ 48 | CallbackInfo c, 49 | @Local List list, 50 | @Local StatusEffectInstance statusEffectInstance, 51 | @Local(ordinal = 2) int i2, 52 | @Local(ordinal = 3) int i3, 53 | @Local(ordinal = 4) int i4, 54 | @Local(ordinal = 5) int i5 55 | ) { 56 | list.add(() -> { 57 | if (AutoHud.config.statusEffectTimer()) { 58 | int x = switch (PlatformUtils.getCurrentPlatform()) { 59 | case FABRIC -> i4; 60 | case FORGE -> i5; 61 | case NEOFORGE -> i2; 62 | }; 63 | int y = switch (PlatformUtils.getCurrentPlatform()) { 64 | case FABRIC -> i5; 65 | case FORGE -> i3; 66 | case NEOFORGE -> i3; 67 | }; 68 | ComponentRenderer.getForStatusEffect(statusEffectInstance).wrap(context, () -> drawStatusEffectOverlay(context, statusEffectInstance, x, y)); 69 | } 70 | }); 71 | } 72 | 73 | @Unique 74 | private void drawStatusEffectOverlay(DrawContext context, StatusEffectInstance statusEffectInstance, int x, int y) { 75 | String duration = getDurationAsString(statusEffectInstance); 76 | int durationLength = client.textRenderer.getWidth(duration); 77 | context.drawTextWithShadow(client.textRenderer, duration, x + 13 - (durationLength / 2), y + 14, 0x99FFFFFF); 78 | 79 | int amplifier = statusEffectInstance.getAmplifier(); 80 | if (amplifier > 0) { 81 | // Convert to roman numerals if possible 82 | String amplifierString = (amplifier < 10) ? I18n.translate("enchantment.level." + (amplifier + 1)) : "**"; 83 | int amplifierLength = client.textRenderer.getWidth(amplifierString); 84 | context.drawTextWithShadow(client.textRenderer, amplifierString, x + 22 - amplifierLength, y + 3, 0x99FFFFFF); 85 | } 86 | } 87 | 88 | @Unique 89 | private String getDurationAsString(StatusEffectInstance statusEffectInstance) { 90 | if (statusEffectInstance.isInfinite()) { 91 | return I18n.translate("effect.duration.infinite"); 92 | } 93 | 94 | int ticks = MathHelper.floor((float) statusEffectInstance.getDuration()); 95 | int seconds = ticks / 20; 96 | 97 | if (seconds >= 3600) { 98 | return seconds / 3600 + "h"; 99 | } else if (seconds >= 60) { 100 | return seconds / 60 + "m"; 101 | } else { 102 | return String.valueOf(seconds); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /neoforge/src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | modLoader = "javafml" 2 | loaderVersion = "*" 3 | issueTrackerURL = "https://github.com/Crendgrim/AutoHUD/issues" 4 | license = "LGPL-3.0" 5 | 6 | [[mods]] 7 | modId = "${id}" 8 | version = "${version}" 9 | displayName = "${name}" 10 | authors = "Crendgrim" 11 | description = ''' 12 | Dynamic HUD that hides interface elements while they are not needed. 13 | ''' 14 | logoFile = "autohud.png" 15 | logoBlur = false 16 | displayTest = "IGNORE_ALL_VERSION" 17 | 18 | [[mixins]] 19 | config = "autohud-common.mixins.json" 20 | 21 | [[mixins]] 22 | config = "autohud-common-compat.mixins.json" 23 | 24 | [[mixins]] 25 | config = "autohud-neoforge.mixins.json" -------------------------------------------------------------------------------- /neoforge/src/main/resources/META-INF/neoforge.mods.toml: -------------------------------------------------------------------------------- 1 | modLoader = "javafml" 2 | loaderVersion = "*" 3 | issueTrackerURL = "https://github.com/Crendgrim/AutoHUD/issues" 4 | license = "LGPL-3.0" 5 | 6 | [[mods]] 7 | modId = "${id}" 8 | version = "${version}" 9 | displayName = "${name}" 10 | authors = "Crendgrim" 11 | description = ''' 12 | Dynamic HUD that hides interface elements while they are not needed. 13 | ''' 14 | logoFile = "autohud.png" 15 | logoBlur = false 16 | displayTest = "IGNORE_ALL_VERSION" 17 | 18 | [[mixins]] 19 | config = "autohud-common.mixins.json" 20 | 21 | [[mixins]] 22 | config = "autohud-common-compat.mixins.json" 23 | 24 | [[mixins]] 25 | config = "autohud-neoforge.mixins.json" -------------------------------------------------------------------------------- /neoforge/src/main/resources/autohud-neoforge.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "mod.crend.autohud.neoforge.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "client": [ 7 | "gui.InGameHudMixin", 8 | "gui.StatusEffectTimerMixin" 9 | ], 10 | "injectors": { 11 | "defaultRequire": 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /neoforge/src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "AutoHUD", 4 | "pack_format": 9 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Crendgrim/AutoHUD/e6fd1ea95c3f74646c5c73d447d89f79eeef7c95/screenshot1.png -------------------------------------------------------------------------------- /screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Crendgrim/AutoHUD/e6fd1ea95c3f74646c5c73d447d89f79eeef7c95/screenshot2.png -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenCentral() 4 | gradlePluginPortal() 5 | maven("https://maven.fabricmc.net/") 6 | maven("https://maven.architectury.dev") 7 | maven("https://maven.minecraftforge.net") 8 | maven("https://maven.neoforged.net/releases/") 9 | maven("https://maven.kikugie.dev/snapshots") 10 | } 11 | } 12 | 13 | plugins { 14 | id("dev.kikugie.stonecutter") version "0.5-beta.5" 15 | } 16 | 17 | var fabricVersions = linkedSetOf( "1.20.1", "1.20.4", "1.20.6", "1.21.1", "1.21.3") 18 | var forgeVersions = linkedSetOf( "1.20.1", "1.20.4", "1.20.6", "1.21.1", "1.21.3") 19 | var neoforgeVersions = linkedSetOf( "1.20.4", "1.20.6", "1.21.1", "1.21.3") 20 | 21 | stonecutter { 22 | centralScript = "build.gradle.kts" 23 | kotlinController = true 24 | create(rootProject) { 25 | // Root `src/` functions as the 'common' project 26 | versions(fabricVersions + forgeVersions + neoforgeVersions) 27 | branch("fabric") { versions(fabricVersions) } 28 | branch("forge") { versions(forgeVersions) } 29 | branch("neoforge") { versions(neoforgeVersions) } 30 | } 31 | } 32 | 33 | rootProject.name = "Auto HUD" -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/AutoHud.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud; 2 | 3 | import mod.crend.autohud.api.AutoHudApi; 4 | import mod.crend.autohud.component.EventHandler; 5 | import mod.crend.autohud.component.Hud; 6 | import mod.crend.autohud.config.ConfigHandler; 7 | import mod.crend.libbamboo.PlatformUtils; 8 | import mod.crend.libbamboo.event.GameEvent; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class AutoHud { 14 | 15 | public static final String MOD_ID = "autohud"; 16 | 17 | public static ConfigHandler config; 18 | public static final List apis = new ArrayList<>(); 19 | 20 | // These are global toggles that are usually always true. 21 | // Whole sections may be disabled using these flags to enhance mod compatibility. 22 | public static boolean targetHotbar = true; 23 | public static boolean targetExperienceBar = true; 24 | public static boolean targetStatusBars = true; 25 | public static boolean targetScoreboard = true; 26 | public static boolean targetStatusEffects = true; 27 | public static boolean targetCrosshair = true; 28 | public static boolean targetChat = true; 29 | 30 | public static void loadConfig() { 31 | config = new ConfigHandler(); 32 | } 33 | public static void init() { 34 | if (config.dynamicOnLoad()) { 35 | Hud.enableDynamic(); 36 | } 37 | GameEvent.WORLD_LOAD.register(Hud::registerState); 38 | GameEvent.WORLD_TICK.register(Hud::tickState); 39 | GameEvent.WORLD_UNLOAD.register(Hud::unregisterState); 40 | GameEvent.PLAYER_RESPAWN.register(Hud::registerState); 41 | EventHandler.registerEvents(); 42 | } 43 | 44 | public static void addApi(AutoHudApi api) { 45 | if (PlatformUtils.isModLoaded(api.modId())) { 46 | apis.add(api); 47 | api.init(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/AutoHudCompatMixinPlugin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud; 2 | 3 | import mod.crend.libbamboo.PlatformUtils; 4 | import org.objectweb.asm.tree.ClassNode; 5 | import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; 6 | import org.spongepowered.asm.mixin.extensibility.IMixinInfo; 7 | 8 | import java.util.List; 9 | import java.util.Set; 10 | 11 | public class AutoHudCompatMixinPlugin implements IMixinConfigPlugin { 12 | 13 | @Override 14 | public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { 15 | String[] split = mixinClassName.split("\\.compat\\.mixin\\."); 16 | if (split.length == 2) { 17 | String modid = split[1].split("\\.")[0]; 18 | // Special handling for mods with - in their mod id 19 | if (modid.equals("statuseffectbars")) { 20 | modid = "status-effect-bars"; 21 | } 22 | return PlatformUtils.isModPresent(modid); 23 | } 24 | return true; 25 | } 26 | 27 | @Override 28 | public void onLoad(String mixinPackage) { 29 | } 30 | 31 | @Override 32 | public String getRefMapperConfig() { 33 | return null; 34 | } 35 | 36 | @Override 37 | public void acceptTargets(Set myTargets, Set otherTargets) { 38 | 39 | } 40 | 41 | @Override 42 | public List getMixins() { 43 | return null; 44 | } 45 | 46 | @Override 47 | public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { 48 | 49 | } 50 | 51 | @Override 52 | public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/ModKeyBindings.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud; 2 | 3 | import mod.crend.autohud.component.Hud; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.option.KeyBinding; 6 | import net.minecraft.client.util.InputUtil; 7 | import org.lwjgl.glfw.GLFW; 8 | 9 | import java.util.List; 10 | 11 | public class ModKeyBindings { 12 | public static final String CATEGORY = "key.category.autohud"; 13 | 14 | public static final KeyBinding TOGGLE_HUD = new KeyBinding( 15 | "key.autohud.toggle-hud", 16 | InputUtil.Type.KEYSYM, 17 | GLFW.GLFW_KEY_G, 18 | CATEGORY 19 | ); 20 | 21 | public static KeyBinding PEEK_HUD = new KeyBinding( 22 | "key.autohud.peek-hud", 23 | InputUtil.Type.KEYSYM, 24 | GLFW.GLFW_KEY_R, 25 | CATEGORY 26 | ); 27 | 28 | public static final List ALL = List.of( 29 | TOGGLE_HUD, 30 | PEEK_HUD 31 | ); 32 | 33 | public static void clientTick(MinecraftClient client) { 34 | while (TOGGLE_HUD.wasPressed()) { 35 | Hud.toggleHud(); 36 | } 37 | Hud.peekHud(PEEK_HUD.isPressed()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/api/AutoHudApi.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.api; 2 | 3 | import net.minecraft.client.network.ClientPlayerEntity; 4 | 5 | public interface AutoHudApi { 6 | /** 7 | * We want to load the compatibility module only if the targeted mod is present. 8 | * @return the targeted mod's ID, as defined in its fabric.mod.json 9 | */ 10 | String modId(); 11 | 12 | /** 13 | * Implement this method for a one-time initialisation on game start. 14 | */ 15 | default void init() { } 16 | 17 | /** 18 | * Implement this method to initialize a component 19 | * @param player currently active player 20 | */ 21 | default void initState(ClientPlayerEntity player) { } 22 | 23 | /** 24 | * Implement this method to add special component handling on ticks 25 | * @param player currently active player 26 | */ 27 | default void tickState(ClientPlayerEntity player) { } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/compat/HotbarSlotCyclingCompat.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat; 2 | 3 | import mod.crend.autohud.api.AutoHudApi; 4 | 5 | //? if hotbarslotcycling { 6 | /*import fuzs.hotbarslotcycling.api.v1.client.CyclingSlotsRenderer; 7 | import fuzs.hotbarslotcycling.api.v1.client.HotbarCyclingProvider; 8 | import mod.crend.autohud.AutoHud; 9 | import mod.crend.autohud.api.AutoHudApi; 10 | import mod.crend.autohud.component.Component; 11 | import mod.crend.autohud.component.Components; 12 | import mod.crend.autohud.component.state.ItemStackComponentState; 13 | import mod.crend.autohud.render.AutoHudRenderer; 14 | import mod.crend.autohud.render.AutoHudRenderLayer; 15 | import mod.crend.autohud.render.ComponentRenderer; 16 | import net.minecraft.client.font.TextRenderer; 17 | import net.minecraft.client.gui.DrawContext; 18 | import net.minecraft.client.network.ClientPlayerEntity; 19 | import net.minecraft.entity.player.PlayerEntity; 20 | import net.minecraft.item.ItemStack; 21 | *///?} 22 | 23 | public class HotbarSlotCyclingCompat implements AutoHudApi { 24 | @Override 25 | public String modId() { 26 | return "hotbarslotcycling"; 27 | } 28 | 29 | //? if hotbarslotcycling { 30 | 31 | /*public static Component HOTBAR_SLOT_CYCLING_COMPONENT = Component.builder("hotbarslotcycling") 32 | .isTargeted(() -> AutoHud.targetHotbar) 33 | .config(AutoHud.config.hotbar()) 34 | .inMainHud() 35 | .state(player -> new ItemStackComponentState( 36 | HotbarSlotCyclingCompat.HOTBAR_SLOT_CYCLING_COMPONENT, 37 | () -> HotbarCyclingProvider.GLOBAL_PROVIDER[0].apply(player).getForwardStack(), 38 | true 39 | )) 40 | .build(); 41 | public static ComponentRenderer COMPONENT_WRAPPER = ComponentRenderer.of(HOTBAR_SLOT_CYCLING_COMPONENT); 42 | public static ComponentRenderer BACKGROUND_WRAPPER = ComponentRenderer.builder(HOTBAR_SLOT_CYCLING_COMPONENT) 43 | .fade() 44 | .isActive(() -> HOTBAR_SLOT_CYCLING_COMPONENT.isActive() && AutoHud.config.animationFade()) 45 | .doRender(AutoHudRenderer::shouldRenderHotbarItems) 46 | .withCustomFramebuffer(true) 47 | .beginRender(COMPONENT_WRAPPER::endFade) 48 | .build(); 49 | public static ComponentRenderer ITEM_WRAPPER = ComponentRenderer.builder(HOTBAR_SLOT_CYCLING_COMPONENT) 50 | .fade() 51 | .isActive(() -> HOTBAR_SLOT_CYCLING_COMPONENT.isActive() && AutoHud.config.animationFade()) 52 | .doRender(() -> ( 53 | // Render items when they're not fully hidden (in other words, visible in some way) 54 | !HOTBAR_SLOT_CYCLING_COMPONENT.fullyHidden() 55 | // If we are in fade mode, only render items if they're not fully transparent. 56 | || (AutoHud.config.animationFade() && AutoHud.config.getHotbarItemsMaximumFade() > 0.0f) 57 | // If we are neither in fade nor move mode, skip rendering if it's hidden. 58 | // If we are in move mode, the items may still be visible in the "hidden" state! 59 | || (!AutoHud.config.animationFade() && AutoHud.config.animationMove()) 60 | )) 61 | .withCustomFramebuffer(true) 62 | .beginRender(COMPONENT_WRAPPER::endFade) 63 | .build(); 64 | 65 | @Override 66 | public void init() { 67 | CyclingSlotsRenderer.setSlotsRenderer(new WrappedCyclingSlotsRenderer(CyclingSlotsRenderer.getSlotsRenderer())); 68 | } 69 | 70 | @Override 71 | public void initState(ClientPlayerEntity player) { 72 | HOTBAR_SLOT_CYCLING_COMPONENT.reveal(); 73 | } 74 | 75 | @Override 76 | public void tickState(ClientPlayerEntity player) { 77 | // With bad timing, we can sometimes be one tick off from the hotbar. 78 | // That will make the slot cycler start moving just a bit earlier, which looks bad. 79 | if (HOTBAR_SLOT_CYCLING_COMPONENT.fullyRevealed()) { 80 | HOTBAR_SLOT_CYCLING_COMPONENT.synchronizeFrom(Components.Hotbar); 81 | } 82 | } 83 | 84 | static class WrappedCyclingSlotsRenderer implements CyclingSlotsRenderer { 85 | 86 | CyclingSlotsRenderer parent; 87 | 88 | public WrappedCyclingSlotsRenderer(CyclingSlotsRenderer parent) { 89 | this.parent = parent; 90 | } 91 | 92 | @Override 93 | public void renderSlots(DrawContext context, int screenWidth, int screenHeight, float partialTick, TextRenderer font, PlayerEntity player, ItemStack backwardStack, ItemStack selectedStack, ItemStack forwardStack) { 94 | COMPONENT_WRAPPER.wrap(context, () -> parent.renderSlots(context, screenWidth, screenHeight, partialTick, font, player, backwardStack, selectedStack, forwardStack)); 95 | } 96 | 97 | @Override 98 | public boolean testValidStacks(ItemStack backwardStack, ItemStack selectedStack, ItemStack forwardStack) { 99 | boolean original = parent.testValidStacks(backwardStack, selectedStack, forwardStack); 100 | if (!AutoHud.targetHotbar) return original; 101 | if (!original) { 102 | HOTBAR_SLOT_CYCLING_COMPONENT.forceHide(); 103 | } 104 | return !HOTBAR_SLOT_CYCLING_COMPONENT.fullyHidden() || (AutoHud.config.animationFade() && AutoHud.config.getHotbarItemsMaximumFade() > 0.0f); 105 | } 106 | 107 | @Override 108 | public void renderSlotBackgrounds(DrawContext context, int posX, int posY, boolean renderForwardStack, boolean renderBackwardStack, boolean renderToRight) { 109 | BACKGROUND_WRAPPER.wrap(context, () -> parent.renderSlotBackgrounds(context, posX, posY, renderForwardStack, renderBackwardStack, renderToRight)); 110 | } 111 | 112 | @Override 113 | public void renderSlotItems(DrawContext context, int posX, int posY, float partialTick, TextRenderer font, PlayerEntity player, ItemStack selectedStack, ItemStack forwardStack, ItemStack backwardStack, boolean renderToRight) { 114 | ITEM_WRAPPER.wrap(context, () -> parent.renderSlotItems(context, posX, posY, partialTick, font, player, selectedStack, forwardStack, backwardStack, renderToRight)); 115 | } 116 | 117 | @Override 118 | public void renderItemInSlot(DrawContext context, int posX, int posY, float partialTick, TextRenderer font, PlayerEntity player, ItemStack stack) { 119 | parent.renderItemInSlot(context, posX, posY, partialTick, font, player, stack); 120 | } 121 | } 122 | *///?} 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/compat/RaisedCompat.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.compat; 2 | 3 | //? if raised { 4 | import dev.yurisuika.raised.api.RaisedApi; 5 | import dev.yurisuika.raised.util.properties.Element; 6 | //?} 7 | import mod.crend.autohud.render.AutoHudRenderer; 8 | import net.minecraft.client.MinecraftClient; 9 | 10 | public class RaisedCompat { 11 | public static void tick() { 12 | //? if raised 13 | AutoHudRenderer.globalOffsetY = RaisedApi.getY(Element.HOTBAR); 14 | } 15 | public static void tick(MinecraftClient client) { 16 | tick(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/component/Components.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.component; 2 | 3 | import mod.crend.autohud.AutoHud; 4 | import mod.crend.autohud.component.state.BooleanComponentState; 5 | import mod.crend.autohud.component.state.ComponentState; 6 | import mod.crend.autohud.component.state.EnhancedPolicyComponentState; 7 | import mod.crend.autohud.component.state.ItemStackComponentState; 8 | import mod.crend.autohud.component.state.PolicyComponentState; 9 | import mod.crend.autohud.component.state.ScoreboardComponentState; 10 | import mod.crend.autohud.component.state.ValueComponentState; 11 | //? if <1.21.2 { 12 | import net.minecraft.item.Equipment; 13 | //?} else { 14 | /*import net.minecraft.component.DataComponentTypes; 15 | import net.minecraft.component.type.EquippableComponent; 16 | import net.minecraft.item.ItemStack; 17 | *///?} 18 | 19 | import java.util.function.Supplier; 20 | 21 | public class Components { 22 | public static final Supplier TARGET_CHAT = () -> AutoHud.targetChat; 23 | public static final Supplier TARGET_CROSSHAIR = () -> AutoHud.targetCrosshair; 24 | public static final Supplier TARGET_EXPERIENCE_BAR = () -> AutoHud.targetExperienceBar; 25 | public static final Supplier TARGET_HOTBAR = () -> AutoHud.targetHotbar; 26 | public static final Supplier TARGET_SCOREBOARD = () -> AutoHud.targetScoreboard; 27 | public static final Supplier TARGET_STATUS_BARS = () -> AutoHud.targetStatusBars; 28 | 29 | public static Component Armor = Component.builder("armor") 30 | .isTargeted(TARGET_STATUS_BARS) 31 | .config(AutoHud.config.armor()) 32 | .inMainHud() 33 | .state(player -> new EnhancedPolicyComponentState(Components.Armor, 34 | player::getArmor, 35 | 20, 36 | () -> 37 | //? if <1.21.2 { 38 | player.getMainHandStack().getItem() instanceof Equipment equipment 39 | && equipment.getSlotType().isArmorSlot() 40 | && player.canEquip(player.getMainHandStack()) 41 | //?} else { 42 | /*{ 43 | ItemStack mainHandStack = player.getMainHandStack(); 44 | EquippableComponent equipment = mainHandStack.get(DataComponentTypes.EQUIPPABLE); 45 | return equipment != null 46 | && equipment.slot().isArmorSlot() 47 | && player.canEquip(mainHandStack, equipment.slot()); 48 | } 49 | *///?} 50 | , true 51 | )) 52 | .build(); 53 | 54 | public static Component Health = Component.builder("health") 55 | .isTargeted(TARGET_STATUS_BARS) 56 | .config(AutoHud.config.health()) 57 | .stackComponents(Armor) 58 | .inMainHud() 59 | .state(player -> new EnhancedPolicyComponentState(Components.Health, 60 | () -> Math.round(player.getHealth()), 61 | () -> Math.round(player.getMaxHealth()), 62 | State::canHeal 63 | )) 64 | .build(); 65 | 66 | public static Component Air = Component.builder("air") 67 | .isTargeted(TARGET_STATUS_BARS) 68 | .config(AutoHud.config.air()) 69 | .inMainHud() 70 | .state(player -> new PolicyComponentState(Components.Air, player::getAir, player::getMaxAir)) 71 | .build(); 72 | 73 | public static Component Hunger = Component.builder("hunger") 74 | .isTargeted(TARGET_STATUS_BARS) 75 | .config(AutoHud.config.hunger()) 76 | .stackComponents(Air) 77 | .inMainHud() 78 | .state(player -> new EnhancedPolicyComponentState(Components.Hunger, 79 | () -> player.getHungerManager().getFoodLevel(), 80 | 20, 81 | () -> AutoHud.config.revealHungerWhenHoldingFoodItem() 82 | && player.getHungerManager().getFoodLevel() < 20 83 | && State.isFood(player.getMainHandStack()) 84 | )) 85 | .build(); 86 | 87 | 88 | public static Component MountHealth = Component.builder("mount_health") 89 | .isTargeted(TARGET_STATUS_BARS) 90 | .config(AutoHud.config.mountHealth()) 91 | .stackComponents(Air) 92 | .inMainHud() 93 | .build(); 94 | 95 | public static Component MountJumpBar = Component.builder("mount_jump_bar") 96 | .isTargeted(TARGET_STATUS_BARS) 97 | .config(AutoHud.config.mountJumpBar()) 98 | .inMainHud() 99 | .state(player -> new ComponentState(Components.MountJumpBar)) 100 | .build(); 101 | 102 | 103 | public static Component ExperienceLevel = Component.builder("experience_level") 104 | .isTargeted(TARGET_EXPERIENCE_BAR) 105 | .config(AutoHud.config.experience()) 106 | .inMainHud() 107 | .state(player -> new ValueComponentState<>(Components.ExperienceLevel, () -> player.experienceLevel, true)) 108 | .build(); 109 | 110 | public static Component ExperienceBar = Component.builder("experience_bar") 111 | .isTargeted(TARGET_EXPERIENCE_BAR) 112 | .config(AutoHud.config.experienceBar()) 113 | .stackComponents(Health, Hunger, MountHealth, ExperienceLevel) 114 | .inMainHud() 115 | .state(player -> new ValueComponentState<>(Components.ExperienceBar, () -> player.totalExperience, true)) 116 | .build(); 117 | 118 | 119 | public static Component Hotbar = Component.builder("hotbar") 120 | .isTargeted(TARGET_HOTBAR) 121 | .config(AutoHud.config.hotbar()) 122 | .stackComponents(ExperienceBar) 123 | .inMainHud() 124 | .state(player -> new ItemStackComponentState(Components.Hotbar, player::getMainHandStack, true)) 125 | .build(); 126 | 127 | public static Component Tooltip = Component.builder("tooltip") 128 | .isTargeted(TARGET_HOTBAR) 129 | .config(AutoHud.config.tooltip()) 130 | .inMainHud() 131 | .state(player -> new ItemStackComponentState(Components.Tooltip, player::getMainHandStack, true)) 132 | .build(); 133 | 134 | 135 | public static Component Scoreboard = Component.builder("scoreboard") 136 | .isTargeted(TARGET_SCOREBOARD) 137 | .config(AutoHud.config.scoreboard()) 138 | .state(player -> new ScoreboardComponentState(Components.Scoreboard)) 139 | .build(); 140 | 141 | 142 | public static Component Crosshair = Component.builder("crosshair") 143 | .isTargeted(TARGET_CROSSHAIR) 144 | .config(AutoHud.config.crosshair()) 145 | .state(player -> new BooleanComponentState(Components.Crosshair, State::shouldShowCrosshair)) 146 | .build(); 147 | 148 | 149 | public static Component Chat = Component.builder("chat") 150 | .isTargeted(TARGET_CHAT) 151 | .config(AutoHud.config.chat()) 152 | .state(player -> new ComponentState(Components.Chat)) 153 | .build(); 154 | 155 | public static Component ChatIndicator = Component.builder("chat_indicator") 156 | .isTargeted(TARGET_CHAT) 157 | .config(AutoHud.config.chatIndicator()) 158 | .state(player -> new ComponentState(Components.ChatIndicator)) 159 | .build(); 160 | 161 | 162 | public static Component ActionBar = Component.builder("action_bar") 163 | .config(AutoHud.config.actionBar()) 164 | .state(player -> new ComponentState(Components.ActionBar)) 165 | .build(); 166 | 167 | public static Component BossBar = Component.builder("boss_bar") 168 | .config(AutoHud.config.bossBar()) 169 | .state(player -> new ComponentState(Components.BossBar)) 170 | .build(); 171 | } 172 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/component/EventHandler.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.component; 2 | 3 | import mod.crend.autohud.AutoHud; 4 | import mod.crend.autohud.component.state.PolicyComponentState; 5 | import mod.crend.autohud.config.EventPolicy; 6 | import mod.crend.libbamboo.event.*; 7 | import net.minecraft.block.Blocks; 8 | import net.minecraft.registry.tag.BlockTags; 9 | import net.minecraft.util.hit.HitResult; 10 | 11 | public class EventHandler { 12 | public static void registerEvents() { 13 | ScreenEvent.CHAT.register(() -> { 14 | Components.Chat.revealNow(); 15 | Components.ChatIndicator.hide(); 16 | }); 17 | ScreenEvent.OPEN.register(screen -> { 18 | if (AutoHud.config.onScreenOpen() == EventPolicy.Hide) Component.forceHideAll(); 19 | }); 20 | ScreenEvent.TICK.register(screen -> { 21 | if (AutoHud.config.onScreenOpen() == EventPolicy.Reveal) Component.revealAll(); 22 | }); 23 | ScreenEvent.CLOSE.register(() -> { 24 | switch (AutoHud.config.onScreenOpen()) { 25 | case Hide -> Component.updateAll(); 26 | case Reveal -> Component.hideAll(); 27 | } 28 | }); 29 | ScreenEvent.PAUSE_TICK.register(() -> { 30 | switch (AutoHud.config.onPauseScreen()) { 31 | case Reveal -> Component.revealAll(); 32 | case Hide -> Component.forceHideAll(); 33 | } 34 | }); 35 | ScreenEvent.UNPAUSE.register(() -> { 36 | switch (AutoHud.config.onPauseScreen()) { 37 | case Hide -> Component.updateAll(); 38 | case Reveal -> Component.hideAll(); 39 | } 40 | }); 41 | 42 | MoveEvent.MOVING.register((player, position) -> { 43 | switch (AutoHud.config.onMoving()) { 44 | case Reveal -> Component.revealAll(); 45 | case Hide -> Component.forceHideAll(); 46 | default -> { 47 | } 48 | } 49 | }); 50 | MoveEvent.STANDING_STILL.register((player, position) -> { 51 | switch (AutoHud.config.onStandingStill()) { 52 | case Reveal -> Component.revealAll(); 53 | case Hide -> Component.forceHideAll(); 54 | default -> { 55 | if (AutoHud.config.onMoving() == EventPolicy.Hide) Component.updateAll(); 56 | } 57 | } 58 | }); 59 | SneakEvent.TICK.register(player -> { 60 | switch (AutoHud.config.onSneaking()) { 61 | case Reveal -> Component.revealAll(); 62 | case Hide -> Component.forceHideAll(); 63 | } 64 | }); 65 | SneakEvent.STOP.register(player -> { 66 | switch (AutoHud.config.onSneaking()) { 67 | case Reveal -> Component.hideAll(); 68 | case Hide -> Component.updateAll(); 69 | } 70 | }); 71 | FlyEvent.TICK.register(player -> { 72 | switch (AutoHud.config.onFlying()) { 73 | case Reveal -> Component.revealAll(); 74 | case Hide -> Component.forceHideAll(); 75 | } 76 | }); 77 | FlyEvent.STOP.register(player -> { 78 | switch (AutoHud.config.onFlying()) { 79 | case Reveal -> Component.hideAll(); 80 | case Hide -> Component.updateAll(); 81 | } 82 | }); 83 | 84 | StatusEvent.HEALTH.register((value, old, max) -> Components.Health.updateState()); 85 | StatusEvent.FOOD.register((value, old, max) -> Components.Hunger.updateState()); 86 | StatusEvent.AIR.register((value, old, max) -> Components.Air.updateState()); 87 | StatusEvent.EXPERIENCE.register((progress, total, level) -> { 88 | Components.ExperienceLevel.updateState(); 89 | Components.ExperienceBar.updateState(); 90 | }); 91 | HotbarEvent.MAIN_HAND_CHANGE.register(stack -> { 92 | Components.Health.updateStateNextTick(); 93 | Components.Hunger.updateStateNextTick(); 94 | Components.Armor.updateStateNextTick(); 95 | }); 96 | HotbarEvent.SELECTED_SLOT_CHANGE.register(() -> { 97 | if (AutoHud.config.isHotbarOnSlotChange()) { 98 | Components.Hotbar.revealCombined(); 99 | 100 | if (AutoHud.config.revealExperienceTextWithHotbar()) { 101 | Components.ExperienceLevel.synchronizeFrom(Components.Hotbar); 102 | } 103 | } 104 | }); 105 | 106 | MountEvent.START.register((player, vehicle) -> { 107 | Components.MountHealth.state = new PolicyComponentState(Components.MountHealth, () -> (int) vehicle.getHealth(), () -> (int) vehicle.getMaxHealth()); 108 | Components.MountHealth.revealCombined(); 109 | }); 110 | MountEvent.MOUNT_HEALTH_CHANGE.register((value, old, max) -> Components.MountHealth.updateState()); 111 | MountEvent.MOUNT_JUMP.register(vehicle -> { 112 | if (AutoHud.config.mountJumpBar().onChange()) Components.MountJumpBar.revealNow(); 113 | }); 114 | MountEvent.STOP.register(player -> Components.MountHealth.state = null); 115 | 116 | InteractionEvent.USING_ITEM_TICK.register(player -> { 117 | if (AutoHud.config.onUsingItem()) { 118 | Component.revealAll(1); 119 | } 120 | }); 121 | InteractionEvent.MINING_TICK.register(player -> { 122 | if (AutoHud.config.onMining()) { 123 | Component.revealAll(1); 124 | } 125 | }); 126 | InteractionEvent.ATTACK.register((player, hitResult) -> { 127 | if (AutoHud.config.onSwinging() 128 | || (AutoHud.config.onAttacking() && hitResult.getType() == HitResult.Type.ENTITY) 129 | ) { 130 | Component.revealAll(); 131 | } 132 | }); 133 | 134 | TargetEvent.TARGETED_BLOCK_TICK.register(((blockPos, blockState) -> { 135 | if (AutoHud.config.revealExperienceTextOnTargetingEnchantingBlock()) { 136 | if (blockState.getBlock() == Blocks.ENCHANTING_TABLE || blockState.isIn(BlockTags.ANVIL)) { 137 | Components.ExperienceLevel.reveal(); 138 | } 139 | } 140 | })); 141 | 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/component/Hud.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.component; 2 | 3 | import mod.crend.autohud.render.ComponentRenderer; 4 | import net.minecraft.client.network.ClientPlayerEntity; 5 | import net.minecraft.entity.effect.StatusEffectInstance; 6 | 7 | public class Hud { 8 | private static boolean dynamic = false; 9 | private static boolean wasPeeking = false; 10 | 11 | private static State state = null; 12 | 13 | public static boolean actDynamic() { 14 | return dynamic || wasPeeking; 15 | } 16 | 17 | public static void disableDynamic() { 18 | dynamic = false; 19 | Component.revealAll(); 20 | Components.ChatIndicator.hide(); 21 | } 22 | 23 | public static void enableDynamic() { 24 | dynamic = true; 25 | Component.hideAll(); 26 | } 27 | 28 | public static void toggleHud() { 29 | if (dynamic) disableDynamic(); 30 | else enableDynamic(); 31 | } 32 | public static void peekHud(boolean doPeek) { 33 | if (dynamic == doPeek) { 34 | Component.revealAll(); 35 | Components.ChatIndicator.hide(); 36 | } else if (doPeek != wasPeeking) { 37 | Component.hideAll(); 38 | } 39 | 40 | wasPeeking = doPeek; 41 | } 42 | 43 | public static void registerState(ClientPlayerEntity player) { 44 | state = new State(player); 45 | wasPeeking = false; 46 | } 47 | public static void tickState(ClientPlayerEntity player) { 48 | state.tick(player); 49 | } 50 | public static void unregisterState() { 51 | state = null; 52 | } 53 | 54 | public static boolean shouldShowIcon(StatusEffectInstance instance) { 55 | ComponentRenderer renderer = ComponentRenderer.getForStatusEffect(instance); 56 | return (!renderer.isActive() || renderer.doRender()); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/component/ScoreboardHelper.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.component; 2 | 3 | import mod.crend.autohud.AutoHud; 4 | import mod.crend.autohud.component.state.ScoreboardComponentState; 5 | //? if >=1.20.3 6 | /*import net.minecraft.scoreboard.ScoreHolder;*/ 7 | import net.minecraft.scoreboard.ScoreboardObjective; 8 | //? if <1.20.3 { 9 | import net.minecraft.scoreboard.ScoreboardPlayerScore; 10 | //?} else { 11 | /*import net.minecraft.scoreboard.ScoreboardScore; 12 | *///?} 13 | import net.minecraft.scoreboard.Team; 14 | 15 | public class ScoreboardHelper { 16 | public static void onObjectiveUpdate(ScoreboardObjective objective) { 17 | if (canUpdate() && AutoHud.config.shouldRevealScoreboardOnTitleChange()) { 18 | getScoreboardComponent().updateObjectiveDisplayName(objective); 19 | } 20 | } 21 | 22 | //? if <1.20.3 { 23 | public static void onPlayerScoreUpdate(ScoreboardPlayerScore score) { 24 | //?} else { 25 | /*public static void onPlayerScoreUpdate(ScoreHolder scoreHolder, ScoreboardObjective objective, ScoreboardScore score) { 26 | *///?} 27 | if (canUpdate() && AutoHud.config.shouldRevealScoreboardOnScoreChange()) { 28 | //? if <1.20.3 { 29 | getScoreboardComponent().onPlayerScoreUpdate(score); 30 | //?} else { 31 | /*getScoreboardComponent().onPlayerScoreUpdate(scoreHolder, objective, score); 32 | *///?} 33 | } 34 | } 35 | 36 | public static void onPlayerScoreRemove(String playerName) { 37 | if (canUpdate() && AutoHud.config.shouldRevealScoreboardOnScoreChange()) { 38 | getScoreboardComponent().onPlayerScoreRemove(playerName); 39 | } 40 | } 41 | 42 | public static void onPlayerScoreRemove(String playerName, ScoreboardObjective objective) { 43 | if (canUpdate() && AutoHud.config.shouldRevealScoreboardOnScoreChange()) { 44 | getScoreboardComponent().onPlayerScoreRemove(playerName, objective); 45 | } 46 | } 47 | 48 | public static void onTeamRemoved(Team team) { 49 | if (canUpdate() && AutoHud.config.shouldRevealScoreboardOnTeamChange()) { 50 | getScoreboardComponent().onTeamRemoved(team); 51 | } 52 | } 53 | 54 | public static void onTeamUpdated(Team team) { 55 | if (canUpdate() && AutoHud.config.shouldRevealScoreboardOnTeamChange()) { 56 | getScoreboardComponent().onTeamUpdated(team); 57 | } 58 | } 59 | 60 | public static void onPlayerAddedToTeam(String playerName, Team team) { 61 | if (canUpdate() && AutoHud.config.shouldRevealScoreboardOnTeamChange()) { 62 | getScoreboardComponent().onPlayerAddedToTeam(playerName, team); 63 | } 64 | } 65 | 66 | public static void onPlayerRemovedFromTeam(String playerName, Team team) { 67 | if (canUpdate() && AutoHud.config.shouldRevealScoreboardOnTeamChange()) { 68 | getScoreboardComponent().onPlayerRemovedFromTeam(playerName, team); 69 | } 70 | } 71 | 72 | // The next two methods are used to cut down on unnecessary duplicate code 73 | private static boolean canUpdate() { 74 | return Components.Scoreboard.config.active() && Components.Scoreboard.state != null; 75 | } 76 | 77 | private static ScoreboardComponentState getScoreboardComponent() { 78 | return (ScoreboardComponentState) Components.Scoreboard.state; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/component/state/BooleanComponentState.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.component.state; 2 | 3 | import mod.crend.autohud.component.Component; 4 | 5 | import java.util.function.Supplier; 6 | 7 | public class BooleanComponentState extends ComponentState { 8 | Supplier display; 9 | 10 | public BooleanComponentState(Component component, Supplier display, boolean updateEveryTick) { 11 | super(component, updateEveryTick); 12 | this.display = display; 13 | } 14 | public BooleanComponentState(Component component, Supplier display) { 15 | this(component, display, true); 16 | } 17 | 18 | @Override 19 | public void update() { 20 | if (!component.config.active() || (component.config.onChange() && display.get())) { 21 | component.revealCombined(); 22 | } else { 23 | component.hide(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/component/state/ComponentState.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.component.state; 2 | 3 | 4 | import mod.crend.autohud.component.Component; 5 | import mod.crend.autohud.component.Hud; 6 | 7 | public class ComponentState { 8 | protected Component component; 9 | 10 | protected boolean updateEveryTick = false; 11 | protected boolean updateNextTick = true; 12 | 13 | public ComponentState(Component component, boolean updateEveryTick) { 14 | this.component = component; 15 | this.updateEveryTick = updateEveryTick; 16 | } 17 | public ComponentState(Component component) { 18 | this(component, false); 19 | } 20 | 21 | public void tick() { 22 | if (updateNextTick || (updateEveryTick && Hud.actDynamic())) { 23 | update(); 24 | updateNextTick = false; 25 | } 26 | } 27 | 28 | public void update() { 29 | if (!component.config.active()) { 30 | component.revealCombined(); 31 | } 32 | } 33 | 34 | public void updateNextTick() { 35 | updateNextTick = true; 36 | } 37 | 38 | public boolean scheduledUpdate() { 39 | return updateNextTick; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/component/state/EnhancedPolicyComponentState.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.component.state; 2 | 3 | import mod.crend.autohud.component.Component; 4 | 5 | import java.util.function.Supplier; 6 | 7 | public class EnhancedPolicyComponentState extends PolicyComponentState { 8 | protected Supplier test; 9 | 10 | public EnhancedPolicyComponentState(Component component, Supplier newValueSupplier, Supplier maxValueSupplier, Supplier test, boolean updateEveryTick) { 11 | super(component, newValueSupplier, maxValueSupplier, updateEveryTick); 12 | this.test = test; 13 | } 14 | 15 | public EnhancedPolicyComponentState(Component component, Supplier newValueSupplier, Supplier maxValueSupplier, Supplier test) { 16 | super(component, newValueSupplier, maxValueSupplier); 17 | this.test = test; 18 | } 19 | 20 | public EnhancedPolicyComponentState(Component component, Supplier newValueSupplier, Integer maxValueSupplier, Supplier test, boolean updateEveryTick) { 21 | super(component, newValueSupplier, maxValueSupplier, updateEveryTick); 22 | this.test = test; 23 | } 24 | 25 | public EnhancedPolicyComponentState(Component component, Supplier newValueSupplier, Integer maxValueSupplier, Supplier test) { 26 | super(component, newValueSupplier, maxValueSupplier); 27 | this.test = test; 28 | } 29 | 30 | @Override 31 | protected boolean doReveal(Integer newValue) { 32 | return test.get() || super.doReveal(newValue); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/component/state/ItemStackComponentState.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.component.state; 2 | 3 | import mod.crend.autohud.component.Component; 4 | import net.minecraft.item.ItemStack; 5 | 6 | import java.util.function.Supplier; 7 | 8 | public class ItemStackComponentState extends ValueComponentState { 9 | public ItemStackComponentState(Component component, Supplier newValueSupplier, boolean updateEveryTick) { 10 | super(component, () -> newValueSupplier.get().copy(), updateEveryTick); 11 | } 12 | public ItemStackComponentState(Component component, Supplier newValueSupplier) { 13 | super(component, newValueSupplier, false); 14 | } 15 | 16 | @Override 17 | protected boolean doReveal(ItemStack newValue) { 18 | return !component.config.active() || (component.config.onChange() && !ItemStack.areEqual(oldValue, newValue)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/component/state/PolicyComponentState.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.component.state; 2 | 3 | import mod.crend.autohud.component.Component; 4 | import mod.crend.autohud.component.Hud; 5 | import mod.crend.autohud.config.ConfigHandler; 6 | 7 | import java.util.function.Supplier; 8 | 9 | public class PolicyComponentState extends ValueComponentState { 10 | protected Supplier maxValueSupplier; 11 | 12 | public PolicyComponentState(Component component, Supplier newValueSupplier, Supplier maxValueSupplier, boolean updateEveryTick) { 13 | super(component, newValueSupplier, updateEveryTick); 14 | this.maxValueSupplier = maxValueSupplier; 15 | } 16 | public PolicyComponentState(Component component, Supplier newValueSupplier, Supplier maxValueSupplier) { 17 | this(component, newValueSupplier, maxValueSupplier, false); 18 | } 19 | public PolicyComponentState(Component component, Supplier newValueSupplier, Integer maxValueSupplier, boolean updateEveryTick) { 20 | this(component, newValueSupplier, () -> maxValueSupplier, updateEveryTick); 21 | } 22 | public PolicyComponentState(Component component, Supplier newValueSupplier, Integer maxValueSupplier) { 23 | this(component, newValueSupplier, maxValueSupplier, false); 24 | } 25 | 26 | @Override 27 | protected boolean doReveal(Integer newValue) { 28 | return switch (((ConfigHandler.PolicyComponent) component.config).policy()) { 29 | case NotFull -> (newValue < maxValueSupplier.get()); 30 | case Low -> (newValue <= maxValueSupplier.get() / 3); 31 | case Increasing -> (newValue > oldValue); 32 | case Decreasing -> (newValue < oldValue); 33 | case Changing -> (!newValue.equals(oldValue)); 34 | case Disabled -> !Hud.actDynamic(); 35 | case Always -> true; 36 | }; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/component/state/ValueComponentState.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.component.state; 2 | 3 | import mod.crend.autohud.component.Component; 4 | 5 | import java.util.Objects; 6 | import java.util.function.Supplier; 7 | 8 | public class ValueComponentState extends ComponentState { 9 | protected T oldValue; 10 | protected Supplier newValueSupplier; 11 | 12 | public ValueComponentState(Component component, Supplier newValueSupplier, boolean updateEveryTick) { 13 | super(component, updateEveryTick); 14 | this.newValueSupplier = newValueSupplier; 15 | this.oldValue = newValueSupplier.get(); 16 | } 17 | public ValueComponentState(Component component, Supplier newValueSupplier) { 18 | this(component, newValueSupplier, false); 19 | } 20 | 21 | @Override 22 | public void update() { 23 | T newValue = newValueSupplier.get(); 24 | if (doReveal(newValue)) { 25 | this.onUpdateReveal(newValue); 26 | component.revealCombined(); 27 | } 28 | oldValue = newValue; 29 | } 30 | 31 | protected boolean doReveal(T newValue) { 32 | return !component.config.active() || (component.config.onChange() && !Objects.equals(newValue, oldValue)); 33 | } 34 | 35 | protected void onUpdateReveal(T newValue) {} 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/config/EventPolicy.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.config; 2 | 3 | import mod.crend.libbamboo.type.NameableEnum; 4 | import net.minecraft.text.Text; 5 | 6 | public enum EventPolicy implements NameableEnum { 7 | Reveal, 8 | Hide, 9 | Nothing; 10 | 11 | @Override 12 | public Text getDisplayName() { 13 | return switch (this) { 14 | case Reveal -> Text.translatable("autohud.eventPolicy.Reveal"); 15 | case Hide -> Text.translatable("autohud.eventPolicy.Hide"); 16 | case Nothing -> Text.translatable("autohud.eventPolicy.Nothing"); 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/config/RevealPolicy.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.config; 2 | 3 | import mod.crend.libbamboo.type.NameableEnum; 4 | import net.minecraft.text.Text; 5 | 6 | public enum RevealPolicy implements NameableEnum { 7 | Always, 8 | Disabled, 9 | Changing, 10 | Increasing, 11 | Decreasing, 12 | NotFull, 13 | Low; 14 | 15 | @Override 16 | public Text getDisplayName() { 17 | return switch (this) { 18 | case Always -> Text.translatable("autohud.revealPolicy.Always"); 19 | case Disabled -> Text.translatable("autohud.revealPolicy.Disabled"); 20 | case Changing -> Text.translatable("autohud.revealPolicy.Changing"); 21 | case Increasing -> Text.translatable("autohud.revealPolicy.Increasing"); 22 | case Decreasing -> Text.translatable("autohud.revealPolicy.Decreasing"); 23 | case NotFull -> Text.translatable("autohud.revealPolicy.NotFull"); 24 | case Low -> Text.translatable("autohud.revealPolicy.Low"); 25 | }; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/config/RevealType.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.config; 2 | 3 | import mod.crend.libbamboo.type.NameableEnum; 4 | import net.minecraft.text.Text; 5 | 6 | public enum RevealType implements NameableEnum { 7 | Individual, 8 | Stacked, 9 | Grouped, 10 | HideCombined, 11 | Combined; 12 | 13 | @Override 14 | public Text getDisplayName() { 15 | return switch (this) { 16 | case Individual -> Text.translatable("autohud.revealType.Individual"); 17 | case Stacked -> Text.translatable("autohud.revealType.Stacked"); 18 | case Grouped -> Text.translatable("autohud.revealType.Grouped"); 19 | case HideCombined -> Text.translatable("autohud.revealType.HideCombined"); 20 | case Combined -> Text.translatable("autohud.revealType.Combined"); 21 | }; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/config/ScrollDirection.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.config; 2 | 3 | import mod.crend.libbamboo.type.NameableEnum; 4 | import net.minecraft.text.Text; 5 | 6 | public enum ScrollDirection implements NameableEnum { 7 | Up, 8 | Down, 9 | Left, 10 | Right; 11 | 12 | @Override 13 | public Text getDisplayName() { 14 | return switch (this) { 15 | case Up -> Text.translatable("autohud.scrollDirection.Up"); 16 | case Down -> Text.translatable("autohud.scrollDirection.Down"); 17 | case Left -> Text.translatable("autohud.scrollDirection.Left"); 18 | case Right -> Text.translatable("autohud.scrollDirection.Right"); 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/mixin/ClientPlayNetworkHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.mixin; 2 | 3 | import mod.crend.autohud.component.ScoreboardHelper; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.network.ClientPlayNetworkHandler; 6 | import net.minecraft.network.packet.s2c.play.TeamS2CPacket; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Mixin(ClientPlayNetworkHandler.class) 13 | public class ClientPlayNetworkHandlerMixin { 14 | @Inject(method="onTeam", at=@At(value="INVOKE", target = "java/util/Optional.ifPresent(Ljava/util/function/Consumer;)V", shift=At.Shift.AFTER)) 15 | private void autoHud$onTeamUpdate(TeamS2CPacket packet, CallbackInfo ci) { 16 | if (MinecraftClient.getInstance().world == null) { 17 | return; 18 | } 19 | 20 | // JuggleStruggle: The reason why both getTeamOperation cannot be REMOVE is because we already perform team removal checks. 21 | // As for team being present, it... just means that it is required to know that it has been updated. 22 | if (packet.getTeamOperation() == TeamS2CPacket.Operation.REMOVE) { 23 | // JuggleStruggle: We need to be sure that we are only calling the rest of the method if, and only if, there's 24 | // no player listing going on as that takes precedence over team addition/removal to avoid multiple calls when 25 | // not needed. Seems to me that "add" from team operation will never get called since it uses player list operation as well. 26 | if (packet.getPlayerListOperation() == null) { 27 | ScoreboardHelper.onTeamRemoved(MinecraftClient.getInstance().world.getScoreboard().getTeam(packet.getTeamName())); 28 | } 29 | } else { 30 | if (packet.getTeam().isPresent()) { 31 | ScoreboardHelper.onTeamUpdated(MinecraftClient.getInstance().world.getScoreboard().getTeam(packet.getTeamName())); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/mixin/ScoreboardMixin.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.mixin; 2 | 3 | import mod.crend.autohud.component.ScoreboardHelper; 4 | import net.minecraft.scoreboard.*; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 10 | 11 | @Mixin(Scoreboard.class) 12 | public class ScoreboardMixin { 13 | @Inject(method="updateExistingObjective", at=@At("HEAD")) 14 | public void autoHud$onObjectiveUpdate(ScoreboardObjective objective, CallbackInfo ci) { 15 | ScoreboardHelper.onObjectiveUpdate(objective); 16 | } 17 | 18 | //? if <1.20.3 { 19 | @Inject(method="updateScore", at=@At("HEAD")) 20 | public void autoHud$onPlayerScoreUpdate(ScoreboardPlayerScore score, CallbackInfo ci) { 21 | ScoreboardHelper.onPlayerScoreUpdate(score); 22 | } 23 | 24 | @Inject(method="updatePlayerScore(Ljava/lang/String;)V", at=@At("HEAD")) 25 | public void autoHud$onPlayerScoreReset(String playerName, CallbackInfo ci) { 26 | ScoreboardHelper.onPlayerScoreRemove(playerName); 27 | } 28 | 29 | @Inject(method="updatePlayerScore(Ljava/lang/String;Lnet/minecraft/scoreboard/ScoreboardObjective;)V", at=@At("HEAD")) 30 | public void autoHud$onPlayerScoreReset(String playerName, ScoreboardObjective objective, CallbackInfo ci) { 31 | ScoreboardHelper.onPlayerScoreRemove(playerName, objective); 32 | } 33 | 34 | @Inject(method="addPlayerToTeam", at=@At("RETURN")) 35 | public void autoHud$onPlayerAddedToTeam(String playerName, Team teamAddedTo, CallbackInfoReturnable ci) { 36 | ScoreboardHelper.onPlayerAddedToTeam(playerName, teamAddedTo); 37 | } 38 | @Inject(method="removePlayerFromTeam", at=@At("TAIL")) 39 | public void autoHud$onPlayerRemovedFromTeam(String playerName, Team teamRemovedFrom, CallbackInfo ci) { 40 | ScoreboardHelper.onPlayerRemovedFromTeam(playerName, teamRemovedFrom); 41 | } 42 | 43 | //?} else { 44 | 45 | /*@Inject(method="updateScore", at=@At("HEAD")) 46 | public void autoHud$onPlayerScoreUpdate(ScoreHolder scoreHolder, ScoreboardObjective objective, ScoreboardScore score, CallbackInfo ci) { 47 | ScoreboardHelper.onPlayerScoreUpdate(scoreHolder, objective, score); 48 | } 49 | 50 | @Inject(method="onScoreRemoved", at=@At("HEAD")) 51 | public void autoHud$onPlayerScoreRemoved(ScoreHolder scoreHolder, ScoreboardObjective objective, CallbackInfo ci) { 52 | ScoreboardHelper.onPlayerScoreRemove(scoreHolder.getNameForScoreboard(), objective); 53 | } 54 | 55 | @Inject(method="onScoreHolderRemoved", at=@At("HEAD")) 56 | public void autoHud$onPlayerRemoved(ScoreHolder scoreHolder, CallbackInfo ci) { 57 | ScoreboardHelper.onPlayerScoreRemove(scoreHolder.getNameForScoreboard()); 58 | } 59 | 60 | @Inject(method="resetScore", at=@At("HEAD")) 61 | public void autoHud$onPlayerScoreReset(ScoreHolder scoreHolder, ScoreboardObjective objective, CallbackInfo ci) { 62 | ScoreboardHelper.onPlayerScoreRemove(scoreHolder.getNameForScoreboard(), objective); 63 | } 64 | 65 | @Inject(method="addScoreHolderToTeam", at=@At("RETURN")) 66 | public void autoHud$onPlayerAddedToTeam(String playerName, Team teamAddedTo, CallbackInfoReturnable ci) { 67 | ScoreboardHelper.onPlayerAddedToTeam(playerName, teamAddedTo); 68 | } 69 | @Inject(method="removeScoreHolderFromTeam", at=@At("TAIL")) 70 | public void autoHud$onPlayerRemovedFromTeam(String playerName, Team teamRemovedFrom, CallbackInfo ci) { 71 | ScoreboardHelper.onPlayerRemovedFromTeam(playerName, teamRemovedFrom); 72 | } 73 | *///?} 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/mixin/TeamMixinAccessor.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.mixin; 2 | 3 | import mod.crend.autohud.component.state.ScoreboardComponentState; 4 | import net.minecraft.scoreboard.Team; 5 | import net.minecraft.text.Text; 6 | import net.minecraft.util.Formatting; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.gen.Accessor; 9 | 10 | /** 11 | * The only reason why this mixin was created was to avoid calling the scoreboard 12 | * instance since that is always null when attempting to create a cache team, which 13 | * is primarily used in {@link ScoreboardComponentState}. 14 | */ 15 | @Mixin(Team.class) 16 | public interface TeamMixinAccessor { 17 | @Accessor("displayName") 18 | void autohud$setDisplayName(Text displayName); 19 | @Accessor("color") 20 | void autohud$setColor(Formatting color); 21 | 22 | /** 23 | * Please do not use this method directly unless you're absolutely sure that the 24 | * text being passed in the {@code prefix} parameter isn't {@code null}. 25 | * 26 | * @param prefix sets the prefix for the team 27 | */ 28 | @Accessor("prefix") 29 | void autohud$setPrefix(Text prefix); 30 | 31 | /** 32 | * Please do not use this method directly unless you're absolutely sure that the 33 | * text being passed in the {@code suffix} parameter isn't {@code null}. 34 | * 35 | * @param suffix sets the suffix for the team 36 | */ 37 | @Accessor("suffix") 38 | void autohud$setSuffix(Text suffix); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/render/AutoHudRenderLayer.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.render; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import mod.crend.autohud.AutoHud; 5 | import mod.crend.autohud.component.Component; 6 | import net.minecraft.client.gui.DrawContext; 7 | 8 | public interface AutoHudRenderLayer { 9 | AutoHudRenderLayer DO_MOVE = new DoMove(); 10 | AutoHudRenderLayer DO_FADE = new DoFade(); 11 | AutoHudRenderLayer DO_REVERSE_TRANSLATION = new DoReverseTranslation(); 12 | AutoHudRenderLayer DO_GLOBAL_TRANSLATION = new DoGlobalTranslation(); 13 | 14 | AutoHudRenderLayer MOVE_MODE = new MoveMode(); 15 | AutoHudRenderLayer FADE_MODE = new FadeMode(); 16 | AutoHudRenderLayer FADE_MODE_WITH_REVERSE_TRANSLATION = new FadeModeWithReverseTranslation(); 17 | 18 | default boolean shouldApply() { return true; } 19 | 20 | void doPreRender(Component component, DrawContext context, float minAlpha); 21 | default void preRender(Component component, DrawContext context, float minAlpha) { 22 | if (shouldApply()) doPreRender(component, context, minAlpha); 23 | } 24 | default void preRender(Component component, DrawContext context) { 25 | preRender(component, context, (float) component.config.maximumFade()); 26 | } 27 | 28 | void doPostRender(Component component, DrawContext context); 29 | default void postRender(Component component, DrawContext context) { 30 | if (shouldApply()) doPostRender(component, context); 31 | } 32 | 33 | default void wrap(Component component, DrawContext context, Runnable original) { 34 | wrap(component, context, (float) component.config.maximumFade(), original); 35 | } 36 | default void wrap(Component component, DrawContext context, float minAlpha, Runnable original) { 37 | preRender(component, context, minAlpha); 38 | original.run(); 39 | postRender(component, context); 40 | } 41 | 42 | class DoMove implements AutoHudRenderLayer { 43 | @Override 44 | public boolean shouldApply() { 45 | return (AutoHud.config.animationMove() || !AutoHud.config.animationFade()); 46 | } 47 | 48 | @Override 49 | public void doPreRender(Component component, DrawContext context, float ignored) { 50 | AutoHudRenderer.active.add(component); 51 | context.getMatrices().push(); 52 | if (component.isHidden()) { 53 | context.getMatrices().translate(component.getOffsetX(AutoHudRenderer.tickDelta), component.getOffsetY(AutoHudRenderer.tickDelta), 0); 54 | } 55 | } 56 | 57 | @Override 58 | public void doPostRender(Component component, DrawContext context) { 59 | AutoHudRenderer.active.remove(component); 60 | context.getMatrices().pop(); 61 | } 62 | } 63 | 64 | class DoFade implements AutoHudRenderLayer { 65 | @Override 66 | public boolean shouldApply() { 67 | return AutoHud.config.animationFade(); 68 | } 69 | 70 | @Override 71 | public void doPreRender(Component component, DrawContext context, float minAlpha) { 72 | AutoHudRenderer.alpha = Math.max(component.getAlpha(AutoHudRenderer.tickDelta), minAlpha); 73 | RenderSystem.enableBlend(); 74 | float[] color = RenderSystem.getShaderColor(); 75 | RenderSystem.setShaderColor(color[0], color[1], color[2], color[3] * AutoHudRenderer.alpha); 76 | } 77 | 78 | @Override 79 | public void doPostRender(Component component, DrawContext context) { 80 | //? if >=1.21.2 81 | /*context.draw();*/ 82 | AutoHudRenderer.alpha = 1.0f; 83 | RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, AutoHudRenderer.alpha); 84 | } 85 | } 86 | 87 | class DoReverseTranslation implements AutoHudRenderLayer { 88 | @Override 89 | public boolean shouldApply() { 90 | return AutoHud.config.animationMove(); 91 | } 92 | 93 | @Override 94 | public void doPreRender(Component component, DrawContext context, float minAlpha) { 95 | context.getMatrices().push(); 96 | if (component.isHidden()) { 97 | context.getMatrices().translate(-component.getOffsetX(AutoHudRenderer.tickDelta), -component.getOffsetY(AutoHudRenderer.tickDelta), 0); 98 | } 99 | } 100 | 101 | @Override 102 | public void doPostRender(Component component, DrawContext context) { 103 | context.getMatrices().pop(); 104 | } 105 | } 106 | 107 | class DoGlobalTranslation implements AutoHudRenderLayer { 108 | @Override 109 | public boolean shouldApply() { 110 | return (AutoHudRenderer.globalOffsetX != 0 || AutoHudRenderer.globalOffsetY != 0); 111 | } 112 | 113 | @Override 114 | public void doPreRender(Component component, DrawContext context, float minAlpha) { 115 | context.getMatrices().push(); 116 | context.getMatrices().translate(AutoHudRenderer.globalOffsetX, AutoHudRenderer.globalOffsetY, 0); 117 | } 118 | 119 | @Override 120 | public void doPostRender(Component component, DrawContext context) { 121 | context.getMatrices().pop(); 122 | } 123 | } 124 | 125 | 126 | class MoveMode implements AutoHudRenderLayer { 127 | @Override 128 | public void doPreRender(Component component, DrawContext context, float minAlpha) { 129 | DO_FADE.preRender(component, context, minAlpha); 130 | DO_MOVE.preRender(component, context, minAlpha); 131 | } 132 | 133 | @Override 134 | public void doPostRender(Component component, DrawContext context) { 135 | DO_MOVE.postRender(component, context); 136 | DO_FADE.postRender(component, context); 137 | } 138 | } 139 | 140 | class FadeMode implements AutoHudRenderLayer { 141 | @Override 142 | public void doPreRender(Component component, DrawContext context, float minAlpha) { 143 | DO_FADE.preRender(component, context, minAlpha); 144 | } 145 | 146 | @Override 147 | public void doPostRender(Component component, DrawContext context) { 148 | DO_FADE.postRender(component, context); 149 | } 150 | } 151 | 152 | class FadeModeWithReverseTranslation implements AutoHudRenderLayer { 153 | @Override 154 | public void doPreRender(Component component, DrawContext context, float minAlpha) { 155 | DO_FADE.preRender(component, context, minAlpha); 156 | DO_REVERSE_TRANSLATION.preRender(component, context, minAlpha); 157 | DO_GLOBAL_TRANSLATION.preRender(component, context, minAlpha); 158 | } 159 | 160 | @Override 161 | public void doPostRender(Component component, DrawContext context) { 162 | DO_GLOBAL_TRANSLATION.postRender(component, context); 163 | DO_REVERSE_TRANSLATION.postRender(component, context); 164 | DO_FADE.postRender(component, context); 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/render/AutoHudRenderer.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.render; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import mod.crend.autohud.AutoHud; 5 | import mod.crend.autohud.component.Component; 6 | import mod.crend.autohud.component.Components; 7 | import net.minecraft.client.gui.DrawContext; 8 | //? if >1.20.1 9 | /*import net.minecraft.client.render.RenderTickCounter;*/ 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public class AutoHudRenderer { 15 | public static boolean inRender; 16 | public static float tickDelta = 0.0f; 17 | public static float alpha = 1.0f; 18 | public static float globalOffsetX = 0; 19 | public static float globalOffsetY = 0; 20 | 21 | 22 | public static boolean shouldRenderHotbarItems() { 23 | // Render items when we're not doing anything with the hotbar 24 | return !AutoHud.targetHotbar 25 | // Render items when they're not fully hidden (in other words, visible in some way) 26 | || !Components.Hotbar.fullyHidden() 27 | // If we are in fade mode, only render items if they're not fully transparent. 28 | || (AutoHud.config.animationFade() && AutoHud.config.getHotbarItemsMaximumFade() > 0.0f) 29 | // If we are neither in fade nor move mode, skip rendering if it's hidden. 30 | // If we are in move mode, the items may still be visible in the "hidden" state! 31 | || (!AutoHud.config.animationFade() && AutoHud.config.animationMove()); 32 | } 33 | 34 | /** 35 | * Modifies the given color to set its alpha value 36 | */ 37 | public static int modifyArgb(int argb) { 38 | int oldAlpha = argb >> 24; 39 | if ((oldAlpha & 0xFC) == 0) { 40 | oldAlpha = 0xFF; 41 | } 42 | return Math.round(alpha * oldAlpha) << 24 | (argb & 0xFFFFFF); 43 | } 44 | public static int getArgb() { 45 | return Math.round(alpha * 0xFF) << 24; 46 | } 47 | 48 | public static void injectTransparency() { 49 | if (inRender) { 50 | RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, alpha); 51 | } 52 | } 53 | 54 | public static List active = new ArrayList<>(); 55 | 56 | public static void startRender(DrawContext context, /*? if <1.21 {*/float/*?} else {*//*RenderTickCounter*//*?}*/ renderTickCounter) { 57 | inRender = true; 58 | tickDelta = renderTickCounter/*? if >=1.21 {*//*.getTickDelta(true)*//*?}*/; 59 | active.clear(); 60 | } 61 | 62 | public static void renderChatMessageIndicator(DrawContext context, /*? if <1.21 {*/float/*?} else {*//*RenderTickCounter*//*?}*/ ignored) { 63 | ComponentRenderer.CHAT_MESSAGE_INDICATOR.wrap(context, ChatMessageIndicator::render); 64 | } 65 | 66 | public static void endRender() { 67 | for (Component component : active) { 68 | System.err.println("Not cleaned up: " + component.identifier); 69 | } 70 | inRender = false; 71 | RenderSystem.setShaderColor(1f, 1f, 1f, 1f); 72 | RenderSystem.defaultBlendFunc(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/mod/crend/autohud/render/ChatMessageIndicator.java: -------------------------------------------------------------------------------- 1 | package mod.crend.autohud.render; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import net.minecraft.client.gui.DrawContext; 5 | import net.minecraft.client.toast.TutorialToast; 6 | 7 | public class ChatMessageIndicator { 8 | public static void render(DrawContext context) { 9 | int x = 10; 10 | int y = MinecraftClient.getInstance().getWindow().getScaledHeight() - 30; 11 | TutorialToast.Type.SOCIAL_INTERACTIONS.drawIcon(context, x, y); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/architectury.common.json: -------------------------------------------------------------------------------- 1 | { 2 | "accessWidener": "autohud.accesswidener" 3 | } -------------------------------------------------------------------------------- /src/main/resources/assets/autohud/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "autohud.title": "Auto HUD", 3 | "autohud.category.general": "自动 HUD", 4 | "autohud.category.components": "组件", 5 | "autohud.category.advanced": "Advanced", 6 | 7 | "autohud.option.dynamicOnLoad": "在游戏加载时启用动态 HUD", 8 | "autohud.option.ticksRevealed": "显示时间 (ticks)", 9 | "autohud.option.animationMove": "动画类型:移动", 10 | "autohud.option.animationFade": "动画类型:渐变", 11 | "autohud.option.animationSpeed": "动画速度", 12 | "autohud.group.animationSpeeds": "Special animation speeds (set to 0 to use above value)", 13 | "autohud.option.animationSpeeds.moveIn": "Moving in", 14 | "autohud.option.animationSpeeds.moveOut": "Moving out", 15 | "autohud.option.animationSpeeds.fadeIn": "Fading in", 16 | "autohud.option.animationSpeeds.fadeOut": "Fading out", 17 | "autohud.option.revealType": "以如下方式处理组件", 18 | "autohud.option.revealType.description": "独立:独立移动所有部件\n叠加:只有在不被其他可见组件阻挡的情况下才会隐藏组件\n分组:将所有逻辑上分组的组件(快捷栏区)移到一起\n隐藏合并:将显示的组件一起隐藏\n合并:将所有组件一起移动", 19 | 20 | "autohud.group.statusBars": "Status Bars", 21 | "autohud.group.health": "Health", 22 | "autohud.group.armor": "Armor", 23 | "autohud.group.hunger": "Hunger", 24 | "autohud.group.air": "Air", 25 | "autohud.group.experience": "Experience", 26 | "autohud.group.mountJumpBar": "Mount Jump Bar", 27 | "autohud.group.mountHealth": "Mount Health", 28 | "autohud.option.health.policy": "在如下条件下显示生命值", 29 | "autohud.option.hunger.policy": "在如下条件下显示饥饿值", 30 | "autohud.option.revealHungerWhenHoldingFoodItem": "Reveal hunger bar when holding a food item in your hand and the player is not at full hunger.", 31 | "autohud.option.air.policy": "在如下条件下显示氧气值", 32 | "autohud.option.armor.policy": "在如下条件下显示盔甲", 33 | "autohud.option.experienceBar.active": "隐藏经验栏", 34 | "autohud.option.experienceBar.onChange": "在经验改变时显示", 35 | "autohud.option.mountJumpBar.active": "不蓄力时隐藏坐骑跳跃栏", 36 | "autohud.option.mountJumpBar.onChange": "蓄力时显示坐骑跳跃栏", 37 | "autohud.option.mountHealth.policy": "在如下条件下显示坐骑健康状况", 38 | "autohud.group.hotbar": "快捷栏", 39 | "autohud.option.hotbar.hotbar.active": "隐藏", 40 | "autohud.option.hotbar.hotbar.onChange": "在活动栏的内容变化时显示", 41 | "autohud.option.hotbar.onSlotChange": "在切换选择存储槽时显示", 42 | "autohud.option.hotbar.onLowDurability": "在低耐久时显示", 43 | "autohud.option.hotbar.durabilityPercentage": "低于显示的百分比", 44 | "autohud.option.hotbar.durabilityTotal": "低于显示的耐久", 45 | "autohud.option.hotbar.maximumFadeHotbarItems": "Fade-out limit for hotbar items", 46 | "autohud.option.hotbar.hideTooltip": "Always hide the selected item tooltip", 47 | "autohud.group.statusEffects": "Status effects", 48 | "autohud.option.statusEffects.active": "隐藏状态效果", 49 | "autohud.option.statusEffects.onChange": "显示当前的状态效果", 50 | "autohud.option.hidePersistentStatusEffects": "隐藏持续的状态效果", 51 | "autohud.option.hidePersistentStatusEffects.description": "对于不变的状态效果总是隐藏状态效果符号,例如戴着海龟壳时。", 52 | "autohud.option.showHiddenStatusEffects": "Show hidden", 53 | "autohud.option.showHiddenStatusEffects.description": "By default, status effects without particles only show in the inventory screen. Toggle this on to also show them in the top right.", 54 | "autohud.option.statusEffectTimer": "在其图标上显示状态效果的剩余时间", 55 | "autohud.option.statusEffectTimer.description": "Show remaining time of status effects on their icon", 56 | "autohud.group.scoreboard": "计分板", 57 | "autohud.option.scoreboard.scoreboard.active": "隐藏", 58 | "autohud.option.scoreboard.scoreboard.onChange": "在标题改变时显示", 59 | "autohud.option.scoreboard.onScoreChange": "在分数改变时显示", 60 | "autohud.option.scoreboard.onTeamChange": "在队伍改变时显示", 61 | "autohud.option.scoreboard.onTeamChange.description": "如果队伍是玩家分数的一部分,则更新它;否则,任何队伍都可以更新,但仍然没有提供实际的可见性。", 62 | "autohud.option.defaultValues.speedMultiplier": "默认的速度倍率", 63 | "autohud.option.defaultValues.distance": "默认距离", 64 | "autohud.option.defaultValues.maximumFade": "默认的淡出限制", 65 | "autohud.option.advanced.label": "Here you can manually adjust values for each component. This might be necessary if some other mod moves components around.\nSet numeric values to -1 to inherit from default.", 66 | "autohud.option.advanced.direction": "方向", 67 | "autohud.option.advanced.speedMultiplier": "速度倍数", 68 | "autohud.option.advanced.distance": "距离", 69 | "autohud.option.advanced.maximumFade": "淡出限制", 70 | 71 | "autohud.scrollDirection.Up": "上", 72 | "autohud.scrollDirection.Down": "下", 73 | "autohud.scrollDirection.Left": "左", 74 | "autohud.scrollDirection.Right": "右", 75 | "autohud.revealType.Individual": "独立", 76 | "autohud.revealType.Stacked": "叠加", 77 | "autohud.revealType.Grouped": "分组", 78 | "autohud.revealType.HideCombined": "隐藏合并", 79 | "autohud.revealType.Combined": "合并", 80 | "autohud.revealPolicy.Always": "总是", 81 | "autohud.revealPolicy.Disabled": "关闭", 82 | "autohud.revealPolicy.Changing": "变化", 83 | "autohud.revealPolicy.Increasing": "增加", 84 | "autohud.revealPolicy.Decreasing": "减少", 85 | "autohud.revealPolicy.NotFull": "未满", 86 | "autohud.revealPolicy.Low": "低", 87 | 88 | "key.category.autohud": "自动 HUD", 89 | "key.autohud.toggle-hud": "切换动态 HUD", 90 | "key.autohud.peek-hud": "按住时切换 HUD", 91 | 92 | "modmenu.summaryTranslation.autohud": "动态地隐藏界面元素", 93 | "modmenu.descriptionTranslation.autohud": "动态 HUD,在不需要时隐藏界面元素。", 94 | "autohud.requireYaclForConfigScreen": "To configure AutoHUD through ModMenu, please install YetAnotherConfigLib!" 95 | } 96 | -------------------------------------------------------------------------------- /src/main/resources/autohud-common-compat.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "mod.crend.autohud.compat.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "client": [ 7 | ], 8 | "injectors": { 9 | "defaultRequire": 0 10 | }, 11 | "plugin": "mod.crend.autohud.AutoHudCompatMixinPlugin" 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/autohud-common.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "mod.crend.autohud.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "client": [ 7 | "ClientPlayNetworkHandlerMixin", 8 | "ScoreboardMixin", 9 | "TeamMixinAccessor" 10 | ], 11 | "injectors": { 12 | "defaultRequire": 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/autohud.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v2 named -------------------------------------------------------------------------------- /src/main/resources/autohud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Crendgrim/AutoHUD/e6fd1ea95c3f74646c5c73d447d89f79eeef7c95/src/main/resources/autohud.png -------------------------------------------------------------------------------- /stonecutter.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("dev.kikugie.stonecutter") 3 | id("dev.architectury.loom") version "1.7-SNAPSHOT" apply false 4 | id("architectury-plugin") version "3.4-SNAPSHOT" apply false 5 | id("com.github.johnrengelman.shadow") version "8.1.1" apply false 6 | id("me.modmuss50.mod-publish-plugin") version "0.8.1" apply false 7 | } 8 | stonecutter active "1.20.1" /* [SC] DO NOT EDIT */ 9 | stonecutter.automaticPlatformConstants = true 10 | 11 | // Builds every version into `build/libs/{mod.version}/{loader}` 12 | stonecutter registerChiseled tasks.register("chiseledBuild", stonecutter.chiseled) { 13 | group = "project" 14 | ofTask("buildAndCollect") 15 | } 16 | 17 | // Builds loader-specific versions into `build/libs/{mod.version}/{loader}` 18 | for (it in stonecutter.tree.branches) { 19 | if (it.id.isEmpty()) continue 20 | val loader = it.id.upperCaseFirst() 21 | stonecutter registerChiseled tasks.register("chiseledBuild$loader", stonecutter.chiseled) { 22 | group = "project" 23 | versions { branch, _ -> branch == it.id } 24 | ofTask("buildAndCollect") 25 | } 26 | } 27 | 28 | stonecutter registerChiseled tasks.register("chiseledPublishToMavenLocal", stonecutter.chiseled) { 29 | group = "project" 30 | ofTask("publishToMavenLocal") 31 | } 32 | 33 | stonecutter registerChiseled tasks.register("chiseledPublish", stonecutter.chiseled) { 34 | group = "project" 35 | ofTask("publishMods") 36 | } 37 | 38 | // Runs active versions for each loader 39 | for (it in stonecutter.tree.nodes) { 40 | if (it.metadata != stonecutter.current || it.branch.id.isEmpty()) continue 41 | val types = listOf("Client", "Server") 42 | val loader = it.branch.id.upperCaseFirst() 43 | for (type in types) it.tasks.register("runActive$type$loader") { 44 | group = "project" 45 | dependsOn("run$type") 46 | } 47 | } 48 | 49 | allprojects { 50 | repositories { 51 | mavenLocal() 52 | maven("https://maven.isxander.dev/releases") 53 | maven("https://maven.terraformersmc.com/") 54 | maven { 55 | name = "Fuzs Mod Resources" 56 | setUrl("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") 57 | } 58 | 59 | // AppleSkin 60 | maven("https://maven.ryanliptak.com/") 61 | 62 | exclusiveContent { 63 | forRepository { 64 | maven { 65 | name = "Modrinth" 66 | setUrl("https://api.modrinth.com/maven") 67 | } 68 | } 69 | filter { 70 | includeGroup("maven.modrinth") 71 | } 72 | } 73 | 74 | exclusiveContent { 75 | forRepository { 76 | maven { 77 | setUrl("https://cursemaven.com") 78 | } 79 | } 80 | filter { 81 | includeGroup("curse.maven") 82 | } 83 | } 84 | 85 | } 86 | } 87 | 88 | stonecutter parameters { 89 | listOf( 90 | "appleskin", 91 | "armorchroma", 92 | "coldsweat", 93 | "dehydration", 94 | "detailab", 95 | "environmentz", 96 | "farmers_delight_refabricated", 97 | "hotbarslotcycling", 98 | "legendary_survival_overhaul", 99 | "onebar", 100 | "quark", 101 | "raised", 102 | "statuseffectbars" 103 | ).map { modName -> 104 | modName to 105 | if (node == null) 106 | // :neoforge:1.20.1 is not defined, so we would not be able to switch back to 1.20.1 without 107 | // defining any constants used in the neoforge source set. Just set them all to unsupported. 108 | "[UNSUPPORTED]" 109 | else if (node!!.sibling("") == null || node!!.prop("loom.platform") == null) 110 | node!!.mod.dep(modName) 111 | else 112 | // For e.g. :fabric:1.20.1, use the property of :1.20.1 113 | node!!.sibling("")!!.mod.dep(node!!.prop("loom.platform")!!, modName) 114 | }.forEach { (mod, version) -> 115 | val modIsPresent = !version.startsWith("["); 116 | const(mod, modIsPresent) 117 | dependency(mod, if (modIsPresent) version else "0") 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /versions/1.20.1/gradle.properties: -------------------------------------------------------------------------------- 1 | mod.mc_dep_fabric=>=1.20 <=1.20.1 2 | mod.mc_dep_forgelike=[1.20, 1.20.1] 3 | mod.mc_title=1.20.1 4 | mod.mc_targets=1.20 1.20.1 5 | 6 | deps.forge_loader=47.3.0 7 | deps.neoforge_loader=[UNSUPPORTED] 8 | 9 | deps.yarn_build=10 10 | 11 | deps.fabric_api=0.92.2+1.20.1 12 | deps.libbamboo=2.4+1.20.1 13 | deps.yacl=3.6.1+1.20.1 14 | deps.modmenu=7.2.2 15 | 16 | deps.appleskin=2.5.1 17 | deps.appleskin_artifact=mc1.20 18 | deps.armorchroma=1.2.6 19 | deps.coldsweat=2.3.8 20 | deps.coldsweat_artifact=AjaHvVAp 21 | deps.dehydration=1.3.6+1.20.1 22 | deps.detailab=2.6.3+1.20.1-fabric 23 | deps.farmers_delight_refabricated=1.20.1-2.2.0 24 | deps.environmentz=2.0.8+1.20.1 25 | deps.hotbarslotcycling=[UNSUPPORTED] 26 | deps.legendary_survival_overhaul=5825918 27 | deps.onebar=4.0.0 28 | deps.quark=1.20.1-4.0-460 29 | deps.raised=4.0.1 30 | deps.raised_artifact=1.20.1 31 | deps.statuseffectbars=1.0.3 -------------------------------------------------------------------------------- /versions/1.20.4/gradle.properties: -------------------------------------------------------------------------------- 1 | mod.mc_dep_fabric=>=1.20.3 <=1.20.4 2 | mod.mc_dep_forgelike=[1.20.3, 1.20.4] 3 | mod.mc_title=1.20.4 4 | mod.mc_targets=1.20.3 1.20.4 5 | 6 | deps.forge_loader=49.1.0 7 | deps.neoforge_loader=20.4.237 8 | deps.neoforge_patch=[UNSUPPORTED] 9 | 10 | deps.yarn_build=3 11 | 12 | deps.fabric_api=0.97.2+1.20.4 13 | deps.libbamboo=2.4+1.20.4 14 | deps.yacl=3.6.1+1.20.4 15 | deps.modmenu=9.0.0 16 | 17 | deps.appleskin=2.5.1 18 | deps.appleskin_artifact=mc1.20.3 19 | deps.armorchroma=1.2.6 20 | deps.coldsweat=[UNSUPPORTED] 21 | deps.coldsweat_artifact=AjaHvVAp 22 | deps.dehydration=[UNSUPPORTED] 23 | deps.detailab=2.6.3+1.20.4-fabric 24 | deps.farmers_delight_refabricated=[UNSUPPORTED] 25 | deps.environmentz=[UNSUPPORTED] 26 | deps.hotbarslotcycling=[UNSUPPORTED] 27 | deps.legendary_survival_overhaul=[UNSUPPORTED] 28 | deps.onebar=4.1.0 29 | deps.quark=[UNSUPPORTED] 30 | deps.raised=4.0.1 31 | deps.raised_artifact=1.20.4 32 | deps.statuseffectbars=1.0.4 33 | -------------------------------------------------------------------------------- /versions/1.20.6/gradle.properties: -------------------------------------------------------------------------------- 1 | mod.mc_dep_fabric=>=1.20.5 <=1.20.6 2 | mod.mc_dep_forgelike=[1.20.5, 1.20.6] 3 | mod.mc_title=1.20.6 4 | mod.mc_targets=1.20.5 1.20.6 5 | 6 | deps.forge_loader=50.1.0 7 | deps.neoforge_loader=20.6.121 8 | deps.neoforge_patch=1.20.6+build.4 9 | 10 | deps.yarn_build=3 11 | 12 | deps.fabric_api=0.100.8+1.20.6 13 | deps.libbamboo=2.4+1.20.6 14 | deps.yacl=3.6.1+1.20.6 15 | deps.modmenu=10.0.0 16 | 17 | deps.appleskin=3.0.5 18 | deps.appleskin_artifact=mc1.20.5 19 | deps.armorchroma=1.2.7 20 | deps.coldsweat=[UNSUPPORTED] 21 | deps.coldsweat_artifact=[UNSUPPORTED] 22 | deps.dehydration=[UNSUPPORTED] 23 | deps.detailab=14.1-beta.2+1.20.6 24 | deps.environmentz=[UNSUPPORTED] 25 | deps.farmers_delight_refabricated=[UNSUPPORTED] 26 | deps.hotbarslotcycling=[UNSUPPORTED] 27 | deps.legendary_survival_overhaul=[UNSUPPORTED] 28 | deps.onebar=4.1.1 29 | deps.quark=[UNSUPPORTED] 30 | deps.raised=4.0.1 31 | deps.raised_artifact=1.20.6 32 | deps.statuseffectbars=1.0.5 33 | -------------------------------------------------------------------------------- /versions/1.21.1/gradle.properties: -------------------------------------------------------------------------------- 1 | mod.mc_dep_fabric=>=1.21 <=1.21.1 2 | mod.mc_dep_forgelike=[1.21, 1.21.1] 3 | mod.mc_title=1.21.1 4 | mod.mc_targets=1.21 1.21.1 5 | 6 | deps.forge_loader=52.0.28 7 | deps.neoforge_loader=21.1.66 8 | deps.neoforge_patch=1.21+build.4 9 | 10 | deps.yarn_build=3 11 | 12 | deps.fabric_api=0.106.0+1.21.1 13 | deps.libbamboo=2.4+1.21.1 14 | deps.yacl=3.6.1+1.21 15 | deps.modmenu=11.0.3 16 | 17 | deps.appleskin=3.0.5 18 | deps.appleskin_artifact=mc1.21 19 | deps.armorchroma=1.2.8 20 | deps.coldsweat=2.3.8 21 | deps.coldsweat_artifact=2.3.8 22 | deps.dehydration=1.3.7+1.21.1 23 | deps.detailab=2.6.3+1.21.1-fabric 24 | deps.environmentz=2.0.9+1.21.1 25 | deps.farmers_delight_refabricated=1.21.1-2.2.2 26 | deps.hotbarslotcycling=21.1.1 27 | deps.hotbarslotcycling_forge=[UNSUPPORTED] 28 | deps.legendary_survival_overhaul=[UNSUPPORTED] 29 | deps.onebar=4.1.2 30 | deps.quark=[UNSUPPORTED] 31 | deps.raised=4.0.1 32 | deps.raised_artifact=1.21.1 33 | deps.statuseffectbars=1.0.6 34 | -------------------------------------------------------------------------------- /versions/1.21.3/gradle.properties: -------------------------------------------------------------------------------- 1 | mod.mc_dep_fabric=>=1.21.2 2 | mod.mc_dep_forgelike=[1.21.2,] 3 | mod.mc_title=1.21.3 4 | mod.mc_targets=1.21.3 5 | 6 | deps.forge_loader=53.0.25 7 | deps.neoforge_loader=21.3.7-beta 8 | deps.neoforge_patch=1.21+build.4 9 | 10 | deps.yarn_build=2 11 | 12 | deps.fabric_api=0.107.0+1.21.3 13 | deps.libbamboo=2.4+1.21.3 14 | deps.yacl=3.6.1+1.21.2 15 | deps.modmenu=12.0.0-beta.1 16 | 17 | deps.appleskin=3.0.6 18 | deps.appleskin_artifact=mc1.21.3 19 | deps.armorchroma=[UNSUPPORTED] 20 | deps.coldsweat=[UNSUPPORTED] 21 | deps.coldsweat_artifact=[UNSUPPORTED] 22 | deps.dehydration=[UNSUPPORTED] 23 | deps.detailab=2.6.3+1.21.3-fabric 24 | deps.environmentz=[UNSUPPORTED] 25 | deps.farmers_delight_refabricated=[UNSUPPORTED] 26 | deps.hotbarslotcycling=[UNSUPPORTED] 27 | deps.legendary_survival_overhaul=[UNSUPPORTED] 28 | deps.onebar=4.2.0 29 | deps.quark=[UNSUPPORTED] 30 | deps.raised=4.0.1 31 | deps.raised_artifact=1.21.3 32 | deps.statuseffectbars=1.0.7 33 | --------------------------------------------------------------------------------