first test
This commit is contained in:
12
README.md
12
README.md
@@ -1 +1,11 @@
|
||||
test
|
||||
# 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
|
||||
|
||||
@@ -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
|
||||
# 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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
*///?}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<Boolean> CAPTURE = ThreadLocal.withInitial(() -> Boolean.FALSE);
|
||||
private static final ThreadLocal<EnchantTooltipData> 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<Component> 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<TooltipComponent> 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<Component> lines) {
|
||||
try {
|
||||
IconsEnhancedConfig config = ConfigManager.get();
|
||||
if (!config.tooltips.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<EnchEntry> entries = ADAPTER.getEnchantments(stack);
|
||||
if (entries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TooltipBlock block = TooltipBlock.find(lines, entries);
|
||||
if (!block.contiguous) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<EnchEntry> 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<EnchEntry> ordered = config.tooltips.reorderEnchantments ? sorted : entries;
|
||||
List<Component> 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<EnchEntry> entries, IconsEnhancedConfig.Tooltips tooltips) {
|
||||
List<TooltipLayoutModel.Row> rows = new ArrayList<>();
|
||||
for (EnchEntry entry : entries) {
|
||||
List<Component> 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<Component> buildTextLines(List<EnchEntry> entries, boolean showDescriptions) {
|
||||
List<Component> 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<Component> lines) {
|
||||
lines.subList(start, end + 1).clear();
|
||||
}
|
||||
|
||||
private void replace(List<Component> lines, List<Component> replacement) {
|
||||
lines.subList(start, end + 1).clear();
|
||||
lines.addAll(start, replacement);
|
||||
}
|
||||
|
||||
private static TooltipBlock find(List<Component> lines, List<EnchEntry> entries) {
|
||||
Set<String> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<String, List<Component>> CACHE = new HashMap<>();
|
||||
private static final Style DESCRIPTION_STYLE = Style.EMPTY;
|
||||
|
||||
private TooltipTextUtil() {
|
||||
}
|
||||
|
||||
public static List<Component> 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<Component> splitLines(String key) {
|
||||
String text = I18n.get(key);
|
||||
if (text == null || text.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
String[] parts = text.split("\\\\n");
|
||||
List<Component> lines = new ArrayList<>(parts.length);
|
||||
for (String part : parts) {
|
||||
if (!part.isEmpty()) {
|
||||
lines.add(Component.literal(part).setStyle(DESCRIPTION_STYLE));
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(lines);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "com.straice.mixin.client",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"client": [
|
||||
"ExampleClientMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
@@ -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!");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
12
src/main/java/dev/dekin/iconsenhanced/IconsEnhanced.java
Normal file
12
src/main/java/dev/dekin/iconsenhanced/IconsEnhanced.java
Normal file
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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<EnchEntry> getEnchantments(ItemStack stack) {
|
||||
if (stack == null || stack.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<EnchEntry> 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<Enchantment, Integer> enchantments = EnchantmentHelper.getEnchantments(stack);
|
||||
if (!enchantments.isEmpty()) {
|
||||
appendEntries(entries, stack, enchantments);
|
||||
}
|
||||
if (stack.getItem() instanceof EnchantedBookItem) {
|
||||
ListTag list = EnchantedBookItem.getEnchantments(stack);
|
||||
Map<Enchantment, Integer> stored = EnchantmentHelper.deserializeEnchantments(list);
|
||||
appendEntries(entries, stack, stored);
|
||||
}
|
||||
*///?}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
//? if >=1.21 {
|
||||
private static void appendEntries(List<EnchEntry> entries, ItemStack stack, ItemEnchantments enchantments) {
|
||||
if (enchantments == null || enchantments.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (Object2IntMap.Entry<Holder<Enchantment>> entry : enchantments.entrySet()) {
|
||||
Holder<Enchantment> 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<EnchEntry> entries, ItemStack stack, Map<Enchantment, Integer> enchantments) {
|
||||
if (enchantments == null || enchantments.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (Map.Entry<Enchantment, Integer> 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));
|
||||
}
|
||||
}
|
||||
@@ -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<EnchEntry> getEnchantments(ItemStack stack);
|
||||
}
|
||||
@@ -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<String, Integer> rarityColors = new HashMap<>();
|
||||
private final Map<String, Integer> 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<String, String> 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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/main/java/dev/dekin/iconsenhanced/common/EnchEntry.java
Normal file
41
src/main/java/dev/dekin/iconsenhanced/common/EnchEntry.java
Normal file
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<EnchEntry> sort(List<EnchEntry> entries, IconsEnhancedConfig.Tooltips tooltips) {
|
||||
List<EnchEntry> sorted = new ArrayList<>(entries);
|
||||
Comparator<EnchEntry> comparator = buildComparator(tooltips);
|
||||
sorted.sort(comparator);
|
||||
return sorted;
|
||||
}
|
||||
|
||||
private static Comparator<EnchEntry> buildComparator(IconsEnhancedConfig.Tooltips tooltips) {
|
||||
Comparator<EnchEntry> base = switch (SortMode.fromString(tooltips.sortMode)) {
|
||||
case BY_NAME -> Comparator.comparing(entry -> entry.displayNameString.toLowerCase(Locale.ROOT));
|
||||
case BY_LEVEL_DESC -> Comparator.<EnchEntry>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<EnchEntry> customPriorityComparator(List<String> priorityList) {
|
||||
Map<String, Integer> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
69
src/main/java/dev/dekin/iconsenhanced/common/IconAtlas.java
Normal file
69
src/main/java/dev/dekin/iconsenhanced/common/IconAtlas.java
Normal file
@@ -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<String, IconSprite> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<String, Visual> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<String, String> rarityColors = defaultRarityColors();
|
||||
public EnchantedOverride enchantedOverride = new EnchantedOverride();
|
||||
public boolean useCustomRules = false;
|
||||
public List<CustomBorderRule> 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<String, String> defaultRarityColors() {
|
||||
Map<String, String> 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<String> 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<String> defaultCustomPriorityList() {
|
||||
List<String> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Row> rows;
|
||||
|
||||
public TooltipLayoutModel(List<Row> rows) {
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
public List<Row> rows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
public static final class Row {
|
||||
public final Component text;
|
||||
public final List<Component> descriptions;
|
||||
public final String iconKey;
|
||||
public final int level;
|
||||
public final boolean isCurse;
|
||||
|
||||
public Row(Component text, List<Component> descriptions, String iconKey, int level, boolean isCurse) {
|
||||
this.text = text;
|
||||
this.descriptions = descriptions;
|
||||
this.iconKey = iconKey;
|
||||
this.level = level;
|
||||
this.isCurse = isCurse;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/assets/iconsenhanced/icon.png
Normal file
BIN
src/main/resources/assets/iconsenhanced/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 404 B |
11
src/main/resources/assets/iconsenhanced/lang/en_us.json
Normal file
11
src/main/resources/assets/iconsenhanced/lang/en_us.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"iconsenhanced.desc.minecraft.sharpness": "Increases melee damage.",
|
||||
"iconsenhanced.desc.minecraft.protection": "Reduces incoming damage.",
|
||||
"iconsenhanced.desc.minecraft.unbreaking": "Items lose durability slower.",
|
||||
"iconsenhanced.desc.minecraft.mending": "Repairs items with experience.",
|
||||
"iconsenhanced.desc.minecraft.efficiency": "Increases mining speed.",
|
||||
"iconsenhanced.desc.minecraft.power": "Increases bow damage.",
|
||||
"iconsenhanced.desc.minecraft.thorns": "Reflects damage to attackers.",
|
||||
"iconsenhanced.desc.minecraft.binding_curse": "Cursed: stays equipped.",
|
||||
"iconsenhanced.desc.minecraft.vanishing_curse": "Cursed: disappears on death."
|
||||
}
|
||||
11
src/main/resources/assets/iconsenhanced/lang/es_es.json
Normal file
11
src/main/resources/assets/iconsenhanced/lang/es_es.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"iconsenhanced.desc.minecraft.sharpness": "Aumenta el dano cuerpo a cuerpo.",
|
||||
"iconsenhanced.desc.minecraft.protection": "Reduce el dano recibido.",
|
||||
"iconsenhanced.desc.minecraft.unbreaking": "Los objetos pierden durabilidad mas lento.",
|
||||
"iconsenhanced.desc.minecraft.mending": "Repara objetos con experiencia.",
|
||||
"iconsenhanced.desc.minecraft.efficiency": "Aumenta la velocidad de mineria.",
|
||||
"iconsenhanced.desc.minecraft.power": "Aumenta el dano del arco.",
|
||||
"iconsenhanced.desc.minecraft.thorns": "Refleja dano a atacantes.",
|
||||
"iconsenhanced.desc.minecraft.binding_curse": "Maldito: queda equipado.",
|
||||
"iconsenhanced.desc.minecraft.vanishing_curse": "Maldito: desaparece al morir."
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.7 KiB |
@@ -1,38 +1,26 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "template-mod",
|
||||
"version": "${version}",
|
||||
"name": "Template Mod",
|
||||
"description": "This is an example description! Tell everyone what your mod is about!",
|
||||
"authors": [
|
||||
"Me!"
|
||||
],
|
||||
"contact": {
|
||||
"homepage": "https://fabricmc.net/",
|
||||
"sources": "https://github.com/FabricMC/fabric-example-mod"
|
||||
},
|
||||
"license": "CC0-1.0",
|
||||
"icon": "assets/template-mod/icon.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"com.straice.TemplateMod"
|
||||
],
|
||||
"client": [
|
||||
"com.straice.TemplateModClient"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"template-mod.mixins.json",
|
||||
{
|
||||
"config": "template-mod.client.mixins.json",
|
||||
"environment": "client"
|
||||
}
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.18.4",
|
||||
"minecraft": "~1.21.11",
|
||||
"java": ">=21",
|
||||
"fabric-api": "*"
|
||||
}
|
||||
}
|
||||
"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"
|
||||
}
|
||||
|
||||
11
src/main/resources/iconsenhanced.mixins.json
Normal file
11
src/main/resources/iconsenhanced.mixins.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "dev.dekin.iconsenhanced.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"client": [
|
||||
"AbstractContainerScreenAccessor"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "com.straice.mixin",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"mixins": [
|
||||
"ExampleMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
"overwrites": {
|
||||
"requireAnnotations": true
|
||||
}
|
||||
}
|
||||
15
stonecutter.gradle
Normal file
15
stonecutter.gradle
Normal file
@@ -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") })
|
||||
}
|
||||
7
versions/1.20.1/gradle.properties
Normal file
7
versions/1.20.1/gradle.properties
Normal file
@@ -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
|
||||
7
versions/1.20.4/gradle.properties
Normal file
7
versions/1.20.4/gradle.properties
Normal file
@@ -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
|
||||
7
versions/1.20.6/gradle.properties
Normal file
7
versions/1.20.6/gradle.properties
Normal file
@@ -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
|
||||
7
versions/1.21.1/gradle.properties
Normal file
7
versions/1.21.1/gradle.properties
Normal file
@@ -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
|
||||
7
versions/1.21.11/gradle.properties
Normal file
7
versions/1.21.11/gradle.properties
Normal file
@@ -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
|
||||
7
versions/1.21.4/gradle.properties
Normal file
7
versions/1.21.4/gradle.properties
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user