├── assets ├── abs.png ├── air.png ├── exh.png ├── mnt.png ├── rgn.png └── stv.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── Common ├── src │ └── main │ │ ├── resources │ │ └── assets │ │ │ └── asteorbar │ │ │ ├── textures │ │ │ ├── gui │ │ │ │ └── overlay.png │ │ │ └── ui │ │ │ │ └── lightmap.png │ │ │ └── lang │ │ │ └── zh_cn.json │ │ └── java │ │ └── com │ │ └── afoxxvi │ │ └── asteorbar │ │ ├── utils │ │ ├── Pair.java │ │ ├── PlatformAdapter.java │ │ ├── Utils.java │ │ └── RenderHelper.java │ │ ├── render │ │ └── IHealthBarFeature.java │ │ ├── overlay │ │ ├── parts │ │ │ ├── StringOverlay.java │ │ │ ├── AirLevelOverlay.java │ │ │ ├── MainOverlay.java │ │ │ ├── MountHealthOverlay.java │ │ │ ├── ArmorLevelOverlay.java │ │ │ ├── ExperienceBarOverlay.java │ │ │ ├── FoodLevelOverlay.java │ │ │ ├── compat │ │ │ │ └── AppleSkinCompat.java │ │ │ └── BaseOverlay.java │ │ └── RenderGui.java │ │ ├── key │ │ └── KeyBinding.java │ │ ├── AsteorBar.java │ │ └── config │ │ └── ConfigAdapter.java └── build.gradle ├── Forge └── src │ └── main │ ├── resources │ ├── pack.mcmeta │ ├── asteorbar.mixins.json │ └── META-INF │ │ └── mods.toml │ └── java │ └── com │ └── afoxxvi │ └── asteorbar │ ├── mixin │ ├── FoodDataMixin.java │ ├── ExperienceBarRendererMixin.java │ ├── ContextualBarRendererMixin.java │ ├── LivingEntityRenderStateMixin.java │ ├── GuiMixin.java │ ├── LivingEntityRendererMixin.java │ └── EntityMixin.java │ ├── listener │ ├── ForgeEventListener.java │ └── ModEventListener.java │ ├── overlay │ ├── ForgeRenderGui.java │ ├── ForgeGuiRegistry.java │ └── parts │ │ └── ToughAsNailsOverlay.java │ ├── AsteorBarForge.java │ ├── entity │ └── AsteorBarRenderType.java │ ├── utils │ └── ForgePlatformAdapter.java │ └── network │ └── NetworkHandler.java ├── NeoForge ├── src │ └── main │ │ ├── resources │ │ ├── pack.mcmeta │ │ ├── asteorbar.mixins.json │ │ └── META-INF │ │ │ └── neoforge.mods.toml │ │ └── java │ │ └── com │ │ └── afoxxvi │ │ └── asteorbar │ │ ├── mixin │ │ ├── FoodDataMixin.java │ │ ├── third │ │ │ └── AppleSkinMixin.java │ │ ├── ExperienceBarRendererMixin.java │ │ ├── ContextualBarRendererMixin.java │ │ ├── LivingEntityRenderStateMixin.java │ │ ├── LivingEntityRendererMixin.java │ │ └── EntityMixin.java │ │ ├── overlay │ │ ├── NeoforgeGuiRegistry.java │ │ ├── NeoForgeRenderGui.java │ │ └── parts │ │ │ └── ToughAsNailsOverlay.java │ │ ├── utils │ │ ├── AppleSkinAdapter.java │ │ └── NeoForgePlatformAdapter.java │ │ ├── AsteorBarNeoForge.java │ │ ├── listener │ │ ├── ModEventListener.java │ │ └── NeoForgeEventListener.java │ │ ├── entity │ │ └── AsteorBarRenderType.java │ │ └── network │ │ └── NetworkHandler.java └── build.gradle ├── Fabric ├── src │ └── main │ │ ├── resources │ │ ├── asteorbar.accesswidener │ │ ├── asteorbar.mixins.json │ │ └── fabric.mod.json │ │ └── java │ │ └── com │ │ └── afoxxvi │ │ └── asteorbar │ │ ├── mixin │ │ ├── FoodDataMixin.java │ │ ├── RenderTypeMixin.java │ │ ├── ServerPlayerMixin.java │ │ ├── ExperienceBarRendererMixin.java │ │ ├── ContextualBarRendererMixin.java │ │ ├── LivingEntityRenderStateMixin.java │ │ ├── GuiMixin.java │ │ ├── ServerEntityMixin.java │ │ ├── LivingEntityRendererMixin.java │ │ └── EntityMixin.java │ │ ├── config │ │ └── ModMenuIntegration.java │ │ ├── AsteorBarFabric.java │ │ ├── overlay │ │ ├── FabricRenderGui.java │ │ ├── FabricGuiRegistry.java │ │ └── parts │ │ │ ├── ThermooOverlays.java │ │ │ └── ToughAsNailsOverlay.java │ │ ├── AsteorBarFabricClient.java │ │ ├── entity │ │ └── AsteorBarRenderType.java │ │ ├── utils │ │ ├── AppleSkinAdapter.java │ │ └── FabricPlatformAdapter.java │ │ └── network │ │ └── NetworkHandler.java └── build.gradle ├── settings.gradle ├── .gitignore ├── LICENSE ├── gradle.properties ├── gradlew.bat ├── version_history.md └── gradlew /assets/abs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afoxxvi/AsteorBarMod/HEAD/assets/abs.png -------------------------------------------------------------------------------- /assets/air.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afoxxvi/AsteorBarMod/HEAD/assets/air.png -------------------------------------------------------------------------------- /assets/exh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afoxxvi/AsteorBarMod/HEAD/assets/exh.png -------------------------------------------------------------------------------- /assets/mnt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afoxxvi/AsteorBarMod/HEAD/assets/mnt.png -------------------------------------------------------------------------------- /assets/rgn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afoxxvi/AsteorBarMod/HEAD/assets/rgn.png -------------------------------------------------------------------------------- /assets/stv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afoxxvi/AsteorBarMod/HEAD/assets/stv.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afoxxvi/AsteorBarMod/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Common/src/main/resources/assets/asteorbar/textures/gui/overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afoxxvi/AsteorBarMod/HEAD/Common/src/main/resources/assets/asteorbar/textures/gui/overlay.png -------------------------------------------------------------------------------- /Common/src/main/resources/assets/asteorbar/textures/ui/lightmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afoxxvi/AsteorBarMod/HEAD/Common/src/main/resources/assets/asteorbar/textures/ui/lightmap.png -------------------------------------------------------------------------------- /Forge/src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "asteorbar resources", 4 | "pack_format": 12, 5 | "forge:server_data_pack_format": 12 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /NeoForge/src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": { 4 | "text": "${mod_id} resources" 5 | }, 6 | "pack_format": ${pack_format_number} 7 | } 8 | } -------------------------------------------------------------------------------- /Fabric/src/main/resources/asteorbar.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v1 named 2 | accessible class net/minecraft/client/renderer/RenderType$CompositeRenderType 3 | accessible class net/minecraft/client/renderer/RenderType$CompositeState 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Feb 17 16:06:01 GMT+08:00 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https://mirrors.aliyun.com/gradle/distributions/v8.14.0/gradle-8.14-all.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/utils/Pair.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.utils; 2 | 3 | public class Pair { 4 | private final A a; 5 | private final B b; 6 | 7 | public Pair(A a, B b) { 8 | this.a = a; 9 | this.b = b; 10 | } 11 | 12 | public A getA() { 13 | return a; 14 | } 15 | 16 | public B getB() { 17 | return b; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Common/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'fabric-loom' version "${loom_version}" 4 | } 5 | 6 | group = 'com.afoxxvi' 7 | version = '1.0-SNAPSHOT' 8 | 9 | repositories { 10 | mavenCentral() 11 | maven { 12 | url "https://cursemaven.com" 13 | } 14 | } 15 | 16 | dependencies { 17 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 18 | mappings loom.officialMojangMappings() 19 | } 20 | 21 | test { 22 | useJUnitPlatform() 23 | } -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/render/IHealthBarFeature.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.render; 2 | 3 | public interface IHealthBarFeature { 4 | double asteorBar$getHealth(); 5 | 6 | void asteorBar$setHealth(double health); 7 | 8 | double asteorBar$getMaxHealth(); 9 | 10 | void asteorBar$setMaxHealth(double maxHealth); 11 | 12 | double asteorBar$getAbsorptionAmount(); 13 | 14 | void asteorBar$setAbsorptionAmount(double absorptionAmount); 15 | } 16 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/mixin/FoodDataMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import net.minecraft.world.food.FoodData; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | 7 | @Mixin(FoodData.class) 8 | public interface FoodDataMixin { 9 | @Accessor("exhaustionLevel") 10 | float getExhaustionLevel(); 11 | 12 | @Accessor("exhaustionLevel") 13 | void setExhaustionLevel(float exhaustionLevel); 14 | } 15 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/mixin/FoodDataMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import net.minecraft.world.food.FoodData; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | 7 | @Mixin(FoodData.class) 8 | public interface FoodDataMixin { 9 | @Accessor("exhaustionLevel") 10 | float getExhaustionLevel(); 11 | 12 | @Accessor("exhaustionLevel") 13 | void setExhaustionLevel(float exhaustionLevel); 14 | } 15 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/mixin/FoodDataMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import net.minecraft.world.food.FoodData; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | 7 | @Mixin(FoodData.class) 8 | public interface FoodDataMixin { 9 | @Accessor("exhaustionLevel") 10 | float getExhaustionLevel(); 11 | 12 | @Accessor("exhaustionLevel") 13 | void setExhaustionLevel(float exhaustionLevel); 14 | } 15 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/mixin/third/AppleSkinMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin.third; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Accessor; 5 | import squeek.appleskin.client.HUDOverlayHandler; 6 | 7 | @Mixin(value = HUDOverlayHandler.class, remap = false) 8 | public interface AppleSkinMixin { 9 | @Accessor("heldFood") 10 | static HUDOverlayHandler.HeldFoodCache getHeldFood() { 11 | throw new AssertionError(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/overlay/parts/StringOverlay.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts; 2 | 3 | import com.afoxxvi.asteorbar.overlay.Overlays; 4 | import com.afoxxvi.asteorbar.overlay.RenderGui; 5 | import net.minecraft.client.gui.GuiGraphics; 6 | 7 | public class StringOverlay extends BaseOverlay { 8 | @Override 9 | public void renderOverlay(RenderGui gui, GuiGraphics guiGraphics, float partialTick, int screenWidth, int screenHeight) { 10 | Overlays.renderString(guiGraphics); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/config/ModMenuIntegration.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.config; 2 | 3 | import com.terraformersmc.modmenu.api.ConfigScreenFactory; 4 | import com.terraformersmc.modmenu.api.ModMenuApi; 5 | import me.shedaniel.autoconfig.AutoConfig; 6 | 7 | public class ModMenuIntegration implements ModMenuApi { 8 | @Override 9 | public ConfigScreenFactory getModConfigScreenFactory() { 10 | return parent -> AutoConfig.getConfigScreen(FabricConfigAdapter.AsteorBarConfig.class, parent).get(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Forge/src/main/resources/asteorbar.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "com.afoxxvi.asteorbar.mixin", 4 | "compatibilityLevel": "JAVA_17", 5 | "client": [ 6 | "ContextualBarRendererMixin", 7 | "EntityMixin", 8 | "ExperienceBarRendererMixin", 9 | "GuiMixin", 10 | "LivingEntityRendererMixin", 11 | "LivingEntityRenderStateMixin" 12 | ], 13 | "server": [], 14 | "injectors": { 15 | "defaultRequire": 1 16 | }, 17 | "refmap": "asteorbar.mixins.refmap.json", 18 | "mixins": [ 19 | "FoodDataMixin" 20 | ] 21 | } -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/overlay/RenderGui.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.gui.Gui; 5 | 6 | public abstract class RenderGui { 7 | abstract public int leftHeight(); 8 | 9 | abstract public int rightHeight(); 10 | 11 | abstract public void leftHeight(int i); 12 | 13 | abstract public void rightHeight(int i); 14 | 15 | abstract public Gui gui(); 16 | 17 | public Minecraft mc() { 18 | return Minecraft.getInstance(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /NeoForge/src/main/resources/asteorbar.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "com.afoxxvi.asteorbar.mixin", 4 | "compatibilityLevel": "JAVA_17", 5 | "client": [ 6 | "ContextualBarRendererMixin", 7 | "EntityMixin", 8 | "ExperienceBarRendererMixin", 9 | "LivingEntityRendererMixin", 10 | "LivingEntityRenderStateMixin" 11 | ], 12 | "server": [], 13 | "injectors": { 14 | "defaultRequire": 1 15 | }, 16 | "refmap": "asteorbar.mixins.refmap.json", 17 | "mixins": [ 18 | "FoodDataMixin", 19 | "third.AppleSkinMixin" 20 | ] 21 | } -------------------------------------------------------------------------------- /Fabric/src/main/resources/asteorbar.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "com.afoxxvi.asteorbar.mixin", 4 | "compatibilityLevel": "JAVA_17", 5 | "mixins": [ 6 | "ServerEntityMixin", 7 | "ServerPlayerMixin", 8 | "FoodDataMixin" 9 | ], 10 | "client": [ 11 | "ContextualBarRendererMixin", 12 | "EntityMixin", 13 | "ExperienceBarRendererMixin", 14 | "GuiMixin", 15 | "LivingEntityRendererMixin", 16 | "LivingEntityRenderStateMixin", 17 | "RenderTypeMixin" 18 | ], 19 | "server": [], 20 | "injectors": { 21 | "defaultRequire": 1 22 | } 23 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | maven { 8 | name = 'MinecraftForge' 9 | url = 'https://maven.minecraftforge.net/' 10 | } 11 | maven { url = 'https://maven.neoforged.net/releases' } 12 | gradlePluginPortal() 13 | } 14 | } 15 | 16 | plugins { 17 | id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0' 18 | } 19 | 20 | rootProject.name = 'AsteorBarMod' 21 | include 'Common' 22 | include 'Fabric' 23 | include 'Forge' 24 | include 'NeoForge' 25 | 26 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/overlay/NeoforgeGuiRegistry.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.parts.ToughAsNailsOverlay; 5 | 6 | public class NeoforgeGuiRegistry { 7 | private NeoforgeGuiRegistry() { 8 | } 9 | 10 | private static boolean initialized = false; 11 | 12 | public static void init() { 13 | if (initialized) return; 14 | initialized = true; 15 | if (AsteorBar.compatibility.toughAsNails) { 16 | Overlays.registerOverlayAtRecommended(new ToughAsNailsOverlay(), Overlays.Position.UNSPECIFIED); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/mixin/RenderTypeMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.mojang.blaze3d.pipeline.RenderPipeline; 4 | import net.minecraft.client.renderer.RenderType; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Invoker; 7 | 8 | //crash when declaring as an abstract class, don't know why 9 | @Mixin(RenderType.class) 10 | public interface RenderTypeMixin { 11 | @Invoker("create") 12 | static RenderType.CompositeRenderType create(String string, int i, boolean bl, boolean bl2, RenderPipeline renderPipeline, RenderType.CompositeState compositeState) { 13 | throw new IllegalStateException(""); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/AsteorBarFabric.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar; 2 | 3 | import com.afoxxvi.asteorbar.config.FabricConfigAdapter; 4 | import com.afoxxvi.asteorbar.utils.FabricPlatformAdapter; 5 | import net.fabricmc.api.ModInitializer; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class AsteorBarFabric implements ModInitializer { 10 | public static final Logger LOGGER = LoggerFactory.getLogger(AsteorBar.MOD_NAME); 11 | 12 | @Override 13 | public void onInitialize() { 14 | FabricConfigAdapter.init(); 15 | AsteorBar.config = new FabricConfigAdapter(); 16 | AsteorBar.platformAdapter = new FabricPlatformAdapter(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/listener/ForgeEventListener.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.listener; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.key.KeyBinding; 5 | import net.minecraftforge.api.distmarker.Dist; 6 | import net.minecraftforge.client.event.InputEvent; 7 | import net.minecraftforge.eventbus.api.listener.SubscribeEvent; 8 | import net.minecraftforge.fml.common.Mod; 9 | 10 | @Mod.EventBusSubscriber(modid = AsteorBar.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT) 11 | public class ForgeEventListener { 12 | @SubscribeEvent 13 | public static void handleKeyInput(InputEvent.Key event) { 14 | KeyBinding.handleKeyInput(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### IntelliJ IDEA ### 8 | .idea/modules.xml 9 | .idea/jarRepositories.xml 10 | .idea/compiler.xml 11 | .idea/libraries/ 12 | .idea/workspace.xml 13 | *.iws 14 | *.iml 15 | *.ipr 16 | out/ 17 | !**/src/main/**/out/ 18 | !**/src/test/**/out/ 19 | .idea 20 | 21 | ### Eclipse ### 22 | .apt_generated 23 | .classpath 24 | .factorypath 25 | .project 26 | .settings 27 | .springBeans 28 | .sts4-cache 29 | bin/ 30 | !**/src/main/**/bin/ 31 | !**/src/test/**/bin/ 32 | 33 | ### NetBeans ### 34 | /nbproject/private/ 35 | /nbbuild/ 36 | /dist/ 37 | /nbdist/ 38 | /.nb-gradle/ 39 | 40 | ### VS Code ### 41 | .vscode/ 42 | 43 | ### Mac OS ### 44 | .DS_Store -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/listener/ModEventListener.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.listener; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.key.KeyBinding; 5 | import net.minecraftforge.api.distmarker.Dist; 6 | import net.minecraftforge.client.event.RegisterKeyMappingsEvent; 7 | import net.minecraftforge.eventbus.api.listener.SubscribeEvent; 8 | import net.minecraftforge.fml.common.Mod; 9 | 10 | @Mod.EventBusSubscriber(modid = AsteorBar.MOD_ID, value = Dist.CLIENT) 11 | public class ModEventListener { 12 | @SubscribeEvent 13 | public static void registerKeyMapping(RegisterKeyMappingsEvent event) { 14 | event.register(KeyBinding.TOGGLE_OVERLAY); 15 | event.register(KeyBinding.TOGGLE_MOB_BAR); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/overlay/ForgeRenderGui.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay; 2 | 3 | import net.minecraft.client.gui.Gui; 4 | 5 | public class ForgeRenderGui extends RenderGui { 6 | private final Gui gui; 7 | 8 | public ForgeRenderGui(Gui gui) { 9 | this.gui = gui; 10 | } 11 | 12 | @Override 13 | public int leftHeight() { 14 | return Overlays.leftHeight; 15 | } 16 | 17 | @Override 18 | public int rightHeight() { 19 | return Overlays.rightHeight; 20 | } 21 | 22 | @Override 23 | public void leftHeight(int i) { 24 | Overlays.leftHeight += i; 25 | } 26 | 27 | @Override 28 | public void rightHeight(int i) { 29 | Overlays.rightHeight += i; 30 | } 31 | 32 | @Override 33 | public Gui gui() { 34 | return gui; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/overlay/FabricRenderGui.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay; 2 | 3 | import net.minecraft.client.gui.Gui; 4 | 5 | public class FabricRenderGui extends RenderGui { 6 | private final Gui gui; 7 | 8 | public FabricRenderGui(Gui gui) { 9 | this.gui = gui; 10 | } 11 | 12 | @Override 13 | public int leftHeight() { 14 | return Overlays.leftHeight; 15 | } 16 | 17 | @Override 18 | public int rightHeight() { 19 | return Overlays.rightHeight; 20 | } 21 | 22 | @Override 23 | public void leftHeight(int i) { 24 | Overlays.leftHeight += i; 25 | } 26 | 27 | @Override 28 | public void rightHeight(int i) { 29 | Overlays.rightHeight += i; 30 | } 31 | 32 | @Override 33 | public Gui gui() { 34 | return gui; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/AsteorBarFabricClient.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar; 2 | 3 | import com.afoxxvi.asteorbar.key.KeyBinding; 4 | import com.afoxxvi.asteorbar.network.NetworkHandler; 5 | import net.fabricmc.api.ClientModInitializer; 6 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; 7 | import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; 8 | 9 | public class AsteorBarFabricClient implements ClientModInitializer { 10 | @Override 11 | public void onInitializeClient() { 12 | NetworkHandler.init(); 13 | KeyBindingHelper.registerKeyBinding(KeyBinding.TOGGLE_OVERLAY); 14 | KeyBindingHelper.registerKeyBinding(KeyBinding.TOGGLE_MOB_BAR); 15 | ClientTickEvents.END_CLIENT_TICK.register(client -> { 16 | KeyBinding.handleKeyInput(); 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/utils/PlatformAdapter.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.utils; 2 | 3 | import net.minecraft.client.renderer.RenderType; 4 | import net.minecraft.world.entity.LivingEntity; 5 | import net.minecraft.world.entity.player.Player; 6 | import org.jetbrains.annotations.Nullable; 7 | import org.slf4j.Logger; 8 | 9 | public interface PlatformAdapter { 10 | Logger getLogger(); 11 | 12 | boolean isBoss(LivingEntity livingEntity); 13 | 14 | boolean isEyeInFluid(Player player); 15 | 16 | RenderType getRenderType(); 17 | 18 | boolean isModLoaded(String modId); 19 | 20 | @Nullable 21 | AppleSkinFoodValues getAppleSkinFoodValues(Player player); 22 | 23 | float getExhaustion(Player player); 24 | 25 | void setExhaustion(Player player, float exhaustion); 26 | 27 | record AppleSkinFoodValues(int hungerIncrement, float saturationIncrement, float healthIncrement) { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Fabric/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "asteorbar", 4 | "version": "${version}", 5 | "name": "AsteorBar", 6 | "description": "", 7 | "authors": [], 8 | "contact": { 9 | "repo": "https://github.com/afoxx/AsteorBarFabric" 10 | }, 11 | "license": "All-Rights-Reserved", 12 | "icon": "assets/asteorbar/icon.png", 13 | "environment": "*", 14 | "entrypoints": { 15 | "client": [ 16 | "com.afoxxvi.asteorbar.AsteorBarFabricClient" 17 | ], 18 | "main": [ 19 | "com.afoxxvi.asteorbar.AsteorBarFabric" 20 | ], 21 | "modmenu": [ 22 | "com.afoxxvi.asteorbar.config.ModMenuIntegration" 23 | ] 24 | }, 25 | "depends": { 26 | "fabricloader": ">=${loader_version}", 27 | "fabric": "*", 28 | "minecraft": ">=${minecraft_version}" 29 | }, 30 | "mixins": [ 31 | "asteorbar.mixins.json" 32 | ], 33 | "accessWidener": "asteorbar.accesswidener" 34 | } 35 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/overlay/parts/AirLevelOverlay.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import net.minecraft.world.entity.player.Player; 5 | 6 | public class AirLevelOverlay extends SimpleBarOverlay { 7 | @Override 8 | protected Parameters getParameters(Player player) { 9 | final var parameters = new Parameters(); 10 | final var air = player.getAirSupply(); 11 | parameters.fillColor = AsteorBar.config.airColor(); 12 | parameters.boundColor = AsteorBar.config.airBoundColor(); 13 | parameters.value = air; 14 | parameters.capacity = 300; 15 | return parameters; 16 | } 17 | 18 | @Override 19 | protected boolean shouldRender(Player player) { 20 | int air = player.getAirSupply(); 21 | return AsteorBar.platformAdapter.isEyeInFluid(player) || air < 300; 22 | } 23 | 24 | @Override 25 | protected boolean alwaysLow() { 26 | return true; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/mixin/ServerPlayerMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.network.NetworkHandler; 4 | import com.mojang.authlib.GameProfile; 5 | import net.minecraft.server.level.ServerPlayer; 6 | import net.minecraft.world.entity.player.Player; 7 | import net.minecraft.world.level.Level; 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(ServerPlayer.class) 14 | public abstract class ServerPlayerMixin extends Player { 15 | public ServerPlayerMixin(Level level, GameProfile gameProfile) { 16 | super(level, gameProfile); 17 | } 18 | 19 | @Inject(at = @At(value = "HEAD"), method = "tick") 20 | void onTick(CallbackInfo ci) { 21 | ServerPlayer player = (ServerPlayer) (Object) this; 22 | NetworkHandler.onPlayerTick(player); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/mixin/ExperienceBarRendererMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import net.minecraft.client.DeltaTracker; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.client.gui.contextualbar.ExperienceBarRenderer; 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(ExperienceBarRenderer.class) 14 | abstract class ExperienceBarRendererMixin { 15 | @Inject(method = "renderBackground", at = @At("HEAD"), cancellable = true) 16 | public void render(GuiGraphics guiGraphics, DeltaTracker deltaTracker, CallbackInfo ci) { 17 | if (Overlays.style != Overlays.STYLE_NONE && AsteorBar.config.overwriteVanillaExperienceBar()) { 18 | ci.cancel(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/mixin/ExperienceBarRendererMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import net.minecraft.client.DeltaTracker; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.client.gui.contextualbar.ExperienceBarRenderer; 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(ExperienceBarRenderer.class) 14 | abstract class ExperienceBarRendererMixin { 15 | @Inject(method = "renderBackground", at = @At("HEAD"), cancellable = true) 16 | public void render(GuiGraphics guiGraphics, DeltaTracker deltaTracker, CallbackInfo ci) { 17 | if (Overlays.style != Overlays.STYLE_NONE && AsteorBar.config.overwriteVanillaExperienceBar()) { 18 | ci.cancel(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/mixin/ExperienceBarRendererMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import net.minecraft.client.DeltaTracker; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.client.gui.contextualbar.ExperienceBarRenderer; 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(ExperienceBarRenderer.class) 14 | abstract class ExperienceBarRendererMixin { 15 | @Inject(method = "renderBackground", at = @At("HEAD"), cancellable = true) 16 | public void render(GuiGraphics guiGraphics, DeltaTracker deltaTracker, CallbackInfo ci) { 17 | if (Overlays.style != Overlays.STYLE_NONE && AsteorBar.config.overwriteVanillaExperienceBar()) { 18 | ci.cancel(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/overlay/parts/MainOverlay.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts; 2 | 3 | import com.afoxxvi.asteorbar.overlay.Overlays; 4 | import com.afoxxvi.asteorbar.overlay.RenderGui; 5 | import net.minecraft.client.gui.GuiGraphics; 6 | 7 | public class MainOverlay extends BaseOverlay { 8 | @Override 9 | public void renderOverlay(RenderGui gui, GuiGraphics guiGraphics, float partialTick, int screenWidth, int screenHeight) { 10 | if (Overlays.style == Overlays.STYLE_NONE) return; 11 | gui.leftHeight(-6); 12 | gui.rightHeight(-6); 13 | final var list = Overlays.getCurrentOrder(); 14 | list.forEach(pair -> { 15 | if (pair.getA() instanceof SimpleBarOverlay simpleBarOverlay) { 16 | simpleBarOverlay.setDefinedPosition(pair.getB()); 17 | } 18 | pair.getA().render(gui, guiGraphics, partialTick, screenWidth, screenHeight); 19 | }); 20 | Overlays.STRING.render(gui, guiGraphics, partialTick, screenWidth, screenHeight); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/mixin/ContextualBarRendererMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import net.minecraft.client.gui.Font; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.client.gui.contextualbar.ContextualBarRenderer; 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(ContextualBarRenderer.class) 14 | interface ContextualBarRendererMixin { 15 | @Inject(method = "renderExperienceLevel(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/gui/Font;I)V", at = @At("HEAD"), cancellable = true) 16 | private static void renderExperienceLevelHead(GuiGraphics guiGraphics, Font font, int i, CallbackInfo ci) { 17 | if (Overlays.style != Overlays.STYLE_NONE && AsteorBar.config.overwriteVanillaExperienceBar()) { 18 | ci.cancel(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/mixin/ContextualBarRendererMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import net.minecraft.client.gui.Font; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.client.gui.contextualbar.ContextualBarRenderer; 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(ContextualBarRenderer.class) 14 | interface ContextualBarRendererMixin { 15 | @Inject(method = "renderExperienceLevel(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/gui/Font;I)V", at = @At("HEAD"), cancellable = true) 16 | private static void renderExperienceLevelHead(GuiGraphics guiGraphics, Font font, int i, CallbackInfo ci) { 17 | if (Overlays.style != Overlays.STYLE_NONE && AsteorBar.config.overwriteVanillaExperienceBar()) { 18 | ci.cancel(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/mixin/ContextualBarRendererMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import net.minecraft.client.gui.Font; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.client.gui.contextualbar.ContextualBarRenderer; 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(ContextualBarRenderer.class) 14 | interface ContextualBarRendererMixin { 15 | @Inject(method = "renderExperienceLevel(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/gui/Font;I)V", at = @At("HEAD"), cancellable = true) 16 | private static void renderExperienceLevelHead(GuiGraphics guiGraphics, Font font, int i, CallbackInfo ci) { 17 | if (Overlays.style != Overlays.STYLE_NONE && AsteorBar.config.overwriteVanillaExperienceBar()) { 18 | ci.cancel(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 afoxxvi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/overlay/ForgeGuiRegistry.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.parts.ToughAsNailsOverlay; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.gui.Gui; 7 | import net.minecraft.client.gui.GuiGraphics; 8 | 9 | public class ForgeGuiRegistry { 10 | private ForgeGuiRegistry() { 11 | } 12 | 13 | private static boolean initialized = false; 14 | 15 | public static void init() { 16 | if (initialized) return; 17 | if (AsteorBar.compatibility.toughAsNails) { 18 | Overlays.registerOverlayAtRecommended(new ToughAsNailsOverlay(), Overlays.Position.UNSPECIFIED); 19 | } 20 | initialized = true; 21 | } 22 | 23 | public static void startRender(Gui instance, GuiGraphics guiGraphics) { 24 | init(); 25 | var mc = Minecraft.getInstance(); 26 | var tick = 0f; 27 | var width = mc.getWindow().getGuiScaledWidth(); 28 | var height = mc.getWindow().getGuiScaledHeight(); 29 | var gui = new ForgeRenderGui(instance); 30 | Overlays.MAIN.renderOverlay(gui, guiGraphics, tick, width, height); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/overlay/FabricGuiRegistry.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay; 2 | 3 | import com.afoxxvi.asteorbar.overlay.parts.*; 4 | import com.afoxxvi.asteorbar.AsteorBar; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.gui.Gui; 7 | import net.minecraft.client.gui.GuiGraphics; 8 | 9 | public class FabricGuiRegistry { 10 | private FabricGuiRegistry() { 11 | } 12 | 13 | static { 14 | if (AsteorBar.compatibility.toughAsNails) { 15 | Overlays.registerOverlayAtRecommended(new ToughAsNailsOverlay(), Overlays.Position.UNSPECIFIED); 16 | } 17 | if (AsteorBar.compatibility.thermoo) { 18 | Overlays.registerOverlayAfter(new ThermooOverlays.Independent(), Overlays.PLAYER_HEALTH, Overlays.Position.UNSPECIFIED); 19 | } 20 | 21 | } 22 | 23 | public static void startRender(Gui instance, GuiGraphics guiGraphics) { 24 | var mc = Minecraft.getInstance(); 25 | var tick = 0f; 26 | var width = mc.getWindow().getGuiScaledWidth(); 27 | var height = mc.getWindow().getGuiScaledHeight(); 28 | var gui = new FabricRenderGui(instance); 29 | Overlays.MAIN.renderOverlay(gui, guiGraphics, tick, width, height); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/key/KeyBinding.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.key; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import net.minecraft.client.KeyMapping; 6 | import net.minecraft.resources.ResourceLocation; 7 | import org.lwjgl.glfw.GLFW; 8 | 9 | public class KeyBinding { 10 | public static final KeyMapping.Category CATEGORY = KeyMapping.Category.register(ResourceLocation.fromNamespaceAndPath(AsteorBar.MOD_ID, "key_bindings")); 11 | 12 | public static final KeyMapping TOGGLE_OVERLAY = new KeyMapping("asteorbar.key.toggle_overlay", GLFW.GLFW_KEY_F8, CATEGORY); 13 | public static final KeyMapping TOGGLE_MOB_BAR = new KeyMapping("asteorbar.key.toggle_mob_bar", GLFW.GLFW_KEY_F10, CATEGORY); 14 | 15 | public static void handleKeyInput() { 16 | while (KeyBinding.TOGGLE_OVERLAY.consumeClick()) { 17 | Overlays.style = (Overlays.style + 1) % Overlays.NUM_STYLES; 18 | AsteorBar.config.enableOverlay(Overlays.style != 0); 19 | AsteorBar.config.overlayLayoutStyle(Overlays.style); 20 | } 21 | while (KeyBinding.TOGGLE_MOB_BAR.consumeClick()) { 22 | AsteorBar.config.enableHealthBar(!AsteorBar.config.enableHealthBar()); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/AsteorBarForge.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar; 2 | 3 | import com.afoxxvi.asteorbar.config.ForgeConfigAdapter; 4 | import com.afoxxvi.asteorbar.network.NetworkHandler; 5 | import com.afoxxvi.asteorbar.utils.ForgePlatformAdapter; 6 | import com.mojang.logging.LogUtils; 7 | import net.minecraftforge.fml.common.Mod; 8 | import net.minecraftforge.fml.config.ModConfig; 9 | import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; 10 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 11 | import org.slf4j.Logger; 12 | 13 | @Mod(AsteorBar.MOD_ID) 14 | public class AsteorBarForge { 15 | public static final Logger LOGGER = LogUtils.getLogger(); 16 | 17 | public AsteorBarForge(FMLJavaModLoadingContext context) { 18 | var modBusGroup = context.getModBusGroup(); 19 | FMLCommonSetupEvent.getBus(modBusGroup).addListener(this::commonSetup); 20 | NetworkHandler.init(); 21 | context.registerConfig(ModConfig.Type.CLIENT, ForgeConfigAdapter.Config.CONFIG); 22 | AsteorBar.platformAdapter = new ForgePlatformAdapter(); 23 | AsteorBar.config = new ForgeConfigAdapter(); 24 | } 25 | 26 | private void commonSetup(final FMLCommonSetupEvent event) { 27 | LOGGER.info("Enabling AsteorBar"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/utils/AppleSkinAdapter.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.utils; 2 | 3 | import com.afoxxvi.asteorbar.mixin.third.AppleSkinMixin; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.world.entity.player.Player; 6 | import squeek.appleskin.helpers.ConsumableFood; 7 | import squeek.appleskin.helpers.FoodHelper; 8 | 9 | public class AppleSkinAdapter { 10 | private static final AppleSkinAdapter INSTANCE = new AppleSkinAdapter(); 11 | 12 | private AppleSkinAdapter() { 13 | } 14 | 15 | public static AppleSkinAdapter getInstance() { 16 | return INSTANCE; 17 | } 18 | 19 | public PlatformAdapter.AppleSkinFoodValues getAppleSkinFoodValues(Player player) { 20 | FoodHelper.QueriedFoodResult result = AppleSkinMixin.getHeldFood().result(Minecraft.getInstance().gui.getGuiTicks(), player); 21 | if (result == null) { 22 | return null; 23 | } 24 | int foodHunger = result.modifiedFoodProperties.nutrition(); 25 | float foodSaturationIncrement = result.modifiedFoodProperties.saturation(); 26 | float foodHealthIncrement = FoodHelper.getEstimatedHealthIncrement(player, new ConsumableFood(result.modifiedFoodProperties, result.consumable)); 27 | return new PlatformAdapter.AppleSkinFoodValues(foodHunger, foodSaturationIncrement, foodHealthIncrement); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/AsteorBarNeoForge.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar; 2 | 3 | import com.afoxxvi.asteorbar.config.NeoForgeConfigAdapter; 4 | import com.afoxxvi.asteorbar.network.NetworkHandler; 5 | import com.afoxxvi.asteorbar.utils.NeoForgePlatformAdapter; 6 | import com.mojang.logging.LogUtils; 7 | import net.neoforged.bus.api.IEventBus; 8 | import net.neoforged.fml.ModLoadingContext; 9 | import net.neoforged.fml.common.Mod; 10 | import net.neoforged.fml.config.ModConfig; 11 | import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; 12 | import net.neoforged.neoforge.common.NeoForge; 13 | import org.slf4j.Logger; 14 | 15 | @Mod(AsteorBar.MOD_ID) 16 | public class AsteorBarNeoForge { 17 | public static final Logger LOGGER = LogUtils.getLogger(); 18 | 19 | public AsteorBarNeoForge(IEventBus modEventBus) { 20 | modEventBus.addListener(this::commonSetup); 21 | modEventBus.addListener(NetworkHandler::register); 22 | NeoForge.EVENT_BUS.addListener(NetworkHandler::onPlayerTick); 23 | ModLoadingContext.get().getActiveContainer().registerConfig(ModConfig.Type.CLIENT, NeoForgeConfigAdapter.Config.CONFIG); 24 | AsteorBar.platformAdapter = new NeoForgePlatformAdapter(); 25 | AsteorBar.config = new NeoForgeConfigAdapter(); 26 | } 27 | 28 | private void commonSetup(final FMLCommonSetupEvent event) { 29 | LOGGER.info("Enabling AsteorBar"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/listener/ModEventListener.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.listener; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.AsteorBarNeoForge; 5 | import com.afoxxvi.asteorbar.key.KeyBinding; 6 | import com.afoxxvi.asteorbar.overlay.NeoForgeRenderGui; 7 | import com.afoxxvi.asteorbar.overlay.Overlays; 8 | import net.minecraft.resources.ResourceLocation; 9 | import net.neoforged.api.distmarker.Dist; 10 | import net.neoforged.bus.api.SubscribeEvent; 11 | import net.neoforged.fml.common.EventBusSubscriber; 12 | import net.neoforged.neoforge.client.event.RegisterGuiLayersEvent; 13 | import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; 14 | import net.neoforged.neoforge.client.gui.VanillaGuiLayers; 15 | 16 | @EventBusSubscriber(modid = AsteorBar.MOD_ID, value = Dist.CLIENT) 17 | public class ModEventListener { 18 | @SubscribeEvent 19 | public static void registerOverlay(RegisterGuiLayersEvent event) { 20 | AsteorBarNeoForge.LOGGER.info("Registering Overlays"); 21 | event.registerBelow(VanillaGuiLayers.PLAYER_HEALTH, ResourceLocation.fromNamespaceAndPath(AsteorBar.MOD_ID, "main"), new NeoForgeRenderGui(Overlays.MAIN)); 22 | } 23 | 24 | @SubscribeEvent 25 | public static void registerKeyMapping(RegisterKeyMappingsEvent event) { 26 | event.register(KeyBinding.TOGGLE_OVERLAY); 27 | event.register(KeyBinding.TOGGLE_MOB_BAR); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/entity/AsteorBarRenderType.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.entity; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import net.minecraft.client.renderer.RenderPipelines; 5 | import net.minecraft.client.renderer.RenderStateShard; 6 | import net.minecraft.client.renderer.RenderType; 7 | import net.minecraft.resources.ResourceLocation; 8 | 9 | public class AsteorBarRenderType extends RenderStateShard { 10 | //If no texture, the bar is not rendered while using shader packs 11 | private static final ResourceLocation LIGHTMAP_TEXTURE = ResourceLocation.fromNamespaceAndPath(AsteorBar.MOD_ID, "textures/ui/lightmap.png"); 12 | public static final RenderType RENDER_TYPE = RenderType.create( 13 | "asteorbar_health_bar", 14 | 1536, 15 | true, 16 | false, 17 | RenderPipelines.ENTITY_TRANSLUCENT, 18 | RenderType.CompositeState.builder() 19 | //.setShaderState(RenderStateShard.POSITION_COLOR_TEX_LIGHTMAP_SHADER) 20 | //.setTransparencyState(TRANSLUCENT_TRANSPARENCY) 21 | .setTextureState(new TextureStateShard(LIGHTMAP_TEXTURE, false)) 22 | .setLightmapState(LIGHTMAP) 23 | .createCompositeState(false) 24 | ); 25 | 26 | public AsteorBarRenderType(String p_110161_, Runnable p_110162_, Runnable p_110163_) { 27 | super(p_110161_, p_110162_, p_110163_); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/entity/AsteorBarRenderType.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.entity; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import net.minecraft.client.renderer.RenderPipelines; 5 | import net.minecraft.client.renderer.RenderStateShard; 6 | import net.minecraft.client.renderer.RenderType; 7 | import net.minecraft.resources.ResourceLocation; 8 | 9 | public class AsteorBarRenderType extends RenderStateShard { 10 | //If no texture, the bar is not rendered while using shader packs 11 | private static final ResourceLocation LIGHTMAP_TEXTURE = ResourceLocation.fromNamespaceAndPath(AsteorBar.MOD_ID, "textures/ui/lightmap.png"); 12 | public static final RenderType RENDER_TYPE = RenderType.create( 13 | "asteorbar_health_bar", 14 | 1536, 15 | true, 16 | false, 17 | RenderPipelines.ENTITY_TRANSLUCENT, 18 | RenderType.CompositeState.builder() 19 | //.setShaderState(RenderStateShard.POSITION_COLOR_TEX_LIGHTMAP_SHADER) 20 | //.setTransparencyState(TRANSLUCENT_TRANSPARENCY) 21 | .setTextureState(new TextureStateShard(LIGHTMAP_TEXTURE, false)) 22 | .setLightmapState(LIGHTMAP) 23 | .createCompositeState(false) 24 | ); 25 | 26 | public AsteorBarRenderType(String p_110161_, Runnable p_110162_, Runnable p_110163_) { 27 | super(p_110161_, p_110162_, p_110163_); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/mixin/LivingEntityRenderStateMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.render.IHealthBarFeature; 4 | import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Unique; 7 | 8 | @Mixin(LivingEntityRenderState.class) 9 | public abstract class LivingEntityRenderStateMixin implements IHealthBarFeature { 10 | @Unique 11 | private double asteorBar$health = 0.0; 12 | @Unique 13 | private double asteorBar$maxHealth = 0.0; 14 | @Unique 15 | private double asteorBar$absorptionAmount = 0.0; 16 | 17 | @Override 18 | public void asteorBar$setHealth(double health) { 19 | this.asteorBar$health = health; 20 | } 21 | 22 | @Override 23 | public double asteorBar$getHealth() { 24 | return asteorBar$health; 25 | } 26 | 27 | @Override 28 | public void asteorBar$setMaxHealth(double maxHealth) { 29 | this.asteorBar$maxHealth = maxHealth; 30 | } 31 | 32 | @Override 33 | public double asteorBar$getMaxHealth() { 34 | return asteorBar$maxHealth; 35 | } 36 | 37 | @Override 38 | public void asteorBar$setAbsorptionAmount(double absorptionAmount) { 39 | this.asteorBar$absorptionAmount = absorptionAmount; 40 | } 41 | 42 | @Override 43 | public double asteorBar$getAbsorptionAmount() { 44 | return asteorBar$absorptionAmount; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/mixin/LivingEntityRenderStateMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.render.IHealthBarFeature; 4 | import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Unique; 7 | 8 | @Mixin(LivingEntityRenderState.class) 9 | public abstract class LivingEntityRenderStateMixin implements IHealthBarFeature { 10 | @Unique 11 | private double asteorBar$health = 0.0; 12 | @Unique 13 | private double asteorBar$maxHealth = 0.0; 14 | @Unique 15 | private double asteorBar$absorptionAmount = 0.0; 16 | 17 | @Override 18 | public void asteorBar$setHealth(double health) { 19 | this.asteorBar$health = health; 20 | } 21 | 22 | @Override 23 | public double asteorBar$getHealth() { 24 | return asteorBar$health; 25 | } 26 | 27 | @Override 28 | public void asteorBar$setMaxHealth(double maxHealth) { 29 | this.asteorBar$maxHealth = maxHealth; 30 | } 31 | 32 | @Override 33 | public double asteorBar$getMaxHealth() { 34 | return asteorBar$maxHealth; 35 | } 36 | 37 | @Override 38 | public void asteorBar$setAbsorptionAmount(double absorptionAmount) { 39 | this.asteorBar$absorptionAmount = absorptionAmount; 40 | } 41 | 42 | @Override 43 | public double asteorBar$getAbsorptionAmount() { 44 | return asteorBar$absorptionAmount; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/mixin/LivingEntityRenderStateMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.render.IHealthBarFeature; 4 | import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Unique; 7 | 8 | @Mixin(LivingEntityRenderState.class) 9 | public abstract class LivingEntityRenderStateMixin implements IHealthBarFeature { 10 | @Unique 11 | private double asteorBar$health = 0.0; 12 | @Unique 13 | private double asteorBar$maxHealth = 0.0; 14 | @Unique 15 | private double asteorBar$absorptionAmount = 0.0; 16 | 17 | @Override 18 | public void asteorBar$setHealth(double health) { 19 | this.asteorBar$health = health; 20 | } 21 | 22 | @Override 23 | public double asteorBar$getHealth() { 24 | return asteorBar$health; 25 | } 26 | 27 | @Override 28 | public void asteorBar$setMaxHealth(double maxHealth) { 29 | this.asteorBar$maxHealth = maxHealth; 30 | } 31 | 32 | @Override 33 | public double asteorBar$getMaxHealth() { 34 | return asteorBar$maxHealth; 35 | } 36 | 37 | @Override 38 | public void asteorBar$setAbsorptionAmount(double absorptionAmount) { 39 | this.asteorBar$absorptionAmount = absorptionAmount; 40 | } 41 | 42 | @Override 43 | public double asteorBar$getAbsorptionAmount() { 44 | return asteorBar$absorptionAmount; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/entity/AsteorBarRenderType.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.entity; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.mixin.RenderTypeMixin; 5 | import net.minecraft.client.renderer.RenderPipelines; 6 | import net.minecraft.client.renderer.RenderStateShard; 7 | import net.minecraft.client.renderer.RenderType; 8 | import net.minecraft.resources.ResourceLocation; 9 | 10 | public class AsteorBarRenderType extends RenderStateShard { 11 | //If no texture, the bar is not rendered while using shader packs 12 | private static final ResourceLocation LIGHTMAP_TEXTURE = ResourceLocation.fromNamespaceAndPath(AsteorBar.MOD_ID, "textures/ui/lightmap.png"); 13 | public static final RenderType RENDER_TYPE = RenderTypeMixin.create( 14 | "asteorbar_health_bar", 15 | 1536, 16 | true, 17 | false, 18 | RenderPipelines.ENTITY_TRANSLUCENT, 19 | RenderType.CompositeState.builder() 20 | //.setShaderState(RenderStateShard.POSITION_COLOR_TEX_LIGHTMAP_SHADER) 21 | //.setTransparencyState(TRANSLUCENT_TRANSPARENCY) 22 | .setTextureState(new TextureStateShard(LIGHTMAP_TEXTURE, false)) 23 | .setLightmapState(LIGHTMAP) 24 | .createCompositeState(false) 25 | ); 26 | 27 | public AsteorBarRenderType(String p_110161_, Runnable p_110162_, Runnable p_110163_) { 28 | super(p_110161_, p_110162_, p_110163_); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/mixin/GuiMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.overlay.FabricGuiRegistry; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import net.minecraft.client.gui.Gui; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.gen.Invoker; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.Redirect; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(Gui.class) 15 | public abstract class GuiMixin { 16 | @Invoker("renderPlayerHealth") 17 | public abstract void renderPlayerHealthRaw(GuiGraphics guiGraphics); 18 | 19 | @Redirect(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;renderPlayerHealth(Lnet/minecraft/client/gui/GuiGraphics;)V"), method = "renderHotbarAndDecorations") 20 | public void renderPlayerHealth(Gui instance, GuiGraphics guiGraphics) { 21 | Overlays.reset(); 22 | if (Overlays.style == Overlays.STYLE_NONE) { 23 | renderPlayerHealthRaw(guiGraphics); 24 | return; 25 | } 26 | FabricGuiRegistry.startRender(instance, guiGraphics); 27 | } 28 | 29 | @Inject(method = "renderVehicleHealth(Lnet/minecraft/client/gui/GuiGraphics;)V", at = @At("HEAD"), cancellable = true) 30 | public void injectVehicle(GuiGraphics p_283368_, CallbackInfo ci) { 31 | if (Overlays.style != Overlays.STYLE_NONE) { 32 | ci.cancel(); 33 | } 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/mixin/GuiMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.overlay.ForgeGuiRegistry; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import net.minecraft.client.gui.Gui; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.gen.Invoker; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.Redirect; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(value = Gui.class, remap = false) 15 | public abstract class GuiMixin { 16 | @Invoker("renderPlayerHealth") 17 | public abstract void renderPlayerHealthRaw(GuiGraphics guiGraphics); 18 | 19 | @Redirect(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;renderPlayerHealth(Lnet/minecraft/client/gui/GuiGraphics;)V"), method = "renderHotbarAndDecorations") 20 | public void renderPlayerHealth(Gui instance, GuiGraphics guiGraphics) { 21 | Overlays.reset(); 22 | if (Overlays.style == Overlays.STYLE_NONE) { 23 | renderPlayerHealthRaw(guiGraphics); 24 | return; 25 | } 26 | ForgeGuiRegistry.startRender(instance, guiGraphics); 27 | } 28 | 29 | @Inject(method = "renderVehicleHealth(Lnet/minecraft/client/gui/GuiGraphics;)V", at = @At("HEAD"), cancellable = true) 30 | public void injectVehicle(GuiGraphics p_283368_, CallbackInfo ci) { 31 | if (Overlays.style != Overlays.STYLE_NONE) { 32 | ci.cancel(); 33 | } 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/mixin/ServerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.network.NetworkHandler; 4 | import net.minecraft.server.level.ServerEntity; 5 | import net.minecraft.world.entity.Entity; 6 | import net.minecraft.world.entity.LivingEntity; 7 | import org.spongepowered.asm.mixin.Final; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | import org.spongepowered.asm.mixin.Unique; 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(ServerEntity.class) 16 | public abstract class ServerEntityMixin { 17 | private static final float EPS = 0.01f; 18 | 19 | @Shadow 20 | @Final 21 | private Entity entity; 22 | 23 | @Shadow @Final private ServerEntity.Synchronizer synchronizer; 24 | @Unique 25 | private float asteorBar$lastAbsorption = -1.0f; 26 | 27 | @Inject(method = "sendChanges", at = @At("TAIL")) 28 | public void onSendChanges(CallbackInfo ci) { 29 | Entity selfEntity = entity; 30 | if (!(selfEntity instanceof LivingEntity livingEntity)) { 31 | return; 32 | } 33 | float currentAbsorption = livingEntity.getAbsorptionAmount(); 34 | if (Math.abs(currentAbsorption - asteorBar$lastAbsorption) > EPS) { 35 | asteorBar$lastAbsorption = currentAbsorption; 36 | // Send update to client 37 | var packet = NetworkHandler.createAbsorptionPacket(livingEntity.getId(), currentAbsorption); 38 | synchronizer.sendToTrackingPlayers(packet); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/mixin/LivingEntityRendererMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.entity.EntityRenderer; 4 | import com.afoxxvi.asteorbar.render.IHealthBarFeature; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.model.EntityModel; 7 | import net.minecraft.client.renderer.entity.LivingEntityRenderer; 8 | import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; 9 | import net.minecraft.world.entity.LivingEntity; 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(LivingEntityRenderer.class) 16 | public abstract class LivingEntityRendererMixin> { 17 | @Inject( 18 | method = "extractRenderState(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/client/renderer/entity/state/LivingEntityRenderState;F)V", 19 | at = @At("TAIL") 20 | ) 21 | public void extract(T livingEntity, S livingEntityRenderState, float f, CallbackInfo ci) { 22 | if (!EntityRenderer.shouldRender(livingEntity, Minecraft.getInstance().player)) { 23 | return; 24 | } 25 | if (livingEntityRenderState instanceof IHealthBarFeature healthBarFeature) { 26 | healthBarFeature.asteorBar$setHealth(livingEntity.getHealth()); 27 | healthBarFeature.asteorBar$setMaxHealth(livingEntity.getMaxHealth()); 28 | healthBarFeature.asteorBar$setAbsorptionAmount(livingEntity.getAbsorptionAmount()); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/mixin/LivingEntityRendererMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.entity.EntityRenderer; 4 | import com.afoxxvi.asteorbar.render.IHealthBarFeature; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.model.EntityModel; 7 | import net.minecraft.client.renderer.entity.LivingEntityRenderer; 8 | import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; 9 | import net.minecraft.world.entity.LivingEntity; 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(LivingEntityRenderer.class) 16 | public abstract class LivingEntityRendererMixin> { 17 | @Inject( 18 | method = "extractRenderState(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/client/renderer/entity/state/LivingEntityRenderState;F)V", 19 | at = @At("TAIL") 20 | ) 21 | public void extract(T livingEntity, S livingEntityRenderState, float f, CallbackInfo ci) { 22 | if (!EntityRenderer.shouldRender(livingEntity, Minecraft.getInstance().player)) { 23 | return; 24 | } 25 | if (livingEntityRenderState instanceof IHealthBarFeature healthBarFeature) { 26 | healthBarFeature.asteorBar$setHealth(livingEntity.getHealth()); 27 | healthBarFeature.asteorBar$setMaxHealth(livingEntity.getMaxHealth()); 28 | healthBarFeature.asteorBar$setAbsorptionAmount(livingEntity.getAbsorptionAmount()); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/mixin/LivingEntityRendererMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.entity.EntityRenderer; 4 | import com.afoxxvi.asteorbar.render.IHealthBarFeature; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.model.EntityModel; 7 | import net.minecraft.client.renderer.entity.LivingEntityRenderer; 8 | import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; 9 | import net.minecraft.world.entity.LivingEntity; 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(LivingEntityRenderer.class) 16 | public abstract class LivingEntityRendererMixin> { 17 | @Inject( 18 | method = "extractRenderState(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/client/renderer/entity/state/LivingEntityRenderState;F)V", 19 | at = @At("TAIL") 20 | ) 21 | public void extract(T livingEntity, S livingEntityRenderState, float f, CallbackInfo ci) { 22 | if (!EntityRenderer.shouldRender(livingEntity, Minecraft.getInstance().player)) { 23 | return; 24 | } 25 | if (livingEntityRenderState instanceof IHealthBarFeature healthBarFeature) { 26 | healthBarFeature.asteorBar$setHealth(livingEntity.getHealth()); 27 | healthBarFeature.asteorBar$setMaxHealth(livingEntity.getMaxHealth()); 28 | healthBarFeature.asteorBar$setAbsorptionAmount(livingEntity.getAbsorptionAmount()); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/utils/AppleSkinAdapter.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.utils; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.world.entity.player.Player; 5 | import net.minecraft.world.food.FoodData; 6 | import squeek.appleskin.api.event.HUDOverlayEvent; 7 | import squeek.appleskin.client.HUDOverlayHandler; 8 | import squeek.appleskin.helpers.ConsumableFood; 9 | import squeek.appleskin.helpers.FoodHelper; 10 | 11 | public class AppleSkinAdapter { 12 | private static final AppleSkinAdapter INSTANCE = new AppleSkinAdapter(); 13 | 14 | private AppleSkinAdapter() { 15 | } 16 | 17 | public static AppleSkinAdapter getInstance() { 18 | return INSTANCE; 19 | } 20 | 21 | public PlatformAdapter.AppleSkinFoodValues getAppleSkinFoodValues(Player player) { 22 | FoodData stats = player.getFoodData(); 23 | FoodHelper.QueriedFoodResult result = HUDOverlayHandler.INSTANCE.heldFood.result(Minecraft.getInstance().gui.getGuiTicks(), player); 24 | if (result == null) { 25 | return null; 26 | } 27 | HUDOverlayEvent.HungerRestored hungerRenderEvent = new HUDOverlayEvent.HungerRestored(stats.getFoodLevel(), result.itemStack, result.modifiedFoodComponent, 0, 0, null); 28 | HUDOverlayEvent.HungerRestored.EVENT.invoker().interact(hungerRenderEvent); 29 | int foodHunger = result.modifiedFoodComponent.nutrition(); 30 | float foodSaturationIncrement = result.modifiedFoodComponent.saturation(); 31 | float foodHealthIncrement = FoodHelper.getEstimatedHealthIncrement(player, new ConsumableFood(result.modifiedFoodComponent, result.consumableComponent)); 32 | return new PlatformAdapter.AppleSkinFoodValues(foodHunger, foodSaturationIncrement, foodHealthIncrement); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/overlay/NeoForgeRenderGui.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay; 2 | 3 | import com.afoxxvi.asteorbar.overlay.parts.BaseOverlay; 4 | import net.minecraft.client.DeltaTracker; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.gui.Gui; 7 | import net.minecraft.client.gui.GuiGraphics; 8 | import net.neoforged.neoforge.client.gui.GuiLayer; 9 | 10 | public class NeoForgeRenderGui extends RenderGui implements GuiLayer { 11 | private Gui gui; 12 | private final BaseOverlay overlay; 13 | private final boolean survival; 14 | 15 | public NeoForgeRenderGui(BaseOverlay overlay) { 16 | this(overlay, true); 17 | } 18 | 19 | public NeoForgeRenderGui(BaseOverlay overlay, boolean survival) { 20 | this.overlay = overlay; 21 | this.survival = survival; 22 | } 23 | 24 | @Override 25 | public int leftHeight() { 26 | return gui.leftHeight; 27 | } 28 | 29 | @Override 30 | public int rightHeight() { 31 | return gui.rightHeight; 32 | } 33 | 34 | @Override 35 | public void leftHeight(int i) { 36 | gui.leftHeight += i; 37 | } 38 | 39 | @Override 40 | public void rightHeight(int i) { 41 | gui.rightHeight += i; 42 | } 43 | 44 | @Override 45 | public Gui gui() { 46 | return gui; 47 | } 48 | 49 | @Override 50 | public void render(GuiGraphics guiGraphics, DeltaTracker deltaTracker) { 51 | final Minecraft mc = Minecraft.getInstance(); 52 | this.gui = mc.gui; 53 | if (!mc.options.hideGui && (!survival || mc.gameMode.canHurtPlayer())) { 54 | overlay.render(this, guiGraphics, deltaTracker.getGameTimeDeltaPartialTick(true), guiGraphics.guiWidth(), guiGraphics.guiHeight()); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/overlay/parts/MountHealthOverlay.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.utils.Utils; 5 | import net.minecraft.world.entity.Entity; 6 | import net.minecraft.world.entity.LivingEntity; 7 | import net.minecraft.world.entity.player.Player; 8 | 9 | public class MountHealthOverlay extends SimpleBarOverlay { 10 | @Override 11 | protected Parameters getParameters(Player player) { 12 | Entity tmp = player.getVehicle(); 13 | if (!(tmp instanceof LivingEntity mount)) return null; 14 | final var parameters = new Parameters(); 15 | parameters.fillColor = AsteorBar.config.mountHealthColor(); 16 | parameters.fillColor2 = AsteorBar.config.mountHealthColor2(); 17 | parameters.boundColor = AsteorBar.config.mountHealthBoundColor(); 18 | parameters.boundColor2 = AsteorBar.config.mountHealthBoundColor2(); 19 | parameters.emptyColor = AsteorBar.config.mountHealthEmptyColor(); 20 | parameters.value = mount.getHealth(); 21 | parameters.capacity = mount.getMaxHealth(); 22 | if (AsteorBar.config.displayHealthText()) { 23 | parameters.centerText = Utils.formatNumber(mount.getHealth()) + "/" + Utils.formatNumber(mount.getMaxHealth()); 24 | parameters.centerColor = 0xFFFFFF; 25 | } 26 | return parameters; 27 | } 28 | 29 | @Override 30 | protected boolean isLeftSide() { 31 | return AsteorBar.config.mountHealthOnLeftSide(); 32 | } 33 | 34 | @Override 35 | protected boolean shouldRender(Player player) { 36 | Entity tmp = player.getVehicle(); 37 | if (tmp instanceof LivingEntity mount) { 38 | return mount.getHealth() > 0; 39 | } 40 | return false; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/utils/ForgePlatformAdapter.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.utils; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBarForge; 4 | import com.afoxxvi.asteorbar.AsteorBar; 5 | import com.afoxxvi.asteorbar.AsteorBarForge; 6 | import com.afoxxvi.asteorbar.entity.AsteorBarRenderType; 7 | import com.afoxxvi.asteorbar.mixin.FoodDataMixin; 8 | import net.minecraft.client.renderer.RenderType; 9 | import net.minecraft.world.entity.LivingEntity; 10 | import net.minecraft.world.entity.player.Player; 11 | import net.minecraftforge.common.ForgeMod; 12 | import net.minecraftforge.common.Tags; 13 | import net.minecraftforge.fml.ModList; 14 | import org.slf4j.Logger; 15 | 16 | public class ForgePlatformAdapter implements PlatformAdapter { 17 | @Override 18 | public Logger getLogger() { 19 | return AsteorBarForge.LOGGER; 20 | } 21 | 22 | @Override 23 | public boolean isBoss(LivingEntity livingEntity) { 24 | return livingEntity.getType().is(Tags.EntityTypes.BOSSES); 25 | } 26 | 27 | @Override 28 | public boolean isEyeInFluid(Player player) { 29 | return player.isEyeInFluidType(ForgeMod.WATER_TYPE.get()); 30 | } 31 | 32 | @Override 33 | public RenderType getRenderType() { 34 | return AsteorBarRenderType.RENDER_TYPE; 35 | } 36 | 37 | @Override 38 | public boolean isModLoaded(String modId) { 39 | return ModList.get().isLoaded(modId); 40 | } 41 | 42 | @Override 43 | public AppleSkinFoodValues getAppleSkinFoodValues(Player player) { 44 | return null; 45 | } 46 | 47 | @Override 48 | public float getExhaustion(Player player) { 49 | return ((FoodDataMixin) player.getFoodData()).getExhaustionLevel(); 50 | } 51 | 52 | @Override 53 | public void setExhaustion(Player player, float exhaustion) { 54 | ((FoodDataMixin) player.getFoodData()).setExhaustionLevel(exhaustion); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | 4 | mod_id=asteorbar 5 | mod_name=AsteorBar 6 | mod_license=All-Rights-Reserved 7 | mod_version=1.5.3 8 | mod_group_id=com.afoxxvi 9 | mod_authors=AsteorFox(afoxxvi) 10 | mod_description= 11 | minecraft_version=1.21.9 12 | minecraft_version_range=[1.21.9,1.22) 13 | pack_format_number=88 14 | # Forge Properties 15 | forge_version=59.0.5 16 | forge_version_range=[59,) 17 | loader_version_range=[59,) 18 | mapping_channel=official 19 | mapping_version=1.21.9 20 | # NeoForge Properties 21 | neo_version=21.9.16-beta 22 | neo_version_range=[21.9,) 23 | neo_loader_version_range=[1,) 24 | # read more on this at https://github.com/neoforged/NeoGradle/blob/NG_7.0/README.md#apply-parchment-mappings 25 | # you can also find the latest versions at: https://parchmentmc.org/docs/getting-started 26 | neogradle.subsystems.parchment.minecraftVersion=1.21.9 27 | neogradle.subsystems.parchment.mappingsVersion=2025.10.05 28 | # Fabric Properties 29 | # check these on https://modmuss50.me/fabric.html 30 | yarn_mappings=1.21.9+build.1 31 | loader_version=0.17.2 32 | loom_version=1.11-SNAPSHOT 33 | # Dependencies 34 | fabric_version=0.134.0+1.21.9 35 | # https://linkie.shedaniel.dev/ 36 | cloth_config_version=20.0.148 37 | mod_menu_version=16.0.0-rc.1 38 | tough_as_nails_version_forge=7064258 39 | tough_as_nails_version_fabric=7064260 40 | tough_as_nails_version_neoforge=7064259 41 | thirst_was_taken_version_forge=0 42 | thirst_was_taken_version_neoforge=0 43 | mekanism_version_forge=0 44 | dehydration_version_fabric=0 45 | parcool_version_forge=0 46 | irons_spellbooks_version_forge=0 47 | feathers_version_forge=0 48 | appleskin_version_forge=0 49 | appleskin_version_fabric=7075567 50 | appleskin_version_neoforge=7075798 51 | superiorshields_version_forge=0 52 | vampirism_version_forge=0 53 | vampirism_version_neoforge=0 54 | light_shield_version_neoforge=0 55 | botania_version_forge=0 56 | terrafirmacraft_version_forge=0 57 | ars_nouveau_version_forge=0 58 | origins_version_forge=0 59 | origins_apoli_version_fabric=0 60 | thermoo_version_fabric=8.0.1 61 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/overlay/parts/ArmorLevelOverlay.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.utils.Utils; 5 | import net.minecraft.world.entity.ai.attributes.Attributes; 6 | import net.minecraft.world.entity.player.Player; 7 | 8 | public class ArmorLevelOverlay extends SimpleBarOverlay { 9 | @Override 10 | protected Parameters getParameters(Player player) { 11 | final var parameters = new Parameters(); 12 | final var armor = player.getArmorValue(); 13 | parameters.fillColor = AsteorBar.config.armorColor(); 14 | parameters.boundColor = AsteorBar.config.armorBoundColor(); 15 | parameters.emptyColor = AsteorBar.config.armorEmptyColor(); 16 | parameters.value = armor; 17 | parameters.capacity = AsteorBar.config.fullArmorValue(); 18 | if (armor > AsteorBar.config.fullArmorValue()) { 19 | parameters.centerText = String.valueOf(armor); 20 | parameters.centerColor = 0xFFFFFF; 21 | } 22 | if (AsteorBar.config.displayArmorToughness()) { 23 | var attr = player.getAttribute(Attributes.ARMOR_TOUGHNESS); 24 | if (attr != null) { 25 | parameters.boundFillColor = AsteorBar.config.armorToughnessColor(); 26 | parameters.boundValue = attr.getValue(); 27 | parameters.boundCapacity = AsteorBar.config.fullArmorToughnessValue(); 28 | if (attr.getValue() > AsteorBar.config.fullArmorToughnessValue()) { 29 | parameters.leftText = Utils.formatNumber(attr.getValue()); 30 | parameters.leftColor = 0xdeecff; 31 | } 32 | } 33 | } 34 | return parameters; 35 | } 36 | 37 | @Override 38 | protected boolean isLeftSide() { 39 | return true; 40 | } 41 | 42 | @Override 43 | protected boolean shouldRender(Player player) { 44 | if (!AsteorBar.config.overwriteVanillaArmorBar()) return false; 45 | int armor = player.getArmorValue(); 46 | return armor > 0; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/utils/NeoForgePlatformAdapter.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.utils; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.AsteorBarNeoForge; 5 | import com.afoxxvi.asteorbar.entity.AsteorBarRenderType; 6 | import com.afoxxvi.asteorbar.mixin.FoodDataMixin; 7 | import net.minecraft.client.renderer.RenderType; 8 | import net.minecraft.world.entity.LivingEntity; 9 | import net.minecraft.world.entity.player.Player; 10 | import net.neoforged.fml.ModList; 11 | import net.neoforged.neoforge.common.NeoForgeMod; 12 | import net.neoforged.neoforge.common.Tags; 13 | import org.slf4j.Logger; 14 | 15 | public class NeoForgePlatformAdapter implements PlatformAdapter { 16 | @Override 17 | public Logger getLogger() { 18 | return AsteorBarNeoForge.LOGGER; 19 | } 20 | 21 | @Override 22 | public boolean isBoss(LivingEntity livingEntity) { 23 | return livingEntity.getType().is(Tags.EntityTypes.BOSSES); 24 | } 25 | 26 | @Override 27 | public boolean isEyeInFluid(Player player) { 28 | return player.isEyeInFluidType(NeoForgeMod.WATER_TYPE.value()); 29 | } 30 | 31 | @Override 32 | public RenderType getRenderType() { 33 | return AsteorBarRenderType.RENDER_TYPE; 34 | } 35 | 36 | @Override 37 | public boolean isModLoaded(String modId) { 38 | return ModList.get().isLoaded(modId); 39 | } 40 | 41 | @Override 42 | public AppleSkinFoodValues getAppleSkinFoodValues(Player player) { 43 | if (!AsteorBar.compatibility.appleskin) { 44 | return null; 45 | } 46 | // if not using third adapter, the game will crash if appleskin is not loaded 47 | return AppleSkinAdapter.getInstance().getAppleSkinFoodValues(player); 48 | } 49 | 50 | 51 | @Override 52 | public float getExhaustion(Player player) { 53 | return ((FoodDataMixin) player.getFoodData()).getExhaustionLevel(); 54 | } 55 | 56 | @Override 57 | public void setExhaustion(Player player, float exhaustion) { 58 | ((FoodDataMixin) player.getFoodData()).setExhaustionLevel(exhaustion); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/utils/FabricPlatformAdapter.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.utils; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.AsteorBarFabric; 5 | import com.afoxxvi.asteorbar.entity.AsteorBarRenderType; 6 | import com.afoxxvi.asteorbar.mixin.FoodDataMixin; 7 | import net.fabricmc.loader.api.FabricLoader; 8 | import net.minecraft.client.renderer.RenderType; 9 | import net.minecraft.tags.FluidTags; 10 | import net.minecraft.world.entity.EntityType; 11 | import net.minecraft.world.entity.LivingEntity; 12 | import net.minecraft.world.entity.player.Player; 13 | import org.slf4j.Logger; 14 | 15 | public class FabricPlatformAdapter implements PlatformAdapter { 16 | @Override 17 | public Logger getLogger() { 18 | return AsteorBarFabric.LOGGER; 19 | } 20 | 21 | @Override 22 | public boolean isBoss(LivingEntity livingEntity) { 23 | var type = livingEntity.getType(); 24 | return type == EntityType.ENDER_DRAGON || type == EntityType.WITHER; 25 | } 26 | 27 | @Override 28 | public boolean isEyeInFluid(Player player) { 29 | return player.isEyeInFluid(FluidTags.WATER); 30 | } 31 | 32 | @Override 33 | public RenderType getRenderType() { 34 | return AsteorBarRenderType.RENDER_TYPE; 35 | } 36 | 37 | @Override 38 | public boolean isModLoaded(String modId) { 39 | return FabricLoader.getInstance().isModLoaded(modId); 40 | } 41 | 42 | @Override 43 | public AppleSkinFoodValues getAppleSkinFoodValues(Player player) { 44 | if (!AsteorBar.compatibility.appleskin) { 45 | return null; 46 | } 47 | // if not using third adapter, the game will crash if appleskin is not loaded 48 | return AppleSkinAdapter.getInstance().getAppleSkinFoodValues(player); 49 | } 50 | 51 | @Override 52 | public float getExhaustion(Player player) { 53 | return ((FoodDataMixin) player.getFoodData()).getExhaustionLevel(); 54 | } 55 | 56 | @Override 57 | public void setExhaustion(Player player, float exhaustion) { 58 | ((FoodDataMixin) player.getFoodData()).setExhaustionLevel(exhaustion); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/mixin/EntityMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.render.IHealthBarFeature; 4 | import com.mojang.blaze3d.vertex.PoseStack; 5 | import net.minecraft.client.renderer.SubmitNodeCollector; 6 | import net.minecraft.client.renderer.entity.EntityRenderDispatcher; 7 | import net.minecraft.client.renderer.entity.EntityRenderer; 8 | import net.minecraft.client.renderer.entity.state.EntityRenderState; 9 | import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; 10 | import net.minecraft.client.renderer.state.CameraRenderState; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.Shadow; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | 17 | @Mixin(EntityRenderDispatcher.class) 18 | public abstract class EntityMixin { 19 | @Shadow 20 | public abstract EntityRenderer getRenderer(S entityRenderState); 21 | 22 | @Inject(method = "submit(Lnet/minecraft/client/renderer/entity/state/EntityRenderState;Lnet/minecraft/client/renderer/state/CameraRenderState;DDDLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;)V", 23 | at = @At("TAIL")) 24 | private void submit(S entityRenderState, CameraRenderState cameraRenderState, double x, double y, double z, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CallbackInfo ci) { 25 | if (!(entityRenderState instanceof IHealthBarFeature feat) || feat.asteorBar$getMaxHealth() <= 0 || !(entityRenderState instanceof LivingEntityRenderState)) { 26 | return; 27 | } 28 | var entityRenderer = getRenderer(entityRenderState); 29 | var vec3 = entityRenderer.getRenderOffset(entityRenderState); 30 | poseStack.pushPose(); 31 | poseStack.translate(x + vec3.x(), y + vec3.y(), z + vec3.z()); 32 | com.afoxxvi.asteorbar.entity.EntityRenderer.submit(feat, (LivingEntityRenderState) entityRenderState, poseStack, submitNodeCollector); 33 | poseStack.popPose(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/mixin/EntityMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.render.IHealthBarFeature; 4 | import com.mojang.blaze3d.vertex.PoseStack; 5 | import net.minecraft.client.renderer.SubmitNodeCollector; 6 | import net.minecraft.client.renderer.entity.EntityRenderDispatcher; 7 | import net.minecraft.client.renderer.entity.EntityRenderer; 8 | import net.minecraft.client.renderer.entity.state.EntityRenderState; 9 | import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; 10 | import net.minecraft.client.renderer.state.CameraRenderState; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.Shadow; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | 17 | @Mixin(EntityRenderDispatcher.class) 18 | public abstract class EntityMixin { 19 | @Shadow 20 | public abstract EntityRenderer getRenderer(S entityRenderState); 21 | 22 | @Inject(method = "submit(Lnet/minecraft/client/renderer/entity/state/EntityRenderState;Lnet/minecraft/client/renderer/state/CameraRenderState;DDDLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;)V", 23 | at = @At("TAIL")) 24 | private void submit(S entityRenderState, CameraRenderState cameraRenderState, double x, double y, double z, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CallbackInfo ci) { 25 | if (!(entityRenderState instanceof IHealthBarFeature feat) || feat.asteorBar$getMaxHealth() <= 0 || !(entityRenderState instanceof LivingEntityRenderState)) { 26 | return; 27 | } 28 | var entityRenderer = getRenderer(entityRenderState); 29 | var vec3 = entityRenderer.getRenderOffset(entityRenderState); 30 | poseStack.pushPose(); 31 | poseStack.translate(x + vec3.x(), y + vec3.y(), z + vec3.z()); 32 | com.afoxxvi.asteorbar.entity.EntityRenderer.submit(feat, (LivingEntityRenderState) entityRenderState, poseStack, submitNodeCollector); 33 | poseStack.popPose(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/mixin/EntityMixin.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.mixin; 2 | 3 | import com.afoxxvi.asteorbar.render.IHealthBarFeature; 4 | import com.mojang.blaze3d.vertex.PoseStack; 5 | import net.minecraft.client.renderer.SubmitNodeCollector; 6 | import net.minecraft.client.renderer.entity.EntityRenderDispatcher; 7 | import net.minecraft.client.renderer.entity.EntityRenderer; 8 | import net.minecraft.client.renderer.entity.state.EntityRenderState; 9 | import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; 10 | import net.minecraft.client.renderer.state.CameraRenderState; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.Shadow; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | 17 | @Mixin(EntityRenderDispatcher.class) 18 | public abstract class EntityMixin { 19 | @Shadow 20 | public abstract EntityRenderer getRenderer(S entityRenderState); 21 | 22 | @Inject(method = "submit(Lnet/minecraft/client/renderer/entity/state/EntityRenderState;Lnet/minecraft/client/renderer/state/CameraRenderState;DDDLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;)V", 23 | at = @At("TAIL")) 24 | private void submit(S entityRenderState, CameraRenderState cameraRenderState, double x, double y, double z, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CallbackInfo ci) { 25 | if (!(entityRenderState instanceof IHealthBarFeature feat) || feat.asteorBar$getMaxHealth() <= 0 || !(entityRenderState instanceof LivingEntityRenderState)) { 26 | return; 27 | } 28 | var entityRenderer = getRenderer(entityRenderState); 29 | var vec3 = entityRenderer.getRenderOffset(entityRenderState); 30 | poseStack.pushPose(); 31 | poseStack.translate(x + vec3.x(), y + vec3.y(), z + vec3.z()); 32 | com.afoxxvi.asteorbar.entity.EntityRenderer.submit(feat, (LivingEntityRenderState) entityRenderState, poseStack, submitNodeCollector); 33 | poseStack.popPose(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/listener/NeoForgeEventListener.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.listener; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.key.KeyBinding; 5 | import com.afoxxvi.asteorbar.overlay.NeoforgeGuiRegistry; 6 | import com.afoxxvi.asteorbar.overlay.Overlays; 7 | import net.minecraft.resources.ResourceLocation; 8 | import net.neoforged.api.distmarker.Dist; 9 | import net.neoforged.bus.api.SubscribeEvent; 10 | import net.neoforged.fml.common.EventBusSubscriber; 11 | import net.neoforged.neoforge.client.event.InputEvent; 12 | import net.neoforged.neoforge.client.event.RenderGuiLayerEvent; 13 | import net.neoforged.neoforge.client.gui.VanillaGuiLayers; 14 | 15 | @EventBusSubscriber(modid = AsteorBar.MOD_ID, value = Dist.CLIENT) 16 | public class NeoForgeEventListener { 17 | private static final ResourceLocation THIRST_SATURATION = ResourceLocation.fromNamespaceAndPath("thirst", "saturation_overlay"); 18 | private static final ResourceLocation THIRST_EXHAUSTION = ResourceLocation.fromNamespaceAndPath("thirst", "exhaustion_overlay"); 19 | 20 | @SubscribeEvent 21 | public static void disableVanillaOverlays(RenderGuiLayerEvent.Pre event) { 22 | if (!AsteorBar.config.enableOverlay()) return; 23 | ResourceLocation overlay = event.getName(); 24 | if (overlay == VanillaGuiLayers.PLAYER_HEALTH) { 25 | Overlays.reset(); 26 | NeoforgeGuiRegistry.init(); 27 | } 28 | if (overlay == VanillaGuiLayers.PLAYER_HEALTH) { 29 | event.setCanceled(true); 30 | return; 31 | } 32 | if (overlay == VanillaGuiLayers.FOOD_LEVEL) { 33 | event.setCanceled(true); 34 | return; 35 | } 36 | if (overlay == VanillaGuiLayers.AIR_LEVEL) { 37 | event.setCanceled(true); 38 | return; 39 | } 40 | if (AsteorBar.config.overwriteVanillaExperienceBar() && (overlay == VanillaGuiLayers.CONTEXTUAL_INFO_BAR_BACKGROUND || overlay == VanillaGuiLayers.EXPERIENCE_LEVEL)) { 41 | event.setCanceled(true); 42 | return; 43 | } 44 | if (overlay == VanillaGuiLayers.VEHICLE_HEALTH) { 45 | event.setCanceled(true); 46 | return; 47 | } 48 | if (AsteorBar.config.overwriteVanillaArmorBar() && overlay == VanillaGuiLayers.ARMOR_LEVEL) { 49 | event.setCanceled(true); 50 | return; 51 | } 52 | if (AsteorBar.compatibility.thirst && AsteorBar.config.hookThirstWasTaken() && (overlay.equals(THIRST_SATURATION) || overlay.equals(THIRST_EXHAUSTION))) { 53 | event.setCanceled(true); 54 | return; 55 | } 56 | } 57 | 58 | @SubscribeEvent 59 | public static void handleKeyInput(InputEvent.Key event) { 60 | KeyBinding.handleKeyInput(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/overlay/parts/ExperienceBarOverlay.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import net.minecraft.client.gui.GuiGraphics; 6 | import net.minecraft.world.entity.player.Player; 7 | 8 | public class ExperienceBarOverlay extends SimpleBarOverlay { 9 | int level; 10 | int need; 11 | int has; 12 | 13 | @Override 14 | protected Parameters getParameters(Player player) { 15 | level = player.experienceLevel; 16 | need = player.getXpNeededForNextLevel(); 17 | has = (int) (player.experienceProgress * player.getXpNeededForNextLevel()); 18 | Parameters parameters = new Parameters(); 19 | parameters.fillColor = AsteorBar.config.experienceColor(); 20 | parameters.boundColor = AsteorBar.config.experienceBoundColor(); 21 | parameters.emptyColor = AsteorBar.config.experienceEmptyColor(); 22 | parameters.value = player.experienceProgress; 23 | return parameters; 24 | } 25 | 26 | @Override 27 | protected void drawDecorations(GuiGraphics guiGraphics, int left, int top, int right, int bottom, Parameters parameters, boolean flip) { 28 | super.drawDecorations(guiGraphics, left, top, right, bottom, parameters, flip); 29 | int innerWidth = right - left - 2; 30 | int textureWidth = Math.min(179, Math.max(0, (innerWidth + 5) / 10 - 1) * 10 + 9); 31 | drawTextureFillColor(guiGraphics, left + 1, top, innerWidth, 5, 10, Y_EXPERIENCE_DECORATION, textureWidth, 5, AsteorBar.config.experienceColor()); 32 | if (AsteorBar.config.displayExperienceLevel()) { 33 | int x = (right + left) / 2; 34 | int y = top - 2; 35 | Overlays.addStringRender(x, y, 0x80FF20, String.valueOf(level), Overlays.ALIGN_CENTER, false, true, 0); 36 | } 37 | if (AsteorBar.config.displayExperienceProgress()) { 38 | int x, y; 39 | int len = (right - left) / 2; 40 | x = left + len; 41 | y = top - 2; 42 | boolean inside = len < 180; 43 | if (x >= 0 && y >= 0) { 44 | if (inside) { 45 | Overlays.addStringRender(x - len + 2, y, 0xFFFFFF, String.valueOf(has), Overlays.ALIGN_LEFT, true); 46 | Overlays.addStringRender(x + len - 2, y, 0xFFFFFF, String.valueOf(need), Overlays.ALIGN_RIGHT, true); 47 | } else { 48 | Overlays.addStringRender(x - len, y, 0xFFFFFF, String.valueOf(has), Overlays.ALIGN_RIGHT, true); 49 | Overlays.addStringRender(x + len, y, 0xFFFFFF, String.valueOf(need), Overlays.ALIGN_LEFT, true); 50 | } 51 | } 52 | } 53 | } 54 | 55 | @Override 56 | protected boolean shouldRender(Player player) { 57 | return true; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.utils; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | 5 | public class Utils { 6 | public static String formatNumber(double val) { 7 | if (val >= AsteorBar.config.hideDecimalWhenEqualOrMoreThan()) { 8 | return String.valueOf((int) val); 9 | } 10 | String str = String.format("%.1f", val); 11 | if (str.endsWith(".0")) { 12 | str = str.substring(0, str.length() - 2); 13 | } 14 | return str; 15 | } 16 | 17 | public static int parseHexColor(String color) { 18 | int value = 0; 19 | for (int i = 0; i < color.length(); i++) { 20 | if (i == 0 && color.charAt(i) == '#') continue; 21 | value <<= 4; 22 | char c = color.charAt(i); 23 | if (c >= '0' && c <= '9') { 24 | value += c - '0'; 25 | } else if (c >= 'A' && c <= 'F') { 26 | value += c - 'A' + 10; 27 | } else if (c >= 'a' && c <= 'f') { 28 | value += c - 'a' + 10; 29 | } 30 | } 31 | return value; 32 | } 33 | 34 | public static int mixColor(int color1, int color2, double ratio) { 35 | short r = (short) ((color1 >> 16 & 0xFF) * ratio + (color2 >> 16 & 0xFF) * (1 - ratio)); 36 | short g = (short) ((color1 >> 8 & 0xFF) * ratio + (color2 >> 8 & 0xFF) * (1 - ratio)); 37 | short b = (short) ((color1 & 0xFF) * ratio + (color2 & 0xFF) * (1 - ratio)); 38 | short a = (short) ((color1 >> 24 & 0xFF) * ratio + (color2 >> 24 & 0xFF) * (1 - ratio)); 39 | return (a << 24) | (r << 16) | (g << 8) | b; 40 | } 41 | 42 | public static int modifyColor(int color, int multi) { 43 | short r = (short) ((color >> 16 & 0xFF) * multi / 255); 44 | short g = (short) ((color >> 8 & 0xFF) * multi / 255); 45 | short b = (short) ((color & 0xFF) * multi / 255); 46 | short a = (short) ((color >> 24 & 0xFF)); 47 | return (a << 24) | (r << 16) | (g << 8) | b; 48 | } 49 | 50 | /** 51 | * Parse color from string. 52 | * Decimal format: "16711680" 53 | * Hex format: "#FF0000" or "0xFF0000" 54 | */ 55 | public static int parseColor(String color) { 56 | try { 57 | if (color.startsWith("#") || color.startsWith("0x") || color.startsWith("0X")) { 58 | return parseHexColor(color); 59 | } else { 60 | return Integer.parseInt(color); 61 | } 62 | } catch (NumberFormatException e) { 63 | return 0xFFFFFFFF; 64 | } 65 | } 66 | 67 | public static int modifyAlpha(int color, float alpha) { 68 | if (alpha == 0) return color; 69 | int alphaInt = (int) (alpha * 255); 70 | return (color & 0x00ffffff) | (alphaInt << 24); 71 | } 72 | 73 | public static int getWhiteAlpha(float alpha) { 74 | int alphaInt = (int) (alpha * 255); 75 | return (alphaInt << 24) | 0x00ffffff; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/overlay/parts/FoodLevelOverlay.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.utils.Utils; 5 | import net.minecraft.client.gui.GuiGraphics; 6 | import net.minecraft.world.effect.MobEffects; 7 | import net.minecraft.world.entity.player.Player; 8 | import net.minecraft.world.food.FoodData; 9 | 10 | @SuppressWarnings("DuplicatedCode") 11 | public class FoodLevelOverlay extends SimpleBarOverlay { 12 | private int foodBlinkTime = 0; 13 | float saturation; 14 | float exhaustion; 15 | 16 | @Override 17 | protected Parameters getParameters(Player player) { 18 | FoodData stats = player.getFoodData(); 19 | int level = stats.getFoodLevel(); 20 | saturation = stats.getSaturationLevel(); 21 | exhaustion = AsteorBar.platformAdapter.getExhaustion(player); 22 | int foodType = AsteorBar.config.foodColorNormal(); 23 | if (player.hasEffect(MobEffects.HUNGER)) { 24 | foodType = AsteorBar.config.foodColorHunger(); 25 | } 26 | if (AsteorBar.config.enableFoodBlink()) { 27 | if (player.getFoodData().getSaturationLevel() <= 0.0F && tick % (Math.max(4, level) * 3L + 1) == 0) { 28 | foodBlinkTime = 2; 29 | } 30 | if (foodBlinkTime > 0) { 31 | foodBlinkTime--; 32 | } 33 | } 34 | Parameters parameters = new Parameters(); 35 | if (level <= 4) { 36 | applyShakeEffect(parameters, level); 37 | } 38 | parameters.boundColor = foodBlinkTime > 0 ? AsteorBar.config.foodBoundColorBlink() : AsteorBar.config.foodBoundColor(); 39 | parameters.emptyColor = AsteorBar.config.foodEmptyColor(); 40 | if (AsteorBar.config.displayFoodText()) { 41 | parameters.centerText = Utils.formatNumber(level) + "/" + Utils.formatNumber(AsteorBar.config.fullFoodLevelValue()); 42 | parameters.centerColor = 0xFFFFFF; 43 | } 44 | parameters.value = (double) level / AsteorBar.config.fullFoodLevelValue(); 45 | parameters.fillColor = foodType; 46 | if (AsteorBar.config.displaySaturation()) { 47 | parameters.boundValue = saturation / AsteorBar.config.fullSaturationValue(); 48 | parameters.boundFillColor = AsteorBar.config.saturationColor(); 49 | } 50 | return parameters; 51 | } 52 | 53 | @Override 54 | protected void drawDecorations(GuiGraphics guiGraphics, int left, int top, int right, int bottom, Parameters parameters, boolean flip) { 55 | super.drawDecorations(guiGraphics, left, top, right, bottom, parameters, flip); 56 | int innerWidth = right - left - 2; 57 | if (AsteorBar.config.displayExhaustion()) { 58 | int exhaustionWidth = (int) (innerWidth * (Math.min(AsteorBar.config.fullExhaustionValue(), exhaustion) / AsteorBar.config.fullExhaustionValue())); 59 | drawTextureFillFlip(guiGraphics, left + 1, top, right - 1, exhaustionWidth, 5, 10, Y_FOOD_EXHAUSTION_FILL, FILL_FULL_WIDTH_LONG, flip); 60 | } 61 | } 62 | 63 | @Override 64 | protected boolean shouldRender(Player player) { 65 | return true; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/overlay/parts/ThermooOverlays.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import net.minecraft.client.gui.GuiGraphics; 5 | import net.minecraft.world.entity.player.Player; 6 | 7 | public class ThermooOverlays { 8 | public static class Independent extends SimpleBarOverlay { 9 | @Override 10 | protected Parameters getParameters(Player player) { 11 | var parameters = new Parameters(); 12 | var value = player.thermoo$getTemperatureScale(); 13 | if (value > 0) { 14 | parameters.value = value; 15 | parameters.capacity = 1.0; 16 | parameters.fillColor = 0xffdb6511; 17 | parameters.fillColor2 = 0xfff4de81; 18 | parameters.boundColor = 0xffb94d00; 19 | } else if (value < 0) { 20 | parameters.value = -value; 21 | parameters.capacity = 1.0; 22 | parameters.fillColor = 0xff4cbad8; 23 | parameters.fillColor2 = 0xff80e5ef; 24 | parameters.boundColor = 0xff073f5c; 25 | } else { 26 | return null; 27 | } 28 | return parameters; 29 | } 30 | 31 | @Override 32 | protected boolean shouldRender(Player player) { 33 | return AsteorBar.compatibility.thermoo && AsteorBar.config.hookThermoo(); 34 | } 35 | 36 | @Override 37 | protected boolean isLeftSide() { 38 | return true; 39 | } 40 | } 41 | 42 | public static class Bound implements SimpleBarOverlay.Layer { 43 | private final SimpleBound simpleBound = new SimpleBound(); 44 | 45 | @Override 46 | public void drawLayer(Player player, GuiGraphics guiGraphics, int left, int top, int right, int bottom, SimpleBarOverlay.Parameters parameters, boolean flip) { 47 | var parameters2 = simpleBound.getParameters(player); 48 | simpleBound.draw(guiGraphics, left, top, right, bottom, parameters2, flip); 49 | } 50 | } 51 | 52 | public static class SimpleBound extends SimpleBarOverlay { 53 | @Override 54 | protected Parameters getParameters(Player player) { 55 | var parameters = new Parameters(); 56 | var value = player.thermoo$getTemperatureScale(); 57 | if (value > 0) { 58 | parameters.boundValue = value; 59 | parameters.boundCapacity = 1.0; 60 | parameters.boundFillColor = 0xffdb6511; 61 | parameters.boundColor2 = 0xffb94d00; 62 | parameters.boundColor = 0xffd28108; 63 | } else if (value < 0) { 64 | parameters.boundValue = -value; 65 | parameters.boundCapacity = 1.0; 66 | parameters.boundFillColor = 0xff4cbad8; 67 | parameters.boundColor2 = 0xff073f5c; 68 | parameters.boundColor = 0xff045c89; 69 | } else { 70 | return null; 71 | } 72 | return parameters; 73 | } 74 | 75 | @Override 76 | protected boolean shouldRender(Player player) { 77 | return AsteorBar.compatibility.thermoo && AsteorBar.config.hookThermoo(); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/overlay/parts/ToughAsNailsOverlay.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.RenderGui; 5 | import com.afoxxvi.asteorbar.utils.Utils; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.world.entity.player.Player; 8 | import toughasnails.api.potion.TANEffects; 9 | import toughasnails.api.thirst.IThirst; 10 | import toughasnails.api.thirst.ThirstHelper; 11 | import toughasnails.init.ModConfig; 12 | import toughasnails.temperature.TemperatureOverlayRenderer; 13 | 14 | public class ToughAsNailsOverlay extends SimpleBarOverlay { 15 | private int thirstBlinkTime = 0; 16 | private float exhaustion; 17 | 18 | @Override 19 | protected Parameters getParameters(Player player) { 20 | var parameters = new Parameters(); 21 | IThirst thirst = ThirstHelper.getThirst(player); 22 | int level = thirst.getThirst(); 23 | float hydration = thirst.getHydration(); 24 | exhaustion = thirst.getExhaustion(); 25 | int thirstColor = 0xff1c5ee4; 26 | if (player.hasEffect(TANEffects.THIRST)) { 27 | thirstColor = 0xff76db4c; 28 | } 29 | if (level <= 4) { 30 | parameters.verticalShift = FoodLevelOverlay.SHIFT[tick / (level + 1) % FoodLevelOverlay.SHIFT.length]; 31 | } 32 | if (AsteorBar.config.enableFoodBlink()) { 33 | if (hydration <= 0.0F && tick % (Math.max(4, level) * 3L + 1) == 0) { 34 | thirstBlinkTime = 2; 35 | } 36 | if (thirstBlinkTime > 0) { 37 | thirstBlinkTime--; 38 | } 39 | } 40 | boolean highlight = thirstBlinkTime > 0; 41 | parameters.boundColor = highlight ? Utils.mixColor(0xffffffff, thirstColor, 0.2) : Utils.mixColor(0xff000000, thirstColor, 0.5); 42 | parameters.emptyColor = AsteorBar.config.foodEmptyColor(); 43 | parameters.fillColor = thirstColor; 44 | parameters.capacity = 20; 45 | parameters.value = level; 46 | if (AsteorBar.config.displaySaturation()) { 47 | parameters.boundFillColor = 0xff2d65d6; 48 | parameters.boundValue = hydration; 49 | parameters.boundCapacity = 10; 50 | } 51 | if (AsteorBar.config.displayFoodText()) { 52 | parameters.centerText = Utils.formatNumber(level) + "/" + Utils.formatNumber(20); 53 | parameters.centerColor = 0xFFFFFF; 54 | } 55 | return parameters; 56 | } 57 | 58 | @Override 59 | protected boolean shouldRender(Player player) { 60 | return AsteorBar.compatibility.toughAsNails && AsteorBar.config.hookToughAsNails() && ThirstHelper.isThirstEnabled(); 61 | } 62 | 63 | 64 | @Override 65 | protected void drawDecorations(GuiGraphics guiGraphics, int left, int top, int right, int bottom, Parameters parameters, boolean flip) { 66 | super.drawDecorations(guiGraphics, left, top, right, bottom, parameters, flip); 67 | int innerWidth = right - left - 2; 68 | if (AsteorBar.config.displayExhaustion()) { 69 | var cap = ModConfig.thirst.thirstExhaustionThreshold; 70 | int exhaustionWidth = (int) (innerWidth * (Math.min(cap, exhaustion) / cap)); 71 | drawTextureFillFlip(guiGraphics, left + 1, top, right - 1, exhaustionWidth, 5, 10, Y_FOOD_EXHAUSTION_FILL, FILL_FULL_WIDTH_LONG, flip); 72 | } 73 | } 74 | 75 | @Override 76 | public void renderOverlay(RenderGui gui, GuiGraphics guiGraphics, float partialTick, int screenWidth, int screenHeight) { 77 | if (!AsteorBar.compatibility.toughAsNails || !AsteorBar.config.hookToughAsNails()) return; 78 | TemperatureOverlayRenderer.renderTemperature(guiGraphics, partialTick, screenWidth, screenHeight); 79 | super.renderOverlay(gui, guiGraphics, partialTick, screenWidth, screenHeight); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/overlay/parts/ToughAsNailsOverlay.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import com.afoxxvi.asteorbar.overlay.RenderGui; 6 | import com.afoxxvi.asteorbar.utils.Utils; 7 | import com.mojang.blaze3d.systems.RenderSystem; 8 | import net.minecraft.client.gui.GuiGraphics; 9 | import net.minecraft.world.entity.player.Player; 10 | import toughasnails.api.potion.TANEffects; 11 | import toughasnails.api.thirst.IThirst; 12 | import toughasnails.api.thirst.ThirstHelper; 13 | import toughasnails.init.ModConfig; 14 | import toughasnails.temperature.TemperatureOverlayRenderer; 15 | 16 | public class ToughAsNailsOverlay extends SimpleBarOverlay { 17 | private int thirstBlinkTime = 0; 18 | private float exhaustion; 19 | 20 | @Override 21 | protected Parameters getParameters(Player player) { 22 | var parameters = new Parameters(); 23 | IThirst thirst = ThirstHelper.getThirst(player); 24 | int level = thirst.getThirst(); 25 | float hydration = thirst.getHydration(); 26 | exhaustion = thirst.getExhaustion(); 27 | int thirstColor = 0xff1c5ee4; 28 | if (player.hasEffect(TANEffects.THIRST)) { 29 | thirstColor = 0xff76db4c; 30 | } 31 | if (level <= 4) { 32 | parameters.verticalShift = FoodLevelOverlay.SHIFT[tick / (level + 1) % FoodLevelOverlay.SHIFT.length]; 33 | } 34 | if (AsteorBar.config.enableFoodBlink()) { 35 | if (hydration <= 0.0F && tick % (Math.max(4, level) * 3L + 1) == 0) { 36 | thirstBlinkTime = 2; 37 | } 38 | if (thirstBlinkTime > 0) { 39 | thirstBlinkTime--; 40 | } 41 | } 42 | boolean highlight = thirstBlinkTime > 0; 43 | parameters.boundColor = highlight ? Utils.mixColor(0xffffffff, thirstColor, 0.2) : Utils.mixColor(0xff000000, thirstColor, 0.5); 44 | parameters.emptyColor = AsteorBar.config.foodEmptyColor(); 45 | parameters.fillColor = thirstColor; 46 | parameters.capacity = 20; 47 | parameters.value = level; 48 | if (AsteorBar.config.displaySaturation()) { 49 | parameters.boundFillColor = 0xff2d65d6; 50 | parameters.boundValue = hydration; 51 | parameters.boundCapacity = 10; 52 | } 53 | if (AsteorBar.config.displayFoodText()) { 54 | parameters.centerText = Utils.formatNumber(level) + "/" + Utils.formatNumber(20); 55 | parameters.centerColor = 0xFFFFFF; 56 | } 57 | return parameters; 58 | } 59 | 60 | @Override 61 | protected boolean shouldRender(Player player) { 62 | return AsteorBar.compatibility.toughAsNails && AsteorBar.config.hookToughAsNails() && ThirstHelper.isThirstEnabled(); 63 | } 64 | 65 | 66 | @Override 67 | protected void drawDecorations(GuiGraphics guiGraphics, int left, int top, int right, int bottom, Parameters parameters, boolean flip) { 68 | super.drawDecorations(guiGraphics, left, top, right, bottom, parameters, flip); 69 | int innerWidth = right - left - 2; 70 | if (AsteorBar.config.displayExhaustion()) { 71 | var cap = ModConfig.thirst.thirstExhaustionThreshold; 72 | int exhaustionWidth = (int) (innerWidth * (Math.min(cap, exhaustion) / cap)); 73 | drawTextureFillFlip(guiGraphics, left + 1, top, right - 1, exhaustionWidth, 5, 10, Y_FOOD_EXHAUSTION_FILL, FILL_FULL_WIDTH_LONG, flip); 74 | } 75 | } 76 | 77 | @Override 78 | public void renderOverlay(RenderGui gui, GuiGraphics guiGraphics, float partialTick, int screenWidth, int screenHeight) { 79 | if (!AsteorBar.compatibility.toughAsNails || !AsteorBar.config.hookToughAsNails()) return; 80 | TemperatureOverlayRenderer.renderTemperature(guiGraphics, partialTick, screenWidth, screenHeight); 81 | super.renderOverlay(gui, guiGraphics, partialTick, screenWidth, screenHeight); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/overlay/parts/ToughAsNailsOverlay.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import com.afoxxvi.asteorbar.overlay.RenderGui; 6 | import com.afoxxvi.asteorbar.utils.Utils; 7 | import com.mojang.blaze3d.systems.RenderSystem; 8 | import net.minecraft.client.gui.GuiGraphics; 9 | import net.minecraft.world.entity.player.Player; 10 | import toughasnails.api.potion.TANEffects; 11 | import toughasnails.api.thirst.IThirst; 12 | import toughasnails.api.thirst.ThirstHelper; 13 | import toughasnails.init.ModConfig; 14 | import toughasnails.temperature.TemperatureOverlayRenderer; 15 | 16 | public class ToughAsNailsOverlay extends SimpleBarOverlay { 17 | private int thirstBlinkTime = 0; 18 | private float exhaustion; 19 | 20 | @Override 21 | protected Parameters getParameters(Player player) { 22 | var parameters = new Parameters(); 23 | IThirst thirst = ThirstHelper.getThirst(player); 24 | int level = thirst.getThirst(); 25 | float hydration = thirst.getHydration(); 26 | exhaustion = thirst.getExhaustion(); 27 | int thirstColor = 0xff1c5ee4; 28 | if (player.hasEffect(TANEffects.THIRST)) { 29 | thirstColor = 0xff76db4c; 30 | } 31 | if (level <= 4) { 32 | parameters.verticalShift = FoodLevelOverlay.SHIFT[tick / (level + 1) % FoodLevelOverlay.SHIFT.length]; 33 | } 34 | if (AsteorBar.config.enableFoodBlink()) { 35 | if (hydration <= 0.0F && tick % (Math.max(4, level) * 3L + 1) == 0) { 36 | thirstBlinkTime = 2; 37 | } 38 | if (thirstBlinkTime > 0) { 39 | thirstBlinkTime--; 40 | } 41 | } 42 | boolean highlight = thirstBlinkTime > 0; 43 | parameters.boundColor = highlight ? Utils.mixColor(0xffffffff, thirstColor, 0.2) : Utils.mixColor(0xff000000, thirstColor, 0.5); 44 | parameters.emptyColor = AsteorBar.config.foodEmptyColor(); 45 | parameters.fillColor = thirstColor; 46 | parameters.capacity = 20; 47 | parameters.value = level; 48 | if (AsteorBar.config.displaySaturation()) { 49 | parameters.boundFillColor = 0xff2d65d6; 50 | parameters.boundValue = hydration; 51 | parameters.boundCapacity = 10; 52 | } 53 | if (AsteorBar.config.displayFoodText()) { 54 | parameters.centerText = Utils.formatNumber(level) + "/" + Utils.formatNumber(20); 55 | parameters.centerColor = 0xFFFFFF; 56 | } 57 | return parameters; 58 | } 59 | 60 | @Override 61 | protected boolean shouldRender(Player player) { 62 | return AsteorBar.compatibility.toughAsNails && AsteorBar.config.hookToughAsNails() && ThirstHelper.isThirstEnabled(); 63 | } 64 | 65 | 66 | @Override 67 | protected void drawDecorations(GuiGraphics guiGraphics, int left, int top, int right, int bottom, Parameters parameters, boolean flip) { 68 | super.drawDecorations(guiGraphics, left, top, right, bottom, parameters, flip); 69 | int innerWidth = right - left - 2; 70 | if (AsteorBar.config.displayExhaustion()) { 71 | var cap = ModConfig.thirst.thirstExhaustionThreshold; 72 | int exhaustionWidth = (int) (innerWidth * (Math.min(cap, exhaustion) / cap)); 73 | drawTextureFillFlip(guiGraphics, left + 1, top, right - 1, exhaustionWidth, 5, 10, Y_FOOD_EXHAUSTION_FILL, FILL_FULL_WIDTH_LONG, flip); 74 | } 75 | } 76 | 77 | @Override 78 | public void renderOverlay(RenderGui gui, GuiGraphics guiGraphics, float partialTick, int screenWidth, int screenHeight) { 79 | if (!AsteorBar.compatibility.toughAsNails || !AsteorBar.config.hookToughAsNails()) return; 80 | TemperatureOverlayRenderer.renderTemperature(guiGraphics, partialTick, screenWidth, screenHeight); 81 | super.renderOverlay(gui, guiGraphics, partialTick, screenWidth, screenHeight); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/AsteorBar.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar; 2 | 3 | 4 | import com.afoxxvi.asteorbar.config.ConfigAdapter; 5 | import com.afoxxvi.asteorbar.config.DefaultConfigAdapter; 6 | import com.afoxxvi.asteorbar.overlay.parts.compat.AppleSkinCompat; 7 | import com.afoxxvi.asteorbar.utils.PlatformAdapter; 8 | import net.minecraft.client.renderer.RenderType; 9 | import net.minecraft.world.entity.LivingEntity; 10 | import net.minecraft.world.entity.player.Player; 11 | import org.slf4j.Logger; 12 | 13 | public class AsteorBar { 14 | public static final String MOD_ID = "asteorbar"; 15 | public static final String MOD_NAME = "AsteorBar"; 16 | public static ConfigAdapter config = new DefaultConfigAdapter(); 17 | public static Compatibility compatibility = new Compatibility(); 18 | 19 | public static PlatformAdapter platformAdapter = new PlatformAdapter() { 20 | @Override 21 | public Logger getLogger() { 22 | return null; 23 | } 24 | 25 | @Override 26 | public boolean isBoss(LivingEntity livingEntity) { 27 | return false; 28 | } 29 | 30 | @Override 31 | public boolean isEyeInFluid(Player player) { 32 | return false; 33 | } 34 | 35 | @Override 36 | public RenderType getRenderType() { 37 | return RenderType.solid(); 38 | } 39 | 40 | @Override 41 | public boolean isModLoaded(String modId) { 42 | return false; 43 | } 44 | 45 | @Override 46 | public AppleSkinFoodValues getAppleSkinFoodValues(Player player) { 47 | return new AppleSkinFoodValues(0, 0, 0); 48 | } 49 | 50 | @Override 51 | public float getExhaustion(Player player) { 52 | return 0; 53 | } 54 | 55 | @Override 56 | public void setExhaustion(Player player, float exhaustion) { 57 | 58 | } 59 | }; 60 | 61 | public static class Compatibility { 62 | private boolean initialized = false; 63 | public boolean toughAsNails = false; 64 | public boolean thirst = false; 65 | public boolean mekanism = false; 66 | public boolean dehydration = false; 67 | public boolean parcool = false; 68 | public boolean ironsSpellbooks = false; 69 | public boolean feathers = false; 70 | public boolean appleskin = false; 71 | public boolean superiorshields = false; 72 | public boolean vampirism = false; 73 | public boolean lightshield = false; 74 | public boolean botania = false; 75 | public boolean origins = false; 76 | public boolean tfc = false; 77 | public boolean arsNouveau = false; 78 | public boolean apoli = false; 79 | public boolean thermoo = false; 80 | public boolean mealApi = false; 81 | 82 | 83 | public void init() { 84 | if (initialized) { 85 | return; 86 | } 87 | toughAsNails = platformAdapter.isModLoaded("toughasnails"); 88 | thirst = platformAdapter.isModLoaded("thirst"); 89 | mekanism = platformAdapter.isModLoaded("mekanism"); 90 | dehydration = platformAdapter.isModLoaded("dehydration"); 91 | parcool = platformAdapter.isModLoaded("parcool"); 92 | ironsSpellbooks = platformAdapter.isModLoaded("irons_spellbooks"); 93 | feathers = platformAdapter.isModLoaded("feathers"); 94 | appleskin = platformAdapter.isModLoaded("appleskin"); 95 | superiorshields = platformAdapter.isModLoaded("superiorshields"); 96 | vampirism = platformAdapter.isModLoaded("vampirism"); 97 | lightshield = platformAdapter.isModLoaded("lightshield"); 98 | botania = platformAdapter.isModLoaded("botania"); 99 | origins = platformAdapter.isModLoaded("origins"); 100 | tfc = platformAdapter.isModLoaded("tfc"); 101 | arsNouveau = platformAdapter.isModLoaded("ars_nouveau"); 102 | apoli = platformAdapter.isModLoaded("apoli"); 103 | thermoo = platformAdapter.isModLoaded("thermoo"); 104 | mealApi = platformAdapter.isModLoaded("mealapi"); 105 | AppleSkinCompat.init(); 106 | initialized = true; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/overlay/parts/compat/AppleSkinCompat.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts.compat; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.Overlays; 5 | import com.afoxxvi.asteorbar.overlay.parts.PlayerHealthOverlay; 6 | import com.afoxxvi.asteorbar.overlay.parts.SimpleBarOverlay; 7 | import net.minecraft.world.entity.player.Player; 8 | import net.minecraft.world.food.FoodData; 9 | 10 | import java.util.function.BiConsumer; 11 | 12 | public class AppleSkinCompat { 13 | private static final BiConsumer APPLE_SKIN_HEALTH_POST_PROCESSOR = (player, parameters) -> { 14 | float maxHealth = player.getMaxHealth(); 15 | float health = player.getHealth(); 16 | float absorb = player.getAbsorptionAmount(); 17 | double healthIncrement = 0; 18 | if (AsteorBar.compatibility.appleskin) { 19 | final var foodValues = AsteorBar.platformAdapter.getAppleSkinFoodValues(player); 20 | if (foodValues != null) { 21 | healthIncrement = foodValues.healthIncrement(); 22 | } 23 | healthIncrement = Math.min(healthIncrement, maxHealth - health); 24 | } 25 | int i = AsteorBar.config.displayAbsorptionMethod(); 26 | if (AsteorBar.config.enableStackHealthBar()) { 27 | i = PlayerHealthOverlay.ABSORPTION_MODE_BOUND; 28 | } 29 | if (i == PlayerHealthOverlay.ABSORPTION_MODE_TOGETHER) { 30 | double full = maxHealth + absorb; 31 | parameters.valueIncrement = healthIncrement / full; 32 | } else { 33 | if (AsteorBar.config.enableStackHealthBar()) { 34 | final int unit = AsteorBar.config.fullHealthValue(); 35 | if (healthIncrement > 0 && health < maxHealth) { 36 | if ((health % unit) + healthIncrement >= unit) { 37 | parameters.valueIncrement = 1 - parameters.value; 38 | parameters.secondValueIncrement = (parameters.value + healthIncrement / unit) % 1; 39 | } else { 40 | healthIncrement = Math.min(healthIncrement, maxHealth - health); 41 | parameters.valueIncrement = healthIncrement / unit; 42 | } 43 | } 44 | } else { 45 | if (healthIncrement > 0 && health < maxHealth) { 46 | parameters.valueIncrement = Math.min(maxHealth - health, healthIncrement) / maxHealth; 47 | } 48 | } 49 | } 50 | }; 51 | 52 | private static final BiConsumer APPLE_SKIN_FOOD_POST_PROCESSOR = (player, parameters) -> { 53 | FoodData stats = player.getFoodData(); 54 | int level = stats.getFoodLevel(); 55 | float saturation = stats.getSaturationLevel(); 56 | int foodIncrement = 0; 57 | float saturationIncrement = 0F; 58 | if (AsteorBar.compatibility.appleskin) { 59 | final var foodValues = AsteorBar.platformAdapter.getAppleSkinFoodValues(player); 60 | if (foodValues != null) { 61 | foodIncrement = foodValues.hungerIncrement(); 62 | saturationIncrement = foodValues.saturationIncrement(); 63 | } 64 | } 65 | if (foodIncrement > 0 && level < AsteorBar.config.fullFoodLevelValue()) { 66 | final var fullFood = AsteorBar.config.fullFoodLevelValue(); 67 | parameters.valueIncrement = Math.min(fullFood - level, (double) foodIncrement) / fullFood; 68 | } 69 | if (AsteorBar.config.displaySaturation()) { 70 | if (foodIncrement > 0 && saturationIncrement > 0 && saturation < AsteorBar.config.fullSaturationValue()) { 71 | final var fullSaturation = AsteorBar.config.fullSaturationValue(); 72 | parameters.boundValueIncrement = Math.min(fullSaturation - saturation, saturationIncrement) / fullSaturation; 73 | } 74 | } 75 | }; 76 | 77 | private static boolean initialized = false; 78 | 79 | public static void init() { 80 | if (initialized) { 81 | return; 82 | } 83 | initialized = true; 84 | if (!AsteorBar.compatibility.appleskin) { 85 | return; 86 | } 87 | Overlays.PLAYER_HEALTH.addParametersProcessor("afoxxvi:apple_skin", APPLE_SKIN_HEALTH_POST_PROCESSOR); 88 | Overlays.FOOD_LEVEL.addParametersProcessor("afoxxvi:apple_skin", APPLE_SKIN_FOOD_POST_PROCESSOR); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Forge/src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | # This is an example mods.toml file. It contains the data relating to the loading mods. 2 | # There are several mandatory fields (#mandatory), and many more that are optional (#optional). 3 | # The overall format is standard TOML format, v0.5.0. 4 | # Note that there are a couple of TOML lists in this file. 5 | # Find more information on toml format here: https://github.com/toml-lang/toml 6 | # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml 7 | modLoader="javafml" #mandatory 8 | # A version range to match for said mod loader - for regular FML @Mod it will be the forge version 9 | loaderVersion="${loader_version_range}" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. 10 | # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. 11 | # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. 12 | license="${mod_license}" 13 | # A URL to refer people to when problems occur with this mod 14 | #issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional 15 | # A list of mods - how many allowed here is determined by the individual mod loader 16 | [[mods]] #mandatory 17 | # The modid of the mod 18 | modId="${mod_id}" #mandatory 19 | # The version number of the mod 20 | version="${mod_version}" #mandatory 21 | # A display name for the mod 22 | displayName="${mod_name}" #mandatory 23 | # A URL to query for updates for this mod. See the JSON update specification https://docs.minecraftforge.net/en/latest/misc/updatechecker/ 24 | #updateJSONURL="https://change.me.example.invalid/updates.json" #optional 25 | # A URL for the "homepage" for this mod, displayed in the mod UI 26 | #displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional 27 | # A file name (in the root of the mod JAR) containing a logo for display 28 | #logoFile="asteorbar.png" #optional 29 | # A text field displayed in the mod UI 30 | #credits="Thanks for this example mod goes to Java" #optional 31 | # A text field displayed in the mod UI 32 | authors="${mod_authors}" #optional 33 | # Display Test controls the display for your mod in the server connection screen 34 | # MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod. 35 | # IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod. 36 | # IGNORE_ALL_VERSION means that your mod will not cause a red X if it's present on the client or the server. This is a special case and should only be used if your mod has no server component. 37 | # NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value. 38 | # IMPORTANT NOTE: this is NOT an instruction as to which environments (CLIENT or DEDICATED SERVER) your mod loads on. Your mod should load (and maybe do nothing!) whereever it finds itself. 39 | #displayTest="MATCH_VERSION" # MATCH_VERSION is the default if nothing is specified (#optional) 40 | 41 | # The description text for the mod (multi line!) (#mandatory) 42 | description='''${mod_description}''' 43 | # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. 44 | [[dependencies.${mod_id}]] #optional 45 | # the modid of the dependency 46 | modId="forge" #mandatory 47 | # Does this dependency have to exist - if not, ordering below must be specified 48 | mandatory=true #mandatory 49 | # The version range of the dependency 50 | versionRange="${forge_version_range}" #mandatory 51 | # An ordering relationship for the dependency - BEFORE or AFTER required if the dependency is not mandatory 52 | # BEFORE - This mod is loaded BEFORE the dependency 53 | # AFTER - This mod is loaded AFTER the dependency 54 | ordering="NONE" 55 | # Side this dependency is applied on - BOTH, CLIENT, or SERVER 56 | side="BOTH"# Here's another dependency 57 | [[dependencies.${mod_id}]] 58 | modId="minecraft" 59 | mandatory=true 60 | # This version range declares a minimum of the current minecraft version up to but not including the next major version 61 | versionRange="${minecraft_version_range}" 62 | ordering="NONE" 63 | side="BOTH" 64 | 65 | [[mixins]] 66 | config="asteorbar.mixins.json" -------------------------------------------------------------------------------- /NeoForge/src/main/resources/META-INF/neoforge.mods.toml: -------------------------------------------------------------------------------- 1 | # This is an example neoforge.mods.toml file. It contains the data relating to the loading mods. 2 | # There are several mandatory fields (#mandatory), and many more that are optional (#optional). 3 | # The overall format is standard TOML format, v0.5.0. 4 | # Note that there are a couple of TOML lists in this file. 5 | # Find more information on toml format here: https://github.com/toml-lang/toml 6 | # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml 7 | modLoader="javafml" #mandatory 8 | # A version range to match for said mod loader - for regular FML @Mod it will be the the FML version. This is currently 47. 9 | loaderVersion="${loader_version_range}" #mandatory 10 | # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. 11 | # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. 12 | license="${mod_license}" 13 | # A URL to refer people to when problems occur with this mod 14 | #issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional 15 | # A list of mods - how many allowed here is determined by the individual mod loader 16 | [[mods]] #mandatory 17 | # The modid of the mod 18 | modId="${mod_id}" #mandatory 19 | # The version number of the mod 20 | version="${mod_version}" #mandatory 21 | # A display name for the mod 22 | displayName="${mod_name}" #mandatory 23 | # A URL to query for updates for this mod. See the JSON update specification https://docs.neoforged.net/docs/misc/updatechecker/ 24 | #updateJSONURL="https://change.me.example.invalid/updates.json" #optional 25 | # A URL for the "homepage" for this mod, displayed in the mod UI 26 | #displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional 27 | # A file name (in the root of the mod JAR) containing a logo for display 28 | #logoFile="examplemod.png" #optional 29 | # A text field displayed in the mod UI 30 | #credits="" #optional 31 | # A text field displayed in the mod UI 32 | authors="${mod_authors}" #optional 33 | # Display Test controls the display for your mod in the server connection screen 34 | # MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod. 35 | # IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod. 36 | # IGNORE_ALL_VERSION means that your mod will not cause a red X if it's present on the client or the server. This is a special case and should only be used if your mod has no server component. 37 | # NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value. 38 | # IMPORTANT NOTE: this is NOT an instruction as to which environments (CLIENT or DEDICATED SERVER) your mod loads on. Your mod should load (and maybe do nothing!) whereever it finds itself. 39 | #displayTest="MATCH_VERSION" # MATCH_VERSION is the default if nothing is specified (#optional) 40 | 41 | # The description text for the mod (multi line!) (#mandatory) 42 | description='''${mod_description}''' 43 | # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. 44 | [[dependencies.${mod_id}]] #optional 45 | # the modid of the dependency 46 | modId="neoforge" #mandatory 47 | # Does this dependency have to exist - if not, ordering below must be specified 48 | mandatory=true #mandatory 49 | # The version range of the dependency 50 | versionRange="${neo_version_range}" #mandatory 51 | # An ordering relationship for the dependency - BEFORE or AFTER required if the dependency is not mandatory 52 | # BEFORE - This mod is loaded BEFORE the dependency 53 | # AFTER - This mod is loaded AFTER the dependency 54 | ordering="NONE" 55 | # Side this dependency is applied on - BOTH, CLIENT, or SERVER 56 | side="BOTH" 57 | # Here's another dependency 58 | [[dependencies.${mod_id}]] 59 | modId="minecraft" 60 | mandatory=true 61 | # This version range declares a minimum of the current minecraft version up to but not including the next major version 62 | versionRange="${minecraft_version_range}" 63 | ordering="NONE" 64 | side="BOTH" 65 | 66 | # Features are specific properties of the game environment, that you may want to declare you require. This example declares 67 | # that your mod requires GL version 3.2 or higher. Other features will be added. They are side aware so declaring this won't 68 | # stop your mod loading on the server for example. 69 | #[features.${mod_id}] 70 | #openGLVersion="[3.2,)" 71 | [[mixins]] 72 | config="asteorbar.mixins.json" -------------------------------------------------------------------------------- /Fabric/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'fabric-loom' version "${loom_version}" 3 | id 'maven-publish' 4 | } 5 | 6 | repositories { 7 | // Add repositories to retrieve artifacts from in here. 8 | // You should only use this when depending on other mods because 9 | // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. 10 | // See https://docs.gradle.org/current/userguide/declaring_repositories.html 11 | // for more information about repositories. 12 | maven { url "https://maven.shedaniel.me/" } 13 | maven { url "https://maven.terraformersmc.com/releases/" } 14 | maven { url "https://cursemaven.com" } 15 | maven { url "https://jitpack.io" } 16 | maven { url 'https://maven.ladysnake.org/releases' } 17 | exclusiveContent { 18 | forRepository { 19 | maven { 20 | name = "Modrinth" 21 | url = "https://api.modrinth.com/maven" 22 | } 23 | } 24 | filter { 25 | includeGroup "maven.modrinth" 26 | } 27 | } 28 | } 29 | 30 | loom { 31 | accessWidenerPath = file("src/main/resources/asteorbar.accesswidener") 32 | } 33 | 34 | dependencies { 35 | compileOnly project(":Common") 36 | // To change the versions see the gradle.properties file 37 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 38 | mappings loom.officialMojangMappings() 39 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 40 | 41 | // Fabric API. This is technically optional, but you probably want it anyway. 42 | modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" 43 | 44 | modApi("me.shedaniel.cloth:cloth-config-fabric:${project.cloth_config_version}") { 45 | exclude(group: "net.fabricmc.fabric-api") 46 | } 47 | include "me.shedaniel.cloth:cloth-config-fabric:${project.cloth_config_version}" 48 | modApi "com.terraformersmc:modmenu:${project.mod_menu_version}" 49 | if (tough_as_nails_version_fabric != "0") { 50 | modImplementation "curse.maven:tough-as-nails-246391:${tough_as_nails_version_fabric}" 51 | } 52 | if (dehydration_version_fabric != "0") { 53 | modImplementation "curse.maven:dehydration-410830:${dehydration_version_fabric}" 54 | } 55 | if (appleskin_version_fabric != "0") { 56 | modImplementation "curse.maven:appleskin-248787:${appleskin_version_fabric}" 57 | } 58 | if (origins_apoli_version_fabric != "0") { 59 | modImplementation("com.github.apace100:apoli:${origins_apoli_version_fabric}") { 60 | exclude(group: "org.quiltmc.parsers") 61 | exclude(group: "maven.modrinth") 62 | exclude(group: "com.jamieswhiteshirt") 63 | } 64 | } 65 | if (thermoo_version_fabric != "0") { 66 | modImplementation "maven.modrinth:thermoo:${thermoo_version_fabric}" 67 | } 68 | } 69 | 70 | compileJava { 71 | source(project(":Common").sourceSets.main.allSource) 72 | } 73 | 74 | processResources { 75 | from project(":Common").sourceSets.main.resources 76 | inputs.property "version", project.mod_version 77 | inputs.property "minecraft_version", project.minecraft_version 78 | inputs.property "loader_version", project.loader_version 79 | filteringCharset "UTF-8" 80 | 81 | filesMatching("fabric.mod.json") { 82 | expand "version": project.mod_version, 83 | "minecraft_version": project.minecraft_version, 84 | "loader_version": project.loader_version 85 | } 86 | } 87 | 88 | def targetJavaVersion = 21 89 | tasks.withType(JavaCompile).configureEach { 90 | // ensure that the encoding is set to UTF-8, no matter what the system default is 91 | // this fixes some edge cases with special characters not displaying correctly 92 | // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html 93 | // If Javadoc is generated, this must be specified in that task too. 94 | it.options.encoding = "UTF-8" 95 | if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { 96 | it.options.release.set(targetJavaVersion) 97 | } 98 | } 99 | 100 | java { 101 | def javaVersion = JavaVersion.toVersion(targetJavaVersion) 102 | if (JavaVersion.current() < javaVersion) { 103 | toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) 104 | } 105 | archivesBaseName = "${project.mod_id}-fabric-${project.minecraft_version}-${project.mod_version}" 106 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task 107 | // if it is present. 108 | // If you remove this line, sources will not be generated. 109 | withSourcesJar() 110 | } 111 | 112 | jar { 113 | from("LICENSE") { 114 | rename { "${it}_${project.archivesBaseName}" } 115 | } 116 | } 117 | 118 | // configure the maven publication 119 | publishing { 120 | publications { 121 | mavenJava(MavenPublication) { 122 | from components.java 123 | } 124 | } 125 | 126 | // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. 127 | repositories { 128 | // Add repositories to publish to here. 129 | // Notice: This block does NOT have the same function as the block in the top level. 130 | // The repositories here will be used for publishing your artifact, not for 131 | // retrieving dependencies. 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/utils/RenderHelper.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.utils; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.mojang.blaze3d.vertex.PoseStack; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.gui.Font; 7 | import net.minecraft.client.renderer.SubmitNodeCollector; 8 | import net.minecraft.network.chat.Style; 9 | import net.minecraft.util.FormattedCharSequence; 10 | 11 | public class RenderHelper { 12 | public static void submitString(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, String string, float left, float top, int color, boolean shadow) { 13 | //color = applyAlpha(color); 14 | submitNodeCollector.submitText(poseStack, left, top, FormattedCharSequence.forward(string, Style.EMPTY), shadow, Font.DisplayMode.NORMAL, 0xF000F0, color, 0, 0); 15 | } 16 | 17 | public static void submitString(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, String string, int left, int top, int color) { 18 | submitString(submitNodeCollector, poseStack, string, left, top, color, false); 19 | } 20 | 21 | public static void submitCenteredString(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, String string, int left, int top, int color) { 22 | submitString(submitNodeCollector, poseStack, string, left - Minecraft.getInstance().font.width(string) / 2.0f, top, color, false); 23 | } 24 | 25 | public static void submitStringShadow(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, String string, int left, int top, int color) { 26 | submitString(submitNodeCollector, poseStack, string, left, top, color, true); 27 | } 28 | 29 | public static void submitCenteredStringShadow(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, String string, int left, int top, int color) { 30 | submitString(submitNodeCollector, poseStack, string, left - Minecraft.getInstance().font.width(string) / 2.0f, top, color, true); 31 | } 32 | 33 | public static void submitSolid(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, int left, int top, int right, int bottom, int color, float z) { 34 | submitNodeCollector.submitCustomGeometry(poseStack, AsteorBar.platformAdapter.getRenderType(), (pose, vertexConsumer) -> 35 | GuiHelper.renderSolid(vertexConsumer, pose.pose(), left, top, right, bottom, color, z)); 36 | } 37 | 38 | public static void submitSolidGradient(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, int left, int top, int right, int bottom, int color, float z) { 39 | submitNodeCollector.submitCustomGeometry(poseStack, AsteorBar.platformAdapter.getRenderType(), (pose, vertexConsumer) -> 40 | GuiHelper.renderSolidGradient(vertexConsumer, pose.pose(), left, top, right, bottom, color, z)); 41 | } 42 | 43 | public static void submitSolidGradientUpDown(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, int left, int top, int right, int bottom, int color, float z) { 44 | submitNodeCollector.submitCustomGeometry(poseStack, AsteorBar.platformAdapter.getRenderType(), (pose, vertexConsumer) -> 45 | GuiHelper.renderSolidGradientUpDown(vertexConsumer, pose.pose(), left, top, right, bottom, color, z)); 46 | } 47 | 48 | public static void submitBound(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, int left, int top, int right, int bottom, int width, int boundWidth, int colorFill, int colorEmpty, boolean vertex, float z) { 49 | //colorFill = applyAlpha(colorFill); 50 | //colorEmpty = applyAlpha(colorEmpty); 51 | int cut = 0; 52 | int expand = vertex ? boundWidth : 0; 53 | if (width > 0) {//left bound, vertex included 54 | int part = Math.min(width, boundWidth); 55 | cut += part; 56 | submitSolid(submitNodeCollector, poseStack, left - boundWidth, top - expand, left - boundWidth + part, bottom + expand, colorFill, z); 57 | if (part < boundWidth) { 58 | submitSolid(submitNodeCollector, poseStack, left - boundWidth + part, top - expand, left, bottom + expand, colorEmpty, z); 59 | } 60 | } else { 61 | submitSolid(submitNodeCollector, poseStack, left - boundWidth, top - expand, left, bottom + expand, colorEmpty, z); 62 | } 63 | if (width > right - left + boundWidth) {//right bound, vertex included 64 | int part = Math.min(width, boundWidth); 65 | cut += part; 66 | submitSolid(submitNodeCollector, poseStack, right, top - expand, right + part, bottom + expand, colorFill, z); 67 | if (part < boundWidth) { 68 | submitSolid(submitNodeCollector, poseStack, right + part, top - expand, right + boundWidth, bottom + expand, colorEmpty, z); 69 | } 70 | } else { 71 | submitSolid(submitNodeCollector, poseStack, right, top - expand, right + boundWidth, bottom + expand, colorEmpty, z); 72 | } 73 | width -= cut; 74 | if (width > 0) {//upper and lower bound, vertex excluded 75 | submitSolid(submitNodeCollector, poseStack, left, top - boundWidth, left + width, top, colorFill, z); 76 | submitSolid(submitNodeCollector, poseStack, left, bottom, left + width, bottom + boundWidth, colorFill, z); 77 | } 78 | if (width < right - left) { 79 | submitSolid(submitNodeCollector, poseStack, left + width, top - boundWidth, right, top, colorEmpty, z); 80 | submitSolid(submitNodeCollector, poseStack, left + width, bottom, right, bottom + boundWidth, colorEmpty, z); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /version_history.md: -------------------------------------------------------------------------------- 1 | # Version History 2 | 3 | ## v1.5.3 4 | 5 | ### Features 6 | - Use text style ARGB color configuration. e.g. #FFE91E63 instead of 4293467747. (Configuration should be proceeded again, sorry for potential inconvenience.) 7 | 8 | ### Adjustments & Fixes 9 | - Render issue while using shader mod in 1.21.5+. 10 | - ArrayIndexOutOfBound not synced to 1.20.4+ versions. 11 | 12 | ## v1.5.2 13 | 14 | ### Features 15 | 16 | - Now support 1.21.5-1.21.10 17 | - Add option to change the height and margin of the HUD bars. 18 | - Add option to lower the opacity of regeneration effect. 19 | - Health bar now has a fade effect on health loss. 20 | - Add option to hide decimal part of the numbers, or adjust the hide threshold. 21 | - Mod compatibility: Walk Jog Run, Legendary Survival Overhaul. 22 | 23 | ### Adjustments & Fixes 24 | 25 | - Fixed the food value increment preview from AppleSkin not accurate. 26 | - Fixed vanilla experience level not hidden when the experience bar is disabled. 27 | - Fixed ArrayIndexOutOfBound when enabling stacked health bar. 28 | 29 | ## v1.5.1 30 | 31 | This update is NeoForge only. 32 | 33 | ### Adjustments & Fixes 34 | 35 | - Fixed the network channel not optional, which prevents the client from joining the server without the mod. 36 | 37 | ## v1.5 38 | 39 | After this update, Minecraft versions below 1.20 and 1.20.2 will no longer be supported. 40 | 41 | ### Features 42 | 43 | - Support Minecraft 1.21.3 and 1.21.4. 44 | - All bars now extends SimpleBarOverlay. 45 | - Add 2 new layout styles for HUD bars: TOP_BOTH_SIDES and BOTTOM_BOTH_SIDES. 46 | - Add `Overlays.registerOverlayXXX()`-related method to allow third-party mods to register their own overlay. 47 | - Mod compatibility: Thermoo and Meal API. 48 | 49 | ### Adjustments & Fixes 50 | 51 | - Re-organized third-party mod support. 52 | - Fixed the compatibility issue with newer versions of Tough As Nails and Thirst Was Taken. 53 | 54 | ## v1.4.6 55 | 56 | ### Features 57 | 58 | - Support Minecraft 1.21 and 1.21.1. 59 | 60 | ### Adjustments & Fixes 61 | 62 | - Fix render issue with oculus shader. 63 | 64 | ## v1.4.5 65 | 66 | 2024/05/26 67 | 68 | ### Features 69 | 70 | - Support Minecraft 1.20.6. 71 | - Option to force render all bars at corner. 72 | - Option to toggle bar shake effect. 73 | - Option to disable health bar for armor stands. 74 | - Display bar of TerraFirmaCraft. 75 | - Display mana bar of Ars Nouveau. 76 | - Display mana bar of Botania. 77 | 78 | ### Adjustments & Fixes 79 | 80 | - Fixed bar bound width not calculated correctly. 81 | 82 | ## v1.4.4 83 | 84 | 2024/05/10 (not released) 85 | 86 | ### Features 87 | 88 | - Health and food bar will shake in low health or hunger. 89 | - Automatically hide unchanged bars. 90 | - Option to display food level text. 91 | 92 | ## v1.4.3 93 | 94 | 2024/04/14 95 | 96 | ### Adjustments & Fixes 97 | 98 | - Add support for NeoForge server. 99 | 100 | ## v1.4.2 101 | 102 | 2024/04/13 103 | 104 | ### Features 105 | 106 | - Display thirst info of Homeostatic. 107 | 108 | ## v1.4.1.1 109 | 110 | 2024/04/03 111 | 112 | ### Features 113 | 114 | - Added compatibility with Light Shield and Superior Shields in Forge 1.20.1. 115 | 116 | ## v1.4.1 117 | 118 | 2024/03/26 119 | 120 | ### Features 121 | 122 | - Preview health&hunger&saturation increment while AppleSkin is loaded. 123 | - Display stamina bar of Parcool. 124 | - Display feather bar of Feather. 125 | - Display mana bar of Iron's Spells 'n Spellbooks 126 | - Display blood bar of Vampirism. 127 | - Display shield bar of Superior Shields. 128 | - Allow to set a global alpha value for entity bars. 129 | - Now display mount health with food level together. 130 | 131 | ### Adjustments & Fixes 132 | 133 | - Fixed the issue in spectator mode in Fabric. 134 | - Fixed entity rendering issue. 135 | - Fixed entity bar not using the lightmap. 136 | 137 | ## v1.4 138 | 139 | 2024/03/16 140 | 141 | ### Features 142 | 143 | - Colorful health bar. 144 | - The max value of armor and food level now configurable. 145 | - Display shield info in hud and entity bar of Light Shield(NeoForge 1.20.4). 146 | 147 | ### Adjustments & Fixes 148 | 149 | - Experience value now displays correctly. 150 | 151 | ## v1.3 152 | 153 | 2024/02/22 154 | 155 | ### Features 156 | 157 | - Fabric and NeoForge support. 158 | - Color of HUD bars customizable. 159 | - Display thirst info of Tough As Nails. 160 | - Display thirst info of Thirst Was Taken. 161 | - Display thirst info of Dehydration. 162 | - Display MekaSuit's energy level of Mekanism. 163 | - In-game configuration through ModMenu. 164 | 165 | ### Adjustments & Fixes 166 | 167 | - Armor bar now has same length with other bars. 168 | - Display numerical value of armor level and armor toughness. 169 | - Fabric configuration should be working correctly now. 170 | 171 | ## v1.2.2 172 | 173 | 2024/02/14 174 | 175 | ### Adjustments & Fixes 176 | 177 | - Adjusted overlay display sequence. 178 | - Added more methods to display absorption. 179 | 180 | ## v1.2.1 181 | 182 | 2024/02/07 183 | 184 | ### Adjustments & Fixes 185 | 186 | - Changed health bar's render time in forge version, now should be more compatible with mod entities. 187 | - Added a lightmap to display health bar correctly with shader packs. 188 | - Fixed text display in 1.18 and 1.19. 189 | 190 | ## v1.2 191 | 192 | 2024/01/11 193 | 194 | ### Features 195 | 196 | - **Display living entity's health and absorption.** 197 | - More configurable options on hud and entity bars. 198 | - More HUD layout options. 199 | - KeyBind to toggle HUD. 200 | - Localization support. 201 | 202 | ### Adjustments & Fixes 203 | 204 | - Add activation packet to assist server-side plugin. 205 | - Adjusted hunger bar's color. 206 | 207 | ## v1.1 208 | 209 | 2024/01/08 210 | 211 | ### Features 212 | 213 | - Display armor. 214 | - Display experience value. 215 | - Now configurable. 216 | - Display exhaustion. 217 | - Server-side support. 218 | 219 | ### Adjustments & Fixes 220 | 221 | - Changed low health flash effect to avoid display issues while both in low health and regeneration. 222 | - Low health now set to fixed rate. 223 | - Optimized the numerical display of health. 224 | - Optimized the height increment after displaying the status bar. 225 | 226 | ## v1.0 227 | 228 | ### Features 229 | 230 | - Display health, hunger, mount health and air level. 231 | - Change the appearance of the bars in different situations. 232 | - Hidden status, like saturation, can be displayed together with hunger. -------------------------------------------------------------------------------- /NeoForge/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | id 'eclipse' 4 | id 'idea' 5 | id 'maven-publish' 6 | id 'net.neoforged.gradle.userdev' version '7.0.173' 7 | id 'net.neoforged.gradle.mixin' version '7.0.173' 8 | } 9 | 10 | repositories { 11 | maven { 12 | url "https://cursemaven.com" 13 | } 14 | } 15 | 16 | base { 17 | archivesName = "$mod_id-neoforge-$minecraft_version-$mod_version" 18 | } 19 | 20 | // Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17. 21 | java.toolchain.languageVersion = JavaLanguageVersion.of(21) 22 | 23 | //minecraft.accessTransformers.file rootProject.file('src/main/resources/META-INF/accesstransformer.cfg') 24 | //minecraft.accessTransformers.entry public net.minecraft.client.Minecraft textureManager # textureManager 25 | 26 | // Default run configurations. 27 | // These can be tweaked, removed, or duplicated as needed. 28 | runs { 29 | // applies to all the run configs below 30 | configureEach { 31 | // Recommended logging data for a userdev environment 32 | // The markers can be added/remove as needed separated by commas. 33 | // "SCAN": For mods scan. 34 | // "REGISTRIES": For firing of registry events. 35 | // "REGISTRYDUMP": For getting the contents of all registries. 36 | systemProperty 'forge.logging.markers', 'REGISTRIES' 37 | 38 | // Recommended logging level for the console 39 | // You can set various levels here. 40 | // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels 41 | systemProperty 'forge.logging.console.level', 'debug' 42 | 43 | modSource project.sourceSets.main 44 | } 45 | 46 | client { 47 | // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. 48 | systemProperty 'forge.enabledGameTestNamespaces', project.mod_id 49 | } 50 | 51 | server { 52 | systemProperty 'forge.enabledGameTestNamespaces', project.mod_id 53 | programArgument '--nogui' 54 | } 55 | 56 | // This run config launches GameTestServer and runs all registered gametests, then exits. 57 | // By default, the server will crash when no gametests are provided. 58 | // The gametest system is also enabled by default for other run configs under the /test command. 59 | gameTestServer { 60 | systemProperty 'forge.enabledGameTestNamespaces', project.mod_id 61 | } 62 | 63 | clientData { 64 | // example of overriding the workingDirectory set in configureEach above, uncomment if you want to use it 65 | // workingDirectory project.file('run-data') 66 | 67 | // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. 68 | programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() 69 | } 70 | } 71 | 72 | // Include resources generated by data generators. 73 | sourceSets.main.resources { srcDir 'src/generated/resources' } 74 | 75 | 76 | dependencies { 77 | compileOnly project(":Common") 78 | // Specify the version of Minecraft to use. 79 | // Depending on the plugin applied there are several options. We will assume you applied the userdev plugin as shown above. 80 | // The group for userdev is net.neoforged, the module name is neoforge, and the version is the same as the neoforge version. 81 | // You can however also use the vanilla plugin (net.neoforged.gradle.vanilla) to use a version of Minecraft without the neoforge loader. 82 | // And its provides the option to then use net.minecraft as the group, and one of; client, server or joined as the module name, plus the game version as version. 83 | // For all intends and purposes: You can treat this dependency as if it is a normal library you would use. 84 | implementation "net.neoforged:neoforge:${neo_version}" 85 | 86 | // Example mod dependency with JEI 87 | // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime 88 | // compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}" 89 | // compileOnly "mezz.jei:jei-${mc_version}-forge-api:${jei_version}" 90 | // runtimeOnly "mezz.jei:jei-${mc_version}-forge:${jei_version}" 91 | 92 | // Example mod dependency using a mod jar from ./libs with a flat dir repository 93 | // This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar 94 | // The group id is ignored when searching -- in this case, it is "blank" 95 | // implementation "blank:coolmod-${mc_version}:${coolmod_version}" 96 | 97 | // Example mod dependency using a file as dependency 98 | // implementation files("libs/coolmod-${mc_version}-${coolmod_version}.jar") 99 | 100 | // Example project dependency using a sister or child project: 101 | // implementation project(":myproject") 102 | 103 | // For more info: 104 | // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html 105 | // http://www.gradle.org/docs/current/userguide/dependency_management.html 106 | if (tough_as_nails_version_neoforge != "0") { 107 | compileOnly "curse.maven:tough-as-nails-246391:${tough_as_nails_version_neoforge}" 108 | } 109 | if (appleskin_version_neoforge != "0") { 110 | compileOnly "curse.maven:appleskin-248787:${appleskin_version_neoforge}" 111 | } 112 | if (vampirism_version_neoforge != "0") { 113 | compileOnly "curse.maven:vampirism-become-a-vampire-233029:${vampirism_version_neoforge}" 114 | } 115 | if (thirst_was_taken_version_neoforge != "0") { 116 | compileOnly "curse.maven:thirst-was-taken-679270:${thirst_was_taken_version_neoforge}" 117 | } 118 | } 119 | 120 | compileJava { 121 | source(project(":Common").sourceSets.main.allSource) 122 | } 123 | 124 | processResources { 125 | from project(":Common").sourceSets.main.resources 126 | } 127 | 128 | // This block of code expands all declared replace properties in the specified resource targets. 129 | // A missing property will result in an error. Properties are expanded using ${} Groovy notation. 130 | // When "copyIdeResources" is enabled, this will also run before the game launches in IDE environments. 131 | // See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html 132 | tasks.withType(ProcessResources).configureEach { 133 | var replaceProperties = [ 134 | minecraft_version : minecraft_version, minecraft_version_range: minecraft_version_range, 135 | neo_version : neo_version, neo_version_range: neo_version_range, 136 | loader_version_range: neo_loader_version_range, 137 | mod_id : mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version, 138 | mod_authors : mod_authors, mod_description: mod_description, pack_format_number: pack_format_number, 139 | ] 140 | inputs.properties replaceProperties 141 | 142 | filesMatching(['META-INF/neoforge.mods.toml', 'pack.mcmeta']) { 143 | expand replaceProperties + [project: project] 144 | } 145 | } 146 | 147 | // Example configuration to allow publishing using the maven-publish plugin 148 | publishing { 149 | publications { 150 | register('mavenJava', MavenPublication) { 151 | from components.java 152 | } 153 | } 154 | repositories { 155 | maven { 156 | url "file://${project.projectDir}/repo" 157 | } 158 | } 159 | } 160 | 161 | tasks.withType(JavaCompile).configureEach { 162 | options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation 163 | } -------------------------------------------------------------------------------- /NeoForge/src/main/java/com/afoxxvi/asteorbar/network/NetworkHandler.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.network; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import net.minecraft.network.FriendlyByteBuf; 5 | import net.minecraft.network.codec.StreamCodec; 6 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 7 | import net.minecraft.resources.ResourceLocation; 8 | import net.minecraft.server.level.ServerPlayer; 9 | import net.minecraft.world.entity.LivingEntity; 10 | import net.neoforged.bus.api.SubscribeEvent; 11 | import net.neoforged.neoforge.client.network.ClientPacketDistributor; 12 | import net.neoforged.neoforge.event.tick.PlayerTickEvent; 13 | import net.neoforged.neoforge.network.PacketDistributor; 14 | import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; 15 | import net.neoforged.neoforge.network.handling.IPayloadContext; 16 | import net.neoforged.neoforge.network.registration.PayloadRegistrar; 17 | import org.jetbrains.annotations.NotNull; 18 | import toughasnails.api.thirst.ThirstHelper; 19 | 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | import java.util.UUID; 23 | 24 | public class NetworkHandler { 25 | private static boolean initialized = false; 26 | //avoid sending packets too frequently 27 | private static final ResourceLocation CHANNEL = ResourceLocation.fromNamespaceAndPath("asteorbar", "network"); 28 | private static final byte INDEX_EXHAUSTION = 0; 29 | private static final byte INDEX_SATURATION = 1; 30 | private static final byte INDEX_ABSORPTION = 2; 31 | private static final byte INDEX_ACTIVATE = 3; 32 | private static final byte INDEX_TOUGH_AS_NAILS = 64; 33 | private static final Map EXHAUSTION = new HashMap<>(); 34 | private static final Map SATURATION = new HashMap<>(); 35 | 36 | private static final Map TOUGH_AS_NAILS_HYDRATION = new HashMap<>(); 37 | private static final Map TOUGH_AS_NAILS_EXHAUSTION = new HashMap<>(); 38 | 39 | public record NetworkPayload(byte index, float f1, float f2, int i1) implements CustomPacketPayload { 40 | public static final StreamCodec PAYLOAD_CODEC = CustomPacketPayload.codec(NetworkPayload::write, NetworkPayload::read); 41 | public static final CustomPacketPayload.Type ID = new CustomPacketPayload.Type<>(CHANNEL); 42 | 43 | @Override 44 | public @NotNull Type type() { 45 | return ID; 46 | } 47 | 48 | public static NetworkPayload read(FriendlyByteBuf friendlyByteBuf) { 49 | return new NetworkPayload(friendlyByteBuf.readByte(), friendlyByteBuf.readFloat(), friendlyByteBuf.readFloat(), friendlyByteBuf.readInt()); 50 | } 51 | 52 | public void write(FriendlyByteBuf friendlyByteBuf) { 53 | friendlyByteBuf.writeByte(index).writeFloat(f1).writeFloat(f2).writeInt(i1); 54 | } 55 | } 56 | 57 | public static void handle(NetworkPayload payload, IPayloadContext context) { 58 | byte index = payload.index; 59 | switch (index) { 60 | case INDEX_EXHAUSTION: { 61 | float exhaustion = payload.f1; 62 | context.enqueueWork(() -> AsteorBar.platformAdapter.setExhaustion(context.player(), exhaustion)); 63 | } 64 | break; 65 | case INDEX_SATURATION: 66 | float saturation = payload.f1; 67 | context.enqueueWork(() -> context.player().getFoodData().setSaturation(saturation)); 68 | break; 69 | case INDEX_ABSORPTION: { 70 | int entityId = payload.i1; 71 | float absorption = payload.f1; 72 | context.enqueueWork(() -> { 73 | var entity = context.player().level().getEntity(entityId); 74 | if (entity instanceof LivingEntity livingEntity) { 75 | livingEntity.setAbsorptionAmount(absorption); 76 | } 77 | }); 78 | } 79 | break; 80 | case INDEX_ACTIVATE: { 81 | boolean activate = payload.i1 != 0; 82 | context.enqueueWork(() -> ClientPacketDistributor.sendToServer(new NetworkPayload(INDEX_ACTIVATE, 0F, 0F, activate ? 1 : 0))); 83 | } 84 | break; 85 | case INDEX_TOUGH_AS_NAILS: { 86 | float hydration = payload.f1; 87 | float exhaustion = payload.f2; 88 | context.enqueueWork(() -> { 89 | var thirst = ThirstHelper.getThirst(context.player()); 90 | thirst.setHydration(hydration); 91 | thirst.setExhaustion(exhaustion); 92 | }); 93 | } 94 | break; 95 | default: 96 | break; 97 | } 98 | } 99 | 100 | @SubscribeEvent 101 | public static void register(final RegisterPayloadHandlersEvent event) { 102 | final PayloadRegistrar registrar = event.registrar(AsteorBar.MOD_ID).optional(); 103 | registrar.playToClient(NetworkPayload.ID, NetworkPayload.PAYLOAD_CODEC, NetworkHandler::handle); 104 | } 105 | 106 | @SubscribeEvent 107 | public static void onPlayerTick(PlayerTickEvent.Pre event) { 108 | if (event.getEntity() instanceof ServerPlayer player) { 109 | var foodStats = player.getFoodData(); 110 | float exhaustionLevel = AsteorBar.platformAdapter.getExhaustion(player); 111 | Float oldExhaustion = EXHAUSTION.get(player.getUUID()); 112 | if (oldExhaustion == null || Math.abs(oldExhaustion - exhaustionLevel) >= 0.01F) { 113 | EXHAUSTION.put(player.getUUID(), exhaustionLevel); 114 | PacketDistributor.sendToPlayer(player, new NetworkPayload(INDEX_EXHAUSTION, exhaustionLevel, 0F, 0)); 115 | } 116 | float saturationLevel = foodStats.getSaturationLevel(); 117 | Float oldSaturation = SATURATION.get(player.getUUID()); 118 | if (oldSaturation == null || Math.abs(oldSaturation - saturationLevel) >= 0.01F) { 119 | SATURATION.put(player.getUUID(), saturationLevel); 120 | PacketDistributor.sendToPlayer(player, new NetworkPayload(INDEX_SATURATION, saturationLevel, 0F, 0)); 121 | } 122 | if (!initialized) { 123 | initialized = true; 124 | AsteorBar.compatibility.init(); 125 | } 126 | if (AsteorBar.compatibility.toughAsNails) { 127 | var thirst = ThirstHelper.getThirst(player); 128 | boolean send = false; 129 | float hydration = thirst.getHydration(); 130 | Float oldHydration = TOUGH_AS_NAILS_HYDRATION.get(player.getUUID()); 131 | if (oldHydration == null || Math.abs(oldHydration - hydration) >= 0.01F) { 132 | TOUGH_AS_NAILS_HYDRATION.put(player.getUUID(), hydration); 133 | send = true; 134 | } 135 | float exhaustion = thirst.getExhaustion(); 136 | Float oldToughAsNailsExhaustion = TOUGH_AS_NAILS_EXHAUSTION.get(player.getUUID()); 137 | if (oldToughAsNailsExhaustion == null || Math.abs(oldToughAsNailsExhaustion - exhaustion) >= 0.01F) { 138 | TOUGH_AS_NAILS_EXHAUSTION.put(player.getUUID(), exhaustion); 139 | send = true; 140 | } 141 | if (send) { 142 | PacketDistributor.sendToPlayer(player, new NetworkPayload(INDEX_TOUGH_AS_NAILS, hydration, exhaustion, 0)); 143 | } 144 | } 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /Forge/src/main/java/com/afoxxvi/asteorbar/network/NetworkHandler.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.network; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.AsteorBarForge; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.network.FriendlyByteBuf; 7 | import net.minecraft.resources.ResourceLocation; 8 | import net.minecraft.server.level.ServerPlayer; 9 | import net.minecraft.world.entity.LivingEntity; 10 | import net.minecraft.world.entity.player.Player; 11 | import net.minecraftforge.event.TickEvent; 12 | import net.minecraftforge.event.network.CustomPayloadEvent; 13 | import net.minecraftforge.eventbus.api.listener.SubscribeEvent; 14 | import net.minecraftforge.fml.common.Mod; 15 | import net.minecraftforge.network.ChannelBuilder; 16 | import net.minecraftforge.network.PacketDistributor; 17 | import net.minecraftforge.network.SimpleChannel; 18 | 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | import java.util.UUID; 22 | 23 | @Mod.EventBusSubscriber(modid = AsteorBar.MOD_ID) 24 | public class NetworkHandler { 25 | private static boolean initialized = false; 26 | private static final SimpleChannel CHANNEL = ChannelBuilder 27 | .named(ResourceLocation.fromNamespaceAndPath(AsteorBar.MOD_ID, "network")) 28 | .networkProtocolVersion(1) 29 | .optional() 30 | .acceptedVersions((status, version) -> true) 31 | .simpleChannel(); 32 | 33 | //avoid sending packets too frequently 34 | private static final Map EXHAUSTION = new HashMap<>(); 35 | private static final Map SATURATION = new HashMap<>(); 36 | 37 | private static final Map TOUGH_AS_NAILS_HYDRATION = new HashMap<>(); 38 | private static final Map TOUGH_AS_NAILS_EXHAUSTION = new HashMap<>(); 39 | 40 | public static void init() { 41 | CHANNEL.messageBuilder(ExhaustionPacket.class, 0) 42 | .encoder(ExhaustionPacket::encode) 43 | .decoder(ExhaustionPacket::decode) 44 | .consumerNetworkThread(ExhaustionPacket::handle) 45 | .add(); 46 | CHANNEL.messageBuilder(SaturationPacket.class, 1) 47 | .encoder(SaturationPacket::encode) 48 | .decoder(SaturationPacket::decode) 49 | .consumerNetworkThread(SaturationPacket::handle) 50 | .add(); 51 | CHANNEL.messageBuilder(EntityAbsorptionPacket.class, 2) 52 | .encoder(EntityAbsorptionPacket::encode) 53 | .decoder(EntityAbsorptionPacket::decode) 54 | .consumerNetworkThread(EntityAbsorptionPacket::handle) 55 | .add(); 56 | CHANNEL.messageBuilder(ActivatePacket.class, 3) 57 | .encoder(ActivatePacket::encode) 58 | .decoder(ActivatePacket::decode) 59 | .consumerNetworkThread(ActivatePacket::handle) 60 | .add(); 61 | } 62 | 63 | @SubscribeEvent 64 | public static void onPlayerTick(TickEvent.PlayerTickEvent.Post event) { 65 | if (event.player() instanceof ServerPlayer player) { 66 | var foodStats = player.getFoodData(); 67 | float exhaustionLevel = AsteorBar.platformAdapter.getExhaustion(player); 68 | Float oldExhaustion = EXHAUSTION.get(player.getUUID()); 69 | if (oldExhaustion == null || Math.abs(oldExhaustion - exhaustionLevel) >= 0.01F) { 70 | EXHAUSTION.put(player.getUUID(), exhaustionLevel); 71 | CHANNEL.send(new ExhaustionPacket(exhaustionLevel), PacketDistributor.PLAYER.with(player)); 72 | } 73 | float saturationLevel = foodStats.getSaturationLevel(); 74 | Float oldSaturation = SATURATION.get(player.getUUID()); 75 | if (oldSaturation == null || Math.abs(oldSaturation - saturationLevel) >= 0.01F) { 76 | SATURATION.put(player.getUUID(), saturationLevel); 77 | CHANNEL.send(new SaturationPacket(saturationLevel), PacketDistributor.PLAYER.with(player)); 78 | } 79 | if (!initialized) { 80 | initialized = true; 81 | AsteorBar.compatibility.init(); 82 | } 83 | } 84 | } 85 | 86 | private static Player getPlayer(CustomPayloadEvent.Context context) { 87 | return context.isServerSide() ? context.getSender() : Minecraft.getInstance().player; 88 | } 89 | 90 | public static class ActivatePacket { 91 | public boolean activate; 92 | 93 | public ActivatePacket(boolean activate) { 94 | this.activate = activate; 95 | } 96 | 97 | public static void encode(ActivatePacket packet, FriendlyByteBuf buffer) { 98 | buffer.writeBoolean(packet.activate); 99 | } 100 | 101 | public static ActivatePacket decode(FriendlyByteBuf buffer) { 102 | return new ActivatePacket(buffer.readBoolean()); 103 | } 104 | 105 | public static void handle(ActivatePacket packet, CustomPayloadEvent.Context context) { 106 | context.enqueueWork(() -> { 107 | AsteorBarForge.LOGGER.info("Received activate packet. Sending back to server."); 108 | CHANNEL.send(new ActivatePacket(true), PacketDistributor.SERVER.noArg()); 109 | }); 110 | context.setPacketHandled(true); 111 | } 112 | } 113 | 114 | public static class SaturationPacket { 115 | public float saturation; 116 | 117 | public SaturationPacket(float saturation) { 118 | this.saturation = saturation; 119 | } 120 | 121 | public static void encode(SaturationPacket packet, FriendlyByteBuf buffer) { 122 | buffer.writeFloat(packet.saturation); 123 | } 124 | 125 | public static SaturationPacket decode(FriendlyByteBuf buffer) { 126 | return new SaturationPacket(buffer.readFloat()); 127 | } 128 | 129 | public static void handle(SaturationPacket packet, CustomPayloadEvent.Context context) { 130 | context.enqueueWork(() -> { 131 | var player = getPlayer(context); 132 | if (player != null) { 133 | var foodStats = player.getFoodData(); 134 | foodStats.setSaturation(packet.saturation); 135 | } 136 | }); 137 | context.setPacketHandled(true); 138 | } 139 | } 140 | 141 | public static class ExhaustionPacket { 142 | public float exhaustion; 143 | 144 | public ExhaustionPacket(float exhaustion) { 145 | this.exhaustion = exhaustion; 146 | } 147 | 148 | public static void encode(ExhaustionPacket packet, FriendlyByteBuf buffer) { 149 | buffer.writeFloat(packet.exhaustion); 150 | } 151 | 152 | public static ExhaustionPacket decode(FriendlyByteBuf buffer) { 153 | return new ExhaustionPacket(buffer.readFloat()); 154 | } 155 | 156 | public static void handle(ExhaustionPacket packet, CustomPayloadEvent.Context context) { 157 | context.enqueueWork(() -> { 158 | var player = getPlayer(context); 159 | if (player != null) { 160 | AsteorBar.platformAdapter.setExhaustion(player, packet.exhaustion); 161 | } 162 | }); 163 | context.setPacketHandled(true); 164 | } 165 | } 166 | 167 | public static class EntityAbsorptionPacket { 168 | public int entityId; 169 | public float absorption; 170 | 171 | public EntityAbsorptionPacket(int entityId, float absorption) { 172 | this.entityId = entityId; 173 | this.absorption = absorption; 174 | } 175 | 176 | public static void encode(EntityAbsorptionPacket packet, FriendlyByteBuf buffer) { 177 | buffer.writeInt(packet.entityId); 178 | buffer.writeFloat(packet.absorption); 179 | } 180 | 181 | public static EntityAbsorptionPacket decode(FriendlyByteBuf buffer) { 182 | return new EntityAbsorptionPacket(buffer.readInt(), buffer.readFloat()); 183 | } 184 | 185 | public static void handle(EntityAbsorptionPacket packet, CustomPayloadEvent.Context context) { 186 | context.enqueueWork(() -> { 187 | var player = getPlayer(context); 188 | if (player != null) { 189 | var entity = player.level().getEntity(packet.entityId); 190 | if (entity instanceof LivingEntity livingEntity) { 191 | livingEntity.setAbsorptionAmount(packet.absorption); 192 | } 193 | } 194 | }); 195 | context.setPacketHandled(true); 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /Fabric/src/main/java/com/afoxxvi/asteorbar/network/NetworkHandler.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.network; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.buffer.Unpooled; 6 | import net.fabricmc.api.EnvType; 7 | import net.fabricmc.api.Environment; 8 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 9 | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 10 | import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; 11 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 12 | import net.minecraft.network.FriendlyByteBuf; 13 | import net.minecraft.network.codec.StreamCodec; 14 | import net.minecraft.network.protocol.common.ClientCommonPacketListener; 15 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 16 | import net.minecraft.network.protocol.Packet; 17 | import net.minecraft.resources.ResourceLocation; 18 | import net.minecraft.server.level.ServerPlayer; 19 | import net.minecraft.world.entity.LivingEntity; 20 | import org.jetbrains.annotations.NotNull; 21 | import toughasnails.api.thirst.ThirstHelper; 22 | 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | import java.util.UUID; 26 | 27 | public class NetworkHandler { 28 | private static boolean initialized = false; 29 | private static final ResourceLocation CHANNEL = ResourceLocation.fromNamespaceAndPath("asteorbar", "network"); 30 | private static final int INDEX_EXHAUSTION = 0; 31 | private static final int INDEX_SATURATION = 1; 32 | private static final int INDEX_ABSORPTION = 2; 33 | private static final int INDEX_ACTIVATE = 3; 34 | private static final int INDEX_TOUGH_AS_NAILS = 64; 35 | 36 | @Environment(EnvType.CLIENT) 37 | public static void init() { 38 | PayloadTypeRegistry.playS2C().register(NetworkPayload.ID, NetworkPayload.PAYLOAD_CODEC); 39 | ClientPlayNetworking.registerGlobalReceiver(NetworkPayload.ID, (payload, context) -> { 40 | final var buf = payload.buf; 41 | byte index = buf.readByte(); 42 | final var client = context.client(); 43 | switch (index) { 44 | case INDEX_EXHAUSTION: { 45 | float exhaustion = payload.buf().readFloat(); 46 | client.execute(() -> { 47 | if (client.player != null) { 48 | AsteorBar.platformAdapter.setExhaustion(client.player, exhaustion); 49 | } 50 | }); 51 | } 52 | break; 53 | case INDEX_SATURATION: 54 | float saturation = payload.buf().readFloat(); 55 | client.execute(() -> { 56 | if (client.player != null) { 57 | client.player.getFoodData().setSaturation(saturation); 58 | } 59 | }); 60 | break; 61 | case INDEX_ABSORPTION: { 62 | int entityId = buf.readInt(); 63 | float absorption = buf.readFloat(); 64 | client.execute(() -> { 65 | if (client.level != null) { 66 | var entity = client.level.getEntity(entityId); 67 | if (entity instanceof LivingEntity livingEntity) { 68 | livingEntity.setAbsorptionAmount(absorption); 69 | } 70 | } 71 | }); 72 | } 73 | break; 74 | case INDEX_ACTIVATE: { 75 | boolean activate = buf.readBoolean(); 76 | client.execute(() -> { 77 | var buffer = Unpooled.buffer(1).writeBoolean(activate); 78 | ClientPlayNetworking.send(new NetworkPayload(new FriendlyByteBuf(buffer))); 79 | }); 80 | } 81 | break; 82 | case INDEX_TOUGH_AS_NAILS: { 83 | float hydration = buf.readFloat(); 84 | float exhaustion = buf.readFloat(); 85 | client.execute(() -> { 86 | if (client.player != null) { 87 | var thirst = ThirstHelper.getThirst(client.player); 88 | thirst.setHydration(hydration); 89 | thirst.setExhaustion(exhaustion); 90 | } 91 | }); 92 | } 93 | break; 94 | default: 95 | break; 96 | } 97 | }); 98 | } 99 | 100 | 101 | //avoid sending packets too frequently 102 | private static final Map EXHAUSTION = new HashMap<>(); 103 | private static final Map SATURATION = new HashMap<>(); 104 | private static final Map TOUGH_AS_NAILS_HYDRATION = new HashMap<>(); 105 | private static final Map TOUGH_AS_NAILS_EXHAUSTION = new HashMap<>(); 106 | 107 | public record NetworkPayload(FriendlyByteBuf buf) implements CustomPacketPayload { 108 | public static final StreamCodec PAYLOAD_CODEC = CustomPacketPayload.codec(NetworkPayload::write, NetworkPayload::read); 109 | public static final CustomPacketPayload.Type ID = new CustomPacketPayload.Type<>(CHANNEL); 110 | 111 | @Override 112 | public @NotNull Type type() { 113 | return ID; 114 | } 115 | 116 | public static NetworkPayload read(FriendlyByteBuf friendlyByteBuf) { 117 | return new NetworkPayload(PacketByteBufs.create().writeBytes(friendlyByteBuf)); 118 | } 119 | 120 | public void write(FriendlyByteBuf friendlyByteBuf) { 121 | friendlyByteBuf.writeBytes(buf); 122 | } 123 | } 124 | 125 | public static void onPlayerTick(ServerPlayer player) { 126 | var foodStats = player.getFoodData(); 127 | float exhaustionLevel = AsteorBar.platformAdapter.getExhaustion(player); 128 | Float oldExhaustion = EXHAUSTION.get(player.getUUID()); 129 | if (oldExhaustion == null || Math.abs(oldExhaustion - exhaustionLevel) >= 0.01F) { 130 | EXHAUSTION.put(player.getUUID(), exhaustionLevel); 131 | ByteBuf buf = PacketByteBufs.create().writeByte(INDEX_EXHAUSTION).writeFloat(exhaustionLevel); 132 | ServerPlayNetworking.send(player, new NetworkPayload(PacketByteBufs.duplicate(buf))); 133 | } 134 | float saturationLevel = foodStats.getSaturationLevel(); 135 | Float oldSaturation = SATURATION.get(player.getUUID()); 136 | if (oldSaturation == null || Math.abs(oldSaturation - saturationLevel) >= 0.01F) { 137 | SATURATION.put(player.getUUID(), saturationLevel); 138 | ByteBuf buf = PacketByteBufs.create().writeByte(INDEX_SATURATION).writeFloat(saturationLevel); 139 | ServerPlayNetworking.send(player, new NetworkPayload(PacketByteBufs.duplicate(buf))); 140 | } 141 | if (!initialized) { 142 | initialized = true; 143 | AsteorBar.compatibility.init(); 144 | } 145 | if (AsteorBar.compatibility.toughAsNails) { 146 | var thirst = ThirstHelper.getThirst(player); 147 | boolean send = false; 148 | float hydration = thirst.getHydration(); 149 | Float oldHydration = TOUGH_AS_NAILS_HYDRATION.get(player.getUUID()); 150 | if (oldHydration == null || Math.abs(oldHydration - hydration) >= 0.01F) { 151 | TOUGH_AS_NAILS_HYDRATION.put(player.getUUID(), hydration); 152 | send = true; 153 | } 154 | float exhaustion = thirst.getExhaustion(); 155 | Float oldToughAsNailsExhaustion = TOUGH_AS_NAILS_EXHAUSTION.get(player.getUUID()); 156 | if (oldToughAsNailsExhaustion == null || Math.abs(oldToughAsNailsExhaustion - exhaustion) >= 0.01F) { 157 | TOUGH_AS_NAILS_EXHAUSTION.put(player.getUUID(), exhaustion); 158 | send = true; 159 | } 160 | if (send) { 161 | ByteBuf buf = PacketByteBufs.create().writeByte(INDEX_TOUGH_AS_NAILS).writeFloat(hydration).writeFloat(exhaustion); 162 | ServerPlayNetworking.send(player, new NetworkPayload(PacketByteBufs.duplicate(buf))); 163 | } 164 | } 165 | } 166 | 167 | public static Packet createAbsorptionPacket(int entityId, float absorption) { 168 | ByteBuf buf = PacketByteBufs.create().writeByte(INDEX_ABSORPTION).writeInt(entityId).writeFloat(absorption); 169 | return ServerPlayNetworking.createS2CPacket(new NetworkPayload(PacketByteBufs.duplicate(buf))); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/overlay/parts/BaseOverlay.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.overlay.parts; 2 | 3 | import com.afoxxvi.asteorbar.AsteorBar; 4 | import com.afoxxvi.asteorbar.overlay.RenderGui; 5 | import com.afoxxvi.asteorbar.utils.GuiHelper; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.resources.ResourceLocation; 8 | 9 | public abstract class BaseOverlay { 10 | public static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(AsteorBar.MOD_ID, "textures/gui/overlay.png"); 11 | public static final ResourceLocation LIGHTMAP_TEXTURE = ResourceLocation.fromNamespaceAndPath(AsteorBar.MOD_ID, "textures/ui/lightmap.png"); 12 | public static final int FILL_FULL_WIDTH_LONG = 180; 13 | public static final int BOUND_FULL_WIDTH_LONG = 182; 14 | public static final int BOUND_FULL_WIDTH_SHORT = 81; 15 | public static final int Y_REGENERATION_FILL = 0; 16 | public static final int Y_FOOD_EXHAUSTION_FILL = 9; 17 | public static final int Y_EXPERIENCE_DECORATION = 18; 18 | public static final int Y_RIGHT_DECORATION = 27; 19 | public static final int Y_LEFT_DECORATION = 36; 20 | 21 | protected BaseOverlay overrideOverlay = null; 22 | protected int tick = 0; 23 | 24 | public void setOverrideOverlay(BaseOverlay overrideOverlay) { 25 | this.overrideOverlay = overrideOverlay; 26 | } 27 | 28 | public boolean shouldOverride() { 29 | return false; 30 | } 31 | 32 | protected void drawTextureFill(GuiGraphics guiGraphics, int left, int top, int width, int height, int textureX, int textureY) { 33 | GuiHelper.drawTexturedRect(guiGraphics, left, top, textureX, textureY, width, height); 34 | } 35 | 36 | protected void drawTextureFillColor(GuiGraphics guiGraphics, int left, int top, int width, int height, int textureX, int textureY, int textureWidth, int textureHeight, int color) { 37 | GuiHelper.drawTexturedRectColor(guiGraphics, left, top, left + width, top + height, textureX, textureY, textureX + textureWidth, textureY + textureHeight, 256, 256, color); 38 | } 39 | 40 | protected void drawTextureFillFlip(GuiGraphics guiGraphics, int left, int top, int right, int width, int height, int textureX, int textureY, int textureFullWidth, boolean flip) { 41 | if (flip) { 42 | GuiHelper.drawTexturedRect(guiGraphics, right - width, top, textureX + textureFullWidth - width, textureY, width, height); 43 | } else { 44 | GuiHelper.drawTexturedRect(guiGraphics, left, top, textureX, textureY, width, height); 45 | } 46 | } 47 | 48 | protected void drawEmptyFill(GuiGraphics guiGraphics, int left, int top, int right, int bottom, int color) { 49 | GuiHelper.drawSolidGradient(guiGraphics, left, top, right, bottom, color); 50 | } 51 | 52 | protected void drawFillFlipConcat(GuiGraphics guiGraphics, int left, int top, int right, int bottom, int has, int width, int color, boolean flip) { 53 | if (has == 0) { 54 | drawFillFlip(guiGraphics, left, top, right, bottom, width, color, flip); 55 | return; 56 | } 57 | width = Math.max(0, Math.min(right - left - has, width)); 58 | if (flip) { 59 | GuiHelper.drawSolidGradientUpDown(guiGraphics, right - has - width, top, right - has, bottom, color); 60 | } else { 61 | GuiHelper.drawSolidGradientUpDown(guiGraphics, left + has, top, left + has + width, bottom, color); 62 | } 63 | } 64 | 65 | protected void drawFillFlip(GuiGraphics guiGraphics, int left, int top, int right, int bottom, int width, int color, boolean flip) { 66 | width = Math.max(0, Math.min(right - left, width)); 67 | if (flip) { 68 | GuiHelper.drawSolidGradientUpDown(guiGraphics, right - width, top, right, bottom, color); 69 | } else { 70 | GuiHelper.drawSolidGradientUpDown(guiGraphics, left, top, left + width, bottom, color); 71 | } 72 | } 73 | 74 | protected void drawFillFlip(GuiGraphics guiGraphics, int left, int top, int right, int bottom, int width, int color, int color2, boolean flip) { 75 | width = Math.max(0, Math.min(right - left, width)); 76 | drawFillFlip(guiGraphics, left, top, right, bottom, width, color, flip); 77 | if (flip) { 78 | GuiHelper.drawSolidColor(guiGraphics, right - width, bottom - 1, right, bottom, color2); 79 | } else { 80 | GuiHelper.drawSolidColor(guiGraphics, left, bottom - 1, left + width, bottom, color2); 81 | } 82 | } 83 | 84 | protected void drawBoundFlipConcat(GuiGraphics guiGraphics, int left, int top, int right, int bottom, int has, int width, int color, boolean flip) { 85 | if (has == 0) { 86 | drawBoundFlip(guiGraphics, left, top, right, bottom, width, color, flip); 87 | return; 88 | } 89 | width = Math.max(0, Math.min(right - left - has, width)); 90 | if (width == 0) return; 91 | if (flip) { 92 | if (has + width >= right - left) { 93 | GuiHelper.drawSolidColor(guiGraphics, left, top + 1, left + 1, bottom - 1, color); 94 | width--; 95 | } 96 | //note that 1 pixel of 'has' is drawn as right bound 97 | GuiHelper.drawSolidColor(guiGraphics, right - has - width, top, right - has, top + 1, color); 98 | GuiHelper.drawSolidColor(guiGraphics, right - has - width, bottom - 1, right - has, bottom, color); 99 | } else { 100 | if (has + width >= right - left) { 101 | GuiHelper.drawSolidColor(guiGraphics, right - 1, top + 1, right, bottom - 1, color); 102 | width--; 103 | } 104 | GuiHelper.drawSolidColor(guiGraphics, left + has, top, left + has + width, top + 1, color); 105 | GuiHelper.drawSolidColor(guiGraphics, left + has, bottom - 1, left + has + width, bottom, color); 106 | } 107 | } 108 | 109 | protected void drawBoundFlip(GuiGraphics guiGraphics, int left, int top, int right, int bottom, int width, int color, boolean flip) { 110 | width = Math.max(0, Math.min(right - left, width)); 111 | if (width == 0) return; 112 | if (width == right - left) { 113 | drawBound(guiGraphics, left, top, right, bottom, color); 114 | return; 115 | } 116 | if (flip) { 117 | GuiHelper.drawSolidColor(guiGraphics, right - 1, top + 1, right, bottom - 1, color); 118 | if (width > 1) { 119 | GuiHelper.drawSolidColor(guiGraphics, right - 1 - width + 1, top, right - 1, top + 1, color); 120 | GuiHelper.drawSolidColor(guiGraphics, right - 1 - width + 1, bottom - 1, right - 1, bottom, color); 121 | } 122 | } else { 123 | GuiHelper.drawSolidColor(guiGraphics, left, top + 1, left + 1, bottom - 1, color); 124 | if (width > 1) { 125 | GuiHelper.drawSolidColor(guiGraphics, left + 1, top, left + 1 + width - 1, top + 1, color); 126 | GuiHelper.drawSolidColor(guiGraphics, left + 1, bottom - 1, left + 1 + width - 1, bottom, color); 127 | } 128 | } 129 | } 130 | 131 | protected void drawBound(GuiGraphics guiGraphics, int left, int top, int right, int bottom, int color) { 132 | GuiHelper.drawSolidColor(guiGraphics, left, top + 1, left + 1, bottom - 1, color); 133 | GuiHelper.drawSolidColor(guiGraphics, right - 1, top + 1, right, bottom - 1, color); 134 | GuiHelper.drawSolidColor(guiGraphics, left + 1, top, right - 1, top + 1, color); 135 | GuiHelper.drawSolidColor(guiGraphics, left + 1, bottom - 1, right - 1, bottom, color); 136 | } 137 | 138 | protected void drawBound(GuiGraphics guiGraphics, int left, int top, int right, int bottom, int color, int color2) { 139 | GuiHelper.drawSolidColor(guiGraphics, left, top + 1, left + 1, bottom - 2, color); 140 | GuiHelper.drawSolidColor(guiGraphics, right - 1, top + 1, right, bottom - 2, color); 141 | GuiHelper.drawSolidColor(guiGraphics, left + 1, top, right - 1, top + 1, color); 142 | GuiHelper.drawSolidColor(guiGraphics, left, bottom - 2, left + 1, bottom - 1, color2); 143 | GuiHelper.drawSolidColor(guiGraphics, right - 1, bottom - 2, right, bottom - 1, color2); 144 | GuiHelper.drawSolidColor(guiGraphics, left + 1, bottom - 1, right - 1, bottom, color2); 145 | } 146 | 147 | public void render(RenderGui gui, GuiGraphics guiGraphics, float partialTick, int screenWidth, int screenHeight) { 148 | if (AsteorBar.config.enableOverlay()) { 149 | tick = gui.gui().getGuiTicks(); 150 | if (overrideOverlay != null && overrideOverlay.shouldOverride()) { 151 | overrideOverlay.render(gui, guiGraphics, partialTick, screenWidth, screenHeight); 152 | } else { 153 | renderOverlay(gui, guiGraphics, partialTick, screenWidth, screenHeight); 154 | } 155 | } 156 | } 157 | 158 | public abstract void renderOverlay(RenderGui gui, GuiGraphics guiGraphics, float partialTick, int screenWidth, int screenHeight); 159 | } 160 | -------------------------------------------------------------------------------- /Common/src/main/resources/assets/asteorbar/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "asteorbar.key.toggle_overlay": "开启/关闭 状态栏", 3 | "asteorbar.key.toggle_mob_bar": "开启/关闭 生物信息条", 4 | "asteorbar.key.category": "AsteorBar 设置", 5 | "key.category.asteorbar.key_bindings": "AsteorBar 设置", 6 | "text.autoconfig.asteorbar.title": "AsteorBar 设置", 7 | "text.autoconfig.asteorbar.option.overlay": "状态栏设置", 8 | "text.autoconfig.asteorbar.option.entity": "生物信息条设置", 9 | "text.autoconfig.asteorbar.option.hook": "Mod联动设置", 10 | "text.autoconfig.asteorbar.option.overlay.enableOverlay": "开启状态栏", 11 | "text.autoconfig.asteorbar.option.overlay.overlayLayoutStyle": "状态栏布局", 12 | "text.autoconfig.asteorbar.option.overlay.overlayTextScale": "状态栏字体大小", 13 | "text.autoconfig.asteorbar.option.overlay.overlayBarInnerHeight": "状态栏内部高度", 14 | "text.autoconfig.asteorbar.option.overlay.overlayBarVerticalMargin": "状态栏垂直间距", 15 | "text.autoconfig.asteorbar.option.overlay.overlayBarTextOffsetY": "状态栏文本垂直偏移", 16 | "text.autoconfig.asteorbar.option.overlay.hideDecimalWhenEqualOrMoreThan": "当值大于等于时隐藏小数", 17 | "text.autoconfig.asteorbar.option.overlay.fullFoodLevelValue": "满饱食度值", 18 | "text.autoconfig.asteorbar.option.overlay.fullSaturationValue": "满饱和度值", 19 | "text.autoconfig.asteorbar.option.overlay.fullExhaustionValue": "满疲劳度值", 20 | "text.autoconfig.asteorbar.option.overlay.fullArmorValue": "满护甲值", 21 | "text.autoconfig.asteorbar.option.overlay.fullArmorToughnessValue": "满护甲韧性值", 22 | "text.autoconfig.asteorbar.option.overlay.fullHealthValue": "单条生命显示值", 23 | "text.autoconfig.asteorbar.option.overlay.enableStackHealthBar": "启用彩色生命条堆叠", 24 | "text.autoconfig.asteorbar.option.overlay.stackHealthBarColors": "彩色生命条颜色列表", 25 | "text.autoconfig.asteorbar.option.overlay.healthRegenerationOpacity": "生命值恢复效果不透明度", 26 | "text.autoconfig.asteorbar.option.overlay.healthRegenerationOpacityOnFull": "生命值恢复效果不透明度(满血)", 27 | "text.autoconfig.asteorbar.option.overlay.hideUnchangingBarAfterSeconds": "在指定秒数后隐藏不变的状态栏", 28 | "text.autoconfig.asteorbar.option.overlay.healthColorNormalARGB": "生命值颜色", 29 | "text.autoconfig.asteorbar.option.overlay.healthColorPoisonARGB": "生命值颜色(中毒)", 30 | "text.autoconfig.asteorbar.option.overlay.healthColorWitherARGB": "生命值颜色(凋零)", 31 | "text.autoconfig.asteorbar.option.overlay.healthColorFrozenARGB": "生命值颜色(冰冻)", 32 | "text.autoconfig.asteorbar.option.overlay.healthBoundColorARGB": "生命值边框颜色", 33 | "text.autoconfig.asteorbar.option.overlay.healthBoundColorBlinkARGB": "生命值边框颜色(闪烁)", 34 | "text.autoconfig.asteorbar.option.overlay.healthBoundColorLowARGB": "生命值边框颜色(低血量)", 35 | "text.autoconfig.asteorbar.option.overlay.healthEmptyColorARGB": "生命值背景颜色", 36 | "text.autoconfig.asteorbar.option.overlay.absorptionColorARGB": "吸收值颜色", 37 | "text.autoconfig.asteorbar.option.overlay.absorptionBoundColorARGB": "吸收值边框颜色", 38 | "text.autoconfig.asteorbar.option.overlay.foodColorNormalARGB": "饱食度颜色", 39 | "text.autoconfig.asteorbar.option.overlay.foodColorHungerARGB": "饱食度颜色(饥饿)", 40 | "text.autoconfig.asteorbar.option.overlay.foodBoundColorARGB": "饱食度边框颜色", 41 | "text.autoconfig.asteorbar.option.overlay.foodBoundColorBlinkARGB": "饱食度边框颜色(闪烁)", 42 | "text.autoconfig.asteorbar.option.overlay.foodEmptyColorARGB": "饱食度背景颜色", 43 | "text.autoconfig.asteorbar.option.overlay.saturationColorARGB": "饱和度颜色", 44 | "text.autoconfig.asteorbar.option.overlay.experienceColorARGB": "经验值颜色", 45 | "text.autoconfig.asteorbar.option.overlay.experienceBoundColorARGB": "经验值边框颜色", 46 | "text.autoconfig.asteorbar.option.overlay.experienceEmptyColorARGB": "经验值背景颜色", 47 | "text.autoconfig.asteorbar.option.overlay.airColorARGB": "氧气值颜色", 48 | "text.autoconfig.asteorbar.option.overlay.airBoundColorARGB": "氧气值边框颜色", 49 | "text.autoconfig.asteorbar.option.overlay.mountHealthColorARGB": "坐骑生命值颜色", 50 | "text.autoconfig.asteorbar.option.overlay.mountHealthColor2ARGB": "坐骑生命值底部颜色", 51 | "text.autoconfig.asteorbar.option.overlay.mountHealthBoundColorARGB": "坐骑生命值边框颜色", 52 | "text.autoconfig.asteorbar.option.overlay.mountHealthBoundColor2ARGB": "坐骑生命值底部边框颜色", 53 | "text.autoconfig.asteorbar.option.overlay.mountHealthEmptyColorARGB": "坐骑生命值背景颜色", 54 | "text.autoconfig.asteorbar.option.overlay.mountHealthOnLeftSide": "坐骑生命值左侧显示", 55 | "text.autoconfig.asteorbar.option.overlay.armorColorARGB": "护甲值颜色", 56 | "text.autoconfig.asteorbar.option.overlay.armorBoundColorARGB": "护甲值边框颜色", 57 | "text.autoconfig.asteorbar.option.overlay.armorEmptyColorARGB": "护甲值背景颜色", 58 | "text.autoconfig.asteorbar.option.overlay.armorToughnessColorARGB": "护甲韧性值颜色", 59 | "text.autoconfig.asteorbar.option.overlay.enableHealthBlink": "生命值低血量闪烁", 60 | "text.autoconfig.asteorbar.option.overlay.lowHealthRate": "低血量比例", 61 | "text.autoconfig.asteorbar.option.overlay.shakeHealthAndFoodWhileLow": "低血量/饱食度时抖动", 62 | "text.autoconfig.asteorbar.option.overlay.overwriteVanillaArmorBar": "替换原版护甲条", 63 | "text.autoconfig.asteorbar.option.overlay.overwriteVanillaExperienceBar": "替换原版经验条", 64 | "text.autoconfig.asteorbar.option.overlay.displayExperienceProgress": "显示经验值文本", 65 | "text.autoconfig.asteorbar.option.overlay.displayExperienceLevel": "显示等级文本", 66 | "text.autoconfig.asteorbar.option.overlay.displayHealthText": "显示生命值文本", 67 | "text.autoconfig.asteorbar.option.overlay.displayAbsorptionMethod": "吸收值显示模式", 68 | "text.autoconfig.asteorbar.option.overlay.displayAbsorptionDivMaxHealth": "显示吸收值/最大生命值", 69 | "text.autoconfig.asteorbar.option.overlay.displayAbsorptionTextMethod": "吸收值文本显示模式", 70 | "text.autoconfig.asteorbar.option.overlay.enableFoodBlink": "饱食度低血量闪烁", 71 | "text.autoconfig.asteorbar.option.overlay.displaySaturation": "显示饱和度", 72 | "text.autoconfig.asteorbar.option.overlay.displayExhaustion": "显示疲劳度", 73 | "text.autoconfig.asteorbar.option.overlay.displayFoodText": "显示饱食度文本", 74 | "text.autoconfig.asteorbar.option.overlay.displayArmorToughness": "显示护甲韧性", 75 | "text.autoconfig.asteorbar.option.overlay.cornerBarLength": "角落布局状态栏长度", 76 | "text.autoconfig.asteorbar.option.overlay.cornerHorizontalPadding": "角落布局状态栏水平内间距", 77 | "text.autoconfig.asteorbar.option.overlay.cornerVerticalPadding": "角落布局状态栏垂直内间距", 78 | "text.autoconfig.asteorbar.option.overlay.forceRenderAtCorner": "强制所有状态栏出现在角落", 79 | "text.autoconfig.asteorbar.option.entity.enableHealthBar": "开启生物信息条", 80 | "text.autoconfig.asteorbar.option.entity.maxDistance": "最大显示距离", 81 | "text.autoconfig.asteorbar.option.entity.showOnSelf": "在自己身上显示", 82 | "text.autoconfig.asteorbar.option.entity.showOnPlayers": "在玩家身上显示", 83 | "text.autoconfig.asteorbar.option.entity.showOnBosses": "在Boss身上显示", 84 | "text.autoconfig.asteorbar.option.entity.showOnArmorStands": "在盔甲架上显示", 85 | "text.autoconfig.asteorbar.option.entity.showOnFullHealthWithoutAbsorption": "生命值满且没有吸收值时显示", 86 | "text.autoconfig.asteorbar.option.entity.showOnFullHealthWithAbsorption": "生命值满且有吸收值时显示", 87 | "text.autoconfig.asteorbar.option.entity.healthBarAlpha": "生物信息条不透明度", 88 | "text.autoconfig.asteorbar.option.entity.healthBarHalfWidth": "生物信息条半宽度", 89 | "text.autoconfig.asteorbar.option.entity.healthBarHalfHeight": "生物信息条半高度", 90 | "text.autoconfig.asteorbar.option.entity.healthBarOffsetY": "生物信息条垂直偏移", 91 | "text.autoconfig.asteorbar.option.entity.healthBarScale": "生物信息条缩放比例", 92 | "text.autoconfig.asteorbar.option.entity.healthBarTextScale": "生物信息条字体大小", 93 | "text.autoconfig.asteorbar.option.entity.healthBarTextOffsetY": "生物信息条文本垂直偏移", 94 | "text.autoconfig.asteorbar.option.entity.healthBarBoundWidth": "生物信息条边框宽度", 95 | "text.autoconfig.asteorbar.option.entity.healthBarBoundVertex": "生物信息条边框顶点", 96 | "text.autoconfig.asteorbar.option.entity.healthBarHealthColorARGB": "生物信息条生命值颜色", 97 | "text.autoconfig.asteorbar.option.entity.healthBarAbsorptionColorARGB": "生物信息条吸收值颜色", 98 | "text.autoconfig.asteorbar.option.entity.healthBarBoundColorARGB": "生物信息条边框颜色", 99 | "text.autoconfig.asteorbar.option.entity.healthBarEmptyColorARGB": "生物信息条背景颜色", 100 | "text.autoconfig.asteorbar.option.entity.healthBarHealthColorDynamic": "生物信息条生命值动态颜色", 101 | "text.autoconfig.asteorbar.option.entity.healthBarHealthColorFullARGB": "生物信息条生命值颜色(满血)", 102 | "text.autoconfig.asteorbar.option.entity.healthBarHealthColorEmptyARGB": "生物信息条生命值颜色(空血)", 103 | "text.autoconfig.asteorbar.option.hook.hookToughAsNails": "Tough As Nails", 104 | "text.autoconfig.asteorbar.option.hook.hookThirstWasTaken": "Thirst Was Taken", 105 | "text.autoconfig.asteorbar.option.hook.hookMekanism": "Mekanism", 106 | "text.autoconfig.asteorbar.option.hook.hookDehydration": "Dehydration", 107 | "text.autoconfig.asteorbar.option.hook.hookParcool": "Parcool", 108 | "text.autoconfig.asteorbar.option.hook.hookIronsSpellbooks": "Iron's Spellbooks", 109 | "text.autoconfig.asteorbar.option.hook.hookFeathers": "Feathers", 110 | "text.autoconfig.asteorbar.option.hook.hookAppleSkin": "AppleSkin", 111 | "text.autoconfig.asteorbar.option.hook.hookSuperiorShields": "Superior Shields", 112 | "text.autoconfig.asteorbar.option.hook.hookVampirism": "Vampirism", 113 | "text.autoconfig.asteorbar.option.hook.hookBotania": "Botania", 114 | "text.autoconfig.asteorbar.option.hook.hookOrigins": "Origins", 115 | "text.autoconfig.asteorbar.option.hook.hookTFC": "TerraFirmaCraft", 116 | "text.autoconfig.asteorbar.option.hook.hookArsNouveau": "Ars Nouveau", 117 | "text.autoconfig.asteorbar.option.hook.hookApoli": "Apoli(Origins)", 118 | "text.autoconfig.asteorbar.option.hook.hookThermoo": "Thermoo(Scorchful & Frostiful)", 119 | "text.autoconfig.asteorbar.option.hook.hookMealApi": "Meal API", 120 | "asteorbar.json.lastPlaceholder": "Last Placeholder" 121 | } 122 | -------------------------------------------------------------------------------- /Common/src/main/java/com/afoxxvi/asteorbar/config/ConfigAdapter.java: -------------------------------------------------------------------------------- 1 | package com.afoxxvi.asteorbar.config; 2 | 3 | import com.afoxxvi.asteorbar.utils.Utils; 4 | 5 | public interface ConfigAdapter { 6 | boolean enableOverlay(); 7 | 8 | void enableOverlay(boolean enable); 9 | 10 | int overlayLayoutStyle(); 11 | 12 | void overlayLayoutStyle(int style); 13 | 14 | double overlayTextScale(); 15 | 16 | int overlayBarInnerHeight(); 17 | 18 | int overlayBarVerticalMargin(); 19 | 20 | int overlayBarTextOffsetY(); 21 | 22 | double hideDecimalWhenEqualOrMoreThan(); 23 | 24 | int fullFoodLevelValue(); 25 | 26 | double fullSaturationValue(); 27 | 28 | double fullExhaustionValue(); 29 | 30 | int fullArmorValue(); 31 | 32 | int fullArmorToughnessValue(); 33 | 34 | int fullHealthValue(); 35 | 36 | boolean enableStackHealthBar(); 37 | 38 | String stackHealthBarColors(); 39 | 40 | double healthRegenerationOpacity(); 41 | 42 | double healthRegenerationOpacityOnFull(); 43 | 44 | int hideUnchangingBarAfterSeconds(); 45 | 46 | default int healthColorNormal() { 47 | return Utils.parseColor(healthColorNormalARGB()); 48 | } 49 | 50 | String healthColorNormalARGB(); 51 | 52 | default int healthColorPoison() { 53 | return Utils.parseColor(healthColorPoisonARGB()); 54 | } 55 | 56 | String healthColorPoisonARGB(); 57 | 58 | default int healthColorWither() { 59 | return Utils.parseColor(healthColorWitherARGB()); 60 | } 61 | 62 | String healthColorWitherARGB(); 63 | 64 | default int healthColorFrozen() { 65 | return Utils.parseColor(healthColorFrozenARGB()); 66 | } 67 | 68 | String healthColorFrozenARGB(); 69 | 70 | default int healthBoundColor() { 71 | return Utils.parseColor(healthBoundColorARGB()); 72 | } 73 | 74 | String healthBoundColorARGB(); 75 | 76 | default int healthBoundColorBlink() { 77 | return Utils.parseColor(healthBoundColorBlinkARGB()); 78 | } 79 | 80 | String healthBoundColorBlinkARGB(); 81 | 82 | default int healthBoundColorLow() { 83 | return Utils.parseColor(healthBoundColorLowARGB()); 84 | } 85 | 86 | String healthBoundColorLowARGB(); 87 | 88 | default int healthEmptyColor() { 89 | return Utils.parseColor(healthEmptyColorARGB()); 90 | } 91 | 92 | String healthEmptyColorARGB(); 93 | 94 | default int absorptionColor() { 95 | return Utils.parseColor(absorptionColorARGB()); 96 | } 97 | 98 | String absorptionColorARGB(); 99 | 100 | default int absorptionBoundColor() { 101 | return Utils.parseColor(absorptionBoundColorARGB()); 102 | } 103 | 104 | String absorptionBoundColorARGB(); 105 | 106 | default int foodColorNormal() { 107 | return Utils.parseColor(foodColorNormalARGB()); 108 | } 109 | 110 | String foodColorNormalARGB(); 111 | 112 | default int foodColorHunger() { 113 | return Utils.parseColor(foodColorHungerARGB()); 114 | } 115 | 116 | String foodColorHungerARGB(); 117 | 118 | default int foodBoundColor() { 119 | return Utils.parseColor(foodBoundColorARGB()); 120 | } 121 | 122 | String foodBoundColorARGB(); 123 | 124 | default int foodBoundColorBlink() { 125 | return Utils.parseColor(foodBoundColorBlinkARGB()); 126 | } 127 | 128 | String foodBoundColorBlinkARGB(); 129 | 130 | default int foodEmptyColor() { 131 | return Utils.parseColor(foodEmptyColorARGB()); 132 | } 133 | 134 | String foodEmptyColorARGB(); 135 | 136 | default int saturationColor() { 137 | return Utils.parseColor(saturationColorARGB()); 138 | } 139 | 140 | String saturationColorARGB(); 141 | 142 | default int experienceColor() { 143 | return Utils.parseColor(experienceColorARGB()); 144 | } 145 | 146 | String experienceColorARGB(); 147 | 148 | default int experienceBoundColor() { 149 | return Utils.parseColor(experienceBoundColorARGB()); 150 | } 151 | 152 | String experienceBoundColorARGB(); 153 | 154 | default int experienceEmptyColor() { 155 | return Utils.parseColor(experienceEmptyColorARGB()); 156 | } 157 | 158 | String experienceEmptyColorARGB(); 159 | 160 | default int airColor() { 161 | return Utils.parseColor(airColorARGB()); 162 | } 163 | 164 | String airColorARGB(); 165 | 166 | default int airBoundColor() { 167 | return Utils.parseColor(airBoundColorARGB()); 168 | } 169 | 170 | String airBoundColorARGB(); 171 | 172 | default int mountHealthColor() { 173 | return Utils.parseColor(mountHealthColorARGB()); 174 | } 175 | 176 | String mountHealthColorARGB(); 177 | 178 | default int mountHealthColor2() { 179 | return Utils.parseColor(mountHealthColor2ARGB()); 180 | } 181 | 182 | String mountHealthColor2ARGB(); 183 | 184 | default int mountHealthBoundColor() { 185 | return Utils.parseColor(mountHealthBoundColorARGB()); 186 | } 187 | 188 | String mountHealthBoundColorARGB(); 189 | 190 | default int mountHealthBoundColor2() { 191 | return Utils.parseColor(mountHealthBoundColor2ARGB()); 192 | } 193 | 194 | String mountHealthBoundColor2ARGB(); 195 | 196 | default int mountHealthEmptyColor() { 197 | return Utils.parseColor(mountHealthEmptyColorARGB()); 198 | } 199 | 200 | String mountHealthEmptyColorARGB(); 201 | 202 | boolean mountHealthOnLeftSide(); 203 | 204 | default int armorColor() { 205 | return Utils.parseColor(armorColorARGB()); 206 | } 207 | 208 | String armorColorARGB(); 209 | 210 | default int armorBoundColor() { 211 | return Utils.parseColor(armorBoundColorARGB()); 212 | } 213 | 214 | String armorBoundColorARGB(); 215 | 216 | default int armorEmptyColor() { 217 | return Utils.parseColor(armorEmptyColorARGB()); 218 | } 219 | 220 | String armorEmptyColorARGB(); 221 | 222 | default int armorToughnessColor() { 223 | return Utils.parseColor(armorToughnessColorARGB()); 224 | } 225 | 226 | String armorToughnessColorARGB(); 227 | 228 | boolean enableHealthBlink(); 229 | 230 | double lowHealthRate(); 231 | 232 | boolean shakeHealthAndFoodWhileLow(); 233 | 234 | boolean overwriteVanillaArmorBar(); 235 | 236 | boolean overwriteVanillaExperienceBar(); 237 | 238 | boolean displayExperienceProgress(); 239 | 240 | boolean displayExperienceLevel(); 241 | 242 | boolean displayHealthText(); 243 | 244 | int displayAbsorptionMethod(); 245 | 246 | boolean displayAbsorptionDivMaxHealth(); 247 | 248 | int displayAbsorptionTextMethod(); 249 | 250 | boolean enableFoodBlink(); 251 | 252 | boolean displaySaturation(); 253 | 254 | boolean displayExhaustion(); 255 | 256 | boolean displayFoodText(); 257 | 258 | boolean displayArmorToughness(); 259 | 260 | int cornerBarLength(); 261 | 262 | int cornerHorizontalPadding(); 263 | 264 | int cornerVerticalPadding(); 265 | 266 | boolean forceRenderAtCorner(); 267 | 268 | //mob config 269 | boolean enableHealthBar(); 270 | 271 | void enableHealthBar(boolean enable); 272 | 273 | double maxDistance(); 274 | 275 | boolean showOnSelf(); 276 | 277 | boolean showOnPlayers(); 278 | 279 | boolean showOnBosses(); 280 | 281 | boolean showOnArmorStands(); 282 | 283 | boolean showOnFullHealthWithoutAbsorption(); 284 | 285 | boolean showOnFullHealthWithAbsorption(); 286 | 287 | int healthBarAlpha(); 288 | 289 | int healthBarHalfWidth(); 290 | 291 | int healthBarHalfHeight(); 292 | 293 | double healthBarOffsetY(); 294 | 295 | double healthBarScale(); 296 | 297 | double healthBarTextScale(); 298 | 299 | double healthBarTextOffsetY(); 300 | 301 | int healthBarBoundWidth(); 302 | 303 | boolean healthBarBoundVertex(); 304 | 305 | default int healthBarHealthColor() { 306 | return Utils.parseColor(healthBarHealthColorARGB()); 307 | } 308 | 309 | String healthBarHealthColorARGB(); 310 | 311 | default int healthBarAbsorptionColor() { 312 | return Utils.parseColor(healthBarAbsorptionColorARGB()); 313 | } 314 | 315 | String healthBarAbsorptionColorARGB(); 316 | 317 | default int healthBarBoundColor() { 318 | return Utils.parseColor(healthBarBoundColorARGB()); 319 | } 320 | 321 | String healthBarBoundColorARGB(); 322 | 323 | default int healthBarEmptyColor() { 324 | return Utils.parseColor(healthBarEmptyColorARGB()); 325 | } 326 | 327 | String healthBarEmptyColorARGB(); 328 | 329 | boolean healthBarHealthColorDynamic(); 330 | 331 | default int healthBarHealthColorFull() { 332 | return Utils.parseColor(healthBarHealthColorFullARGB()); 333 | } 334 | 335 | String healthBarHealthColorFullARGB(); 336 | 337 | default int healthBarHealthColorEmpty() { 338 | return Utils.parseColor(healthBarHealthColorEmptyARGB()); 339 | } 340 | 341 | String healthBarHealthColorEmptyARGB(); 342 | 343 | boolean hookToughAsNails(); 344 | 345 | boolean hookThirstWasTaken(); 346 | 347 | boolean hookMekanism(); 348 | 349 | boolean hookDehydration(); 350 | 351 | boolean hookParcool(); 352 | 353 | boolean hookIronsSpellbooks(); 354 | 355 | boolean hookFeathers(); 356 | 357 | boolean hookAppleSkin(); 358 | 359 | boolean hookSuperiorShields(); 360 | 361 | boolean hookVampirism(); 362 | 363 | boolean hookBotania(); 364 | 365 | boolean hookOrigins(); 366 | 367 | boolean hookTFC(); 368 | 369 | boolean hookArsNouveau(); 370 | 371 | boolean hookApoli(); 372 | 373 | boolean hookThermoo(); 374 | 375 | boolean hookMealApi(); 376 | } 377 | --------------------------------------------------------------------------------