mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2026-11-12 07:54:52 +09:00
Each plugin class now has a private constructor and a static async fromContext(context) that loads its datastores, constructs the instance and attaches its handlers and hooks. This replaces the public constructor followed by init(), and AutoRestart's start(). Datastores are loaded before construction and passed to the constructor, so the definite assignment assertions on them are gone. Tests build the plugins through fromContext and pass a wrapped logger in the context instead of overwriting plugin.logger before init(). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
2.7 KiB
TypeScript
92 lines
2.7 KiB
TypeScript
import * as lib from "@clusterio/lib";
|
|
import type { Instance, InstancePluginContext } from "@clusterio/host";
|
|
|
|
export class InstancePlugin {
|
|
private updateInterval?: ReturnType<typeof setInterval>;
|
|
private gameTimes: number[] = [];
|
|
|
|
private constructor(
|
|
public instance: Instance,
|
|
public logger: lib.Logger,
|
|
public name: string,
|
|
) {}
|
|
|
|
static async fromContext(context: InstancePluginContext) {
|
|
const instance = context.instance;
|
|
const plugin = new InstancePlugin(instance, context.logger, context.plugin.name);
|
|
|
|
const hooks = instance.hooks;
|
|
hooks.start.attach(plugin.name, plugin.onStart.bind(plugin));
|
|
hooks.exit.attach(plugin.name, plugin.onExit.bind(plugin));
|
|
hooks.instanceConfigFieldChanged.attach(plugin.name, plugin.onInstanceConfigFieldChanged.bind(plugin));
|
|
hooks.playerEvent.attach(plugin.name, plugin.onPlayerEvent.bind(plugin));
|
|
return plugin;
|
|
}
|
|
|
|
async onStart() {
|
|
if (!this.instance.config.get("factorio.settings")["auto_pause"]) {
|
|
this.setInterval();
|
|
}
|
|
}
|
|
|
|
onExit() {
|
|
this.clearInterval();
|
|
}
|
|
|
|
async onInstanceConfigFieldChanged(field: string, curr: unknown): Promise<void> {
|
|
if (field === "exp_server_ups.update_interval") {
|
|
this.clearInterval();
|
|
this.setInterval();
|
|
} else if (field === "exp_server_ups.average_interval") {
|
|
this.gameTimes.splice(curr as number);
|
|
}
|
|
}
|
|
|
|
async onPlayerEvent(event: lib.PlayerEvent): Promise<void> {
|
|
if (event.type === "join") {
|
|
this.setInterval();
|
|
} else if (event.type === "leave" && this.instance.playersOnline.size == 0 && this.instance.config.get("factorio.settings")["auto_pause"]) {
|
|
this.clearInterval();
|
|
}
|
|
}
|
|
|
|
setInterval() {
|
|
if (!this.updateInterval) {
|
|
this.updateInterval = setInterval(this.updateUps.bind(this), this.instance.config.get("exp_server_ups.update_interval"));
|
|
}
|
|
}
|
|
|
|
clearInterval() {
|
|
if (this.updateInterval) {
|
|
clearInterval(this.updateInterval);
|
|
this.updateInterval = undefined;
|
|
}
|
|
}
|
|
|
|
async updateUps() {
|
|
let ups = 0;
|
|
const collected = this.gameTimes.length - 1;
|
|
if (collected > 0) {
|
|
const minTick = this.gameTimes[0];
|
|
const maxTick = this.gameTimes[collected];
|
|
const interval = this.instance.config.get("exp_server_ups.update_interval") / 1000;
|
|
ups = (maxTick - minTick) / (collected * interval);
|
|
}
|
|
|
|
try {
|
|
const newGameTime = await this.instance.sendRcon(`/_rcon return exp_server_ups.refresh(${ups})`, false, this.name);
|
|
this.gameTimes.push(Number(newGameTime));
|
|
} catch (error: any) {
|
|
this.logger.error(`Failed to receive new game time: ${error}`);
|
|
}
|
|
|
|
if (collected > this.instance.config.get("exp_server_ups.average_interval")) {
|
|
this.gameTimes.shift();
|
|
}
|
|
}
|
|
}
|
|
|
|
export default async function (context: InstancePluginContext) {
|
|
await InstancePlugin.fromContext(context);
|
|
}
|