Skip to main content
Glama
equipment.ts6.69 kB
import { join } from 'path'; import { readXML } from './xml.js'; import { readDVPLString } from '../dvpl/reader.js'; import { getString } from './strings.js'; import type { Config } from '../config.js'; import type { Equipment, Consumable, Provision } from '../data/types.js'; interface ScriptObject { '#text'?: string; cooldown?: number; duration?: number; bonusValues?: Record<string, number>; } type DisplayParamValue = number | Record<string, number>; interface OptionalDeviceEntry { id: number; userString: string; description: string; icon: string; script: string | ScriptObject; display_params?: Record<string, DisplayParamValue>; } interface OptionalDevicesXML { root: Record<string, OptionalDeviceEntry | number>; } interface ConsumableEntry { id: number; userString: string; description: string; icon: string; category: string; tags: string; script: string | ScriptObject; display_params?: Record<string, DisplayParamValue>; } interface ConsumablesXML { root: Record<string, ConsumableEntry>; } interface ProvisionEntry { id: number; userString: string; description: string; icon: string; category: string; tags: string; script: string | ScriptObject; display_params?: Record<string, DisplayParamValue>; } interface ProvisionsXML { root: Record<string, ProvisionEntry>; } let equipmentCache: Equipment[] | null = null; let consumablesCache: Consumable[] | null = null; let provisionsCache: Provision[] | null = null; function getScriptCooldown(script: string | ScriptObject): number { if (typeof script === 'string') return 0; return script.cooldown ?? 0; } function getScriptDuration(script: string | ScriptObject): number | undefined { if (typeof script === 'string') return undefined; return script.duration; } function getScriptCrewBonus(script: string | ScriptObject): number | undefined { if (typeof script === 'string') return undefined; return script.bonusValues?.crewLevelIncrease; } function getScriptBonusValues(script: string | ScriptObject): Record<string, number> | undefined { if (typeof script === 'string') return undefined; if (!script.bonusValues) return undefined; const result: Record<string, number> = {}; for (const [key, value] of Object.entries(script.bonusValues)) { if (typeof value === 'number') { result[key] = value; } } return Object.keys(result).length > 0 ? result : undefined; } export async function loadEquipment(config: Config): Promise<void> { if (equipmentCache) return; const path = join(config.paths.common, 'optional_devices.xml'); const data = await readXML<OptionalDevicesXML>(path); equipmentCache = []; for (const [key, entry] of Object.entries(data.root)) { if (key === 'nextAvailableId' || typeof entry === 'number') continue; const nameKey = entry.userString.startsWith('#artefacts:') ? entry.userString : entry.userString.replace('#', ''); const descKey = entry.description.startsWith('#artefacts:') ? entry.description : entry.description.replace('#', ''); equipmentCache.push({ id: entry.id, name: getString(nameKey), description: getString(descKey), effects: entry.display_params, }); } } async function loadConsumableFile(path: string): Promise<ConsumableEntry[]> { const data = await readXML<ConsumablesXML>(path); return Object.entries(data.root) .filter(([key, entry]) => key !== 'nextAvailableId' && typeof entry === 'object' && entry.id) .map(([, entry]) => entry as ConsumableEntry); } export async function loadConsumables(config: Config): Promise<void> { if (consumablesCache) return; const consumablesPath = join(config.paths.common, 'consumables'); const listPath = join(consumablesPath, 'list.xml'); const listContent = await readDVPLString(listPath); const fileMatches = listContent.matchAll(/<items path="(.+)\.xml"\/>/g); const entries: ConsumableEntry[] = []; for (const match of fileMatches) { const fileName = match[1]; if (!fileName || fileName === 'prototypes') continue; const filePath = join(consumablesPath, `${fileName}.xml`); const fileEntries = await loadConsumableFile(filePath); entries.push(...fileEntries); } consumablesCache = entries.map(entry => { const nameKey = entry.userString.startsWith('#artefacts:') ? entry.userString : entry.userString.replace('#', ''); const descKey = entry.description.startsWith('#artefacts:') ? entry.description : entry.description.replace('#', ''); const effects = entry.display_params ?? getScriptBonusValues(entry.script); return { id: entry.id, name: getString(nameKey), description: getString(descKey), cooldown: getScriptCooldown(entry.script), duration: getScriptDuration(entry.script), effects, }; }); } async function loadProvisionFile(path: string): Promise<ProvisionEntry[]> { const data = await readXML<ProvisionsXML>(path); return Object.entries(data.root) .filter(([key, entry]) => key !== 'nextAvailableId' && typeof entry === 'object' && entry.id) .map(([, entry]) => entry as ProvisionEntry); } export async function loadProvisions(config: Config): Promise<void> { if (provisionsCache) return; const provisionsPath = join(config.paths.common, 'provisions'); const listPath = join(provisionsPath, 'list.xml'); const listContent = await readDVPLString(listPath); const fileMatches = listContent.matchAll(/<items path="(.+)\.xml"\/>/g); const entries: ProvisionEntry[] = []; for (const match of fileMatches) { const fileName = match[1]; if (!fileName || fileName === 'prototypes') continue; const filePath = join(provisionsPath, `${fileName}.xml`); const fileEntries = await loadProvisionFile(filePath); entries.push(...fileEntries); } provisionsCache = entries.map(entry => { const nameKey = entry.userString.startsWith('#artefacts:') ? entry.userString : entry.userString.replace('#', ''); const descKey = entry.description.startsWith('#artefacts:') ? entry.description : entry.description.replace('#', ''); const effects = entry.display_params ?? getScriptBonusValues(entry.script); return { id: entry.id, name: getString(nameKey), description: getString(descKey), crewBonus: getScriptCrewBonus(entry.script), effects, }; }); } export function getEquipment(): Equipment[] { return equipmentCache ?? []; } export function getConsumables(): Consumable[] { return consumablesCache ?? []; } export function getProvisions(): Provision[] { return provisionsCache ?? []; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Revenant30102000/wotblitz-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server