From 4fb4b669bcc25b87d50c80c100a8b09a2d76ef66 Mon Sep 17 00:00:00 2001 From: DekinDev Date: Thu, 8 Jan 2026 23:52:08 +0100 Subject: [PATCH] first test --- README.md | 12 +- gradle.properties | 25 +- settings.gradle | 27 ++- .../java/com/straice/TemplateModClient.java | 10 - .../mixin/client/ExampleClientMixin.java | 15 -- .../iconsenhanced/client/BorderRenderer.java | 59 +++++ .../iconsenhanced/client/ClientInit.java | 21 ++ .../client/EnchantTooltipComponent.java | 201 ++++++++++++++++ .../client/EnchantTooltipData.java | 28 +++ .../client/TooltipAugmenter.java | 218 ++++++++++++++++++ .../iconsenhanced/client/TooltipTextUtil.java | 44 ++++ .../AbstractContainerScreenAccessor.java | 14 ++ .../resources/template-mod.client.mixins.json | 11 - src/main/java/com/straice/TemplateMod.java | 24 -- .../java/com/straice/mixin/ExampleMixin.java | 15 -- .../dekin/iconsenhanced/IconsEnhanced.java | 12 + .../adapters/DefaultEnchantmentAdapter.java | 116 ++++++++++ .../adapters/EnchantmentAdapter.java | 10 + .../common/BorderColorLogic.java | 115 +++++++++ .../iconsenhanced/common/ConfigManager.java | 72 ++++++ .../dekin/iconsenhanced/common/EnchEntry.java | 41 ++++ .../common/EnchantSortLogic.java | 63 +++++ .../dekin/iconsenhanced/common/IconAtlas.java | 69 ++++++ .../iconsenhanced/common/IconKeyResolver.java | 89 +++++++ .../common/IconsEnhancedConfig.java | 164 +++++++++++++ .../common/TooltipLayoutModel.java | 33 +++ .../resources/assets/iconsenhanced/icon.png | Bin 0 -> 404 bytes .../assets/iconsenhanced/lang/en_us.json | 11 + .../assets/iconsenhanced/lang/es_es.json | 11 + .../textures/gui/enchant_icons.png | Bin 0 -> 19245 bytes .../resources/assets/template-mod/icon.png | Bin 2786 -> 0 bytes src/main/resources/fabric.mod.json | 62 ++--- src/main/resources/iconsenhanced.mixins.json | 11 + src/main/resources/template-mod.mixins.json | 14 -- stonecutter.gradle | 15 ++ versions/1.20.1/gradle.properties | 7 + versions/1.20.4/gradle.properties | 7 + versions/1.20.6/gradle.properties | 7 + versions/1.21.1/gradle.properties | 7 + versions/1.21.11/gradle.properties | 7 + versions/1.21.4/gradle.properties | 7 + 41 files changed, 1535 insertions(+), 139 deletions(-) delete mode 100644 src/client/java/com/straice/TemplateModClient.java delete mode 100644 src/client/java/com/straice/mixin/client/ExampleClientMixin.java create mode 100644 src/client/java/dev/dekin/iconsenhanced/client/BorderRenderer.java create mode 100644 src/client/java/dev/dekin/iconsenhanced/client/ClientInit.java create mode 100644 src/client/java/dev/dekin/iconsenhanced/client/EnchantTooltipComponent.java create mode 100644 src/client/java/dev/dekin/iconsenhanced/client/EnchantTooltipData.java create mode 100644 src/client/java/dev/dekin/iconsenhanced/client/TooltipAugmenter.java create mode 100644 src/client/java/dev/dekin/iconsenhanced/client/TooltipTextUtil.java create mode 100644 src/client/java/dev/dekin/iconsenhanced/mixin/AbstractContainerScreenAccessor.java delete mode 100644 src/client/resources/template-mod.client.mixins.json delete mode 100644 src/main/java/com/straice/TemplateMod.java delete mode 100644 src/main/java/com/straice/mixin/ExampleMixin.java create mode 100644 src/main/java/dev/dekin/iconsenhanced/IconsEnhanced.java create mode 100644 src/main/java/dev/dekin/iconsenhanced/adapters/DefaultEnchantmentAdapter.java create mode 100644 src/main/java/dev/dekin/iconsenhanced/adapters/EnchantmentAdapter.java create mode 100644 src/main/java/dev/dekin/iconsenhanced/common/BorderColorLogic.java create mode 100644 src/main/java/dev/dekin/iconsenhanced/common/ConfigManager.java create mode 100644 src/main/java/dev/dekin/iconsenhanced/common/EnchEntry.java create mode 100644 src/main/java/dev/dekin/iconsenhanced/common/EnchantSortLogic.java create mode 100644 src/main/java/dev/dekin/iconsenhanced/common/IconAtlas.java create mode 100644 src/main/java/dev/dekin/iconsenhanced/common/IconKeyResolver.java create mode 100644 src/main/java/dev/dekin/iconsenhanced/common/IconsEnhancedConfig.java create mode 100644 src/main/java/dev/dekin/iconsenhanced/common/TooltipLayoutModel.java create mode 100644 src/main/resources/assets/iconsenhanced/icon.png create mode 100644 src/main/resources/assets/iconsenhanced/lang/en_us.json create mode 100644 src/main/resources/assets/iconsenhanced/lang/es_es.json create mode 100644 src/main/resources/assets/iconsenhanced/textures/gui/enchant_icons.png delete mode 100644 src/main/resources/assets/template-mod/icon.png create mode 100644 src/main/resources/iconsenhanced.mixins.json delete mode 100644 src/main/resources/template-mod.mixins.json create mode 100644 stonecutter.gradle create mode 100644 versions/1.20.1/gradle.properties create mode 100644 versions/1.20.4/gradle.properties create mode 100644 versions/1.20.6/gradle.properties create mode 100644 versions/1.21.1/gradle.properties create mode 100644 versions/1.21.11/gradle.properties create mode 100644 versions/1.21.4/gradle.properties diff --git a/README.md b/README.md index 30d74d2..6fcd8cf 100644 --- a/README.md +++ b/README.md @@ -1 +1,11 @@ -test \ No newline at end of file +# Icons Enhanced + +Icons Enhanced mejora la lectura de encantamientos y la UI sin cambiar el gameplay. + +## Caracteristicas +- Iconos y colores por encantamiento en los tooltips. +- Descripciones de encantamientos. +- Bordes en slots de inventario y contenedores. + +## Licencia +Apache-2.0 diff --git a/gradle.properties b/gradle.properties index 190cc96..1a61a72 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,16 +5,21 @@ org.gradle.parallel=true # IntelliJ IDEA is not yet fully compatible with configuration cache, see: https://github.com/FabricMC/fabric-loom/issues/1349 org.gradle.configuration-cache=false -# Fabric Properties -# check these on https://fabricmc.net/develop -minecraft_version=1.21.11 -loader_version=0.18.4 +# Fabric tooling loom_version=1.14-SNAPSHOT -# Mod Properties -mod_version=1.0.0 -maven_group=com.straice -archives_base_name=template-mod +# Mod metadata +mod.id=iconsenhanced +mod.name=Icons Enhanced +mod.version=0.1.0 +mod.group=dev.dekin +mod.description=Client-only suite of enchantment and UI improvements. +mod.license=Apache-2.0 +mod.author=DekinDev -# Dependencies -fabric_api_version=0.141.1+1.21.11 \ No newline at end of file +# Dependencies (overridden per version in versions/*/gradle.properties) +deps.fabric_loader=0.18.4 +deps.fabric_api=0.141.1+1.21.11 + +# Defaults (overridden per version as needed) +java_version=21 diff --git a/settings.gradle b/settings.gradle index 75c4d72..f134370 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,10 +1,33 @@ pluginManagement { repositories { + gradlePluginPortal() + maven { + name = 'KikuGie Releases' + url = 'https://maven.kikugie.dev/releases' + } + maven { + name = 'KikuGie Snapshots' + url = 'https://maven.kikugie.dev/snapshots' + } maven { name = 'Fabric' url = 'https://maven.fabricmc.net/' } mavenCentral() - gradlePluginPortal() } -} \ No newline at end of file +} + +plugins { + id 'dev.kikugie.stonecutter' version '0.8.2' +} + +stonecutter { + // Stonecutter uses Kotlin controller by default; keep Groovy for consistency. + kotlinController = false + centralScript = 'build.gradle' + + create(rootProject) { + versions '1.20.1', '1.20.4', '1.20.6', '1.21.1', '1.21.4', '1.21.11' + vcsVersion = '1.21.11' + } +} diff --git a/src/client/java/com/straice/TemplateModClient.java b/src/client/java/com/straice/TemplateModClient.java deleted file mode 100644 index 25d31e2..0000000 --- a/src/client/java/com/straice/TemplateModClient.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.straice; - -import net.fabricmc.api.ClientModInitializer; - -public class TemplateModClient implements ClientModInitializer { - @Override - public void onInitializeClient() { - // This entrypoint is suitable for setting up client-specific logic, such as rendering. - } -} \ No newline at end of file diff --git a/src/client/java/com/straice/mixin/client/ExampleClientMixin.java b/src/client/java/com/straice/mixin/client/ExampleClientMixin.java deleted file mode 100644 index 2c88d92..0000000 --- a/src/client/java/com/straice/mixin/client/ExampleClientMixin.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.straice.mixin.client; - -import net.minecraft.client.Minecraft; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(Minecraft.class) -public class ExampleClientMixin { - @Inject(at = @At("HEAD"), method = "run") - private void init(CallbackInfo info) { - // This code is injected into the start of Minecraft.run()V - } -} \ No newline at end of file diff --git a/src/client/java/dev/dekin/iconsenhanced/client/BorderRenderer.java b/src/client/java/dev/dekin/iconsenhanced/client/BorderRenderer.java new file mode 100644 index 0000000..40d9cf8 --- /dev/null +++ b/src/client/java/dev/dekin/iconsenhanced/client/BorderRenderer.java @@ -0,0 +1,59 @@ +package dev.dekin.iconsenhanced.client; + +import dev.dekin.iconsenhanced.common.BorderColorLogic; +import dev.dekin.iconsenhanced.common.ConfigManager; +import dev.dekin.iconsenhanced.common.IconsEnhancedConfig; +import dev.dekin.iconsenhanced.mixin.AbstractContainerScreenAccessor; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; + +public final class BorderRenderer { + private static final BorderColorLogic COLOR_LOGIC = new BorderColorLogic(); + + private BorderRenderer() { + } + + public static void applyConfig() { + COLOR_LOGIC.applyConfig(ConfigManager.get()); + } + + public static void render(Screen screen, GuiGraphics graphics, int mouseX, int mouseY) { + IconsEnhancedConfig config = ConfigManager.get(); + if (!config.borders.enabled) { + return; + } + if (!(screen instanceof AbstractContainerScreen handled)) { + return; + } + + int thickness = clamp(config.borders.thickness, 1, 3); + AbstractContainerScreenAccessor accessor = (AbstractContainerScreenAccessor) handled; + int left = accessor.iconsenhanced$getLeftPos(); + int top = accessor.iconsenhanced$getTopPos(); + + for (Slot slot : handled.getMenu().slots) { + ItemStack stack = slot.getItem(); + if (stack.isEmpty()) { + continue; + } + int color = COLOR_LOGIC.resolve(stack); + drawBorder(graphics, left + slot.x, top + slot.y, thickness, color); + } + } + + private static void drawBorder(GuiGraphics graphics, int x, int y, int thickness, int color) { + int x2 = x + 16; + int y2 = y + 16; + graphics.fill(x, y, x2, y + thickness, color); + graphics.fill(x, y2 - thickness, x2, y2, color); + graphics.fill(x, y, x + thickness, y2, color); + graphics.fill(x2 - thickness, y, x2, y2, color); + } + + private static int clamp(int value, int min, int max) { + return Math.min(max, Math.max(min, value)); + } +} diff --git a/src/client/java/dev/dekin/iconsenhanced/client/ClientInit.java b/src/client/java/dev/dekin/iconsenhanced/client/ClientInit.java new file mode 100644 index 0000000..6c90dd6 --- /dev/null +++ b/src/client/java/dev/dekin/iconsenhanced/client/ClientInit.java @@ -0,0 +1,21 @@ +package dev.dekin.iconsenhanced.client; + +import dev.dekin.iconsenhanced.common.ConfigManager; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; + +public final class ClientInit implements ClientModInitializer { + @Override + public void onInitializeClient() { + ConfigManager.load(); + BorderRenderer.applyConfig(); + TooltipAugmenter.register(); + + ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> { + ScreenEvents.afterRender(screen).register((current, graphics, mouseX, mouseY, delta) -> { + BorderRenderer.render(current, graphics, mouseX, mouseY); + TooltipAugmenter.renderOverlay(current, graphics, mouseX, mouseY); + }); + }); + } +} diff --git a/src/client/java/dev/dekin/iconsenhanced/client/EnchantTooltipComponent.java b/src/client/java/dev/dekin/iconsenhanced/client/EnchantTooltipComponent.java new file mode 100644 index 0000000..32707e3 --- /dev/null +++ b/src/client/java/dev/dekin/iconsenhanced/client/EnchantTooltipComponent.java @@ -0,0 +1,201 @@ +package dev.dekin.iconsenhanced.client; + +import dev.dekin.iconsenhanced.common.IconAtlas; +import dev.dekin.iconsenhanced.common.TooltipLayoutModel; +import dev.dekin.iconsenhanced.common.TooltipLayoutModel.Row; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.network.chat.Component; +//? if >=1.21 { +import net.minecraft.client.renderer.RenderPipelines; +//?} else { +/*import net.minecraft.client.renderer.MultiBufferSource; +import org.joml.Matrix4f; +*///?} + +public final class EnchantTooltipComponent implements ClientTooltipComponent { + private static final int ROW_GAP = 2; + private static final int TEXT_PADDING = 4; + private static final int BADGE_BG = 0xAA000000; + private static final int BADGE_TEXT = 0xFFFFFFFF; + private static final int FULL_BRIGHT = 0xF000F0; + + private final TooltipLayoutModel layout; + private final int iconSize; + private final boolean showLevelBadge; + + public EnchantTooltipComponent(EnchantTooltipData data) { + this.layout = data.layout(); + this.iconSize = Math.max(4, data.iconSize()); + this.showLevelBadge = data.showLevelBadge(); + } + + @Override + public int getWidth(Font font) { + int textStart = iconSize + TEXT_PADDING; + int width = 0; + for (Row row : layout.rows()) { + width = Math.max(width, textStart + font.width(row.text)); + for (Component desc : row.descriptions) { + width = Math.max(width, textStart + font.width(desc)); + } + } + return width; + } + + //? if >=1.21 { + @Override + public int getHeight(Font font) { + return computeHeight(font); + } + //?} else { + /*@Override + public int getHeight() { + return computeHeight(null); + } + *///?} + + private int computeHeight(Font font) { + int height = 0; + int lineHeight = font == null ? 9 : font.lineHeight; + int rowHeight = Math.max(iconSize, lineHeight); + for (int i = 0; i < layout.rows().size(); i++) { + Row row = layout.rows().get(i); + height += rowHeight; + height += row.descriptions.size() * lineHeight; + if (i < layout.rows().size() - 1) { + height += ROW_GAP; + } + } + return height; + } + + //? if >=1.21 { + @Override + public boolean showTooltipWithItemInHand() { + return true; + } + //?} + + //? if >=1.21 { + @Override + public void renderText(GuiGraphics graphics, Font font, int x, int y) { + int yOffset = 0; + int rowHeight = Math.max(iconSize, font.lineHeight); + int textX = x + iconSize + TEXT_PADDING; + for (Row row : layout.rows()) { + int textY = y + yOffset + (rowHeight - font.lineHeight) / 2; + graphics.drawString(font, row.text, textX, textY, 0xFFFFFFFF, false); + yOffset += rowHeight; + for (Component desc : row.descriptions) { + graphics.drawString(font, desc, textX, y + yOffset, 0xFFFFFFFF, false); + yOffset += font.lineHeight; + } + yOffset += ROW_GAP; + } + } + //?} else { + /*@Override + public void renderText(Font font, int x, int y, Matrix4f matrix, MultiBufferSource.BufferSource buffer) { + int yOffset = 0; + int rowHeight = Math.max(iconSize, font.lineHeight); + int textX = x + iconSize + TEXT_PADDING; + for (Row row : layout.rows()) { + int textY = y + yOffset + (rowHeight - font.lineHeight) / 2; + font.drawInBatch(row.text, textX, textY, 0xFFFFFFFF, false, matrix, buffer, Font.DisplayMode.NORMAL, 0, FULL_BRIGHT); + yOffset += rowHeight; + for (Component desc : row.descriptions) { + font.drawInBatch(desc, textX, y + yOffset, 0xFFFFFFFF, false, matrix, buffer, Font.DisplayMode.NORMAL, 0, FULL_BRIGHT); + yOffset += font.lineHeight; + } + yOffset += ROW_GAP; + } + } + *///?} + + //? if >=1.21 { + @Override + public void renderImage(Font font, int x, int y, int width, int height, GuiGraphics graphics) { + renderIcons(font, x, y, graphics); + } + //?} else { + /*@Override + public void renderImage(Font font, int x, int y, GuiGraphics graphics) { + renderIcons(font, x, y, graphics); + } + *///?} + + private void renderIcons(Font font, int x, int y, GuiGraphics graphics) { + int yOffset = 0; + int rowHeight = Math.max(iconSize, font.lineHeight); + for (Row row : layout.rows()) { + int iconY = y + yOffset + (rowHeight - iconSize) / 2; + drawIcon(graphics, x, iconY, row.iconKey); + if (showLevelBadge) { + drawBadge(graphics, font, x, iconY, row.level); + } + yOffset += rowHeight; + yOffset += row.descriptions.size() * font.lineHeight; + yOffset += ROW_GAP; + } + } + + private void drawIcon(GuiGraphics graphics, int x, int y, String key) { + IconAtlas.IconSprite sprite = IconAtlas.get(key); + float scale = iconSize / (float) IconAtlas.ICON_SOURCE_SIZE; + //? if >=1.21 { + graphics.pose().pushMatrix(); + graphics.pose().translate(x, y); + graphics.pose().scale(scale, scale); + //?} else { + /*graphics.pose().pushPose(); + graphics.pose().translate(x, y, 0); + graphics.pose().scale(scale, scale, 1.0f); + *///?} + blit(graphics, 0, 0, sprite.u, sprite.v, sprite.size); + //? if >=1.21 { + graphics.pose().popMatrix(); + //?} else { + /*graphics.pose().popPose(); + *///?} + } + + private void drawBadge(GuiGraphics graphics, Font font, int x, int y, int level) { + String text = levelToRoman(level); + if (text.isEmpty()) { + return; + } + int textWidth = font.width(text); + int badgeWidth = textWidth + 2; + int badgeHeight = font.lineHeight; + int badgeX = x + iconSize - badgeWidth; + int badgeY = y - 1; + graphics.fill(badgeX, badgeY, badgeX + badgeWidth, badgeY + badgeHeight, BADGE_BG); + graphics.drawString(font, text, badgeX + 1, badgeY + 1, BADGE_TEXT, false); + } + + private static String levelToRoman(int level) { + return switch (level) { + case 1 -> "I"; + case 2 -> "II"; + case 3 -> "III"; + case 4 -> "IV"; + case 5 -> "V"; + case 6 -> "VI"; + case 7 -> "VII"; + case 8 -> "VIII"; + case 9 -> "IX"; + case 10 -> "X"; + default -> Integer.toString(level); + }; + } + + private static void blit(GuiGraphics graphics, int x, int y, int u, int v, int size) { + //? if >=1.21 { + graphics.blit(RenderPipelines.GUI_TEXTURED, IconAtlas.ATLAS, x, y, u, v, size, size, IconAtlas.ATLAS_SIZE, IconAtlas.ATLAS_SIZE); + //?} else { + /*graphics.blit(IconAtlas.ATLAS, x, y, 0, (float) u, (float) v, size, size, IconAtlas.ATLAS_SIZE, IconAtlas.ATLAS_SIZE); + *///?} + } +} diff --git a/src/client/java/dev/dekin/iconsenhanced/client/EnchantTooltipData.java b/src/client/java/dev/dekin/iconsenhanced/client/EnchantTooltipData.java new file mode 100644 index 0000000..9ed70e4 --- /dev/null +++ b/src/client/java/dev/dekin/iconsenhanced/client/EnchantTooltipData.java @@ -0,0 +1,28 @@ +package dev.dekin.iconsenhanced.client; + +import dev.dekin.iconsenhanced.common.TooltipLayoutModel; +import net.minecraft.world.inventory.tooltip.TooltipComponent; + +public final class EnchantTooltipData implements TooltipComponent { + private final TooltipLayoutModel layout; + private final int iconSize; + private final boolean showLevelBadge; + + public EnchantTooltipData(TooltipLayoutModel layout, int iconSize, boolean showLevelBadge) { + this.layout = layout; + this.iconSize = iconSize; + this.showLevelBadge = showLevelBadge; + } + + public TooltipLayoutModel layout() { + return layout; + } + + public int iconSize() { + return iconSize; + } + + public boolean showLevelBadge() { + return showLevelBadge; + } +} diff --git a/src/client/java/dev/dekin/iconsenhanced/client/TooltipAugmenter.java b/src/client/java/dev/dekin/iconsenhanced/client/TooltipAugmenter.java new file mode 100644 index 0000000..0ff9a88 --- /dev/null +++ b/src/client/java/dev/dekin/iconsenhanced/client/TooltipAugmenter.java @@ -0,0 +1,218 @@ +package dev.dekin.iconsenhanced.client; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import dev.dekin.iconsenhanced.IconsEnhanced; +import dev.dekin.iconsenhanced.adapters.DefaultEnchantmentAdapter; +import dev.dekin.iconsenhanced.adapters.EnchantmentAdapter; +import dev.dekin.iconsenhanced.common.ConfigManager; +import dev.dekin.iconsenhanced.common.EnchEntry; +import dev.dekin.iconsenhanced.common.EnchantSortLogic; +import dev.dekin.iconsenhanced.common.IconsEnhancedConfig; +import dev.dekin.iconsenhanced.common.TooltipLayoutModel; +import dev.dekin.iconsenhanced.mixin.AbstractContainerScreenAccessor; +import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; +import net.fabricmc.fabric.api.client.rendering.v1.TooltipComponentCallback; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.inventory.tooltip.TooltipComponent; + +public final class TooltipAugmenter { + private static final EnchantmentAdapter ADAPTER = new DefaultEnchantmentAdapter(); + private static final EnchantSortLogic SORT_LOGIC = new EnchantSortLogic(); + private static final ThreadLocal CAPTURE = ThreadLocal.withInitial(() -> Boolean.FALSE); + private static final ThreadLocal CAPTURED_DATA = new ThreadLocal<>(); + + private TooltipAugmenter() { + } + + public static void register() { + //? if >=1.21 { + ItemTooltipCallback.EVENT.register((stack, context, flag, lines) -> onTooltip(stack, lines)); + //?} else { + /*ItemTooltipCallback.EVENT.register((stack, context, lines) -> onTooltip(stack, lines)); + *///?} + + TooltipComponentCallback.EVENT.register(data -> { + if (data instanceof EnchantTooltipData enchData) { + return new EnchantTooltipComponent(enchData); + } + return null; + }); + } + + public static void renderOverlay(Screen screen, GuiGraphics graphics, int mouseX, int mouseY) { + IconsEnhancedConfig config = ConfigManager.get(); + if (!config.tooltips.enabled || !config.tooltips.showIcons) { + return; + } + if (!(screen instanceof AbstractContainerScreen handled)) { + return; + } + + Slot hovered = findHoveredSlot(handled, mouseX, mouseY); + if (hovered == null) { + return; + } + ItemStack stack = hovered.getItem(); + if (stack.isEmpty()) { + return; + } + + Minecraft client = Minecraft.getInstance(); + List lines; + EnchantTooltipData data; + try { + CAPTURE.set(Boolean.TRUE); + CAPTURED_DATA.remove(); + lines = Screen.getTooltipFromItem(client, stack); + data = CAPTURED_DATA.get(); + } finally { + CAPTURE.remove(); + CAPTURED_DATA.remove(); + } + + if (data == null) { + return; + } + + Optional tooltipData = Optional.of(data); + //? if >=1.21 { + graphics.setTooltipForNextFrame(client.font, lines, tooltipData, mouseX, mouseY); + //?} else { + /*graphics.renderTooltip(client.font, lines, tooltipData, mouseX, mouseY); + *///?} + } + + private static void onTooltip(ItemStack stack, List lines) { + try { + IconsEnhancedConfig config = ConfigManager.get(); + if (!config.tooltips.enabled) { + return; + } + + List entries = ADAPTER.getEnchantments(stack); + if (entries.isEmpty()) { + return; + } + + TooltipBlock block = TooltipBlock.find(lines, entries); + if (!block.contiguous) { + return; + } + + List sorted = SORT_LOGIC.sort(entries, config.tooltips); + + if (Boolean.TRUE.equals(CAPTURE.get()) && config.tooltips.showIcons) { + EnchantTooltipData data = buildTooltipData(sorted, config.tooltips); + CAPTURED_DATA.set(data); + block.remove(lines); + return; + } + + if (!config.tooltips.reorderEnchantments && !config.tooltips.showDescriptions) { + return; + } + + List ordered = config.tooltips.reorderEnchantments ? sorted : entries; + List replacement = buildTextLines(ordered, config.tooltips.showDescriptions); + block.replace(lines, replacement); + } catch (Exception e) { + IconsEnhanced.LOGGER.warn("Tooltip augmentation failed.", e); + } + } + + private static EnchantTooltipData buildTooltipData(List entries, IconsEnhancedConfig.Tooltips tooltips) { + List rows = new ArrayList<>(); + for (EnchEntry entry : entries) { + List desc = tooltips.showDescriptions + ? TooltipTextUtil.getDescriptionLines(entry.descKey) + : List.of(); + rows.add(new TooltipLayoutModel.Row(entry.displayName, desc, entry.iconKey, entry.level, entry.isCurse)); + } + return new EnchantTooltipData(new TooltipLayoutModel(rows), tooltips.iconSize, tooltips.showLevelBadge); + } + + private static List buildTextLines(List entries, boolean showDescriptions) { + List lines = new ArrayList<>(); + for (EnchEntry entry : entries) { + lines.add(entry.displayName); + if (showDescriptions) { + lines.addAll(TooltipTextUtil.getDescriptionLines(entry.descKey)); + } + } + return lines; + } + + private static Slot findHoveredSlot(AbstractContainerScreen screen, int mouseX, int mouseY) { + AbstractContainerScreenAccessor accessor = (AbstractContainerScreenAccessor) screen; + int left = accessor.iconsenhanced$getLeftPos(); + int top = accessor.iconsenhanced$getTopPos(); + for (Slot slot : screen.getMenu().slots) { + int sx = left + slot.x; + int sy = top + slot.y; + if (mouseX >= sx && mouseX < sx + 16 && mouseY >= sy && mouseY < sy + 16) { + return slot; + } + } + return null; + } + + private static final class TooltipBlock { + private final int start; + private final int end; + private final boolean contiguous; + + private TooltipBlock(int start, int end, boolean contiguous) { + this.start = start; + this.end = end; + this.contiguous = contiguous; + } + + private void remove(List lines) { + lines.subList(start, end + 1).clear(); + } + + private void replace(List lines, List replacement) { + lines.subList(start, end + 1).clear(); + lines.addAll(start, replacement); + } + + private static TooltipBlock find(List lines, List entries) { + Set names = new HashSet<>(); + for (EnchEntry entry : entries) { + names.add(entry.displayNameString); + } + + int first = -1; + int last = -1; + int count = 0; + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i).getString(); + if (names.contains(line)) { + if (first == -1) { + first = i; + } + last = i; + count++; + } + } + + if (first == -1) { + return new TooltipBlock(0, 0, false); + } + + boolean contiguous = (last - first + 1) == count; + return new TooltipBlock(first, last, contiguous); + } + } +} diff --git a/src/client/java/dev/dekin/iconsenhanced/client/TooltipTextUtil.java b/src/client/java/dev/dekin/iconsenhanced/client/TooltipTextUtil.java new file mode 100644 index 0000000..038401b --- /dev/null +++ b/src/client/java/dev/dekin/iconsenhanced/client/TooltipTextUtil.java @@ -0,0 +1,44 @@ +package dev.dekin.iconsenhanced.client; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; + +public final class TooltipTextUtil { + private static final Map> CACHE = new HashMap<>(); + private static final Style DESCRIPTION_STYLE = Style.EMPTY; + + private TooltipTextUtil() { + } + + public static List getDescriptionLines(String key) { + if (key == null || key.isBlank()) { + return Collections.emptyList(); + } + if (!I18n.exists(key)) { + return Collections.emptyList(); + } + return CACHE.computeIfAbsent(key, TooltipTextUtil::splitLines); + } + + private static List splitLines(String key) { + String text = I18n.get(key); + if (text == null || text.isEmpty()) { + return Collections.emptyList(); + } + String[] parts = text.split("\\\\n"); + List lines = new ArrayList<>(parts.length); + for (String part : parts) { + if (!part.isEmpty()) { + lines.add(Component.literal(part).setStyle(DESCRIPTION_STYLE)); + } + } + return Collections.unmodifiableList(lines); + } +} diff --git a/src/client/java/dev/dekin/iconsenhanced/mixin/AbstractContainerScreenAccessor.java b/src/client/java/dev/dekin/iconsenhanced/mixin/AbstractContainerScreenAccessor.java new file mode 100644 index 0000000..d06e0c1 --- /dev/null +++ b/src/client/java/dev/dekin/iconsenhanced/mixin/AbstractContainerScreenAccessor.java @@ -0,0 +1,14 @@ +package dev.dekin.iconsenhanced.mixin; + +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(AbstractContainerScreen.class) +public interface AbstractContainerScreenAccessor { + @Accessor("leftPos") + int iconsenhanced$getLeftPos(); + + @Accessor("topPos") + int iconsenhanced$getTopPos(); +} diff --git a/src/client/resources/template-mod.client.mixins.json b/src/client/resources/template-mod.client.mixins.json deleted file mode 100644 index e232005..0000000 --- a/src/client/resources/template-mod.client.mixins.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "required": true, - "package": "com.straice.mixin.client", - "compatibilityLevel": "JAVA_21", - "client": [ - "ExampleClientMixin" - ], - "injectors": { - "defaultRequire": 1 - } -} \ No newline at end of file diff --git a/src/main/java/com/straice/TemplateMod.java b/src/main/java/com/straice/TemplateMod.java deleted file mode 100644 index 1f53723..0000000 --- a/src/main/java/com/straice/TemplateMod.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.straice; - -import net.fabricmc.api.ModInitializer; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TemplateMod implements ModInitializer { - public static final String MOD_ID = "template-mod"; - - // This logger is used to write text to the console and the log file. - // It is considered best practice to use your mod id as the logger's name. - // That way, it's clear which mod wrote info, warnings, and errors. - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - - @Override - public void onInitialize() { - // This code runs as soon as Minecraft is in a mod-load-ready state. - // However, some things (like resources) may still be uninitialized. - // Proceed with mild caution. - - LOGGER.info("Hello Fabric world!"); - } -} \ No newline at end of file diff --git a/src/main/java/com/straice/mixin/ExampleMixin.java b/src/main/java/com/straice/mixin/ExampleMixin.java deleted file mode 100644 index 386c877..0000000 --- a/src/main/java/com/straice/mixin/ExampleMixin.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.straice.mixin; - -import net.minecraft.server.MinecraftServer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(MinecraftServer.class) -public class ExampleMixin { - @Inject(at = @At("HEAD"), method = "loadLevel") - private void init(CallbackInfo info) { - // This code is injected into the start of MinecraftServer.loadLevel()V - } -} \ No newline at end of file diff --git a/src/main/java/dev/dekin/iconsenhanced/IconsEnhanced.java b/src/main/java/dev/dekin/iconsenhanced/IconsEnhanced.java new file mode 100644 index 0000000..3d5c4c1 --- /dev/null +++ b/src/main/java/dev/dekin/iconsenhanced/IconsEnhanced.java @@ -0,0 +1,12 @@ +package dev.dekin.iconsenhanced; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class IconsEnhanced { + public static final String MOD_ID = "iconsenhanced"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + + private IconsEnhanced() { + } +} diff --git a/src/main/java/dev/dekin/iconsenhanced/adapters/DefaultEnchantmentAdapter.java b/src/main/java/dev/dekin/iconsenhanced/adapters/DefaultEnchantmentAdapter.java new file mode 100644 index 0000000..e84988d --- /dev/null +++ b/src/main/java/dev/dekin/iconsenhanced/adapters/DefaultEnchantmentAdapter.java @@ -0,0 +1,116 @@ +package dev.dekin.iconsenhanced.adapters; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +//? if <1.21 { +/*import java.util.Map; +*///?} + +import dev.dekin.iconsenhanced.IconsEnhanced; +import dev.dekin.iconsenhanced.common.EnchEntry; +import dev.dekin.iconsenhanced.common.IconKeyResolver; +import dev.dekin.iconsenhanced.common.IconKeyResolver.Visual; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +//? if >=1.21 { +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.minecraft.core.Holder; +import net.minecraft.core.component.DataComponents; +import net.minecraft.tags.EnchantmentTags; +import net.minecraft.world.item.enchantment.ItemEnchantments; +//?} else { +/*import net.minecraft.nbt.ListTag; +import net.minecraft.world.item.EnchantedBookItem; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +*///?} + +public final class DefaultEnchantmentAdapter implements EnchantmentAdapter { + @Override + public List getEnchantments(ItemStack stack) { + if (stack == null || stack.isEmpty()) { + return Collections.emptyList(); + } + + List entries = new ArrayList<>(); + + //? if >=1.21 { + appendEntries(entries, stack, stack.getEnchantments()); + ItemEnchantments stored = stack.get(DataComponents.STORED_ENCHANTMENTS); + if (stored != null && !stored.isEmpty()) { + appendEntries(entries, stack, stored); + } + //?} else { + /*Map enchantments = EnchantmentHelper.getEnchantments(stack); + if (!enchantments.isEmpty()) { + appendEntries(entries, stack, enchantments); + } + if (stack.getItem() instanceof EnchantedBookItem) { + ListTag list = EnchantedBookItem.getEnchantments(stack); + Map stored = EnchantmentHelper.deserializeEnchantments(list); + appendEntries(entries, stack, stored); + } + *///?} + + return entries; + } + + //? if >=1.21 { + private static void appendEntries(List entries, ItemStack stack, ItemEnchantments enchantments) { + if (enchantments == null || enchantments.isEmpty()) { + return; + } + for (Object2IntMap.Entry> entry : enchantments.entrySet()) { + Holder holder = entry.getKey(); + Enchantment enchantment = holder.value(); + int level = entry.getIntValue(); + String id = holder.unwrapKey() + .map(key -> key.identifier().toString()) + .orElse(""); + boolean isCurse = holder.is(EnchantmentTags.CURSE); + Visual visual = IconKeyResolver.resolve(id, isCurse); + Component name = colorize(enchantment.getFullname(holder, level), visual.color); + String descKey = buildDescKey(id); + entries.add(new EnchEntry(id, level, name, isCurse, visual.iconKey, descKey)); + } + } + //?} else { + /*private static void appendEntries(List entries, ItemStack stack, Map enchantments) { + if (enchantments == null || enchantments.isEmpty()) { + return; + } + for (Map.Entry entry : enchantments.entrySet()) { + Enchantment enchantment = entry.getKey(); + int level = entry.getValue(); + String id = BuiltInRegistries.ENCHANTMENT.getKey(enchantment).toString(); + boolean isCurse = enchantment.isCurse(); + Visual visual = IconKeyResolver.resolve(id, isCurse); + Component name = colorize(enchantment.getFullname(level), visual.color); + String descKey = buildDescKey(id); + entries.add(new EnchEntry(id, level, name, isCurse, visual.iconKey, descKey)); + } + } + *///?} + + private static String buildDescKey(String id) { + if (id == null || id.isBlank()) { + return ""; + } + int split = id.indexOf(':'); + if (split <= 0 || split >= id.length() - 1) { + return ""; + } + String namespace = id.substring(0, split); + String path = id.substring(split + 1); + return IconsEnhanced.MOD_ID + ".desc." + namespace + "." + path; + } + + private static Component colorize(Component name, int color) { + if (color == 0) { + return name; + } + return name.copy().withStyle(style -> style.withColor(color)); + } +} diff --git a/src/main/java/dev/dekin/iconsenhanced/adapters/EnchantmentAdapter.java b/src/main/java/dev/dekin/iconsenhanced/adapters/EnchantmentAdapter.java new file mode 100644 index 0000000..6cbcae7 --- /dev/null +++ b/src/main/java/dev/dekin/iconsenhanced/adapters/EnchantmentAdapter.java @@ -0,0 +1,10 @@ +package dev.dekin.iconsenhanced.adapters; + +import java.util.List; + +import dev.dekin.iconsenhanced.common.EnchEntry; +import net.minecraft.world.item.ItemStack; + +public interface EnchantmentAdapter { + List getEnchantments(ItemStack stack); +} diff --git a/src/main/java/dev/dekin/iconsenhanced/common/BorderColorLogic.java b/src/main/java/dev/dekin/iconsenhanced/common/BorderColorLogic.java new file mode 100644 index 0000000..a909645 --- /dev/null +++ b/src/main/java/dev/dekin/iconsenhanced/common/BorderColorLogic.java @@ -0,0 +1,115 @@ +package dev.dekin.iconsenhanced.common; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import dev.dekin.iconsenhanced.IconsEnhanced; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Rarity; + +public final class BorderColorLogic { + private final Map rarityColors = new HashMap<>(); + private final Map customRuleColors = new HashMap<>(); + private boolean enchantedOverride; + private int enchantedColor; + private boolean useCustomRules; + private String mode; + private int alpha; + + public void applyConfig(IconsEnhancedConfig config) { + IconsEnhancedConfig.Borders borders = config.borders; + rarityColors.clear(); + for (Map.Entry entry : borders.rarityColors.entrySet()) { + rarityColors.put(entry.getKey(), parseColor(entry.getValue(), 0xFFAAAAAA)); + } + + customRuleColors.clear(); + for (IconsEnhancedConfig.CustomBorderRule rule : borders.customRules) { + String id = normalizeId(rule.itemId); + if (id == null) { + IconsEnhanced.LOGGER.warn("Invalid border rule item id: {}", rule.itemId); + continue; + } + customRuleColors.put(id, parseColor(rule.color, 0xFFFFFFFF)); + } + + enchantedOverride = borders.enchantedOverride.enabled; + enchantedColor = parseColor(borders.enchantedOverride.color, 0xFFFFD700); + useCustomRules = borders.useCustomRules; + mode = borders.mode == null ? "RARITY" : borders.mode.trim().toUpperCase(); + alpha = clamp(borders.alpha, 0, 255); + } + + public int resolve(ItemStack stack) { + String itemId = BuiltInRegistries.ITEM.getKey(stack.getItem()).toString(); + if (useCustomRules) { + Integer ruleColor = customRuleColors.get(itemId); + if (ruleColor != null) { + return withAlpha(ruleColor, alpha); + } + } + + if (enchantedOverride && stack.isEnchanted()) { + return withAlpha(enchantedColor, alpha); + } + + if ("CUSTOM".equals(mode)) { + Integer ruleColor = customRuleColors.get(itemId); + if (ruleColor != null) { + return withAlpha(ruleColor, alpha); + } + } + + int rarityColor = rarityColors.getOrDefault(rarityKey(stack.getRarity()), 0xFFAAAAAA); + return withAlpha(rarityColor, alpha); + } + + private static String normalizeId(String raw) { + if (raw == null) { + return null; + } + String cleaned = raw.trim().toLowerCase(Locale.ROOT); + if (cleaned.isEmpty() || !cleaned.contains(":")) { + return null; + } + return cleaned; + } + + private static String rarityKey(Rarity rarity) { + if (rarity == Rarity.UNCOMMON) { + return "uncommon"; + } + if (rarity == Rarity.RARE) { + return "rare"; + } + if (rarity == Rarity.EPIC) { + return "epic"; + } + return "common"; + } + + private static int parseColor(String value, int fallback) { + if (value == null) { + return fallback; + } + try { + String cleaned = value.trim(); + if (cleaned.isEmpty()) { + return fallback; + } + return (int) Long.decode(cleaned).longValue(); + } catch (NumberFormatException ex) { + return fallback; + } + } + + private static int withAlpha(int color, int alpha) { + return (color & 0x00FFFFFF) | ((alpha & 0xFF) << 24); + } + + private static int clamp(int value, int min, int max) { + return Math.min(max, Math.max(min, value)); + } +} diff --git a/src/main/java/dev/dekin/iconsenhanced/common/ConfigManager.java b/src/main/java/dev/dekin/iconsenhanced/common/ConfigManager.java new file mode 100644 index 0000000..56f927c --- /dev/null +++ b/src/main/java/dev/dekin/iconsenhanced/common/ConfigManager.java @@ -0,0 +1,72 @@ +package dev.dekin.iconsenhanced.common; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; + +import dev.dekin.iconsenhanced.IconsEnhanced; +import net.fabricmc.loader.api.FabricLoader; + +public final class ConfigManager { + private static final Gson GSON = new GsonBuilder() + .setPrettyPrinting() + .disableHtmlEscaping() + .create(); + private static final Path CONFIG_PATH = FabricLoader.getInstance() + .getConfigDir() + .resolve(IconsEnhanced.MOD_ID + ".json"); + + private static IconsEnhancedConfig config = new IconsEnhancedConfig(); + + private ConfigManager() { + } + + public static IconsEnhancedConfig get() { + return config; + } + + public static void load() { + IconsEnhancedConfig loaded = null; + boolean needsSave = false; + if (Files.exists(CONFIG_PATH)) { + try (Reader reader = Files.newBufferedReader(CONFIG_PATH)) { + loaded = GSON.fromJson(reader, IconsEnhancedConfig.class); + } catch (JsonSyntaxException | IOException e) { + IconsEnhanced.LOGGER.warn("Config parse failed, recreating defaults.", e); + needsSave = true; + } + } else { + needsSave = true; + } + + if (loaded == null) { + loaded = new IconsEnhancedConfig(); + needsSave = true; + } else { + needsSave |= loaded.applyDefaults(); + } + + config = loaded; + + if (needsSave) { + save(); + } + } + + public static void save() { + try { + Files.createDirectories(CONFIG_PATH.getParent()); + try (Writer writer = Files.newBufferedWriter(CONFIG_PATH)) { + GSON.toJson(config, writer); + } + } catch (IOException e) { + IconsEnhanced.LOGGER.warn("Failed to write config to disk.", e); + } + } +} diff --git a/src/main/java/dev/dekin/iconsenhanced/common/EnchEntry.java b/src/main/java/dev/dekin/iconsenhanced/common/EnchEntry.java new file mode 100644 index 0000000..594a574 --- /dev/null +++ b/src/main/java/dev/dekin/iconsenhanced/common/EnchEntry.java @@ -0,0 +1,41 @@ +package dev.dekin.iconsenhanced.common; + +import net.minecraft.network.chat.Component; + +public final class EnchEntry { + public final String id; + public final String namespace; + public final String path; + public final int level; + public final Component displayName; + public final String displayNameString; + public final boolean isCurse; + public final String iconKey; + public final String descKey; + + public EnchEntry(String id, int level, Component displayName, boolean isCurse, String iconKey, String descKey) { + this.id = id == null ? "" : id; + IdParts parts = IdParts.parse(this.id); + this.namespace = parts.namespace; + this.path = parts.path; + this.level = level; + this.displayName = displayName; + this.displayNameString = displayName.getString(); + this.isCurse = isCurse; + this.iconKey = iconKey; + this.descKey = descKey; + } + + private record IdParts(String namespace, String path) { + private static IdParts parse(String id) { + if (id == null || id.isEmpty()) { + return new IdParts("", ""); + } + int split = id.indexOf(':'); + if (split <= 0 || split >= id.length() - 1) { + return new IdParts("minecraft", id); + } + return new IdParts(id.substring(0, split), id.substring(split + 1)); + } + } +} diff --git a/src/main/java/dev/dekin/iconsenhanced/common/EnchantSortLogic.java b/src/main/java/dev/dekin/iconsenhanced/common/EnchantSortLogic.java new file mode 100644 index 0000000..f5f3bb7 --- /dev/null +++ b/src/main/java/dev/dekin/iconsenhanced/common/EnchantSortLogic.java @@ -0,0 +1,63 @@ +package dev.dekin.iconsenhanced.common; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public final class EnchantSortLogic { + public List sort(List entries, IconsEnhancedConfig.Tooltips tooltips) { + List sorted = new ArrayList<>(entries); + Comparator comparator = buildComparator(tooltips); + sorted.sort(comparator); + return sorted; + } + + private static Comparator buildComparator(IconsEnhancedConfig.Tooltips tooltips) { + Comparator base = switch (SortMode.fromString(tooltips.sortMode)) { + case BY_NAME -> Comparator.comparing(entry -> entry.displayNameString.toLowerCase(Locale.ROOT)); + case BY_LEVEL_DESC -> Comparator.comparingInt(entry -> entry.level).reversed() + .thenComparing(entry -> entry.displayNameString.toLowerCase(Locale.ROOT)); + case CUSTOM_PRIORITY_LIST -> customPriorityComparator(tooltips.customPriorityList); + case BY_VANILLA_LIKE -> Comparator + .comparing((EnchEntry entry) -> entry.namespace) + .thenComparing(entry -> entry.path); + }; + + if (tooltips.cursesLast) { + return Comparator.comparingInt((EnchEntry entry) -> entry.isCurse ? 1 : 0).thenComparing(base); + } + return base; + } + + private static Comparator customPriorityComparator(List priorityList) { + Map priority = new HashMap<>(); + for (int i = 0; i < priorityList.size(); i++) { + priority.put(priorityList.get(i), i); + } + return Comparator + .comparingInt((EnchEntry entry) -> priority.getOrDefault(entry.id, Integer.MAX_VALUE)) + .thenComparing(entry -> entry.displayNameString.toLowerCase(Locale.ROOT)); + } + + public enum SortMode { + BY_VANILLA_LIKE, + BY_NAME, + BY_LEVEL_DESC, + CUSTOM_PRIORITY_LIST; + + public static SortMode fromString(String raw) { + if (raw == null) { + return BY_LEVEL_DESC; + } + for (SortMode value : values()) { + if (value.name().equalsIgnoreCase(raw)) { + return value; + } + } + return BY_LEVEL_DESC; + } + } +} diff --git a/src/main/java/dev/dekin/iconsenhanced/common/IconAtlas.java b/src/main/java/dev/dekin/iconsenhanced/common/IconAtlas.java new file mode 100644 index 0000000..a259e6e --- /dev/null +++ b/src/main/java/dev/dekin/iconsenhanced/common/IconAtlas.java @@ -0,0 +1,69 @@ +package dev.dekin.iconsenhanced.common; + +import java.util.HashMap; +import java.util.Map; + +import dev.dekin.iconsenhanced.IconsEnhanced; +//? if >=1.21 { +import net.minecraft.resources.Identifier; +//?} else { +/*import net.minecraft.resources.ResourceLocation; +*///?} + +public final class IconAtlas { + //? if >=1.21 { + public static final Identifier ATLAS = Identifier.fromNamespaceAndPath(IconsEnhanced.MOD_ID, "textures/gui/enchant_icons.png"); + //?} else { + /*public static final ResourceLocation ATLAS = new ResourceLocation(IconsEnhanced.MOD_ID, "textures/gui/enchant_icons.png"); + *///?} + public static final int ICON_SOURCE_SIZE = 16; + public static final int ATLAS_COLUMNS = 4; + public static final int ATLAS_SIZE = ICON_SOURCE_SIZE * ATLAS_COLUMNS; + + private static final Map ICONS = new HashMap<>(); + + static { + register("boots", 0); + register("bow", 1); + register("chestplate", 2); + register("crossbow", 3); + register("fishing", 4); + register("helmet", 5); + register("leggings", 6); + register("mace", 7); + register("pickaxe", 8); + register("curse", 9); + register("default", 10); + register("sword", 11); + register("trident", 12); + } + + private IconAtlas() { + } + + public static IconSprite get(String key) { + IconSprite sprite = ICONS.get(key); + if (sprite != null) { + return sprite; + } + return ICONS.get("default"); + } + + private static void register(String key, int index) { + int col = index % ATLAS_COLUMNS; + int row = index / ATLAS_COLUMNS; + ICONS.put(key, new IconSprite(col * ICON_SOURCE_SIZE, row * ICON_SOURCE_SIZE, ICON_SOURCE_SIZE)); + } + + public static final class IconSprite { + public final int u; + public final int v; + public final int size; + + private IconSprite(int u, int v, int size) { + this.u = u; + this.v = v; + this.size = size; + } + } +} diff --git a/src/main/java/dev/dekin/iconsenhanced/common/IconKeyResolver.java b/src/main/java/dev/dekin/iconsenhanced/common/IconKeyResolver.java new file mode 100644 index 0000000..9fb3198 --- /dev/null +++ b/src/main/java/dev/dekin/iconsenhanced/common/IconKeyResolver.java @@ -0,0 +1,89 @@ +package dev.dekin.iconsenhanced.common; + +import java.util.HashMap; +import java.util.Map; + +public final class IconKeyResolver { + public static final class Visual { + public final String iconKey; + public final int color; + + private Visual(String iconKey, int color) { + this.iconKey = iconKey; + this.color = color; + } + } + + private static final Visual DEFAULT = new Visual("default", 0xFCFCFC); + private static final Visual CURSE_DEFAULT = new Visual("curse", 0xA80000); + private static final Map VISUALS = new HashMap<>(); + + static { + register("minecraft:aqua_affinity", "helmet", 0x54FCFC); + register("minecraft:bane_of_arthropods", "sword", 0xA800A8); + register("minecraft:curse_of_binding", "curse", 0xA80000); + register("minecraft:blast_protection", "chestplate", 0x00A800); + register("minecraft:channeling", "trident", 0xFCA800); + register("minecraft:depth_strider", "boots", 0x54FCFC); + register("minecraft:efficiency", "pickaxe", 0x00A800); + register("minecraft:feather_falling", "boots", 0x5454FC); + register("minecraft:fire_aspect", "sword", 0xFC5454); + register("minecraft:fire_protection", "chestplate", 0xFC5454); + register("minecraft:flame", "bow", 0xFC5454); + register("minecraft:fortune", "pickaxe", 0xFC54FC); + register("minecraft:frost_walker", "boots", 0x54FCFC); + register("minecraft:impaling", "trident", 0x54FCFC); + register("minecraft:infinity", "bow", 0xFC54FC); + register("minecraft:knockback", "sword", 0x00A8A8); + register("minecraft:looting", "sword", 0xFC54FC); + register("minecraft:loyalty", "trident", 0x0000A8); + register("minecraft:luck_of_the_sea", "fishing", 0x54FCFC); + register("minecraft:lure", "fishing", 0x54FCFC); + register("minecraft:mending", "default", 0xFCFC54); + register("minecraft:multishot", "crossbow", 0xFC54FC); + register("minecraft:piercing", "crossbow", 0xFCA800); + register("minecraft:power", "bow", 0xFCA800); + register("minecraft:projectile_protection", "chestplate", 0x54FC54); + register("minecraft:protection", "chestplate", 0xFC54FC); + register("minecraft:punch", "bow", 0x54FC54); + register("minecraft:quick_charge", "crossbow", 0x54FC54); + register("minecraft:respiration", "helmet", 0x00A8A8); + register("minecraft:riptide", "trident", 0x00A8A8); + register("minecraft:sharpness", "sword", 0x54FC54); + register("minecraft:silk_touch", "pickaxe", 0x54FCFC); + register("minecraft:smite", "sword", 0xFCA800); + register("minecraft:soul_speed", "boots", 0x00A8A8); + register("minecraft:sweeping_edge", "sword", 0x54FCFC); + register("minecraft:swift_sneak", "leggings", 0x00A8A8); + register("minecraft:thorns", "chestplate", 0x00A800); + register("minecraft:unbreaking", "default", 0xFCFC54); + register("minecraft:curse_of_vanishing", "curse", 0xA80000); + + register("minecraft:breach", "mace", 0xA800A8); + register("minecraft:density", "mace", 0xA80000); + register("minecraft:wind_burst", "mace", 0x54FCFC); + } + + private IconKeyResolver() { + } + + public static Visual resolve(String id, boolean isCurse) { + String key = normalizeId(id); + Visual visual = VISUALS.get(key); + if (visual != null) { + return visual; + } + if (isCurse) { + return CURSE_DEFAULT; + } + return DEFAULT; + } + + private static void register(String id, String iconKey, int color) { + VISUALS.put(id, new Visual(iconKey, color)); + } + + private static String normalizeId(String id) { + return id == null ? "" : id; + } +} diff --git a/src/main/java/dev/dekin/iconsenhanced/common/IconsEnhancedConfig.java b/src/main/java/dev/dekin/iconsenhanced/common/IconsEnhancedConfig.java new file mode 100644 index 0000000..c7c24cb --- /dev/null +++ b/src/main/java/dev/dekin/iconsenhanced/common/IconsEnhancedConfig.java @@ -0,0 +1,164 @@ +package dev.dekin.iconsenhanced.common; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public final class IconsEnhancedConfig { + public Borders borders = new Borders(); + public Tooltips tooltips = new Tooltips(); + + public boolean applyDefaults() { + boolean changed = false; + if (borders == null) { + borders = new Borders(); + changed = true; + } else { + changed |= borders.applyDefaults(); + } + if (tooltips == null) { + tooltips = new Tooltips(); + changed = true; + } else { + changed |= tooltips.applyDefaults(); + } + return changed; + } + + public static final class Borders { + public boolean enabled = true; + public int thickness = 1; + public int alpha = 200; + public String mode = "RARITY"; + public Map rarityColors = defaultRarityColors(); + public EnchantedOverride enchantedOverride = new EnchantedOverride(); + public boolean useCustomRules = false; + public List customRules = new ArrayList<>(); + + private boolean applyDefaults() { + boolean changed = false; + if (mode == null || mode.isBlank()) { + mode = "RARITY"; + changed = true; + } + if (rarityColors == null) { + rarityColors = defaultRarityColors(); + changed = true; + } else { + changed |= ensureRarityKey("common", "0xFFAAAAAA"); + changed |= ensureRarityKey("uncommon", "0xFF55FF55"); + changed |= ensureRarityKey("rare", "0xFF5555FF"); + changed |= ensureRarityKey("epic", "0xFFFF55FF"); + } + if (enchantedOverride == null) { + enchantedOverride = new EnchantedOverride(); + changed = true; + } + if (customRules == null) { + customRules = new ArrayList<>(); + changed = true; + } + return changed; + } + + private boolean ensureRarityKey(String key, String value) { + if (!rarityColors.containsKey(key)) { + rarityColors.put(key, value); + return true; + } + return false; + } + + private static Map defaultRarityColors() { + Map defaults = new LinkedHashMap<>(); + defaults.put("common", "0xFFAAAAAA"); + defaults.put("uncommon", "0xFF55FF55"); + defaults.put("rare", "0xFF5555FF"); + defaults.put("epic", "0xFFFF55FF"); + return defaults; + } + } + + public static final class EnchantedOverride { + public boolean enabled = true; + public String color = "0xFFFFD700"; + } + + public static final class CustomBorderRule { + public String itemId = ""; + public String color = "0xFFFFFFFF"; + } + + public static final class Tooltips { + public boolean enabled = true; + public boolean reorderEnchantments = true; + public String sortMode = "CUSTOM_PRIORITY_LIST"; + public boolean cursesLast = true; + public boolean showDescriptions = true; + public boolean showIcons = true; + public int iconSize = 10; + public boolean showLevelBadge = true; + public List customPriorityList = defaultCustomPriorityList(); + + private boolean applyDefaults() { + boolean changed = false; + if (sortMode == null || sortMode.isBlank()) { + sortMode = "CUSTOM_PRIORITY_LIST"; + changed = true; + } + if (customPriorityList == null || customPriorityList.isEmpty()) { + customPriorityList = defaultCustomPriorityList(); + changed = true; + } + return changed; + } + + private static List defaultCustomPriorityList() { + List defaults = new ArrayList<>(); + defaults.add("minecraft:bane_of_arthropods"); + defaults.add("minecraft:density"); + defaults.add("minecraft:efficiency"); + defaults.add("minecraft:impaling"); + defaults.add("minecraft:power"); + defaults.add("minecraft:sharpness"); + defaults.add("minecraft:smite"); + defaults.add("minecraft:blast_protection"); + defaults.add("minecraft:breach"); + defaults.add("minecraft:feather_falling"); + defaults.add("minecraft:fire_protection"); + defaults.add("minecraft:piercing"); + defaults.add("minecraft:projectile_protection"); + defaults.add("minecraft:protection"); + defaults.add("minecraft:depth_strider"); + defaults.add("minecraft:fortune"); + defaults.add("minecraft:looting"); + defaults.add("minecraft:loyalty"); + defaults.add("minecraft:luck_of_the_sea"); + defaults.add("minecraft:lure"); + defaults.add("minecraft:quick_charge"); + defaults.add("minecraft:respiration"); + defaults.add("minecraft:riptide"); + defaults.add("minecraft:soul_speed"); + defaults.add("minecraft:sweeping_edge"); + defaults.add("minecraft:swift_sneak"); + defaults.add("minecraft:thorns"); + defaults.add("minecraft:unbreaking"); + defaults.add("minecraft:wind_burst"); + defaults.add("minecraft:fire_aspect"); + defaults.add("minecraft:frost_walker"); + defaults.add("minecraft:knockback"); + defaults.add("minecraft:punch"); + defaults.add("minecraft:aqua_affinity"); + defaults.add("minecraft:channeling"); + defaults.add("minecraft:curse_of_binding"); + defaults.add("minecraft:curse_of_vanishing"); + defaults.add("minecraft:flame"); + defaults.add("minecraft:infinity"); + defaults.add("minecraft:mending"); + defaults.add("minecraft:multishot"); + defaults.add("minecraft:silk_touch"); + return defaults; + } + } +} diff --git a/src/main/java/dev/dekin/iconsenhanced/common/TooltipLayoutModel.java b/src/main/java/dev/dekin/iconsenhanced/common/TooltipLayoutModel.java new file mode 100644 index 0000000..7d9e2cf --- /dev/null +++ b/src/main/java/dev/dekin/iconsenhanced/common/TooltipLayoutModel.java @@ -0,0 +1,33 @@ +package dev.dekin.iconsenhanced.common; + +import java.util.List; + +import net.minecraft.network.chat.Component; + +public final class TooltipLayoutModel { + private final List rows; + + public TooltipLayoutModel(List rows) { + this.rows = rows; + } + + public List rows() { + return rows; + } + + public static final class Row { + public final Component text; + public final List descriptions; + public final String iconKey; + public final int level; + public final boolean isCurse; + + public Row(Component text, List descriptions, String iconKey, int level, boolean isCurse) { + this.text = text; + this.descriptions = descriptions; + this.iconKey = iconKey; + this.level = level; + this.isCurse = isCurse; + } + } +} diff --git a/src/main/resources/assets/iconsenhanced/icon.png b/src/main/resources/assets/iconsenhanced/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4f2fe2b5f19ae55c00ceea38da5ad44dad8f1577 GIT binary patch literal 404 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/template-mod/icon.png b/src/main/resources/assets/template-mod/icon.png deleted file mode 100644 index 66db08f8f3548698e4fe8a7eb5a94959fc287400..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2786 zcmdT`=T{T>68$9sf>{HoEX^e#$}Ua1AW{rX+JaH4tcjp>qzD4R5DB8vo4^L8gGiG^ zdhgP!A~p2B0wP5cLwoG|8{U`qVP?*`XJ+o1Ip@xqFpP;F5+Q&903Z$Yb#9+T(!a*e zcH&z#YL0c`S+W_=y`tn}#q3F51_p679j{YeXe~RN z#oLBin0MWxFkNZ!aK4N``KsF{>4yW3sUGV4Q{){rNA*pW+WNFpn}oE|y=m9Oy$M$; z(I0+vurJ5#vVg%5=!yy%0SZ`j3uG1c-j@Uj5?jz6g$z0L$nvPLtoP2p$TDQx0sVkf zw?Q3h>fN9MG4KZ7`34dNDN$-Pfhj0ALNkC9O4x%3 z_zH(U0R`I@mK8e3Z&z(@Lso$GsfnJ*L&XcUM2ntFsh^a0)5K2whid3_O-zLaF-p_P$ogZKWtC zo>z8Hd96XLsV46GZgFUs_3v%aQl-q?lpSt`#^Fz2c{H!HbGYwU>PD-Omu`uC_V~;* zkKQD?*>N+7|N zAcpfxw?V(4uis4cg-x97hm0AQuUemL4Iwl-Hab>j^Ah)1N%YMby>lXyK3QimEs^{R zy@i(4Zd}AnYZ9;YU9mN17%A<;{kHIVbzZ*jhzOp`@|;2%Qt1n+1L@bv@@`;oO)rwq z_UX~VcpTjm(lz5#PS}_zUs`8p&061D=tx%fm`-?kLoi*<|MnMnQzL#W>pg9_(6Wy# zb1yty?!~)-&bW(x&B5@Vbi%OXJrF7?HOnDqd};JxwmF!iGIC{Ylq!S0U?~MBNpc|P z2JRaCaY9wkhqeqqzLGMTQAelZvR%EoD-%y|g0FcDj;h7&tyrI#KB z&)eY3wRk%@kBD=km(aV9d=V{aNaAebLL2?~_~@|ZM@vq8^5VGm?a)HKkMHabRLJ}=V3;-A ztMq&m`;AGAHG*LN%Zt<-XtFy0*F8@pgo65X6Lb!mL-H4;#sQrJw)Jg!vYjf}(G1MQsLz&idrT&@#-2+#oWy z(4t5_iIe8-U3-7Glp9Q5wuF%GJ~8LSwABy!X@!-#tDR(W!$@$);ya+vM|*J}2(`x>A|kaABPStd*2s)F$oL zV|F0*_2JluOnvd4UAaV~2#r|XS!H6u4v<_-5n4GRBz>!GI)wg-DkW0E?k9mV?_8JLxiRKj;U)-R zHy&HOvoW4)@mWA~2yR;V{^*MBZuA##39`QdCRPw!Q4&nNk zOl^5FBE&%0p5|%(s-i0no(cSJuVv>n#2Qs=_Bg(k1Qli>)sJu#OOHkyi)QP^d=o40 zs&4of-54QKrpi$6s=6B2u9CM0L?dLK6YOhHH=ym4CHbDOPN!wdDquX(wfQS_*fbGm_?PcH}-#q3d55 z#Vv`12}IvoA0B}xvtT*~WFh0t0P+Hg9&%zTv!P~0);oF;AHZnXcO!wW{*4s``g;c8~GEisE z6#W2`fMQy+r=m?ejQ6d|^cU_#It#IsQ@bmh=YPWXLwR#T#4YE#hx7pl<1#Rjv_s|BQ{o0Lyv)KkjdYRR^2Ab#B1nWr^F^7 z{ON}rs_&4rq)2_!w61?r-c0dYMc!u!_zXpwwcvSD74Y7k?3%Q zaZx`4?ZR`8LWK&yAN=xB9OU2mv#J3>`k-ZcE*HFYkeg#lfEI+YaSAl{P22OeLclJm gc;(UmZ4sT5Q6a(WV%qWQ=0.18.4", - "minecraft": "~1.21.11", - "java": ">=21", - "fabric-api": "*" - } -} \ No newline at end of file + "schemaVersion": 1, + "id": "${mod_id}", + "version": "${version}", + "name": "${mod_name}", + "description": "${mod_description}", + "authors": [ + "${mod_author}" + ], + "license": "${mod_license}", + "environment": "client", + "entrypoints": { + "client": [ + "dev.dekin.iconsenhanced.client.ClientInit" + ] + }, + "mixins": [ + "iconsenhanced.mixins.json" + ], + "depends": { + "fabricloader": ">=${fabric_loader_version}", + "fabric": "*", + "minecraft": "${minecraft_version}" + }, + "icon": "assets/${mod_id}/icon.png" +} diff --git a/src/main/resources/iconsenhanced.mixins.json b/src/main/resources/iconsenhanced.mixins.json new file mode 100644 index 0000000..cd00aac --- /dev/null +++ b/src/main/resources/iconsenhanced.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "package": "dev.dekin.iconsenhanced.mixin", + "compatibilityLevel": "JAVA_17", + "client": [ + "AbstractContainerScreenAccessor" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/src/main/resources/template-mod.mixins.json b/src/main/resources/template-mod.mixins.json deleted file mode 100644 index 63ee472..0000000 --- a/src/main/resources/template-mod.mixins.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "required": true, - "package": "com.straice.mixin", - "compatibilityLevel": "JAVA_21", - "mixins": [ - "ExampleMixin" - ], - "injectors": { - "defaultRequire": 1 - }, - "overwrites": { - "requireAnnotations": true - } -} \ No newline at end of file diff --git a/stonecutter.gradle b/stonecutter.gradle new file mode 100644 index 0000000..42f43a1 --- /dev/null +++ b/stonecutter.gradle @@ -0,0 +1,15 @@ +plugins { + id 'dev.kikugie.stonecutter' +} + +stonecutter.active "1.21.11" + +tasks.register("chiseledBuild") { + group = "build" + dependsOn(stonecutter.tree.nodes.collect { it.project.tasks.named("build") }) +} + +tasks.register("chiseledClean") { + group = "build" + dependsOn(stonecutter.tree.nodes.collect { it.project.tasks.named("clean") }) +} diff --git a/versions/1.20.1/gradle.properties b/versions/1.20.1/gradle.properties new file mode 100644 index 0000000..13a3076 --- /dev/null +++ b/versions/1.20.1/gradle.properties @@ -0,0 +1,7 @@ +# Fabric dependencies + +deps.fabric_loader=0.18.4 +deps.fabric_api=0.92.6+1.20.1 + +# Java +java_version=17 diff --git a/versions/1.20.4/gradle.properties b/versions/1.20.4/gradle.properties new file mode 100644 index 0000000..34b45a4 --- /dev/null +++ b/versions/1.20.4/gradle.properties @@ -0,0 +1,7 @@ +# Fabric dependencies + +deps.fabric_loader=0.18.4 +deps.fabric_api=0.97.3+1.20.4 + +# Java +java_version=17 diff --git a/versions/1.20.6/gradle.properties b/versions/1.20.6/gradle.properties new file mode 100644 index 0000000..3cab226 --- /dev/null +++ b/versions/1.20.6/gradle.properties @@ -0,0 +1,7 @@ +# Fabric dependencies + +deps.fabric_loader=0.18.4 +deps.fabric_api=0.99.4+1.20.6 + +# Java +java_version=21 diff --git a/versions/1.21.1/gradle.properties b/versions/1.21.1/gradle.properties new file mode 100644 index 0000000..3696d6e --- /dev/null +++ b/versions/1.21.1/gradle.properties @@ -0,0 +1,7 @@ +# Fabric dependencies + +deps.fabric_loader=0.18.4 +deps.fabric_api=0.116.7+1.21.1 + +# Java +java_version=21 diff --git a/versions/1.21.11/gradle.properties b/versions/1.21.11/gradle.properties new file mode 100644 index 0000000..4ae4286 --- /dev/null +++ b/versions/1.21.11/gradle.properties @@ -0,0 +1,7 @@ +# Fabric dependencies + +deps.fabric_loader=0.18.4 +deps.fabric_api=0.141.1+1.21.11 + +# Java +java_version=21 diff --git a/versions/1.21.4/gradle.properties b/versions/1.21.4/gradle.properties new file mode 100644 index 0000000..f4157d3 --- /dev/null +++ b/versions/1.21.4/gradle.properties @@ -0,0 +1,7 @@ +# Fabric dependencies + +deps.fabric_loader=0.18.4 +deps.fabric_api=0.119.4+1.21.4 + +# Java +java_version=21