mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 15:04:52 +09:00
Merge pull request #573 from CCpersonguy/feature/instance-version-2
Display Instance's Factorio version in the web UI
This commit is contained in:
11 files changed
+51
-11
No files matched your search
@@ -45,18 +45,22 @@ Many thanks to the following for contributing to this release:
|
||||
- Fixed spaces passed in arguments to the installer causing it to break [#620](https://github.com/clusterio/clusterio/issues/620)
|
||||
- Fixed numeric admin name breaking login [#536](https://github.com/clusterio/clusterio/issues/536)
|
||||
- Added factorio.executable_path option which allows overriding the default path to the Factorio executable run.
|
||||
- Added instance version display [#573](https://github.com/clusterio/clusterio/pull/573)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- Previously silent errors for controller.sendEvent now throw exceptions [#625](https://github.com/clusterio/clusterio/pull/625).
|
||||
- @clusterio/controller export InstanceInfo has added factorioVersion parameter.
|
||||
|
||||
Many thanks to the following for contributing to this release:
|
||||
[@CCpersonguy](https://github.com/CCpersonguy)
|
||||
[@Cooldude2606](https://github.com/Cooldude2606)
|
||||
[@Danielv123](https://github.com/Danielv123)
|
||||
[@Hornwitser](https://github.com/Hornwitser)
|
||||
[@Laar](https://github.com/Laar)
|
||||
[@psihius](https://github.com/psihius)
|
||||
|
||||
|
||||
## Version 2.0.0-alpha.18
|
||||
|
||||
### Features
|
||||
|
||||
@@ -896,7 +896,7 @@ export default class Controller {
|
||||
};
|
||||
instanceConfig.set("factorio.settings", settings);
|
||||
|
||||
let instance = new InstanceInfo(instanceConfig, "unassigned", undefined, Date.now());
|
||||
let instance = new InstanceInfo(instanceConfig, "unassigned", undefined, undefined, Date.now());
|
||||
this.instances.set(instanceId, instance);
|
||||
this.instancesDirty = true;
|
||||
await lib.invokeHook(this.plugins, "onInstanceStatusChanged", instance);
|
||||
|
||||
@@ -188,6 +188,7 @@ export default class HostConnection extends BaseConnection {
|
||||
let prev = instance.status;
|
||||
instance.status = request.status;
|
||||
instance.gamePort = request.gamePort;
|
||||
instance.factorioVersion = request.factorioVersion;
|
||||
instance.updatedAtMs = Date.now();
|
||||
logger.verbose(`Instance ${instance.config.get("instance.name")} State: ${instance.status}`);
|
||||
this._controller.instanceDetailsUpdated([instance]);
|
||||
@@ -225,6 +226,7 @@ export default class HostConnection extends BaseConnection {
|
||||
let prev = controllerInstance.status;
|
||||
controllerInstance.status = instanceData.status;
|
||||
controllerInstance.gamePort = instanceData.gamePort;
|
||||
controllerInstance.factorioVersion = instanceData.factorioVersion;
|
||||
controllerInstance.updatedAtMs = Date.now();
|
||||
logger.verbose(`Instance ${instanceConfig.get("instance.name")} State: ${instanceData.status}`);
|
||||
instanceUpdates.push(controllerInstance);
|
||||
@@ -240,6 +242,7 @@ export default class HostConnection extends BaseConnection {
|
||||
instanceConfig,
|
||||
instanceData.status,
|
||||
instanceData.gamePort,
|
||||
instanceData.factorioVersion,
|
||||
Date.now(),
|
||||
);
|
||||
this._controller.instances.set(instanceConfig.get("instance.id"), newInstance);
|
||||
|
||||
@@ -11,6 +11,7 @@ export default class InstanceInfo {
|
||||
public config: lib.InstanceConfig,
|
||||
public status: lib.InstanceStatus,
|
||||
public gamePort?: number,
|
||||
public factorioVersion?: string,
|
||||
public updatedAtMs = 0,
|
||||
) {
|
||||
this.config = config;
|
||||
@@ -22,6 +23,7 @@ export default class InstanceInfo {
|
||||
"status": lib.InstanceStatus,
|
||||
"gamePort": Type.Optional(Type.Number()),
|
||||
"updatedAtMs": Type.Optional(Type.Number()),
|
||||
"factorioVersion": Type.Optional(Type.String()),
|
||||
});
|
||||
|
||||
static fromJSON(json: Static<typeof this.jsonSchema>, location: lib.ConfigLocation) {
|
||||
@@ -29,6 +31,7 @@ export default class InstanceInfo {
|
||||
lib.InstanceConfig.fromJSON(json.config, location),
|
||||
json.status,
|
||||
json.gamePort,
|
||||
json.factorioVersion,
|
||||
json.updatedAtMs,
|
||||
);
|
||||
}
|
||||
@@ -40,6 +43,7 @@ export default class InstanceInfo {
|
||||
this.config.get("instance.assigned_host") ?? undefined,
|
||||
this.gamePort,
|
||||
this.status,
|
||||
this.factorioVersion,
|
||||
this.updatedAtMs,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -667,6 +667,9 @@ export default class Host extends lib.Link {
|
||||
instanceId,
|
||||
instanceConnection ? instanceConnection.instance.status : "stopped",
|
||||
instanceConnection ? instanceConnection.instance.server.gamePort : this.gamePort(instanceId),
|
||||
instanceConnection
|
||||
? instanceConnection.instance.server.version
|
||||
: instanceInfo.config.get("factorio.version"),
|
||||
)
|
||||
);
|
||||
|
||||
@@ -736,7 +739,7 @@ export default class Host extends lib.Link {
|
||||
}
|
||||
|
||||
assignGamePort(instanceId: number) {
|
||||
const availablePorts = lib.parseRanges(this.config.get("host.factorio_port_range"), 1, 2**16 - 1);
|
||||
const availablePorts = lib.parseRanges(this.config.get("host.factorio_port_range"), 1, 2 ** 16 - 1);
|
||||
for (const [id, instance] of this.instanceInfos) {
|
||||
if (id === instanceId) {
|
||||
continue;
|
||||
@@ -1060,6 +1063,7 @@ export default class Host extends lib.Link {
|
||||
instanceInfo.config.toRemote("controller"),
|
||||
instanceConnection ? instanceConnection.instance.status : "stopped",
|
||||
instanceConnection ? instanceConnection.instance.server.gamePort : this.gamePort(instanceId),
|
||||
instanceConnection ? instanceConnection.instance.server.version : undefined,
|
||||
));
|
||||
}
|
||||
await this.send(new lib.InstancesUpdateRequest(list));
|
||||
|
||||
@@ -454,6 +454,7 @@ rcon.print(game.table_to_json(players))`.replace(/\r?\n/g, " ");
|
||||
this.id,
|
||||
status,
|
||||
this.server.gamePort,
|
||||
status === "running"? this.server.version : this.config.get("factorio.version"),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ async function generateExportMod(server: FactorioServer) {
|
||||
sourceDir: path.join(__dirname, "..", "..", "..", "lua", "export"),
|
||||
outputDir: server.writePath("mods"),
|
||||
bumpPatch: false,
|
||||
factorioVersion: server.version.replace(/\.\d+$/, ""),
|
||||
factorioVersion: server.version?.replace(/\.\d+$/, ""),
|
||||
dependencies,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -730,12 +730,12 @@ export class FactorioServer extends events.EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of Factorio in use. This will be the actual version if
|
||||
* "latest" (the default) was specified as `factorioVersion` to the
|
||||
* constructor.
|
||||
* The version of Factorio in use. This will be the actual version if
|
||||
* "latest" (the default) was specified as `factorioVersion` to the constructor.
|
||||
* This will be undefined before the server is initialized, or if init failed.
|
||||
*/
|
||||
get version() {
|
||||
return this._version!;
|
||||
get version(): string | undefined {
|
||||
return this._version ?? undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,6 +42,7 @@ export class InstanceDetails {
|
||||
public assignedHost: number | undefined,
|
||||
public gamePort: number | undefined,
|
||||
public status: InstanceStatus,
|
||||
public factorioVersion: string | undefined,
|
||||
/** Millisecond Unix timestamp this entry was last updated at */
|
||||
public updatedAtMs = 0,
|
||||
) { }
|
||||
@@ -55,6 +56,7 @@ export class InstanceDetails {
|
||||
"unknown", "unassigned", "stopped", "starting", "running", "stopping",
|
||||
"creating_save", "exporting_data", "deleted",
|
||||
]),
|
||||
"factorioVersion": Type.Optional(Type.String()),
|
||||
"updatedAtMs": Type.Optional(Type.Number()),
|
||||
});
|
||||
|
||||
@@ -65,6 +67,7 @@ export class InstanceDetails {
|
||||
json.assignedHost,
|
||||
json.gamePort,
|
||||
json.status,
|
||||
json.factorioVersion,
|
||||
json.updatedAtMs,
|
||||
);
|
||||
}
|
||||
@@ -717,6 +720,7 @@ export class HostInstanceUpdate {
|
||||
public config: Static<typeof InstanceConfig.jsonSchema>,
|
||||
public status: InstanceStatus,
|
||||
public gamePort: undefined | number,
|
||||
public factorioVersion: undefined | string,
|
||||
) { }
|
||||
|
||||
static jsonSchema = Type.Object({
|
||||
@@ -725,10 +729,11 @@ export class HostInstanceUpdate {
|
||||
"stopped", "starting", "running", "stopping", "creating_save", "exporting_data",
|
||||
]),
|
||||
"gamePort": Type.Optional(Type.Number()),
|
||||
"factorioVersion": Type.Optional(Type.String()),
|
||||
});
|
||||
|
||||
static fromJSON(json: Static<typeof this.jsonSchema>) {
|
||||
return new this(json.config, json.status, json.gamePort);
|
||||
return new this(json.config, json.status, json.gamePort, json.factorioVersion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -822,6 +827,7 @@ export class InstanceStatusChangedEvent {
|
||||
public instanceId: number,
|
||||
public status: InstanceStatus,
|
||||
public gamePort?: number,
|
||||
public factorioVersion?: string,
|
||||
) { }
|
||||
|
||||
static jsonSchema = Type.Object({
|
||||
@@ -830,10 +836,11 @@ export class InstanceStatusChangedEvent {
|
||||
"stopped", "starting", "running", "stopping", "creating_save", "exporting_data",
|
||||
]),
|
||||
"gamePort": Type.Optional(Type.Integer()),
|
||||
"factorioVersion": Type.Optional(Type.String()),
|
||||
});
|
||||
|
||||
static fromJSON(json: Static<typeof this.jsonSchema>) {
|
||||
return new this(json.instanceId, json.status, json.gamePort);
|
||||
return new this(json.instanceId, json.status, json.gamePort, json.factorioVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useAccount } from "../model/account";
|
||||
import { useHosts } from "../model/host";
|
||||
import InstanceStatusTag from "./InstanceStatusTag";
|
||||
import StartStopInstanceButton from "./StartStopInstanceButton";
|
||||
import { InstanceDetails } from "@clusterio/lib";
|
||||
import { InstanceDetails, integerFactorioVersion } from "@clusterio/lib";
|
||||
import Link from "./Link";
|
||||
|
||||
const strcmp = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" }).compare;
|
||||
@@ -46,6 +46,13 @@ export default function InstanceList(props: InstanceListProps) {
|
||||
return `${host.publicAddress}:${instance.gamePort}`;
|
||||
}
|
||||
|
||||
function integerFactorioVersionOrDefault(instance: InstanceDetails) {
|
||||
if (instance.factorioVersion === undefined) {
|
||||
return -1;
|
||||
}
|
||||
return integerFactorioVersion(instance.factorioVersion);
|
||||
}
|
||||
|
||||
let columns: ColumnsType<InstanceDetails> = [
|
||||
{
|
||||
title: "Name",
|
||||
@@ -86,6 +93,13 @@ export default function InstanceList(props: InstanceListProps) {
|
||||
sorter: (a, b) => strcmp(instancePublicAddress(a), instancePublicAddress(b)),
|
||||
responsive: ["lg"],
|
||||
},
|
||||
{
|
||||
title: "Factorio Version",
|
||||
key: "version",
|
||||
render: (_, instance) => instance.factorioVersion ?? "unknown",
|
||||
sorter: (a, b) => integerFactorioVersionOrDefault(a) - integerFactorioVersionOrDefault(b),
|
||||
responsive: ["xl"],
|
||||
},
|
||||
{
|
||||
title: "Status",
|
||||
key: "status",
|
||||
|
||||
@@ -59,6 +59,9 @@ function InstanceDescription(props: InstanceDescriptionProps) {
|
||||
buttonContent={assigned ? "Reassign" : "Assign"}
|
||||
/>}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Version">
|
||||
{instance.factorioVersion ?? "unknown"}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Status"><InstanceStatusTag status={instance.status!} /></Descriptions.Item>
|
||||
</Descriptions>;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user