import { safeTags } from "./encoding";
declare global {
interface Window {
setServ: (ID: number) => void;
}
}
interface AOServer {
name: string;
description: string;
ip: string;
players: number;
online: string;
port?: number;
ws_port?: number;
wss_port?: number;
assets?: string;
}
const clientVersion = process.env.npm_package_version;
// const MASTERSERVER_IP = 'master.aceattorneyonline.com:27014';
const serverlist_domain = "servers.aceattorneyonline.com";
const protocol = window.location.protocol;
const serverlist_cache_key = "masterlist";
const servers: AOServer[] = [];
servers[-2] = {
name: "Singleplayer",
description: "Build cases, try out new things",
ip: "127.0.0.1",
players: 0,
online: "Singleplayer",
port: 50001,
} as AOServer;
servers[-1] = {
name: "Localhost",
description: "This is your computer on port 50001",
ip: "127.0.0.1",
players: 0,
online: "Localhost",
port: 50001,
} as AOServer;
function main() {
getServerlist().then((serverlist) => {
processServerlist(serverlist);
});
processClientVersion(clientVersion);
getMasterVersion().then((masterVersion) => {
processMasterVersion(masterVersion);
});
}
main();
export function setServ(ID: number) {
const server = servers[ID];
const onlineStr = server.online;
const serverDesc = safeTags(server.description);
document.getElementById("serverdescription_content").innerHTML =
`${onlineStr} ${serverDesc}`;
}
window.setServ = setServ;
// Fetches the serverlist from the masterserver
// Returns a properly typed list of servers
async function getServerlist(): Promise {
const url = `${protocol}//${serverlist_domain}/servers`;
const response = await fetch(url);
if (!response.ok) {
console.error(
`Bad status code from masterserver. status: ${response.status}, body: ${response.body}`,
);
document.getElementById("ms_error").style.display = "block";
// If we get a bad status code, try to use the cached serverlist
return getCachedServerlist();
}
const data = await response.json();
const serverlist: AOServer[] = [];
for (const item of data) {
if (!item.name) {
console.warn(`Server ${item} has no name, skipping`);
continue;
}
if (!item.ip) {
console.warn(`Server ${item.name} has no ip, skipping`);
continue;
}
if (!item.description) {
console.warn(`Server ${item.name} has no description, skipping`);
continue;
}
const newServer: AOServer = {
name: item.name,
description: item.description,
ip: item.ip,
players: item.players || 0,
online: `Players: ${item.players}`,
};
if (item.ws_port) {
newServer.ws_port = item.ws_port;
}
if (item.wss_port) {
newServer.wss_port = item.wss_port;
}
// if none of ws_port or wss_port are defined, skip
// Note that this is not an error condition, as many servers only has port (TCP) enabled
// Which means they don't support webAO
if (!newServer.ws_port && !newServer.wss_port) {
continue;
}
serverlist.push(newServer);
}
// Always cache the result when we get it
localStorage.setItem(serverlist_cache_key, JSON.stringify(serverlist));
return serverlist;
}
function getCachedServerlist(): AOServer[] {
// If it's not in the cache, return an empty list
const cached = localStorage.getItem(serverlist_cache_key) || "[]";
return JSON.parse(cached) as AOServer[];
}
// Constructs the client URL robustly, independent of domain and path
function constructClientURL(protocol: string): string {
const clientURL = new URL(window.location.href);
// Use the given protocol
clientURL.protocol = protocol;
// Remove the last part of the pathname (e.g., "index.html")
const pathname = clientURL.pathname;
const parts = pathname.split("/");
parts.pop();
// Reconstruct the pathname
clientURL.pathname = parts.join("/");
// If clientURL.pathname does not end with a slash, add one
if (clientURL.pathname[clientURL.pathname.length - 1] !== "/") {
clientURL.pathname += "/";
}
clientURL.pathname += "client.html";
return clientURL.href;
}
function processServerlist(serverlist: AOServer[]) {
for (let i = 0; i < serverlist.length; i++) {
const server = serverlist[i];
let ws_port = 0;
let ws_protocol = "";
let http_protocol = "";
if (server.ws_port) {
ws_port = server.ws_port;
ws_protocol = "ws";
http_protocol = "http";
}
if (server.wss_port && !window.navigator.userAgent.includes("Nintendo")) {
ws_port = server.wss_port;
ws_protocol = "wss";
http_protocol = "https";
}
if (ws_port === 0 || ws_protocol === "" || http_protocol === "") {
console.warn(`Server ${server.name} has no websocket port, skipping`);
continue;
}
const clientURL = constructClientURL(http_protocol);
const connect = `${ws_protocol}://${server.ip}:${ws_port}`;
const serverName = server.name;
const fullClientWatchURL = `${clientURL}?mode=watch&connect=${connect}&serverName=${serverName}`;
const fullClientJoinURL = `${clientURL}?mode=join&connect=${connect}&serverName=${serverName}`;
servers.push(server);
document.getElementById("masterlist").innerHTML +=
`