From ef1bad99fde49385034a17761a0644eea9f761bb Mon Sep 17 00:00:00 2001 From: Pieter Date: Wed, 18 Feb 2026 21:29:54 +0100 Subject: [PATCH 1/9] Update version information in bug report template Updated version placeholders for mod and Minecraft. --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 6939294..0c30497 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,8 +8,8 @@ assignees: '' --- **Version** - - Mod Version [e.g. 1.21.1] - - Minecraft Version [e.g. 1.2.3] + - Mod Version [e.g. 1.1.0] + - Minecraft Version [e.g. 1.21.2] **Describe the bug** A clear and concise description of what the bug is. From f6c997960f0c6acb2156e534e651e03c1a671cdf Mon Sep 17 00:00:00 2001 From: Pieter Date: Sun, 5 Apr 2026 10:26:25 +0200 Subject: [PATCH 2/9] Implement text formatting utilities --- .../utilize/internal/models/TextCacheKey.java | 52 +++++++++++ .../utilize/internal/models/UIdentifier.java | 79 +++++++++++++++++ .../utilize/internal/utils/ColorUtils.java | 26 ++++++ .../java/nl/devpieter/utilize/text/IText.java | 21 +++++ .../text/formatter/ITextFormatter.java | 9 ++ .../text/formatter/TextFormatRegistry.java | 62 +++++++++++++ .../text/formatter/TextFormatUtils.java | 54 ++++++++++++ .../formatter/formats/HexColorFormatter.java | 23 +++++ .../formatter/formats/StyleFormatter.java | 29 +++++++ .../utilize/text/helpers/TextCacheHelper.java | 26 ++++++ .../text/helpers/TextDrawerHelper.java | 83 ++++++++++++++++++ .../utilize/text/texts/ItemStackText.java | 87 +++++++++++++++++++ .../utilize/text/texts/TextLine.java | 83 ++++++++++++++++++ .../utilize/text/texts/TextSpacer.java | 70 +++++++++++++++ 14 files changed, 704 insertions(+) create mode 100644 src/main/java/nl/devpieter/utilize/internal/models/TextCacheKey.java create mode 100644 src/main/java/nl/devpieter/utilize/internal/models/UIdentifier.java create mode 100644 src/main/java/nl/devpieter/utilize/internal/utils/ColorUtils.java create mode 100644 src/main/java/nl/devpieter/utilize/text/IText.java create mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/ITextFormatter.java create mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java create mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/TextFormatUtils.java create mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formats/HexColorFormatter.java create mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formats/StyleFormatter.java create mode 100644 src/main/java/nl/devpieter/utilize/text/helpers/TextCacheHelper.java create mode 100644 src/main/java/nl/devpieter/utilize/text/helpers/TextDrawerHelper.java create mode 100644 src/main/java/nl/devpieter/utilize/text/texts/ItemStackText.java create mode 100644 src/main/java/nl/devpieter/utilize/text/texts/TextLine.java create mode 100644 src/main/java/nl/devpieter/utilize/text/texts/TextSpacer.java diff --git a/src/main/java/nl/devpieter/utilize/internal/models/TextCacheKey.java b/src/main/java/nl/devpieter/utilize/internal/models/TextCacheKey.java new file mode 100644 index 0000000..6f98a06 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/internal/models/TextCacheKey.java @@ -0,0 +1,52 @@ +package nl.devpieter.utilize.internal.models; + +import net.minecraft.text.Style; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +@ApiStatus.Internal +public record TextCacheKey(String key, Style style, Object[] args) { + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + + TextCacheKey other = (TextCacheKey) obj; + if (!key.equals(other.key)) return false; + if (!style.equals(other.style)) return false; + if (args.length != other.args.length) return false; + + for (int i = 0; i < args.length; i++) { + if (!args[i].equals(other.args[i])) return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = key.hashCode(); + + result = 31 * result + style.hashCode(); + for (Object arg : args) result = 31 * result + arg.hashCode(); + + return result; + } + + @Override + public @NotNull String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("CacheKey{key='").append(key).append('\''); + sb.append(", style=").append(style); + sb.append(", args=["); + + for (int i = 0; i < args.length; i++) { + sb.append(args[i]); + if (i < args.length - 1) sb.append(", "); + } + + sb.append("]}"); + return sb.toString(); + } +} diff --git a/src/main/java/nl/devpieter/utilize/internal/models/UIdentifier.java b/src/main/java/nl/devpieter/utilize/internal/models/UIdentifier.java new file mode 100644 index 0000000..78357ce --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/internal/models/UIdentifier.java @@ -0,0 +1,79 @@ +package nl.devpieter.utilize.internal.models; + +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public class UIdentifier { + + public static final char NAMESPACE_SEPARATOR = Identifier.NAMESPACE_SEPARATOR; + + public static final String DEFAULT_NAMESPACE = "utilize"; + public static final String VANILLA_NAMESPACE = Identifier.DEFAULT_NAMESPACE; + + private final String namespace; + private final String path; + + private UIdentifier(String namespace, String path) { + assert (Identifier.isNamespaceValid(namespace)); + assert (Identifier.isPathValid(path)); + + this.namespace = namespace; + this.path = path; + } + + public Identifier toVanilla() { + return Identifier.of(namespace, path); + } + + public static UIdentifier toUtilize(Identifier identifier) { + return new UIdentifier(identifier.getNamespace(), identifier.getPath()); + } + + public static UIdentifier ofValidated(String namespace, String path) { + if (!Identifier.isNamespaceValid(namespace)) throw new IllegalArgumentException("Invalid namespace"); + if (!Identifier.isPathValid(path)) throw new IllegalArgumentException("Invalid path"); + + return new UIdentifier(namespace, path); + } + + public static UIdentifier of(String namespace, String path) { + return ofValidated(namespace, path); + } + + public static UIdentifier of(String namespacePath) { + String[] parts = namespacePath.split(String.valueOf(NAMESPACE_SEPARATOR), 2); + if (parts.length != 2) throw new IllegalArgumentException("Invalid identifier format"); + + return ofValidated(parts[0], parts[1]); + } + + public static UIdentifier ofVanilla(String path) { + if (!Identifier.isPathValid(path)) throw new IllegalArgumentException("Invalid path"); + return new UIdentifier(VANILLA_NAMESPACE, path); + } + + public static UIdentifier ofUtilize(String path) { + if (!Identifier.isPathValid(path)) throw new IllegalArgumentException("Invalid path"); + return new UIdentifier(DEFAULT_NAMESPACE, path); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + + UIdentifier other = (UIdentifier) obj; + return namespace.equals(other.namespace) && path.equals(other.path); + } + + @Override + public int hashCode() { + return namespace.hashCode() * 31 + path.hashCode(); + } + + @Override + public String toString() { + return namespace + NAMESPACE_SEPARATOR + path; + } +} diff --git a/src/main/java/nl/devpieter/utilize/internal/utils/ColorUtils.java b/src/main/java/nl/devpieter/utilize/internal/utils/ColorUtils.java new file mode 100644 index 0000000..bb1e76d --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/internal/utils/ColorUtils.java @@ -0,0 +1,26 @@ +package nl.devpieter.utilize.internal.utils; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +@ApiStatus.Internal +public class ColorUtils { + + public static int parseHexColor(@NotNull String hex) { + if (hex.startsWith("#")) hex = hex.substring(1); + + if (hex.length() == 3) { + char r = hex.charAt(0); + char g = hex.charAt(1); + char b = hex.charAt(2); + hex = "" + r + r + g + g + b + b; + } + + return Integer.parseInt(hex, 16); + } + + public static boolean isValidHexColor(@NotNull String hex) { + if (hex.startsWith("#")) hex = hex.substring(1); + return hex.matches("^[0-9a-fA-F]{3}$") || hex.matches("^[0-9a-fA-F]{6}$"); + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/IText.java b/src/main/java/nl/devpieter/utilize/text/IText.java new file mode 100644 index 0000000..33525b5 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/IText.java @@ -0,0 +1,21 @@ +package nl.devpieter.utilize.text; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; + +public interface IText { + + Text text(); + + void render(@NotNull DrawContext context, @NotNull TextRenderer textRenderer, int x, int y); + + default int width(@NotNull TextRenderer textRenderer) { + return textRenderer.getWidth(text()); + } + + default int height(@NotNull TextRenderer textRenderer) { + return textRenderer.fontHeight; + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/ITextFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/ITextFormatter.java new file mode 100644 index 0000000..a8c4be1 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/formatter/ITextFormatter.java @@ -0,0 +1,9 @@ +package nl.devpieter.utilize.text.formatter; + +import net.minecraft.text.MutableText; +import net.minecraft.text.Style; + +public interface ITextFormatter { + + MutableText format(String content, Style baseStyle); +} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java b/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java new file mode 100644 index 0000000..cafc344 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java @@ -0,0 +1,62 @@ +package nl.devpieter.utilize.text.formatter; + +import nl.devpieter.utilize.internal.models.UIdentifier; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +public class TextFormatRegistry { + + private static final TextFormatRegistry INSTANCE = new TextFormatRegistry(); + + private final HashMap formatters = new HashMap<>(); + + private Pattern pattern; + private boolean isDirty = true; + + private TextFormatRegistry() { + } + + public static TextFormatRegistry getInstance() { + return INSTANCE; + } + + public void register(@NotNull String namespace, @NotNull String path, @NotNull ITextFormatter formatter) { + register(UIdentifier.of(namespace, path), formatter); + } + + public void register(@NotNull UIdentifier identifier, @NotNull ITextFormatter formatter) { + formatters.put(identifier, formatter); + isDirty = true; + } + + public @Nullable ITextFormatter getFormatter(@Nullable UIdentifier identifier) { + if (identifier == null) return null; + return formatters.get(identifier); + } + + public @Nullable ITextFormatter getFormatter(String namespacePath) { + try { + return getFormatter(UIdentifier.of(namespacePath)); + } catch (IllegalArgumentException e) { + return null; + } + } + + public Map getFormatters() { + return new HashMap<>(formatters); + } + + public Pattern getPattern() { + if (!isDirty && pattern != null) return pattern; + + String tagAlternatives = formatters.keySet().stream().map(identifier -> Pattern.quote(identifier.toString())).collect(java.util.stream.Collectors.joining("|")); + pattern = Pattern.compile("<(#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6}|" + tagAlternatives + ")>(.*?)", Pattern.DOTALL); + + isDirty = false; + return pattern; + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatUtils.java b/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatUtils.java new file mode 100644 index 0000000..4c2eccd --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatUtils.java @@ -0,0 +1,54 @@ +package nl.devpieter.utilize.text.formatter; + +import net.minecraft.text.MutableText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import nl.devpieter.utilize.internal.utils.ColorUtils; +import nl.devpieter.utilize.text.formatter.formats.HexColorFormatter; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TextFormatUtils { + + private static final TextFormatRegistry REGISTRY = TextFormatRegistry.getInstance(); + + private TextFormatUtils() { + } + + public static MutableText format(String key, Style style, Object... args) { + String raw = Text.translatable(key, args).getString(); + + Pattern pattern = REGISTRY.getPattern(); + MutableText result = Text.empty(); + + int lastIndex = 0; + Matcher matcher = pattern.matcher(raw); + + while (matcher.find()) { + if (matcher.start() < lastIndex) continue; + + if (matcher.start() > lastIndex) { + result.append(Text.literal(raw.substring(lastIndex, matcher.start())).setStyle(style)); + } + + String tag = matcher.group(1); + String content = matcher.group(2); + + ITextFormatter formatter = REGISTRY.getFormatter(tag); + + if (formatter == null + && tag.startsWith("#") + && ColorUtils.isValidHexColor(tag) + ) formatter = new HexColorFormatter(tag); + + if (formatter != null) result.append(formatter.format(content, style)); + else result.append(Text.literal(matcher.group(0)).setStyle(style)); + + lastIndex = matcher.end(); + } + + if (lastIndex < raw.length()) result.append(Text.literal(raw.substring(lastIndex)).setStyle(style)); + return result; + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formats/HexColorFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formats/HexColorFormatter.java new file mode 100644 index 0000000..fa2c128 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/formatter/formats/HexColorFormatter.java @@ -0,0 +1,23 @@ +package nl.devpieter.utilize.text.formatter.formats; + +import net.minecraft.text.MutableText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.text.TextColor; +import nl.devpieter.utilize.text.formatter.ITextFormatter; +import nl.devpieter.utilize.internal.utils.ColorUtils; +import org.jetbrains.annotations.NotNull; + +public class HexColorFormatter implements ITextFormatter { + + private final TextColor color; + + public HexColorFormatter(@NotNull String hex) { + this.color = TextColor.fromRgb(ColorUtils.parseHexColor(hex)); + } + + @Override + public MutableText format(String content, Style baseStyle) { + return Text.literal(content).setStyle(baseStyle.withColor(color)); + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formats/StyleFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formats/StyleFormatter.java new file mode 100644 index 0000000..966fc73 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/formatter/formats/StyleFormatter.java @@ -0,0 +1,29 @@ +package nl.devpieter.utilize.text.formatter.formats; + +import net.minecraft.text.MutableText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.text.TextColor; +import nl.devpieter.utilize.text.formatter.ITextFormatter; + +public class StyleFormatter implements ITextFormatter { + + private final Style style; + + public StyleFormatter(Style style) { + this.style = style; + } + + public StyleFormatter(TextColor color) { + this(Style.EMPTY.withColor(color)); + } + + public StyleFormatter(int rgbColor) { + this(Style.EMPTY.withColor(rgbColor)); + } + + @Override + public MutableText format(String content, Style baseStyle) { + return Text.literal(content).setStyle(style); + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/helpers/TextCacheHelper.java b/src/main/java/nl/devpieter/utilize/text/helpers/TextCacheHelper.java new file mode 100644 index 0000000..a8b4b7b --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/helpers/TextCacheHelper.java @@ -0,0 +1,26 @@ +package nl.devpieter.utilize.text.helpers; + +import net.minecraft.text.MutableText; +import net.minecraft.text.Style; +import nl.devpieter.utilize.internal.models.TextCacheKey; +import nl.devpieter.utilize.text.formatter.TextFormatUtils; + +import java.util.HashMap; + +public class TextCacheHelper { + + private final HashMap cache = new HashMap<>(); + + public void clear() { + cache.clear(); + } + + public boolean contains(String key, Style style, Object... args) { + return cache.containsKey(new TextCacheKey(key, style, args)); + } + + public MutableText getFormatted(String key, Style style, Object... args) { + TextCacheKey cacheKey = new TextCacheKey(key, style, args); + return cache.computeIfAbsent(cacheKey, k -> TextFormatUtils.format(k.key(), k.style(), k.args())); + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/helpers/TextDrawerHelper.java b/src/main/java/nl/devpieter/utilize/text/helpers/TextDrawerHelper.java new file mode 100644 index 0000000..18b9ea2 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/helpers/TextDrawerHelper.java @@ -0,0 +1,83 @@ +package nl.devpieter.utilize.text.helpers; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.text.Text; +import nl.devpieter.utilize.text.IText; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class TextDrawerHelper { + + public void drawDynamicBox(@NotNull DrawContext context, @NotNull TextRenderer textRenderer, int x, int y, int color, List lines) { + drawDynamicBox(context, textRenderer, x, y, color, null, lines); + } + + public void drawDynamicBox(@NotNull DrawContext context, @NotNull TextRenderer textRenderer, int x, int y, int color, @Nullable Text title, List lines) { + int titleHeight = title != null ? textRenderer.fontHeight + 8 : 0; + int boxPadding = 10; + + int boxWidth = calculateBoxWidth(textRenderer, title, lines); + int boxHeight = calculateBoxHeight(textRenderer, title, lines); + + // Draw background + context.fill(x, y, x + boxWidth, y + boxHeight, color); + + int textX = x + boxPadding; + int textY = y + boxPadding; + + // Draw title + if (title != null) { + context.drawTextWithShadow(textRenderer, title, textX, textY, 0xFFFFFFFF); + textY += titleHeight; + } + + // Draw lines + for (IText line : lines) { + line.render(context, textRenderer, textX, textY); + textY += line.height(textRenderer); + } + } + + public int getLargestLineWidth(@NotNull TextRenderer textRenderer, List lines) { + return getLargestLineWidth(textRenderer, null, lines); + } + + public int getLargestLineWidth(@NotNull TextRenderer textRenderer, @Nullable Text title, List lines) { + int largestTextWidth = 0; + if (title != null) largestTextWidth = textRenderer.getWidth(title); + + for (IText line : lines) { + int lineWidth = line.width(textRenderer); + if (lineWidth > largestTextWidth) largestTextWidth = lineWidth; + } + + return largestTextWidth; + } + + public int calculateBoxWidth(@NotNull TextRenderer textRenderer, List lines) { + return calculateBoxWidth(textRenderer, null, lines); + } + + public int calculateBoxWidth(@NotNull TextRenderer textRenderer, @Nullable Text title, List lines) { + int largestTextWidth = getLargestLineWidth(textRenderer, title, lines); + + int boxPadding = 10; + return largestTextWidth + (boxPadding * 2); + } + + public int calculateBoxHeight(@NotNull TextRenderer textRenderer, List lines) { + return calculateBoxHeight(textRenderer, null, lines); + } + + public int calculateBoxHeight(@NotNull TextRenderer textRenderer, @Nullable Text title, List lines) { + int boxHeight = 0; + for (IText line : lines) boxHeight += line.height(textRenderer); + + int titleHeight = title != null ? textRenderer.fontHeight + 8 : 0; + int boxPadding = 10; + return boxHeight + titleHeight + (boxPadding * 2) - 4; + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/texts/ItemStackText.java b/src/main/java/nl/devpieter/utilize/text/texts/ItemStackText.java new file mode 100644 index 0000000..4d31ea0 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/texts/ItemStackText.java @@ -0,0 +1,87 @@ +package nl.devpieter.utilize.text.texts; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.item.ItemStack; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import nl.devpieter.utilize.text.IText; +import nl.devpieter.utilize.text.formatter.TextFormatUtils; +import nl.devpieter.utilize.text.helpers.TextCacheHelper; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ItemStackText implements IText { + + public static ItemStackText of(ItemStack stack, Text text) { + return new ItemStackText(stack, text); + } + + public static ItemStackText of(ItemStack stack, String text) { + return new ItemStackText(stack, Text.of(text)); + } + + public static ItemStackText off(ItemStack stack, String key, Style style, Object... args) { + return off(null, stack, key, style, args); + } + + public static ItemStackText off(@Nullable TextCacheHelper cache, ItemStack stack, String key, Style style, Object... args) { + if (cache == null) return new ItemStackText(stack, TextFormatUtils.format(key, style, args)); + return new ItemStackText(stack, cache.getFormatted(key, style, args)); + } + + private final ItemStack stack; + private final Text text; + + private int xPadding; + private int yPadding; + + public ItemStackText(ItemStack stack, Text text) { + this.stack = stack; + this.text = text; + + this.xPadding = 0; + this.yPadding = 4; + } + + @Override + public Text text() { + return text; + } + + public ItemStack stack() { + return stack; + } + + @Override + public void render(@NotNull DrawContext context, @NotNull TextRenderer textRenderer, int x, int y) { + context.drawItem(stack(), x - 4, y - 4); + context.drawTextWithShadow(textRenderer, text(), x + 14, y + 2, 0xFFFFFFFF); + } + + @Override + public int width(@NotNull TextRenderer textRenderer) { + return IText.super.width(textRenderer) + 14 + xPadding; + } + + @Override + public int height(@NotNull TextRenderer textRenderer) { + return IText.super.height(textRenderer) + 2 + yPadding; + } + + public ItemStackText padding(int xPadding, int yPadding) { + this.xPadding = xPadding; + this.yPadding = yPadding; + return this; + } + + public ItemStackText xPadding(int xPadding) { + this.xPadding = xPadding; + return this; + } + + public ItemStackText yPadding(int yPadding) { + this.yPadding = yPadding; + return this; + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/texts/TextLine.java b/src/main/java/nl/devpieter/utilize/text/texts/TextLine.java new file mode 100644 index 0000000..96bc4b1 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/texts/TextLine.java @@ -0,0 +1,83 @@ +package nl.devpieter.utilize.text.texts; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import nl.devpieter.utilize.text.IText; +import nl.devpieter.utilize.text.formatter.TextFormatUtils; +import nl.devpieter.utilize.text.helpers.TextCacheHelper; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class TextLine implements IText { + + public static TextLine of(Text text) { + return new TextLine(text); + } + + public static TextLine of(String text) { + return TextLine.of(Text.of(text)); + } + + public static TextLine off(String key, Style style, Object... args) { + return off(null, key, style, args); + } + + public static TextLine off(@Nullable TextCacheHelper cache, String key, Style style, Object... args) { + if (cache == null) return TextLine.of(TextFormatUtils.format(key, style, args)); + return TextLine.of(cache.getFormatted(key, style, args)); + } + + public static TextLine empty() { + return TextLine.of(Text.empty()); + } + + private final Text text; + + private int xPadding; + private int yPadding; + + public TextLine(Text text) { + this.text = text; + + this.xPadding = 0; + this.yPadding = 4; + } + + @Override + public Text text() { + return text; + } + + @Override + public void render(@NotNull DrawContext context, @NotNull TextRenderer textRenderer, int x, int y) { + context.drawTextWithShadow(textRenderer, text(), x, y, 0xFFFFFFFF); + } + + @Override + public int width(@NotNull TextRenderer textRenderer) { + return IText.super.width(textRenderer) + xPadding; + } + + @Override + public int height(@NotNull TextRenderer textRenderer) { + return IText.super.height(textRenderer) + yPadding; + } + + public TextLine padding(int xPadding, int yPadding) { + this.xPadding = xPadding; + this.yPadding = yPadding; + return this; + } + + public TextLine xPadding(int xPadding) { + this.xPadding = xPadding; + return this; + } + + public TextLine yPadding(int yPadding) { + this.yPadding = yPadding; + return this; + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/texts/TextSpacer.java b/src/main/java/nl/devpieter/utilize/text/texts/TextSpacer.java new file mode 100644 index 0000000..ba24b13 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/texts/TextSpacer.java @@ -0,0 +1,70 @@ +package nl.devpieter.utilize.text.texts; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.text.Text; +import nl.devpieter.utilize.text.IText; +import org.jetbrains.annotations.NotNull; + +public class TextSpacer implements IText { + + public static TextSpacer of(int width, int height) { + return new TextSpacer(width, height); + } + + public static TextSpacer of(int height) { + return new TextSpacer(0, height); + } + + public static TextSpacer ofWidth(int width) { + return new TextSpacer(width, 0); + } + + public static TextSpacer ofHeight(int height) { + return new TextSpacer(0, height); + } + + private int width; + private int height; + + public TextSpacer(int width, int height) { + this.width = width; + this.height = height; + } + + @Override + public Text text() { + return Text.empty(); + } + + @Override + public void render(@NotNull DrawContext context, @NotNull TextRenderer textRenderer, int x, int y) { + context.drawTextWithShadow(textRenderer, text(), x, y, 0xFFFFFFFF); + } + + @Override + public int width(@NotNull TextRenderer textRenderer) { + return width; + } + + @Override + public int height(@NotNull TextRenderer textRenderer) { + return height; + } + + public TextSpacer dimensions(int width, int height) { + this.width = width; + this.height = height; + return this; + } + + public TextSpacer width(int width) { + this.width = width; + return this; + } + + public TextSpacer height(int height) { + this.height = height; + return this; + } +} From 96737194bf58b0aa6144bdc7268ea6b7631faae0 Mon Sep 17 00:00:00 2001 From: Pieter Date: Sun, 5 Apr 2026 11:11:21 +0200 Subject: [PATCH 3/9] Small refactor; Add default formats --- .../java/nl/devpieter/utilize/Utilize.java | 53 +++++++++++++++++++ .../utilize/internal/models/TextCacheKey.java | 44 +++++---------- .../{internal => }/models/UIdentifier.java | 45 +++++++++------- .../text/formatter/TextFormatRegistry.java | 6 ++- 4 files changed, 96 insertions(+), 52 deletions(-) rename src/main/java/nl/devpieter/utilize/{internal => }/models/UIdentifier.java (52%) diff --git a/src/main/java/nl/devpieter/utilize/Utilize.java b/src/main/java/nl/devpieter/utilize/Utilize.java index 82a703a..9313432 100644 --- a/src/main/java/nl/devpieter/utilize/Utilize.java +++ b/src/main/java/nl/devpieter/utilize/Utilize.java @@ -5,8 +5,11 @@ import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.minecraft.SharedConstants; +import net.minecraft.text.Style; import nl.devpieter.utilize.http.AsyncRequest; import nl.devpieter.utilize.setting.SettingManager; +import nl.devpieter.utilize.text.formatter.TextFormatRegistry; +import nl.devpieter.utilize.text.formatter.formats.StyleFormatter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,8 +33,58 @@ public void onInitializeClient() { AsyncRequest.shutdown(); }); + // https://minecraft.wiki/w/Formatting_codes + TextFormatRegistry formatRegistry = TextFormatRegistry.getInstance(); + formatRegistry.register("bold", new StyleFormatter(Style.EMPTY.withBold(true))); + formatRegistry.register("italic", new StyleFormatter(Style.EMPTY.withItalic(true))); + formatRegistry.register("underline", new StyleFormatter(Style.EMPTY.withUnderline(true))); + formatRegistry.register("strikethrough", new StyleFormatter(Style.EMPTY.withStrikethrough(true))); + formatRegistry.register("obfuscated", new StyleFormatter(Style.EMPTY.withObfuscated(true))); + formatRegistry.register("black", new StyleFormatter(0x000000)); + formatRegistry.register("dark_blue", new StyleFormatter(0x0000AA)); + formatRegistry.register("dark_green", new StyleFormatter(0x00AA00)); + formatRegistry.register("dark_aqua", new StyleFormatter(0x00AAAA)); + formatRegistry.register("dark_red", new StyleFormatter(0xAA0000)); + formatRegistry.register("dark_purple", new StyleFormatter(0xAA00AA)); + formatRegistry.register("gold", new StyleFormatter(0xFFAA00)); + formatRegistry.register("gray", new StyleFormatter(0xAAAAAA)); + formatRegistry.register("dark_gray", new StyleFormatter(0x555555)); + formatRegistry.register("blue", new StyleFormatter(0x5555FF)); + formatRegistry.register("green", new StyleFormatter(0x55FF55)); + formatRegistry.register("aqua", new StyleFormatter(0x55FFFF)); + formatRegistry.register("red", new StyleFormatter(0xFF5555)); + formatRegistry.register("light_purple", new StyleFormatter(0xFF55FF)); + formatRegistry.register("yellow", new StyleFormatter(0xFFFF55)); + formatRegistry.register("white", new StyleFormatter(0xFFFFFF)); +// formatRegistry.register("minecoin_gold", new StyleFormatter(0xDDD605)); +// formatRegistry.register("material_quartz", new StyleFormatter(0xE3D4D1)); +// formatRegistry.register("material_iron", new StyleFormatter(0xCECACA)); +// formatRegistry.register("material_netherite", new StyleFormatter(0x443A3B)); +// formatRegistry.register("material_redstone", new StyleFormatter(0x971607)); +// formatRegistry.register("material_copper", new StyleFormatter(0xB4684D)); +// formatRegistry.register("material_gold", new StyleFormatter(0xDEB12D)); +// formatRegistry.register("material_emerald", new StyleFormatter(0x47A036)); +// formatRegistry.register("material_diamond", new StyleFormatter(0x2CBAA8)); +// formatRegistry.register("material_lapis", new StyleFormatter(0x21497B)); +// formatRegistry.register("material_amethyst", new StyleFormatter(0x9A5CC6)); +// formatRegistry.register("material_resin", new StyleFormatter(0xEB7114)); + logger.info("Utilize initialized successfully! Version: {}", getUtilizeVersion()); isInitialized = true; + +// TextCacheHelper textCacheHelper = new TextCacheHelper(); +// +// ClientTickEvents.START_CLIENT_TICK.register(client -> { +// boolean isInGame = client.player != null && client.world != null; +// if (!isInGame) return; +// +// PlayerEntity player = client.player; +// String sneaking = player.isSneaking() ? "Yes" : "No"; +// +//// MutableText sneakingText = textCacheHelper.getFormatted("Sneaking: %s testing", Style.EMPTY, sneaking); +// MutableText sneakingText = textCacheHelper.getFormatted("Sneaking: %s testing", Style.EMPTY, sneaking); +// PlayerUtils.sendMessage(sneakingText, true); +// }); } /** diff --git a/src/main/java/nl/devpieter/utilize/internal/models/TextCacheKey.java b/src/main/java/nl/devpieter/utilize/internal/models/TextCacheKey.java index 6f98a06..6650523 100644 --- a/src/main/java/nl/devpieter/utilize/internal/models/TextCacheKey.java +++ b/src/main/java/nl/devpieter/utilize/internal/models/TextCacheKey.java @@ -4,49 +4,29 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; +import java.util.Objects; + @ApiStatus.Internal public record TextCacheKey(String key, Style style, Object[] args) { @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - - TextCacheKey other = (TextCacheKey) obj; - if (!key.equals(other.key)) return false; - if (!style.equals(other.style)) return false; - if (args.length != other.args.length) return false; - - for (int i = 0; i < args.length; i++) { - if (!args[i].equals(other.args[i])) return false; - } - - return true; + public boolean equals(Object o) { + if (!(o instanceof TextCacheKey(String key1, Style style1, Object[] args1))) return false; + return Objects.equals(key, key1) && Objects.equals(style, style1) && Objects.deepEquals(args, args1); } @Override public int hashCode() { - int result = key.hashCode(); - - result = 31 * result + style.hashCode(); - for (Object arg : args) result = 31 * result + arg.hashCode(); - - return result; + return Objects.hash(key, style, Arrays.hashCode(args)); } @Override public @NotNull String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("CacheKey{key='").append(key).append('\''); - sb.append(", style=").append(style); - sb.append(", args=["); - - for (int i = 0; i < args.length; i++) { - sb.append(args[i]); - if (i < args.length - 1) sb.append(", "); - } - - sb.append("]}"); - return sb.toString(); + return "TextCacheKey{" + + "key='" + key + '\'' + + ", style=" + style + + ", args=" + Arrays.toString(args) + + '}'; } } diff --git a/src/main/java/nl/devpieter/utilize/internal/models/UIdentifier.java b/src/main/java/nl/devpieter/utilize/models/UIdentifier.java similarity index 52% rename from src/main/java/nl/devpieter/utilize/internal/models/UIdentifier.java rename to src/main/java/nl/devpieter/utilize/models/UIdentifier.java index 78357ce..9c879ae 100644 --- a/src/main/java/nl/devpieter/utilize/internal/models/UIdentifier.java +++ b/src/main/java/nl/devpieter/utilize/models/UIdentifier.java @@ -1,7 +1,11 @@ -package nl.devpieter.utilize.internal.models; +package nl.devpieter.utilize.models; import net.minecraft.util.Identifier; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; @ApiStatus.Internal public class UIdentifier { @@ -11,18 +15,19 @@ public class UIdentifier { public static final String DEFAULT_NAMESPACE = "utilize"; public static final String VANILLA_NAMESPACE = Identifier.DEFAULT_NAMESPACE; - private final String namespace; - private final String path; + private final @Nullable String namespace; + private final @NotNull String path; - private UIdentifier(String namespace, String path) { - assert (Identifier.isNamespaceValid(namespace)); - assert (Identifier.isPathValid(path)); + private UIdentifier(@Nullable String namespace, @NotNull String path) { + assert namespace == null || Identifier.isNamespaceValid(namespace); + assert Identifier.isPathValid(path); this.namespace = namespace; this.path = path; } public Identifier toVanilla() { + if (namespace == null) return Identifier.of(DEFAULT_NAMESPACE, path); return Identifier.of(namespace, path); } @@ -30,22 +35,22 @@ public static UIdentifier toUtilize(Identifier identifier) { return new UIdentifier(identifier.getNamespace(), identifier.getPath()); } - public static UIdentifier ofValidated(String namespace, String path) { - if (!Identifier.isNamespaceValid(namespace)) throw new IllegalArgumentException("Invalid namespace"); + public static UIdentifier ofValidated(@Nullable String namespace, @NotNull String path) { + if (namespace != null && !Identifier.isNamespaceValid(namespace)) throw new IllegalArgumentException("Invalid namespace"); if (!Identifier.isPathValid(path)) throw new IllegalArgumentException("Invalid path"); return new UIdentifier(namespace, path); } - public static UIdentifier of(String namespace, String path) { + public static UIdentifier of(@Nullable String namespace, @NotNull String path) { return ofValidated(namespace, path); } public static UIdentifier of(String namespacePath) { String[] parts = namespacePath.split(String.valueOf(NAMESPACE_SEPARATOR), 2); - if (parts.length != 2) throw new IllegalArgumentException("Invalid identifier format"); - return ofValidated(parts[0], parts[1]); + if (parts.length == 1) return ofNoNamespace(parts[0]); + else return of(parts[0], parts[1]); } public static UIdentifier ofVanilla(String path) { @@ -58,22 +63,24 @@ public static UIdentifier ofUtilize(String path) { return new UIdentifier(DEFAULT_NAMESPACE, path); } - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; + public static UIdentifier ofNoNamespace(String path) { + if (!Identifier.isPathValid(path)) throw new IllegalArgumentException("Invalid path"); + return new UIdentifier(null, path); + } - UIdentifier other = (UIdentifier) obj; - return namespace.equals(other.namespace) && path.equals(other.path); + @Override + public boolean equals(Object o) { + if (!(o instanceof UIdentifier that)) return false; + return Objects.equals(namespace, that.namespace) && Objects.equals(path, that.path); } @Override public int hashCode() { - return namespace.hashCode() * 31 + path.hashCode(); + return Objects.hash(namespace, path); } @Override public String toString() { - return namespace + NAMESPACE_SEPARATOR + path; + return (namespace != null ? namespace + NAMESPACE_SEPARATOR : "") + path; } } diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java b/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java index cafc344..a58b473 100644 --- a/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java +++ b/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java @@ -1,6 +1,6 @@ package nl.devpieter.utilize.text.formatter; -import nl.devpieter.utilize.internal.models.UIdentifier; +import nl.devpieter.utilize.models.UIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,6 +28,10 @@ public void register(@NotNull String namespace, @NotNull String path, @NotNull I register(UIdentifier.of(namespace, path), formatter); } + public void register(@NotNull String namespacePath, @NotNull ITextFormatter formatter) { + register(UIdentifier.of(namespacePath), formatter); + } + public void register(@NotNull UIdentifier identifier, @NotNull ITextFormatter formatter) { formatters.put(identifier, formatter); isDirty = true; From 6af0148066520ce6c8b0b88250f87c0e2bc14e5d Mon Sep 17 00:00:00 2001 From: Pieter Date: Mon, 6 Apr 2026 11:07:28 +0200 Subject: [PATCH 4/9] Small refactor of packages; QoL --- src/main/java/nl/devpieter/utilize/models/UIdentifier.java | 2 -- .../utilize/text/formatter/{ => utils}/TextFormatUtils.java | 4 +++- .../nl/devpieter/utilize/text/helpers/TextCacheHelper.java | 2 +- .../java/nl/devpieter/utilize/text/texts/ItemStackText.java | 2 +- src/main/java/nl/devpieter/utilize/text/texts/TextLine.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) rename src/main/java/nl/devpieter/utilize/text/formatter/{ => utils}/TextFormatUtils.java (90%) diff --git a/src/main/java/nl/devpieter/utilize/models/UIdentifier.java b/src/main/java/nl/devpieter/utilize/models/UIdentifier.java index 9c879ae..e3ac253 100644 --- a/src/main/java/nl/devpieter/utilize/models/UIdentifier.java +++ b/src/main/java/nl/devpieter/utilize/models/UIdentifier.java @@ -1,13 +1,11 @@ package nl.devpieter.utilize.models; import net.minecraft.util.Identifier; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Objects; -@ApiStatus.Internal public class UIdentifier { public static final char NAMESPACE_SEPARATOR = Identifier.NAMESPACE_SEPARATOR; diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatUtils.java b/src/main/java/nl/devpieter/utilize/text/formatter/utils/TextFormatUtils.java similarity index 90% rename from src/main/java/nl/devpieter/utilize/text/formatter/TextFormatUtils.java rename to src/main/java/nl/devpieter/utilize/text/formatter/utils/TextFormatUtils.java index 4c2eccd..bdb924d 100644 --- a/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatUtils.java +++ b/src/main/java/nl/devpieter/utilize/text/formatter/utils/TextFormatUtils.java @@ -1,9 +1,11 @@ -package nl.devpieter.utilize.text.formatter; +package nl.devpieter.utilize.text.formatter.utils; import net.minecraft.text.MutableText; import net.minecraft.text.Style; import net.minecraft.text.Text; import nl.devpieter.utilize.internal.utils.ColorUtils; +import nl.devpieter.utilize.text.formatter.ITextFormatter; +import nl.devpieter.utilize.text.formatter.TextFormatRegistry; import nl.devpieter.utilize.text.formatter.formats.HexColorFormatter; import java.util.regex.Matcher; diff --git a/src/main/java/nl/devpieter/utilize/text/helpers/TextCacheHelper.java b/src/main/java/nl/devpieter/utilize/text/helpers/TextCacheHelper.java index a8b4b7b..1e44786 100644 --- a/src/main/java/nl/devpieter/utilize/text/helpers/TextCacheHelper.java +++ b/src/main/java/nl/devpieter/utilize/text/helpers/TextCacheHelper.java @@ -3,7 +3,7 @@ import net.minecraft.text.MutableText; import net.minecraft.text.Style; import nl.devpieter.utilize.internal.models.TextCacheKey; -import nl.devpieter.utilize.text.formatter.TextFormatUtils; +import nl.devpieter.utilize.text.formatter.utils.TextFormatUtils; import java.util.HashMap; diff --git a/src/main/java/nl/devpieter/utilize/text/texts/ItemStackText.java b/src/main/java/nl/devpieter/utilize/text/texts/ItemStackText.java index 4d31ea0..41e4a40 100644 --- a/src/main/java/nl/devpieter/utilize/text/texts/ItemStackText.java +++ b/src/main/java/nl/devpieter/utilize/text/texts/ItemStackText.java @@ -6,7 +6,7 @@ import net.minecraft.text.Style; import net.minecraft.text.Text; import nl.devpieter.utilize.text.IText; -import nl.devpieter.utilize.text.formatter.TextFormatUtils; +import nl.devpieter.utilize.text.formatter.utils.TextFormatUtils; import nl.devpieter.utilize.text.helpers.TextCacheHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/nl/devpieter/utilize/text/texts/TextLine.java b/src/main/java/nl/devpieter/utilize/text/texts/TextLine.java index 96bc4b1..b0f8377 100644 --- a/src/main/java/nl/devpieter/utilize/text/texts/TextLine.java +++ b/src/main/java/nl/devpieter/utilize/text/texts/TextLine.java @@ -5,7 +5,7 @@ import net.minecraft.text.Style; import net.minecraft.text.Text; import nl.devpieter.utilize.text.IText; -import nl.devpieter.utilize.text.formatter.TextFormatUtils; +import nl.devpieter.utilize.text.formatter.utils.TextFormatUtils; import nl.devpieter.utilize.text.helpers.TextCacheHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; From c8b615f4feee5a4f737d4861948f4b184457c455 Mon Sep 17 00:00:00 2001 From: Pieter Date: Mon, 6 Apr 2026 11:08:44 +0200 Subject: [PATCH 5/9] Bump mod version to 1.1.3 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 0b47489..efc21ad 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,6 +7,6 @@ loader_version=0.18.4 # Mod Properties artifact_id=utilize -mod_version=1.1.2 +mod_version=1.1.3 maven_group=nl.devpieter archives_base_name=Utilize From eb90bc5fd831d19dce4026cbe3cf53d47cb80130 Mon Sep 17 00:00:00 2001 From: Pieter Date: Mon, 6 Apr 2026 12:48:02 +0200 Subject: [PATCH 6/9] Refactor TextFormatUtils to work recursively --- .../java/nl/devpieter/utilize/Utilize.java | 72 +++++++++---------- .../text/formatter/ITextFormatter.java | 3 +- .../formatter/formats/StyleFormatter.java | 29 -------- .../formatters/color/ColorFormatter.java | 24 +++++++ .../color}/HexColorFormatter.java | 10 ++- .../formatters/format/BoldFormatter.java | 12 ++++ .../formatters/format/ItalicFormatter.java | 12 ++++ .../format/ObfuscatedFormatter.java | 12 ++++ .../format/StrikethroughFormatter.java | 12 ++++ .../formatters/format/UnderlineFormatter.java | 12 ++++ .../text/formatter/utils/TextFormatUtils.java | 24 +++++-- 11 files changed, 145 insertions(+), 77 deletions(-) delete mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formats/StyleFormatter.java create mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/ColorFormatter.java rename src/main/java/nl/devpieter/utilize/text/formatter/{formats => formatters/color}/HexColorFormatter.java (64%) create mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/BoldFormatter.java create mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ItalicFormatter.java create mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ObfuscatedFormatter.java create mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/StrikethroughFormatter.java create mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/UnderlineFormatter.java diff --git a/src/main/java/nl/devpieter/utilize/Utilize.java b/src/main/java/nl/devpieter/utilize/Utilize.java index 9313432..730bd80 100644 --- a/src/main/java/nl/devpieter/utilize/Utilize.java +++ b/src/main/java/nl/devpieter/utilize/Utilize.java @@ -5,11 +5,11 @@ import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.minecraft.SharedConstants; -import net.minecraft.text.Style; import nl.devpieter.utilize.http.AsyncRequest; import nl.devpieter.utilize.setting.SettingManager; import nl.devpieter.utilize.text.formatter.TextFormatRegistry; -import nl.devpieter.utilize.text.formatter.formats.StyleFormatter; +import nl.devpieter.utilize.text.formatter.formatters.color.ColorFormatter; +import nl.devpieter.utilize.text.formatter.formatters.format.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,39 +35,39 @@ public void onInitializeClient() { // https://minecraft.wiki/w/Formatting_codes TextFormatRegistry formatRegistry = TextFormatRegistry.getInstance(); - formatRegistry.register("bold", new StyleFormatter(Style.EMPTY.withBold(true))); - formatRegistry.register("italic", new StyleFormatter(Style.EMPTY.withItalic(true))); - formatRegistry.register("underline", new StyleFormatter(Style.EMPTY.withUnderline(true))); - formatRegistry.register("strikethrough", new StyleFormatter(Style.EMPTY.withStrikethrough(true))); - formatRegistry.register("obfuscated", new StyleFormatter(Style.EMPTY.withObfuscated(true))); - formatRegistry.register("black", new StyleFormatter(0x000000)); - formatRegistry.register("dark_blue", new StyleFormatter(0x0000AA)); - formatRegistry.register("dark_green", new StyleFormatter(0x00AA00)); - formatRegistry.register("dark_aqua", new StyleFormatter(0x00AAAA)); - formatRegistry.register("dark_red", new StyleFormatter(0xAA0000)); - formatRegistry.register("dark_purple", new StyleFormatter(0xAA00AA)); - formatRegistry.register("gold", new StyleFormatter(0xFFAA00)); - formatRegistry.register("gray", new StyleFormatter(0xAAAAAA)); - formatRegistry.register("dark_gray", new StyleFormatter(0x555555)); - formatRegistry.register("blue", new StyleFormatter(0x5555FF)); - formatRegistry.register("green", new StyleFormatter(0x55FF55)); - formatRegistry.register("aqua", new StyleFormatter(0x55FFFF)); - formatRegistry.register("red", new StyleFormatter(0xFF5555)); - formatRegistry.register("light_purple", new StyleFormatter(0xFF55FF)); - formatRegistry.register("yellow", new StyleFormatter(0xFFFF55)); - formatRegistry.register("white", new StyleFormatter(0xFFFFFF)); -// formatRegistry.register("minecoin_gold", new StyleFormatter(0xDDD605)); -// formatRegistry.register("material_quartz", new StyleFormatter(0xE3D4D1)); -// formatRegistry.register("material_iron", new StyleFormatter(0xCECACA)); -// formatRegistry.register("material_netherite", new StyleFormatter(0x443A3B)); -// formatRegistry.register("material_redstone", new StyleFormatter(0x971607)); -// formatRegistry.register("material_copper", new StyleFormatter(0xB4684D)); -// formatRegistry.register("material_gold", new StyleFormatter(0xDEB12D)); -// formatRegistry.register("material_emerald", new StyleFormatter(0x47A036)); -// formatRegistry.register("material_diamond", new StyleFormatter(0x2CBAA8)); -// formatRegistry.register("material_lapis", new StyleFormatter(0x21497B)); -// formatRegistry.register("material_amethyst", new StyleFormatter(0x9A5CC6)); -// formatRegistry.register("material_resin", new StyleFormatter(0xEB7114)); + formatRegistry.register("bold", new BoldFormatter()); + formatRegistry.register("italic", new ItalicFormatter()); + formatRegistry.register("underline", new UnderlineFormatter()); + formatRegistry.register("strikethrough", new StrikethroughFormatter()); + formatRegistry.register("obfuscated", new ObfuscatedFormatter()); + formatRegistry.register("black", new ColorFormatter(0x000000)); + formatRegistry.register("dark_blue", new ColorFormatter(0x0000AA)); + formatRegistry.register("dark_green", new ColorFormatter(0x00AA00)); + formatRegistry.register("dark_aqua", new ColorFormatter(0x00AAAA)); + formatRegistry.register("dark_red", new ColorFormatter(0xAA0000)); + formatRegistry.register("dark_purple", new ColorFormatter(0xAA00AA)); + formatRegistry.register("gold", new ColorFormatter(0xFFAA00)); + formatRegistry.register("gray", new ColorFormatter(0xAAAAAA)); + formatRegistry.register("dark_gray", new ColorFormatter(0x555555)); + formatRegistry.register("blue", new ColorFormatter(0x5555FF)); + formatRegistry.register("green", new ColorFormatter(0x55FF55)); + formatRegistry.register("aqua", new ColorFormatter(0x55FFFF)); + formatRegistry.register("red", new ColorFormatter(0xFF5555)); + formatRegistry.register("light_purple", new ColorFormatter(0xFF55FF)); + formatRegistry.register("yellow", new ColorFormatter(0xFFFF55)); + formatRegistry.register("white", new ColorFormatter(0xFFFFFF)); +// formatRegistry.register("minecoin_gold", new ColorFormatter(0xDDD605)); +// formatRegistry.register("material_quartz", new ColorFormatter(0xE3D4D1)); +// formatRegistry.register("material_iron", new ColorFormatter(0xCECACA)); +// formatRegistry.register("material_netherite", new ColorFormatter(0x443A3B)); +// formatRegistry.register("material_redstone", new ColorFormatter(0x971607)); +// formatRegistry.register("material_copper", new ColorFormatter(0xB4684D)); +// formatRegistry.register("material_gold", new ColorFormatter(0xDEB12D)); +// formatRegistry.register("material_emerald", new ColorFormatter(0x47A036)); +// formatRegistry.register("material_diamond", new ColorFormatter(0x2CBAA8)); +// formatRegistry.register("material_lapis", new ColorFormatter(0x21497B)); +// formatRegistry.register("material_amethyst", new ColorFormatter(0x9A5CC6)); +// formatRegistry.register("material_resin", new ColorFormatter(0xEB7114)); logger.info("Utilize initialized successfully! Version: {}", getUtilizeVersion()); isInitialized = true; @@ -82,7 +82,7 @@ public void onInitializeClient() { // String sneaking = player.isSneaking() ? "Yes" : "No"; // //// MutableText sneakingText = textCacheHelper.getFormatted("Sneaking: %s testing", Style.EMPTY, sneaking); -// MutableText sneakingText = textCacheHelper.getFormatted("Sneaking: %s testing", Style.EMPTY, sneaking); +// MutableText sneakingText = textCacheHelper.getFormatted("2 Sneaking: %s tt0 t0 t2 tt1 <#bda2f2>tt2", Style.EMPTY, sneaking); // PlayerUtils.sendMessage(sneakingText, true); // }); } diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/ITextFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/ITextFormatter.java index a8c4be1..c0652ea 100644 --- a/src/main/java/nl/devpieter/utilize/text/formatter/ITextFormatter.java +++ b/src/main/java/nl/devpieter/utilize/text/formatter/ITextFormatter.java @@ -1,9 +1,8 @@ package nl.devpieter.utilize.text.formatter; -import net.minecraft.text.MutableText; import net.minecraft.text.Style; public interface ITextFormatter { - MutableText format(String content, Style baseStyle); + Style applyFormatting(Style parent); } diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formats/StyleFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formats/StyleFormatter.java deleted file mode 100644 index 966fc73..0000000 --- a/src/main/java/nl/devpieter/utilize/text/formatter/formats/StyleFormatter.java +++ /dev/null @@ -1,29 +0,0 @@ -package nl.devpieter.utilize.text.formatter.formats; - -import net.minecraft.text.MutableText; -import net.minecraft.text.Style; -import net.minecraft.text.Text; -import net.minecraft.text.TextColor; -import nl.devpieter.utilize.text.formatter.ITextFormatter; - -public class StyleFormatter implements ITextFormatter { - - private final Style style; - - public StyleFormatter(Style style) { - this.style = style; - } - - public StyleFormatter(TextColor color) { - this(Style.EMPTY.withColor(color)); - } - - public StyleFormatter(int rgbColor) { - this(Style.EMPTY.withColor(rgbColor)); - } - - @Override - public MutableText format(String content, Style baseStyle) { - return Text.literal(content).setStyle(style); - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/ColorFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/ColorFormatter.java new file mode 100644 index 0000000..b2c5a24 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/ColorFormatter.java @@ -0,0 +1,24 @@ +package nl.devpieter.utilize.text.formatter.formatters.color; + +import net.minecraft.text.Style; +import net.minecraft.text.TextColor; +import nl.devpieter.utilize.text.formatter.ITextFormatter; +import org.jetbrains.annotations.NotNull; + +public class ColorFormatter implements ITextFormatter { + + private final TextColor color; + + public ColorFormatter(@NotNull TextColor color) { + this.color = color; + } + + public ColorFormatter(int rgb) { + this.color = TextColor.fromRgb(rgb); + } + + @Override + public Style applyFormatting(Style parent) { + return parent.withColor(color); + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formats/HexColorFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/HexColorFormatter.java similarity index 64% rename from src/main/java/nl/devpieter/utilize/text/formatter/formats/HexColorFormatter.java rename to src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/HexColorFormatter.java index fa2c128..edd23d9 100644 --- a/src/main/java/nl/devpieter/utilize/text/formatter/formats/HexColorFormatter.java +++ b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/HexColorFormatter.java @@ -1,11 +1,9 @@ -package nl.devpieter.utilize.text.formatter.formats; +package nl.devpieter.utilize.text.formatter.formatters.color; -import net.minecraft.text.MutableText; import net.minecraft.text.Style; -import net.minecraft.text.Text; import net.minecraft.text.TextColor; -import nl.devpieter.utilize.text.formatter.ITextFormatter; import nl.devpieter.utilize.internal.utils.ColorUtils; +import nl.devpieter.utilize.text.formatter.ITextFormatter; import org.jetbrains.annotations.NotNull; public class HexColorFormatter implements ITextFormatter { @@ -17,7 +15,7 @@ public HexColorFormatter(@NotNull String hex) { } @Override - public MutableText format(String content, Style baseStyle) { - return Text.literal(content).setStyle(baseStyle.withColor(color)); + public Style applyFormatting(Style parent) { + return parent.withColor(color); } } diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/BoldFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/BoldFormatter.java new file mode 100644 index 0000000..44e059e --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/BoldFormatter.java @@ -0,0 +1,12 @@ +package nl.devpieter.utilize.text.formatter.formatters.format; + +import net.minecraft.text.Style; +import nl.devpieter.utilize.text.formatter.ITextFormatter; + +public class BoldFormatter implements ITextFormatter { + + @Override + public Style applyFormatting(Style parent) { + return parent.withBold(true); + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ItalicFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ItalicFormatter.java new file mode 100644 index 0000000..e687aa2 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ItalicFormatter.java @@ -0,0 +1,12 @@ +package nl.devpieter.utilize.text.formatter.formatters.format; + +import net.minecraft.text.Style; +import nl.devpieter.utilize.text.formatter.ITextFormatter; + +public class ItalicFormatter implements ITextFormatter { + + @Override + public Style applyFormatting(Style parent) { + return parent.withItalic(true); + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ObfuscatedFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ObfuscatedFormatter.java new file mode 100644 index 0000000..fc9b65c --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ObfuscatedFormatter.java @@ -0,0 +1,12 @@ +package nl.devpieter.utilize.text.formatter.formatters.format; + +import net.minecraft.text.Style; +import nl.devpieter.utilize.text.formatter.ITextFormatter; + +public class ObfuscatedFormatter implements ITextFormatter { + + @Override + public Style applyFormatting(Style parent) { + return parent.withObfuscated(true); + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/StrikethroughFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/StrikethroughFormatter.java new file mode 100644 index 0000000..82ed9ad --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/StrikethroughFormatter.java @@ -0,0 +1,12 @@ +package nl.devpieter.utilize.text.formatter.formatters.format; + +import net.minecraft.text.Style; +import nl.devpieter.utilize.text.formatter.ITextFormatter; + +public class StrikethroughFormatter implements ITextFormatter { + + @Override + public Style applyFormatting(Style parent) { + return parent.withStrikethrough(true); + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/UnderlineFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/UnderlineFormatter.java new file mode 100644 index 0000000..4a82bd5 --- /dev/null +++ b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/UnderlineFormatter.java @@ -0,0 +1,12 @@ +package nl.devpieter.utilize.text.formatter.formatters.format; + +import net.minecraft.text.Style; +import nl.devpieter.utilize.text.formatter.ITextFormatter; + +public class UnderlineFormatter implements ITextFormatter { + + @Override + public Style applyFormatting(Style parent) { + return parent.withUnderline(true); + } +} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/utils/TextFormatUtils.java b/src/main/java/nl/devpieter/utilize/text/formatter/utils/TextFormatUtils.java index bdb924d..753540c 100644 --- a/src/main/java/nl/devpieter/utilize/text/formatter/utils/TextFormatUtils.java +++ b/src/main/java/nl/devpieter/utilize/text/formatter/utils/TextFormatUtils.java @@ -6,7 +6,7 @@ import nl.devpieter.utilize.internal.utils.ColorUtils; import nl.devpieter.utilize.text.formatter.ITextFormatter; import nl.devpieter.utilize.text.formatter.TextFormatRegistry; -import nl.devpieter.utilize.text.formatter.formats.HexColorFormatter; +import nl.devpieter.utilize.text.formatter.formatters.color.HexColorFormatter; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -20,6 +20,16 @@ private TextFormatUtils() { public static MutableText format(String key, Style style, Object... args) { String raw = Text.translatable(key, args).getString(); + return formatRecursive(raw, style, 0, 20); + } + + public static MutableText formatWithDepth(String key, Style style, int maxDepth, Object... args) { + String raw = Text.translatable(key, args).getString(); + return formatRecursive(raw, style, 0, maxDepth); + } + + private static MutableText formatRecursive(String raw, Style style, int depth, int maxDepth) { + if (depth > maxDepth) return Text.literal(raw).setStyle(style); Pattern pattern = REGISTRY.getPattern(); MutableText result = Text.empty(); @@ -44,13 +54,19 @@ public static MutableText format(String key, Style style, Object... args) { && ColorUtils.isValidHexColor(tag) ) formatter = new HexColorFormatter(tag); - if (formatter != null) result.append(formatter.format(content, style)); - else result.append(Text.literal(matcher.group(0)).setStyle(style)); + if (formatter != null) { + result.append(formatRecursive(content, formatter.applyFormatting(style), depth + 1, maxDepth)); + } else { + result.append(Text.literal(matcher.group(0)).setStyle(style)); + } lastIndex = matcher.end(); } - if (lastIndex < raw.length()) result.append(Text.literal(raw.substring(lastIndex)).setStyle(style)); + if (lastIndex < raw.length()) { + result.append(Text.literal(raw.substring(lastIndex)).setStyle(style)); + } + return result; } } From d10109a0e67439be368022a7d0667729b5e728cd Mon Sep 17 00:00:00 2001 From: Pieter Date: Mon, 6 Apr 2026 12:51:22 +0200 Subject: [PATCH 7/9] Fix missing import --- .../devpieter/utilize/text/formatter/TextFormatRegistry.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java b/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java index a58b473..651e866 100644 --- a/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java +++ b/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class TextFormatRegistry { @@ -57,7 +58,7 @@ public Map getFormatters() { public Pattern getPattern() { if (!isDirty && pattern != null) return pattern; - String tagAlternatives = formatters.keySet().stream().map(identifier -> Pattern.quote(identifier.toString())).collect(java.util.stream.Collectors.joining("|")); + String tagAlternatives = formatters.keySet().stream().map(identifier -> Pattern.quote(identifier.toString())).collect(Collectors.joining("|")); pattern = Pattern.compile("<(#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6}|" + tagAlternatives + ")>(.*?)", Pattern.DOTALL); isDirty = false; From b50827ccd3e735259181ef4f4ac285ac6cbddf86 Mon Sep 17 00:00:00 2001 From: Pieter Date: Thu, 6 Aug 2026 15:27:11 +0200 Subject: [PATCH 8/9] v2 26.x --- LICENSE.txt | 2 +- build.gradle | 63 +++++-- gradle.properties | 7 +- gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 48462 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 18 +- gradlew.bat | 36 ++-- root.gradle | 14 +- settings.gradle | 12 +- .../utilize/client/UtilizeClient.java | 56 ++++++ .../client}/enums/KeyActionOverride.java | 2 +- .../keybinding/AttackKeyPressedEvent.java | 2 +- .../KeyBindingPressedCheckEvent.java | 4 +- .../keybinding/KeyBindingPressedEvent.java | 4 +- .../keybinding/UseKeyPressedEvent.java | 2 +- .../events/player/PlayerDamagedEvent.java | 2 +- .../events/player/PlayerHealedEvent.java | 2 +- .../events/tick/ClientPlayerTickEvent.java | 2 +- .../tick/ClientPlayerTickTailEvent.java | 2 +- .../client}/events/tick/ClientTickEvent.java | 2 +- .../events/tick/ClientTickTailEvent.java | 2 +- .../client}/events/tick/ITickEvent.java | 2 +- .../client}/managers/DamageManager.java | 6 +- .../client/mixin/KeyMappingMixin.java} | 40 ++-- .../client/mixin/LocalPlayerMixin.java} | 29 +-- .../utilize/client/mixin/MinecraftMixin.java} | 44 ++--- .../utilize/client}/setting/KeyedSetting.java | 2 +- .../client}/setting/SettingManager.java | 4 +- .../client}/setting/base/SettingBase.java | 4 +- .../setting/interfaces/IBooleanSetting.java | 2 +- .../setting/interfaces/IListSetting.java | 2 +- .../setting/interfaces/IMapSetting.java | 2 +- .../setting/interfaces/INumberSetting.java | 2 +- .../interfaces/IPolymorphicSetting.java | 4 +- .../client}/setting/interfaces/ISetting.java | 4 +- .../setting/interfaces/IStringSetting.java | 2 +- .../setting}/models/PolymorphicValue.java | 2 +- .../setting/settings/BooleanSetting.java | 6 +- .../setting/settings/FloatSetting.java | 6 +- .../client}/setting/settings/IntSetting.java | 6 +- .../client}/setting/settings/ListSetting.java | 6 +- .../client}/setting/settings/MapSetting.java | 6 +- .../setting/settings/StringSetting.java | 6 +- .../devpieter/utilize/client/task/ITask.java | 8 + .../utilize/client/task/TaskEntry.java | 6 + .../utilize/client}/task/TaskManager.java | 21 +-- .../utilize/client/task/enums/TickPhase.java | 8 + .../utilize/client/task/enums/TickResult.java | 7 + .../client}/task/tasks/RunLaterTask.java | 14 +- .../resources/utilize.client.mixins.json | 19 ++ .../java/nl/devpieter/utilize/Utilize.java | 71 +------ .../events/chat/ReceiveMessageEvent.java | 28 --- .../UpdateBlockBreakingProgressEvent.java | 24 --- .../interaction/block/AttackBlockEvent.java | 28 --- .../block/AttackBlockReturnEvent.java | 36 ---- .../block/AttackBlockTailEvent.java | 8 - .../interaction/block/BreakBlockEvent.java | 21 --- .../block/BreakBlockReturnEvent.java | 30 --- .../block/BreakBlockTailEvent.java | 7 - .../interaction/block/InteractBlockEvent.java | 28 --- .../block/InteractBlockReturnEvent.java | 37 ---- .../block/InteractBlockTailEvent.java | 8 - .../interaction/entity/AttackEntityEvent.java | 21 --- .../entity/AttackEntityReturnEvent.java | 7 - .../entity/AttackEntityTailEvent.java | 7 - .../entity/InteractEntityEvent.java | 28 --- .../entity/InteractEntityReturnEvent.java | 37 ---- .../entity/InteractEntityTailEvent.java | 8 - .../interaction/item/InteractItemEvent.java | 21 --- .../item/InteractItemReturnEvent.java | 30 --- .../item/InteractItemTailEvent.java | 8 - .../inventory/HotbarSlotChangedEvent.java | 6 - .../events/inventory/SlotClickEvent.java | 35 ---- .../events/screen/ScreenChangedEvent.java | 8 - .../devpieter/utilize/http/AsyncRequest.java | 80 -------- .../devpieter/utilize/http/RequestHelper.java | 52 ------ .../utilize/http/ResultConsumer.java | 8 - .../utilize/internal/models/TextCacheKey.java | 32 ---- .../utilize/internal/utils/ColorUtils.java | 26 --- .../utilize/managers/PacketManager.java | 4 +- .../ConnectionMixin.java} | 14 +- .../utilize/mixins/ChatHudMixin.java | 56 ------ .../ClientPlayerInteractionManagerMixin.java | 173 ------------------ .../devpieter/utilize/mixins/SeesMixin.java | 32 ---- .../devpieter/utilize/models/UIdentifier.java | 84 --------- .../packet/IPacketListener.java | 4 +- .../utilize/task/interfaces/ITask.java | 8 - .../java/nl/devpieter/utilize/text/IText.java | 21 --- .../text/formatter/ITextFormatter.java | 8 - .../text/formatter/TextFormatRegistry.java | 67 ------- .../formatters/color/ColorFormatter.java | 24 --- .../formatters/color/HexColorFormatter.java | 21 --- .../formatters/format/BoldFormatter.java | 12 -- .../formatters/format/ItalicFormatter.java | 12 -- .../format/ObfuscatedFormatter.java | 12 -- .../format/StrikethroughFormatter.java | 12 -- .../formatters/format/UnderlineFormatter.java | 12 -- .../text/formatter/utils/TextFormatUtils.java | 72 -------- .../utilize/text/helpers/TextCacheHelper.java | 26 --- .../text/helpers/TextDrawerHelper.java | 83 --------- .../utilize/text/texts/ItemStackText.java | 87 --------- .../utilize/text/texts/TextLine.java | 83 --------- .../utilize/text/texts/TextSpacer.java | 70 ------- .../utilize/utils/common/MathUtils.java | 15 -- .../utilize/utils/minecraft/ClientUtils.java | 63 ------- .../utils/minecraft/EnchantmentUtils.java | 70 ------- .../utils/minecraft/InteractionUtils.java | 14 -- .../utils/minecraft/InventoryUtils.java | 99 ---------- .../utilize/utils/minecraft/NetworkUtils.java | 29 --- .../utilize/utils/minecraft/PlayerUtils.java | 52 ------ .../utilize/utils/minecraft/SoundUtils.java | 29 --- .../utilize/utils/minecraft/TextUtils.java | 32 ---- .../utilize/utils/minecraft/WorldUtils.java | 50 ----- src/main/resources/fabric.mod.json | 34 ++-- src/main/resources/utilize.mixins.json | 19 +- versions/1.21.9/gradle.properties | 6 - versions/26.1/gradle.properties | 4 + versions/mainProject | 2 +- 118 files changed, 334 insertions(+), 2429 deletions(-) create mode 100644 src/client/java/nl/devpieter/utilize/client/UtilizeClient.java rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/enums/KeyActionOverride.java (65%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/events/interaction/keybinding/AttackKeyPressedEvent.java (64%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/events/interaction/keybinding/KeyBindingPressedCheckEvent.java (83%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/events/interaction/keybinding/KeyBindingPressedEvent.java (83%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/events/interaction/keybinding/UseKeyPressedEvent.java (64%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/events/player/PlayerDamagedEvent.java (71%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/events/player/PlayerHealedEvent.java (70%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/events/tick/ClientPlayerTickEvent.java (57%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/events/tick/ClientPlayerTickTailEvent.java (58%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/events/tick/ClientTickEvent.java (54%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/events/tick/ClientTickTailEvent.java (56%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/events/tick/ITickEvent.java (64%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/managers/DamageManager.java (84%) rename src/{main/java/nl/devpieter/utilize/mixins/KeyBindingMixin.java => client/java/nl/devpieter/utilize/client/mixin/KeyMappingMixin.java} (63%) rename src/{main/java/nl/devpieter/utilize/mixins/ClientPlayerEntityMixin.java => client/java/nl/devpieter/utilize/client/mixin/LocalPlayerMixin.java} (53%) rename src/{main/java/nl/devpieter/utilize/mixins/MinecraftClientMixin.java => client/java/nl/devpieter/utilize/client/mixin/MinecraftMixin.java} (53%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/KeyedSetting.java (55%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/SettingManager.java (98%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/base/SettingBase.java (91%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/interfaces/IBooleanSetting.java (81%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/interfaces/IListSetting.java (82%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/interfaces/IMapSetting.java (81%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/interfaces/INumberSetting.java (76%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/interfaces/IPolymorphicSetting.java (69%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/interfaces/ISetting.java (85%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/interfaces/IStringSetting.java (75%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client/setting}/models/PolymorphicValue.java (94%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/settings/BooleanSetting.java (80%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/settings/FloatSetting.java (89%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/settings/IntSetting.java (89%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/settings/ListSetting.java (92%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/settings/MapSetting.java (90%) rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/setting/settings/StringSetting.java (65%) create mode 100644 src/client/java/nl/devpieter/utilize/client/task/ITask.java create mode 100644 src/client/java/nl/devpieter/utilize/client/task/TaskEntry.java rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/task/TaskManager.java (84%) create mode 100644 src/client/java/nl/devpieter/utilize/client/task/enums/TickPhase.java create mode 100644 src/client/java/nl/devpieter/utilize/client/task/enums/TickResult.java rename src/{main/java/nl/devpieter/utilize => client/java/nl/devpieter/utilize/client}/task/tasks/RunLaterTask.java (69%) create mode 100644 src/client/resources/utilize.client.mixins.json delete mode 100644 src/main/java/nl/devpieter/utilize/events/chat/ReceiveMessageEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/UpdateBlockBreakingProgressEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/block/AttackBlockEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/block/AttackBlockReturnEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/block/AttackBlockTailEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/block/BreakBlockEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/block/BreakBlockReturnEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/block/BreakBlockTailEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/block/InteractBlockEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/block/InteractBlockReturnEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/block/InteractBlockTailEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/entity/AttackEntityEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/entity/AttackEntityReturnEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/entity/AttackEntityTailEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/entity/InteractEntityEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/entity/InteractEntityReturnEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/entity/InteractEntityTailEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/item/InteractItemEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/item/InteractItemReturnEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/interaction/item/InteractItemTailEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/inventory/HotbarSlotChangedEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/inventory/SlotClickEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/events/screen/ScreenChangedEvent.java delete mode 100644 src/main/java/nl/devpieter/utilize/http/AsyncRequest.java delete mode 100644 src/main/java/nl/devpieter/utilize/http/RequestHelper.java delete mode 100644 src/main/java/nl/devpieter/utilize/http/ResultConsumer.java delete mode 100644 src/main/java/nl/devpieter/utilize/internal/models/TextCacheKey.java delete mode 100644 src/main/java/nl/devpieter/utilize/internal/utils/ColorUtils.java rename src/main/java/nl/devpieter/utilize/{mixins/ClientConnectionMixin.java => mixin/ConnectionMixin.java} (65%) delete mode 100644 src/main/java/nl/devpieter/utilize/mixins/ChatHudMixin.java delete mode 100644 src/main/java/nl/devpieter/utilize/mixins/ClientPlayerInteractionManagerMixin.java delete mode 100644 src/main/java/nl/devpieter/utilize/mixins/SeesMixin.java delete mode 100644 src/main/java/nl/devpieter/utilize/models/UIdentifier.java rename src/main/java/nl/devpieter/utilize/{listeners => }/packet/IPacketListener.java (62%) delete mode 100644 src/main/java/nl/devpieter/utilize/task/interfaces/ITask.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/IText.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/ITextFormatter.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/ColorFormatter.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/HexColorFormatter.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/BoldFormatter.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ItalicFormatter.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ObfuscatedFormatter.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/StrikethroughFormatter.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/UnderlineFormatter.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/formatter/utils/TextFormatUtils.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/helpers/TextCacheHelper.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/helpers/TextDrawerHelper.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/texts/ItemStackText.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/texts/TextLine.java delete mode 100644 src/main/java/nl/devpieter/utilize/text/texts/TextSpacer.java delete mode 100644 src/main/java/nl/devpieter/utilize/utils/minecraft/ClientUtils.java delete mode 100644 src/main/java/nl/devpieter/utilize/utils/minecraft/EnchantmentUtils.java delete mode 100644 src/main/java/nl/devpieter/utilize/utils/minecraft/InteractionUtils.java delete mode 100644 src/main/java/nl/devpieter/utilize/utils/minecraft/InventoryUtils.java delete mode 100644 src/main/java/nl/devpieter/utilize/utils/minecraft/NetworkUtils.java delete mode 100644 src/main/java/nl/devpieter/utilize/utils/minecraft/PlayerUtils.java delete mode 100644 src/main/java/nl/devpieter/utilize/utils/minecraft/SoundUtils.java delete mode 100644 src/main/java/nl/devpieter/utilize/utils/minecraft/TextUtils.java delete mode 100644 src/main/java/nl/devpieter/utilize/utils/minecraft/WorldUtils.java delete mode 100644 versions/1.21.9/gradle.properties create mode 100644 versions/26.1/gradle.properties diff --git a/LICENSE.txt b/LICENSE.txt index 8e290a8..f28a123 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2025 DevPieter +Copyright (c) 2026 DevPieter Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/build.gradle b/build.gradle index 0784e65..b6541b1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,21 +1,39 @@ +//plugins { +// id 'net.fabricmc.fabric-loom' version '1.17-SNAPSHOT' +// id 'maven-publish' +//} + plugins { - id 'fabric-loom' + id 'net.fabricmc.fabric-loom' id 'com.replaymod.preprocess' id 'maven-publish' } -def targetJavaVersion = 21 +//version = project.mod_version +//group = project.maven_group def isSnapshot = providers.environmentVariable("SNAPSHOT_BUILD").map { it.toBoolean() }.orElse(false).get() def buildNumber = System.getenv('BUILD_NUMBER') ?: 'dev' -group = maven_group -version = "${mod_version}+${minecraft_version}-${max_minecraft_version}" + (isSnapshot ? "-SNAPSHOT+${buildNumber}" : "") +group = project.maven_group +version = "${project.mod_version}+${project.minecraft_version}-${project.max_minecraft_version}" + (isSnapshot ? "-SNAPSHOT+${buildNumber}" : "") base { - archivesName = archives_base_name + archivesName = project.archives_base_name +} + +loom { + splitEnvironmentSourceSets() + + mods { + "utilize" { + sourceSet sourceSets.main + sourceSet sourceSets.client + } + } } + repositories { maven { name "Pietr Space Releases" @@ -24,11 +42,11 @@ repositories { } dependencies { - minecraft "com.mojang:minecraft:${minecraft_version}" - mappings "net.fabricmc:yarn:${yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${loader_version}" + // To change the versions see the gradle.properties file + minecraft "com.mojang:minecraft:${project.minecraft_version}" + implementation "net.fabricmc:fabric-loader:${project.loader_version}" - modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}" + implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" implementation "nl.devpieter:sees:1.2.1" include "nl.devpieter:sees:1.2.1" @@ -54,29 +72,44 @@ processResources { } } +def targetJavaVersion = 25 tasks.withType(JavaCompile).configureEach { - options.encoding = "UTF-8" + // ensure that the encoding is set to UTF-8, no matter what the system default is + // this fixes some edge cases with special characters not displaying correctly + // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html + // If Javadoc is generated, this must be specified in that task too. + it.options.encoding = "UTF-8" + if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { + it.options.release.set(targetJavaVersion) + } } java { - toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) + def javaVersion = JavaVersion.toVersion(targetJavaVersion) + if (JavaVersion.current() < javaVersion) { + toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) + } + // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task + // if it is present. + // If you remove this line, sources will not be generated. withSourcesJar() - withJavadocJar() } jar { from("LICENSE") { - rename { "${it}_${base.archivesName.get()}" } + rename { "${it}_${project.archives_base_name}" } } } +// configure the maven publication publishing { publications { - mavenJava(MavenPublication) { + create("mavenJava", MavenPublication) { + artifactId = project.archives_base_name from components.java - artifactId = artifact_id } } + repositories { maven { url = uri(providers.gradleProperty("mavenRepositoryUrl").orNull ?: "http://localhost:8081/releases/nl/devpieter/utilize") diff --git a/gradle.properties b/gradle.properties index efc21ad..9fa5d02 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,10 +3,9 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://modmuss50.me/fabric.html -loader_version=0.18.4 +loader_version=0.19.3 # Mod Properties -artifact_id=utilize -mod_version=1.1.3 +mod_version=2.0.0 maven_group=nl.devpieter -archives_base_name=Utilize +archives_base_name=Utilize \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..b1b8ef56b44f16b14dc800fa8103a6d89abb526f 100644 GIT binary patch delta 40229 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 delta 35349 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 /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -115,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -173,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -206,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9d21a21..a51ec4f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -19,12 +19,12 @@ @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -51,7 +51,7 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -65,30 +65,18 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/root.gradle b/root.gradle index 0535b8f..32fd390 100644 --- a/root.gradle +++ b/root.gradle @@ -1,16 +1,8 @@ plugins { - id 'fabric-loom' version '1.14-SNAPSHOT' apply false -// id 'com.replaymod.preprocess' version '79307437eb' - id 'com.replaymod.preprocess' version '1678b67969' + id 'net.fabricmc.fabric-loom' version '1.17-SNAPSHOT' apply false + id 'com.replaymod.preprocess' version '221276c7d4' } preprocess { -// def mc12105 = createNode('1.21.5', 12105, "yarn") -// def mc12102 = createNode('1.21.2', 12102, "yarn") -// def mc12100 = createNode('1.21.0', 12100, "yarn") - -// mc12105.link(mc12102, null) -// mc12102.link(mc12100, null) - - def mc12109 = createNode('1.21.9', 12109, "yarn") + def mc261 = createNode('26.1', 261, null) } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 99ee0aa..49f8210 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,20 +1,24 @@ pluginManagement { + def replaymodPreprocessVersion = "221276c7d4" + repositories { maven { name = 'Fabric' url = 'https://maven.fabricmc.net/' } maven { - name = 'Jitpack' + name = 'JitPack' url = 'https://jitpack.io' } mavenCentral() gradlePluginPortal() } + resolutionStrategy { eachPlugin { if (requested.id.id == "com.replaymod.preprocess") { - useModule("com.github.ReplayMod:preprocessor:${requested.version}") + def resolvedVersion = requested.version ?: replaymodPreprocessVersion + useModule("com.github.ReplayMod:preprocessor:${resolvedVersion}") } } } @@ -23,11 +27,11 @@ pluginManagement { rootProject.buildFileName = "root.gradle" var versions = [ - "1.21.9" + "26.1" ] versions.forEach { version -> include(":${version}") project(":${version}").projectDir = file("versions/${version}") project(":${version}").buildFileName = "../../build.gradle" -} +} \ No newline at end of file diff --git a/src/client/java/nl/devpieter/utilize/client/UtilizeClient.java b/src/client/java/nl/devpieter/utilize/client/UtilizeClient.java new file mode 100644 index 0000000..8a005db --- /dev/null +++ b/src/client/java/nl/devpieter/utilize/client/UtilizeClient.java @@ -0,0 +1,56 @@ +package nl.devpieter.utilize.client; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import nl.devpieter.utilize.Utilize; +import nl.devpieter.utilize.client.setting.SettingManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class UtilizeClient implements ClientModInitializer { + + private static UtilizeClient INSTANCE; + + private final Logger logger = LoggerFactory.getLogger("Utilize Client"); + private boolean isInitialized; + + @Override + public void onInitializeClient() { + INSTANCE = this; + + ClientLifecycleEvents.CLIENT_STOPPING.register((client) -> { + logger.info("Shutting down Utilize Client..."); + + SettingManager.shutdown(); +// AsyncRequest.shutdown(); + }); + + Utilize utilize = Utilize.getInstance(); + logger.info("Utilize Client initialized successfully! Version: {}", utilize.getUtilizeVersion()); + + isInitialized = true; + } + + /** + * Checks if Utilize has been initialized. + * + * @return true if the mod instance exists and is initialized, false otherwise + */ + public static boolean initialized() { + return INSTANCE != null && INSTANCE.isInitialized; + } + + /** + * Returns the singleton instance of Utilize. + * + * @return the initialized Utilize instance + * @throws IllegalStateException if Utilize has not been initialized yet + */ + public static UtilizeClient getInstance() { + if (INSTANCE == null || !INSTANCE.isInitialized) { + throw new IllegalStateException("Utilize has not been initialized yet!"); + } + + return INSTANCE; + } +} diff --git a/src/main/java/nl/devpieter/utilize/enums/KeyActionOverride.java b/src/client/java/nl/devpieter/utilize/client/enums/KeyActionOverride.java similarity index 65% rename from src/main/java/nl/devpieter/utilize/enums/KeyActionOverride.java rename to src/client/java/nl/devpieter/utilize/client/enums/KeyActionOverride.java index e8b4dd3..17fcb08 100644 --- a/src/main/java/nl/devpieter/utilize/enums/KeyActionOverride.java +++ b/src/client/java/nl/devpieter/utilize/client/enums/KeyActionOverride.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.enums; +package nl.devpieter.utilize.client.enums; public enum KeyActionOverride { NONE, diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/keybinding/AttackKeyPressedEvent.java b/src/client/java/nl/devpieter/utilize/client/events/interaction/keybinding/AttackKeyPressedEvent.java similarity index 64% rename from src/main/java/nl/devpieter/utilize/events/interaction/keybinding/AttackKeyPressedEvent.java rename to src/client/java/nl/devpieter/utilize/client/events/interaction/keybinding/AttackKeyPressedEvent.java index c94cd28..393ac2b 100644 --- a/src/main/java/nl/devpieter/utilize/events/interaction/keybinding/AttackKeyPressedEvent.java +++ b/src/client/java/nl/devpieter/utilize/client/events/interaction/keybinding/AttackKeyPressedEvent.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.events.interaction.keybinding; +package nl.devpieter.utilize.client.events.interaction.keybinding; import nl.devpieter.sees.event.SCancelableEventBase; diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/keybinding/KeyBindingPressedCheckEvent.java b/src/client/java/nl/devpieter/utilize/client/events/interaction/keybinding/KeyBindingPressedCheckEvent.java similarity index 83% rename from src/main/java/nl/devpieter/utilize/events/interaction/keybinding/KeyBindingPressedCheckEvent.java rename to src/client/java/nl/devpieter/utilize/client/events/interaction/keybinding/KeyBindingPressedCheckEvent.java index abdc253..07e2801 100644 --- a/src/main/java/nl/devpieter/utilize/events/interaction/keybinding/KeyBindingPressedCheckEvent.java +++ b/src/client/java/nl/devpieter/utilize/client/events/interaction/keybinding/KeyBindingPressedCheckEvent.java @@ -1,7 +1,7 @@ -package nl.devpieter.utilize.events.interaction.keybinding; +package nl.devpieter.utilize.client.events.interaction.keybinding; import nl.devpieter.sees.event.SReturnableEvent; -import nl.devpieter.utilize.enums.KeyActionOverride; +import nl.devpieter.utilize.client.enums.KeyActionOverride; import org.jetbrains.annotations.NotNull; public class KeyBindingPressedCheckEvent implements SReturnableEvent { diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/keybinding/KeyBindingPressedEvent.java b/src/client/java/nl/devpieter/utilize/client/events/interaction/keybinding/KeyBindingPressedEvent.java similarity index 83% rename from src/main/java/nl/devpieter/utilize/events/interaction/keybinding/KeyBindingPressedEvent.java rename to src/client/java/nl/devpieter/utilize/client/events/interaction/keybinding/KeyBindingPressedEvent.java index 38a7d83..8b75a75 100644 --- a/src/main/java/nl/devpieter/utilize/events/interaction/keybinding/KeyBindingPressedEvent.java +++ b/src/client/java/nl/devpieter/utilize/client/events/interaction/keybinding/KeyBindingPressedEvent.java @@ -1,7 +1,7 @@ -package nl.devpieter.utilize.events.interaction.keybinding; +package nl.devpieter.utilize.client.events.interaction.keybinding; import nl.devpieter.sees.event.SReturnableEvent; -import nl.devpieter.utilize.enums.KeyActionOverride; +import nl.devpieter.utilize.client.enums.KeyActionOverride; import org.jetbrains.annotations.NotNull; public class KeyBindingPressedEvent implements SReturnableEvent { diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/keybinding/UseKeyPressedEvent.java b/src/client/java/nl/devpieter/utilize/client/events/interaction/keybinding/UseKeyPressedEvent.java similarity index 64% rename from src/main/java/nl/devpieter/utilize/events/interaction/keybinding/UseKeyPressedEvent.java rename to src/client/java/nl/devpieter/utilize/client/events/interaction/keybinding/UseKeyPressedEvent.java index 9ab28ac..cc7d6a6 100644 --- a/src/main/java/nl/devpieter/utilize/events/interaction/keybinding/UseKeyPressedEvent.java +++ b/src/client/java/nl/devpieter/utilize/client/events/interaction/keybinding/UseKeyPressedEvent.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.events.interaction.keybinding; +package nl.devpieter.utilize.client.events.interaction.keybinding; import nl.devpieter.sees.event.SCancelableEventBase; diff --git a/src/main/java/nl/devpieter/utilize/events/player/PlayerDamagedEvent.java b/src/client/java/nl/devpieter/utilize/client/events/player/PlayerDamagedEvent.java similarity index 71% rename from src/main/java/nl/devpieter/utilize/events/player/PlayerDamagedEvent.java rename to src/client/java/nl/devpieter/utilize/client/events/player/PlayerDamagedEvent.java index f3addcc..ad30215 100644 --- a/src/main/java/nl/devpieter/utilize/events/player/PlayerDamagedEvent.java +++ b/src/client/java/nl/devpieter/utilize/client/events/player/PlayerDamagedEvent.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.events.player; +package nl.devpieter.utilize.client.events.player; import nl.devpieter.sees.event.SEvent; diff --git a/src/main/java/nl/devpieter/utilize/events/player/PlayerHealedEvent.java b/src/client/java/nl/devpieter/utilize/client/events/player/PlayerHealedEvent.java similarity index 70% rename from src/main/java/nl/devpieter/utilize/events/player/PlayerHealedEvent.java rename to src/client/java/nl/devpieter/utilize/client/events/player/PlayerHealedEvent.java index 1e3a2ee..82ecbb1 100644 --- a/src/main/java/nl/devpieter/utilize/events/player/PlayerHealedEvent.java +++ b/src/client/java/nl/devpieter/utilize/client/events/player/PlayerHealedEvent.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.events.player; +package nl.devpieter.utilize.client.events.player; import nl.devpieter.sees.event.SEvent; diff --git a/src/main/java/nl/devpieter/utilize/events/tick/ClientPlayerTickEvent.java b/src/client/java/nl/devpieter/utilize/client/events/tick/ClientPlayerTickEvent.java similarity index 57% rename from src/main/java/nl/devpieter/utilize/events/tick/ClientPlayerTickEvent.java rename to src/client/java/nl/devpieter/utilize/client/events/tick/ClientPlayerTickEvent.java index ffb136a..05f94f3 100644 --- a/src/main/java/nl/devpieter/utilize/events/tick/ClientPlayerTickEvent.java +++ b/src/client/java/nl/devpieter/utilize/client/events/tick/ClientPlayerTickEvent.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.events.tick; +package nl.devpieter.utilize.client.events.tick; public record ClientPlayerTickEvent() implements ITickEvent { } diff --git a/src/main/java/nl/devpieter/utilize/events/tick/ClientPlayerTickTailEvent.java b/src/client/java/nl/devpieter/utilize/client/events/tick/ClientPlayerTickTailEvent.java similarity index 58% rename from src/main/java/nl/devpieter/utilize/events/tick/ClientPlayerTickTailEvent.java rename to src/client/java/nl/devpieter/utilize/client/events/tick/ClientPlayerTickTailEvent.java index 8e8cd13..25ab7da 100644 --- a/src/main/java/nl/devpieter/utilize/events/tick/ClientPlayerTickTailEvent.java +++ b/src/client/java/nl/devpieter/utilize/client/events/tick/ClientPlayerTickTailEvent.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.events.tick; +package nl.devpieter.utilize.client.events.tick; public record ClientPlayerTickTailEvent() implements ITickEvent { } diff --git a/src/main/java/nl/devpieter/utilize/events/tick/ClientTickEvent.java b/src/client/java/nl/devpieter/utilize/client/events/tick/ClientTickEvent.java similarity index 54% rename from src/main/java/nl/devpieter/utilize/events/tick/ClientTickEvent.java rename to src/client/java/nl/devpieter/utilize/client/events/tick/ClientTickEvent.java index df75c70..e18d8a0 100644 --- a/src/main/java/nl/devpieter/utilize/events/tick/ClientTickEvent.java +++ b/src/client/java/nl/devpieter/utilize/client/events/tick/ClientTickEvent.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.events.tick; +package nl.devpieter.utilize.client.events.tick; public record ClientTickEvent() implements ITickEvent { } diff --git a/src/main/java/nl/devpieter/utilize/events/tick/ClientTickTailEvent.java b/src/client/java/nl/devpieter/utilize/client/events/tick/ClientTickTailEvent.java similarity index 56% rename from src/main/java/nl/devpieter/utilize/events/tick/ClientTickTailEvent.java rename to src/client/java/nl/devpieter/utilize/client/events/tick/ClientTickTailEvent.java index f512b87..c23fc73 100644 --- a/src/main/java/nl/devpieter/utilize/events/tick/ClientTickTailEvent.java +++ b/src/client/java/nl/devpieter/utilize/client/events/tick/ClientTickTailEvent.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.events.tick; +package nl.devpieter.utilize.client.events.tick; public record ClientTickTailEvent() implements ITickEvent { } diff --git a/src/main/java/nl/devpieter/utilize/events/tick/ITickEvent.java b/src/client/java/nl/devpieter/utilize/client/events/tick/ITickEvent.java similarity index 64% rename from src/main/java/nl/devpieter/utilize/events/tick/ITickEvent.java rename to src/client/java/nl/devpieter/utilize/client/events/tick/ITickEvent.java index 78a0d1b..ed9048c 100644 --- a/src/main/java/nl/devpieter/utilize/events/tick/ITickEvent.java +++ b/src/client/java/nl/devpieter/utilize/client/events/tick/ITickEvent.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.events.tick; +package nl.devpieter.utilize.client.events.tick; import nl.devpieter.sees.event.SEvent; diff --git a/src/main/java/nl/devpieter/utilize/managers/DamageManager.java b/src/client/java/nl/devpieter/utilize/client/managers/DamageManager.java similarity index 84% rename from src/main/java/nl/devpieter/utilize/managers/DamageManager.java rename to src/client/java/nl/devpieter/utilize/client/managers/DamageManager.java index aa6bdfc..5294227 100644 --- a/src/main/java/nl/devpieter/utilize/managers/DamageManager.java +++ b/src/client/java/nl/devpieter/utilize/client/managers/DamageManager.java @@ -1,8 +1,8 @@ -package nl.devpieter.utilize.managers; +package nl.devpieter.utilize.client.managers; import nl.devpieter.sees.Sees; -import nl.devpieter.utilize.events.player.PlayerDamagedEvent; -import nl.devpieter.utilize.events.player.PlayerHealedEvent; +import nl.devpieter.utilize.client.events.player.PlayerDamagedEvent; +import nl.devpieter.utilize.client.events.player.PlayerHealedEvent; public final class DamageManager { diff --git a/src/main/java/nl/devpieter/utilize/mixins/KeyBindingMixin.java b/src/client/java/nl/devpieter/utilize/client/mixin/KeyMappingMixin.java similarity index 63% rename from src/main/java/nl/devpieter/utilize/mixins/KeyBindingMixin.java rename to src/client/java/nl/devpieter/utilize/client/mixin/KeyMappingMixin.java index ee3826f..3a462a5 100644 --- a/src/main/java/nl/devpieter/utilize/mixins/KeyBindingMixin.java +++ b/src/client/java/nl/devpieter/utilize/client/mixin/KeyMappingMixin.java @@ -1,12 +1,12 @@ -package nl.devpieter.utilize.mixins; +package nl.devpieter.utilize.client.mixin; -import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.KeyMapping; import nl.devpieter.sees.Sees; -import nl.devpieter.utilize.enums.KeyActionOverride; -import nl.devpieter.utilize.events.interaction.keybinding.AttackKeyPressedEvent; -import nl.devpieter.utilize.events.interaction.keybinding.KeyBindingPressedCheckEvent; -import nl.devpieter.utilize.events.interaction.keybinding.KeyBindingPressedEvent; -import nl.devpieter.utilize.events.interaction.keybinding.UseKeyPressedEvent; +import nl.devpieter.utilize.client.enums.KeyActionOverride; +import nl.devpieter.utilize.client.events.interaction.keybinding.AttackKeyPressedEvent; +import nl.devpieter.utilize.client.events.interaction.keybinding.KeyBindingPressedCheckEvent; +import nl.devpieter.utilize.client.events.interaction.keybinding.KeyBindingPressedEvent; +import nl.devpieter.utilize.client.events.interaction.keybinding.UseKeyPressedEvent; import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -15,28 +15,22 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(KeyBinding.class) -public abstract class KeyBindingMixin { +@Mixin(KeyMapping.class) +public abstract class KeyMappingMixin { @Shadow - private int timesPressed; - - @Shadow - public abstract void setPressed(boolean pressed); - - @Shadow - public abstract String getId(); + public abstract String getName(); @Unique private final Sees sees = Sees.getSharedInstance(); - @Inject(at = @At("RETURN"), method = "isPressed", cancellable = true) + @Inject(at = @At("RETURN"), method = "isDown", cancellable = true) private void isPressed(CallbackInfoReturnable cir) { handle(cir); if (cir.getReturnValue()) handlePress(cir); } - @Inject(at = @At("RETURN"), method = "wasPressed", cancellable = true) + @Inject(at = @At("RETURN"), method = "consumeClick", cancellable = true) private void wasPressed(CallbackInfoReturnable cir) { handle(cir); if (cir.getReturnValue()) handlePress(cir); @@ -44,22 +38,22 @@ private void wasPressed(CallbackInfoReturnable cir) { @Unique private void handle(@NotNull CallbackInfoReturnable cir) { - KeyActionOverride override = sees.dispatchWithResult(new KeyBindingPressedCheckEvent(getId())); + KeyActionOverride override = sees.dispatchWithResult(new KeyBindingPressedCheckEvent(getName())); if (override == KeyActionOverride.FORCE_RELEASE) forceRelease(cir); else if (override == KeyActionOverride.FORCE_PRESS) forcePress(cir); } @Unique private void handlePress(@NotNull CallbackInfoReturnable cir) { - String keyId = getId(); + String keyName = getName(); - if (keyId.equals("key.attack")) { + if (keyName.equals("key.attack")) { if (sees.dispatch(new AttackKeyPressedEvent())) forceRelease(cir); - } else if (keyId.equals("key.use")) { + } else if (keyName.equals("key.use")) { if (sees.dispatch(new UseKeyPressedEvent())) forceRelease(cir); } - KeyActionOverride override = sees.dispatchWithResult(new KeyBindingPressedEvent(keyId)); + KeyActionOverride override = sees.dispatchWithResult(new KeyBindingPressedEvent(keyName)); if (override == KeyActionOverride.FORCE_RELEASE) forceRelease(cir); else if (override == KeyActionOverride.FORCE_PRESS) forcePress(cir); } diff --git a/src/main/java/nl/devpieter/utilize/mixins/ClientPlayerEntityMixin.java b/src/client/java/nl/devpieter/utilize/client/mixin/LocalPlayerMixin.java similarity index 53% rename from src/main/java/nl/devpieter/utilize/mixins/ClientPlayerEntityMixin.java rename to src/client/java/nl/devpieter/utilize/client/mixin/LocalPlayerMixin.java index 724a6b8..25ac094 100644 --- a/src/main/java/nl/devpieter/utilize/mixins/ClientPlayerEntityMixin.java +++ b/src/client/java/nl/devpieter/utilize/client/mixin/LocalPlayerMixin.java @@ -1,22 +1,23 @@ -package nl.devpieter.utilize.mixins; +package nl.devpieter.utilize.client.mixin; import com.mojang.authlib.GameProfile; -import net.minecraft.client.network.AbstractClientPlayerEntity; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.world.ClientWorld; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.client.player.LocalPlayer; import nl.devpieter.sees.Sees; -import nl.devpieter.utilize.events.tick.ClientPlayerTickEvent; -import nl.devpieter.utilize.events.tick.ClientPlayerTickTailEvent; -import nl.devpieter.utilize.managers.DamageManager; -import nl.devpieter.utilize.task.TaskManager; +import nl.devpieter.utilize.client.events.tick.ClientPlayerTickEvent; +import nl.devpieter.utilize.client.events.tick.ClientPlayerTickTailEvent; +import nl.devpieter.utilize.client.managers.DamageManager; +import nl.devpieter.utilize.client.task.TaskManager; +import nl.devpieter.utilize.client.task.enums.TickPhase; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(ClientPlayerEntity.class) -public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity { +@Mixin(LocalPlayer.class) +public abstract class LocalPlayerMixin extends AbstractClientPlayer { @Unique private final Sees sees = Sees.getSharedInstance(); @@ -27,20 +28,20 @@ public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity @Unique private final TaskManager taskManager = TaskManager.getInstance(); - public ClientPlayerEntityMixin(ClientWorld world, GameProfile profile) { - super(world, profile); + public LocalPlayerMixin(ClientLevel level, GameProfile gameProfile) { + super(level, gameProfile); } @Inject(at = @At("HEAD"), method = "tick") private void onTick(CallbackInfo ci) { - taskManager.tick(TaskManager.TickPhase.PLAYER_HEAD); + taskManager.tick(TickPhase.PLAYER_HEAD); sees.dispatch(new ClientPlayerTickEvent()); } @Inject(at = @At("TAIL"), method = "tick") private void onTickTail(CallbackInfo ci) { damageManager.tick(getHealth()); - taskManager.tick(TaskManager.TickPhase.PLAYER_TAIL); + taskManager.tick(TickPhase.PLAYER_TAIL); sees.dispatch(new ClientPlayerTickTailEvent()); } diff --git a/src/main/java/nl/devpieter/utilize/mixins/MinecraftClientMixin.java b/src/client/java/nl/devpieter/utilize/client/mixin/MinecraftMixin.java similarity index 53% rename from src/main/java/nl/devpieter/utilize/mixins/MinecraftClientMixin.java rename to src/client/java/nl/devpieter/utilize/client/mixin/MinecraftMixin.java index f9c26cd..64f87ce 100644 --- a/src/main/java/nl/devpieter/utilize/mixins/MinecraftClientMixin.java +++ b/src/client/java/nl/devpieter/utilize/client/mixin/MinecraftMixin.java @@ -1,31 +1,21 @@ -package nl.devpieter.utilize.mixins; +package nl.devpieter.utilize.client.mixin; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.Minecraft; import nl.devpieter.sees.Sees; import nl.devpieter.utilize.Utilize; -import nl.devpieter.utilize.events.screen.ScreenChangedEvent; -import nl.devpieter.utilize.events.tick.ClientTickEvent; -import nl.devpieter.utilize.events.tick.ClientTickTailEvent; -import nl.devpieter.utilize.setting.SettingManager; -import nl.devpieter.utilize.task.TaskManager; -import org.jetbrains.annotations.Nullable; +import nl.devpieter.utilize.client.events.tick.ClientTickEvent; +import nl.devpieter.utilize.client.events.tick.ClientTickTailEvent; +import nl.devpieter.utilize.client.setting.SettingManager; +import nl.devpieter.utilize.client.task.TaskManager; +import nl.devpieter.utilize.client.task.enums.TickPhase; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(MinecraftClient.class) -public class MinecraftClientMixin { - - @Shadow - @Nullable - public Screen currentScreen; - - @Unique - private Screen previousScreen; +@Mixin(Minecraft.class) +public class MinecraftMixin { @Unique private final Sees sees = Sees.getSharedInstance(); @@ -36,23 +26,13 @@ public class MinecraftClientMixin { @Unique private TaskManager taskManager; - @Inject(at = @At("HEAD"), method = "setScreen") - private void onSetScreenHead(Screen screen, CallbackInfo ci) { - previousScreen = currentScreen; - } - - @Inject(at = @At("TAIL"), method = "setScreen") - private void onSetScreenTail(Screen screen, CallbackInfo ci) { - sees.dispatch(new ScreenChangedEvent(previousScreen, screen)); - } - @Inject(at = @At("HEAD"), method = "tick") private void onTick(CallbackInfo ci) { tryInitializeManagers(); if (taskManager != null) { taskManager.beginTick(); - taskManager.tick(TaskManager.TickPhase.CLIENT_HEAD); + taskManager.tick(TickPhase.CLIENT_HEAD); } sees.dispatch(new ClientTickEvent()); @@ -61,14 +41,14 @@ private void onTick(CallbackInfo ci) { @Inject(at = @At("TAIL"), method = "tick") private void onTickTail(CallbackInfo ci) { if (settingManager != null) settingManager.tick(); - if (taskManager != null) taskManager.tick(TaskManager.TickPhase.CLIENT_TAIL); + if (taskManager != null) taskManager.tick(TickPhase.CLIENT_TAIL); sees.dispatch(new ClientTickTailEvent()); } /** * We need to initialize the managers here because Utilize may not be fully initialized - * when MinecraftClient is being constructed, leading to potential null references. + * when Minecraft is being constructed, leading to potential null references. */ @Unique private void tryInitializeManagers() { diff --git a/src/main/java/nl/devpieter/utilize/setting/KeyedSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/KeyedSetting.java similarity index 55% rename from src/main/java/nl/devpieter/utilize/setting/KeyedSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/KeyedSetting.java index 2bf57e0..a97c4b4 100644 --- a/src/main/java/nl/devpieter/utilize/setting/KeyedSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/KeyedSetting.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.setting; +package nl.devpieter.utilize.client.setting; public record KeyedSetting(String key, T value) { } diff --git a/src/main/java/nl/devpieter/utilize/setting/SettingManager.java b/src/client/java/nl/devpieter/utilize/client/setting/SettingManager.java similarity index 98% rename from src/main/java/nl/devpieter/utilize/setting/SettingManager.java rename to src/client/java/nl/devpieter/utilize/client/setting/SettingManager.java index ad48d86..124c1ed 100644 --- a/src/main/java/nl/devpieter/utilize/setting/SettingManager.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/SettingManager.java @@ -1,9 +1,9 @@ -package nl.devpieter.utilize.setting; +package nl.devpieter.utilize.client.setting; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.reflect.TypeToken; -import nl.devpieter.utilize.setting.interfaces.ISetting; +import nl.devpieter.utilize.client.setting.interfaces.ISetting; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; diff --git a/src/main/java/nl/devpieter/utilize/setting/base/SettingBase.java b/src/client/java/nl/devpieter/utilize/client/setting/base/SettingBase.java similarity index 91% rename from src/main/java/nl/devpieter/utilize/setting/base/SettingBase.java rename to src/client/java/nl/devpieter/utilize/client/setting/base/SettingBase.java index c36ddae..68fd7b8 100644 --- a/src/main/java/nl/devpieter/utilize/setting/base/SettingBase.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/base/SettingBase.java @@ -1,6 +1,6 @@ -package nl.devpieter.utilize.setting.base; +package nl.devpieter.utilize.client.setting.base; -import nl.devpieter.utilize.setting.interfaces.ISetting; +import nl.devpieter.utilize.client.setting.interfaces.ISetting; import org.jetbrains.annotations.NotNull; public abstract class SettingBase implements ISetting { diff --git a/src/main/java/nl/devpieter/utilize/setting/interfaces/IBooleanSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/IBooleanSetting.java similarity index 81% rename from src/main/java/nl/devpieter/utilize/setting/interfaces/IBooleanSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/interfaces/IBooleanSetting.java index 0db22e5..ef442fd 100644 --- a/src/main/java/nl/devpieter/utilize/setting/interfaces/IBooleanSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/IBooleanSetting.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.setting.interfaces; +package nl.devpieter.utilize.client.setting.interfaces; import java.lang.reflect.Type; diff --git a/src/main/java/nl/devpieter/utilize/setting/interfaces/IListSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/IListSetting.java similarity index 82% rename from src/main/java/nl/devpieter/utilize/setting/interfaces/IListSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/interfaces/IListSetting.java index 38b013e..e74102e 100644 --- a/src/main/java/nl/devpieter/utilize/setting/interfaces/IListSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/IListSetting.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.setting.interfaces; +package nl.devpieter.utilize.client.setting.interfaces; import java.util.List; diff --git a/src/main/java/nl/devpieter/utilize/setting/interfaces/IMapSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/IMapSetting.java similarity index 81% rename from src/main/java/nl/devpieter/utilize/setting/interfaces/IMapSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/interfaces/IMapSetting.java index 5ecc667..1ae71a9 100644 --- a/src/main/java/nl/devpieter/utilize/setting/interfaces/IMapSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/IMapSetting.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.setting.interfaces; +package nl.devpieter.utilize.client.setting.interfaces; import java.util.Map; diff --git a/src/main/java/nl/devpieter/utilize/setting/interfaces/INumberSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/INumberSetting.java similarity index 76% rename from src/main/java/nl/devpieter/utilize/setting/interfaces/INumberSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/interfaces/INumberSetting.java index 2e2fbe1..2f47452 100644 --- a/src/main/java/nl/devpieter/utilize/setting/interfaces/INumberSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/INumberSetting.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.setting.interfaces; +package nl.devpieter.utilize.client.setting.interfaces; public interface INumberSetting extends ISetting { diff --git a/src/main/java/nl/devpieter/utilize/setting/interfaces/IPolymorphicSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/IPolymorphicSetting.java similarity index 69% rename from src/main/java/nl/devpieter/utilize/setting/interfaces/IPolymorphicSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/interfaces/IPolymorphicSetting.java index 66267bc..8a0af20 100644 --- a/src/main/java/nl/devpieter/utilize/setting/interfaces/IPolymorphicSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/IPolymorphicSetting.java @@ -1,7 +1,7 @@ -package nl.devpieter.utilize.setting.interfaces; +package nl.devpieter.utilize.client.setting.interfaces; import com.google.common.reflect.TypeToken; -import nl.devpieter.utilize.models.PolymorphicValue; +import nl.devpieter.utilize.client.setting.models.PolymorphicValue; import java.lang.reflect.Type; diff --git a/src/main/java/nl/devpieter/utilize/setting/interfaces/ISetting.java b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/ISetting.java similarity index 85% rename from src/main/java/nl/devpieter/utilize/setting/interfaces/ISetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/interfaces/ISetting.java index e7d5d11..2d390c2 100644 --- a/src/main/java/nl/devpieter/utilize/setting/interfaces/ISetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/ISetting.java @@ -1,6 +1,6 @@ -package nl.devpieter.utilize.setting.interfaces; +package nl.devpieter.utilize.client.setting.interfaces; -import nl.devpieter.utilize.setting.KeyedSetting; +import nl.devpieter.utilize.client.setting.KeyedSetting; import java.lang.reflect.Type; diff --git a/src/main/java/nl/devpieter/utilize/setting/interfaces/IStringSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/IStringSetting.java similarity index 75% rename from src/main/java/nl/devpieter/utilize/setting/interfaces/IStringSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/interfaces/IStringSetting.java index 4c04b67..6883bd1 100644 --- a/src/main/java/nl/devpieter/utilize/setting/interfaces/IStringSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/interfaces/IStringSetting.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.setting.interfaces; +package nl.devpieter.utilize.client.setting.interfaces; import java.lang.reflect.Type; diff --git a/src/main/java/nl/devpieter/utilize/models/PolymorphicValue.java b/src/client/java/nl/devpieter/utilize/client/setting/models/PolymorphicValue.java similarity index 94% rename from src/main/java/nl/devpieter/utilize/models/PolymorphicValue.java rename to src/client/java/nl/devpieter/utilize/client/setting/models/PolymorphicValue.java index 755b600..01cd37c 100644 --- a/src/main/java/nl/devpieter/utilize/models/PolymorphicValue.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/models/PolymorphicValue.java @@ -1,4 +1,4 @@ -package nl.devpieter.utilize.models; +package nl.devpieter.utilize.client.setting.models; import com.google.gson.Gson; import com.google.gson.JsonElement; diff --git a/src/main/java/nl/devpieter/utilize/setting/settings/BooleanSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/settings/BooleanSetting.java similarity index 80% rename from src/main/java/nl/devpieter/utilize/setting/settings/BooleanSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/settings/BooleanSetting.java index 4ef0a54..dccd389 100644 --- a/src/main/java/nl/devpieter/utilize/setting/settings/BooleanSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/settings/BooleanSetting.java @@ -1,7 +1,7 @@ -package nl.devpieter.utilize.setting.settings; +package nl.devpieter.utilize.client.setting.settings; -import nl.devpieter.utilize.setting.base.SettingBase; -import nl.devpieter.utilize.setting.interfaces.IBooleanSetting; +import nl.devpieter.utilize.client.setting.base.SettingBase; +import nl.devpieter.utilize.client.setting.interfaces.IBooleanSetting; import org.jetbrains.annotations.NotNull; public class BooleanSetting extends SettingBase implements IBooleanSetting { diff --git a/src/main/java/nl/devpieter/utilize/setting/settings/FloatSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/settings/FloatSetting.java similarity index 89% rename from src/main/java/nl/devpieter/utilize/setting/settings/FloatSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/settings/FloatSetting.java index e974858..1906a11 100644 --- a/src/main/java/nl/devpieter/utilize/setting/settings/FloatSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/settings/FloatSetting.java @@ -1,7 +1,7 @@ -package nl.devpieter.utilize.setting.settings; +package nl.devpieter.utilize.client.setting.settings; -import nl.devpieter.utilize.setting.base.SettingBase; -import nl.devpieter.utilize.setting.interfaces.INumberSetting; +import nl.devpieter.utilize.client.setting.base.SettingBase; +import nl.devpieter.utilize.client.setting.interfaces.INumberSetting; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/nl/devpieter/utilize/setting/settings/IntSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/settings/IntSetting.java similarity index 89% rename from src/main/java/nl/devpieter/utilize/setting/settings/IntSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/settings/IntSetting.java index a7a93b7..195b07e 100644 --- a/src/main/java/nl/devpieter/utilize/setting/settings/IntSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/settings/IntSetting.java @@ -1,7 +1,7 @@ -package nl.devpieter.utilize.setting.settings; +package nl.devpieter.utilize.client.setting.settings; -import nl.devpieter.utilize.setting.base.SettingBase; -import nl.devpieter.utilize.setting.interfaces.INumberSetting; +import nl.devpieter.utilize.client.setting.base.SettingBase; +import nl.devpieter.utilize.client.setting.interfaces.INumberSetting; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/nl/devpieter/utilize/setting/settings/ListSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/settings/ListSetting.java similarity index 92% rename from src/main/java/nl/devpieter/utilize/setting/settings/ListSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/settings/ListSetting.java index e939954..d774cb9 100644 --- a/src/main/java/nl/devpieter/utilize/setting/settings/ListSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/settings/ListSetting.java @@ -1,8 +1,8 @@ -package nl.devpieter.utilize.setting.settings; +package nl.devpieter.utilize.client.setting.settings; import com.google.common.reflect.TypeToken; -import nl.devpieter.utilize.setting.base.SettingBase; -import nl.devpieter.utilize.setting.interfaces.IListSetting; +import nl.devpieter.utilize.client.setting.base.SettingBase; +import nl.devpieter.utilize.client.setting.interfaces.IListSetting; import java.lang.reflect.Type; import java.util.List; diff --git a/src/main/java/nl/devpieter/utilize/setting/settings/MapSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/settings/MapSetting.java similarity index 90% rename from src/main/java/nl/devpieter/utilize/setting/settings/MapSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/settings/MapSetting.java index cd498c8..e8b3d2a 100644 --- a/src/main/java/nl/devpieter/utilize/setting/settings/MapSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/settings/MapSetting.java @@ -1,8 +1,8 @@ -package nl.devpieter.utilize.setting.settings; +package nl.devpieter.utilize.client.setting.settings; import com.google.common.reflect.TypeToken; -import nl.devpieter.utilize.setting.base.SettingBase; -import nl.devpieter.utilize.setting.interfaces.IMapSetting; +import nl.devpieter.utilize.client.setting.base.SettingBase; +import nl.devpieter.utilize.client.setting.interfaces.IMapSetting; import org.jetbrains.annotations.NotNull; import java.lang.reflect.Type; diff --git a/src/main/java/nl/devpieter/utilize/setting/settings/StringSetting.java b/src/client/java/nl/devpieter/utilize/client/setting/settings/StringSetting.java similarity index 65% rename from src/main/java/nl/devpieter/utilize/setting/settings/StringSetting.java rename to src/client/java/nl/devpieter/utilize/client/setting/settings/StringSetting.java index c50f6c9..e6b157d 100644 --- a/src/main/java/nl/devpieter/utilize/setting/settings/StringSetting.java +++ b/src/client/java/nl/devpieter/utilize/client/setting/settings/StringSetting.java @@ -1,7 +1,7 @@ -package nl.devpieter.utilize.setting.settings; +package nl.devpieter.utilize.client.setting.settings; -import nl.devpieter.utilize.setting.base.SettingBase; -import nl.devpieter.utilize.setting.interfaces.IStringSetting; +import nl.devpieter.utilize.client.setting.base.SettingBase; +import nl.devpieter.utilize.client.setting.interfaces.IStringSetting; public class StringSetting extends SettingBase implements IStringSetting { diff --git a/src/client/java/nl/devpieter/utilize/client/task/ITask.java b/src/client/java/nl/devpieter/utilize/client/task/ITask.java new file mode 100644 index 0000000..c24bd25 --- /dev/null +++ b/src/client/java/nl/devpieter/utilize/client/task/ITask.java @@ -0,0 +1,8 @@ +package nl.devpieter.utilize.client.task; + +import nl.devpieter.utilize.client.task.enums.TickResult; + +public interface ITask { + + TickResult tick(); +} diff --git a/src/client/java/nl/devpieter/utilize/client/task/TaskEntry.java b/src/client/java/nl/devpieter/utilize/client/task/TaskEntry.java new file mode 100644 index 0000000..0a362f0 --- /dev/null +++ b/src/client/java/nl/devpieter/utilize/client/task/TaskEntry.java @@ -0,0 +1,6 @@ +package nl.devpieter.utilize.client.task; + +import nl.devpieter.utilize.client.task.enums.TickPhase; + +public record TaskEntry(ITask task, TickPhase phase) { +} diff --git a/src/main/java/nl/devpieter/utilize/task/TaskManager.java b/src/client/java/nl/devpieter/utilize/client/task/TaskManager.java similarity index 84% rename from src/main/java/nl/devpieter/utilize/task/TaskManager.java rename to src/client/java/nl/devpieter/utilize/client/task/TaskManager.java index 187f5b5..cbb7a1a 100644 --- a/src/main/java/nl/devpieter/utilize/task/TaskManager.java +++ b/src/client/java/nl/devpieter/utilize/client/task/TaskManager.java @@ -1,6 +1,7 @@ -package nl.devpieter.utilize.task; +package nl.devpieter.utilize.client.task; -import nl.devpieter.utilize.task.interfaces.ITask; +import nl.devpieter.utilize.client.task.enums.TickPhase; +import nl.devpieter.utilize.client.task.enums.TickResult; import java.util.ArrayList; import java.util.EnumMap; @@ -73,20 +74,4 @@ private void flushPendingTasks() { pendingTasks.clear(); } - - public enum TickPhase { - PLAYER_HEAD, - PLAYER_TAIL, - CLIENT_HEAD, - CLIENT_TAIL - } - - public enum TickResult { - CONTINUE, - FINISHED, - REQUEUE - } - - private record TaskEntry(ITask task, TickPhase phase) { - } } diff --git a/src/client/java/nl/devpieter/utilize/client/task/enums/TickPhase.java b/src/client/java/nl/devpieter/utilize/client/task/enums/TickPhase.java new file mode 100644 index 0000000..9f09c55 --- /dev/null +++ b/src/client/java/nl/devpieter/utilize/client/task/enums/TickPhase.java @@ -0,0 +1,8 @@ +package nl.devpieter.utilize.client.task.enums; + +public enum TickPhase { + PLAYER_HEAD, + PLAYER_TAIL, + CLIENT_HEAD, + CLIENT_TAIL +} diff --git a/src/client/java/nl/devpieter/utilize/client/task/enums/TickResult.java b/src/client/java/nl/devpieter/utilize/client/task/enums/TickResult.java new file mode 100644 index 0000000..8862106 --- /dev/null +++ b/src/client/java/nl/devpieter/utilize/client/task/enums/TickResult.java @@ -0,0 +1,7 @@ +package nl.devpieter.utilize.client.task.enums; + +public enum TickResult { + CONTINUE, + FINISHED, + REQUEUE +} diff --git a/src/main/java/nl/devpieter/utilize/task/tasks/RunLaterTask.java b/src/client/java/nl/devpieter/utilize/client/task/tasks/RunLaterTask.java similarity index 69% rename from src/main/java/nl/devpieter/utilize/task/tasks/RunLaterTask.java rename to src/client/java/nl/devpieter/utilize/client/task/tasks/RunLaterTask.java index e056da3..0e30e0d 100644 --- a/src/main/java/nl/devpieter/utilize/task/tasks/RunLaterTask.java +++ b/src/client/java/nl/devpieter/utilize/client/task/tasks/RunLaterTask.java @@ -1,7 +1,7 @@ -package nl.devpieter.utilize.task.tasks; +package nl.devpieter.utilize.client.task.tasks; -import nl.devpieter.utilize.task.TaskManager; -import nl.devpieter.utilize.task.interfaces.ITask; +import nl.devpieter.utilize.client.task.ITask; +import nl.devpieter.utilize.client.task.enums.TickResult; import nl.devpieter.utilize.utils.common.MathUtils; import org.jetbrains.annotations.NotNull; @@ -26,17 +26,17 @@ public RunLaterTask(@NotNull Runnable runnable, int startDelayTicks) { } @Override - public TaskManager.TickResult tick() { - if (finished) return TaskManager.TickResult.FINISHED; + public TickResult tick() { + if (finished) return TickResult.FINISHED; tickCounter++; if (tickCounter < startDelayTicks) { - return TaskManager.TickResult.CONTINUE; + return TickResult.CONTINUE; } runnable.run(); finished = true; - return TaskManager.TickResult.FINISHED; + return TickResult.FINISHED; } } diff --git a/src/client/resources/utilize.client.mixins.json b/src/client/resources/utilize.client.mixins.json new file mode 100644 index 0000000..8838def --- /dev/null +++ b/src/client/resources/utilize.client.mixins.json @@ -0,0 +1,19 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "nl.devpieter.utilize.client.mixin", + "compatibilityLevel": "JAVA_25", + "client": [ + ], + "injectors": { + "defaultRequire": 1 + }, + "overwrites": { + "requireAnnotations": true + }, + "mixins": [ + "KeyMappingMixin", + "LocalPlayerMixin", + "MinecraftMixin" + ] +} diff --git a/src/main/java/nl/devpieter/utilize/Utilize.java b/src/main/java/nl/devpieter/utilize/Utilize.java index 730bd80..1344a12 100644 --- a/src/main/java/nl/devpieter/utilize/Utilize.java +++ b/src/main/java/nl/devpieter/utilize/Utilize.java @@ -1,19 +1,13 @@ package nl.devpieter.utilize; -import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.minecraft.SharedConstants; -import nl.devpieter.utilize.http.AsyncRequest; -import nl.devpieter.utilize.setting.SettingManager; -import nl.devpieter.utilize.text.formatter.TextFormatRegistry; -import nl.devpieter.utilize.text.formatter.formatters.color.ColorFormatter; -import nl.devpieter.utilize.text.formatter.formatters.format.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class Utilize implements ClientModInitializer { +public class Utilize implements ModInitializer { private static Utilize INSTANCE; @@ -23,68 +17,11 @@ public class Utilize implements ClientModInitializer { private boolean isInitialized; @Override - public void onInitializeClient() { + public void onInitialize() { INSTANCE = this; - ClientLifecycleEvents.CLIENT_STOPPING.register((client) -> { - logger.info("Shutting down Utilize..."); - - SettingManager.shutdown(); - AsyncRequest.shutdown(); - }); - - // https://minecraft.wiki/w/Formatting_codes - TextFormatRegistry formatRegistry = TextFormatRegistry.getInstance(); - formatRegistry.register("bold", new BoldFormatter()); - formatRegistry.register("italic", new ItalicFormatter()); - formatRegistry.register("underline", new UnderlineFormatter()); - formatRegistry.register("strikethrough", new StrikethroughFormatter()); - formatRegistry.register("obfuscated", new ObfuscatedFormatter()); - formatRegistry.register("black", new ColorFormatter(0x000000)); - formatRegistry.register("dark_blue", new ColorFormatter(0x0000AA)); - formatRegistry.register("dark_green", new ColorFormatter(0x00AA00)); - formatRegistry.register("dark_aqua", new ColorFormatter(0x00AAAA)); - formatRegistry.register("dark_red", new ColorFormatter(0xAA0000)); - formatRegistry.register("dark_purple", new ColorFormatter(0xAA00AA)); - formatRegistry.register("gold", new ColorFormatter(0xFFAA00)); - formatRegistry.register("gray", new ColorFormatter(0xAAAAAA)); - formatRegistry.register("dark_gray", new ColorFormatter(0x555555)); - formatRegistry.register("blue", new ColorFormatter(0x5555FF)); - formatRegistry.register("green", new ColorFormatter(0x55FF55)); - formatRegistry.register("aqua", new ColorFormatter(0x55FFFF)); - formatRegistry.register("red", new ColorFormatter(0xFF5555)); - formatRegistry.register("light_purple", new ColorFormatter(0xFF55FF)); - formatRegistry.register("yellow", new ColorFormatter(0xFFFF55)); - formatRegistry.register("white", new ColorFormatter(0xFFFFFF)); -// formatRegistry.register("minecoin_gold", new ColorFormatter(0xDDD605)); -// formatRegistry.register("material_quartz", new ColorFormatter(0xE3D4D1)); -// formatRegistry.register("material_iron", new ColorFormatter(0xCECACA)); -// formatRegistry.register("material_netherite", new ColorFormatter(0x443A3B)); -// formatRegistry.register("material_redstone", new ColorFormatter(0x971607)); -// formatRegistry.register("material_copper", new ColorFormatter(0xB4684D)); -// formatRegistry.register("material_gold", new ColorFormatter(0xDEB12D)); -// formatRegistry.register("material_emerald", new ColorFormatter(0x47A036)); -// formatRegistry.register("material_diamond", new ColorFormatter(0x2CBAA8)); -// formatRegistry.register("material_lapis", new ColorFormatter(0x21497B)); -// formatRegistry.register("material_amethyst", new ColorFormatter(0x9A5CC6)); -// formatRegistry.register("material_resin", new ColorFormatter(0xEB7114)); - logger.info("Utilize initialized successfully! Version: {}", getUtilizeVersion()); isInitialized = true; - -// TextCacheHelper textCacheHelper = new TextCacheHelper(); -// -// ClientTickEvents.START_CLIENT_TICK.register(client -> { -// boolean isInGame = client.player != null && client.world != null; -// if (!isInGame) return; -// -// PlayerEntity player = client.player; -// String sneaking = player.isSneaking() ? "Yes" : "No"; -// -//// MutableText sneakingText = textCacheHelper.getFormatted("Sneaking: %s testing", Style.EMPTY, sneaking); -// MutableText sneakingText = textCacheHelper.getFormatted("2 Sneaking: %s tt0 t0 t2 tt1 <#bda2f2>tt2", Style.EMPTY, sneaking); -// PlayerUtils.sendMessage(sneakingText, true); -// }); } /** @@ -124,7 +61,7 @@ public String getUtilizeVersion() { } public String getMinecraftVersion() { - return SharedConstants.getGameVersion().name(); + return SharedConstants.getCurrentVersion().name(); } /** diff --git a/src/main/java/nl/devpieter/utilize/events/chat/ReceiveMessageEvent.java b/src/main/java/nl/devpieter/utilize/events/chat/ReceiveMessageEvent.java deleted file mode 100644 index a4f2590..0000000 --- a/src/main/java/nl/devpieter/utilize/events/chat/ReceiveMessageEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -package nl.devpieter.utilize.events.chat; - -import net.minecraft.text.Text; -import nl.devpieter.sees.event.SCancelableEventBase; -import nl.devpieter.sees.event.SReturnableEvent; - -public class ReceiveMessageEvent extends SCancelableEventBase implements SReturnableEvent { - - private Text message; - - public ReceiveMessageEvent(Text message) { - this.message = message; - } - - @Override - public Text getResult() { - return this.message; - } - - @Override - public void setResult(Text message) { - this.message = message; - } - - public Text message() { - return this.message; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/UpdateBlockBreakingProgressEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/UpdateBlockBreakingProgressEvent.java deleted file mode 100644 index 92df5c9..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/UpdateBlockBreakingProgressEvent.java +++ /dev/null @@ -1,24 +0,0 @@ -package nl.devpieter.utilize.events.interaction; - -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import nl.devpieter.sees.event.SCancelableEventBase; - -public class UpdateBlockBreakingProgressEvent extends SCancelableEventBase { - - private final BlockPos blockPos; - private final Direction direction; - - public UpdateBlockBreakingProgressEvent(BlockPos blockPos, Direction direction) { - this.blockPos = blockPos; - this.direction = direction; - } - - public BlockPos blockPos() { - return blockPos; - } - - public Direction direction() { - return direction; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/block/AttackBlockEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/block/AttackBlockEvent.java deleted file mode 100644 index 955ef68..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/block/AttackBlockEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -package nl.devpieter.utilize.events.interaction.block; - -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import nl.devpieter.sees.event.SCancelableEventBase; - -/** - * It's not recommended to directly cancel this event, as it may cause issues with the game logic. - * Instead, use the {@link nl.devpieter.utilize.events.interaction.keybinding.AttackKeyPressedEvent} to directly cancel the attack action. - */ -public class AttackBlockEvent extends SCancelableEventBase { - - private final BlockPos blockPos; - private final Direction direction; - - public AttackBlockEvent(BlockPos blockPos, Direction direction) { - this.blockPos = blockPos; - this.direction = direction; - } - - public BlockPos blockPos() { - return this.blockPos; - } - - public Direction direction() { - return this.direction; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/block/AttackBlockReturnEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/block/AttackBlockReturnEvent.java deleted file mode 100644 index fb927f2..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/block/AttackBlockReturnEvent.java +++ /dev/null @@ -1,36 +0,0 @@ -package nl.devpieter.utilize.events.interaction.block; - -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import nl.devpieter.sees.event.SReturnableEvent; - -public class AttackBlockReturnEvent implements SReturnableEvent { - - private final BlockPos blockPos; - private final Direction direction; - private boolean returnValue; - - public AttackBlockReturnEvent(BlockPos blockPos, Direction direction, boolean returnValue) { - this.blockPos = blockPos; - this.direction = direction; - this.returnValue = returnValue; - } - - public BlockPos blockPos() { - return this.blockPos; - } - - public Direction direction() { - return this.direction; - } - - @Override - public Boolean getResult() { - return this.returnValue; - } - - @Override - public void setResult(Boolean result) { - this.returnValue = result; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/block/AttackBlockTailEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/block/AttackBlockTailEvent.java deleted file mode 100644 index 94f197d..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/block/AttackBlockTailEvent.java +++ /dev/null @@ -1,8 +0,0 @@ -package nl.devpieter.utilize.events.interaction.block; - -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import nl.devpieter.sees.event.SEvent; - -public record AttackBlockTailEvent(BlockPos blockPos, Direction direction) implements SEvent { -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/block/BreakBlockEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/block/BreakBlockEvent.java deleted file mode 100644 index deb8878..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/block/BreakBlockEvent.java +++ /dev/null @@ -1,21 +0,0 @@ -package nl.devpieter.utilize.events.interaction.block; - -import net.minecraft.util.math.BlockPos; -import nl.devpieter.sees.event.SCancelableEventBase; - -/** - * It's not recommended to directly cancel this event, as it may cause issues with the game logic. - * Instead, use the {@link nl.devpieter.utilize.events.interaction.keybinding.AttackKeyPressedEvent} to directly cancel the attack action. - */ -public class BreakBlockEvent extends SCancelableEventBase { - - private final BlockPos blockPos; - - public BreakBlockEvent(BlockPos blockPos) { - this.blockPos = blockPos; - } - - public BlockPos blockPos() { - return this.blockPos; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/block/BreakBlockReturnEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/block/BreakBlockReturnEvent.java deleted file mode 100644 index 734c737..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/block/BreakBlockReturnEvent.java +++ /dev/null @@ -1,30 +0,0 @@ -package nl.devpieter.utilize.events.interaction.block; - -import net.minecraft.util.math.BlockPos; -import nl.devpieter.sees.event.SCancelableEventBase; -import nl.devpieter.sees.event.SReturnableEvent; - -public class BreakBlockReturnEvent implements SReturnableEvent { - - private final BlockPos blockPos; - private boolean returnValue; - - public BreakBlockReturnEvent(BlockPos blockPos, boolean returnValue) { - this.blockPos = blockPos; - this.returnValue = returnValue; - } - - public BlockPos blockPos() { - return this.blockPos; - } - - @Override - public Boolean getResult() { - return this.returnValue; - } - - @Override - public void setResult(Boolean result) { - this.returnValue = result; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/block/BreakBlockTailEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/block/BreakBlockTailEvent.java deleted file mode 100644 index 14ed4ad..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/block/BreakBlockTailEvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package nl.devpieter.utilize.events.interaction.block; - -import net.minecraft.util.math.BlockPos; -import nl.devpieter.sees.event.SEvent; - -public record BreakBlockTailEvent(BlockPos blockPos) implements SEvent { -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/block/InteractBlockEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/block/InteractBlockEvent.java deleted file mode 100644 index 99b35c9..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/block/InteractBlockEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -package nl.devpieter.utilize.events.interaction.block; - -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import nl.devpieter.sees.event.SCancelableEventBase; - -/** - * It's not recommended to directly cancel this event, as it may cause issues with the game logic. - * Instead, use the {@link nl.devpieter.utilize.events.interaction.keybinding.UseKeyPressedEvent} to directly cancel the use action. - */ -public class InteractBlockEvent extends SCancelableEventBase { - - private final Hand hand; - private final BlockHitResult hitResult; - - public InteractBlockEvent(Hand hand, BlockHitResult hitResult) { - this.hand = hand; - this.hitResult = hitResult; - } - - public Hand hand() { - return this.hand; - } - - public BlockHitResult hitResult() { - return this.hitResult; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/block/InteractBlockReturnEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/block/InteractBlockReturnEvent.java deleted file mode 100644 index 11fb675..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/block/InteractBlockReturnEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -package nl.devpieter.utilize.events.interaction.block; - -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import nl.devpieter.sees.event.SReturnableEvent; - -public class InteractBlockReturnEvent implements SReturnableEvent { - - private final Hand hand; - private final BlockHitResult hitResult; - private ActionResult returnValue; - - public InteractBlockReturnEvent(Hand hand, BlockHitResult hitResult, ActionResult returnValue) { - this.hand = hand; - this.hitResult = hitResult; - this.returnValue = returnValue; - } - - public Hand hand() { - return this.hand; - } - - public BlockHitResult hitResult() { - return this.hitResult; - } - - @Override - public ActionResult getResult() { - return this.returnValue; - } - - @Override - public void setResult(ActionResult result) { - this.returnValue = result; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/block/InteractBlockTailEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/block/InteractBlockTailEvent.java deleted file mode 100644 index f4d9e50..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/block/InteractBlockTailEvent.java +++ /dev/null @@ -1,8 +0,0 @@ -package nl.devpieter.utilize.events.interaction.block; - -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import nl.devpieter.sees.event.SEvent; - -public record InteractBlockTailEvent(Hand hand, BlockHitResult hitResult) implements SEvent { -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/entity/AttackEntityEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/entity/AttackEntityEvent.java deleted file mode 100644 index 825da1b..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/entity/AttackEntityEvent.java +++ /dev/null @@ -1,21 +0,0 @@ -package nl.devpieter.utilize.events.interaction.entity; - -import net.minecraft.entity.Entity; -import nl.devpieter.sees.event.SCancelableEventBase; - -/** - * It's not recommended to directly cancel this event, as it may cause issues with the game logic. - * Instead, use the {@link nl.devpieter.utilize.events.interaction.keybinding.AttackKeyPressedEvent} to directly cancel the attack action. - */ -public class AttackEntityEvent extends SCancelableEventBase { - - private final Entity target; - - public AttackEntityEvent(Entity target) { - this.target = target; - } - - public Entity target() { - return this.target; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/entity/AttackEntityReturnEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/entity/AttackEntityReturnEvent.java deleted file mode 100644 index 28a343a..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/entity/AttackEntityReturnEvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package nl.devpieter.utilize.events.interaction.entity; - -import net.minecraft.entity.Entity; -import nl.devpieter.sees.event.SEvent; - -public record AttackEntityReturnEvent(Entity target) implements SEvent { -} \ No newline at end of file diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/entity/AttackEntityTailEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/entity/AttackEntityTailEvent.java deleted file mode 100644 index de30110..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/entity/AttackEntityTailEvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package nl.devpieter.utilize.events.interaction.entity; - -import net.minecraft.entity.Entity; -import nl.devpieter.sees.event.SEvent; - -public record AttackEntityTailEvent(Entity target) implements SEvent { -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/entity/InteractEntityEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/entity/InteractEntityEvent.java deleted file mode 100644 index dbe3b83..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/entity/InteractEntityEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -package nl.devpieter.utilize.events.interaction.entity; - -import net.minecraft.entity.Entity; -import net.minecraft.util.Hand; -import nl.devpieter.sees.event.SCancelableEventBase; - -/** - * It's not recommended to directly cancel this event, as it may cause issues with the game logic. - * Instead, use the {@link nl.devpieter.utilize.events.interaction.keybinding.UseKeyPressedEvent} to directly cancel the use action. - */ -public class InteractEntityEvent extends SCancelableEventBase { - - private final Entity target; - private final Hand hand; - - public InteractEntityEvent(Entity target, Hand hand) { - this.hand = hand; - this.target = target; - } - - public Entity target() { - return this.target; - } - - public Hand hand() { - return this.hand; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/entity/InteractEntityReturnEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/entity/InteractEntityReturnEvent.java deleted file mode 100644 index c02028c..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/entity/InteractEntityReturnEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -package nl.devpieter.utilize.events.interaction.entity; - -import net.minecraft.entity.Entity; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import nl.devpieter.sees.event.SReturnableEvent; - -public class InteractEntityReturnEvent implements SReturnableEvent { - - private final Entity target; - private final Hand hand; - private ActionResult returnValue; - - public InteractEntityReturnEvent(Entity target, Hand hand, ActionResult returnValue) { - this.target = target; - this.hand = hand; - this.returnValue = returnValue; - } - - public Entity target() { - return this.target; - } - - public Hand hand() { - return this.hand; - } - - @Override - public ActionResult getResult() { - return this.returnValue; - } - - @Override - public void setResult(ActionResult result) { - this.returnValue = result; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/entity/InteractEntityTailEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/entity/InteractEntityTailEvent.java deleted file mode 100644 index 823dec8..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/entity/InteractEntityTailEvent.java +++ /dev/null @@ -1,8 +0,0 @@ -package nl.devpieter.utilize.events.interaction.entity; - -import net.minecraft.entity.Entity; -import net.minecraft.util.Hand; -import nl.devpieter.sees.event.SEvent; - -public record InteractEntityTailEvent(Entity target, Hand hand) implements SEvent { -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/item/InteractItemEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/item/InteractItemEvent.java deleted file mode 100644 index fb8af87..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/item/InteractItemEvent.java +++ /dev/null @@ -1,21 +0,0 @@ -package nl.devpieter.utilize.events.interaction.item; - -import net.minecraft.util.Hand; -import nl.devpieter.sees.event.SCancelableEventBase; - -/** - * It's not recommended to directly cancel this event, as it may cause issues with the game logic. - * Instead, use the {@link nl.devpieter.utilize.events.interaction.keybinding.UseKeyPressedEvent} to directly cancel the use action. - */ -public class InteractItemEvent extends SCancelableEventBase { - - private final Hand hand; - - public InteractItemEvent(Hand hand) { - this.hand = hand; - } - - public Hand hand() { - return this.hand; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/item/InteractItemReturnEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/item/InteractItemReturnEvent.java deleted file mode 100644 index 22d8bbe..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/item/InteractItemReturnEvent.java +++ /dev/null @@ -1,30 +0,0 @@ -package nl.devpieter.utilize.events.interaction.item; - -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import nl.devpieter.sees.event.SReturnableEvent; - -public class InteractItemReturnEvent implements SReturnableEvent { - - private final Hand hand; - private ActionResult returnValue; - - public InteractItemReturnEvent(Hand hand, ActionResult returnValue) { - this.hand = hand; - this.returnValue = returnValue; - } - - public Hand hand() { - return this.hand; - } - - @Override - public ActionResult getResult() { - return this.returnValue; - } - - @Override - public void setResult(ActionResult result) { - this.returnValue = result; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/interaction/item/InteractItemTailEvent.java b/src/main/java/nl/devpieter/utilize/events/interaction/item/InteractItemTailEvent.java deleted file mode 100644 index 913bd5c..0000000 --- a/src/main/java/nl/devpieter/utilize/events/interaction/item/InteractItemTailEvent.java +++ /dev/null @@ -1,8 +0,0 @@ -package nl.devpieter.utilize.events.interaction.item; - -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import nl.devpieter.sees.event.SEvent; - -public record InteractItemTailEvent(Hand hand) implements SEvent { -} diff --git a/src/main/java/nl/devpieter/utilize/events/inventory/HotbarSlotChangedEvent.java b/src/main/java/nl/devpieter/utilize/events/inventory/HotbarSlotChangedEvent.java deleted file mode 100644 index a8e5963..0000000 --- a/src/main/java/nl/devpieter/utilize/events/inventory/HotbarSlotChangedEvent.java +++ /dev/null @@ -1,6 +0,0 @@ -package nl.devpieter.utilize.events.inventory; - -import nl.devpieter.sees.event.SEvent; - -public record HotbarSlotChangedEvent(int previous, int current) implements SEvent { -} diff --git a/src/main/java/nl/devpieter/utilize/events/inventory/SlotClickEvent.java b/src/main/java/nl/devpieter/utilize/events/inventory/SlotClickEvent.java deleted file mode 100644 index 43d3fdf..0000000 --- a/src/main/java/nl/devpieter/utilize/events/inventory/SlotClickEvent.java +++ /dev/null @@ -1,35 +0,0 @@ -package nl.devpieter.utilize.events.inventory; - -import net.minecraft.screen.slot.SlotActionType; -import nl.devpieter.sees.event.SCancelableEventBase; - -public class SlotClickEvent extends SCancelableEventBase { - - private final int syncId; - private final int slotId; - private final int button; - private final SlotActionType actionType; - - public SlotClickEvent(int syncId, int slotId, int button, SlotActionType actionType) { - this.syncId = syncId; - this.slotId = slotId; - this.button = button; - this.actionType = actionType; - } - - public int syncId() { - return syncId; - } - - public int slotId() { - return slotId; - } - - public int button() { - return button; - } - - public SlotActionType actionType() { - return actionType; - } -} diff --git a/src/main/java/nl/devpieter/utilize/events/screen/ScreenChangedEvent.java b/src/main/java/nl/devpieter/utilize/events/screen/ScreenChangedEvent.java deleted file mode 100644 index bf842e3..0000000 --- a/src/main/java/nl/devpieter/utilize/events/screen/ScreenChangedEvent.java +++ /dev/null @@ -1,8 +0,0 @@ -package nl.devpieter.utilize.events.screen; - -import net.minecraft.client.gui.screen.Screen; -import nl.devpieter.sees.event.SEvent; -import org.jetbrains.annotations.Nullable; - -public record ScreenChangedEvent(@Nullable Screen previous, @Nullable Screen current) implements SEvent { -} diff --git a/src/main/java/nl/devpieter/utilize/http/AsyncRequest.java b/src/main/java/nl/devpieter/utilize/http/AsyncRequest.java deleted file mode 100644 index f8b74a5..0000000 --- a/src/main/java/nl/devpieter/utilize/http/AsyncRequest.java +++ /dev/null @@ -1,80 +0,0 @@ -package nl.devpieter.utilize.http; - -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.*; - -public abstract class AsyncRequest extends RequestHelper { - - private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool(); - - private final List> callbacks = new ArrayList<>(); - private CompletableFuture future; - - protected abstract @Nullable T requestAsync() throws Exception; - - public AsyncRequest() { - this(null); - } - - public AsyncRequest(@Nullable ResultConsumer requestCallback) { - if (requestCallback == null) return; - callbacks.add(requestCallback); - } - - public static void shutdown() { - EXECUTOR_SERVICE.shutdown(); - - try { - if (EXECUTOR_SERVICE.awaitTermination(5, TimeUnit.SECONDS)) return; - EXECUTOR_SERVICE.shutdownNow(); - } catch (InterruptedException e) { - EXECUTOR_SERVICE.shutdownNow(); - Thread.currentThread().interrupt(); - } - } - - public void addCallback(@Nullable ResultConsumer callback) { - if (callback == null) return; - callbacks.add(callback); - } - - public void execute() { - if (future != null) return; - - future = CompletableFuture.supplyAsync(() -> { - try { - T result = requestAsync(); - callCallbacks(result, null); - return result; - } catch (Exception e) { - callCallbacks(null, e); - throw new RuntimeException(e); - } - }, EXECUTOR_SERVICE); - } - - public void cancel() { - future.cancel(true); - } - - public boolean isDone() { - return future.isDone(); - } - - public T get() throws ExecutionException, InterruptedException { - return future.get(); - } - - public CompletableFuture getFuture() { - return future; - } - - private void callCallbacks(@Nullable T result, @Nullable Exception exception) { - for (ResultConsumer callback : callbacks) { - if (callback != null) callback.accept(result, exception); - } - } -} \ No newline at end of file diff --git a/src/main/java/nl/devpieter/utilize/http/RequestHelper.java b/src/main/java/nl/devpieter/utilize/http/RequestHelper.java deleted file mode 100644 index 58340a4..0000000 --- a/src/main/java/nl/devpieter/utilize/http/RequestHelper.java +++ /dev/null @@ -1,52 +0,0 @@ -package nl.devpieter.utilize.http; - -import nl.devpieter.utilize.Utilize; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; - -public abstract class RequestHelper { - - public static final String USER_AGENT_HEADER = "User-Agent"; - - protected static final HttpClient CLIENT = HttpClient.newHttpClient(); - - public static @NotNull HttpResponse simpleGet(@NotNull URI uri) throws IOException, InterruptedException { - HttpRequest request = createRequestBuilder(uri).GET().build(); - return CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); - } - - public static @NotNull HttpResponse simplePost(@NotNull URI uri, @NotNull HttpRequest.BodyPublisher bodyPublisher) throws IOException, InterruptedException { - HttpRequest request = createRequestBuilder(uri).POST(bodyPublisher).build(); - return CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); - } - - public static @NotNull HttpResponse simplePut(@NotNull URI uri, @NotNull HttpRequest.BodyPublisher bodyPublisher) throws IOException, InterruptedException { - HttpRequest request = createRequestBuilder(uri).PUT(bodyPublisher).build(); - return CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); - } - - public static @NotNull HttpResponse simpleDelete(@NotNull URI uri) throws IOException, InterruptedException { - HttpRequest request = createRequestBuilder(uri).DELETE().build(); - return CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); - } - - public static HttpRequest.Builder createRequestBuilder(@NotNull URI uri) { - return createRequestBuilder(uri, Utilize.getInstance().getUserAgent()); - } - - /** - * @see Utilize#getUserAgent(String, String) - */ - public static HttpRequest.Builder createRequestBuilder(@NotNull URI uri, @NotNull String userAgent) { - return HttpRequest.newBuilder() - .header(USER_AGENT_HEADER, userAgent) - .header("Content-Type", "application/json") - .header("Accept", "application/json") - .uri(uri); - } -} \ No newline at end of file diff --git a/src/main/java/nl/devpieter/utilize/http/ResultConsumer.java b/src/main/java/nl/devpieter/utilize/http/ResultConsumer.java deleted file mode 100644 index f0e2799..0000000 --- a/src/main/java/nl/devpieter/utilize/http/ResultConsumer.java +++ /dev/null @@ -1,8 +0,0 @@ -package nl.devpieter.utilize.http; - -import org.jetbrains.annotations.Nullable; - -public interface ResultConsumer { - - void accept(@Nullable T result, @Nullable Exception exception); -} \ No newline at end of file diff --git a/src/main/java/nl/devpieter/utilize/internal/models/TextCacheKey.java b/src/main/java/nl/devpieter/utilize/internal/models/TextCacheKey.java deleted file mode 100644 index 6650523..0000000 --- a/src/main/java/nl/devpieter/utilize/internal/models/TextCacheKey.java +++ /dev/null @@ -1,32 +0,0 @@ -package nl.devpieter.utilize.internal.models; - -import net.minecraft.text.Style; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; -import java.util.Objects; - -@ApiStatus.Internal -public record TextCacheKey(String key, Style style, Object[] args) { - - @Override - public boolean equals(Object o) { - if (!(o instanceof TextCacheKey(String key1, Style style1, Object[] args1))) return false; - return Objects.equals(key, key1) && Objects.equals(style, style1) && Objects.deepEquals(args, args1); - } - - @Override - public int hashCode() { - return Objects.hash(key, style, Arrays.hashCode(args)); - } - - @Override - public @NotNull String toString() { - return "TextCacheKey{" + - "key='" + key + '\'' + - ", style=" + style + - ", args=" + Arrays.toString(args) + - '}'; - } -} diff --git a/src/main/java/nl/devpieter/utilize/internal/utils/ColorUtils.java b/src/main/java/nl/devpieter/utilize/internal/utils/ColorUtils.java deleted file mode 100644 index bb1e76d..0000000 --- a/src/main/java/nl/devpieter/utilize/internal/utils/ColorUtils.java +++ /dev/null @@ -1,26 +0,0 @@ -package nl.devpieter.utilize.internal.utils; - -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -@ApiStatus.Internal -public class ColorUtils { - - public static int parseHexColor(@NotNull String hex) { - if (hex.startsWith("#")) hex = hex.substring(1); - - if (hex.length() == 3) { - char r = hex.charAt(0); - char g = hex.charAt(1); - char b = hex.charAt(2); - hex = "" + r + r + g + g + b + b; - } - - return Integer.parseInt(hex, 16); - } - - public static boolean isValidHexColor(@NotNull String hex) { - if (hex.startsWith("#")) hex = hex.substring(1); - return hex.matches("^[0-9a-fA-F]{3}$") || hex.matches("^[0-9a-fA-F]{6}$"); - } -} diff --git a/src/main/java/nl/devpieter/utilize/managers/PacketManager.java b/src/main/java/nl/devpieter/utilize/managers/PacketManager.java index 040b2e8..ee46585 100644 --- a/src/main/java/nl/devpieter/utilize/managers/PacketManager.java +++ b/src/main/java/nl/devpieter/utilize/managers/PacketManager.java @@ -1,7 +1,7 @@ package nl.devpieter.utilize.managers; -import net.minecraft.network.packet.Packet; -import nl.devpieter.utilize.listeners.packet.IPacketListener; +import net.minecraft.network.protocol.Packet; +import nl.devpieter.utilize.packet.IPacketListener; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/nl/devpieter/utilize/mixins/ClientConnectionMixin.java b/src/main/java/nl/devpieter/utilize/mixin/ConnectionMixin.java similarity index 65% rename from src/main/java/nl/devpieter/utilize/mixins/ClientConnectionMixin.java rename to src/main/java/nl/devpieter/utilize/mixin/ConnectionMixin.java index ac769a5..d3ff27d 100644 --- a/src/main/java/nl/devpieter/utilize/mixins/ClientConnectionMixin.java +++ b/src/main/java/nl/devpieter/utilize/mixin/ConnectionMixin.java @@ -1,8 +1,8 @@ -package nl.devpieter.utilize.mixins; +package nl.devpieter.utilize.mixin; -import net.minecraft.network.ClientConnection; -import net.minecraft.network.listener.PacketListener; -import net.minecraft.network.packet.Packet; +import net.minecraft.network.Connection; +import net.minecraft.network.PacketListener; +import net.minecraft.network.protocol.Packet; import nl.devpieter.utilize.managers.PacketManager; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @@ -10,13 +10,13 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(ClientConnection.class) -public class ClientConnectionMixin { +@Mixin(Connection.class) +public class ConnectionMixin { @Unique private static final PacketManager packetManager = PacketManager.getInstance(); - @Inject(at = @At("HEAD"), method = "handlePacket", cancellable = true) + @Inject(at = @At("HEAD"), method = "genericsFtw", cancellable = true) private static void onHandlePacket(Packet packet, PacketListener listener, CallbackInfo ci) { if (packetManager.packetReceived(packet)) ci.cancel(); } diff --git a/src/main/java/nl/devpieter/utilize/mixins/ChatHudMixin.java b/src/main/java/nl/devpieter/utilize/mixins/ChatHudMixin.java deleted file mode 100644 index 8c85c2e..0000000 --- a/src/main/java/nl/devpieter/utilize/mixins/ChatHudMixin.java +++ /dev/null @@ -1,56 +0,0 @@ -package nl.devpieter.utilize.mixins; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.hud.ChatHud; -import net.minecraft.client.gui.hud.ChatHudLine; -import net.minecraft.client.gui.hud.MessageIndicator; -import net.minecraft.network.message.MessageSignatureData; -import net.minecraft.text.Text; -import nl.devpieter.sees.Sees; -import nl.devpieter.utilize.events.chat.ReceiveMessageEvent; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(ChatHud.class) -public abstract class ChatHudMixin { - - @Shadow - @Final - private MinecraftClient client; - - @Shadow - protected abstract void logChatMessage(ChatHudLine message); - - @Shadow - protected abstract void addVisibleMessage(ChatHudLine message); - - @Shadow - protected abstract void addMessage(ChatHudLine message); - - @Unique - private final Sees sees = Sees.getSharedInstance(); - - @Inject(at = @At("HEAD"), method = "addMessage(Lnet/minecraft/text/Text;Lnet/minecraft/network/message/MessageSignatureData;Lnet/minecraft/client/gui/hud/MessageIndicator;)V", cancellable = true) - public void onAddMessage(Text message, MessageSignatureData signatureData, MessageIndicator indicator, CallbackInfo ci) { - ReceiveMessageEvent event = new ReceiveMessageEvent(message); // rename to ChatHudMessageAddEvent, or something similar - Text result = sees.dispatchWithResult(event); - - if (event.isCancelled()) { - ci.cancel(); - return; - } - - // TODO - Optimize - ChatHudLine chatHudLine = new ChatHudLine(client.inGameHud.getTicks(), result, signatureData, indicator); - logChatMessage(chatHudLine); - addVisibleMessage(chatHudLine); - addMessage(chatHudLine); - - ci.cancel(); - } -} diff --git a/src/main/java/nl/devpieter/utilize/mixins/ClientPlayerInteractionManagerMixin.java b/src/main/java/nl/devpieter/utilize/mixins/ClientPlayerInteractionManagerMixin.java deleted file mode 100644 index 0754270..0000000 --- a/src/main/java/nl/devpieter/utilize/mixins/ClientPlayerInteractionManagerMixin.java +++ /dev/null @@ -1,173 +0,0 @@ -package nl.devpieter.utilize.mixins; - -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.network.ClientPlayerInteractionManager; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.screen.slot.SlotActionType; -import net.minecraft.util.ActionResult; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import nl.devpieter.sees.Sees; -import nl.devpieter.utilize.events.interaction.UpdateBlockBreakingProgressEvent; -import nl.devpieter.utilize.events.interaction.block.*; -import nl.devpieter.utilize.events.interaction.entity.*; -import nl.devpieter.utilize.events.interaction.item.InteractItemEvent; -import nl.devpieter.utilize.events.interaction.item.InteractItemReturnEvent; -import nl.devpieter.utilize.events.interaction.item.InteractItemTailEvent; -import nl.devpieter.utilize.events.inventory.HotbarSlotChangedEvent; -import nl.devpieter.utilize.events.inventory.SlotClickEvent; -import nl.devpieter.utilize.utils.minecraft.InventoryUtils; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(ClientPlayerInteractionManager.class) -public abstract class ClientPlayerInteractionManagerMixin { - - @Shadow - public abstract void cancelBlockBreaking(); - - @Unique - private int lastSelectedHotbarSlot = -1; - - @Unique - private final Sees sees = Sees.getSharedInstance(); - - @Inject(at = @At("HEAD"), method = "updateBlockBreakingProgress", cancellable = true) - private void onUpdateBlockBreakingProgress(BlockPos pos, Direction direction, CallbackInfoReturnable cir) { - if (!sees.dispatch(new UpdateBlockBreakingProgressEvent(pos, direction))) return; - - // TODO - Make not cancelable? - - cancelBlockBreaking(); - cir.setReturnValue(false); - } - - @Inject(at = @At("HEAD"), method = "attackBlock", cancellable = true) - private void onAttackBlock(BlockPos pos, Direction direction, CallbackInfoReturnable cir) { - if (!sees.dispatch(new AttackBlockEvent(pos, direction))) return; - - cancelBlockBreaking(); - cir.setReturnValue(false); - } - - @Inject(at = @At("RETURN"), method = "attackBlock", cancellable = true) - private void onAttackBlockReturn(BlockPos pos, Direction direction, CallbackInfoReturnable cir) { - cir.setReturnValue(sees.dispatchWithResult(new AttackBlockReturnEvent(pos, direction, cir.getReturnValue()))); - } - - @Inject(at = @At("TAIL"), method = "attackBlock") - private void onAttackBlockTail(BlockPos pos, Direction direction, CallbackInfoReturnable cir) { - sees.dispatch(new AttackBlockTailEvent(pos, direction)); - } - - @Inject(at = @At("HEAD"), method = "breakBlock", cancellable = true) - private void onBreakBlock(BlockPos pos, CallbackInfoReturnable cir) { - if (!sees.dispatch(new BreakBlockEvent(pos))) return; - - cancelBlockBreaking(); - cir.setReturnValue(false); - } - - @Inject(at = @At("RETURN"), method = "breakBlock", cancellable = true) - private void onBreakBlockReturn(BlockPos pos, CallbackInfoReturnable cir) { - cir.setReturnValue(sees.dispatchWithResult(new BreakBlockReturnEvent(pos, cir.getReturnValue()))); - } - - @Inject(at = @At("TAIL"), method = "breakBlock") - private void onBreakBlockTail(BlockPos pos, CallbackInfoReturnable cir) { - sees.dispatch(new BreakBlockTailEvent(pos)); - } - - @Inject(at = @At("HEAD"), method = "interactBlock", cancellable = true) - private void onInteractBlock(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable cir) { - if (!sees.dispatch(new InteractBlockEvent(hand, hitResult))) return; - cir.setReturnValue(ActionResult.FAIL); - } - - @Inject(at = @At("RETURN"), method = "interactBlock", cancellable = true) - private void onInteractBlockReturn(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable cir) { - cir.setReturnValue(sees.dispatchWithResult(new InteractBlockReturnEvent(hand, hitResult, cir.getReturnValue()))); - } - - @Inject(at = @At("TAIL"), method = "interactBlock") - private void onInteractBlockTail(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable cir) { - sees.dispatch(new InteractBlockTailEvent(hand, hitResult)); - } - - @Inject(at = @At("HEAD"), method = "interactItem", cancellable = true) - private void onInteractItem(PlayerEntity player, Hand hand, CallbackInfoReturnable cir) { - if (!sees.dispatch(new InteractItemEvent(hand))) return; - cir.setReturnValue(ActionResult.FAIL); - } - - @Inject(at = @At("RETURN"), method = "interactItem", cancellable = true) - private void onInteractItemReturn(PlayerEntity player, Hand hand, CallbackInfoReturnable cir) { - cir.setReturnValue(sees.dispatchWithResult(new InteractItemReturnEvent(hand, cir.getReturnValue()))); - } - - @Inject(at = @At("TAIL"), method = "interactItem") - private void onInteractItemTail(PlayerEntity player, Hand hand, CallbackInfoReturnable cir) { - sees.dispatch(new InteractItemTailEvent(hand)); - } - - @Inject(at = @At("HEAD"), method = "attackEntity", cancellable = true) - private void onAttackEntity(PlayerEntity player, Entity target, CallbackInfo ci) { - if (!sees.dispatch(new AttackEntityEvent(target))) return; - ci.cancel(); - } - - @Inject(at = @At("RETURN"), method = "attackEntity") - private void onAttackEntityReturn(PlayerEntity player, Entity target, CallbackInfo ci) { - sees.dispatch(new AttackEntityReturnEvent(target)); - } - - @Inject(at = @At("TAIL"), method = "attackEntity") - private void onAttackEntityTail(PlayerEntity player, Entity target, CallbackInfo ci) { - sees.dispatch(new AttackEntityTailEvent(target)); - } - - @Inject(at = @At("HEAD"), method = "interactEntity", cancellable = true) - private void onInteractEntity(PlayerEntity player, Entity target, Hand hand, CallbackInfoReturnable cir) { - if (!sees.dispatch(new InteractEntityEvent(target, hand))) return; - cir.setReturnValue(ActionResult.FAIL); - } - - @Inject(at = @At("RETURN"), method = "interactEntity", cancellable = true) - private void onInteractEntityReturn(PlayerEntity player, Entity target, Hand hand, CallbackInfoReturnable cir) { - cir.setReturnValue(sees.dispatchWithResult(new InteractEntityReturnEvent(target, hand, cir.getReturnValue()))); - } - - @Inject(at = @At("TAIL"), method = "interactEntity") - private void onInteractEntityTail(PlayerEntity player, Entity target, Hand hand, CallbackInfoReturnable cir) { - sees.dispatch(new InteractEntityTailEvent(target, hand)); - } - - @Inject(at = @At("HEAD"), method = "clickSlot", cancellable = true) - private void onClickSlot(int syncId, int slotId, int button, SlotActionType actionType, PlayerEntity player, CallbackInfo ci) { - if (!sees.dispatch(new SlotClickEvent(syncId, slotId, button, actionType))) return; - ci.cancel(); - } - - @Inject(at = @At("TAIL"), method = "syncSelectedSlot") - private void onSyncSelectedSlot(CallbackInfo ci) { - int slot = InventoryUtils.getSelectedHotbarSlot(); - - if (lastSelectedHotbarSlot == -1) { - lastSelectedHotbarSlot = slot; - return; - } - - if (slot == lastSelectedHotbarSlot) return; - lastSelectedHotbarSlot = slot; - - sees.dispatch(new HotbarSlotChangedEvent(lastSelectedHotbarSlot, slot)); - } -} diff --git a/src/main/java/nl/devpieter/utilize/mixins/SeesMixin.java b/src/main/java/nl/devpieter/utilize/mixins/SeesMixin.java deleted file mode 100644 index d60e598..0000000 --- a/src/main/java/nl/devpieter/utilize/mixins/SeesMixin.java +++ /dev/null @@ -1,32 +0,0 @@ -package nl.devpieter.utilize.mixins; - -import nl.devpieter.sees.Sees; -import nl.devpieter.sees.event.SEvent; -import nl.devpieter.utilize.events.interaction.keybinding.KeyBindingPressedCheckEvent; -import nl.devpieter.utilize.events.tick.ITickEvent; -import nl.devpieter.utilize.utils.minecraft.ClientUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(value = Sees.class, remap = false) -public class SeesMixin { - - @Unique - private final Logger logger = LoggerFactory.getLogger("Utilize/SeesMixin"); - -// @Inject( -// method = "dispatch(Lnl/devpieter/sees/event/SEvent;)Z", -// at = @At("RETURN") -// ) -// private void onDispatch(SEvent event, CallbackInfoReturnable cir) { -// if (event instanceof ITickEvent || event instanceof KeyBindingPressedCheckEvent) return; -// if (!ClientUtils.isDevEnv()) return; -// -// logger.info("Dispatched event: {} (canceled: {})", event.getClass().getSimpleName(), cir.getReturnValue()); -// } -} diff --git a/src/main/java/nl/devpieter/utilize/models/UIdentifier.java b/src/main/java/nl/devpieter/utilize/models/UIdentifier.java deleted file mode 100644 index e3ac253..0000000 --- a/src/main/java/nl/devpieter/utilize/models/UIdentifier.java +++ /dev/null @@ -1,84 +0,0 @@ -package nl.devpieter.utilize.models; - -import net.minecraft.util.Identifier; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; - -public class UIdentifier { - - public static final char NAMESPACE_SEPARATOR = Identifier.NAMESPACE_SEPARATOR; - - public static final String DEFAULT_NAMESPACE = "utilize"; - public static final String VANILLA_NAMESPACE = Identifier.DEFAULT_NAMESPACE; - - private final @Nullable String namespace; - private final @NotNull String path; - - private UIdentifier(@Nullable String namespace, @NotNull String path) { - assert namespace == null || Identifier.isNamespaceValid(namespace); - assert Identifier.isPathValid(path); - - this.namespace = namespace; - this.path = path; - } - - public Identifier toVanilla() { - if (namespace == null) return Identifier.of(DEFAULT_NAMESPACE, path); - return Identifier.of(namespace, path); - } - - public static UIdentifier toUtilize(Identifier identifier) { - return new UIdentifier(identifier.getNamespace(), identifier.getPath()); - } - - public static UIdentifier ofValidated(@Nullable String namespace, @NotNull String path) { - if (namespace != null && !Identifier.isNamespaceValid(namespace)) throw new IllegalArgumentException("Invalid namespace"); - if (!Identifier.isPathValid(path)) throw new IllegalArgumentException("Invalid path"); - - return new UIdentifier(namespace, path); - } - - public static UIdentifier of(@Nullable String namespace, @NotNull String path) { - return ofValidated(namespace, path); - } - - public static UIdentifier of(String namespacePath) { - String[] parts = namespacePath.split(String.valueOf(NAMESPACE_SEPARATOR), 2); - - if (parts.length == 1) return ofNoNamespace(parts[0]); - else return of(parts[0], parts[1]); - } - - public static UIdentifier ofVanilla(String path) { - if (!Identifier.isPathValid(path)) throw new IllegalArgumentException("Invalid path"); - return new UIdentifier(VANILLA_NAMESPACE, path); - } - - public static UIdentifier ofUtilize(String path) { - if (!Identifier.isPathValid(path)) throw new IllegalArgumentException("Invalid path"); - return new UIdentifier(DEFAULT_NAMESPACE, path); - } - - public static UIdentifier ofNoNamespace(String path) { - if (!Identifier.isPathValid(path)) throw new IllegalArgumentException("Invalid path"); - return new UIdentifier(null, path); - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof UIdentifier that)) return false; - return Objects.equals(namespace, that.namespace) && Objects.equals(path, that.path); - } - - @Override - public int hashCode() { - return Objects.hash(namespace, path); - } - - @Override - public String toString() { - return (namespace != null ? namespace + NAMESPACE_SEPARATOR : "") + path; - } -} diff --git a/src/main/java/nl/devpieter/utilize/listeners/packet/IPacketListener.java b/src/main/java/nl/devpieter/utilize/packet/IPacketListener.java similarity index 62% rename from src/main/java/nl/devpieter/utilize/listeners/packet/IPacketListener.java rename to src/main/java/nl/devpieter/utilize/packet/IPacketListener.java index c875652..fd85236 100644 --- a/src/main/java/nl/devpieter/utilize/listeners/packet/IPacketListener.java +++ b/src/main/java/nl/devpieter/utilize/packet/IPacketListener.java @@ -1,6 +1,6 @@ -package nl.devpieter.utilize.listeners.packet; +package nl.devpieter.utilize.packet; -import net.minecraft.network.packet.Packet; +import net.minecraft.network.protocol.Packet; import java.lang.reflect.Type; diff --git a/src/main/java/nl/devpieter/utilize/task/interfaces/ITask.java b/src/main/java/nl/devpieter/utilize/task/interfaces/ITask.java deleted file mode 100644 index b2fd1a0..0000000 --- a/src/main/java/nl/devpieter/utilize/task/interfaces/ITask.java +++ /dev/null @@ -1,8 +0,0 @@ -package nl.devpieter.utilize.task.interfaces; - -import nl.devpieter.utilize.task.TaskManager; - -public interface ITask { - - TaskManager.TickResult tick(); -} diff --git a/src/main/java/nl/devpieter/utilize/text/IText.java b/src/main/java/nl/devpieter/utilize/text/IText.java deleted file mode 100644 index 33525b5..0000000 --- a/src/main/java/nl/devpieter/utilize/text/IText.java +++ /dev/null @@ -1,21 +0,0 @@ -package nl.devpieter.utilize.text; - -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.text.Text; -import org.jetbrains.annotations.NotNull; - -public interface IText { - - Text text(); - - void render(@NotNull DrawContext context, @NotNull TextRenderer textRenderer, int x, int y); - - default int width(@NotNull TextRenderer textRenderer) { - return textRenderer.getWidth(text()); - } - - default int height(@NotNull TextRenderer textRenderer) { - return textRenderer.fontHeight; - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/ITextFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/ITextFormatter.java deleted file mode 100644 index c0652ea..0000000 --- a/src/main/java/nl/devpieter/utilize/text/formatter/ITextFormatter.java +++ /dev/null @@ -1,8 +0,0 @@ -package nl.devpieter.utilize.text.formatter; - -import net.minecraft.text.Style; - -public interface ITextFormatter { - - Style applyFormatting(Style parent); -} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java b/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java deleted file mode 100644 index 651e866..0000000 --- a/src/main/java/nl/devpieter/utilize/text/formatter/TextFormatRegistry.java +++ /dev/null @@ -1,67 +0,0 @@ -package nl.devpieter.utilize.text.formatter; - -import nl.devpieter.utilize.models.UIdentifier; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -public class TextFormatRegistry { - - private static final TextFormatRegistry INSTANCE = new TextFormatRegistry(); - - private final HashMap formatters = new HashMap<>(); - - private Pattern pattern; - private boolean isDirty = true; - - private TextFormatRegistry() { - } - - public static TextFormatRegistry getInstance() { - return INSTANCE; - } - - public void register(@NotNull String namespace, @NotNull String path, @NotNull ITextFormatter formatter) { - register(UIdentifier.of(namespace, path), formatter); - } - - public void register(@NotNull String namespacePath, @NotNull ITextFormatter formatter) { - register(UIdentifier.of(namespacePath), formatter); - } - - public void register(@NotNull UIdentifier identifier, @NotNull ITextFormatter formatter) { - formatters.put(identifier, formatter); - isDirty = true; - } - - public @Nullable ITextFormatter getFormatter(@Nullable UIdentifier identifier) { - if (identifier == null) return null; - return formatters.get(identifier); - } - - public @Nullable ITextFormatter getFormatter(String namespacePath) { - try { - return getFormatter(UIdentifier.of(namespacePath)); - } catch (IllegalArgumentException e) { - return null; - } - } - - public Map getFormatters() { - return new HashMap<>(formatters); - } - - public Pattern getPattern() { - if (!isDirty && pattern != null) return pattern; - - String tagAlternatives = formatters.keySet().stream().map(identifier -> Pattern.quote(identifier.toString())).collect(Collectors.joining("|")); - pattern = Pattern.compile("<(#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6}|" + tagAlternatives + ")>(.*?)", Pattern.DOTALL); - - isDirty = false; - return pattern; - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/ColorFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/ColorFormatter.java deleted file mode 100644 index b2c5a24..0000000 --- a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/ColorFormatter.java +++ /dev/null @@ -1,24 +0,0 @@ -package nl.devpieter.utilize.text.formatter.formatters.color; - -import net.minecraft.text.Style; -import net.minecraft.text.TextColor; -import nl.devpieter.utilize.text.formatter.ITextFormatter; -import org.jetbrains.annotations.NotNull; - -public class ColorFormatter implements ITextFormatter { - - private final TextColor color; - - public ColorFormatter(@NotNull TextColor color) { - this.color = color; - } - - public ColorFormatter(int rgb) { - this.color = TextColor.fromRgb(rgb); - } - - @Override - public Style applyFormatting(Style parent) { - return parent.withColor(color); - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/HexColorFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/HexColorFormatter.java deleted file mode 100644 index edd23d9..0000000 --- a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/color/HexColorFormatter.java +++ /dev/null @@ -1,21 +0,0 @@ -package nl.devpieter.utilize.text.formatter.formatters.color; - -import net.minecraft.text.Style; -import net.minecraft.text.TextColor; -import nl.devpieter.utilize.internal.utils.ColorUtils; -import nl.devpieter.utilize.text.formatter.ITextFormatter; -import org.jetbrains.annotations.NotNull; - -public class HexColorFormatter implements ITextFormatter { - - private final TextColor color; - - public HexColorFormatter(@NotNull String hex) { - this.color = TextColor.fromRgb(ColorUtils.parseHexColor(hex)); - } - - @Override - public Style applyFormatting(Style parent) { - return parent.withColor(color); - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/BoldFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/BoldFormatter.java deleted file mode 100644 index 44e059e..0000000 --- a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/BoldFormatter.java +++ /dev/null @@ -1,12 +0,0 @@ -package nl.devpieter.utilize.text.formatter.formatters.format; - -import net.minecraft.text.Style; -import nl.devpieter.utilize.text.formatter.ITextFormatter; - -public class BoldFormatter implements ITextFormatter { - - @Override - public Style applyFormatting(Style parent) { - return parent.withBold(true); - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ItalicFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ItalicFormatter.java deleted file mode 100644 index e687aa2..0000000 --- a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ItalicFormatter.java +++ /dev/null @@ -1,12 +0,0 @@ -package nl.devpieter.utilize.text.formatter.formatters.format; - -import net.minecraft.text.Style; -import nl.devpieter.utilize.text.formatter.ITextFormatter; - -public class ItalicFormatter implements ITextFormatter { - - @Override - public Style applyFormatting(Style parent) { - return parent.withItalic(true); - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ObfuscatedFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ObfuscatedFormatter.java deleted file mode 100644 index fc9b65c..0000000 --- a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/ObfuscatedFormatter.java +++ /dev/null @@ -1,12 +0,0 @@ -package nl.devpieter.utilize.text.formatter.formatters.format; - -import net.minecraft.text.Style; -import nl.devpieter.utilize.text.formatter.ITextFormatter; - -public class ObfuscatedFormatter implements ITextFormatter { - - @Override - public Style applyFormatting(Style parent) { - return parent.withObfuscated(true); - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/StrikethroughFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/StrikethroughFormatter.java deleted file mode 100644 index 82ed9ad..0000000 --- a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/StrikethroughFormatter.java +++ /dev/null @@ -1,12 +0,0 @@ -package nl.devpieter.utilize.text.formatter.formatters.format; - -import net.minecraft.text.Style; -import nl.devpieter.utilize.text.formatter.ITextFormatter; - -public class StrikethroughFormatter implements ITextFormatter { - - @Override - public Style applyFormatting(Style parent) { - return parent.withStrikethrough(true); - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/UnderlineFormatter.java b/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/UnderlineFormatter.java deleted file mode 100644 index 4a82bd5..0000000 --- a/src/main/java/nl/devpieter/utilize/text/formatter/formatters/format/UnderlineFormatter.java +++ /dev/null @@ -1,12 +0,0 @@ -package nl.devpieter.utilize.text.formatter.formatters.format; - -import net.minecraft.text.Style; -import nl.devpieter.utilize.text.formatter.ITextFormatter; - -public class UnderlineFormatter implements ITextFormatter { - - @Override - public Style applyFormatting(Style parent) { - return parent.withUnderline(true); - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/formatter/utils/TextFormatUtils.java b/src/main/java/nl/devpieter/utilize/text/formatter/utils/TextFormatUtils.java deleted file mode 100644 index 753540c..0000000 --- a/src/main/java/nl/devpieter/utilize/text/formatter/utils/TextFormatUtils.java +++ /dev/null @@ -1,72 +0,0 @@ -package nl.devpieter.utilize.text.formatter.utils; - -import net.minecraft.text.MutableText; -import net.minecraft.text.Style; -import net.minecraft.text.Text; -import nl.devpieter.utilize.internal.utils.ColorUtils; -import nl.devpieter.utilize.text.formatter.ITextFormatter; -import nl.devpieter.utilize.text.formatter.TextFormatRegistry; -import nl.devpieter.utilize.text.formatter.formatters.color.HexColorFormatter; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class TextFormatUtils { - - private static final TextFormatRegistry REGISTRY = TextFormatRegistry.getInstance(); - - private TextFormatUtils() { - } - - public static MutableText format(String key, Style style, Object... args) { - String raw = Text.translatable(key, args).getString(); - return formatRecursive(raw, style, 0, 20); - } - - public static MutableText formatWithDepth(String key, Style style, int maxDepth, Object... args) { - String raw = Text.translatable(key, args).getString(); - return formatRecursive(raw, style, 0, maxDepth); - } - - private static MutableText formatRecursive(String raw, Style style, int depth, int maxDepth) { - if (depth > maxDepth) return Text.literal(raw).setStyle(style); - - Pattern pattern = REGISTRY.getPattern(); - MutableText result = Text.empty(); - - int lastIndex = 0; - Matcher matcher = pattern.matcher(raw); - - while (matcher.find()) { - if (matcher.start() < lastIndex) continue; - - if (matcher.start() > lastIndex) { - result.append(Text.literal(raw.substring(lastIndex, matcher.start())).setStyle(style)); - } - - String tag = matcher.group(1); - String content = matcher.group(2); - - ITextFormatter formatter = REGISTRY.getFormatter(tag); - - if (formatter == null - && tag.startsWith("#") - && ColorUtils.isValidHexColor(tag) - ) formatter = new HexColorFormatter(tag); - - if (formatter != null) { - result.append(formatRecursive(content, formatter.applyFormatting(style), depth + 1, maxDepth)); - } else { - result.append(Text.literal(matcher.group(0)).setStyle(style)); - } - - lastIndex = matcher.end(); - } - - if (lastIndex < raw.length()) { - result.append(Text.literal(raw.substring(lastIndex)).setStyle(style)); - } - - return result; - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/helpers/TextCacheHelper.java b/src/main/java/nl/devpieter/utilize/text/helpers/TextCacheHelper.java deleted file mode 100644 index 1e44786..0000000 --- a/src/main/java/nl/devpieter/utilize/text/helpers/TextCacheHelper.java +++ /dev/null @@ -1,26 +0,0 @@ -package nl.devpieter.utilize.text.helpers; - -import net.minecraft.text.MutableText; -import net.minecraft.text.Style; -import nl.devpieter.utilize.internal.models.TextCacheKey; -import nl.devpieter.utilize.text.formatter.utils.TextFormatUtils; - -import java.util.HashMap; - -public class TextCacheHelper { - - private final HashMap cache = new HashMap<>(); - - public void clear() { - cache.clear(); - } - - public boolean contains(String key, Style style, Object... args) { - return cache.containsKey(new TextCacheKey(key, style, args)); - } - - public MutableText getFormatted(String key, Style style, Object... args) { - TextCacheKey cacheKey = new TextCacheKey(key, style, args); - return cache.computeIfAbsent(cacheKey, k -> TextFormatUtils.format(k.key(), k.style(), k.args())); - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/helpers/TextDrawerHelper.java b/src/main/java/nl/devpieter/utilize/text/helpers/TextDrawerHelper.java deleted file mode 100644 index 18b9ea2..0000000 --- a/src/main/java/nl/devpieter/utilize/text/helpers/TextDrawerHelper.java +++ /dev/null @@ -1,83 +0,0 @@ -package nl.devpieter.utilize.text.helpers; - -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.text.Text; -import nl.devpieter.utilize.text.IText; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -public class TextDrawerHelper { - - public void drawDynamicBox(@NotNull DrawContext context, @NotNull TextRenderer textRenderer, int x, int y, int color, List lines) { - drawDynamicBox(context, textRenderer, x, y, color, null, lines); - } - - public void drawDynamicBox(@NotNull DrawContext context, @NotNull TextRenderer textRenderer, int x, int y, int color, @Nullable Text title, List lines) { - int titleHeight = title != null ? textRenderer.fontHeight + 8 : 0; - int boxPadding = 10; - - int boxWidth = calculateBoxWidth(textRenderer, title, lines); - int boxHeight = calculateBoxHeight(textRenderer, title, lines); - - // Draw background - context.fill(x, y, x + boxWidth, y + boxHeight, color); - - int textX = x + boxPadding; - int textY = y + boxPadding; - - // Draw title - if (title != null) { - context.drawTextWithShadow(textRenderer, title, textX, textY, 0xFFFFFFFF); - textY += titleHeight; - } - - // Draw lines - for (IText line : lines) { - line.render(context, textRenderer, textX, textY); - textY += line.height(textRenderer); - } - } - - public int getLargestLineWidth(@NotNull TextRenderer textRenderer, List lines) { - return getLargestLineWidth(textRenderer, null, lines); - } - - public int getLargestLineWidth(@NotNull TextRenderer textRenderer, @Nullable Text title, List lines) { - int largestTextWidth = 0; - if (title != null) largestTextWidth = textRenderer.getWidth(title); - - for (IText line : lines) { - int lineWidth = line.width(textRenderer); - if (lineWidth > largestTextWidth) largestTextWidth = lineWidth; - } - - return largestTextWidth; - } - - public int calculateBoxWidth(@NotNull TextRenderer textRenderer, List lines) { - return calculateBoxWidth(textRenderer, null, lines); - } - - public int calculateBoxWidth(@NotNull TextRenderer textRenderer, @Nullable Text title, List lines) { - int largestTextWidth = getLargestLineWidth(textRenderer, title, lines); - - int boxPadding = 10; - return largestTextWidth + (boxPadding * 2); - } - - public int calculateBoxHeight(@NotNull TextRenderer textRenderer, List lines) { - return calculateBoxHeight(textRenderer, null, lines); - } - - public int calculateBoxHeight(@NotNull TextRenderer textRenderer, @Nullable Text title, List lines) { - int boxHeight = 0; - for (IText line : lines) boxHeight += line.height(textRenderer); - - int titleHeight = title != null ? textRenderer.fontHeight + 8 : 0; - int boxPadding = 10; - return boxHeight + titleHeight + (boxPadding * 2) - 4; - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/texts/ItemStackText.java b/src/main/java/nl/devpieter/utilize/text/texts/ItemStackText.java deleted file mode 100644 index 41e4a40..0000000 --- a/src/main/java/nl/devpieter/utilize/text/texts/ItemStackText.java +++ /dev/null @@ -1,87 +0,0 @@ -package nl.devpieter.utilize.text.texts; - -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.item.ItemStack; -import net.minecraft.text.Style; -import net.minecraft.text.Text; -import nl.devpieter.utilize.text.IText; -import nl.devpieter.utilize.text.formatter.utils.TextFormatUtils; -import nl.devpieter.utilize.text.helpers.TextCacheHelper; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class ItemStackText implements IText { - - public static ItemStackText of(ItemStack stack, Text text) { - return new ItemStackText(stack, text); - } - - public static ItemStackText of(ItemStack stack, String text) { - return new ItemStackText(stack, Text.of(text)); - } - - public static ItemStackText off(ItemStack stack, String key, Style style, Object... args) { - return off(null, stack, key, style, args); - } - - public static ItemStackText off(@Nullable TextCacheHelper cache, ItemStack stack, String key, Style style, Object... args) { - if (cache == null) return new ItemStackText(stack, TextFormatUtils.format(key, style, args)); - return new ItemStackText(stack, cache.getFormatted(key, style, args)); - } - - private final ItemStack stack; - private final Text text; - - private int xPadding; - private int yPadding; - - public ItemStackText(ItemStack stack, Text text) { - this.stack = stack; - this.text = text; - - this.xPadding = 0; - this.yPadding = 4; - } - - @Override - public Text text() { - return text; - } - - public ItemStack stack() { - return stack; - } - - @Override - public void render(@NotNull DrawContext context, @NotNull TextRenderer textRenderer, int x, int y) { - context.drawItem(stack(), x - 4, y - 4); - context.drawTextWithShadow(textRenderer, text(), x + 14, y + 2, 0xFFFFFFFF); - } - - @Override - public int width(@NotNull TextRenderer textRenderer) { - return IText.super.width(textRenderer) + 14 + xPadding; - } - - @Override - public int height(@NotNull TextRenderer textRenderer) { - return IText.super.height(textRenderer) + 2 + yPadding; - } - - public ItemStackText padding(int xPadding, int yPadding) { - this.xPadding = xPadding; - this.yPadding = yPadding; - return this; - } - - public ItemStackText xPadding(int xPadding) { - this.xPadding = xPadding; - return this; - } - - public ItemStackText yPadding(int yPadding) { - this.yPadding = yPadding; - return this; - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/texts/TextLine.java b/src/main/java/nl/devpieter/utilize/text/texts/TextLine.java deleted file mode 100644 index b0f8377..0000000 --- a/src/main/java/nl/devpieter/utilize/text/texts/TextLine.java +++ /dev/null @@ -1,83 +0,0 @@ -package nl.devpieter.utilize.text.texts; - -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.text.Style; -import net.minecraft.text.Text; -import nl.devpieter.utilize.text.IText; -import nl.devpieter.utilize.text.formatter.utils.TextFormatUtils; -import nl.devpieter.utilize.text.helpers.TextCacheHelper; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class TextLine implements IText { - - public static TextLine of(Text text) { - return new TextLine(text); - } - - public static TextLine of(String text) { - return TextLine.of(Text.of(text)); - } - - public static TextLine off(String key, Style style, Object... args) { - return off(null, key, style, args); - } - - public static TextLine off(@Nullable TextCacheHelper cache, String key, Style style, Object... args) { - if (cache == null) return TextLine.of(TextFormatUtils.format(key, style, args)); - return TextLine.of(cache.getFormatted(key, style, args)); - } - - public static TextLine empty() { - return TextLine.of(Text.empty()); - } - - private final Text text; - - private int xPadding; - private int yPadding; - - public TextLine(Text text) { - this.text = text; - - this.xPadding = 0; - this.yPadding = 4; - } - - @Override - public Text text() { - return text; - } - - @Override - public void render(@NotNull DrawContext context, @NotNull TextRenderer textRenderer, int x, int y) { - context.drawTextWithShadow(textRenderer, text(), x, y, 0xFFFFFFFF); - } - - @Override - public int width(@NotNull TextRenderer textRenderer) { - return IText.super.width(textRenderer) + xPadding; - } - - @Override - public int height(@NotNull TextRenderer textRenderer) { - return IText.super.height(textRenderer) + yPadding; - } - - public TextLine padding(int xPadding, int yPadding) { - this.xPadding = xPadding; - this.yPadding = yPadding; - return this; - } - - public TextLine xPadding(int xPadding) { - this.xPadding = xPadding; - return this; - } - - public TextLine yPadding(int yPadding) { - this.yPadding = yPadding; - return this; - } -} diff --git a/src/main/java/nl/devpieter/utilize/text/texts/TextSpacer.java b/src/main/java/nl/devpieter/utilize/text/texts/TextSpacer.java deleted file mode 100644 index ba24b13..0000000 --- a/src/main/java/nl/devpieter/utilize/text/texts/TextSpacer.java +++ /dev/null @@ -1,70 +0,0 @@ -package nl.devpieter.utilize.text.texts; - -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.text.Text; -import nl.devpieter.utilize.text.IText; -import org.jetbrains.annotations.NotNull; - -public class TextSpacer implements IText { - - public static TextSpacer of(int width, int height) { - return new TextSpacer(width, height); - } - - public static TextSpacer of(int height) { - return new TextSpacer(0, height); - } - - public static TextSpacer ofWidth(int width) { - return new TextSpacer(width, 0); - } - - public static TextSpacer ofHeight(int height) { - return new TextSpacer(0, height); - } - - private int width; - private int height; - - public TextSpacer(int width, int height) { - this.width = width; - this.height = height; - } - - @Override - public Text text() { - return Text.empty(); - } - - @Override - public void render(@NotNull DrawContext context, @NotNull TextRenderer textRenderer, int x, int y) { - context.drawTextWithShadow(textRenderer, text(), x, y, 0xFFFFFFFF); - } - - @Override - public int width(@NotNull TextRenderer textRenderer) { - return width; - } - - @Override - public int height(@NotNull TextRenderer textRenderer) { - return height; - } - - public TextSpacer dimensions(int width, int height) { - this.width = width; - this.height = height; - return this; - } - - public TextSpacer width(int width) { - this.width = width; - return this; - } - - public TextSpacer height(int height) { - this.height = height; - return this; - } -} diff --git a/src/main/java/nl/devpieter/utilize/utils/common/MathUtils.java b/src/main/java/nl/devpieter/utilize/utils/common/MathUtils.java index a79bb51..30a2b45 100644 --- a/src/main/java/nl/devpieter/utilize/utils/common/MathUtils.java +++ b/src/main/java/nl/devpieter/utilize/utils/common/MathUtils.java @@ -1,10 +1,5 @@ package nl.devpieter.utilize.utils.common; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.Vec3i; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - import java.time.Duration; public final class MathUtils { @@ -24,16 +19,6 @@ public static int durationToTicks(Duration duration) { return (int) (duration.toMillis() / 50); } - @Contract("_ -> new") - public static @NotNull Vec3d from(@NotNull Vec3i vec3i) { - return new Vec3d(vec3i.getX(), vec3i.getY(), vec3i.getZ()); - } - - @Contract("_ -> new") - public static @NotNull Vec3i from(@NotNull Vec3d vec3d) { - return new Vec3i((int) vec3d.getX(), (int) vec3d.getY(), (int) vec3d.getZ()); - } - public static double notNegative(double value) { return Math.max(0, value); } diff --git a/src/main/java/nl/devpieter/utilize/utils/minecraft/ClientUtils.java b/src/main/java/nl/devpieter/utilize/utils/minecraft/ClientUtils.java deleted file mode 100644 index a50737d..0000000 --- a/src/main/java/nl/devpieter/utilize/utils/minecraft/ClientUtils.java +++ /dev/null @@ -1,63 +0,0 @@ -package nl.devpieter.utilize.utils.minecraft; - -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.network.ClientPlayerInteractionManager; -import net.minecraft.client.sound.SoundManager; -import net.minecraft.client.world.ClientWorld; - -public final class ClientUtils { - - private ClientUtils() { - } - - public static boolean isDevEnv() { - return FabricLoader.getInstance().isDevelopmentEnvironment(); - } - - public static MinecraftClient getClient() { - return MinecraftClient.getInstance(); - } - - public static boolean hasPlayer() { - return getClient().player != null; - } - - public static ClientPlayerEntity getPlayer() { - return getClient().player; - } - - public static boolean hasWorld() { - return getClient().world != null; - } - - public static ClientWorld getWorld() { - return getClient().world; - } - - public static boolean hasSoundManager() { - return getClient().getSoundManager() != null; - } - - public static SoundManager getSoundManager() { - return getClient().getSoundManager(); - } - - public static boolean hasNetworkHandler() { - return getClient().getNetworkHandler() != null; - } - - public static ClientPlayNetworkHandler getNetworkHandler() { - return getClient().getNetworkHandler(); - } - - public static boolean hasInteractionManager() { - return getClient().interactionManager != null; - } - - public static ClientPlayerInteractionManager getInteractionManager() { - return getClient().interactionManager; - } -} diff --git a/src/main/java/nl/devpieter/utilize/utils/minecraft/EnchantmentUtils.java b/src/main/java/nl/devpieter/utilize/utils/minecraft/EnchantmentUtils.java deleted file mode 100644 index b17db70..0000000 --- a/src/main/java/nl/devpieter/utilize/utils/minecraft/EnchantmentUtils.java +++ /dev/null @@ -1,70 +0,0 @@ -package nl.devpieter.utilize.utils.minecraft; - -import net.minecraft.component.type.ItemEnchantmentsComponent; -import net.minecraft.enchantment.Enchantment; -import net.minecraft.enchantment.EnchantmentHelper; -import net.minecraft.item.ItemStack; -import net.minecraft.registry.RegistryKey; -import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.registry.tag.EnchantmentTags; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Set; - -public final class EnchantmentUtils { - - private EnchantmentUtils() { - } - - public static boolean isMaxLevel(@NotNull RegistryEntry enchantment, int level) { - return level == enchantment.value().getMaxLevel(); - } - - public static boolean isAboveMaxLevel(@NotNull RegistryEntry enchantment, int level) { - return level > enchantment.value().getMaxLevel(); - } - - public static boolean isCurse(@NotNull RegistryEntry enchantment) { - return enchantment.isIn(EnchantmentTags.CURSE); - } - - public static boolean hasEnchantments(ItemStack stack) { - return EnchantmentHelper.hasEnchantments(stack); - } - - public static boolean hasEnchantment(@Nullable ItemStack stack, @NotNull RegistryEntry enchantment) { - if (stack == null || !hasEnchantments(stack)) return false; - - Set> enchantments = getEnchantments(stack); - return enchantments.stream().anyMatch(entry -> entry == enchantment); - } - - public static boolean hasEnchantment(@Nullable ItemStack stack, @NotNull RegistryKey enchantment) { - if (stack == null || !hasEnchantments(stack)) return false; - - Set> enchantments = getEnchantments(stack); - return enchantments.stream().anyMatch(entry -> entry.matchesKey(enchantment)); - } - - public static void forEachEnchantment(@NotNull ItemStack stack, @NotNull Consumer consumer) { - ItemEnchantmentsComponent component = getComponent(stack); - Set> enchantments = getEnchantments(stack); - - for (RegistryEntry enchantment : enchantments) { - consumer.accept(enchantment, component.getLevel(enchantment)); - } - } - - public static ItemEnchantmentsComponent getComponent(@NotNull ItemStack stack) { - return EnchantmentHelper.getEnchantments(stack); - } - - public static Set> getEnchantments(@NotNull ItemStack stack) { - return getComponent(stack).getEnchantments(); - } - - public interface Consumer { - void accept(RegistryEntry enchantment, int level); - } -} diff --git a/src/main/java/nl/devpieter/utilize/utils/minecraft/InteractionUtils.java b/src/main/java/nl/devpieter/utilize/utils/minecraft/InteractionUtils.java deleted file mode 100644 index c17d3af..0000000 --- a/src/main/java/nl/devpieter/utilize/utils/minecraft/InteractionUtils.java +++ /dev/null @@ -1,14 +0,0 @@ -package nl.devpieter.utilize.utils.minecraft; - -import net.minecraft.screen.slot.SlotActionType; - -public final class InteractionUtils { - - private InteractionUtils() { - } - - public static void clickInventorySlot(int syncId, int packetSlot, int button, SlotActionType actionType) { - if (!ClientUtils.hasInteractionManager() || !ClientUtils.hasPlayer()) return; - ClientUtils.getInteractionManager().clickSlot(syncId, packetSlot, button, actionType, ClientUtils.getPlayer()); - } -} diff --git a/src/main/java/nl/devpieter/utilize/utils/minecraft/InventoryUtils.java b/src/main/java/nl/devpieter/utilize/utils/minecraft/InventoryUtils.java deleted file mode 100644 index 406f430..0000000 --- a/src/main/java/nl/devpieter/utilize/utils/minecraft/InventoryUtils.java +++ /dev/null @@ -1,99 +0,0 @@ -package nl.devpieter.utilize.utils.minecraft; - -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; -import net.minecraft.screen.slot.SlotActionType; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -public final class InventoryUtils { - - private InventoryUtils() { - } - - public static boolean hasInventory() { - return ClientUtils.hasPlayer() && ClientUtils.getPlayer().getInventory() != null; - } - - public static @Nullable PlayerInventory getInventory() { - if (!ClientUtils.hasPlayer()) return null; - return ClientUtils.getPlayer().getInventory(); - } - - public static boolean isMainHandOf(@Nullable Item item) { - if (item == null || !hasInventory()) return false; - - ItemStack mainHand = getMainHand(); - return mainHand != null && mainHand.isOf(item); - } - - public static @Nullable ItemStack getMainHand() { - if (!hasInventory()) return null; - return ClientUtils.getPlayer().getMainHandStack(); - } - - public static boolean isOffhandOf(@Nullable Item item) { - if (item == null || !hasInventory()) return false; - - ItemStack offhand = getOffhand(); - return offhand != null && offhand.isOf(item); - } - - public static @Nullable ItemStack getOffhand() { - if (!hasInventory()) return null; - return ClientUtils.getPlayer().getOffHandStack(); - } - - public static void selectHotbarSlot(int slot) { - if (slot < 0 || slot > 8 || !hasInventory()) return; - getInventory().setSelectedSlot(slot); - } - - public static int getSelectedHotbarSlot() { - if (!hasInventory()) return -1; - return getInventory().getSelectedSlot(); - } - - public static @NotNull List findHotbarSlots(@Nullable Item item) { - if (item == null || !hasInventory()) return new ArrayList<>(); - - PlayerInventory inventory = getInventory(); - List slots = new ArrayList<>(); - - for (int i = 0; i < 9; i++) { - ItemStack stack = inventory.getStack(i); - if (stack.isOf(item)) slots.add(i); - } - - return slots; - } - - public static int countItem(@Nullable Item item) { - if (item == null || !hasInventory()) return -1; - PlayerInventory inventory = getInventory(); - - int count = 0; - - for (int i = 0; i < inventory.size(); i++) { - ItemStack stack = inventory.getStack(i); - if (stack.isOf(item)) count += stack.getCount(); - } - - return count; - } - - public static void clickSlot(int syncId, int packetSlot, int button, SlotActionType actionType) { - InteractionUtils.clickInventorySlot(syncId, packetSlot, button, actionType); - } - - public static void swapItemWithOffhand() { - NetworkUtils.sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN)); - } -} diff --git a/src/main/java/nl/devpieter/utilize/utils/minecraft/NetworkUtils.java b/src/main/java/nl/devpieter/utilize/utils/minecraft/NetworkUtils.java deleted file mode 100644 index e3ae13f..0000000 --- a/src/main/java/nl/devpieter/utilize/utils/minecraft/NetworkUtils.java +++ /dev/null @@ -1,29 +0,0 @@ -package nl.devpieter.utilize.utils.minecraft; - -import net.minecraft.network.packet.Packet; -import org.jetbrains.annotations.NotNull; - -public final class NetworkUtils { - - private NetworkUtils() { - } - - public static void sendPacket(@NotNull Packet packet) { - if (!ClientUtils.hasNetworkHandler()) return; - ClientUtils.getNetworkHandler().sendPacket(packet); - } - - public static void sendChatMessage(@NotNull String message) { - if (!ClientUtils.hasNetworkHandler()) return; - - if (message.startsWith("/")) sendChatCommand(message); - else ClientUtils.getNetworkHandler().sendChatMessage(message); - } - - public static void sendChatCommand(@NotNull String command) { - if (!ClientUtils.hasNetworkHandler()) return; - if (command.startsWith("/")) command = command.substring(1); - - ClientUtils.getNetworkHandler().sendChatCommand(command); - } -} diff --git a/src/main/java/nl/devpieter/utilize/utils/minecraft/PlayerUtils.java b/src/main/java/nl/devpieter/utilize/utils/minecraft/PlayerUtils.java deleted file mode 100644 index 9f5bb71..0000000 --- a/src/main/java/nl/devpieter/utilize/utils/minecraft/PlayerUtils.java +++ /dev/null @@ -1,52 +0,0 @@ -package nl.devpieter.utilize.utils.minecraft; - -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.text.Text; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.HitResult; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public final class PlayerUtils { - - private PlayerUtils() { - } - - public static void sendMessage(@NotNull Text message, boolean overlay) { - if (!ClientUtils.hasPlayer()) return; - ClientUtils.getPlayer().sendMessage(message, overlay); - } - - public static @Nullable HitResult getHitResult() { - if (!ClientUtils.hasPlayer()) return null; - - HitResult result = ClientUtils.getClient().crosshairTarget; - if (!(result instanceof HitResult hitResult)) return null; - - return hitResult; - } - - public static @Nullable BlockHitResult getBlockHitResult() { - if (!ClientUtils.hasPlayer()) return null; - - HitResult result = ClientUtils.getClient().crosshairTarget; - if (!(result instanceof BlockHitResult blockHitResult)) return null; - - return blockHitResult; - } - - public static @Nullable Block getTargetedBlock() { - BlockState blockState = getTargetedBlockState(); - if (blockState == null) return null; - - return blockState.getBlock(); - } - - public static @Nullable BlockState getTargetedBlockState() { - BlockHitResult blockHitResult = getBlockHitResult(); - if (blockHitResult == null) return null; - - return ClientUtils.getWorld().getBlockState(blockHitResult.getBlockPos()); - } -} diff --git a/src/main/java/nl/devpieter/utilize/utils/minecraft/SoundUtils.java b/src/main/java/nl/devpieter/utilize/utils/minecraft/SoundUtils.java deleted file mode 100644 index f1b533e..0000000 --- a/src/main/java/nl/devpieter/utilize/utils/minecraft/SoundUtils.java +++ /dev/null @@ -1,29 +0,0 @@ -package nl.devpieter.utilize.utils.minecraft; - -import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.sound.SoundInstance; -import net.minecraft.sound.SoundEvent; -import org.jetbrains.annotations.NotNull; - -public final class SoundUtils { - - private SoundUtils() { - } - - public static void playOnMaster(@NotNull SoundEvent soundEvent) { - playOnMaster(soundEvent, 1.0F, 1.0F); - } - - public static void playOnMaster(@NotNull SoundEvent soundEvent, float pitch) { - playOnMaster(soundEvent, pitch, 1.0F); - } - - public static void playOnMaster(@NotNull SoundEvent soundEvent, float pitch, float volume) { - play(PositionedSoundInstance.master(soundEvent, pitch, volume)); - } - - public static void play(@NotNull SoundInstance soundInstance) { - if (!ClientUtils.hasSoundManager()) return; - ClientUtils.getSoundManager().play(soundInstance); - } -} diff --git a/src/main/java/nl/devpieter/utilize/utils/minecraft/TextUtils.java b/src/main/java/nl/devpieter/utilize/utils/minecraft/TextUtils.java deleted file mode 100644 index 72603bd..0000000 --- a/src/main/java/nl/devpieter/utilize/utils/minecraft/TextUtils.java +++ /dev/null @@ -1,32 +0,0 @@ -package nl.devpieter.utilize.utils.minecraft; - -import net.minecraft.text.MutableText; -import net.minecraft.text.Style; -import net.minecraft.text.Text; -import org.jetbrains.annotations.NotNull; - -public final class TextUtils { - - private TextUtils() { - } - - public static MutableText currentOrDefaultStyle(@NotNull Text text, @NotNull Style defaultStyle) { - return Text.of("").copy().setStyle(defaultStyle).append(text); - } - - public static MutableText withStyle(@NotNull String text, @NotNull Style style) { - return withStyle(Text.of(text), style); - } - - public static MutableText withStyle(@NotNull Text text, @NotNull Style style) { - return text.copy().setStyle(style); - } - - public static MutableText clearStyle(@NotNull String text) { - return clearStyle(Text.of(text)); - } - - public static MutableText clearStyle(@NotNull Text text) { - return text.copy().setStyle(Style.EMPTY); - } -} \ No newline at end of file diff --git a/src/main/java/nl/devpieter/utilize/utils/minecraft/WorldUtils.java b/src/main/java/nl/devpieter/utilize/utils/minecraft/WorldUtils.java deleted file mode 100644 index bac83d7..0000000 --- a/src/main/java/nl/devpieter/utilize/utils/minecraft/WorldUtils.java +++ /dev/null @@ -1,50 +0,0 @@ -package nl.devpieter.utilize.utils.minecraft; - -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.entity.Entity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.Vec3i; -import nl.devpieter.utilize.utils.common.MathUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public final class WorldUtils { - - private WorldUtils() { - } - - public static @Nullable BlockState getStateAt(@NotNull Vec3d vec3d) { - return getStateAt(MathUtils.from(vec3d)); - } - - public static @Nullable BlockState getStateAt(@NotNull Vec3i vec3i) { - return getStateAt(new BlockPos(vec3i)); - } - - public static @Nullable BlockState getStateAt(@NotNull BlockPos pos) { - if (!ClientUtils.hasWorld()) return null; - return ClientUtils.getWorld().getBlockState(pos); - } - - public static @Nullable Block getBlockAt(@NotNull Vec3d vec3d) { - return getBlockAt(MathUtils.from(vec3d)); - } - - public static @Nullable Block getBlockAt(@NotNull Vec3i vec3i) { - return getBlockAt(new BlockPos(vec3i)); - } - - public static @Nullable Block getBlockAt(@NotNull BlockPos pos) { - BlockState state = getStateAt(pos); - if (state == null) return null; - - return state.getBlock(); - } - - public static @Nullable Entity getEntity(int id) { - if (!ClientUtils.hasWorld()) return null; - return ClientUtils.getWorld().getEntityById(id); - } -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 9f84965..6734d73 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -3,36 +3,30 @@ "id": "utilize", "version": "${version}", "name": "Utilize", - "description": "Yet another Minecraft modding library, made for DevPieter's mods.", - "authors": [ - "DevPieter" - ], - "contact": { - "homepage": "https://pietr.space/", - "sources": "https://github.com/DevPieter/Utilize", - "issues": "https://github.com/DevPieter/Utilize/issues" - }, + "description": "todo", + "authors": [], + "contact": {}, "license": "MIT", "icon": "assets/utilize/icon.png", - "environment": "client", + "environment": "*", "entrypoints": { "client": [ + "nl.devpieter.utilize.client.UtilizeClient" + ], + "main": [ "nl.devpieter.utilize.Utilize" ] }, "mixins": [ - "utilize.mixins.json" + "utilize.mixins.json", + { + "config": "utilize.client.mixins.json", + "environment": "client" + } ], "depends": { "fabricloader": ">=${loader_version}", - "fabric": "*", - "minecraft": ">=${minecraft_version} <=${max_minecraft_version}" - }, - "custom": { - "modmenu": { - "badges": [ - "library" - ] - } + "fabric-api": "*", + "minecraft": "${minecraft_version}" } } diff --git a/src/main/resources/utilize.mixins.json b/src/main/resources/utilize.mixins.json index 4140fc6..dd7c1c8 100644 --- a/src/main/resources/utilize.mixins.json +++ b/src/main/resources/utilize.mixins.json @@ -1,20 +1,15 @@ { "required": true, "minVersion": "0.8", - "package": "nl.devpieter.utilize.mixins", - "compatibilityLevel": "JAVA_21", - "client": [ - "ChatHudMixin", - "ClientPlayerEntityMixin", - "ClientPlayerInteractionManagerMixin", - "KeyBindingMixin", - "MinecraftClientMixin" + "package": "nl.devpieter.utilize.mixin", + "compatibilityLevel": "JAVA_25", + "mixins": [ + "ConnectionMixin" ], "injectors": { "defaultRequire": 1 }, - "mixins": [ - "ClientConnectionMixin", - "SeesMixin" - ] + "overwrites": { + "requireAnnotations": true + } } diff --git a/versions/1.21.9/gradle.properties b/versions/1.21.9/gradle.properties deleted file mode 100644 index 1ead45f..0000000 --- a/versions/1.21.9/gradle.properties +++ /dev/null @@ -1,6 +0,0 @@ -# check this on https://modmuss50.me/fabric.html -minecraft_version=1.21.9 -max_minecraft_version=1.21.11 - -yarn_mappings=1.21.9+build.1 -fabric_version=0.134.1+1.21.9 \ No newline at end of file diff --git a/versions/26.1/gradle.properties b/versions/26.1/gradle.properties new file mode 100644 index 0000000..d41f3d4 --- /dev/null +++ b/versions/26.1/gradle.properties @@ -0,0 +1,4 @@ +# check this on https://modmuss50.me/fabric.html +minecraft_version=26.1 +max_minecraft_version=26.2 +fabric_version=0.155.2+26.1.2 \ No newline at end of file diff --git a/versions/mainProject b/versions/mainProject index 3434b8f..bf18016 100644 --- a/versions/mainProject +++ b/versions/mainProject @@ -1 +1 @@ -1.21.9 \ No newline at end of file +26.1 \ No newline at end of file From e94d5681d0919578956cfe74756030b6402c0c23 Mon Sep 17 00:00:00 2001 From: Pieter Date: Thu, 6 Aug 2026 15:53:02 +0200 Subject: [PATCH 9/9] Cleanup --- build.gradle | 10 ---------- gradle.properties | 2 +- src/main/resources/fabric.mod.json | 2 +- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index b6541b1..76acdf8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,17 +1,9 @@ -//plugins { -// id 'net.fabricmc.fabric-loom' version '1.17-SNAPSHOT' -// id 'maven-publish' -//} - plugins { id 'net.fabricmc.fabric-loom' id 'com.replaymod.preprocess' id 'maven-publish' } -//version = project.mod_version -//group = project.maven_group - def isSnapshot = providers.environmentVariable("SNAPSHOT_BUILD").map { it.toBoolean() }.orElse(false).get() def buildNumber = System.getenv('BUILD_NUMBER') ?: 'dev' @@ -33,7 +25,6 @@ loom { } } - repositories { maven { name "Pietr Space Releases" @@ -42,7 +33,6 @@ repositories { } dependencies { - // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" implementation "net.fabricmc:fabric-loader:${project.loader_version}" diff --git a/gradle.properties b/gradle.properties index 9fa5d02..d12076d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,4 +8,4 @@ loader_version=0.19.3 # Mod Properties mod_version=2.0.0 maven_group=nl.devpieter -archives_base_name=Utilize \ No newline at end of file +archives_base_name=utilize \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 6734d73..31ff07a 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -27,6 +27,6 @@ "depends": { "fabricloader": ">=${loader_version}", "fabric-api": "*", - "minecraft": "${minecraft_version}" + "minecraft": ">=${minecraft_version} <=${max_minecraft_version}" } }