aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--webAO/client/handleCharacterInfo.ts174
-rw-r--r--webAO/packets/handlers/handleMS.ts5
-rw-r--r--webAO/packets/handlers/handlePU.ts6
-rw-r--r--webAO/packets/handlers/handlePV.ts3
-rw-r--r--webAO/packets/handlers/handleSC.ts7
-rw-r--r--webAO/packets/handlers/handleSI.ts1
6 files changed, 116 insertions, 80 deletions
diff --git a/webAO/client/handleCharacterInfo.ts b/webAO/client/handleCharacterInfo.ts
index 3764c84..0235f3b 100644
--- a/webAO/client/handleCharacterInfo.ts
+++ b/webAO/client/handleCharacterInfo.ts
@@ -2,50 +2,21 @@ import { client } from "../client";
import { safeTags } from "../encoding";
import iniParse from "../iniParse";
import request from "../services/request";
-import fileExists from "../utils/fileExists";
import { AO_HOST } from "./aoHost";
-export const getCharIcon = async (img: HTMLImageElement, charname: string) => {
- img.alt = charname;
- const charIconBaseUrl = `${AO_HOST}characters/${encodeURI(
- charname.toLowerCase(),
- )}/char_icon`;
- for (let i = 0; i < client.charicon_extensions.length; i++) {
- const fileUrl = charIconBaseUrl + client.charicon_extensions[i];
- const exists = await fileExists(fileUrl);
- if (exists) {
- img.alt = charname;
- img.title = charname;
- img.src = fileUrl;
- return;
- }
- }
-};
-
/**
- * Handles the incoming character information, and downloads the sprite + ini for it
- * @param {Array} chargs packet arguments
- * @param {Number} charid character ID
+ * Lightweight character setup that runs on join. Sets the icon src directly
+ * (letting the browser handle loading) and stores default character data.
+ * Does NOT fetch char.ini — that is deferred until needed via ensureCharIni.
*/
-export const handleCharacterInfo = async (chargs: string[], charid: number) => {
+export const setupCharacterBasic = (chargs: string[], charid: number) => {
const img = <HTMLImageElement>document.getElementById(`demo_${charid}`);
if (chargs[0]) {
- let cini: any = {};
-
- getCharIcon(img, chargs[0]);
-
- // If the ini doesn't exist on the server this will throw an error
- try {
- const cinidata = await request(
- `${AO_HOST}characters/${encodeURI(chargs[0].toLowerCase())}/char.ini`,
- );
- cini = iniParse(cinidata);
- } catch (err) {
- cini = {};
- img.classList.add("noini");
- console.warn(`character ${chargs[0]} is missing from webAO`);
- // If it does, give the user a visual indication that the character is unusable
- }
+ img.alt = chargs[0];
+ img.title = chargs[0];
+ img.src = `${AO_HOST}characters/${encodeURI(
+ chargs[0].toLowerCase(),
+ )}/char_icon.png`;
const mute_select = <HTMLSelectElement>(
document.getElementById("mute_select")
@@ -56,47 +27,108 @@ export const handleCharacterInfo = async (chargs: string[], charid: number) => {
);
pair_select.add(new Option(safeTags(chargs[0]), String(charid)));
- // sometimes ini files lack important settings
- const default_options = {
- name: chargs[0],
- showname: chargs[0],
- side: "def",
- blips: "male",
- chat: "",
- category: "",
- };
- cini.options = Object.assign(default_options, cini.options);
-
- // sometimes ini files lack important settings
- const default_emotions = {
- number: 0,
- };
- cini.emotions = Object.assign(default_emotions, cini.emotions);
-
+ // Store defaults — these get replaced with actual ini values by ensureCharIni
client.chars[charid] = {
name: safeTags(chargs[0]),
- showname: safeTags(cini.options.showname),
+ showname: safeTags(chargs[0]),
desc: safeTags(chargs[1]),
- blips: safeTags(cini.options.blips).toLowerCase(),
- gender: safeTags(cini.options.gender).toLowerCase(),
- side: safeTags(cini.options.side).toLowerCase(),
- chat:
- cini.options.chat === ""
- ? safeTags(cini.options.category).toLowerCase()
- : safeTags(cini.options.chat).toLowerCase(),
+ blips: "male",
+ gender: "",
+ side: "def",
+ chat: "",
evidence: chargs[3],
- icon: img.src,
- inifile: cini,
+ icon: "",
muted: false,
};
+ } else {
+ console.warn(`missing charid ${charid}`);
+ img.style.display = "none";
+ }
+};
- if (
- client.chars[charid].blips === "male" &&
- client.chars[charid].gender !== "male" &&
- client.chars[charid].gender !== ""
- ) {
- client.chars[charid].blips = client.chars[charid].gender;
+/**
+ * Fetches and parses char.ini for a character if not already loaded.
+ * Replaces default values in client.chars[charid] with actual ini values.
+ */
+export const ensureCharIni = async (charid: number): Promise<any> => {
+ const char = client.chars[charid];
+ if (!char) return {};
+ if (char.inifile) return char.inifile;
+
+ const img = <HTMLImageElement>document.getElementById(`demo_${charid}`);
+ let cini: any = {};
+
+ try {
+ const cinidata = await request(
+ `${AO_HOST}characters/${encodeURI(char.name.toLowerCase())}/char.ini`,
+ );
+ cini = iniParse(cinidata);
+ } catch (err) {
+ cini = {};
+ if (img) img.classList.add("noini");
+ console.warn(`character ${char.name} is missing from webAO`);
+ }
+
+ const default_options = {
+ name: char.name,
+ showname: char.name,
+ side: "def",
+ blips: "male",
+ chat: "",
+ category: "",
+ };
+ cini.options = Object.assign(default_options, cini.options);
+
+ const default_emotions = {
+ number: 0,
+ };
+ cini.emotions = Object.assign(default_emotions, cini.emotions);
+
+ // Replace defaults with actual ini values
+ char.showname = safeTags(cini.options.showname);
+ char.blips = safeTags(cini.options.blips).toLowerCase();
+ char.gender = safeTags(cini.options.gender).toLowerCase();
+ char.side = safeTags(cini.options.side).toLowerCase();
+ char.chat =
+ cini.options.chat === ""
+ ? safeTags(cini.options.category).toLowerCase()
+ : safeTags(cini.options.chat).toLowerCase();
+ char.icon = img ? img.src : "";
+ char.inifile = cini;
+
+ if (
+ char.blips === "male" &&
+ char.gender !== "male" &&
+ char.gender !== ""
+ ) {
+ char.blips = char.gender;
+ }
+
+ return cini;
+};
+
+/**
+ * Full character info load (used by iniEdit and handleMS ini-edit path).
+ * Fetches icon + ini for a single character, replacing any existing data.
+ */
+export const handleCharacterInfo = async (chargs: string[], charid: number) => {
+ const img = <HTMLImageElement>document.getElementById(`demo_${charid}`);
+ if (chargs[0]) {
+ img.alt = chargs[0];
+ img.title = chargs[0];
+ img.src = `${AO_HOST}characters/${encodeURI(
+ chargs[0].toLowerCase(),
+ )}/char_icon.png`;
+
+ // Reset inifile so ensureCharIni will re-fetch
+ if (client.chars[charid]) {
+ client.chars[charid].name = safeTags(chargs[0]);
+ client.chars[charid].inifile = null;
+ } else {
+ setupCharacterBasic(chargs, charid);
}
+
+ await ensureCharIni(charid);
} else {
console.warn(`missing charid ${charid}`);
img.style.display = "none";
diff --git a/webAO/packets/handlers/handleMS.ts b/webAO/packets/handlers/handleMS.ts
index 2622fe6..9b46bc0 100644
--- a/webAO/packets/handlers/handleMS.ts
+++ b/webAO/packets/handlers/handleMS.ts
@@ -1,7 +1,7 @@
/* eslint indent: ["error", 2, { "SwitchCase": 1 }] */
import { client, extrafeatures, UPDATE_INTERVAL } from "../../client";
-import { handleCharacterInfo } from "../../client/handleCharacterInfo";
+import { handleCharacterInfo, ensureCharIni } from "../../client/handleCharacterInfo";
import { resetICParams } from "../../client/resetICParams";
import { prepChat, safeTags } from "../../encoding";
import { handle_ic_speaking } from "../../viewport/utils/handleICSpeaking";
@@ -27,6 +27,9 @@ export const handleMS = (args: string[]) => {
);
const chargs = (`${char_name}&` + "iniediter").split("&");
handleCharacterInfo(chargs, char_id);
+ } else if (!client.chars[char_id].inifile) {
+ // Lazily load char.ini in background so future messages have proper data
+ ensureCharIni(char_id);
}
}
diff --git a/webAO/packets/handlers/handlePU.ts b/webAO/packets/handlers/handlePU.ts
index 508bb51..18e508e 100644
--- a/webAO/packets/handlers/handlePU.ts
+++ b/webAO/packets/handlers/handlePU.ts
@@ -1,6 +1,6 @@
import { client } from "../../client";
-import { getCharIcon } from "../../client/handleCharacterInfo";
import { updatePlayerAreas } from "../../dom/updatePlayerAreas";
+import { AO_HOST } from "../../client/aoHost";
/**
* Handles a playerlist update
@@ -19,7 +19,9 @@ export const handlePU = (args: string[]) => {
break;
case 1:
const playerImg = <HTMLImageElement>playerRow.childNodes[0].firstChild;
- getCharIcon(playerImg, data);
+ playerImg.alt = data;
+ playerImg.title = data;
+ playerImg.src = `${AO_HOST}characters/${encodeURI(data.toLowerCase())}/char_icon.png`;
const charName = <HTMLElement>playerRow.childNodes[1];
charName.innerText = `[${args[1]}] ${data}`;
break;
diff --git a/webAO/packets/handlers/handlePV.ts b/webAO/packets/handlers/handlePV.ts
index 4ac747f..149d90e 100644
--- a/webAO/packets/handlers/handlePV.ts
+++ b/webAO/packets/handlers/handlePV.ts
@@ -3,6 +3,7 @@ import fileExists from "../../utils/fileExists";
import { updateActionCommands } from "../../dom/updateActionCommands";
import { pickEmotion } from "../../dom/pickEmotion";
import { AO_HOST } from "../../client/aoHost";
+import { ensureCharIni } from "../../client/handleCharacterInfo";
function addEmoteButton(i: number, imgurl: string, desc: string) {
const emotesList = document.getElementById("client_emo");
@@ -34,7 +35,7 @@ export const handlePV = async (args: string[]) => {
const emotesList = document.getElementById("client_emo");
emotesList.style.display = "";
emotesList.innerHTML = ""; // Clear emote box
- const ini = me.inifile;
+ const ini = await ensureCharIni(client.charID);
me.side = ini.options.side;
updateActionCommands(me.side);
if (ini.emotions.number === 0) {
diff --git a/webAO/packets/handlers/handleSC.ts b/webAO/packets/handlers/handleSC.ts
index 271a164..f7b789f 100644
--- a/webAO/packets/handlers/handleSC.ts
+++ b/webAO/packets/handlers/handleSC.ts
@@ -1,7 +1,7 @@
import queryParser from "../../utils/queryParser";
import { client } from "../../client";
-import { handleCharacterInfo } from "../../client/handleCharacterInfo";
+import { setupCharacterBasic } from "../../client/handleCharacterInfo";
const { mode } = queryParser();
/**
@@ -17,13 +17,10 @@ export const handleSC = async (args: string[]) => {
document.getElementById("client_charselect")!.style.display = "block";
}
- document.getElementById("client_loadingtext")!.innerHTML =
- "Loading Characters";
for (let i = 1; i < args.length; i++) {
const chargs = args[i].split("&");
const charid = i - 1;
-
- setTimeout(() => handleCharacterInfo(chargs, charid), charid * 6);
+ setupCharacterBasic(chargs, charid);
}
// We're done with the characters, request the music
client.sender.sendServer("RM#%");
diff --git a/webAO/packets/handlers/handleSI.ts b/webAO/packets/handlers/handleSI.ts
index f20f4b2..eac84e0 100644
--- a/webAO/packets/handlers/handleSI.ts
+++ b/webAO/packets/handlers/handleSI.ts
@@ -20,6 +20,7 @@ export const handleSI = (args: string[]) => {
const demothing = document.createElement("img");
demothing.className = "demothing";
+ demothing.loading = "lazy";
demothing.id = `demo_${i}`;
const demoonclick = document.createAttribute("onclick");
demoonclick.value = `pickChar(${i})`;