diff --git a/gradle.properties b/gradle.properties index 924bcf3..9558125 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,7 @@ -# Done to increase the memory available to gradle. org.gradle.jvmargs=-Xmx1G -# Fabric Properties - # check these on https://fabricmc.net/develop - minecraft_version=1.20.6 - yarn_mappings=1.20.6+build.3 - loader_version=0.15.11 -# Mod Properties + minecraft_version=1.21.6 + loader_version=0.16.1 mod_version = 1.0.5 maven_group = com.github.voxxin archives_base_name = ColourMyServers \ No newline at end of file diff --git a/src/main/java/com/github/voxxin/colourmyservers/mixin/server/EditServerScreenMixin.java b/src/main/java/com/github/voxxin/colourmyservers/mixin/server/EditServerScreenMixin.java index 0f8156e..1a6dbbb 100644 --- a/src/main/java/com/github/voxxin/colourmyservers/mixin/server/EditServerScreenMixin.java +++ b/src/main/java/com/github/voxxin/colourmyservers/mixin/server/EditServerScreenMixin.java @@ -1,14 +1,9 @@ package com.github.voxxin.colourmyservers.mixin.server; -import com.github.voxxin.colourmyservers.util.ComponentU; import com.github.voxxin.colourmyservers.util.ErrorCatching; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.EditBox; -import net.minecraft.client.gui.components.toasts.SystemToast; import net.minecraft.client.gui.screens.EditServerScreen; -import net.minecraft.client.multiplayer.resolver.ServerAddress; -import net.minecraft.network.chat.Component; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -17,32 +12,20 @@ @Mixin(EditServerScreen.class) public class EditServerScreenMixin { - @Shadow private EditBox nameEdit; - @Shadow private Button addButton; @Inject(at = @At("TAIL"), method = "init") public void init(CallbackInfo ci) { - if (!nameEdit.getValue().isEmpty()) nameEdit.setMaxLength(9999999); - } - - @Inject(at = @At("HEAD"), method = "onAdd", cancellable = true) - public void onAdd(CallbackInfo ci) { - if (ErrorCatching.stringTooLong(this.nameEdit.getValue())) { - ErrorCatching.nameTooLongToast(); - ci.cancel(); - } + nameEdit.setMaxLength(Integer.MAX_VALUE); } - @Inject(at = @At("HEAD"), method = "updateAddButtonStatus", cancellable = true) - public void updateAddButtonStatus(CallbackInfo ci) { - if (ErrorCatching.stringTooLong(this.nameEdit.getValue())) { - if (this.addButton.active) { - ErrorCatching.nameTooLongToast(); - } - this.addButton.active = false; + @Inject(at = @At("HEAD"), method = {"onAdd", "updateAddButtonStatus"}, cancellable = true) + public void handleValidation(CallbackInfo ci) { + if (ErrorCatching.isTooLong(nameEdit.getValue())) { + if (addButton.active) ErrorCatching.showToast(); + addButton.active = false; ci.cancel(); } } -} +} \ No newline at end of file diff --git a/src/main/java/com/github/voxxin/colourmyservers/mixin/server/ServerSelectionListMixin.java b/src/main/java/com/github/voxxin/colourmyservers/mixin/server/ServerSelectionListMixin.java index 4afd878..656d599 100644 --- a/src/main/java/com/github/voxxin/colourmyservers/mixin/server/ServerSelectionListMixin.java +++ b/src/main/java/com/github/voxxin/colourmyservers/mixin/server/ServerSelectionListMixin.java @@ -14,11 +14,11 @@ public class ServerSelectionListMixin { method = "render", at = @At( value = "INVOKE", - target = "Lnet/minecraft/client/gui/GuiGraphics;drawString(Lnet/minecraft/client/gui/Font;Ljava/lang/String;IIIZ)I", ordinal = 0 + target = "Lnet/minecraft/client/gui/GuiGraphics;drawString(Lnet/minecraft/client/gui/Font;Ljava/lang/String;III)V", ordinal = 0 ) ) - private int render(GuiGraphics instance, Font font, String string, int i, int j, int k, boolean bl) { - net.minecraft.network.chat.Component component = new ComponentU(string).getComponent(); - return instance.drawString(font, component, i, j, k, bl); + private void render(GuiGraphics instance, Font font, String string, int i, int j, int k) { + net.minecraft.network.chat.Component component = new ComponentU(string).parse(); + instance.drawString(font, component, i, j, k); } } diff --git a/src/main/java/com/github/voxxin/colourmyservers/mixin/world/CreateWorldScreenGameTabMixin.java b/src/main/java/com/github/voxxin/colourmyservers/mixin/world/CreateWorldScreenGameTabMixin.java index d15853c..7638000 100644 --- a/src/main/java/com/github/voxxin/colourmyservers/mixin/world/CreateWorldScreenGameTabMixin.java +++ b/src/main/java/com/github/voxxin/colourmyservers/mixin/world/CreateWorldScreenGameTabMixin.java @@ -1,6 +1,5 @@ package com.github.voxxin.colourmyservers.mixin.world; -import com.github.voxxin.colourmyservers.util.ComponentU; import com.github.voxxin.colourmyservers.util.CreateWorldScreenExt; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen; @@ -10,19 +9,14 @@ 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; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(CreateWorldScreen.GameTab.class) public class CreateWorldScreenGameTabMixin { - @Shadow @Final private EditBox nameEdit; - @Inject(at = @At(value = "TAIL"), method = "", locals = LocalCapture.CAPTURE_FAILHARD) + @Inject(at = @At("TAIL"), method = "") private void init(CreateWorldScreen createWorldScreen, CallbackInfo ci) { - if (!nameEdit.getValue().isEmpty()) nameEdit.setMaxLength(9999999); - nameEdit.setResponder(w -> { - ((CreateWorldScreenExt)createWorldScreen).cms$updateFinalizeButton(w); - }); + nameEdit.setMaxLength(Integer.MAX_VALUE); + nameEdit.setResponder(w -> ((CreateWorldScreenExt) createWorldScreen).updateFinalizeButton(w)); } -} +} \ No newline at end of file diff --git a/src/main/java/com/github/voxxin/colourmyservers/mixin/world/CreateWorldScreenMixin.java b/src/main/java/com/github/voxxin/colourmyservers/mixin/world/CreateWorldScreenMixin.java index a0cb635..946d978 100644 --- a/src/main/java/com/github/voxxin/colourmyservers/mixin/world/CreateWorldScreenMixin.java +++ b/src/main/java/com/github/voxxin/colourmyservers/mixin/world/CreateWorldScreenMixin.java @@ -1,12 +1,9 @@ package com.github.voxxin.colourmyservers.mixin.world; -import com.github.voxxin.colourmyservers.util.ComponentU; import com.github.voxxin.colourmyservers.util.CreateWorldScreenExt; import com.github.voxxin.colourmyservers.util.ErrorCatching; -import net.minecraft.client.Minecraft; +import com.llamalad7.mixinextras.sugar.Local; import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.EditBox; -import net.minecraft.client.gui.components.toasts.SystemToast; import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen; import net.minecraft.client.gui.screens.worldselection.WorldCreationUiState; @@ -18,37 +15,27 @@ 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.LocalCapture; @Mixin(CreateWorldScreen.class) public class CreateWorldScreenMixin implements CreateWorldScreenExt { - @Shadow @Final WorldCreationUiState uiState; + @Unique private LinearLayout layout; - @Unique - private LinearLayout layout; - - @Inject(method = "init", at = @At("TAIL"), locals = LocalCapture.CAPTURE_FAILHARD) - private void init(CallbackInfo ci, LinearLayout linearLayout) { + @Inject(method = "init", at = @At("TAIL")) + private void init(CallbackInfo ci, @Local LinearLayout linearLayout) { this.layout = linearLayout; } - @Override - public void cms$updateFinalizeButton(String name) { - this.layout.visitWidgets((w) -> { + public void updateFinalizeButton(String name) { + this.layout.visitWidgets(w -> { if (w instanceof Button button && button.getMessage().equals(Component.translatable("selectWorld.create"))) { - if (ErrorCatching.stringTooLong(name)) { - if (button.active) { - ErrorCatching.nameTooLongToast(); - } - button.active = false; - } else { - this.uiState.setName(name); - button.active = true; - } + boolean valid = !ErrorCatching.isTooLong(name); + if (!valid && button.active) ErrorCatching.showToast(); + button.active = valid; + if (valid) uiState.setName(name); } }); } -} +} \ No newline at end of file diff --git a/src/main/java/com/github/voxxin/colourmyservers/mixin/world/EditWorldScreenMixin.java b/src/main/java/com/github/voxxin/colourmyservers/mixin/world/EditWorldScreenMixin.java index 9ced48d..2da0b5b 100644 --- a/src/main/java/com/github/voxxin/colourmyservers/mixin/world/EditWorldScreenMixin.java +++ b/src/main/java/com/github/voxxin/colourmyservers/mixin/world/EditWorldScreenMixin.java @@ -1,43 +1,26 @@ package com.github.voxxin.colourmyservers.mixin.world; import com.github.voxxin.colourmyservers.util.ErrorCatching; -import it.unimi.dsi.fastutil.booleans.BooleanConsumer; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; +import com.llamalad7.mixinextras.sugar.Local; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.EditBox; -import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.screens.worldselection.EditWorldScreen; -import net.minecraft.world.level.storage.LevelStorageSource; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; 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.LocalCapture; @Mixin(EditWorldScreen.class) public class EditWorldScreenMixin { - @Shadow @Final private EditBox nameEdit; - @Inject(method = "", at = @At("TAIL"), locals = LocalCapture.CAPTURE_FAILHARD) - public void init(Minecraft minecraft, LevelStorageSource.LevelStorageAccess levelStorageAccess, String string, BooleanConsumer booleanConsumer, CallbackInfo ci, Font font, LinearLayout linearLayout, Button button) { - if (nameEdit.getValue().isEmpty()) nameEdit.setMaxLength(9999999); + @Inject(method = "", at = @At("TAIL")) + public void init(CallbackInfo ci, @Local Button button) { + nameEdit.setMaxLength(Integer.MAX_VALUE); nameEdit.setResponder(w -> { - if (ErrorCatching.stringTooLong(w)) { - if (button.active) { - ErrorCatching.nameTooLongToast(); - } - button.active = false; - } else { - button.active = true; - } - - if (w.isEmpty()) { - button.active = false; - } + button.active = !w.isEmpty() && !ErrorCatching.isTooLong(w); }); } -} +} \ No newline at end of file diff --git a/src/main/java/com/github/voxxin/colourmyservers/mixin/world/WorldCreationUiStateMixin.java b/src/main/java/com/github/voxxin/colourmyservers/mixin/world/WorldCreationUiStateMixin.java index 3751967..6664f86 100644 --- a/src/main/java/com/github/voxxin/colourmyservers/mixin/world/WorldCreationUiStateMixin.java +++ b/src/main/java/com/github/voxxin/colourmyservers/mixin/world/WorldCreationUiStateMixin.java @@ -10,8 +10,8 @@ @Mixin(WorldCreationUiState.class) public class WorldCreationUiStateMixin { - @Inject(at = @At(value = "INVOKE_ASSIGN", target = "Ljava/lang/String;trim()Ljava/lang/String;"), method = "findResultFolder", cancellable = true) + @Inject(at = @At(value = "HEAD"), method = "findResultFolder") private void findResultFolder(String string, CallbackInfoReturnable cir) { - cir.setReturnValue(new ComponentU(string).getComponent().getString()); + string = new ComponentU(string).parse().getString(); } } diff --git a/src/main/java/com/github/voxxin/colourmyservers/mixin/world/WorldSelectionListMixin.java b/src/main/java/com/github/voxxin/colourmyservers/mixin/world/WorldSelectionListMixin.java index 9cccec4..ff72e23 100644 --- a/src/main/java/com/github/voxxin/colourmyservers/mixin/world/WorldSelectionListMixin.java +++ b/src/main/java/com/github/voxxin/colourmyservers/mixin/world/WorldSelectionListMixin.java @@ -15,11 +15,11 @@ public class WorldSelectionListMixin { method = "render", at = @At( value = "INVOKE", - target = "Lnet/minecraft/client/gui/GuiGraphics;drawString(Lnet/minecraft/client/gui/Font;Ljava/lang/String;IIIZ)I", ordinal = 0 + target = "Lnet/minecraft/client/gui/GuiGraphics;drawString(Lnet/minecraft/client/gui/Font;Ljava/lang/String;III)V", ordinal = 0 ) ) - private int render(GuiGraphics instance, Font font, String string, int i, int j, int k, boolean bl) { - net.minecraft.network.chat.Component component = new ComponentU(string).getComponent(); - return instance.drawString(font, component, i, j, k, bl); + private void render(GuiGraphics instance, Font font, String string, int i, int j, int k) { + net.minecraft.network.chat.Component component = new ComponentU(string).parse(); + instance.drawString(font, component, i, j, k); } } diff --git a/src/main/java/com/github/voxxin/colourmyservers/util/ComponentU.java b/src/main/java/com/github/voxxin/colourmyservers/util/ComponentU.java index 9089077..0f0627f 100644 --- a/src/main/java/com/github/voxxin/colourmyservers/util/ComponentU.java +++ b/src/main/java/com/github/voxxin/colourmyservers/util/ComponentU.java @@ -1,135 +1,83 @@ package com.github.voxxin.colourmyservers.util; import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; -import java.util.ArrayList; -import java.util.Arrays; - public class ComponentU { - private final char[] characters; - - private final MutableComponent parsedComponentString = net.minecraft.network.chat.Component.literal(""); - private StringBuilder parsingCharString = new StringBuilder(); - - private final ArrayList uniqueCharacters = new ArrayList<>(Arrays.asList("r", "l", "o", "k", "m", "n")); - private final ArrayList startCharacters = new ArrayList<>(Arrays.asList("§", "&")); - private ChatFormatting parsingWithColourFormatting = null; - private int parsingWithColourInt = 0; - private boolean bold = false; - private boolean italic = false; - private boolean obfuscated = false; - private boolean strikethrough = false; - private boolean underline = false; + private final String input; - private boolean finalized = false; - - public ComponentU(String original) { - this.characters = original.toCharArray(); + public ComponentU(String input) { + this.input = input; } + public MutableComponent parse() { + MutableComponent result = Component.literal(""); + StringBuilder currentText = new StringBuilder(); + Style currentStyle = Style.EMPTY; + int pos = 0; - public net.minecraft.network.chat.Component getComponent() { - for (int i = 0; i < this.characters.length; i++) { + while (pos < input.length()) { + char c = input.charAt(pos++); - if (finalized) { - addToParsingCharString(); - finalized = false; - } + if ((c == '§' || c == '&') && pos < input.length()) { + char code = input.charAt(pos++); - if ((startCharacters.contains(String.valueOf(characters[i]))) && i + 1 < characters.length) { - if (characters[i + 1] == '#' && i + 8 < characters.length) { - addToParsingCharString(); - String hexString = new String(characters, i + 2, 6); - if (hexString.matches("[A-Fa-f0-9]{6}")) { - parsingWithColourInt = Integer.parseInt(hexString, 16); - if (i + 8 < characters.length && startCharacters.contains(String.valueOf(characters[i + 8]))) { - i += 7; - finalized = !parsingCharString.isEmpty(); + if (code == 'r') { + flush(currentText, result, currentStyle); + currentStyle = Style.EMPTY; + continue; + } + + if (code == '#') { + if (pos + 6 <= input.length()) { + String hex = input.substring(pos, pos + 6); + if (hex.matches("[0-9a-fA-F]{6}")) { + flush(currentText, result, currentStyle); + currentStyle = currentStyle.withColor(Integer.parseInt(hex, 16)); + pos += 6; continue; } - i += 8; - finalized = !parsingCharString.isEmpty(); } - } else if (i + 1 < characters.length && uniqueCharacters.contains(String.valueOf(characters[i + 1]))) { - addToParsingCharString(); - char nextChar = characters[i + 1]; - if (nextChar == 'r') resetFormatting(); - else if (hasColour()) - switch (nextChar) { - case 'l': bold = true; break; - case 'o': italic = true; break; - case 'k': obfuscated = true; break; - case 'm': strikethrough = true; break; - case 'n': underline = true; break; + } else { + ChatFormatting format = ChatFormatting.getByCode(code); + if (format != null) { + if (format.isColor()) { + flush(currentText, result, currentStyle); + currentStyle = Style.EMPTY.withColor(format); + } else { + currentStyle = applyFormat(currentStyle, format); } - - i += 1; - finalized = !parsingCharString.isEmpty(); - continue; - } else if (ChatFormatting.getByCode(characters[i + 1]) != null && i + 1 < characters.length) { - addToParsingCharString(); - - bold = false; - italic = false; - obfuscated = false; - strikethrough = false; - underline = false; - - parsingWithColourFormatting = ChatFormatting.getByCode(characters[i + 1]); - - if (i + 2 < characters.length && startCharacters.contains(String.valueOf(characters[i + 2]))) { - i += 1; - finalized = !parsingCharString.isEmpty(); continue; } - i += 2; - finalized = !parsingCharString.isEmpty(); } + // Fallback for invalid codes + currentText.append(c).append(code); + } else { + currentText.append(c); } - - if (i < characters.length) parsingCharString.append(characters[i]); } - addToParsingCharString(); - - return parsedComponentString; - } - - private void resetFormatting() { - bold = false; - italic = false; - obfuscated = false; - strikethrough = false; - underline = false; - parsingWithColourFormatting = null; - parsingWithColourInt = 0; + flush(currentText, result, currentStyle); + return result; } - - private void addToParsingCharString() { - parsedComponentString.append( - net.minecraft.network.chat.Component.literal(parsingCharString.toString()).withStyle( - parsingWithColourInt == 0 ? Style.EMPTY.withColor(parsingWithColourFormatting == null ? ChatFormatting.WHITE : parsingWithColourFormatting) - .withBold(bold) - .withItalic(italic) - .withObfuscated(obfuscated) - .withStrikethrough(strikethrough) - .withUnderlined(underline) : - Style.EMPTY.withColor(parsingWithColourInt) - .withBold(bold) - .withItalic(italic) - .withObfuscated(obfuscated) - .withStrikethrough(strikethrough) - .withUnderlined(underline)) - ); - - parsingCharString = new StringBuilder(); + private Style applyFormat(Style style, ChatFormatting format) { + return switch (format) { + case BOLD -> style.withBold(true); + case ITALIC -> style.withItalic(true); + case UNDERLINE -> style.withUnderlined(true); + case STRIKETHROUGH -> style.withStrikethrough(true); + case OBFUSCATED -> style.withObfuscated(true); + default -> style; + }; } - private boolean hasColour() { - return parsingWithColourInt != 0 || parsingWithColourFormatting != null; + private void flush(StringBuilder text, MutableComponent result, Style style) { + if (text.length() > 0) { + result.append(Component.literal(text.toString()).withStyle(style)); + text.setLength(0); + } } - -} +} \ No newline at end of file diff --git a/src/main/java/com/github/voxxin/colourmyservers/util/CreateWorldScreenExt.java b/src/main/java/com/github/voxxin/colourmyservers/util/CreateWorldScreenExt.java index 6d2f913..43dfed3 100644 --- a/src/main/java/com/github/voxxin/colourmyservers/util/CreateWorldScreenExt.java +++ b/src/main/java/com/github/voxxin/colourmyservers/util/CreateWorldScreenExt.java @@ -1,5 +1,5 @@ package com.github.voxxin.colourmyservers.util; public interface CreateWorldScreenExt { - void cms$updateFinalizeButton(String name); -} + void updateFinalizeButton(String name); +} \ No newline at end of file diff --git a/src/main/java/com/github/voxxin/colourmyservers/util/ErrorCatching.java b/src/main/java/com/github/voxxin/colourmyservers/util/ErrorCatching.java index e9d6986..51edf1e 100644 --- a/src/main/java/com/github/voxxin/colourmyservers/util/ErrorCatching.java +++ b/src/main/java/com/github/voxxin/colourmyservers/util/ErrorCatching.java @@ -5,16 +5,19 @@ import net.minecraft.network.chat.Component; public class ErrorCatching { + private static final int MAX_LENGTH = 32; + private static SystemToast lastToast; - public static boolean stringTooLong(String string) { - return new ComponentU(string).getComponent().getString().length() > 32; + public static boolean isTooLong(String text) { + return new ComponentU(text).parse().getString().length() > MAX_LENGTH; } - public static void nameTooLongToast() { + public static void showToast() { SystemToast.add( - Minecraft.getInstance().getToasts(), new SystemToast.SystemToastId(5000L), + Minecraft.getInstance().getToastManager(), + new SystemToast.SystemToastId(5000L), Component.literal("Name too long!"), - Component.literal("Max length: 32 characters") - ); + Component.literal("Max length: " + MAX_LENGTH + " characters") + ); } -} +} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 344d989..f94aea0 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -22,6 +22,6 @@ ], "depends": { - "fabricloader": ">=0.14.17" + "fabricloader": ">=0.16.1" } }