Skip to content

Commit 468f942

Browse files
committed
improve performance of chat rendering
1 parent 97df7b6 commit 468f942

File tree

9 files changed

+103
-13
lines changed

9 files changed

+103
-13
lines changed

src/js/net/minecraft/client/GameWindow.js

+8
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export default class GameWindow {
5252
// Create render layers
5353
this.canvasWorld = document.createElement('canvas');
5454
this.canvasDebug = document.createElement('canvas');
55+
this.canvasChat = document.createElement('canvas');
5556
this.canvasPlayerList = document.createElement('canvas');
5657
this.canvasItems = document.createElement('canvas');
5758

@@ -381,6 +382,11 @@ export default class GameWindow {
381382
this.canvasDebug.height = this.canvas.height;
382383
}
383384

385+
if (this.canvasChat.width !== this.canvas.width || this.canvasChat.height !== this.canvas.height) {
386+
this.canvasChat.width = this.canvas.width;
387+
this.canvasChat.height = this.canvas.height;
388+
}
389+
384390
if (this.canvasPlayerList.width !== this.canvas.width || this.canvasPlayerList.height !== this.canvas.height) {
385391
this.canvasPlayerList.width = this.canvas.width;
386392
this.canvasPlayerList.height = this.canvas.height;
@@ -394,6 +400,8 @@ export default class GameWindow {
394400
this.minecraft.currentScreen.setup(this.minecraft, this.width, this.height);
395401
}
396402

403+
this.minecraft.ingameOverlay.chatOverlay.setDirty();
404+
397405
// Render first frame
398406
if (this.minecraft.isInGame()) {
399407
this.minecraft.worldRenderer.render(0);

src/js/net/minecraft/client/Minecraft.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ export default class Minecraft {
3232

3333
// TODO Add to settings
3434
static PROXY = {
35-
"address": "localhost",
36-
"port": 30023
35+
"url": "wss://socket.labystudio.de/minecraft/"
3736
};
3837

3938
/**
@@ -350,7 +349,8 @@ export default class Minecraft {
350349

351350
// Open chat
352351
if (button === this.settings.keyOpenChat) {
353-
this.displayScreen(new GuiChat());
352+
this.displayScreen(new GuiChat(this));
353+
this.ingameOverlay.chatOverlay.setDirty();
354354
}
355355

356356
// Toggle debug overlay

src/js/net/minecraft/client/command/command/TeleportCommand.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Command from "../Command.js";
33
export default class TeleportCommand extends Command {
44

55
constructor() {
6-
super("tp", "<x> <y> <y>", "Teleport to a position")
6+
super("tp", "<x> <y> <z>", "Teleport to a position")
77
}
88

99
execute(minecraft, args) {

src/js/net/minecraft/client/gui/overlay/ChatOverlay.js

+23-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ export default class ChatOverlay extends Gui {
88
constructor(minecraft) {
99
super(minecraft);
1010

11+
this.chatWidth = 320;
12+
1113
this.messages = [];
1214
this.sentHistory = [];
15+
this.dirty = true;
1316
}
1417

1518
render(stack, mouseX, mouseY, partialTicks) {
@@ -30,25 +33,43 @@ export default class ChatOverlay extends Gui {
3033
if (alpha > 0) {
3134
let y = this.minecraft.window.height - 40 - i * 9;
3235

33-
this.drawRect(stack, 2, y - 1, 2 + 320, y + 8, '#000000', alpha / 2 / 255);
36+
this.drawRect(stack, 2, y - 1, 2 + this.chatWidth, y + 8, '#000000', alpha / 2 / 255);
3437
this.drawString(stack, message.message, 2, y, 0xffffff + (alpha << 24));
3538
}
3639
}
40+
this.dirty = false;
3741
}
3842

3943
onTick() {
4044
for (let i = 0; i < this.messages.length; i++) {
4145
let message = this.messages[i];
4246
message.updateCounter++;
47+
48+
// Fade out animation
49+
if (message.updateCounter >= 180 && message.updateCounter <= 200) {
50+
this.dirty = true;
51+
}
4352
}
4453
}
4554

4655
addMessage(message) {
47-
this.messages.splice(0, 0, new ChatLine(message));
56+
for (let line of this.minecraft.fontRenderer.listFormattedStringToWidth(message, this.chatWidth)) {
57+
this.messages.splice(0, 0, new ChatLine(line));
58+
}
59+
this.dirty = true;
4860
}
4961

5062
addMessageToSentHistory(message) {
5163
this.sentHistory.splice(0, 0, message);
64+
this.dirty = true;
65+
}
66+
67+
isDirty() {
68+
return this.dirty;
69+
}
70+
71+
setDirty() {
72+
this.dirty = true;
5273
}
5374

5475
}

src/js/net/minecraft/client/gui/overlay/IngameOverlay.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ export default class IngameOverlay extends Gui {
3434
// Render hotbar
3535
this.renderHotbar(stack, this.window.width / 2 - 91, this.window.height - 22);
3636

37-
// Render chat
38-
this.chatOverlay.render(stack, mouseX, mouseY, partialTicks);
37+
// Render chat canvas
38+
stack.drawImage(this.window.canvasChat, 0, 0);
3939

4040
// Render debug canvas on stack
4141
if (this.minecraft.settings.debugOverlay) {
@@ -70,6 +70,13 @@ export default class IngameOverlay extends Gui {
7070

7171
this.ticksRendered++;
7272
}
73+
74+
// Render chat on tick if dirty
75+
if (this.chatOverlay.isDirty()) {
76+
let stack = this.window.canvasChat.getContext('2d');
77+
stack.clearRect(0, 0, this.window.width, this.window.height);
78+
this.chatOverlay.render(stack, 0, 0, 0);
79+
}
7380
}
7481

7582
renderCrosshair(stack, x, y) {

src/js/net/minecraft/client/gui/screens/GuiChat.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import GuiTextField from "../widgets/GuiTextField.js";
33

44
export default class GuiChat extends GuiScreen {
55

6-
constructor() {
6+
constructor(minecraft) {
77
super();
88

9+
this.minecraft = minecraft;
10+
911
this.inputField = new GuiTextField(0, 0, 0, 0);
1012
this.inputField.renderBackground = false;
1113

@@ -24,6 +26,11 @@ export default class GuiChat extends GuiScreen {
2426
this.buttonList.push(this.inputField);
2527
}
2628

29+
onClose() {
30+
super.onClose();
31+
this.minecraft.ingameOverlay.chatOverlay.setDirty();
32+
}
33+
2734
drawScreen(stack, mouseX, mouseY, partialTicks) {
2835
this.drawRect(stack, 2, this.height - 14, this.width - 2, this.height - 2, '#000000', 0.5);
2936

src/js/net/minecraft/client/network/NetworkManager.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default class NetworkManager {
3131
}
3232

3333
connect(address, port, proxy) {
34-
this.socket = new WebSocket("ws://" + proxy.address + ":" + proxy.port);
34+
this.socket = new WebSocket(proxy.url);
3535
this.socket.binaryType = "arraybuffer";
3636

3737
this.socket.onopen = e => this._onOpen(e);

src/js/net/minecraft/client/network/packet/play/server/ServerJoinGamePacket.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default class ServerJoinGamePacket extends Packet {
2020
}
2121

2222
read(buffer) {
23-
this.entityId = buffer.readVarInt();
23+
this.entityId = buffer.readInt();
2424
let bits = buffer.readByte();
2525
this.hardcoreMode = (bits & 8) === 8;
2626
this.gameType = bits & -9;

src/js/net/minecraft/client/render/gui/FontRenderer.js

+49-2
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ export default class FontRenderer {
140140
return length;
141141
}
142142

143-
144143
createBitMap(img) {
145144
let canvas = document.createElement('canvas');
146145
canvas.width = img.width;
@@ -178,6 +177,54 @@ export default class FontRenderer {
178177
}
179178

180179
listFormattedStringToWidth(text, wrapWidth) {
181-
return text.split("\n"); // TODO Implement wrap logic
180+
let lines = [];
181+
let currentColorCharacter = "r";
182+
for (let line of text.split('\n')) {
183+
let currentLine = '';
184+
let currentLineWidth = 0;
185+
186+
// Split the text into words
187+
for (let word of line.split(' ')) {
188+
const wordWidth = this.getStringWidth(word + " ");
189+
190+
// If adding the word exceeds the wrap width, start a new line
191+
if (currentLineWidth + wordWidth > wrapWidth) {
192+
lines.push(FontRenderer.COLOR_PREFIX + currentColorCharacter + currentLine.trim());
193+
currentColorCharacter = this.getLastColorCharacterOfText(currentLine);
194+
195+
currentLine = '';
196+
currentLineWidth = 0;
197+
}
198+
199+
// Add the word to the current line
200+
currentLine += word + ' ';
201+
currentLineWidth += wordWidth;
202+
}
203+
204+
// Push the last line
205+
if (currentLine.length > 0) {
206+
lines.push(FontRenderer.COLOR_PREFIX + currentColorCharacter + currentLine.trim());
207+
currentColorCharacter = this.getLastColorCharacterOfText(currentLine);
208+
}
209+
}
210+
return lines;
211+
}
212+
213+
getLastColorCharacterOfText(text) {
214+
let character = "r";
215+
let isColorCode = false;
216+
217+
// For each character
218+
for (let i = 0; i < text.length; i++) {
219+
if (text[i] === FontRenderer.COLOR_PREFIX) {
220+
isColorCode = true;
221+
} else {
222+
if (isColorCode) {
223+
character = text[i];
224+
isColorCode = false;
225+
}
226+
}
227+
}
228+
return character;
182229
}
183230
}

0 commit comments

Comments
 (0)