mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2026-11-13 16:14:52 +09:00
The instance plugins of exp_groups, exp_reports, exp_roles, exp_scenario and exp_server_ups, and the controller plugins of exp_reports and exp_scenario, were classes only to hold their handlers. They are now init functions with closures, like clusterio's own plugins. The exp_roles and exp_groups controller plugins stay classes because exp_scenario reaches their datastores through get(controller). AutoRestart stays a class because its tests step check() with a fake clock. Tests spy on handle() and the hooks to call the handlers. The reports webhook tests stub fetch instead of replacing postWebhook, and the feature reconcile test writes the stored records to disk before start. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
2.2 KiB
TypeScript
67 lines
2.2 KiB
TypeScript
import type { InstancePluginContext } from "@clusterio/host";
|
|
import * as lib from "@clusterio/lib";
|
|
import * as messages from "./messages.js";
|
|
import { features, FeatureValue } from "./features.js";
|
|
|
|
/** Sends feature config to the lua side, see module/features.lua. */
|
|
export default async function (context: InstancePluginContext) {
|
|
const { instance, plugin } = context;
|
|
/** Rcon is up and the lua side can take updates */
|
|
let started = false;
|
|
|
|
/** Subscribe, then send every feature */
|
|
async function syncFeatures() {
|
|
await instance.sendTo("controller", new lib.SubscriptionRequest(
|
|
`exp_scenario:${messages.FeatureUpdatedEvent.name}`, "subscribe", Date.now(),
|
|
));
|
|
const records = await instance.sendTo("controller", new messages.FeatureListRequest());
|
|
await luaSendFeatures(records);
|
|
}
|
|
|
|
/** Every value of each feature is sent, so the lua side sets them all */
|
|
async function luaSendFeatures(records: messages.FeatureRecord[]) {
|
|
if (!records.length) {
|
|
return;
|
|
}
|
|
|
|
const updates = records.map(record => {
|
|
const values: Record<string, FeatureValue> = { enabled: record.enabled };
|
|
for (const field of features.find(feature => feature.name === record.id)?.fields ?? []) {
|
|
values[field.name] = field.name in record.values ? record.values[field.name] : field.default;
|
|
}
|
|
return { name: record.id, values };
|
|
});
|
|
const json = JSON.stringify(updates);
|
|
// Pick a long bracket the json does not contain
|
|
let level = "=";
|
|
while (json.includes(`]${level}]`)) {
|
|
level += "=";
|
|
}
|
|
await instance.sendRcon(
|
|
`/sc exp_scenario.features.receive_update(helpers.json_to_table[${level}[${json}]${level}])`, true,
|
|
);
|
|
}
|
|
|
|
instance.handle(messages.FeatureUpdatedEvent, async event => {
|
|
if (started) {
|
|
await luaSendFeatures(event.updates.filter(feature => !feature.isDeleted));
|
|
}
|
|
});
|
|
|
|
instance.hooks.start.attach(plugin.name, async () => {
|
|
started = true;
|
|
await syncFeatures();
|
|
});
|
|
|
|
instance.hooks.exit.attach(plugin.name, async () => {
|
|
started = false;
|
|
});
|
|
|
|
// A new session means the controller restarted and forgot the subscription
|
|
instance.hooks.controllerConnectionEvent.attach(plugin.name, async event => {
|
|
if (event === "connect" && started) {
|
|
await syncFeatures();
|
|
}
|
|
});
|
|
}
|