Files
factorio-expcluster/exp_server_list/instance.ts
T
bbassieandClaude Opus 5.5 c0289ed8a7 Address review on exp_server_list
The controller and instance plugins are init functions with closures.
The controller batches refreshes with setMany and deleteMany, and the
instance gates updates on its status instead of a started flag.

short_name is now display_name. New always_on_top field sorts servers
first in get_servers. The record carries has_password from the game
password in factorio.settings, never the password itself, and the
description falls back to the one in factorio.settings. A controller
welcome is used when the instance has none, and the readme falls back
to a default welcome from the locale.

Lua gets is_synced for connect.lua. The readme passes an empty detail
instead of nil to the join tooltip so the player count stays in __2__,
restores the Password status, shows the welcome title as a centered
label and shortens long descriptions with the full text as a tooltip.

The Lua tests assert the lookups they index, which fixes the lint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 21:35:33 +00:00

54 lines
1.8 KiB
TypeScript

import type { InstancePluginContext } from "@clusterio/host";
import * as lib from "@clusterio/lib";
import * as messages from "./messages.js";
/**
* Sends the server list to the lua side, see module/control.lua.
*
* The subscription is made by the start hook once rcon is up, so updates
* only arrive while the game can take them.
*/
export default async function (context: InstancePluginContext) {
const { instance, plugin } = context;
async function luaSendServers(servers: messages.ServerRecord[], replace: boolean) {
const json = JSON.stringify({
current_id: instance.id,
replace,
servers: servers.map(server => server.toJSON()),
});
// Pick a long bracket the json does not contain
let level = "=";
while (json.includes(`]${level}]`)) {
level += "=";
}
await instance.sendRcon(
`/sc exp_server_list.receive_update(helpers.json_to_table[${level}[${json}]${level}])`, true,
);
}
/** Subscribe, then replace the whole list */
async function syncServers() {
await instance.sendTo("controller", new lib.SubscriptionRequest(
`exp_server_list:${messages.ServerUpdatesEvent.name}`, "subscribe", Date.now(),
));
const servers = await instance.sendTo("controller", new messages.ServerListRequest());
await luaSendServers(servers, true);
}
instance.handle(messages.ServerUpdatesEvent, async event => {
if (instance.status === "starting" || instance.status === "running") {
await luaSendServers(event.updates, false);
}
});
instance.hooks.start.attach(plugin.name, syncServers);
// A new session means the controller restarted and forgot the subscription
instance.hooks.controllerConnectionEvent.attach(plugin.name, async event => {
if (event === "connect" && instance.status === "running") {
await syncServers();
}
});
}