improve performance of chat rendering

This commit is contained in:
LabyStudio
2024-01-26 13:25:53 +01:00
parent 97df7b6560
commit 468f942c49
9 changed files with 103 additions and 13 deletions
@@ -52,6 +52,7 @@ export default class GameWindow {
// Create render layers // Create render layers
this.canvasWorld = document.createElement('canvas'); this.canvasWorld = document.createElement('canvas');
this.canvasDebug = document.createElement('canvas'); this.canvasDebug = document.createElement('canvas');
this.canvasChat = document.createElement('canvas');
this.canvasPlayerList = document.createElement('canvas'); this.canvasPlayerList = document.createElement('canvas');
this.canvasItems = document.createElement('canvas'); this.canvasItems = document.createElement('canvas');
@@ -381,6 +382,11 @@ export default class GameWindow {
this.canvasDebug.height = this.canvas.height; this.canvasDebug.height = this.canvas.height;
} }
if (this.canvasChat.width !== this.canvas.width || this.canvasChat.height !== this.canvas.height) {
this.canvasChat.width = this.canvas.width;
this.canvasChat.height = this.canvas.height;
}
if (this.canvasPlayerList.width !== this.canvas.width || this.canvasPlayerList.height !== this.canvas.height) { if (this.canvasPlayerList.width !== this.canvas.width || this.canvasPlayerList.height !== this.canvas.height) {
this.canvasPlayerList.width = this.canvas.width; this.canvasPlayerList.width = this.canvas.width;
this.canvasPlayerList.height = this.canvas.height; this.canvasPlayerList.height = this.canvas.height;
@@ -394,6 +400,8 @@ export default class GameWindow {
this.minecraft.currentScreen.setup(this.minecraft, this.width, this.height); this.minecraft.currentScreen.setup(this.minecraft, this.width, this.height);
} }
this.minecraft.ingameOverlay.chatOverlay.setDirty();
// Render first frame // Render first frame
if (this.minecraft.isInGame()) { if (this.minecraft.isInGame()) {
this.minecraft.worldRenderer.render(0); this.minecraft.worldRenderer.render(0);
+3 -3
View File
@@ -32,8 +32,7 @@ export default class Minecraft {
// TODO Add to settings // TODO Add to settings
static PROXY = { static PROXY = {
"address": "localhost", "url": "wss://socket.labystudio.de/minecraft/"
"port": 30023
}; };
/** /**
@@ -350,7 +349,8 @@ export default class Minecraft {
// Open chat // Open chat
if (button === this.settings.keyOpenChat) { if (button === this.settings.keyOpenChat) {
this.displayScreen(new GuiChat()); this.displayScreen(new GuiChat(this));
this.ingameOverlay.chatOverlay.setDirty();
} }
// Toggle debug overlay // Toggle debug overlay
@@ -3,7 +3,7 @@ import Command from "../Command.js";
export default class TeleportCommand extends Command { export default class TeleportCommand extends Command {
constructor() { constructor() {
super("tp", "<x> <y> <y>", "Teleport to a position") super("tp", "<x> <y> <z>", "Teleport to a position")
} }
execute(minecraft, args) { execute(minecraft, args) {
@@ -8,8 +8,11 @@ export default class ChatOverlay extends Gui {
constructor(minecraft) { constructor(minecraft) {
super(minecraft); super(minecraft);
this.chatWidth = 320;
this.messages = []; this.messages = [];
this.sentHistory = []; this.sentHistory = [];
this.dirty = true;
} }
render(stack, mouseX, mouseY, partialTicks) { render(stack, mouseX, mouseY, partialTicks) {
@@ -30,25 +33,43 @@ export default class ChatOverlay extends Gui {
if (alpha > 0) { if (alpha > 0) {
let y = this.minecraft.window.height - 40 - i * 9; let y = this.minecraft.window.height - 40 - i * 9;
this.drawRect(stack, 2, y - 1, 2 + 320, y + 8, '#000000', alpha / 2 / 255); this.drawRect(stack, 2, y - 1, 2 + this.chatWidth, y + 8, '#000000', alpha / 2 / 255);
this.drawString(stack, message.message, 2, y, 0xffffff + (alpha << 24)); this.drawString(stack, message.message, 2, y, 0xffffff + (alpha << 24));
} }
} }
this.dirty = false;
} }
onTick() { onTick() {
for (let i = 0; i < this.messages.length; i++) { for (let i = 0; i < this.messages.length; i++) {
let message = this.messages[i]; let message = this.messages[i];
message.updateCounter++; message.updateCounter++;
// Fade out animation
if (message.updateCounter >= 180 && message.updateCounter <= 200) {
this.dirty = true;
}
} }
} }
addMessage(message) { addMessage(message) {
this.messages.splice(0, 0, new ChatLine(message)); for (let line of this.minecraft.fontRenderer.listFormattedStringToWidth(message, this.chatWidth)) {
this.messages.splice(0, 0, new ChatLine(line));
}
this.dirty = true;
} }
addMessageToSentHistory(message) { addMessageToSentHistory(message) {
this.sentHistory.splice(0, 0, message); this.sentHistory.splice(0, 0, message);
this.dirty = true;
}
isDirty() {
return this.dirty;
}
setDirty() {
this.dirty = true;
} }
} }
@@ -34,8 +34,8 @@ export default class IngameOverlay extends Gui {
// Render hotbar // Render hotbar
this.renderHotbar(stack, this.window.width / 2 - 91, this.window.height - 22); this.renderHotbar(stack, this.window.width / 2 - 91, this.window.height - 22);
// Render chat // Render chat canvas
this.chatOverlay.render(stack, mouseX, mouseY, partialTicks); stack.drawImage(this.window.canvasChat, 0, 0);
// Render debug canvas on stack // Render debug canvas on stack
if (this.minecraft.settings.debugOverlay) { if (this.minecraft.settings.debugOverlay) {
@@ -70,6 +70,13 @@ export default class IngameOverlay extends Gui {
this.ticksRendered++; this.ticksRendered++;
} }
// Render chat on tick if dirty
if (this.chatOverlay.isDirty()) {
let stack = this.window.canvasChat.getContext('2d');
stack.clearRect(0, 0, this.window.width, this.window.height);
this.chatOverlay.render(stack, 0, 0, 0);
}
} }
renderCrosshair(stack, x, y) { renderCrosshair(stack, x, y) {
@@ -3,9 +3,11 @@ import GuiTextField from "../widgets/GuiTextField.js";
export default class GuiChat extends GuiScreen { export default class GuiChat extends GuiScreen {
constructor() { constructor(minecraft) {
super(); super();
this.minecraft = minecraft;
this.inputField = new GuiTextField(0, 0, 0, 0); this.inputField = new GuiTextField(0, 0, 0, 0);
this.inputField.renderBackground = false; this.inputField.renderBackground = false;
@@ -24,6 +26,11 @@ export default class GuiChat extends GuiScreen {
this.buttonList.push(this.inputField); this.buttonList.push(this.inputField);
} }
onClose() {
super.onClose();
this.minecraft.ingameOverlay.chatOverlay.setDirty();
}
drawScreen(stack, mouseX, mouseY, partialTicks) { drawScreen(stack, mouseX, mouseY, partialTicks) {
this.drawRect(stack, 2, this.height - 14, this.width - 2, this.height - 2, '#000000', 0.5); this.drawRect(stack, 2, this.height - 14, this.width - 2, this.height - 2, '#000000', 0.5);
@@ -31,7 +31,7 @@ export default class NetworkManager {
} }
connect(address, port, proxy) { connect(address, port, proxy) {
this.socket = new WebSocket("ws://" + proxy.address + ":" + proxy.port); this.socket = new WebSocket(proxy.url);
this.socket.binaryType = "arraybuffer"; this.socket.binaryType = "arraybuffer";
this.socket.onopen = e => this._onOpen(e); this.socket.onopen = e => this._onOpen(e);
@@ -20,7 +20,7 @@ export default class ServerJoinGamePacket extends Packet {
} }
read(buffer) { read(buffer) {
this.entityId = buffer.readVarInt(); this.entityId = buffer.readInt();
let bits = buffer.readByte(); let bits = buffer.readByte();
this.hardcoreMode = (bits & 8) === 8; this.hardcoreMode = (bits & 8) === 8;
this.gameType = bits & -9; this.gameType = bits & -9;
@@ -140,7 +140,6 @@ export default class FontRenderer {
return length; return length;
} }
createBitMap(img) { createBitMap(img) {
let canvas = document.createElement('canvas'); let canvas = document.createElement('canvas');
canvas.width = img.width; canvas.width = img.width;
@@ -178,6 +177,54 @@ export default class FontRenderer {
} }
listFormattedStringToWidth(text, wrapWidth) { listFormattedStringToWidth(text, wrapWidth) {
return text.split("\n"); // TODO Implement wrap logic let lines = [];
let currentColorCharacter = "r";
for (let line of text.split('\n')) {
let currentLine = '';
let currentLineWidth = 0;
// Split the text into words
for (let word of line.split(' ')) {
const wordWidth = this.getStringWidth(word + " ");
// If adding the word exceeds the wrap width, start a new line
if (currentLineWidth + wordWidth > wrapWidth) {
lines.push(FontRenderer.COLOR_PREFIX + currentColorCharacter + currentLine.trim());
currentColorCharacter = this.getLastColorCharacterOfText(currentLine);
currentLine = '';
currentLineWidth = 0;
}
// Add the word to the current line
currentLine += word + ' ';
currentLineWidth += wordWidth;
}
// Push the last line
if (currentLine.length > 0) {
lines.push(FontRenderer.COLOR_PREFIX + currentColorCharacter + currentLine.trim());
currentColorCharacter = this.getLastColorCharacterOfText(currentLine);
}
}
return lines;
}
getLastColorCharacterOfText(text) {
let character = "r";
let isColorCode = false;
// For each character
for (let i = 0; i < text.length; i++) {
if (text[i] === FontRenderer.COLOR_PREFIX) {
isColorCode = true;
} else {
if (isColorCode) {
character = text[i];
isColorCode = false;
}
}
}
return character;
} }
} }