diff --git a/common/src/main/java/com/viaversion/viarewind/protocol/v1_8to1_7_6_10/data/ChatNewlineRewriter.java b/common/src/main/java/com/viaversion/viarewind/protocol/v1_8to1_7_6_10/data/ChatNewlineRewriter.java
new file mode 100644
index 000000000..fd4761aa8
--- /dev/null
+++ b/common/src/main/java/com/viaversion/viarewind/protocol/v1_8to1_7_6_10/data/ChatNewlineRewriter.java
@@ -0,0 +1,149 @@
+/*
+ * This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind
+ * Copyright (C) 2018-2026 ViaVersion and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data;
+
+import com.viaversion.viaversion.libs.gson.JsonArray;
+import com.viaversion.viaversion.libs.gson.JsonElement;
+import com.viaversion.viaversion.libs.gson.JsonObject;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class ChatNewlineRewriter {
+ public static List splitChatComponentByNewline(JsonElement element) {
+ return splitChatComponentByNewline(element, new JsonObject());
+ }
+
+ private static List splitChatComponentByNewline(JsonElement element, JsonObject inheritedStyle) {
+ List results = new ArrayList<>();
+ if (element == null || element.isJsonNull()) {
+ return results;
+ }
+
+ if (element.isJsonPrimitive()) {
+ String text = element.getAsString();
+ for (String part : text.split("\n", -1)) {
+ JsonObject obj = inheritedStyle.deepCopy();
+ obj.addProperty("text", part);
+ results.add(obj);
+ }
+ return results;
+ }
+
+ if (element.isJsonArray()) {
+ for (JsonElement child : element.getAsJsonArray()) {
+ results.addAll(splitChatComponentByNewline(child, inheritedStyle));
+ }
+ return results;
+ }
+
+ if (!element.isJsonObject()) {
+ return results;
+ }
+
+ JsonObject obj = element.getAsJsonObject();
+
+ // Build the style for this node: inherit first, then override with this object's style
+ JsonObject currentStyle = inheritedStyle.deepCopy();
+ for (Map.Entry entry : obj.entrySet()) {
+ String key = entry.getKey();
+ if (!"text".equals(key) && !"extra".equals(key)) {
+ currentStyle.add(key, entry.getValue());
+ }
+ }
+
+ // Gather components in order: base text then extra array
+ List ordered = new ArrayList<>();
+ if (obj.has("text")) {
+ ordered.add(obj.get("text"));
+ }
+ if (obj.has("extra") && obj.get("extra").isJsonArray()) {
+ for (JsonElement extra : obj.getAsJsonArray("extra")) {
+ ordered.add(extra);
+ }
+ }
+
+ // If there is no text/extra, return a single object with the style
+ if (ordered.isEmpty()) {
+ results.add(currentStyle);
+ return results;
+ }
+
+ // Build lines by concatenating split pieces
+ List currentLine = new ArrayList<>();
+ for (JsonElement part : ordered) {
+ if (part == null || part.isJsonNull()) {
+ continue;
+ }
+
+ if (part.isJsonPrimitive()) {
+ String text = part.getAsString();
+ String[] split = text.split("\n", -1);
+ for (int i = 0; i < split.length; i++) {
+ JsonObject piece = currentStyle.deepCopy();
+ piece.addProperty("text", split[i]);
+ currentLine.add(piece);
+
+ if (i < split.length - 1) {
+ results.add(mergeLine(currentLine));
+ currentLine.clear();
+ }
+ }
+ continue;
+ }
+
+ if (part.isJsonObject() || part.isJsonArray()) {
+ List splitParts = splitChatComponentByNewline(part, currentStyle);
+ for (int i = 0; i < splitParts.size(); i++) {
+ currentLine.add(splitParts.get(i));
+ if (i < splitParts.size() - 1) {
+ results.add(mergeLine(currentLine));
+ currentLine.clear();
+ }
+ }
+ }
+ }
+
+ if (!currentLine.isEmpty()) {
+ results.add(mergeLine(currentLine));
+ }
+
+ return results;
+ }
+
+ private static JsonObject mergeLine(List lineParts) {
+ if (lineParts.isEmpty()) {
+ JsonObject empty = new JsonObject();
+ empty.addProperty("text", "");
+ return empty;
+ }
+
+ JsonObject first = lineParts.get(0);
+ if (lineParts.size() == 1) {
+ return first;
+ }
+
+ JsonArray extra = new JsonArray();
+ for (int i = 1; i < lineParts.size(); i++) {
+ extra.add(lineParts.get(i));
+ }
+ first.add("extra", extra);
+ return first;
+ }
+}
diff --git a/common/src/main/java/com/viaversion/viarewind/protocol/v1_8to1_7_6_10/rewriter/PlayerPacketRewriter1_8.java b/common/src/main/java/com/viaversion/viarewind/protocol/v1_8to1_7_6_10/rewriter/PlayerPacketRewriter1_8.java
index ef5c08199..ccfac6dd6 100644
--- a/common/src/main/java/com/viaversion/viarewind/protocol/v1_8to1_7_6_10/rewriter/PlayerPacketRewriter1_8.java
+++ b/common/src/main/java/com/viaversion/viarewind/protocol/v1_8to1_7_6_10/rewriter/PlayerPacketRewriter1_8.java
@@ -30,6 +30,7 @@
import com.viaversion.viarewind.protocol.v1_7_6_10to1_7_2_5.packet.ServerboundPackets1_7_2_5;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.Protocol1_8To1_7_6_10;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data.ChatItemRewriter;
+import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.data.ChatNewlineRewriter;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.provider.TitleRenderProvider;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.EntityTracker1_8;
import com.viaversion.viarewind.protocol.v1_8to1_7_6_10.storage.GameProfileStorage;
@@ -46,6 +47,7 @@
import com.viaversion.viaversion.api.rewriter.RewriterBase;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonElement;
+import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_8;
import com.viaversion.viaversion.util.ComponentUtil;
@@ -70,13 +72,27 @@ protected void registerPackets() {
@Override
public void register() {
map(Types.COMPONENT); // Chat message
+
handler(wrapper -> {
final JsonElement json = wrapper.get(Types.COMPONENT, 0);
- ChatItemRewriter.toClient(protocol, wrapper.user(), json);
-
final int position = wrapper.read(Types.BYTE);
+
if (position == 2) { // Above hotbar
wrapper.cancel();
+ return;
+ }
+
+ ChatItemRewriter.toClient(protocol, wrapper.user(), json);
+ List splitComponents = ChatNewlineRewriter.splitChatComponentByNewline(json);
+
+ if (splitComponents.size() > 1) {
+ wrapper.cancel();
+
+ for (JsonObject split : splitComponents) {
+ PacketWrapper newWrapper = wrapper.create(ClientboundPackets1_7_2_5.CHAT);
+ newWrapper.write(Types.COMPONENT, split);
+ newWrapper.send(Protocol1_8To1_7_6_10.class);
+ }
}
});
}