diff options
| -rw-r--r-- | webAO/client/handleCharacterInfo.ts | 174 | ||||
| -rw-r--r-- | webAO/packets/handlers/handleMS.ts | 5 | ||||
| -rw-r--r-- | webAO/packets/handlers/handlePU.ts | 6 | ||||
| -rw-r--r-- | webAO/packets/handlers/handlePV.ts | 3 | ||||
| -rw-r--r-- | webAO/packets/handlers/handleSC.ts | 7 | ||||
| -rw-r--r-- | webAO/packets/handlers/handleSI.ts | 1 |
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})`; |
