diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenFontTest.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenFontTest.java index 7018bad74..ba0ea3781 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/ScreenFontTest.java +++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenFontTest.java @@ -1,10 +1,10 @@ package net.minecraft.client.gui; import net.minecraft.client.render.font.Alignment; +import net.minecraft.client.render.font.FontFile; import net.minecraft.client.render.font.Fonts; import net.minecraft.core.net.ChatEmotes; import net.minecraft.core.util.collection.NamespaceID; -import net.minecraft.core.util.helper.ChatAllowedCharacters; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.lwjgl.input.Mouse; @@ -35,7 +35,7 @@ public class ScreenFontTest extends Screen{ for (int i = 0; i < 1000; i++) { builder.append("a"); } - builder.append("\n").append(ChatAllowedCharacters.ALLOWED_CHARACTERS); + builder.append("\n").append(FontFile.CHARS); builder.append("\n").append("§rItalic test: §oTEST STRING"); builder.append("\n").append("§rBold test: §lTEST STRING"); builder.append("\n").append("§rUnderline test: §nTEST STRING"); diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenLabelEditor.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenLabelEditor.java index f0f276e61..104cb33c2 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/ScreenLabelEditor.java +++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenLabelEditor.java @@ -54,6 +54,10 @@ public class ScreenLabelEditor extends Screen implements ITextField { return; } if (button.id == 0) { + if (!this.mc.thePlayer.gamemode.allowColorFormattingInDyeableText()) { + this.text = TextFormatting.removeAllColorFormatting(this.text); + } + this.item.setCustomName(this.text); this.mc.displayScreen(null); diff --git a/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java b/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java index c9d89fa4e..30f412f04 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java +++ b/game/client/src/main/java/net/minecraft/client/gui/ScreenSignEditor.java @@ -19,7 +19,7 @@ import net.minecraft.core.lang.I18n; import net.minecraft.core.net.packet.PacketSignUpdate; import net.minecraft.core.sound.SoundCategory; import net.minecraft.core.util.Nullability; -import net.minecraft.core.util.helper.ChatAllowedCharacters; +import net.minecraft.core.util.helper.NetCharacters; import net.minecraft.core.util.helper.DyeColor; import org.jetbrains.annotations.NotNull; import org.joml.Math; @@ -28,11 +28,6 @@ import org.lwjgl.input.Keyboard; import java.util.Objects; public class ScreenSignEditor extends Screen { - private static final @NotNull String ALLOWED_CHARACTERS; - static { - ALLOWED_CHARACTERS = ChatAllowedCharacters.ALLOWED_CHARACTERS; - } - protected @NotNull String screenTitle; private final @NotNull TileEntitySign entitySign; @@ -96,7 +91,10 @@ public class ScreenSignEditor extends Screen { Keyboard.enableRepeatEvents(false); // I have no idea how the hell the world is null sometimes // but thaboard was getting a crash from the world being null - if (this.mc.currentWorld != null && this.mc.currentWorld.isClientSide) { + if (this.mc.currentWorld == null) return; + if (!this.mc.currentWorld.isClientSide) { + this.entitySign.finalizeEditor(this.mc.thePlayer); + } else { Objects.requireNonNull(this.mc.getSendQueue()) .addToSendQueue( new PacketSignUpdate( @@ -140,7 +138,7 @@ public class ScreenSignEditor extends Screen { if (eventKey == Keyboard.KEY_BACK && !this.entitySign.signText[this.editLine].isEmpty()) { this.entitySign.signText[this.editLine] = this.entitySign.signText[this.editLine].substring(0, this.entitySign.signText[this.editLine].length() - 1); } - if ((ALLOWED_CHARACTERS.indexOf(eventCharacter) >= 0 || Character.isLetterOrDigit(eventCharacter)) && this.entitySign.signText[this.editLine].length() < TileEntitySign.MAX_LINE_SIZE) { + if (NetCharacters.isAllowed(eventCharacter) && this.entitySign.signText[this.editLine].length() < TileEntitySign.MAX_LINE_SIZE) { this.entitySign.signText[this.editLine] += eventCharacter; } } diff --git a/game/client/src/main/java/net/minecraft/client/gui/keyboard/ScreenKeyboard.java b/game/client/src/main/java/net/minecraft/client/gui/keyboard/ScreenKeyboard.java index fd3e0b839..7c5a5d105 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/keyboard/ScreenKeyboard.java +++ b/game/client/src/main/java/net/minecraft/client/gui/keyboard/ScreenKeyboard.java @@ -9,7 +9,6 @@ import net.minecraft.client.input.controller.ControllerInput; import net.minecraft.client.render.renderer.GLRenderer; import net.minecraft.client.render.texture.stitcher.TextureRegistry; import net.minecraft.core.sound.SoundCategory; -import net.minecraft.core.util.helper.ChatAllowedCharacters; import net.minecraft.core.util.helper.MathHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -389,10 +388,6 @@ public class ScreenKeyboard extends Screen implements ITextField { return Integer.MAX_VALUE; } - public boolean isCharacterAllowed(char c) { - return ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c) >= 0 || Character.isLetterOrDigit(c); - } - public interface KeyAction { void apply(char c, int key, String workingString); } diff --git a/game/client/src/main/java/net/minecraft/client/gui/text/ITextField.java b/game/client/src/main/java/net/minecraft/client/gui/text/ITextField.java index b98eca3d7..d721cc48a 100644 --- a/game/client/src/main/java/net/minecraft/client/gui/text/ITextField.java +++ b/game/client/src/main/java/net/minecraft/client/gui/text/ITextField.java @@ -1,6 +1,6 @@ package net.minecraft.client.gui.text; -import net.minecraft.core.util.helper.ChatAllowedCharacters; +import net.minecraft.core.util.helper.NetCharacters; public interface ITextField { @@ -12,6 +12,6 @@ public interface ITextField default boolean isCharacterAllowed(char c) { - return ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c) >= 0 || Character.isLetterOrDigit(c); + return NetCharacters.isAllowed(c); } } diff --git a/game/client/src/main/java/net/minecraft/client/render/font/FontDefault.java b/game/client/src/main/java/net/minecraft/client/render/font/FontDefault.java index 33aae017e..a4cffe434 100644 --- a/game/client/src/main/java/net/minecraft/client/render/font/FontDefault.java +++ b/game/client/src/main/java/net/minecraft/client/render/font/FontDefault.java @@ -13,13 +13,13 @@ public class FontDefault extends FontFile { @Override public boolean canRenderChar(final char c) { - return c == ' ' || (ALLOWED_CHARACTER_INDICES[c] >= 0 && textureForChar(c) != 0); + return c == ' ' || (CHARACTER_INDICES[c] >= 0 && textureForChar(c) != 0); // return false; } @Override public int textureForChar(final char c) { - final int fontIndex = ALLOWED_CHARACTER_INDICES[c]; + final int fontIndex = CHARACTER_INDICES[c]; if (fontIndex < 0) return 0; final int index = fontIndex / GLYPHS_PER_TEXTURE; if (this.texHandleCache[index] != TEXTURE_UNASSIGNED) return this.texHandleCache[index]; @@ -35,7 +35,7 @@ public class FontDefault extends FontFile { @Override public double charWidthDouble(final char c) { if (c == ' ') return 4; - final int fontIndex = ALLOWED_CHARACTER_INDICES[c]; + final int fontIndex = CHARACTER_INDICES[c]; if (fontIndex < 0) return 0; final int upper = this.charWidth[fontIndex] >> 4; @@ -49,7 +49,7 @@ public class FontDefault extends FontFile { @Override public double renderChar(final TessellatorFont tessellator, final char c, final double x, final double y, final double z) { if (c == ' ') return 4; - final int fontIndex = ALLOWED_CHARACTER_INDICES[c]; + final int fontIndex = CHARACTER_INDICES[c]; if (fontIndex < 0) return 0; final int upper = this.charWidth[fontIndex] >> 4; diff --git a/game/client/src/main/java/net/minecraft/client/render/font/FontFile.java b/game/client/src/main/java/net/minecraft/client/render/font/FontFile.java index 49aa6d5b8..47026d5c5 100644 --- a/game/client/src/main/java/net/minecraft/client/render/font/FontFile.java +++ b/game/client/src/main/java/net/minecraft/client/render/font/FontFile.java @@ -1,38 +1,56 @@ package net.minecraft.client.render.font; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.client.Minecraft; import net.minecraft.client.render.tessellator.TessellatorFont; import net.minecraft.client.render.texture.Texture; import net.minecraft.client.render.texturepack.TexturePackList; -import net.minecraft.core.util.helper.ChatAllowedCharacters; +import net.minecraft.core.util.helper.NetCharacters; + import org.jetbrains.annotations.NotNull; +import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.util.Arrays; -import java.util.List; import java.util.Random; public class FontFile implements Font { - /** - * Some characters somehow are recognized as "default" characters while their rendering is not supported. - * Have to delete this once workarounds are found. - */ - protected static final List DEFAULT_BLACKLIST = new ObjectArrayList<>(); - static { - DEFAULT_BLACKLIST.addAll(Arrays.asList('\uff0c', '\u3002', '\u3001', '\u3010', '\u3011', '\uff1b', '\u2019', '\u2018', '\u201c', '\u201d', '\uff1f', '\uff01', '\u00b7')); - } - public static final int[] ALLOWED_CHARACTER_INDICES = new int[Character.MAX_VALUE]; + public static final String CHARS = parseCharactersFromFile(); + public static final int[] CHARACTER_INDICES = new int[Character.MAX_VALUE]; static { - for (char c = 0; c < ALLOWED_CHARACTER_INDICES.length; c++) { - ALLOWED_CHARACTER_INDICES[c] = ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c); - } - for (var c : DEFAULT_BLACKLIST) { - ALLOWED_CHARACTER_INDICES[c] = -1; + for (var c = 0; c < CHARACTER_INDICES.length; c++) { + CHARACTER_INDICES[c] = CHARS.indexOf(c); } + // Some characters somehow are recognized as "default" characters while their rendering is not supported. + // Have to delete this once workarounds are found. + final char[] blacklist = { + '\uff0c', '\u3002', '\u3001', '\u3010', '\u3011', '\uff1b', '\u2019', '\u2018', + '\u201c', '\u201d', '\uff1f', '\uff01', '\u00b7' + }; + for (var c : blacklist) CHARACTER_INDICES[c] = -1; } + @NotNull + private static String parseCharactersFromFile() { + final var buf = new StringBuilder(); + try (final var bufferedReader = new BufferedReader(new InputStreamReader( + FontFile.class.getResourceAsStream("/font.txt"), + StandardCharsets.UTF_8 + ))) { + while (true) { + final var line = bufferedReader.readLine(); + if (line == null) break; + if (line.startsWith("#")) continue; + buf.append(line); + } + } catch (Exception ignored) {} + // empty file will result in every character fallback to unicode, which should be acceptable + + return buf.toString(); + } + protected static final int ITALICS_SHIFT = 1; protected static final int GLYPHS_PER_TEXTURE = 256; protected static final int TEXTURE_UNASSIGNED = -1; @@ -89,17 +107,15 @@ public class FontFile implements Font { @Override public char getObfuscatedChar(final char c, final Random random) { - if (ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c) < 0) return c; - char randomChar; - int counter = 0; - do { - randomChar = ChatAllowedCharacters.ALLOWED_CHARACTERS.charAt(random.nextInt(ChatAllowedCharacters.ALLOWED_CHARACTERS.length())); - if (counter++ > 1000) { - randomChar = c; - break; - } - } while (charWidth(c) != charWidth(randomChar) || !canRenderChar(randomChar)); - return randomChar; + if (!NetCharacters.isAllowed(c)) return c; + for (int i = 0; i < 1000; i++) { + final char randomChar = (char)(short)random.nextInt(Short.MAX_VALUE); + if (!NetCharacters.isAllowed(randomChar)) continue; + if (charWidth(randomChar) != charWidth(randomChar)) continue; + if (!canRenderChar(randomChar)) continue; + return randomChar; + } + return c; } @Override diff --git a/game/client/src/main/java/net/minecraft/client/render/font/FontMonospace.java b/game/client/src/main/java/net/minecraft/client/render/font/FontMonospace.java index 086a3df02..e96032cf6 100644 --- a/game/client/src/main/java/net/minecraft/client/render/font/FontMonospace.java +++ b/game/client/src/main/java/net/minecraft/client/render/font/FontMonospace.java @@ -21,7 +21,7 @@ public class FontMonospace extends FontFile{ @Override public boolean canRenderChar(final char c) { - return ALLOWED_CHARACTER_INDICES[c] != -1 && (c == ' ' || textureForChar(c) != 0); + return CHARACTER_INDICES[c] != -1 && (c == ' ' || textureForChar(c) != 0); } @Override @@ -32,7 +32,7 @@ public class FontMonospace extends FontFile{ @Override public double renderChar(final TessellatorFont tessellator, final char c, final double x, final double y, final double z) { if (c != ' ') { - final int fontIndex = ALLOWED_CHARACTER_INDICES[c]; + final int fontIndex = CHARACTER_INDICES[c]; if (fontIndex < 0) return 0; final int upper = this.charWidth[fontIndex] >> 4; diff --git a/game/client/src/main/java/net/minecraft/client/render/font/FontRendererDefault.java b/game/client/src/main/java/net/minecraft/client/render/font/FontRendererDefault.java index bdd99e294..c0060d244 100644 --- a/game/client/src/main/java/net/minecraft/client/render/font/FontRendererDefault.java +++ b/game/client/src/main/java/net/minecraft/client/render/font/FontRendererDefault.java @@ -177,7 +177,7 @@ public class FontRendererDefault extends FontRenderer { tessellator.setShadow(shadow); tessellator.setConfig(this.currentConfig); double shift; - final int fontIndex = FontDefault.ALLOWED_CHARACTER_INDICES[c]; + final int fontIndex = FontDefault.CHARACTER_INDICES[c]; if (SF.isObfuscated(this.currentConfig) && c != ' ' && fontIndex > 0) { shift = font.charWidth(c); final char randomChar = font.getObfuscatedChar(c, this.random); diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySign.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySign.java index b1a5c079d..fb64b5fa6 100644 --- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySign.java +++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntitySign.java @@ -123,11 +123,20 @@ public class TileEntitySign extends TileEntity public void setLocked(boolean locked) { this.locked = locked; } - + + public void finalizeEditor(@NotNull Player editor) { + finalizeEditor(editor.gamemode.allowColorFormattingInDyeableText()); + } + + public void finalizeEditor(boolean allowColorCode) { + if (!allowColorCode) for(int i = 0; i < 4; i++) { + signText[i] = TextFormatting.removeAllColorFormatting(signText[i]); + } + } + @Override public Packet getDescriptionPacket() { return new PacketTileEntityData(this); } - } diff --git a/game/core/src/main/java/net/minecraft/core/net/command/TextFormatting.java b/game/core/src/main/java/net/minecraft/core/net/command/TextFormatting.java index 25825a9b9..b94457bea 100644 --- a/game/core/src/main/java/net/minecraft/core/net/command/TextFormatting.java +++ b/game/core/src/main/java/net/minecraft/core/net/command/TextFormatting.java @@ -5,6 +5,9 @@ import org.jetbrains.annotations.Nullable; public class TextFormatting { public static final String FORMAT_CHARS = "0123456789abcdefklmnopr+-"; public static final String FORMAT_REGEX = "§[0123456789abcdefklmnopr+-]|§<(.*?)>"; + + public static final String COLOR_FORMAT_REGEX = "§[0123456789abcdef]|§<(.*?)>"; + public static final TextFormatting[] FORMATTINGS = new TextFormatting[FORMAT_CHARS.length()]; public static final TextFormatting WHITE = new TextFormatting('0').setNames("White"); @@ -75,6 +78,10 @@ public class TextFormatting { return name.replaceAll(FORMAT_REGEX, ""); } + public static String removeAllColorFormatting(String name) { + return name.replaceAll(COLOR_FORMAT_REGEX, ""); + } + public static String formatted(String string, TextFormatting... formattings) { StringBuilder sb = new StringBuilder(); for (TextFormatting formatting : formattings) { @@ -98,7 +105,7 @@ public class TextFormatting { public String[] getNames() { return names; } - + @Override public String toString() { return "" + SPECIAL_CHAR + code; diff --git a/game/core/src/main/java/net/minecraft/core/player/gamemode/Gamemode.java b/game/core/src/main/java/net/minecraft/core/player/gamemode/Gamemode.java index 681a78a03..562494605 100644 --- a/game/core/src/main/java/net/minecraft/core/player/gamemode/Gamemode.java +++ b/game/core/src/main/java/net/minecraft/core/player/gamemode/Gamemode.java @@ -27,11 +27,12 @@ public final class Gamemode { private final boolean properToolNeededToMine; private final boolean canInteract; private final boolean permaDeath; + private final boolean colorFormattingInDyeableText; private final float blockReachDistance; private final float entityReachDistance; - + /* package-private */ Gamemode( - final @NotNull String languageKey, + final @NotNull String languageKey, final @NotNull Function<@NotNull ContainerInventory, @NotNull MenuInventory> inventoryMenuSupplier, final boolean invulnerablePlayer, final boolean playerFlight, @@ -45,6 +46,7 @@ public final class Gamemode { final boolean properToolNeededToMine, final boolean canInteract, final boolean permaDeath, + final boolean colorFormattingInDyeableText, final float blockReachDistance, final float entityReachDistance ) { @@ -62,6 +64,7 @@ public final class Gamemode { this.properToolNeededToMine = properToolNeededToMine; this.canInteract = canInteract; this.permaDeath = permaDeath; + this.colorFormattingInDyeableText = colorFormattingInDyeableText; this.blockReachDistance = blockReachDistance; this.entityReachDistance = entityReachDistance; } @@ -186,4 +189,11 @@ public final class Gamemode { public boolean hasPermaDeath() { return this.permaDeath; } + + /** + * If true, the player is allowed to apply color formatting code on dyeable texts fields, e.g. signs and labels + */ + public boolean allowColorFormattingInDyeableText() { + return this.colorFormattingInDyeableText; + } } diff --git a/game/core/src/main/java/net/minecraft/core/player/gamemode/GamemodeBuilder.java b/game/core/src/main/java/net/minecraft/core/player/gamemode/GamemodeBuilder.java index 8ecbcb55a..de808f350 100644 --- a/game/core/src/main/java/net/minecraft/core/player/gamemode/GamemodeBuilder.java +++ b/game/core/src/main/java/net/minecraft/core/player/gamemode/GamemodeBuilder.java @@ -25,6 +25,7 @@ public class GamemodeBuilder { private boolean properToolNeededToMine = false; private boolean canInteract = true; private boolean permaDeath = false; + private boolean colorFormattingInDyeableText = false; private float blockReachDistance = 4.5f; private float entityReachDistance = 3.0f; @@ -52,6 +53,7 @@ public class GamemodeBuilder { this.properToolNeededToMine, this.canInteract, this.permaDeath, + this.colorFormattingInDyeableText, this.blockReachDistance, this.entityReachDistance ); @@ -182,4 +184,13 @@ public class GamemodeBuilder { this.permaDeath = true; return this; } + + /** + * Sets that the player can apply color formatting code on dyeable texts fields. + * @see Gamemode#allowColorFormattingInDyeableText() + */ + public @NotNull GamemodeBuilder withColorFormattingInDyeableText() { + this.colorFormattingInDyeableText = true; + return this; + } } diff --git a/game/core/src/main/java/net/minecraft/core/player/gamemode/Gamemodes.java b/game/core/src/main/java/net/minecraft/core/player/gamemode/Gamemodes.java index 5ab6818c3..8ac71ebb9 100644 --- a/game/core/src/main/java/net/minecraft/core/player/gamemode/Gamemodes.java +++ b/game/core/src/main/java/net/minecraft/core/player/gamemode/Gamemodes.java @@ -31,6 +31,7 @@ public final class Gamemodes { .withPlayerFlight() .withFireImmunity() .withInstantPortalTravel() + .withColorFormattingInDyeableText() .withBlockReachDistance(6.0f) .withEntityReachDistance(4.5f) .build() diff --git a/game/core/src/main/java/net/minecraft/core/util/helper/ChatAllowedCharacters.java b/game/core/src/main/java/net/minecraft/core/util/helper/ChatAllowedCharacters.java deleted file mode 100644 index 157e92e50..000000000 --- a/game/core/src/main/java/net/minecraft/core/util/helper/ChatAllowedCharacters.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.minecraft.core.util.helper; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; - -public class ChatAllowedCharacters -{ - - public ChatAllowedCharacters() - { - } - - private static String getAllowedCharacters() - { - StringBuilder s = new StringBuilder(); - try (BufferedReader bufferedReader = new BufferedReader( - new InputStreamReader( - ChatAllowedCharacters.class.getResourceAsStream("/font.txt"), - StandardCharsets.UTF_8 - ) - )) { - do { - String s2 = bufferedReader.readLine(); - if (s2 == null) { - break; - } - if (!s2.startsWith("#")) { - s.append(s2); - } - } while (true); - } catch (Exception ignored) {} - return s.toString(); - } - - public static final String ALLOWED_CHARACTERS = getAllowedCharacters(); - public static final char[] ALLOWED_CHARACTERS_ARRAY = { - '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', - '<', '>', '|', '"', ':' - }; - -} diff --git a/game/core/src/main/java/net/minecraft/core/util/helper/NetCharacters.java b/game/core/src/main/java/net/minecraft/core/util/helper/NetCharacters.java new file mode 100644 index 000000000..d83149464 --- /dev/null +++ b/game/core/src/main/java/net/minecraft/core/util/helper/NetCharacters.java @@ -0,0 +1,37 @@ +package net.minecraft.core.util.helper; + +public abstract class NetCharacters { + private NetCharacters() {} + + private static final short C0_MASK = ~(short)0x1F; + private static final short ASCII_MASK = ~(short)0x7F; + + public static boolean isAllowed(String message) { + for (int i = 0; i < message.length(); i++) { + if (!isAllowed(message.charAt(i))) return false; + } + return true; + } + + public static boolean isAllowed(char ch) { + final var u16 = (short)ch; + + // fast path for ascii + if ((u16 & C0_MASK) == 0) return false; + if ((u16 & ASCII_MASK) == 0) { + if (u16 == 0x7F) return false; // DEL + return true; + } + + switch (Character.getType(ch)) { + case Character.CONTROL: + case Character.FORMAT: + case Character.SURROGATE: + case Character.PRIVATE_USE: + case Character.UNASSIGNED: + return false; + default: + return true; + } + } +} diff --git a/game/core/src/main/java/net/minecraft/core/world/settings/WorldConfiguration.java b/game/core/src/main/java/net/minecraft/core/world/settings/WorldConfiguration.java index fd116a7a4..6c735c023 100644 --- a/game/core/src/main/java/net/minecraft/core/world/settings/WorldConfiguration.java +++ b/game/core/src/main/java/net/minecraft/core/world/settings/WorldConfiguration.java @@ -5,7 +5,6 @@ import net.minecraft.core.data.gamerule.GameRuleCollection; import net.minecraft.core.lang.I18n; import net.minecraft.core.player.gamemode.Gamemode; import net.minecraft.core.player.gamemode.Gamemodes; -import net.minecraft.core.util.helper.ChatAllowedCharacters; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.world.Dimension; import net.minecraft.core.world.config.spawning.SpawnerConfig; @@ -36,6 +35,8 @@ public class WorldConfiguration implements WorldConfigurationReader { private final @NotNull Map<@NotNull Dimension, @NotNull SettingNodesValues> worldSettings = new Object2ObjectArrayMap<>(); private @Nullable ChangeListener changeListener; + private static String DISALLOWED_CHARS_REGEX = "[\\/\\n\\r\\t\\x00\\f`\\?\\*\\\\<>|\":]"; + public WorldConfiguration() { for (final @NotNull Dimension dimension : Dimension.getDimensionList().values()) { this.worldSettings.put(dimension, new SettingNodesValues(WorldSettingNodes.getRootNode(), dimension)); @@ -184,15 +185,12 @@ public class WorldConfiguration implements WorldConfigurationReader { } public @NotNull String getFolderName(final @NotNull ISaveFormat saveFormat) { - final char @NotNull [] ac = ChatAllowedCharacters.ALLOWED_CHARACTERS_ARRAY; @NotNull String folderName = this.worldName.trim(); if (MathHelper.stringNullOrLengthZero(folderName)) { folderName = I18n.getInstance().translateKey("gui.create_world.label.new_world"); } - for (final char c : ac) { - folderName = folderName.replace(c, '_'); - } + folderName = folderName.replaceAll(DISALLOWED_CHARS_REGEX, "_"); final @NotNull String fixedFolderName = folderName; diff --git a/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java b/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java index 7a03a7989..e8cf4ceeb 100644 --- a/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java +++ b/game/server/src/main/java/net/minecraft/server/net/handler/PacketHandlerServer.java @@ -30,7 +30,7 @@ import net.minecraft.core.player.inventory.menu.MenuFlag; import net.minecraft.core.player.inventory.menu.MenuInventoryCreative; import net.minecraft.core.player.inventory.slot.Slot; import net.minecraft.core.util.helper.AES; -import net.minecraft.core.util.helper.ChatAllowedCharacters; +import net.minecraft.core.util.helper.NetCharacters; import net.minecraft.core.util.helper.Direction; import net.minecraft.core.util.helper.MathHelper; import net.minecraft.core.util.helper.RestHandler; @@ -494,18 +494,14 @@ public class PacketHandlerServer extends PacketHandler } if (message.length() > 256) { - message = message.substring(0, 255); + message = message.substring(0, 256); } message = message.trim(); -// message = message.replace('§', '$'); - for (int i = 0; i < message.length(); i++) { - char c = message.charAt(i); - if (ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(c) < 0) { - sendPacket(new PacketChat(String.valueOf(TextFormatting.GRAY) + TextFormatting.ITALIC + "[SERVER] Illegal characters in chat message.")); - return; - } + if (!NetCharacters.isAllowed(message)) { + sendPacket(new PacketChat(String.valueOf(TextFormatting.GRAY) + TextFormatting.ITALIC + "[SERVER] Illegal characters in chat message.")); + return; } if (message.startsWith("/")) { @@ -676,46 +672,35 @@ public class PacketHandlerServer extends PacketHandler @Override public void handleSignUpdate(@NotNull PacketSignUpdate packetSignUpdate) { if (!this.playerEntity.getGamemode().canInteract() || !this.playerEntity.isAlive()) return; - WorldServer worldserver = this.mcServer.getDimensionWorld(this.playerEntity.dimension); - if (worldserver.isBlockLoaded(packetSignUpdate.xPosition, packetSignUpdate.yPosition, packetSignUpdate.zPosition)) { - TileEntity tileEntity = worldserver.getTileEntity(packetSignUpdate.xPosition, packetSignUpdate.yPosition, packetSignUpdate.zPosition); - if (tileEntity instanceof TileEntitySign sign) { - if (!sign.isEditableBy(this.playerEntity)) { - LOGGER.warn("Player {} just tried to change non-editable sign", this.playerEntity.username); - return; - } - } - for (int i = 0; i < 4; i++) { - boolean isLineValid = true; - if (packetSignUpdate.signLines[i].length() > 15) { - isLineValid = false; - } else { - packetSignUpdate.signLines[i] = packetSignUpdate.signLines[i].replaceAll("§", "$"); - for (int l = 0; l < packetSignUpdate.signLines[i].length(); l++) { - if (ChatAllowedCharacters.ALLOWED_CHARACTERS.indexOf(packetSignUpdate.signLines[i].charAt(l)) < 0) { - isLineValid = false; - break; - } - } - } - if (!isLineValid) { - packetSignUpdate.signLines[i] = "!?"; - } - } + final var worldserver = this.mcServer.getDimensionWorld(this.playerEntity.dimension); + final var pos = new TilePos(packetSignUpdate.xPosition, packetSignUpdate.yPosition, packetSignUpdate.zPosition); - if (tileEntity instanceof TileEntitySign sign) { - int x = packetSignUpdate.xPosition; - int y = packetSignUpdate.yPosition; - int z = packetSignUpdate.zPosition; - System.arraycopy(packetSignUpdate.signLines, 0, sign.signText, 0, 4); + if (!worldserver.isBlockLoaded(pos)) return; + if (!(worldserver.getTileEntity(pos) instanceof TileEntitySign sign)) return; - sign.setColor(TextFormatting.FORMATTINGS[packetSignUpdate.color]); - sign.setPicture(EnumSignPicture.values()[packetSignUpdate.picture]); + if (!sign.isEditableBy(this.playerEntity)) { + LOGGER.warn("Player {} just tried to change non-editable sign", this.playerEntity.username); + return; + } - sign.setChanged(); - worldserver.markBlockNeedsUpdate(x, y, z); + for (int i = 0; i < packetSignUpdate.signLines.length; i++) { + final String line = packetSignUpdate.signLines[i]; + assert line.length() <= TileEntitySign.MAX_LINE_SIZE; // PacketSignUpdate.read guarantees + + if (!NetCharacters.isAllowed(line)) { + packetSignUpdate.signLines[i] = "!?"; + continue; } } + + System.arraycopy(packetSignUpdate.signLines, 0, sign.signText, 0, 4); + sign.finalizeEditor(this.playerEntity); + + sign.setColor(TextFormatting.FORMATTINGS[packetSignUpdate.color]); + sign.setPicture(EnumSignPicture.values()[packetSignUpdate.picture]); + + sign.setChanged(); + worldserver.markBlockNeedsUpdate(pos); } @Override @@ -738,6 +723,9 @@ public class PacketHandlerServer extends PacketHandler public void handleSetItemName(@NotNull PacketSetItemName packet) { String name = packet.name; if (name.length() > 16) name = packet.name.substring(0, 16); + if (!this.playerEntity.gamemode.allowColorFormattingInDyeableText()) { + name = TextFormatting.removeAllColorFormatting(name); + } this.playerEntity.inventory.getItem(packet.slot).setCustomName(name); }