aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Skoland <davidskoland@gmail.com>2026-02-10 23:38:17 +0100
committerDavid Skoland <davidskoland@gmail.com>2026-02-10 23:38:17 +0100
commit020dfcda00ca06b9a06e7076eaf8a0164ae1327e (patch)
tree9fe2a8d9fdf81823e48d9a3795e47d0c59964f69
parent9c68a1afcf178a86063f094b96471fa73531bd9a (diff)
Refactor playerlist to state-driven rendering with renderPlayerList
handlePR and handlePU now only update client.playerlist state, and renderPlayerList handles all DOM rendering from that state. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
-rw-r--r--webAO/client.ts5
-rw-r--r--webAO/dom/areaClick.ts10
-rw-r--r--webAO/dom/renderPlayerList.ts50
-rw-r--r--webAO/dom/updatePlayerAreas.ts24
-rw-r--r--webAO/packets/handlers/handleASS.ts21
-rw-r--r--webAO/packets/handlers/handlePR.ts55
-rw-r--r--webAO/packets/handlers/handlePU.ts47
7 files changed, 75 insertions, 137 deletions
diff --git a/webAO/client.ts b/webAO/client.ts
index 95df67a..05a40c9 100644
--- a/webAO/client.ts
+++ b/webAO/client.ts
@@ -150,7 +150,8 @@ class Client extends EventEmitter {
connect: () => void;
loadResources: () => void;
isLowMemory: () => void;
- players: Map<number, { charId: number; area: number }>;
+ /** Maps player ID to player data */
+ playerlist: Map<number, { charId: number; charName: string; showName: string; name: string; area: number }>;
charicon_extensions: string[];
emote_extensions: string[];
emotions_extensions: string[];
@@ -212,7 +213,7 @@ class Client extends EventEmitter {
this.temp_packet = "";
loadResources;
isLowMemory;
- this.players = new Map();
+ this.playerlist = new Map();
this.charicon_extensions = [".png", ".webp"];
this.emote_extensions = [".gif", ".png", ".apng", ".webp", ".webp.static"];
this.emotions_extensions = [".png", ".webp"];
diff --git a/webAO/dom/areaClick.ts b/webAO/dom/areaClick.ts
index 19953a5..f7b177e 100644
--- a/webAO/dom/areaClick.ts
+++ b/webAO/dom/areaClick.ts
@@ -1,6 +1,4 @@
import { client } from "../client";
-import { updatePlayerAreas } from "./updatePlayerAreas";
-import { ensureCharIni } from "../client/handleCharacterInfo";
/**
* Triggered when an item on the area list is clicked.
* @param {HTMLElement} el
@@ -14,13 +12,5 @@ export function area_click(el: HTMLElement) {
areaHr.textContent = `switched to ${el.textContent}`;
document.getElementById("client_log")!.appendChild(areaHr);
client.area = Number(el.id.substring(4));
- updatePlayerAreas(client.area);
-
- // Prefetch char.ini for all characters present in the new area
- for (const player of client.players.values()) {
- if (player.area === client.area && player.charId >= 0) {
- ensureCharIni(player.charId);
- }
- }
}
window.area_click = area_click;
diff --git a/webAO/dom/renderPlayerList.ts b/webAO/dom/renderPlayerList.ts
new file mode 100644
index 0000000..43dab64
--- /dev/null
+++ b/webAO/dom/renderPlayerList.ts
@@ -0,0 +1,50 @@
+import { client } from "../client";
+import { AO_HOST } from "../client/aoHost";
+
+export function renderPlayerList() {
+ const list = document.getElementById("client_playerlist") as HTMLTableElement;
+ list.innerHTML = "";
+
+ for (const [playerID, player] of client.playerlist) {
+ const playerRow = list.insertRow();
+ playerRow.id = `client_playerlist_entry${playerID}`;
+
+ const imgCell = playerRow.insertCell(0);
+ imgCell.style.width = "64px";
+ const img = document.createElement("img");
+ if (player.charId >= 0) {
+ const char = client.chars[player.charId];
+ if (char) {
+ const iconExt = client.charicon_extensions[0] || ".png";
+ img.src = `${AO_HOST}characters/${encodeURI(char.name.toLowerCase())}/char_icon${iconExt}`;
+ img.alt = char.name;
+ img.title = char.name;
+ }
+ }
+ imgCell.appendChild(img);
+
+ const charNameCell = playerRow.insertCell(1);
+ charNameCell.textContent =
+ player.charId >= 0 ? `[${playerID}] ${player.charName}` : "";
+
+ const showNameCell = playerRow.insertCell(2);
+ showNameCell.textContent = player.showName;
+
+ const oocNameCell = playerRow.insertCell(3);
+ oocNameCell.textContent = player.name;
+
+ const kickCell = playerRow.insertCell(4);
+ kickCell.style.width = "64px";
+ const kick = document.createElement("button");
+ kick.innerText = "Kick";
+ kick.onclick = () => window.kickPlayer(playerID);
+ kickCell.appendChild(kick);
+
+ const banCell = playerRow.insertCell(5);
+ banCell.style.width = "64px";
+ const ban = document.createElement("button");
+ ban.innerText = "Ban";
+ ban.onclick = () => window.banPlayer(playerID);
+ banCell.appendChild(ban);
+ }
+}
diff --git a/webAO/dom/updatePlayerAreas.ts b/webAO/dom/updatePlayerAreas.ts
deleted file mode 100644
index 99eccf1..0000000
--- a/webAO/dom/updatePlayerAreas.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { client } from "../client";
-import { area_click } from "./areaClick";
-/**
- * Triggered when someone switches areas
- * @param {Number} ownarea
- */
-export function updatePlayerAreas(ownarea: number) {
- for (let i = 0; i < client.areas.length; i++) {
- if (i === ownarea)
- for (let classelement of Array.from(
- document.getElementsByClassName(
- `area${i}`,
- ) as HTMLCollectionOf<HTMLElement>,
- ))
- classelement.style.display = "";
- else
- for (let classelement of Array.from(
- document.getElementsByClassName(
- `area${i}`,
- ) as HTMLCollectionOf<HTMLElement>,
- ))
- classelement.style.display = "none";
- }
-}
diff --git a/webAO/packets/handlers/handleASS.ts b/webAO/packets/handlers/handleASS.ts
index 092e4f9..c50443a 100644
--- a/webAO/packets/handlers/handleASS.ts
+++ b/webAO/packets/handlers/handleASS.ts
@@ -1,26 +1,11 @@
import { setAOhost } from "../../client/aoHost";
-import { client } from "../../client";
+import { renderPlayerList } from "../../dom/renderPlayerList";
/**
* new asset url!!
* @param {Array} args packet arguments
*/
export const handleASS = (args: string[]) => {
- const host = args[1] !== "None" ? setAOhost(args[1]) : args[1];
-
- // Re-apply playerlist icon srcs that were set before AO_HOST was known
- const iconExt = client.charicon_extensions[0] || ".png";
- for (const [playerID, player] of client.players) {
- if (player.charId >= 0) {
- const char = client.chars[player.charId];
- if (char) {
- const img = document.querySelector<HTMLImageElement>(
- `#client_playerlist_entry${playerID} img`
- );
- if (img) {
- img.src = `${host}characters/${encodeURI(char.name.toLowerCase())}/char_icon${iconExt}`;
- }
- }
- }
- }
+ if (args[1] !== "None") setAOhost(args[1]);
+ renderPlayerList();
};
diff --git a/webAO/packets/handlers/handlePR.ts b/webAO/packets/handlers/handlePR.ts
index e39103d..f81d8dc 100644
--- a/webAO/packets/handlers/handlePR.ts
+++ b/webAO/packets/handlers/handlePR.ts
@@ -1,51 +1,5 @@
import { client } from "../../client";
-import { kickPlayer, banPlayer } from "../../dom/banPlayer";
-
-function addPlayer(playerID: number) {
- const list = <HTMLTableElement>document.getElementById("client_playerlist");
- const playerRow = list.insertRow();
- playerRow.id = `client_playerlist_entry${playerID}`;
- playerRow.className = `area0`;
-
- const imgCell = playerRow.insertCell(0);
- imgCell.style.width = "64px";
- const img = document.createElement("img");
- imgCell.appendChild(img);
-
- const name = document.createTextNode("No Data");
-
- const charNameCell = playerRow.insertCell(1);
- charNameCell.appendChild(name);
- const showNameCell = playerRow.insertCell(2);
- showNameCell.appendChild(name);
- const oocNameCell = playerRow.insertCell(3);
- oocNameCell.appendChild(name);
-
- const kickCell = playerRow.insertCell(4);
- kickCell.style.width = "64px";
- const kick = <HTMLButtonElement>document.createElement("button");
- kick.innerText = "Kick";
- kick.onclick = () => {
- window.kickPlayer(playerID);
- };
- kickCell.appendChild(kick);
-
- const banCell = playerRow.insertCell(5);
- banCell.style.width = "64px";
- const ban = <HTMLButtonElement>document.createElement("button");
- ban.innerText = "Ban";
- ban.onclick = () => {
- window.banPlayer(playerID);
- };
- banCell.appendChild(ban);
-}
-
-function removePlayer(playerID: number) {
- const playerRow = <HTMLTableElement>(
- document.getElementById(`client_playerlist_entry${playerID}`)
- );
- playerRow.remove();
-}
+import { renderPlayerList } from "../../dom/renderPlayerList";
/**
* Handles a player joining or leaving
@@ -54,10 +8,9 @@ function removePlayer(playerID: number) {
export const handlePR = (args: string[]) => {
const playerID = Number(args[1]);
if (Number(args[2]) === 0) {
- addPlayer(playerID);
- client.players.set(playerID, { charId: -1, area: 0 });
+ client.playerlist.set(playerID, { charId: -1, charName: "", showName: "", name: "", area: 0 });
} else if (Number(args[2]) === 1) {
- removePlayer(playerID);
- client.players.delete(playerID);
+ client.playerlist.delete(playerID);
}
+ renderPlayerList();
};
diff --git a/webAO/packets/handlers/handlePU.ts b/webAO/packets/handlers/handlePU.ts
index d8d9b44..3b70ad3 100644
--- a/webAO/packets/handlers/handlePU.ts
+++ b/webAO/packets/handlers/handlePU.ts
@@ -1,59 +1,42 @@
import { client } from "../../client";
-import { updatePlayerAreas } from "../../dom/updatePlayerAreas";
-import { AO_HOST } from "../../client/aoHost";
import { ensureCharIni } from "../../client/handleCharacterInfo";
+import { renderPlayerList } from "../../dom/renderPlayerList";
/**
* Handles a playerlist update
* @param {Array} args packet arguments
*/
export const handlePU = (args: string[]) => {
- const playerRow = <HTMLTableElement>(
- document.getElementById(`client_playerlist_entry${Number(args[1])}`)
- );
+ const playerID = Number(args[1]);
+ const player = client.playerlist.get(playerID);
+ if (!player) return;
+
const type = Number(args[2]);
const data = args[3];
+
switch (type) {
case 0:
- const oocName = <HTMLElement>playerRow.childNodes[3];
- oocName.innerText = data;
+ player.name = data;
break;
case 1:
- const playerImg = <HTMLImageElement>playerRow.childNodes[0].firstChild;
- playerImg.alt = data;
- playerImg.title = data;
- const iconExt = client.charicon_extensions[0] || ".png";
- playerImg.src = `${AO_HOST}characters/${encodeURI(data.toLowerCase())}/char_icon${iconExt}`;
- const charName = <HTMLElement>playerRow.childNodes[1];
- charName.innerText = `[${args[1]}] ${data}`;
+ player.charName = data;
const charId = client.chars.findIndex(
(c: any) => c && c.name.toLowerCase() === data.toLowerCase()
);
if (charId >= 0) {
- const player = client.players.get(Number(args[1]));
- if (player) {
- player.charId = charId;
- if (player.area === client.area) {
- ensureCharIni(charId);
- }
- }
+ player.charId = charId;
+ ensureCharIni(charId);
}
break;
case 2:
- const showName = <HTMLElement>playerRow.childNodes[2];
- showName.innerText = data;
+ player.showName = data;
break;
case 3:
- playerRow.className = `area${data}`;
- updatePlayerAreas(client.area);
- const puPlayer = client.players.get(Number(args[1]));
- if (puPlayer) {
- puPlayer.area = Number(data);
- if (puPlayer.area === client.area && puPlayer.charId >= 0) {
- ensureCharIni(puPlayer.charId);
- }
- }
+ player.area = Number(data);
+ break;
default:
break;
}
+
+ renderPlayerList();
};