Skip to content

Commit 3d5ce85

Browse files
committed
1.1.0
1 parent 9c53e82 commit 3d5ce85

File tree

7 files changed

+227
-79
lines changed

7 files changed

+227
-79
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
plugins {
2-
id 'fabric-loom' version '0.11-SNAPSHOT'
2+
id 'fabric-loom' version '1.1-SNAPSHOT'
33
}
44

55
sourceCompatibility = JavaVersion.VERSION_17

gradle.properties

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
org.gradle.jvmargs=-Xmx1G
33

44
# Fabric Properties
5-
minecraft_version=1.18.2
6-
yarn_mappings=1.18.2+build.2
7-
loader_version=0.13.3
5+
minecraft_version=1.18
6+
yarn_mappings=1.18+build.1
7+
loader_version=0.14.19
88

99
# Mod Properties
10-
mod_version = 1.0.0
10+
mod_version = 1.1.0
1111
archives_base_name = PlayerHealthIndicators
1212

1313
# Dependencies
14-
fabric_version=0.47.10+1.18.2
14+
fabric_version=0.46.6+1.18
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package me.andrew.healthindicators;
2+
3+
import com.google.gson.Gson;
4+
import net.fabricmc.loader.api.FabricLoader;
5+
6+
import java.io.BufferedReader;
7+
import java.io.BufferedWriter;
8+
import java.io.FileReader;
9+
import java.io.FileWriter;
10+
11+
public class Config {
12+
private static final Gson GSON = new Gson();
13+
14+
private static Config INSTANCE = new Config();
15+
16+
private boolean renderingEnabled = true;
17+
private boolean heartStackingEnabled = true;
18+
private int heartOffset = 0;
19+
20+
public static boolean getRenderingEnabled() {
21+
return INSTANCE.renderingEnabled;
22+
}
23+
24+
public static void setRenderingEnabled(boolean renderingEnabled) {
25+
INSTANCE.renderingEnabled = renderingEnabled;
26+
save();
27+
}
28+
29+
public static boolean getHeartStackingEnabled() {
30+
return INSTANCE.heartStackingEnabled;
31+
}
32+
33+
public static void setHeartStackingEnabled(boolean heartStackingEnabled) {
34+
INSTANCE.heartStackingEnabled = heartStackingEnabled;
35+
save();
36+
}
37+
38+
public static int getHeartOffset() {
39+
return INSTANCE.heartOffset;
40+
}
41+
42+
public static void setHeartOffset(int heartOffset) {
43+
INSTANCE.heartOffset = heartOffset;
44+
save();
45+
}
46+
47+
public static void load() {
48+
try (BufferedReader reader = new BufferedReader(new FileReader(FabricLoader.getInstance().getConfigDir().resolve(HealthIndicatorsMod.CONFIG_FILE).toFile()))) {
49+
Config config = GSON.fromJson(reader, Config.class);
50+
if (config != null) {
51+
INSTANCE = config;
52+
}
53+
} catch (Exception e) {
54+
e.printStackTrace();
55+
}
56+
}
57+
58+
public static void save() {
59+
try (BufferedWriter writer = new BufferedWriter(new FileWriter(FabricLoader.getInstance().getConfigDir().resolve(HealthIndicatorsMod.CONFIG_FILE).toFile()))) {
60+
GSON.toJson(INSTANCE, writer);
61+
} catch (Exception e) {
62+
e.printStackTrace();
63+
}
64+
}
65+
}

src/main/java/me/andrew/healthindicators/HealthIndicatorsMod.java

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,59 @@
1010
public class HealthIndicatorsMod implements ModInitializer {
1111
public static final String MOD_ID = "healthindicators";
1212

13-
public static KeyBinding keyBinding;
14-
public static boolean toggled = true;
13+
public static final String CONFIG_FILE = "healthindicators.json";
14+
15+
public static final KeyBinding RENDERING_ENABLED_KEY_BINDING = KeyBindingHelper.registerKeyBinding(new KeyBinding(
16+
"key." + MOD_ID + ".renderingEnabled",
17+
InputUtil.UNKNOWN_KEY.getCode(),
18+
"key.categories." + MOD_ID
19+
));
20+
public static final KeyBinding HEART_STACKING_ENABLED_KEY_BINDING = KeyBindingHelper.registerKeyBinding(new KeyBinding(
21+
"key." + MOD_ID + ".heartStackingEnabled",
22+
InputUtil.UNKNOWN_KEY.getCode(),
23+
"key.categories." + MOD_ID
24+
));
25+
public static final KeyBinding INCREASE_HEART_OFFSET_KEY_BINDING = KeyBindingHelper.registerKeyBinding(new KeyBinding(
26+
"key." + MOD_ID + ".increaseHeartOffset",
27+
InputUtil.UNKNOWN_KEY.getCode(),
28+
"key.categories." + MOD_ID
29+
));
30+
public static final KeyBinding DECREASE_HEART_OFFSET_KEY_BINDING = KeyBindingHelper.registerKeyBinding(new KeyBinding(
31+
"key." + MOD_ID + ".decreaseHeartOffset",
32+
InputUtil.UNKNOWN_KEY.getCode(),
33+
"key.categories." + MOD_ID
34+
));
1535

1636
@Override
1737
public void onInitialize() {
18-
keyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
19-
"key." + MOD_ID + ".toggle",
20-
InputUtil.UNKNOWN_KEY.getCode(),
21-
"key.categories." + MOD_ID
22-
));
38+
Config.load();
2339

2440
ClientTickEvents.END_CLIENT_TICK.register(client -> {
25-
while (keyBinding.wasPressed()) {
26-
toggled = !toggled;
27-
if(client.player != null) {
28-
client.player.sendMessage(new LiteralText((toggled ? "Enabled" : "Disabled") + " Health Indicators"), true);
41+
while (RENDERING_ENABLED_KEY_BINDING.wasPressed()) {
42+
Config.setRenderingEnabled(!Config.getRenderingEnabled());
43+
if (client.player != null) {
44+
client.player.sendMessage(new LiteralText((Config.getRenderingEnabled() ? "Enabled" : "Disabled") + " Health Indicators"), true);
45+
}
46+
}
47+
48+
while (HEART_STACKING_ENABLED_KEY_BINDING.wasPressed()) {
49+
Config.setHeartStackingEnabled(!Config.getHeartStackingEnabled());
50+
if (client.player != null) {
51+
client.player.sendMessage(new LiteralText((Config.getHeartStackingEnabled() ? "Enabled" : "Disabled") + " Heart Stacking"), true);
52+
}
53+
}
54+
55+
while (INCREASE_HEART_OFFSET_KEY_BINDING.wasPressed()) {
56+
Config.setHeartOffset(Config.getHeartOffset() + 1);
57+
if (client.player != null) {
58+
client.player.sendMessage(new LiteralText("Set heart offset to " + Config.getHeartOffset()), true);
59+
}
60+
}
61+
62+
while (DECREASE_HEART_OFFSET_KEY_BINDING.wasPressed()) {
63+
Config.setHeartOffset(Config.getHeartOffset() - 1);
64+
if (client.player != null) {
65+
client.player.sendMessage(new LiteralText("Set heart offset to " + Config.getHeartOffset()), true);
2966
}
3067
}
3168
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package me.andrew.healthindicators;
2+
3+
public enum HeartType {
4+
EMPTY(16 + 0 * 9, 0),
5+
RED_FULL(16 + 4 * 9, 0),
6+
RED_HALF(16 + 5 * 9, 0),
7+
YELLOW_FULL(16 + 16 * 9, 0),
8+
YELLOW_HALF(16 + 17 * 9, 0);
9+
10+
public final int u;
11+
public final int v;
12+
13+
HeartType(int u, int v) {
14+
this.u = u;
15+
this.v = v;
16+
}
17+
}

src/main/java/me/andrew/healthindicators/mixin/PlayerEntityRendererMixin.java

Lines changed: 87 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package me.andrew.healthindicators.mixin;
22

33
import com.mojang.blaze3d.systems.RenderSystem;
4-
import me.andrew.healthindicators.HealthIndicatorsMod;
4+
import me.andrew.healthindicators.Config;
5+
import me.andrew.healthindicators.HeartType;
6+
import net.minecraft.client.MinecraftClient;
57
import net.minecraft.client.gui.DrawableHelper;
68
import net.minecraft.client.network.AbstractClientPlayerEntity;
79
import net.minecraft.client.render.*;
@@ -10,6 +12,7 @@
1012
import net.minecraft.client.render.entity.PlayerEntityRenderer;
1113
import net.minecraft.client.render.entity.model.PlayerEntityModel;
1214
import net.minecraft.client.util.math.MatrixStack;
15+
import net.minecraft.entity.Entity;
1316
import net.minecraft.util.math.MathHelper;
1417
import net.minecraft.util.math.Matrix4f;
1518
import org.spongepowered.asm.mixin.Mixin;
@@ -28,86 +31,109 @@ public PlayerEntityRendererMixin(EntityRendererFactory.Context ctx, PlayerEntity
2831
at = @At("RETURN")
2932
)
3033
public void renderHealth(AbstractClientPlayerEntity abstractClientPlayerEntity, float f, float g, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) {
31-
if (HealthIndicatorsMod.toggled && !abstractClientPlayerEntity.isMainPlayer()) {
32-
matrixStack.push();
34+
if (!Config.getRenderingEnabled()) return;
3335

34-
double d = this.dispatcher.getSquaredDistanceToCamera(abstractClientPlayerEntity);
36+
if (!shouldRenderHeartsForEntity(abstractClientPlayerEntity)) return;
3537

36-
matrixStack.translate(0, abstractClientPlayerEntity.getHeight() + 0.5f, 0);
37-
if (this.hasLabel(abstractClientPlayerEntity) && d <= 4096.0) {
38+
matrixStack.push();
39+
40+
double d = this.dispatcher.getSquaredDistanceToCamera(abstractClientPlayerEntity);
41+
42+
matrixStack.translate(0, abstractClientPlayerEntity.getHeight() + 0.5f, 0);
43+
if (this.hasLabel(abstractClientPlayerEntity) && d <= 4096.0) {
44+
matrixStack.translate(0.0D, 9.0F * 1.15F * 0.025F, 0.0D);
45+
if (d < 100.0 && abstractClientPlayerEntity.getScoreboard().getObjectiveForSlot(2) != null) {
3846
matrixStack.translate(0.0D, 9.0F * 1.15F * 0.025F, 0.0D);
39-
if (d < 100.0 && abstractClientPlayerEntity.getScoreboard().getObjectiveForSlot(2) != null) {
40-
matrixStack.translate(0.0D, 9.0F * 1.15F * 0.025F, 0.0D);
41-
}
4247
}
48+
}
4349

44-
matrixStack.multiply(this.dispatcher.getRotation());
50+
matrixStack.multiply(this.dispatcher.getRotation());
4551
// matrixStack.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(mc.gameRenderer.getCamera().getPitch()));
4652

47-
float pixelSize = 0.025F;
48-
matrixStack.scale(pixelSize, pixelSize, pixelSize);
49-
50-
Tessellator tessellator = Tessellator.getInstance();
51-
BufferBuilder vertexConsumer = tessellator.getBuffer();
52-
53-
vertexConsumer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE);
54-
RenderSystem.setShader(GameRenderer::getPositionTexShader);
55-
RenderSystem.setShaderTexture(0, DrawableHelper.GUI_ICONS_TEXTURE);
56-
RenderSystem.enableDepthTest();
57-
58-
Matrix4f model = matrixStack.peek().getPositionMatrix();
59-
60-
int healthRed = MathHelper.ceil(abstractClientPlayerEntity.getHealth());
61-
int maxHealth = MathHelper.ceil(abstractClientPlayerEntity.getMaxHealth());
62-
int healthYellow = MathHelper.ceil(abstractClientPlayerEntity.getAbsorptionAmount());
63-
64-
int heartsRed = MathHelper.ceil(healthRed / 2.0f);
65-
boolean lastRedHalf = (healthRed & 1) == 1;
66-
int heartsNormal = MathHelper.ceil(maxHealth / 2.0f);
67-
int heartsYellow = MathHelper.ceil(healthYellow / 2.0f);
68-
boolean lastYellowHalf = (healthYellow & 1) == 1;
69-
int heartsTotal = heartsNormal + heartsYellow;
70-
71-
int pixelsTotal = heartsTotal * 8 + 1;
72-
float maxX = pixelsTotal / 2.0f;
73-
for (int heart = 0; heart < heartsTotal; heart++){
74-
float x = maxX - heart * 8;
75-
drawHeart(model, vertexConsumer, x, 0);
76-
// Offset in the gui icons texture in hearts
77-
// 0 - empty, 2 - red, 8 - yellow, +1 for half
78-
int type;
79-
if (heart < heartsRed) {
80-
type = 2 * 2;
81-
if (heart == heartsRed - 1 && lastRedHalf) type += 1;
82-
} else if (heart < heartsNormal) {
83-
type = 0;
84-
} else {
85-
type = 8 * 2;
86-
if(heart == heartsTotal - 1 && lastYellowHalf) type += 1;
53+
float pixelSize = 0.025F;
54+
matrixStack.scale(pixelSize, pixelSize, pixelSize);
55+
matrixStack.translate(0, Config.getHeartOffset(), 0);
56+
57+
Tessellator tessellator = Tessellator.getInstance();
58+
BufferBuilder vertexConsumer = tessellator.getBuffer();
59+
60+
vertexConsumer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE);
61+
RenderSystem.setShader(GameRenderer::getPositionTexShader);
62+
RenderSystem.setShaderTexture(0, DrawableHelper.GUI_ICONS_TEXTURE);
63+
RenderSystem.enableDepthTest();
64+
65+
Matrix4f model = matrixStack.peek().getPositionMatrix();
66+
67+
int healthRed = MathHelper.ceil(abstractClientPlayerEntity.getHealth());
68+
int maxHealth = MathHelper.ceil(abstractClientPlayerEntity.getMaxHealth());
69+
int healthYellow = MathHelper.ceil(abstractClientPlayerEntity.getAbsorptionAmount());
70+
71+
int heartsRed = MathHelper.ceil(healthRed / 2.0f);
72+
boolean lastRedHalf = (healthRed & 1) == 1;
73+
int heartsNormal = MathHelper.ceil(maxHealth / 2.0f);
74+
int heartsYellow = MathHelper.ceil(healthYellow / 2.0f);
75+
boolean lastYellowHalf = (healthYellow & 1) == 1;
76+
int heartsTotal = heartsNormal + heartsYellow;
77+
78+
int heartsPerRow = Config.getHeartStackingEnabled() ? 10 : heartsTotal;
79+
int rowsTotal = (heartsTotal + heartsPerRow - 1) / heartsPerRow;
80+
int rowOffset = Math.max(10 - (rowsTotal - 2), 3);
81+
82+
int pixelsTotal = Math.min(heartsTotal, heartsPerRow) * 8 + 1;
83+
float maxX = pixelsTotal / 2.0f;
84+
for (int heart = 0; heart < heartsTotal; heart++){
85+
int row = heart / heartsPerRow;
86+
int col = heart % heartsPerRow;
87+
88+
float x = maxX - col * 8;
89+
float y = row * rowOffset;
90+
float z = row * 0.01F;
91+
drawHeart(model, vertexConsumer, x, y, z, HeartType.EMPTY);
92+
93+
HeartType type;
94+
if (heart < heartsRed) {
95+
type = HeartType.RED_FULL;
96+
if (heart == heartsRed - 1 && lastRedHalf) {
97+
type = HeartType.RED_HALF;
8798
}
88-
if (type != 0) {
89-
drawHeart(model, vertexConsumer, x, type);
99+
} else if (heart < heartsNormal) {
100+
type = HeartType.EMPTY;
101+
} else {
102+
type = HeartType.YELLOW_FULL;
103+
if (heart == heartsTotal - 1 && lastYellowHalf) {
104+
type = HeartType.YELLOW_HALF;
90105
}
91106
}
107+
if (type != HeartType.EMPTY) {
108+
drawHeart(model, vertexConsumer, x, y, z, type);
109+
}
110+
}
111+
112+
tessellator.draw();
92113

93-
tessellator.draw();
114+
matrixStack.pop();
115+
}
94116

95-
matrixStack.pop();
117+
private static boolean shouldRenderHeartsForEntity(Entity entity) {
118+
if (entity instanceof AbstractClientPlayerEntity abstractClientPlayerEntity) {
119+
return !abstractClientPlayerEntity.isMainPlayer() && !abstractClientPlayerEntity.isInvisibleTo(MinecraftClient.getInstance().player);
96120
}
121+
122+
return false;
97123
}
98124

99-
private static void drawHeart(Matrix4f model, VertexConsumer vertexConsumer, float x, int type){
100-
float minU = 16F / 256F + type * 9F / 256F;
125+
private static void drawHeart(Matrix4f model, VertexConsumer vertexConsumer, float x, float y, float z, HeartType type){
126+
float minU = type.u / 256F;
101127
float maxU = minU + 9F / 256F;
102-
float minV = 0;
128+
float minV = type.v / 256F;
103129
float maxV = minV + 9F / 256F;
104130

105131
float heartSize = 9F;
106132

107-
drawVertex(model, vertexConsumer, x, 0F - heartSize, 0F, minU, maxV);
108-
drawVertex(model, vertexConsumer, x - heartSize, 0F - heartSize, 0F, maxU, maxV);
109-
drawVertex(model, vertexConsumer, x - heartSize, 0F, 0F, maxU, minV);
110-
drawVertex(model, vertexConsumer, x, 0F, 0F, minU, minV);
133+
drawVertex(model, vertexConsumer, x, y - heartSize, z, minU, maxV);
134+
drawVertex(model, vertexConsumer, x - heartSize, y - heartSize, z, maxU, maxV);
135+
drawVertex(model, vertexConsumer, x - heartSize, y, z, maxU, minV);
136+
drawVertex(model, vertexConsumer, x, y, z, minU, minV);
111137
}
112138

113139
private static void drawVertex(Matrix4f model, VertexConsumer vertices, float x, float y, float z, float u, float v) {
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
{
22
"key.categories.healthindicators": "Player Health Indicators",
3-
"key.healthindicators.toggle": "Toggle"
3+
"key.healthindicators.renderingEnabled": "Toggle Rendering",
4+
"key.healthindicators.heartStackingEnabled": "Toggle Heart Stacking",
5+
"key.healthindicators.increaseHeartOffset": "Increase Heart Offset",
6+
"key.healthindicators.decreaseHeartOffset": "Decrease Heart Offset"
47
}

0 commit comments

Comments
 (0)