Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
Display Health and Mana in a ring around the crosshair on Hypixel SkyBlock.

**New:** Ported from a 1.8.9 ChatTriggers module into a 1.21.10 Fabric mod.
The Fabric version of StatsRing depends on the [Cloth Config API](https://modrinth.com/mod/cloth-config).


Optionally include percentages, visual alerts on low stats, and smooth animation. Useful for combat across SkyBlock.

Expand Down
12 changes: 6 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ base {
}

repositories {
// Add repositories to retrieve artifacts from in here.
// You should only use this when depending on other mods because
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories.
maven { url "https://maven.shedaniel.me/" }
}

dependencies {
Expand All @@ -26,7 +22,11 @@ dependencies {

// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}"


// Cloth Config for settings GUI
modApi("me.shedaniel.cloth:cloth-config-fabric:${project.cloth_config_version}") {
exclude(group: "net.fabricmc.fabric-api")
}
}

processResources {
Expand Down
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ maven_group=me.bubner.statsring
archives_base_name=statsring

# Dependencies
fabric_api_version=0.138.4+1.21.10
fabric_api_version=0.138.4+1.21.10
cloth_config_version=20.0.148
Empty file modified gradlew
100644 → 100755
Empty file.
95 changes: 95 additions & 0 deletions src/main/java/me/bubner/statsring/ConfigScreen.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package me.bubner.statsring;

import me.shedaniel.clothconfig2.api.ConfigBuilder;
import me.shedaniel.clothconfig2.api.ConfigCategory;
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;

/**
* Cloth Config screen for StatsRing settings.
* Replaces the original Vigilance config GUI from config.js.
*
* @author Lucas Bubner, 2023 (Original CT module)
*/
public class ConfigScreen {
private ConfigScreen() {
}

/**
* Create the Cloth Config settings screen.
*
* @param parent the parent screen to return to
* @param config the mod configuration instance
* @return the built config screen
*/
public static Screen create(Screen parent, ModConfig config) {
ConfigBuilder builder = ConfigBuilder.create()
.setParentScreen(parent)
.setTitle(Component.empty()
.append(Component.literal("Stats Ring: ").withStyle(ChatFormatting.BOLD))
.append(Component.literal("Health ").withStyle(ChatFormatting.RED))
.append(Component.literal("and "))
.append(Component.literal("Mana ").withStyle(ChatFormatting.AQUA))
.append(Component.literal("ring")));

ConfigEntryBuilder entryBuilder = builder.entryBuilder();

// Core category
ConfigCategory core = builder.getOrCreateCategory(Component.literal("Core"));
core.addEntry(entryBuilder.startBooleanToggle(Component.literal("Enable ring"), config.getActive())
.setDefaultValue(true)
.setTooltip(Component.literal("Render the ring (on/off)."))
.setSaveConsumer(val -> config.properties.setProperty("active", String.valueOf(val)))
.build());
core.addEntry(entryBuilder.startBooleanToggle(Component.literal("Show percentages"), config.getPercentage())
.setDefaultValue(true)
.setTooltip(Component.literal("Render percentages of health/mana next to ring (on/off)."))
.setSaveConsumer(val -> config.properties.setProperty("percentage", String.valueOf(val)))
.build());
core.addEntry(entryBuilder.startBooleanToggle(Component.literal("Show absorption"), config.getAbsorption())
.setDefaultValue(true)
.setTooltip(Component.literal("Show over 100% health for absorption hearts (on/off)."))
.setSaveConsumer(val -> config.properties.setProperty("absorption", String.valueOf(val)))
.build());

// Display category
ConfigCategory display = builder.getOrCreateCategory(Component.literal("Display"));
display.addEntry(entryBuilder.startBooleanToggle(Component.literal("Show backing image"), config.getBackingImage())
.setDefaultValue(true)
.setTooltip(Component.literal("Show the background image for the ring that surrounds the bars (on/off)."))
.setSaveConsumer(val -> config.properties.setProperty("backingImage", String.valueOf(val)))
.build());
display.addEntry(entryBuilder.startBooleanToggle(Component.literal("Interpolate colour"), config.getInterpolateColour())
.setDefaultValue(true)
.setTooltip(Component.literal("Linear interpolates mana and health colour depending on percentage filled (on/off)."))
.setSaveConsumer(val -> config.properties.setProperty("interpolateColour", String.valueOf(val)))
.build());
display.addEntry(entryBuilder.startBooleanToggle(Component.literal("Interpolate bars"), config.getInterpolateBars())
.setDefaultValue(true)
.setTooltip(Component.literal("Linear interpolates the filled progress of the bars (on/off)."))
.setSaveConsumer(val -> config.properties.setProperty("interpolateBars", String.valueOf(val)))
.build());

// Visual Warnings category
ConfigCategory warnings = builder.getOrCreateCategory(Component.literal("Visual Warnings"));
warnings.addEntry(entryBuilder.startIntField(Component.literal("Low HP percent alert threshold"), (int) config.getAlertLowHpPercent())
.setDefaultValue(40)
.setMin(-1)
.setMax(100)
.setTooltip(Component.literal("Visually flashes HP when equal to or below this percentage (% from 0 to 100, -1 to disable)"))
.setSaveConsumer(val -> config.properties.setProperty("alertLowHpPercent", String.valueOf(val)))
.build());
warnings.addEntry(entryBuilder.startIntField(Component.literal("Low Mana percent alert threshold"), (int) config.getAlertLowManaPercent())
.setDefaultValue(20)
.setMin(-1)
.setMax(100)
.setTooltip(Component.literal("Visually flashes Mana when equal to or below this percentage (% from 0 to 100, -1 to disable)"))
.setSaveConsumer(val -> config.properties.setProperty("alertLowManaPercent", String.valueOf(val)))
.build());

builder.setSavingRunnable(config::save);
return builder.build();
}
}
12 changes: 12 additions & 0 deletions src/main/java/me/bubner/statsring/ManaReadStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package me.bubner.statsring;

/**
* Represents the mana read status from the action bar.
*
* @author Lucas Bubner, 2023 (Original CT module)
*/
public enum ManaReadStatus {
OK,
FROZEN,
NOT_ENOUGH_MANA
}
79 changes: 79 additions & 0 deletions src/main/java/me/bubner/statsring/ModConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package me.bubner.statsring;

import net.fabricmc.loader.api.FabricLoader;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Properties;

/**
* Properties-based configuration for StatsRing.
* Serialises settings to a .properties file in the Fabric config directory.
*
* @author Lucas Bubner, 2023 (Original CT module)
*/
public class ModConfig {
private static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir().resolve("statsring.properties");
public final Properties properties = new Properties();

public void load() {
if (Files.exists(CONFIG_PATH)) {
try (var reader = Files.newBufferedReader(CONFIG_PATH)) {
properties.load(reader);
} catch (IOException e) {
StatsRing.LOGGER.error("Failed to load config", e);
}
} else {
save();
}
}

public void save() {
try (var writer = Files.newBufferedWriter(CONFIG_PATH)) {
properties.store(writer, "StatsRing configuration");
} catch (IOException e) {
StatsRing.LOGGER.error("Failed to save config", e);
}
}

public boolean getActive() {
return Boolean.parseBoolean(properties.getProperty("active", "true"));
}

public boolean getPercentage() {
return Boolean.parseBoolean(properties.getProperty("percentage", "true"));
}

public boolean getAbsorption() {
return Boolean.parseBoolean(properties.getProperty("absorption", "true"));
}

public boolean getBackingImage() {
return Boolean.parseBoolean(properties.getProperty("backingImage", "true"));
}

public boolean getInterpolateColour() {
return Boolean.parseBoolean(properties.getProperty("interpolateColour", "true"));
}

public boolean getInterpolateBars() {
return Boolean.parseBoolean(properties.getProperty("interpolateBars", "true"));
}

public float getAlertLowHpPercent() {
try {
return Float.parseFloat(properties.getProperty("alertLowHpPercent", "40"));
} catch (NumberFormatException e) {
return 40f;
}
}

public float getAlertLowManaPercent() {
try {
return Float.parseFloat(properties.getProperty("alertLowManaPercent", "20"));
} catch (NumberFormatException e) {
return 20f;
}
}
}
40 changes: 33 additions & 7 deletions src/main/java/me/bubner/statsring/StatsRing.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,42 @@
package me.bubner.statsring;

import net.fabricmc.api.ClientModInitializer;

import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* StatsRing - Display Health and Mana in a ring around the crosshair on Hypixel SkyBlock.
* Ported from a 1.8.9 ChatTriggers module into a 1.21.10 Fabric mod.
*
* @author Lucas Bubner, 2023 (Original CT module)
*/
public class StatsRing implements ClientModInitializer {
public static final String MOD_ID = "statsring";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
public static final String MOD_ID = "statsring";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
private volatile boolean scheduleOpenConfigScreen = false;

@Override
public void onInitializeClient() {
final ModConfig config = new ModConfig();
config.load();

new StatsRingRenderer(config).register();

@Override
public void onInitializeClient() {

}
// Register /ring command to open the settings GUI
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) ->
dispatcher.register(ClientCommandManager.literal("ring").executes(context -> {
scheduleOpenConfigScreen = true;
return 1;
}))
);
ClientTickEvents.END_CLIENT_TICK.register(client -> {
if (scheduleOpenConfigScreen) {
client.execute(() -> client.setScreen(ConfigScreen.create(client.screen, config)));
scheduleOpenConfigScreen = false;
}
});
}
}
Loading