diff options
| author | inyourwalls <inyourwalls@tutanota.com> | 2024-01-29 12:30:52 -0500 |
|---|---|---|
| committer | inyourwalls <inyourwalls@tutanota.com> | 2024-01-29 12:30:52 -0500 |
| commit | 9b8c377e785208e0b53c1b82cc99ebee94df7f66 (patch) | |
| tree | 607f472a9bfef8242ccf9c1e7044969cae016b09 | |
| parent | 3f01599a3e61af1d3f49f986ad9ecb210d4d4b47 (diff) | |
| parent | 3567fea6ca8749d66e0ad4f62ba5efd5ea705d9f (diff) | |
merge amazing-config-update into 1.20.1-backport
| -rw-r--r-- | build.gradle.kts | 5 | ||||
| -rw-r--r-- | src/main/java/net/inyourwalls/frank/Frank.java | 211 | ||||
| -rw-r--r-- | src/main/java/net/inyourwalls/frank/ModMenuIntegration.java | 15 | ||||
| -rw-r--r-- | src/main/java/net/inyourwalls/frank/config/ConfigScreen.java | 210 | ||||
| -rw-r--r-- | src/main/java/net/inyourwalls/frank/config/FrankConfig.java | 84 | ||||
| -rw-r--r-- | src/main/resources/assets/frank/lang/en_ca.json | 4 | ||||
| -rw-r--r-- | src/main/resources/assets/frank/lang/en_us.json | 12 | ||||
| -rw-r--r-- | src/main/resources/fabric.mod.json | 7 |
8 files changed, 488 insertions, 60 deletions
diff --git a/build.gradle.kts b/build.gradle.kts index 69a6ec6..bdae5b0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,11 +4,12 @@ plugins { } val minecraftVersion = "1.20.1" -version = "0.1.1+$minecraftVersion" +version = "1.0.0+$minecraftVersion" group = "net.inyourwalls" repositories { // Repositories to fetch additional dependencies from. + maven("https://maven.terraformersmc.com/") } dependencies { @@ -18,6 +19,8 @@ dependencies { mappings("net.fabricmc:yarn:$minecraftVersion+build.$yarnBuild:v2") modImplementation("net.fabricmc:fabric-loader:0.14.23") modImplementation("net.fabricmc.fabric-api:fabric-api:0.90.4+$minecraftVersion") + + modImplementation("com.terraformersmc:modmenu:9.0.0") } tasks { diff --git a/src/main/java/net/inyourwalls/frank/Frank.java b/src/main/java/net/inyourwalls/frank/Frank.java index 3ac8f09..8418dc4 100644 --- a/src/main/java/net/inyourwalls/frank/Frank.java +++ b/src/main/java/net/inyourwalls/frank/Frank.java @@ -2,8 +2,10 @@ package net.inyourwalls.frank; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.fabricmc.fabric.api.registry.FuelRegistry; +import net.inyourwalls.frank.config.FrankConfig; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.ingame.AbstractFurnaceScreen; @@ -15,70 +17,165 @@ import net.minecraft.text.Text; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.nio.file.Path; + public class Frank implements ClientModInitializer { - public static final Logger LOGGER = LoggerFactory.getLogger(Frank.class); + public static final Logger LOGGER = LoggerFactory.getLogger(Frank.class); + private static final int CRAFTING_SLOT_INDEX = 0; + private static final int FUEL_SLOT_INDEX = 1; + private static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir().resolve("frank.json"); + private static FrankConfig config; + + @Override + public void onInitializeClient() { + try { + config = FrankConfig.load(CONFIG_PATH); + } catch (IOException ex) { + LOGGER.warn("Failed to load configuration file, falling back on default values."); + config = new FrankConfig(); + } + + ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> { + if (screen instanceof AbstractFurnaceScreen furnace) { + AbstractFurnaceScreenHandler handler = (AbstractFurnaceScreenHandler) furnace.getScreenHandler(); + + int speedMultiplier = (handler instanceof BlastFurnaceScreenHandler || handler instanceof SmokerScreenHandler) ? 2 : 1; + ScreenEvents.afterRender(screen).register((_s, drawContext, mouseX, mouseY, tickDelta) -> { + int x = screen.width / 2 + 90; // just after the right edge. + int y = screen.height / 2 - 80; // more or less in line with the top edge. + if (furnace.recipeBook.isOpen()) x += 77; + switch (config.getDisplayMode()) { + case TIME_LEFT_FIRST -> { + renderTimeLeft( + drawContext, + client.textRenderer, + x, + y, + config.getTextColour(), + handler.getSlot(CRAFTING_SLOT_INDEX).getStack().getCount(), + speedMultiplier, + handler.getCookProgressPercent() + ); + renderItemsSmeltable( + drawContext, + client.textRenderer, + x, + y + 10, + config.getTextColour(), + handler.getSlot(FUEL_SLOT_INDEX).getStack(), + handler.getFuelProgressPercent() + ); + break; + } - private static final int CRAFTING_SLOT_INDEX = 0; - private static final int FUEL_SLOT_INDEX = 1; - private static final int WHITE = 0xffffff; + case TIME_LEFT_ONLY -> { + renderTimeLeft( + drawContext, + client.textRenderer, + x, + y, + config.getTextColour(), + handler.getSlot(CRAFTING_SLOT_INDEX).getStack().getCount(), + speedMultiplier, + handler.getCookProgressPercent() + ); + break; + } - @Override - public void onInitializeClient() { - ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> { - if (screen instanceof AbstractFurnaceScreen furnace) { - ScreenEvents.afterRender(screen).register((_s, drawContext, mouseX, mouseY, tickDelta) -> { - AbstractFurnaceScreenHandler handler = (AbstractFurnaceScreenHandler) furnace.getScreenHandler(); - int speedMultiplier = (handler instanceof BlastFurnaceScreenHandler || handler instanceof SmokerScreenHandler) ? 2 : 1; - renderInfoLines( - furnace, - drawContext, - client.textRenderer, - handler.getSlot(CRAFTING_SLOT_INDEX).getStack().getCount(), - handler.getCookProgressPercent(), - handler.getSlot(FUEL_SLOT_INDEX).getStack(), - handler.getFuelProgressPercent(), - speedMultiplier - ); + case ITEMS_SMELTABLE_FIRST -> { + renderItemsSmeltable( + drawContext, + client.textRenderer, + x, + y, + config.getTextColour(), + handler.getSlot(FUEL_SLOT_INDEX).getStack(), + handler.getFuelProgressPercent() + ); + renderTimeLeft( + drawContext, + client.textRenderer, + x, + y + 10, + config.getTextColour(), + handler.getSlot(CRAFTING_SLOT_INDEX).getStack().getCount(), + speedMultiplier, + handler.getCookProgressPercent() + ); + break; + } + + case ITEMS_SMELTABLE_ONLY -> { + renderItemsSmeltable( + drawContext, + client.textRenderer, + x, + y, + config.getTextColour(), + handler.getSlot(FUEL_SLOT_INDEX).getStack(), + handler.getFuelProgressPercent() + ); + break; + } + + case DISABLED -> {} + } + }); + } }); - } - }); - LOGGER.info("Screen events registered."); - } + LOGGER.info("Screen events registered."); + } - /** - * Renders the info lines on the given screen. - */ - private void renderInfoLines( - AbstractFurnaceScreen<?> screen, - DrawContext context, - TextRenderer renderer, - int itemsInProgress, - float cookProgress, - ItemStack fuel, - float fuelProgress, - int speedMultiplier - ) { - // Determine where to start drawing the information. - int infoX = screen.width / 2 + 90; - int infoY = screen.height / 2 - 80; - if (screen.recipeBook.isOpen()) { - infoX += 77; + private void renderTimeLeft( + DrawContext context, + TextRenderer renderer, + int x, + int y, + int textColour, + int itemsInProgress, + int speedMultiplier, + float cookProgress + ) { + int smeltingSpeed = 10 / speedMultiplier; // still kinda lame, but it works! + int secondsLeft = itemsInProgress * smeltingSpeed - (int)(cookProgress * smeltingSpeed); + int minutesLeft = secondsLeft / 60; + secondsLeft = secondsLeft % 60; + + context.drawTextWithShadow(renderer, Text.translatable("ui.frank.time_left", minutesLeft, secondsLeft), x, y, textColour); + } + + private void renderItemsSmeltable( + DrawContext context, + TextRenderer renderer, + int x, + int y, + int textColour, + ItemStack fuel, + float fuelProgress + ) { + int fuelCount = fuel.getCount(); + Integer fuelTicks = FuelRegistry.INSTANCE.get(fuel.getItem()); + if (fuelTicks == null) fuelTicks = 0; + int burningFuel = (int)((float)(fuelTicks / 10) * fuelProgress); + int itemsSmeltable = (((fuelTicks / 10) * fuelCount) / 20) + (burningFuel / 20); + + context.drawTextWithShadow(renderer, Text.translatable("ui.frank.smeltable", itemsSmeltable), x, y, textColour); } - - int smeltingSpeed = 10 / speedMultiplier; // this code sucks, but i don't care. - int secondsLeft = itemsInProgress * smeltingSpeed - (int)(cookProgress * smeltingSpeed); - int minutesLeft = secondsLeft / 60; - secondsLeft = secondsLeft % 60; - int fuelCount = fuel.getCount(); - Integer fuelTicks = FuelRegistry.INSTANCE.get(fuel.getItem()); - // Avoid null pointer exception because Java is terrible. - if (fuelTicks == null) fuelTicks = 0; - int burningFuel = (int)((float)(fuelTicks / 10) * fuelProgress); - int itemsSmeltable = (((fuelTicks / 10) * fuelCount) / 20) + (burningFuel / 20); + /** + * Gets the current active configuration. + */ + public static FrankConfig getConfig() { + return config; + } - context.drawTextWithShadow(renderer, Text.translatable("ui.frank.time_left", minutesLeft, secondsLeft), infoX, infoY, WHITE); - context.drawTextWithShadow(renderer, Text.translatable("ui.frank.smeltable", itemsSmeltable), infoX, infoY + 10, WHITE); - } + /** + * Attempts to save the provided configuration. + */ + public static void saveConfig(FrankConfig configToSave) throws IOException { + config = configToSave; + FrankConfig.save(config, CONFIG_PATH); + } } diff --git a/src/main/java/net/inyourwalls/frank/ModMenuIntegration.java b/src/main/java/net/inyourwalls/frank/ModMenuIntegration.java new file mode 100644 index 0000000..053e871 --- /dev/null +++ b/src/main/java/net/inyourwalls/frank/ModMenuIntegration.java @@ -0,0 +1,15 @@ +// ModMenuIntegration: Entrypoint for integrating with Mod Menu. +package net.inyourwalls.frank; + +import com.terraformersmc.modmenu.api.ConfigScreenFactory; +import com.terraformersmc.modmenu.api.ModMenuApi; +import net.inyourwalls.frank.config.ConfigScreen; + +public class ModMenuIntegration implements ModMenuApi { + @Override + public ConfigScreenFactory<?> getModConfigScreenFactory() { + return parent -> { + return new ConfigScreen(parent, Frank.getConfig()); + }; + } +} diff --git a/src/main/java/net/inyourwalls/frank/config/ConfigScreen.java b/src/main/java/net/inyourwalls/frank/config/ConfigScreen.java new file mode 100644 index 0000000..211dee5 --- /dev/null +++ b/src/main/java/net/inyourwalls/frank/config/ConfigScreen.java @@ -0,0 +1,210 @@ +// ConfigScreen: Frank's configuration screen. +package net.inyourwalls.frank.config; + +import net.inyourwalls.frank.Frank; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +import java.io.IOException; + +import static net.minecraft.client.gui.widget.ButtonWidget.DEFAULT_WIDTH; +import static net.minecraft.client.gui.widget.ButtonWidget.DEFAULT_WIDTH_SMALL; +import static net.minecraft.client.gui.widget.ButtonWidget.DEFAULT_HEIGHT; + +public class ConfigScreen extends Screen { + private static final Identifier FURNACE_UI_TEXTURE = new Identifier("textures/gui/container/furnace.png"); + private static final int FURNACE_TEXTURE_WIDTH = 176; + private static final int FURNACE_TEXTURE_HEIGHT = 166; + private static final Text DISPLAY_MODE_LABEL = Text.translatable("ui.frank.config.display_mode"); + private static final Text TEXT_COLOUR_LABEL = Text.translatable("ui.frank.config.text_colour"); + private final FrankConfig modifiedConfig = new FrankConfig(); + private final Screen previousScreen; + + public ConfigScreen(Screen previous, FrankConfig currentConfig) { + super(Text.translatable("ui.frank.config")); + this.previousScreen = previous; + modifiedConfig.setDisplayMode(currentConfig.getDisplayMode()); + modifiedConfig.setTextColour(currentConfig.getTextColour()); + } + + @Override + public void init() { + ButtonWidget backButton = ButtonWidget.builder(Text.translatable("gui.back"), thisButton -> this.close()) + .size(DEFAULT_WIDTH, DEFAULT_HEIGHT) + .position(this.width / 2 - DEFAULT_WIDTH - 4, this.height - 28) + .build(); + + ButtonWidget saveButton = ButtonWidget.builder(Text.translatable("selectWorld.edit.save"), thisButton -> { + try { + Frank.saveConfig(modifiedConfig); + Frank.LOGGER.debug("Configuration file was successfully saved."); + } catch (IOException ex) { + Frank.LOGGER.error("Failed to save configuration file", ex); + } + }) + .size(DEFAULT_WIDTH, DEFAULT_HEIGHT) + .position(this.width / 2 + 4, this.height - 28) + .build(); + + ButtonWidget modeToggleButton = ButtonWidget.builder( + Text.translatable(modifiedConfig.getDisplayMode().translationKey()), + thisButton -> { + int ordinal = modifiedConfig.getDisplayMode().ordinal(); + FrankConfig.InfoDisplayMode[] infoDisplayModes = FrankConfig.InfoDisplayMode.values(); + if (++ordinal >= infoDisplayModes.length) { + ordinal = 0; + } + + modifiedConfig.setDisplayMode(infoDisplayModes[ordinal]); + thisButton.setMessage(Text.translatable(modifiedConfig.getDisplayMode().translationKey())); + } + ) + .size(DEFAULT_WIDTH_SMALL, DEFAULT_HEIGHT) + .position(this.width / 2 + 4, 25) + .build(); + + TextFieldWidget colourField = new TextFieldWidget( + this.textRenderer, + this.width / 2 + 4, + 55, + DEFAULT_WIDTH_SMALL, + DEFAULT_HEIGHT, + TEXT_COLOUR_LABEL + ); + colourField.setChangedListener(input -> { + try { + int newColour = Integer.parseInt(input, 16); + modifiedConfig.setTextColour(newColour); + } catch (NumberFormatException ex) { /* how */ } + }); + colourField.setTextPredicate(text -> + text.length() <= 6 && text.chars().allMatch(c -> + (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <= '9') + ) + ); + colourField.setText(String.format("%x", modifiedConfig.getTextColour())); + colourField.setTooltip(Tooltip.of(Text.translatable("ui.frank.config.text_colour.tooltip"))); + + this.addDrawableChild(backButton); + this.addDrawableChild(saveButton); + this.addDrawableChild(modeToggleButton); + this.addDrawableChild(colourField); + } + + @Override + public void close() { + this.client.setScreen(this.previousScreen); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + context.drawCenteredTextWithShadow(this.textRenderer, Text.translatable("ui.frank.config"), this.width / 2, 5, 0xffffff); + + int labelX = this.width / 2 - Math.max(this.textRenderer.getWidth(DISPLAY_MODE_LABEL), this.textRenderer.getWidth(TEXT_COLOUR_LABEL)) - 4; + context.drawTextWithShadow( + this.textRenderer, + DISPLAY_MODE_LABEL, + labelX, + 30, + 0xffffff + ); + context.drawTextWithShadow( + this.textRenderer, + TEXT_COLOUR_LABEL, + labelX, + 60, + 0xffffff + ); + + int x = (this.width / 2) - (FURNACE_TEXTURE_WIDTH / 2); + int y = this.height / 2 - (FURNACE_TEXTURE_HEIGHT / 2); + renderPreview(context, x, y); + } + + private void renderPreview(DrawContext context, int x, int y) { + context.drawTexture(FURNACE_UI_TEXTURE, x, y, 0, 0, FURNACE_TEXTURE_WIDTH, FURNACE_TEXTURE_HEIGHT); + drawCenteredText( + context, + this.textRenderer, + Text.translatable("ui.frank.config.preview"), + x + (FURNACE_TEXTURE_WIDTH / 2), + y + 6, + 0x404040 + ); + + int infoX = x + FURNACE_TEXTURE_WIDTH + 2; + int infoY = y + 3; + switch (modifiedConfig.getDisplayMode()) { + case TIME_LEFT_FIRST -> { + context.drawTextWithShadow( + this.textRenderer, + Text.translatable("ui.frank.time_left", 0, 0), + infoX, + infoY, + modifiedConfig.getTextColour() + ); + context.drawTextWithShadow( + this.textRenderer, + Text.translatable("ui.frank.smeltable", 0), + infoX, + infoY + 10, + modifiedConfig.getTextColour() + ); + break; + } + + case TIME_LEFT_ONLY -> { + context.drawTextWithShadow( + this.textRenderer, + Text.translatable("ui.frank.time_left", 0, 0), + infoX, + infoY, + modifiedConfig.getTextColour() + ); + break; + } + + case ITEMS_SMELTABLE_FIRST -> { + context.drawTextWithShadow( + this.textRenderer, + Text.translatable("ui.frank.smeltable", 0), + infoX, + infoY, + modifiedConfig.getTextColour() + ); + context.drawTextWithShadow( + this.textRenderer, + Text.translatable("ui.frank.time_left", 0, 0), + infoX, + infoY + 10, + modifiedConfig.getTextColour() + ); + break; + } + + case ITEMS_SMELTABLE_ONLY -> { + context.drawTextWithShadow( + this.textRenderer, + Text.translatable("ui.frank.smeltable", 0), + infoX, + infoY, + modifiedConfig.getTextColour() + ); + break; + } + + case DISABLED -> {} + } + } + + private void drawCenteredText(DrawContext context, TextRenderer renderer, Text text, int centerX, int y, int colour) { + context.drawText(renderer, text, centerX - renderer.getWidth(text) / 2, y, colour, false); + } +} diff --git a/src/main/java/net/inyourwalls/frank/config/FrankConfig.java b/src/main/java/net/inyourwalls/frank/config/FrankConfig.java new file mode 100644 index 0000000..4619bb7 --- /dev/null +++ b/src/main/java/net/inyourwalls/frank/config/FrankConfig.java @@ -0,0 +1,84 @@ +// FrankConfig: Config class for Frank. +package net.inyourwalls.frank.config; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; + +public class FrankConfig { + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + + private InfoDisplayMode infoDisplayMode = InfoDisplayMode.TIME_LEFT_FIRST; + private int textColour = 0xffffff; + + /** + * Gets the "mode" Frank should display its information in. + */ + public InfoDisplayMode getDisplayMode() { + return this.infoDisplayMode; + } + + /** + * Sets the "mode" Frank should display its information in. + */ + public void setDisplayMode(InfoDisplayMode infoDisplayMode) { + this.infoDisplayMode = infoDisplayMode; + } + + /** + * Gets the current text colour. + */ + public int getTextColour() { + return this.textColour; + } + + /** + * Sets a new text colour. + */ + public void setTextColour(int textColour) { + this.textColour = textColour; + } + + /** + * Attempts to load the configuration from the given path. If the file is + * empty, all values will be set to default. + * @param configPath The path to try loading the configuration from. + * @throws IOException If any I/O errors occur while loading the config. + */ + public static FrankConfig load(Path configPath) throws IOException { + FileReader reader = new FileReader(configPath.toFile()); + FrankConfig loadedConfig = GSON.fromJson(reader, FrankConfig.class); + return loadedConfig == null ? new FrankConfig() : loadedConfig; + } + + /** + * Attempts to save the given configuration to the given path. + * @param config The configuration to save. + * @param configPath The path to try saving the configuration to. + * @throws IOException If any errors occur while saving the config. + */ + public static void save(FrankConfig config, Path configPath) throws IOException { + FileWriter writer = new FileWriter(configPath.toFile()); + GSON.toJson(config, writer); + writer.close(); + } + + /** + * An enum representing the five ways Frank can display its information. + */ + public static enum InfoDisplayMode { + TIME_LEFT_FIRST, + TIME_LEFT_ONLY, + ITEMS_SMELTABLE_FIRST, + ITEMS_SMELTABLE_ONLY, + DISABLED; + + public String translationKey() { + return "ui.frank.config." + this.toString().toLowerCase(); + } + } +} diff --git a/src/main/resources/assets/frank/lang/en_ca.json b/src/main/resources/assets/frank/lang/en_ca.json new file mode 100644 index 0000000..07f9fda --- /dev/null +++ b/src/main/resources/assets/frank/lang/en_ca.json @@ -0,0 +1,4 @@ +{ + "ui.frank.config.text_colour": "Text Colour", + "ui.frank.config.text_colour.tooltip": "Hexadecimal RGB value for the text colour." +} diff --git a/src/main/resources/assets/frank/lang/en_us.json b/src/main/resources/assets/frank/lang/en_us.json index ca2862d..1a7471d 100644 --- a/src/main/resources/assets/frank/lang/en_us.json +++ b/src/main/resources/assets/frank/lang/en_us.json @@ -1,5 +1,17 @@ { "ui.frank.time_left": "Time remaining: %sm %ss", "ui.frank.smeltable": "Items smeltable: %s", + + "ui.frank.config": "Configuration - Frank", + "ui.frank.config.preview": "Preview", + "ui.frank.config.time_left_first": "Time Left First", + "ui.frank.config.time_left_only": "Time Left Only", + "ui.frank.config.items_smeltable_first": "Items Smeltable First", + "ui.frank.config.items_smeltable_only": "Items Smeltable Only", + "ui.frank.config.disabled": "Disabled", + "ui.frank.config.display_mode": "Display Mode", + "ui.frank.config.text_colour": "Text Color", + "ui.frank.config.text_colour.tooltip": "Hexadecimal RGB value for the text color.", + "frank.matrix": "Matrix" } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 047001e..0a46f48 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -3,7 +3,7 @@ "id": "frank", "version": "${version}", "name": "Frank", - "description": "Mod that displays additional info about furnaces and fuels.", + "description": "Mod that displays additional info in furnaces.", "authors": [ "InYourWalls" ], @@ -16,6 +16,9 @@ "entrypoints": { "client": [ "net.inyourwalls.frank.Frank" + ], + "modmenu": [ + "net.inyourwalls.frank.ModMenuIntegration" ] }, "mixins": [ @@ -23,8 +26,8 @@ ], "depends": { "fabricloader": ">=0.14.22", - "fabric-api": ">=0.90.4+1.20.1", "minecraft": "1.20.1", + "fabric-screen-api-v1": ">=0.90.4+1.20.1", "java": ">=17" }, "suggests": {}, |
