diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index a770f02..d21f292 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -8,13 +8,13 @@
// Use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon.
"args": { "VARIANT": "ubuntu-22.04" }
},
- "workspaceMount": "source=${localWorkspaceFolder},target=/factorioClusterio/external_plugins/gridworld,type=bind",
- "workspaceFolder": "/factorioClusterio",
+ "workspaceMount": "source=${localWorkspaceFolder},target=/clusterio/external_plugins/gridworld,type=bind",
+ "workspaceFolder": "/clusterio",
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [8080],
- // sudo mv /workspaces/gridworld /factorioClusterio/external_plugins/
+ // sudo mv /workspaces/gridworld /clusterio/external_plugins/
// Use 'postCreateCommand' to run commands after the container is created. wget -O factorio.tar.xz https://www.factorio.com/get-download/latest/headless/linux64 && tar -xf factorio.tar.xz && rm factorio.tar.xz
- "postCreateCommand": "mv /workspaces/gridworld/ /workspaces/gridworld2 && cp -r /factorioClusterio/ /workspaces/gridworld && sudo rm -rf /factorioClusterio && mv /workspaces/gridworld2/ /workspaces/gridworld/external_plugins/gridworld && cd /workspaces/gridworld && git pull && pnpm install && wget -O factorio.tar.xz https://www.factorio.com/get-download/latest/headless/linux64 && tar -xf factorio.tar.xz && rm factorio.tar.xz",
+ "postCreateCommand": "mv /workspaces/gridworld/ /workspaces/gridworld2 && cp -r /clusterio/ /workspaces/gridworld && sudo rm -rf /clusterio && mv /workspaces/gridworld2/ /workspaces/gridworld/external_plugins/gridworld && cd /workspaces/gridworld && git pull && pnpm install && wget -O factorio.tar.xz https://www.factorio.com/get-download/latest/headless/linux64 && tar -xf factorio.tar.xz && rm factorio.tar.xz",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode",
@@ -28,7 +28,8 @@
"vscode": {
"extensions": [
"yzhang.markdown-all-in-one",
- "yinfei.luahelper"
+ "yinfei.luahelper",
+ "dbaeumer.vscode-eslint"
]
}
}
diff --git a/.eslintrc.js b/.eslintrc.js
index 2422663..4af543e 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -139,7 +139,7 @@ module.exports = {
"linebreak-style": ["error", "unix"],
"lines-around-comment": "off",
"lines-around-directive": "off",
- "lines-between-class-members": ["error", "always"],
+ "lines-between-class-members": "off",
"max-classes-per-file": "off",
"max-depth": "error",
"max-len": ["error", {
diff --git a/.github/workflows/diagram.yml b/.github/workflows/diagram.yml
index f0a767e..80015a7 100644
--- a/.github/workflows/diagram.yml
+++ b/.github/workflows/diagram.yml
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@master
+ uses: actions/checkout@controller
- name: Update diagram
uses: githubocto/repo-visualizer@main
with:
diff --git a/README.md b/README.md
index 17f66b4..fba2754 100644
--- a/README.md
+++ b/README.md
@@ -14,9 +14,9 @@ Dependencies:
Run the following commands in the folder Clusterio is installed to:
npm install @danielv123/gridworld
- npx clusteriomaster plugin add @danielv123/gridworld
+ npx clusteriocontroller plugin add @danielv123/gridworld
-Substitute clusteriomaster with clusterioslave or clusterioctl if this a dedicated slave or ctl installation respectively.
+Substitute clusteriocontroller with clusteriohost or clusterioctl if this a dedicated host or ctl installation respectively.

@@ -26,29 +26,33 @@ Clone the repository in clusterio/external_plugins/
cd clusterio
pnpm install
+ node packages/create --dev # Interactive
node packages/ctl plugin add ./external_plugins/gridworld
pnpm install @clusterio/plugin-edge_transports -w
pnpm install @hornwitser/server_select -w
- node packages/master/ bootstrap create-admin Danielv123
- node packages/master plugin add @clusterio/plugin-edge_transports
- node packages/master plugin add @hornwitser/server_select
- node packages/master plugin add ./plugins/global_chat
- node packages/master plugin add ./plugins/inventory_sync
- node packages/master plugin add ./plugins/player_auth
- node packages/master plugin add ./plugins/research_sync
- node packages/master plugin add ./plugins/statistics_exporter
- node packages/master/ bootstrap generate-user-token Danielv123 > token.txt
- node packages/master run --dev --dev-plugin gridworld
-
-Log into the webui with the token in token.txt and create a new slave token with id `1` then run the following in terminal to setup the slave:
+ node packages/controller bootstrap create-ctl-config Danielv123
+ node packages/controller bootstrap create-admin Danielv123
+ node packages/controller plugin add @clusterio/plugin-edge_transports
+ node packages/controller plugin add @hornwitser/server_select
+ node packages/controller plugin add ./plugins/global_chat
+ node packages/controller plugin add ./plugins/inventory_sync
+ node packages/controller plugin add ./plugins/player_auth
+ node packages/controller plugin add ./plugins/research_sync
+ node packages/controller plugin add ./plugins/statistics_exporter
+ node packages/controller bootstrap generate-user-token Danielv123 > token.txt
+ node packages/controller run --dev --dev-plugin gridworld
+
+Log into the webui with the token in token.txt and create a new host token with id `1` then run the following in terminal to setup the host:
wget -O factorio.tar.gz https://www.factorio.com/get-download/latest/headless/linux64
tar -xf factorio.tar.gz
- node packages/slave config set slave.id 1
- node packages/slave config set slave.master_token xxxxxxxxxxxxxxxxxxxxx
- node packages/slave config set slave.name "Slave 1"
- node packages/slave config set slave.public_address "localhost"
+ node packages/host config set host.id 1
+ node packages/host config set host.controller_token xxxxxxxxxxxxxxxxxxxxx
+ node packages/host config set host.name "Host 1"
+ node packages/host config set host.public_address "localhost"
Luacheck can be downloaded from https://github.com/mpeterv/luacheck/releases/download/0.23.0/luacheck.exe or `sudo apt install lua-check`
Put it in your `%path%` and run `luacheck ./module`
+
+eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ1c2VyIiwidXNlciI6IkRhbmllbHYxMjMiLCJpYXQiOjE3MDcwNjYwNDR9.g9iiIDvhX8GrEWGQQYig_smOdf212dmst6HKg9LKU3g
\ No newline at end of file
diff --git a/master.js b/controller.js
similarity index 52%
rename from master.js
rename to controller.js
index e71532c..facc2e6 100644
--- a/master.js
+++ b/controller.js
@@ -2,13 +2,19 @@
const fs = require("fs-extra");
const path = require("path");
-const { libLink, libPlugin, libErrors } = require("@clusterio/lib");
+const lib = require("@clusterio/lib");
+// eslint-disable-next-line node/no-extraneous-require
+const { BaseControllerPlugin } = require("@clusterio/controller");
const registerTileServer = require("./src/routes/tileserver");
+// Messages
+const messages = require("./messages");
+const MigrateInstanceRequest = require("./src/instance_migration/info/MigrateInstanceRequest");
+
+// Message handlers
const getMapDataRequestHandler = require("./src/request_handlers/getMapDataRequestHandler");
const refreshTileDataRequestHandler = require("./src/request_handlers/refreshTileDataRequestHandler");
const setWebSubscriptionRequestHandler = require("./src/request_handlers/setWebSubscriptionRequestHandler");
-const startInstanceRequestHandler = require("./src/request_handlers/startInstanceRequestHandler");
const createFactionRequestHandler = require("./src/request_handlers/createFactionRequestHandler");
const updateFactionRequestHandler = require("./src/request_handlers/updateFactionRequestHandler");
const migrateInstanceRequestHandler = require("./src/instance_migration/migrateInstanceRequestHandler");
@@ -27,7 +33,7 @@ const unclaimServerRequestHandler = require("./src/request_handlers/unclaimServe
const setLoadFactorEventHandler = require("./src/event_handlers/setLoadFactorEventHandler");
async function loadDatabase(config, filename, logger) {
- let itemsPath = path.resolve(config.get("master.database_directory"), filename);
+ let itemsPath = path.resolve(config.get("controller.database_directory"), filename);
logger.verbose(`Loading ${itemsPath}`);
try {
let content = await fs.readFile(itemsPath);
@@ -42,89 +48,70 @@ async function loadDatabase(config, filename, logger) {
}
}
-async function saveDatabase(masterConfig, datastore, filename, logger) {
+async function saveDatabase(controllerConfig, datastore, filename, logger) {
if (datastore) {
- let file = path.resolve(masterConfig.get("master.database_directory"), filename);
+ let file = path.resolve(controllerConfig.get("controller.database_directory"), filename);
logger.verbose(`writing ${file}`);
let content = JSON.stringify(Array.from(datastore));
await fs.outputFile(file, content);
}
}
-class MasterPlugin extends libPlugin.BaseMasterPlugin {
+class ControllerPlugin extends BaseControllerPlugin {
async init() {
- this.gridworldDatastore = await loadDatabase(this.master.config, "gridworld.json", this.logger);
- this.factionsDatastore = await loadDatabase(this.master.config, "factions.json", this.logger);
+ this.gridworldDatastore = await loadDatabase(this.controller.config, "gridworld.json", this.logger);
+ this.factionsDatastore = await loadDatabase(this.controller.config, "factions.json", this.logger);
this.autosaveId = setInterval(() => {
- saveDatabase(this.master.config, this.gridworldDatastore, "gridworld.json", this.logger).catch(err => {
+ saveDatabase(this.controller.config, this.gridworldDatastore, "gridworld.json", this.logger).catch(err => {
this.logger.error(`Unexpected error autosaving gridworld data:\n${err.stack}`);
});
- saveDatabase(this.master.config, this.factionsDatastore, "factions.json", this.logger).catch(err => {
+ saveDatabase(this.controller.config, this.factionsDatastore, "factions.json", this.logger).catch(err => {
this.logger.error(`Unexpected error autosaving factions data:\n${err.stack}`);
});
- }, this.master.config.get("gridworld.autosave_interval") * 1000);
+ }, this.controller.config.get("gridworld.autosave_interval") * 1000);
// Prepare tiles folder
this._tilesPath = path.resolve(
- this.master.config.get("master.database_directory"),
- this.master.config.get("gridworld.tiles_directory")
+ this.controller.config.get("controller.database_directory"),
+ this.controller.config.get("gridworld.tiles_directory")
);
await fs.ensureDir(this._tilesPath);
- registerTileServer(this.master.app, this._tilesPath);
+ registerTileServer(this.controller.app, this._tilesPath);
this.subscribedControlLinks = [];
- }
-
- playerPositionEventHandler = playerPositionEventHandler;
-
- getMapDataRequestHandler = getMapDataRequestHandler;
-
- updateEdgeTransportEdgesRequestHandler = updateEdgeTransportEdgesRequestHandler;
-
- createFactionGridRequestHandler = createFactionGridRequestHandler;
-
- refreshTileDataRequestHandler = refreshTileDataRequestHandler;
-
- setWebSubscriptionRequestHandler = setWebSubscriptionRequestHandler;
-
- startInstanceRequestHandler = startInstanceRequestHandler;
-
- createFactionRequestHandler = createFactionRequestHandler;
-
- updateFactionRequestHandler = updateFactionRequestHandler;
-
- migrateInstanceRequestHandler = migrateInstanceRequestHandler;
- joinGridworldRequestHandler = joinGridworldRequestHandler;
-
- performEdgeTeleportRequestHandler = performEdgeTeleportRequestHandler;
-
- refreshFactionDataRequestHandler = refreshFactionDataRequestHandler;
-
- factionInvitePlayerRequestHandler = factionInvitePlayerRequestHandler;
-
- joinFactionRequestHandler = joinFactionRequestHandler;
-
- factionChangeMemberRoleRequestHandler = factionChangeMemberRoleRequestHandler;
-
- leaveFactionRequestHandler = leaveFactionRequestHandler;
-
- claimServerRequestHandler = claimServerRequestHandler;
-
- unclaimServerRequestHandler = unclaimServerRequestHandler;
-
- setLoadFactorEventHandler = setLoadFactorEventHandler;
+ // Register event handlers to messages
+ this.controller.handle(messages.PlayerPosition, playerPositionEventHandler.bind(this));
+ this.controller.handle(messages.GetMapData, getMapDataRequestHandler.bind(this));
+ this.controller.handle(messages.UpdateEdgeTransportEdges, updateEdgeTransportEdgesRequestHandler.bind(this));
+ this.controller.handle(messages.CreateFactionGrid, createFactionGridRequestHandler.bind(this));
+ this.controller.handle(messages.RefreshTileData, refreshTileDataRequestHandler.bind(this));
+ this.controller.handle(messages.SetWebSubscription, setWebSubscriptionRequestHandler.bind(this));
+ this.controller.handle(messages.CreateFaction, createFactionRequestHandler.bind(this));
+ this.controller.handle(messages.UpdateFaction, updateFactionRequestHandler.bind(this));
+ this.controller.handle(MigrateInstanceRequest, migrateInstanceRequestHandler.bind(this));
+ this.controller.handle(messages.JoinGridworld, joinGridworldRequestHandler.bind(this));
+ this.controller.handle(messages.PerformEdgeTeleport, performEdgeTeleportRequestHandler.bind(this));
+ this.controller.handle(messages.RefreshFactionData, refreshFactionDataRequestHandler.bind(this));
+ this.controller.handle(messages.FactionInvitePlayer, factionInvitePlayerRequestHandler.bind(this));
+ this.controller.handle(messages.JoinFaction, joinFactionRequestHandler.bind(this));
+ this.controller.handle(messages.FactionChangeMemberRole, factionChangeMemberRoleRequestHandler.bind(this));
+ this.controller.handle(messages.LeaveFaction, leaveFactionRequestHandler.bind(this));
+ this.controller.handle(messages.ClaimServer, claimServerRequestHandler.bind(this));
+ this.controller.handle(messages.UnclaimServer, unclaimServerRequestHandler.bind(this));
+ this.controller.handle(messages.SetLoadFactor, setLoadFactorEventHandler.bind(this));
+ }
async onInstanceStatusChanged(instance) {
if (instance.status === "running") {
let instanceId = instance.config.get("instance.id");
- let slaveId = instance.config.get("instance.assigned_slave");
+ let hostId = instance.config.get("instance.assigned_host");
let x = instance.config.get("gridworld.grid_x_position");
let y = instance.config.get("gridworld.grid_y_position");
- let slaveConnection = this.master.wsServer.slaveConnections.get(slaveId);
- let instances = [...this.master.instances];
- await this.info.messages.populateNeighborData.send(slaveConnection, {
+ let hostConnection = this.controller.wsServer.hostConnections.get(hostId);
+ let instances = [...this.controller.instances];
+ await this.controller.sendTo({ instanceId }, new messages.PopulateNeighborData({
instance_id: instanceId,
north: instances.find(z => z[1].config.get("gridworld.grid_x_position") === x
&& z[1].config.get("gridworld.grid_y_position") === y - 1)?.[0] || null,
@@ -134,24 +121,24 @@ class MasterPlugin extends libPlugin.BaseMasterPlugin {
&& z[1].config.get("gridworld.grid_y_position") === y)?.[0] || null,
west: instances.find(z => z[1].config.get("gridworld.grid_x_position") === x - 1
&& z[1].config.get("gridworld.grid_y_position") === y)?.[0] || null,
- });
+ }));
}
}
async setInstanceConfigField(instanceId, field, value) {
// Code lifted from ControlConnection.js setInstanceConfigFieldRequestHandler(message)
- let instance = this.master.instances.get(instanceId);
+ let instance = this.controller.instances.get(instanceId);
if (!instance) {
- throw new libErrors.RequestError(`Instance with ID ${instanceId} does not exist`);
+ throw new lib.RequestError(`Instance with ID ${instanceId} does not exist`);
}
- if (field === "instance.assigned_slave") {
- throw new libErrors.RequestError("instance.assigned_slave must be set through the assign-slave interface");
+ if (field === "instance.assigned_host") {
+ throw new lib.RequestError("instance.assigned_host must be set through the assign-host interface");
}
if (field === "instance.id") {
// XXX is this worth implementing? It's race condition galore.
- throw new libErrors.RequestError("Setting instance.id is not supported");
+ throw new lib.RequestError("Setting instance.id is not supported");
}
instance.config.set(field, value, "control");
@@ -159,14 +146,14 @@ class MasterPlugin extends libPlugin.BaseMasterPlugin {
}
async updateInstanceConfig(instance) {
- let slaveId = instance.config.get("instance.assigned_slave");
- if (slaveId) {
- let connection = this.master.wsServer.slaveConnections.get(slaveId);
+ let hostId = instance.config.get("instance.assigned_host");
+ if (hostId) {
+ let connection = this.controller.wsServer.hostConnections.get(hostId);
if (connection) {
- await libLink.messages.assignInstance.send(connection, {
- instance_id: instance.config.get("instance.id"),
- serialized_config: instance.config.serialize("slave"),
- });
+ await connection.send(new lib.InstanceAssignInternalRequest({
+ instanceId: instance_id,
+ config: instance.config.toRemote("host"),
+ }));
}
}
}
@@ -180,11 +167,11 @@ class MasterPlugin extends libPlugin.BaseMasterPlugin {
async onShutdown() {
clearInterval(this.autosaveId);
- await saveDatabase(this.master.config, this.gridworldDatastore, "gridworld.json", this.logger);
- await saveDatabase(this.master.config, this.factionsDatastore, "factions.json", this.logger);
+ await saveDatabase(this.controller.config, this.gridworldDatastore, "gridworld.json", this.logger);
+ await saveDatabase(this.controller.config, this.factionsDatastore, "factions.json", this.logger);
}
}
module.exports = {
- MasterPlugin,
+ ControllerPlugin,
};
diff --git a/docs/docs.md b/docs/docs.md
index 6f70783..cffd9b4 100644
--- a/docs/docs.md
+++ b/docs/docs.md
@@ -22,7 +22,7 @@ Far fetched goals:
The current version of the plugin has the following flow:
1. Installation
-1. User clicks "create new gridworld" and enters their preferred grid cell size and the slave used to host the lobby server
+1. User clicks "create new gridworld" and enters their preferred grid cell size and the host used to host the lobby server
1. User clicks "create gridworld"
1. The plugin creates a lobby server with a new grid_id
the web map
@@ -45,16 +45,16 @@ Clone the repository in clusterio/external_plugins/ and run the following:
node packages/ctl plugin add ./external_plugins/gridworld
pnpm install @clusterio/plugin-edge_transports -w
pnpm install @hornwitser/server_select -w
- node packages/master/ bootstrap create-admin Danielv123
- node packages/master plugin add @clusterio/plugin-edge_transports
- node packages/master plugin add @hornwitser/server_select
- node packages/master plugin add ./plugins/global_chat
- node packages/master plugin add ./plugins/inventory_sync
- node packages/master plugin add ./plugins/player_auth
- node packages/master plugin add ./plugins/research_sync
- node packages/master plugin add ./plugins/statistics_exporter
- node packages/master/ bootstrap generate-user-token Danielv123 > token.txt
- node packages/master run --dev --dev-plugin gridworld
+ node packages/controller/ bootstrap create-admin Danielv123
+ node packages/controller plugin add @clusterio/plugin-edge_transports
+ node packages/controller plugin add @hornwitser/server_select
+ node packages/controller plugin add ./plugins/global_chat
+ node packages/controller plugin add ./plugins/inventory_sync
+ node packages/controller plugin add ./plugins/player_auth
+ node packages/controller plugin add ./plugins/research_sync
+ node packages/controller plugin add ./plugins/statistics_exporter
+ node packages/controller/ bootstrap generate-user-token Danielv123 > token.txt
+ node packages/controller run --dev --dev-plugin gridworld
Luacheck can be downloaded from https://github.com/mpeterv/luacheck/releases/download/0.23.0/luacheck.exe
diff --git a/docs/load balancing/load balancing.md b/docs/load balancing/load balancing.md
index 3bd8ab8..138eb4f 100644
--- a/docs/load balancing/load balancing.md
+++ b/docs/load balancing/load balancing.md
@@ -10,7 +10,7 @@ Servers claimed by a faction stays online for 48 hours after the last player fro
## Load balancing active instances
-While gridworld spreads newly created instances across available nodes, that is not enough to ensure even load. As servers are started and stopping by the algorithm and people build factories on some instances but not others, the load will become uneven. To solve this problem gridworld has a load balancing algorithm that determines instances in need of migration. Once the imbalance reaches a certain threshold servers with no players online will be migrated to a new slave.
+While gridworld spreads newly created instances across available nodes, that is not enough to ensure even load. As servers are started and stopping by the algorithm and people build factories on some instances but not others, the load will become uneven. To solve this problem gridworld has a load balancing algorithm that determines instances in need of migration. Once the imbalance reaches a certain threshold servers with no players online will be migrated to a new host.
## Algorithm
diff --git a/docs/worldgen/factionGrid/generate server.md b/docs/worldgen/factionGrid/generate server.md
index 63c3cb4..e8a50da 100644
--- a/docs/worldgen/factionGrid/generate server.md
+++ b/docs/worldgen/factionGrid/generate server.md
@@ -1,11 +1,11 @@
# Generate server
-The server generation is a multi-step process executed by the master. It is expected to run frequently while players are using the cluster so reliability and speed is important.
+The server generation is a multi-step process executed by the controller. It is expected to run frequently while players are using the cluster so reliability and speed is important.
The server generation function takes care of the following:
1. Create a new instance
-2. Assign to a slave with free capacity
+2. Assign to a host with free capacity
3. Create a new save
4. Apply gridworld configuration options
5. Apply edge transports configuration
diff --git a/docs/worldgen/server creation and linking.md b/docs/worldgen/server creation and linking.md
index 6737fbc..be7d8e9 100644
--- a/docs/worldgen/server creation and linking.md
+++ b/docs/worldgen/server creation and linking.md
@@ -7,16 +7,16 @@ This page describes the internal workings of the server creation and linking sys
| Message | Link | Description |
| :-----------------------------------: | :-------------: | :------------------------------------------------------------------------------------------------------------- |
| `ipc-gridworld:join_gridworld` | module-instance | Join gridworld in last location |
-| `gridworld:join_gridworld` | instance-master | Forward message to master to determine join location, respond with connection details after server is prepared |
-| `gridworld:sync_faction_data` | master-instance | Forward message to instance to sync faction data |
-| `gridworld:sync_player_data_for_join` | master-instance | Sync player data to the instance and open the server for a specific player connecting |
+| `gridworld:join_gridworld` | instance-controller | Forward message to controller to determine join location, respond with connection details after server is prepared |
+| `gridworld:sync_faction_data` | controller-instance | Forward message to instance to sync faction data |
+| `gridworld:sync_player_data_for_join` | controller-instance | Sync player data to the instance and open the server for a specific player connecting |
| `/sc gridworld.join_server` | instance-module | Prompt for server connection |
### Instance join_gridworld IPC handler
-Forward request to master using gridworld:join_gridworld message. Once we get the connection details in the response from the master we use `/sc gridworld.join_server()` to prompt the user to connect to the prepared server.
+Forward request to controller using gridworld:join_gridworld message. Once we get the connection details in the response from the controller we use `/sc gridworld.join_server()` to prompt the user to connect to the prepared server.
-### Master join_gridworld request handler
+### Controller join_gridworld request handler
Get current player location in gridworld by looking up the player profile. If the player does not have a disconnect location, use the default spawn point for the faction.
diff --git a/docs/worldgen/worldgen overview.md b/docs/worldgen/worldgen overview.md
index a0cb96f..04c3950 100644
--- a/docs/worldgen/worldgen overview.md
+++ b/docs/worldgen/worldgen overview.md
@@ -5,7 +5,7 @@ When creating a new gridworld, only a lobby server is generated. The game worlds
## Event flow (user perspective)
An user joins the gridworld lobby and creates a new faction, then joins the game.
-Pressing the join game button sends a message to the master. It tries to determine the spawn point for the user.
+Pressing the join game button sends a message to the controller. It tries to determine the spawn point for the user.
1. If the user has spawned in before it will use the last known spawn point.
1. If the user hasn't spawned in before it will use the default spawn point of the faction.
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..1710c98
--- /dev/null
+++ b/index.js
@@ -0,0 +1,149 @@
+"use strict";
+const lib = require("@clusterio/lib");
+
+const MigrateInstanceRequest = require("./src/instance_migration/info/MigrateInstanceRequest");
+const messages = require("./messages");
+
+const pluginName = "gridworld";
+
+// Define migrate instance permission
+require("./src/instance_migration/info/migrateInstancePermission");
+
+lib.definePermission({
+ name: "gridworld.overview.view",
+ title: "View gridworld overview",
+ description: "View gridworld overview",
+ grantByDefault: true,
+});
+lib.definePermission({
+ name: "gridworld.create",
+ title: "Create gridworld",
+ description: "Create gridworld",
+ grantByDefault: true,
+});
+lib.definePermission({
+ name: "gridworld.map.refresh",
+ title: "Refresh map tiles",
+ description:
+ "Load tile data from factorio and recreate images for web interface map",
+ grantByDefault: true,
+});
+lib.definePermission({
+ name: "gridworld.map.create_by_exploration",
+ title: "Create servers by exploration",
+ description:
+ "Allow for new instances to be created by exploration through edge_teleports",
+ grantByDefault: true,
+});
+lib.definePermission({
+ name: "gridworld.map.start_by_exploration",
+ title: "Start servers by exploration",
+ description:
+ "Allow for existing instances to be started by exploration through edge_teleports",
+ grantByDefault: true,
+});
+lib.definePermission({
+ name: "gridworld.faction.delete",
+ title: "Delete faction",
+ description: "Delete *any* faction",
+ grantByDefault: false,
+});
+
+module.exports = {
+ plugin: {
+ name: pluginName,
+ title: "Gridworld",
+ description: "Generates a gridworld cluster layout",
+
+ instanceEntrypoint: "instance",
+ instanceConfigFields: {
+ "gridworld.grid_x_position": {
+ type: "number",
+ title: "Server position on X axis",
+ description: "Server position index along the X axis in the gridworld",
+ initial_value: 1000,
+ },
+ "gridworld.grid_y_position": {
+ type: "number",
+ title: "Server position on Y axis",
+ description: "Server position index along the Y axis in the gridworld",
+ initial_value: 1000,
+ },
+ "gridworld.grid_x_size": {
+ type: "number",
+ title: "Server size on X axis",
+ description: "Server size along the X axis",
+ initial_value: 512,
+ },
+ "gridworld.grid_y_size": {
+ type: "number",
+ title: "Server size on Y axis",
+ description: "Server size along the Y axis",
+ initial_value: 512,
+ },
+ "gridworld.is_lobby_server": {
+ type: "boolean",
+ title: "Server is a lobby server",
+ description: "Make this instance act as a lobby server for a gridworld",
+ initial_value: false,
+ },
+ "gridworld.grid_id": {
+ type: "number",
+ title: "Grid ID",
+ description:
+ "Grid identifier - used to run multiple gridworlds on the same cluster",
+ initial_value: 0,
+ },
+ "gridworld.claimed_by_faction": {
+ type: "string",
+ title: "Claimed by faction",
+ description: "Faction that has claimed this server",
+ initial_value: "",
+ },
+ },
+
+ controllerEntrypoint: "controller",
+ controllerConfigFields: {
+ "gridworld.autosave_interval": {
+ type: "number",
+ title: "Autosave Interval",
+ description: "Interval the gridworld data is autosaved at in seconds.",
+ initial_value: 600, // 10 minutes
+ },
+ "gridworld.gridworld_seed": {
+ type: "number",
+ title: "Gridworld seed",
+ description: "Seed for servers created using gridworld generator",
+ initial_value: 999,
+ },
+ "gridworld.gridworld_map_exchange_string": {
+ type: "string",
+ title: "Gridworld map exchange string",
+ description:
+ "Map exchange string for servers created using gridworld generator",
+ initial_value:
+ // eslint-disable-next-line max-len
+ ">>>eNpjZGBk0GIAgwZ7EOZgSc5PzIHwDjiAMFdyfkFBapFuflEqsjBnclFpSqpufiaq4tS81NxK3aTEYqhiiMkcmUX5eegmsBaX5OehipQUpaYWw5wCwtylRYl5maW5EL0H7OGqGb+qrnZoaJFjAOH/9QwK//+DMJD1AGgjCDMwNoBVMwLFYIA1OSczLY2BQcERiJ1A0owMjNUi69wfVk0BMsFAzwHK+AAVOZAEE/GEMfwccEqpwBgmSOYYg8FnJAbE0hKQ/RBVHA4IBkSyBSTJyNj7duuC78cu2DH+Wfnxkm9Sgj2joavIuw9G6+yAkuwgfzLBiVkzQWAnzCsMMDMf2EOlbtoznj0DAm/sGVlBOkRAhIMFkDjgzczAKMAHZC3oARIKMgwwp9nBjBFxYEwDg28wnzyGMS7bo/sDGBA2IMPlQMQJEAG2EO4yRgjTod+B0UEeJiuJUALUb8SA7IYUhA9Pwqw9jGQ/mkMwIwLZH2giKg5YooELZGEKnHjBDHcNMDwvsMN4DvMdGJlBDJCqL0AxCA8kAzMKQgs4gIObmQEBPtgzuMX47gAAJhSjWw==<<<",
+ },
+ "gridworld.tiles_directory": {
+ type: "string",
+ title: "Tiles directory",
+ description: "Folder to store map tiles relative to database",
+ initial_value: "tiles",
+ },
+ },
+
+ webEntrypoint: "./web",
+ routes: [
+ "/gridworld",
+ "/gridworld/create",
+ "/gridworld/factions",
+ "/gridworld/factions/:factionId/view",
+ ],
+
+ messages: [
+ MigrateInstanceRequest,
+ ...Object.keys(messages).map(key => messages[key]),
+ ],
+ },
+};
diff --git a/info.js b/info.js
deleted file mode 100644
index 1d3c8aa..0000000
--- a/info.js
+++ /dev/null
@@ -1,499 +0,0 @@
-"use strict";
-const { libConfig, libLink, libUsers } = require("@clusterio/lib");
-
-const factionProperties = require("./src/factions/faction_message_properties");
-const migrateInstanceCommandRequest = require("./src/instance_migration/info/migrateInstanceCommandRequest");
-
-// Define migrate instance permission
-require("./src/instance_migration/info/migrateInstancePermission");
-
-class MasterConfigGroup extends libConfig.PluginConfigGroup { }
-MasterConfigGroup.defaultAccess = ["master", "slave", "control"];
-MasterConfigGroup.groupName = "gridworld";
-MasterConfigGroup.define({
- name: "autosave_interval",
- title: "Autosave Interval",
- description: "Interval the gridworld data is autosaved at in seconds.",
- type: "number",
- initial_value: 600, // 10 minutes
-});
-MasterConfigGroup.define({
- name: "gridworld_seed",
- title: "Gridworld seed",
- description: "Seed for servers created using gridworld generator",
- type: "number",
- initial_value: 999,
-});
-MasterConfigGroup.define({
- name: "gridworld_map_exchange_string",
- title: "Gridworld map exchange string",
- description: "Map exchange string for servers created using gridworld generator",
- type: "string",
- // eslint-disable-next-line max-len
- initial_value: ">>>eNpjZGBk0GIAgwZ7EOZgSc5PzIHwDjiAMFdyfkFBapFuflEqsjBnclFpSqpufiaq4tS81NxK3aTEYqhiiMkcmUX5eegmsBaX5OehipQUpaYWw5wCwtylRYl5maW5EL0H7OGqGb+qrnZoaJFjAOH/9QwK//+DMJD1AGgjCDMwNoBVMwLFYIA1OSczLY2BQcERiJ1A0owMjNUi69wfVk0BMsFAzwHK+AAVOZAEE/GEMfwccEqpwBgmSOYYg8FnJAbE0hKQ/RBVHA4IBkSyBSTJyNj7duuC78cu2DH+Wfnxkm9Sgj2joavIuw9G6+yAkuwgfzLBiVkzQWAnzCsMMDMf2EOlbtoznj0DAm/sGVlBOkRAhIMFkDjgzczAKMAHZC3oARIKMgwwp9nBjBFxYEwDg28wnzyGMS7bo/sDGBA2IMPlQMQJEAG2EO4yRgjTod+B0UEeJiuJUALUb8SA7IYUhA9Pwqw9jGQ/mkMwIwLZH2giKg5YooELZGEKnHjBDHcNMDwvsMN4DvMdGJlBDJCqL0AxCA8kAzMKQgs4gIObmQEBPtgzuMX47gAAJhSjWw==<<<",
-});
-MasterConfigGroup.define({
- name: "tiles_directory",
- title: "Tiles directory",
- description: "Folder to store map tiles relative to database",
- type: "string",
- initial_value: "tiles",
-});
-MasterConfigGroup.finalize();
-
-class InstanceConfigGroup extends libConfig.PluginConfigGroup { }
-InstanceConfigGroup.defaultAccess = ["master", "slave", "control"];
-InstanceConfigGroup.groupName = "gridworld";
-InstanceConfigGroup.define({
- name: "grid_x_position",
- title: "Server position on X axis",
- description: "Server position index along the X axis in the gridworld",
- type: "number",
- initial_value: 1000,
-});
-InstanceConfigGroup.define({
- name: "grid_y_position",
- title: "Server position on Y axis",
- description: "Server position index along the Y axis in the gridworld",
- type: "number",
- initial_value: 1000,
-});
-InstanceConfigGroup.define({
- name: "grid_x_size",
- title: "Server size on X axis",
- description: "Server size along the X axis",
- type: "number",
- initial_value: 512,
-});
-InstanceConfigGroup.define({
- name: "grid_y_size",
- title: "Server size on Y axis",
- description: "Server size along the Y axis",
- type: "number",
- initial_value: 512,
-});
-InstanceConfigGroup.define({
- name: "is_lobby_server",
- title: "Server is a lobby server",
- description: "Make this instance act as a lobby server for a gridworld",
- type: "boolean",
- initial_value: false,
-});
-InstanceConfigGroup.define({
- name: "grid_id",
- title: "Grid ID",
- description: "Grid identifier - used to run multiple gridworlds on the same cluster",
- type: "number",
- initial_value: 0,
-});
-InstanceConfigGroup.define({
- name: "claimed_by_faction",
- title: "Claimed by faction",
- description: "Faction that has claimed this server",
- type: "string",
- initial_value: "",
-});
-InstanceConfigGroup.finalize();
-
-libUsers.definePermission({
- name: "gridworld.overview.view",
- title: "View gridworld overview",
- description: "View gridworld overview",
- grantByDefault: true,
-});
-libUsers.definePermission({
- name: "gridworld.create",
- title: "Create gridworld",
- description: "Create gridworld",
- grantByDefault: true,
-});
-libUsers.definePermission({
- name: "gridworld.map.refresh",
- title: "Refresh map tiles",
- description: "Load tile data from factorio and recreate images for web interface map",
- grantByDefault: true,
-});
-libUsers.definePermission({
- name: "gridworld.map.create_by_exploration",
- title: "Create servers by exploration",
- description: "Allow for new instances to be created by exploration through edge_teleports",
- grantByDefault: true,
-});
-libUsers.definePermission({
- name: "gridworld.map.start_by_exploration",
- title: "Start servers by exploration",
- description: "Allow for existing instances to be started by exploration through edge_teleports",
- grantByDefault: true,
-});
-libUsers.definePermission({
- name: "gridworld.faction.delete",
- title: "Delete faction",
- description: "Delete *any* faction",
- grantByDefault: false,
-});
-
-module.exports = {
- name: "gridworld",
- title: "Gridworld",
- description: "Generates a gridworld cluster layout",
-
- instanceEntrypoint: "instance",
- InstanceConfigGroup,
-
- masterEntrypoint: "master",
- MasterConfigGroup,
-
- webEntrypoint: "./web",
- routes: [
- "/gridworld",
- "/gridworld/create",
- "/gridworld/factions",
- "/gridworld/factions/:factionId/view",
- ],
-
- messages: {
- migrateInstance: migrateInstanceCommandRequest,
- createFactionGrid: new libLink.Request({
- type: "gridworld:create",
- links: ["control-master"],
- permission: "gridworld.create",
- requestProperties: {
- name_prefix: { type: "string" },
- use_edge_transports: { type: "boolean" },
- x_size: { type: "integer" },
- y_size: { type: "integer" },
- slave: { type: "integer" }, // slaveID to use for instance creation
- },
- }),
- getMapData: new libLink.Request({
- type: "gridworld:get_map_data",
- links: ["control-master", "instance-slave", "slave-master"],
- permission: "gridworld.overview.view",
- forwardTo: "master",
- responseProperties: {
- map_data: {
- type: "array",
- items: {
- type: "object",
- additionalProperties: false,
- properties: {
- instance_id: { type: "integer" },
- center: { type: "array", items: { type: "number" } },
- bounds: {
- type: "array", items: {
- type: "array",
- items: { type: "number" },
- },
- },
- edges: {
- type: "array",
- items: {
- type: "object",
- properties: {
- id: { type: "integer" },
- origin: {
- type: "array",
- items: { type: "integer" },
- },
- surface: { type: "integer" },
- direction: { type: "integer" },
- length: { type: "integer" },
- target_instance: { type: "integer" },
- target_edge: { type: "integer" },
- },
- },
- },
- },
- },
- },
- },
- }),
- populateNeighborData: new libLink.Request({
- type: "gridworld:populate_neighbor_data",
- links: ["master-slave", "slave-instance"],
- forwardTo: "instance",
- requestProperties: {
- north: { type: ["integer", "null"] },
- south: { type: ["integer", "null"] },
- east: { type: ["integer", "null"] },
- west: { type: ["integer", "null"] },
- },
- }),
- updateEdgeTransportEdges: new libLink.Request({
- type: "gridworld:update_edge_transport_edges",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- requestProperties: {
- instance_id: { type: "integer" },
- },
- }),
- teleportPlayer: new libLink.Request({
- type: "gridworld:teleport_player",
- links: ["instance-slave", "slave-master", "master-slave", "slave-instance"],
- forwardTo: "instance",
- requestProperties: {
- player_name: { type: "string" },
- x: { type: "number" },
- y: { type: "number" },
- },
- }),
- playerPosition: new libLink.Event({
- type: "gridworld:player_position",
- links: ["instance-slave", "slave-master", "master-control"],
- forwardTo: "master",
- eventProperties: {
- player_name: { type: "string" },
- instance_id: { type: "integer" },
- x: { type: "number" },
- y: { type: "number" },
- },
- }),
- setWebSubscription: new libLink.Request({
- type: "gridworld:set_web_subscription",
- links: ["control-master"],
- permission: "gridworld.overview.view",
- requestProperties: {
- player_position: { type: "boolean" },
- faction_list: { type: "boolean" },
- },
- }),
- startInstance: new libLink.Request({
- type: "gridworld:start_instance",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- requestProperties: {
- instance_id: { type: "integer" },
- save: { type: ["string", "null"] },
- },
- }),
- createFaction: new libLink.Request({
- type: "gridworld:create_faction",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- requestProperties: factionProperties,
- responseProperties: {
- ok: { type: "boolean" },
- faction: {
- type: "object",
- properties: factionProperties,
- },
- },
- }),
- /**
- * Send updated faction data to master for propagation throughout the cluster
- * Used to edit factions
- */
- updateFaction: new libLink.Request({
- type: "gridworld:update_faction",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- requestProperties: {
- faction_id: { type: "string" },
- name: { type: "string" },
- open: { type: "boolean" },
- about: {
- type: "object",
- properties: {
- header: { type: "string" },
- description: { type: "string" },
- rules: { type: "string" },
- },
- },
- },
- responseRequired: ["ok", "message"],
- responseProperties: {
- ok: { type: "boolean" },
- message: { type: "string" },
- faction: {
- type: "object",
- properties: factionProperties,
- },
- },
- }),
- /**
- * Event notifying an instance of changes to a faction
- */
- factionUpdate: new libLink.Event({
- type: "gridworld:faction_update",
- links: ["master-slave", "slave-instance", "master-control"],
- broadcastTo: "instance",
- eventProperties: {
- faction: {
- type: "object",
- properties: factionProperties,
- },
- },
- }),
- /**
- * Get changed factions
- */
- refreshFactionData: new libLink.Request({
- type: "gridworld:refresh_faction_data",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- responseProperties: {
- ok: { type: "boolean" },
- message: { type: "string" },
- factions: {
- type: "array",
- items: {
- type: "object",
- properties: factionProperties,
- },
- },
- },
- }),
- factionInvitePlayer: new libLink.Request({
- type: "gridworld:faction_invite_player",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- requestProperties: {
- faction_id: { type: "string" },
- player_name: { type: "string" },
- role: { type: "string" },
- },
- responseProperties: {
- ok: { type: "boolean" },
- message: { type: "string" },
- },
- }),
- joinFaction: new libLink.Request({
- type: "gridworld:join_faction",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- requestProperties: {
- faction_id: { type: "string" },
- player_name: { type: "string" },
- },
- responseProperties: {
- ok: { type: "boolean" },
- message: { type: "string" },
- },
- }),
- leaveFaction: new libLink.Request({
- type: "gridworld:leave_faction",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- requestProperties: {
- faction_id: { type: "string" },
- player_name: { type: "string" },
- },
- responseProperties: {
- ok: { type: "boolean" },
- message: { type: "string" },
- },
- }),
- factionChangeMemberRole: new libLink.Request({
- type: "gridworld:faction_change_member_role",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- requestProperties: {
- faction_id: { type: "string" },
- player_name: { type: "string" },
- role: factionProperties.members.items.properties.role,
- },
- responseProperties: {
- ok: { type: "boolean" },
- message: { type: "string" },
- },
- }),
- claimServer: new libLink.Request({
- type: "gridworld:claim_server",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- requestProperties: {
- instance_id: { type: "integer" },
- player_name: { type: "string" },
- faction_id: { type: "string" },
- },
- responseProperties: {
- ok: { type: "boolean" },
- message: { type: "string" },
- },
- }),
- unclaimServer: new libLink.Request({
- type: "gridworld:unclaim_server",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- requestProperties: {
- instance_id: { type: "integer" },
- player_name: { type: "string" },
- },
- responseProperties: {
- ok: { type: "boolean" },
- message: { type: "string" },
- },
- }),
- joinGridworld: new libLink.Request({
- type: "gridworld:join_gridworld",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- requestProperties: {
- player_name: { type: "string" },
- grid_id: { type: "integer" },
- },
- responseRequired: ["ok", "message"],
- responseProperties: {
- ok: { type: "boolean" },
- message: { type: "string" },
- connection_address: { type: "string" },
- server_name: { type: "string" },
- server_description: { type: "string" },
- },
- }),
- performEdgeTeleport: new libLink.Request({
- type: "gridworld:perform_edge_teleport",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- requestProperties: {
- player_name: { type: "string" },
- player_x_position: { type: "number" },
- player_y_position: { type: "number" },
- grid_id: { type: "integer" },
- },
- responseRequired: ["ok", "message"],
- responseProperties: {
- ok: { type: "boolean" },
- message: { type: "string" },
- connection_address: { type: "string" },
- server_name: { type: "string" },
- server_description: { type: "string" },
- instance_id: { type: "integer" },
- },
- }),
- getTileData: new libLink.Request({
- type: "gridworld:get_tile_data",
- links: ["master-slave", "slave-instance"],
- forwardTo: "instance",
- requestProperties: {
- position_a: { type: "array", items: { type: "number" } },
- position_b: { type: "array", items: { type: "number" } },
- },
- responseProperties: {
- tile_data: {
- type: "array",
- items: {
- type: "string",
- },
- },
- },
- }),
- refreshTileData: new libLink.Request({
- type: "gridworld:refresh_tile_data",
- links: ["control-master"],
- permission: "gridworld.map.refresh",
- requestProperties: {
- instance_id: { type: "integer" },
- },
- }),
- setLoadFactor: new libLink.Event({
- type: "gridworld:set_load_factor",
- links: ["instance-slave", "slave-master"],
- forwardTo: "master",
- eventProperties: {
- instance_id: { type: "integer" },
- load_factor: { type: "number" },
- },
- }),
- },
-};
diff --git a/instance.js b/instance.js
index 0a4558a..bfb739c 100644
--- a/instance.js
+++ b/instance.js
@@ -2,13 +2,14 @@
* @module
*/
"use strict";
-const libPlugin = require("@clusterio/lib/plugin");
-const libLuaTools = require("@clusterio/lib/lua_tools");
-const { libLink } = require("@clusterio/lib");
+const lib = require("@clusterio/lib");
+// eslint-disable-next-line node/no-extraneous-require
+const { BaseInstancePlugin } = require("@clusterio/host");
const sleep = require("./src/util/sleep");
+const messages = require("./messages");
-class InstancePlugin extends libPlugin.BaseInstancePlugin {
+class InstancePlugin extends BaseInstancePlugin {
async init() {
this.pendingTasks = new Set();
this.disconnecting = false;
@@ -78,6 +79,12 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
`Error performing load balancing:\n${err.stack}`
));
});
+
+ // Register message handlers
+ this.instance.handle(messages.PopulateNeighborData, this.populateNeighborDataRequestHandler.bind(this));
+ this.instance.handle(messages.TeleportPlayer, this.teleportPlayerRequestHandler.bind(this));
+ this.instance.handle(messages.FactionUpdate, this.factionUpdateEventHandler.bind(this));
+ this.instance.handle(messages.GetTileData, this.getTileDataRequestHandler.bind(this));
}
async onStart() {
@@ -90,7 +97,7 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
if (this.instance.config.get("gridworld.is_lobby_server")) {
await this.sendRcon("/sc gridworld.register_lobby_server(true)");
// Get gridworld data
- const { map_data } = await this.info.messages.getMapData.send(this.instance);
+ const { map_data } = await this.instance.sendTo("controller", new messages.GetMapData());
await this.sendRcon(`/sc gridworld.register_map_data('${JSON.stringify(map_data)}')`);
} else {
await this.sendRcon("/sc global.disable_crashsite = true");
@@ -98,13 +105,13 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
await this.sendRcon(`/sc gridworld.create_spawn("${data.x_size}","${data.y_size}","${data.world_x}","${data.world_y}", false)`, true);
// Update neighboring nodes for edge_transports
await sleep(1000);
- await this.info.messages.updateEdgeTransportEdges.send(this.instance, {
+ await this.instance.sendTo("controller", new messages.UpdateEdgeTransportEdges({
instance_id: this.instance.id,
- });
+ }));
// Refresh faction data
- const response = await this.info.messages.refreshFactionData.send(this.instance);
+ const response = await this.instance.sendTo("controller", new messages.RefreshFactionData());
for (let faction of response.factions) {
- await this.runTask(this.sendRcon(`/sc gridworld.sync_faction("${faction.faction_id}",'${libLuaTools.escapeString(JSON.stringify(faction))}')`));
+ await this.runTask(this.sendRcon(`/sc gridworld.sync_faction("${faction.faction_id}",'${lib.escapeString(JSON.stringify(faction))}')`));
}
}
}
@@ -114,7 +121,7 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
await Promise.all(this.pendingTasks);
}
- onMasterConnectionEvent(event) {
+ onControllerConnectionEvent(event) {
if (event === "drop" || event === "close") {
this.sendRcon("/sc gridworld.populate_neighbor_data(nil, nil, nil, nil)").catch(
err => this.logger(`Error deactivating neighbors:\n${err.stack}`)
@@ -122,11 +129,11 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
}
}
- onPrepareMasterDisconnect() {
+ onPrepareControllerDisconnect() {
this.disconnecting = true;
}
- onMasterConnectionEvent(event) {
+ onControllerConnectionEvent(event) {
if (event === "connect") {
this.disconnecting = false;
}
@@ -149,12 +156,11 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
}
async teleportPlayer(data) {
- await this.info.messages.teleportPlayer.send(this.instance, {
- instance_id: data.instance_id,
+ await this.instance.sendTo({ instanceId: data.instance_id }, new messages.TeleportPlayer({
player_name: data.player_name,
x: data.x,
y: data.y,
- });
+ }));
}
async teleportPlayerRequestHandler(message) {
@@ -162,20 +168,20 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
return;
}
- await this.runTask(this.sendRcon(`/sc gridworld.receive_teleport_data("${libLuaTools.escapeString(JSON.stringify(message.data))}")`));
+ await this.runTask(this.sendRcon(`/sc gridworld.receive_teleport_data("${lib.escapeString(JSON.stringify(message.data))}")`));
}
async sendPlayerPosition(data) {
- await this.info.messages.playerPosition.send(this.instance, {
+ await this.instance.sendTo("controller", new messages.PlayerPosition({
player_name: data.player_name,
instance_id: data.instance_id,
x: data.x,
y: data.y,
- });
+ }));
}
async createFaction(data) {
- const status = await this.info.messages.createFaction.send(this.instance, {
+ const status = await this.instance.sendTo("controller", new messages.CreateFactionGrid({
faction_id: data.faction_id,
name: data.name,
open: data.open,
@@ -191,10 +197,10 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
description: `${data.name} was started by ${data.owner} on ${new Date().toISOString()}`,
rules: "The faction leader has not set any rules",
},
- });
+ }));
if (status.ok) {
// Sync faction with lobby world
- await this.sendRcon(`/sc gridworld.sync_faction("${data.faction_id}","${libLuaTools.escapeString(JSON.stringify(status.faction))}")`);
+ await this.sendRcon(`/sc gridworld.sync_faction("${data.faction_id}","${lib.escapeString(JSON.stringify(status.faction))}")`);
// Open faction admin screen for owner
await this.sendRcon(`/sc gridworld.open_faction_admin_screen("${data.owner}","${data.faction_id}")`);
}
@@ -204,13 +210,13 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
// Show received progress in game
await this.sendRcon(`/sc gridworld.show_progress("${data.player_name}", "Saving faction", "Propagating changes", 2, 3)`);
- // Update master server
- const status = await this.info.messages.updateFaction.send(this.instance, {
+ // Update controller server
+ const status = await this.instance.sendTo("controller", new messages.UpdateFaction({
faction_id: data.faction_id,
name: data.name,
open: data.open,
about: data.about,
- });
+ }));
// Show completed progress in game
await this.sendRcon(`/sc gridworld.show_progress("${data.player_name}", "Saving faction", "Finishing", 3, 3)`);
await new Promise(r => setTimeout(r, 500));
@@ -219,11 +225,11 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
}
async factionInvitePlayer(data) {
- let response = await this.info.messages.factionInvitePlayer.send(this.instance, {
+ let response = await this.instance.sendTo("controller", new messages.FactionInvitePlayer({
faction_id: data.faction_id,
player_name: data.player_name,
role: data.role,
- });
+ }));
if (response.ok) {
// Close invite player dialog
await this.sendRcon(`/sc game.get_player("${data.requesting_player}").gui.center.gridworld_invite_player_dialog.destroy()`);
@@ -234,10 +240,10 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
}
async joinFaction(data) {
- let response = await this.info.messages.joinFaction.send(this.instance, {
+ let response = await this.instance.sendTo("controller", new messages.JoinFaction({
faction_id: data.faction_id,
player_name: data.player_name,
- });
+ }));
if (response.ok) {
await this.sendRcon(`/sc game.get_player("${data.player_name}").print("${response.message}")`);
} else {
@@ -247,10 +253,10 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
}
async factionKickPlayer(data) {
- const response = await this.info.messages.leaveFaction.send(this.instance, {
+ const response = await this.instance.sendTo("controller", new messages.LeaveFaction({
faction_id: data.faction_id,
player_name: data.player_name,
- });
+ }));
if (!response.ok) {
// Show error message
await this.sendRcon(`/sc game.get_player("${data.requesting_player}").print("${response.message}")`);
@@ -258,11 +264,11 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
}
async factionChangeMemberRole(data) {
- const response = await this.info.messages.factionChangeMemberRole.send(this.instance, {
+ const response = await this.instance.sendTo("controller", new messages.FactionChangeMemberRole({
faction_id: data.faction_id,
player_name: data.player_name,
role: data.role,
- });
+ }));
if (!response.ok) {
// Show error message
await this.sendRcon(`/sc game.get_player("${data.requesting_player}").print("${response.message}")`);
@@ -272,12 +278,12 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
async claimServer(data) {
// Show received progress in game
await this.sendRcon(`/sc gridworld.show_progress("${data.player_name}", "Claiming server", "Propagating changes", 2, 3)`);
- // Update master
- const status = await this.info.messages.claimServer.send(this.instance, {
+ // Update controller
+ const status = await this.instance.sendTo("controller", new messages.ClaimServer({
instance_id: this.instance.config.get("instance.id"),
player_name: data.player_name,
faction_id: data.faction_id,
- });
+ }));
if (status.ok) {
await this.sendRcon(`/sc gridworld.show_progress("${data.player_name}", "Claiming server", "Finishing", 3, 3)`);
await this.sendRcon(`/sc gridworld.claim_server("${data.faction_id}")`);
@@ -293,11 +299,11 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
async unclaimServer(data) {
// Show received progress in game
await this.sendRcon(`/sc gridworld.show_progress("${data.player_name}", "Unclaiming server", "Propagating changes", 2, 3)`);
- // Update master
- const status = await this.info.messages.unclaimServer.send(this.instance, {
+ // Update controller
+ const status = await this.instance.sendTo("controller", new messages.UnclaimServer({
instance_id: this.instance.config.get("instance.id"),
player_name: data.player_name,
- });
+ }));
if (status.ok) {
await this.sendRcon(`/sc gridworld.show_progress("${data.player_name}", "Unclaiming server", "Finishing", 3, 3)`);
await this.sendRcon(`/sc gridworld.unclaim_server("${data.faction_id}")`);
@@ -313,7 +319,7 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
async factionUpdateEventHandler(message) {
if (this.instance.status === "running") {
// Update faction in game
- await this.runTask(this.sendRcon(`/sc gridworld.sync_faction("${message.data.faction.faction_id}",'${libLuaTools.escapeString(JSON.stringify(message.data.faction))}')`));
+ await this.runTask(this.sendRcon(`/sc gridworld.sync_faction("${message.data.faction.faction_id}",'${lib.escapeString(JSON.stringify(message.data.faction))}')`));
}
}
@@ -321,10 +327,10 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
// Show received progress in game
await this.sendRcon(`/sc gridworld.show_progress("${data.player_name}", "Finding server", "Loading world", 1, 3)`);
- let response = await this.info.messages.joinGridworld.send(this.instance, {
+ let response = await this.instance.sendTo("controller", new messages.JoinGridworld({
player_name: data.player_name,
grid_id: this.instance.config.get("gridworld.grid_id"),
- });
+ }));
// Show completed progress in game
await this.sendRcon(`/sc gridworld.show_progress("${data.player_name}", "Joining gridworld", "${response.message}", 3, 3)`);
@@ -344,12 +350,12 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
* @param {number} data.player_y_position - Y position of the player
*/
async performEdgeTeleport(data) {
- const response = await this.info.messages.performEdgeTeleport.send(this.instance, {
+ const response = await this.instance.sendTo("controller", new messages.PerformEdgeTeleport({
player_name: data.player_name,
player_x_position: data.player_x_position,
player_y_position: data.player_y_position,
grid_id: this.instance.config.get("gridworld.grid_id"),
- });
+ }));
if (response.ok) {
// Prepare server in case the player accepts the teleport
@@ -380,7 +386,7 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
switch (data.action) {
case "stop_server":
// console.log(this, this.instance.plugins, this.instance.server, this.instance.sendSaveListUpdate);
- await libPlugin.invokeHook(this.instance.plugins, "onStop");
+ await lib.invokeHook(this.instance.plugins, "onStop");
await this.instance.server.stop();
await this.instance.sendSaveListUpdate();
break;
@@ -388,16 +394,16 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
this.logger.error(`Unknown load balancing action: ${data.action}`);
break;
}
- // Send load_factor to master
- await this.info.messages.setLoadFactor.send(this.instance, {
+ // Send load_factor to controller
+ await this.instance.sendTo("controller", new messages.SetLoadFactor({
instance_id: this.instance.config.get("instance.id"),
load_factor: data.load_factor,
- });
+ }));
}
async getTileDataRequestHandler(message) {
if (this.instance.status !== "running") {
- throw new libErrors.RequestError(`Instance with ID ${message.data.instance_id} is not running ${this.instance.status}`);
+ throw new lib.RequestError(`Instance with ID ${message.data.instance_id} is not running ${this.instance.status}`);
}
let { position_a, position_b } = message.data;
let response = await this.sendRcon(`/sc gridworld.dump_mapview({${position_a}}, {${position_b}})`);
diff --git a/messages.js b/messages.js
new file mode 100644
index 0000000..a8213cc
--- /dev/null
+++ b/messages.js
@@ -0,0 +1,476 @@
+"use strict";
+const factionProperties = require("./src/factions/faction_message_properties");
+
+const pluginName = "gridworld";
+
+module.exports = {
+ CreateFactionGrid: class CreateFactionGrid {
+ static type = "request"; // request/event
+ static src = "control"; // string or array of strings
+ static dst = "controller";
+ static plugin = pluginName;
+ static permission = "gridworld.create";
+ constructor(data) {
+ this.data = data;
+ }
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ name_prefix: { type: "string" },
+ use_edge_transports: { type: "boolean" },
+ x_size: { type: "integer" },
+ y_size: { type: "integer" },
+ host: { type: "integer" }, // hostID to use for instance creation
+ },
+ };
+ },
+ GetMapData: class GetMapData {
+ static type = "request";
+ static src = "control";
+ static dst = "controller";
+ static plugin = pluginName;
+ static permission = "gridworld.overview.view";
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ properties: {
+ map_data: {
+ type: "array",
+ items: {
+ type: "object",
+ additionalProperties: false,
+ properties: {
+ instance_id: { type: "integer" },
+ center: { type: "array", items: { type: "number" } },
+ bounds: {
+ type: "array",
+ items: {
+ type: "array",
+ items: { type: "number" },
+ },
+ },
+ edges: {
+ type: "array",
+ items: {
+ type: "object",
+ properties: {
+ id: { type: "integer" },
+ origin: {
+ type: "array",
+ items: { type: "integer" },
+ },
+ surface: { type: "integer" },
+ direction: { type: "integer" },
+ length: { type: "integer" },
+ target_instance: { type: "integer" },
+ target_edge: { type: "integer" },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ fromJson(data) {
+ return data;
+ },
+ };
+ },
+ PopulateNeighborData: class PopulateNeighborData {
+ static type = "request";
+ static src = "controller";
+ static dst = "instance";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ north: { type: ["integer", "null"] },
+ south: { type: ["integer", "null"] },
+ east: { type: ["integer", "null"] },
+ west: { type: ["integer", "null"] },
+ },
+ };
+ },
+ UpdateEdgeTransportEdges: class UpdateEdgeTransportEdges {
+ static type = "request";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ instance_id: { type: "integer" },
+ },
+ };
+ },
+ TeleportPlayer: class TeleportPlayer {
+ static type = "request";
+ static src = "instance";
+ static dst = "instance"; // To broadcast, use .sendTo("allInstances", ...) otherwise use target instance ID
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ player_name: { type: "string" },
+ x: { type: "number" },
+ y: { type: "number" },
+ },
+ };
+ },
+ PlayerPosition: class PlayerPosition {
+ static type = "event";
+ static src = "instance";
+ static dst = ["controller", "control"];
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ player_name: { type: "string" },
+ instance_id: { type: "integer" },
+ x: { type: "number" },
+ y: { type: "number" },
+ },
+ };
+ },
+ SetWebSubscription: class SetWebSubscription {
+ static type = "request";
+ static src = "control";
+ static dst = "controller";
+ static plugin = pluginName;
+ static permission = "gridworld.overview.view";
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ player_position: { type: "boolean" },
+ faction_list: { type: "boolean" },
+ },
+ };
+ },
+ CreateFaction: class CreateFaction {
+ static type = "request";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: factionProperties,
+ };
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ properties: {
+ ok: { type: "boolean" },
+ faction: {
+ type: "object",
+ properties: factionProperties,
+ },
+ },
+ },
+ };
+ },
+ // Send updated faction data to controller for propagation. Used to edit factions
+ UpdateFaction: class UpdateFaction {
+ static type = "request";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ faction_id: { type: "string" },
+ name: { type: "string" },
+ open: { type: "boolean" },
+ about: {
+ type: "object",
+ properties: {
+ header: { type: "string" },
+ description: { type: "string" },
+ rules: { type: "string" },
+ },
+ },
+ },
+ };
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ required: ["ok", "message"],
+ properties: {
+ ok: { type: "boolean" },
+ message: { type: "string" },
+ faction: {
+ type: "object",
+ properties: factionProperties,
+ },
+ },
+ },
+ };
+ },
+ // Event notifying an instance of changes to a faction
+ FactionUpdate: class FactionUpdate {
+ static type = "event";
+ static src = "controller";
+ static dst = ["instance", "control"];
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ faction: {
+ type: "object",
+ properties: factionProperties,
+ },
+ },
+ };
+ },
+ // Get changed factions
+ RefreshFactionData: class RefreshFactionData {
+ static type = "request";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ properties: {
+ ok: { type: "boolean" },
+ message: { type: "string" },
+ factions: {
+ type: "array",
+ items: {
+ type: "object",
+ properties: factionProperties,
+ },
+ },
+ },
+ },
+ };
+ },
+ FactionInvitePlayer: class FactionInvitePlayer {
+ static type = "request";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ faction_id: { type: "string" },
+ player_name: { type: "string" },
+ role: { type: "string" },
+ },
+ };
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ properties: {
+ ok: { type: "boolean" },
+ message: { type: "string" },
+ },
+ },
+ };
+ },
+ JoinFaction: class JoinFaction {
+ static type = "request";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ faction_id: { type: "string" },
+ player_name: { type: "string" },
+ },
+ };
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ properties: {
+ ok: { type: "boolean" },
+ message: { type: "string" },
+ },
+ },
+ };
+ },
+ LeaveFaction: class LeaveFaction {
+ static type = "request";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ faction_id: { type: "string" },
+ player_name: { type: "string" },
+ },
+ };
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ properties: {
+ ok: { type: "boolean" },
+ message: { type: "string" },
+ },
+ },
+ };
+ },
+ FactionChangeMemberRole: class FactionChangeMemberRole {
+ static type = "request";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ faction_id: { type: "string" },
+ player_name: { type: "string" },
+ role: factionProperties.members.items.properties.role,
+ },
+ };
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ properties: {
+ ok: { type: "boolean" },
+ message: { type: "string" },
+ },
+ },
+ };
+ },
+ ClaimServer: class ClaimServer {
+ static type = "request";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ instance_id: { type: "integer" },
+ player_name: { type: "string" },
+ faction_id: { type: "string" },
+ },
+ };
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ properties: {
+ ok: { type: "boolean" },
+ message: { type: "string" },
+ },
+ },
+ };
+ },
+ UnclaimServer: class UnclaimServer {
+ static type = "request";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ instance_id: { type: "integer" },
+ player_name: { type: "string" },
+ },
+ };
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ properties: {
+ ok: { type: "boolean" },
+ message: { type: "string" },
+ },
+ },
+ };
+ },
+ JoinGridworld: class JoinGridworld {
+ static type = "request";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ player_name: { type: "string" },
+ grid_id: { type: "integer" },
+ },
+ };
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ properties: {
+ ok: { type: "boolean" },
+ message: { type: "string" },
+ connection_address: { type: "string" },
+ server_name: { type: "string" },
+ server_description: { type: "string" },
+ },
+ },
+ };
+ },
+ PerformEdgeTeleport: class PerformEdgeTeleport {
+ static type = "request";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ player_name: { type: "string" },
+ player_x_position: { type: "number" },
+ player_y_position: { type: "number" },
+ grid_id: { type: "integer" },
+ },
+ };
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ properties: {
+ ok: { type: "boolean" },
+ message: { type: "string" },
+ connection_address: { type: "string" },
+ server_name: { type: "string" },
+ server_description: { type: "string" },
+ instance_id: { type: "integer" },
+ },
+ },
+ };
+ },
+ GetTileData: class GetTileData {
+ static type = "request";
+ static src = "controller";
+ static dst = "instance";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ instance_id: { type: "integer" },
+ position_a: { type: "array", items: { type: "number" } },
+ position_b: { type: "array", items: { type: "number" } },
+ },
+ };
+ },
+ RefreshTileData: class RefreshTileData {
+ static type = "request";
+ static src = "control";
+ static dst = "controller";
+ static plugin = pluginName;
+ static permission = "gridworld.map.refresh";
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ instance_id: { type: "integer" },
+ },
+ };
+ },
+ SetLoadFactor: class SetLoadFactor {
+ static type = "event";
+ static src = "instance";
+ static dst = "controller";
+ static plugin = pluginName;
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ instance_id: { type: "integer" },
+ load_factor: { type: "number" },
+ },
+ };
+ },
+};
diff --git a/module/edge_teleport.lua b/module/edge_teleport.lua
index 4be28fe..1092742 100644
--- a/module/edge_teleport.lua
+++ b/module/edge_teleport.lua
@@ -77,7 +77,7 @@ local function send_teleport_command_on_player_leave(player_name, instance_id, x
global.gridworld.players[player_name].teleport_data = nil
end
--[[
- Called when the master has determined which instance the player should be offered a teleport to.
+ Called when the controller has determined which instance the player should be offered a teleport to.
Data is forwarded to the correct instance once the player leaves this server
]]
local function prepare_teleport_data(json)
diff --git a/package.json b/package.json
index 66708b0..37316ae 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,7 @@
"url": "https://github.com/Danielv123/gridworld/issues"
},
"engines": {
- "node": ">=14"
+ "node": ">=18"
},
"peerDependencies": {
"@clusterio/lib": "^2.0.0-alpha.0",
@@ -29,20 +29,19 @@
},
"devDependencies": {
"@clusterio/web_ui": "^2.0.0-alpha.0",
- "antd": "^4.16.0",
+ "antd": "^5.13.0",
"eslint": "^8.4.1",
"eslint-plugin-node": "^11.1.0",
"husky": "^8.0.1",
"leaflet": "^1.7.1",
"leaflet-rastercoords": "^1.0.4",
- "react": "^16.13.1",
- "react-dom": "^16.13.1",
- "react-leaflet": "^2.8.0",
- "react-leaflet-enhanced-marker": "^1.0.21",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-leaflet": "^4.2.1",
"spaces-to-tabs": "^0.0.3",
- "webpack": "^5.36.2",
- "webpack-cli": "^4.7.0",
- "webpack-merge": "^5.2.0"
+ "webpack": "^5.88.2",
+ "webpack-cli": "^5.1.4",
+ "webpack-merge": "^5.9.0"
},
"publishConfig": {
"access": "public"
diff --git a/run_controller.sh b/run_controller.sh
new file mode 100755
index 0000000..9c03563
--- /dev/null
+++ b/run_controller.sh
@@ -0,0 +1 @@
+(cd ../.. && node packages/controller run --dev --dev-plugin gridworld)
diff --git a/run_host.sh b/run_host.sh
new file mode 100755
index 0000000..45db617
--- /dev/null
+++ b/run_host.sh
@@ -0,0 +1 @@
+(cd ../.. && node packages/host run)
diff --git a/run_master.sh b/run_master.sh
deleted file mode 100755
index 5dffeec..0000000
--- a/run_master.sh
+++ /dev/null
@@ -1 +0,0 @@
-(cd ../.. && node packages/master run --dev --dev-plugin gridworld)
diff --git a/run_slave.sh b/run_slave.sh
deleted file mode 100755
index 52e8d59..0000000
--- a/run_slave.sh
+++ /dev/null
@@ -1 +0,0 @@
-(cd ../.. && node packages/slave run)
diff --git a/src/event_handlers/playerPositionEventHandler.js b/src/event_handlers/playerPositionEventHandler.js
index b12cad4..cb0cfc6 100644
--- a/src/event_handlers/playerPositionEventHandler.js
+++ b/src/event_handlers/playerPositionEventHandler.js
@@ -1,9 +1,14 @@
"use strict";
+
+const messages = require("../../messages");
+
module.exports = async function playerPositionEventHandler(message) {
// Broadcast player position from instance to web interface
- // TODO: Save position on master and broadcast full list on connect.
+ // TODO: Save position on controller and broadcast full list on connect.
// TODO: Don't broadcast individual events unless position has changed.
for (let sub of this.subscribedControlLinks) {
- if (sub.player_posiiton) { this.info.messages.playerPosition.send(sub.link, message.data); }
+ if (sub.player_posiiton) {
+ sub.link.send(new messages.PlayerPosition(message.data));
+ }
}
};
diff --git a/src/instance_migration/info/MigrateInstanceRequest.js b/src/instance_migration/info/MigrateInstanceRequest.js
new file mode 100644
index 0000000..933d7b8
--- /dev/null
+++ b/src/instance_migration/info/MigrateInstanceRequest.js
@@ -0,0 +1,33 @@
+"use strict";
+const { libLink } = require("@clusterio/lib");
+
+class MigrateInstanceRequest {
+ static type = "request";
+ static src = "control";
+ static dst = "controller";
+ static permission = "gridworld.migrate_instance";
+ static jsonSchema = {
+ type: "object",
+ properties: {
+ instance_id: { type: "integer" },
+ host_id: { type: "integer" },
+ },
+ required: ["instance_id", "host_id"],
+ additionalProperties: false,
+ };
+ static Response = {
+ jsonSchema: {
+ type: "object",
+ properties: {
+ status: {
+ type: "string",
+ enum: ["success", "failure"],
+ },
+ },
+ required: ["status"],
+ additionalProperties: false,
+ },
+ };
+}
+
+module.exports = MigrateInstanceRequest;
diff --git a/src/instance_migration/info/migrateInstanceCommandRequest.js b/src/instance_migration/info/migrateInstanceCommandRequest.js
deleted file mode 100644
index 8e4031b..0000000
--- a/src/instance_migration/info/migrateInstanceCommandRequest.js
+++ /dev/null
@@ -1,20 +0,0 @@
-"use strict";
-const { libLink } = require("@clusterio/lib");
-
-const migrateInstanceCommand = new libLink.Request({
- type: "gridworld:migrate_instance",
- links: ["control-master"],
- permission: "gridworld.migrate_instance",
- requestProperties: {
- "instance_id": { type: "integer" },
- "slave_id": { type: "integer" },
- },
- responseProperties: {
- "status": {
- type: "string",
- enum: ["success", "failure"],
- },
- },
-});
-
-module.exports = migrateInstanceCommand;
diff --git a/src/instance_migration/info/migrateInstancePermission.js b/src/instance_migration/info/migrateInstancePermission.js
index cf09cc1..fa4c722 100644
--- a/src/instance_migration/info/migrateInstancePermission.js
+++ b/src/instance_migration/info/migrateInstancePermission.js
@@ -1,8 +1,8 @@
"use strict";
-const { libUsers } = require("@clusterio/lib");
+const lib = require("@clusterio/lib");
-libUsers.definePermission({
+lib.definePermission({
name: "gridworld.migrate_instance",
title: "Migrate instance",
- description: "Migrate an instance to another slave. Uses stop, start, and assign internally.",
+ description: "Migrate an instance to another host. Uses stop, start, and assign internally.",
});
diff --git a/src/instance_migration/migrateInstanceRequestHandler.js b/src/instance_migration/migrateInstanceRequestHandler.js
index d0a7783..ba4fb47 100644
--- a/src/instance_migration/migrateInstanceRequestHandler.js
+++ b/src/instance_migration/migrateInstanceRequestHandler.js
@@ -3,11 +3,11 @@ const crypto = require("crypto");
const events = require("events");
const util = require("util");
-const { libLink, libErrors } = require("@clusterio/lib");
-const { logger } = require("@clusterio/lib/logging");
+const lib = require("@clusterio/lib");
+const messages = require("../../messages");
-// Somehow require routes from packages/master/src/routes
+// Somehow require routes from packages/controller/src/routes
async function createProxyStream(app) {
let asyncRandomBytes = util.promisify(crypto.randomBytes);
@@ -21,7 +21,7 @@ async function createProxyStream(app) {
events: new events.EventEmitter(),
timeout: setTimeout(() => {
stream.events.emit("timeout");
- }, app.locals.master.config.get("master.proxy_stream_timeout") * 1000),
+ }, app.locals.controller.config.get("controller.proxy_stream_timeout") * 1000),
};
stream.events.on("close", () => {
clearTimeout(stream.timeout);
@@ -36,76 +36,73 @@ async function createProxyStream(app) {
module.exports = async function migrateInstanceRequestHandler(message, request) {
- let { instance_id, slave_id } = message.data;
- let instance = this.master.instances.get(instance_id);
+ let { instance_id, host_id } = message.data;
+ let instance = this.controller.instances.get(instance_id);
if (!instance) {
- throw new libErrors.RequestError(`Instance with ID ${instance_id} does not exist`);
+ throw new lib.RequestError(`Instance with ID ${instance_id} does not exist`);
}
- if (instance.config.get("instance.assigned_slave") === null) {
- throw new libErrors.RequestError(`Instance with ID ${instance_id} is not assigned to a slave`);
+ if (instance.config.get("instance.assigned_host") === null) {
+ throw new lib.RequestError(`Instance with ID ${instance_id} is not assigned to a host`);
}
- let originSlaveId = instance.config.get("instance.assigned_slave");
- let originSlave = this.master.slaves.get(originSlaveId);
- if (!originSlave) {
- throw new libErrors.RequestError(`Slave with ID ${originSlaveId} does not exist`);
+ let originHostId = instance.config.get("instance.assigned_host");
+ let originHost = this.controller.hosts.get(originHostId);
+ if (!originHost) {
+ throw new lib.RequestError(`Host with ID ${originHostId} does not exist`);
}
- const originSlaveConnection = this.master.wsServer.slaveConnections.get(originSlaveId);
- if (!originSlaveConnection) {
- throw new libErrors.RequestError(`Origin slave with ID ${originSlaveId} is not online`);
+ const originHostConnection = this.controller.wsServer.hostConnections.get(originHostId);
+ if (!originHostConnection) {
+ throw new lib.RequestError(`Origin host with ID ${originHostId} is not online`);
}
- let destinationSlave = this.master.slaves.get(slave_id);
- if (!destinationSlave) {
- throw new libErrors.RequestError(`Slave with ID ${slave_id} does not exist`);
+ let destinationHost = this.controller.hosts.get(host_id);
+ if (!destinationHost) {
+ throw new lib.RequestError(`Host with ID ${host_id} does not exist`);
}
- const destinationSlaveConnection = this.master.wsServer.slaveConnections.get(slave_id);
- if (!destinationSlaveConnection) {
- throw new libErrors.RequestError(`Destination slave with ID ${slave_id} is not online`);
+ const destinationHostConnection = this.controller.wsServer.hostConnections.get(host_id);
+ if (!destinationHostConnection) {
+ throw new lib.RequestError(`Destination host with ID ${host_id} is not online`);
}
// If the instance is running, stop it first
const originalStatus = instance.status;
if (instance.status === "running") {
- await libLink.messages.stopInstance.send(originSlaveConnection, {
+ this.controller.sendTo({ instanceId: instance_id }, new lib.InstanceStopRequest({
instance_id: instance_id,
- });
+ }));
}
- // Get savefiles from origin slave
- const saves = (await libLink.messages.listSaves.send(originSlaveConnection, {
- instance_id: instance_id,
- })).list;
+ // Get savefiles from origin host
+ // TODO-migrate: I don't think this can be sent from host, check Controller.ts
+ const saves = (await this.controller.sendTo({ instanceId: instance_id }, new lib.InstanceSaveDetailsListRequest())).list;
- // Delete any remnants of the instance on the destination slave
+ // Delete any remnants of the instance on the destination host
try {
- await libLink.messages.deleteInstance.send(destinationSlaveConnection, {
- instance_id: instance_id,
- });
- } catch (e) {}
+ await destinationHostConnection.send(new lib.InstanceDeleteInternalRequest(instance_id));
+ } catch (e) { }
const preparedUploads = await Promise.all(saves.map(async save => {
const filename = save.name;
- let stream = await createProxyStream(this.master.app);
+ let stream = await createProxyStream(this.controller.app);
stream.filename = filename;
let ready = new Promise((resolve, reject) => {
stream.events.on("source", resolve);
stream.events.on("timeout", () => reject(
- new libErrors.RequestError("Timed out establishing stream from slave")
+ new lib.RequestError("Timed out establishing stream from host")
));
});
ready.catch(() => { });
- // Send start upload message to slave
- await this.master.forwardRequestToInstance(libLink.messages.pushSave, {
- instance_id,
+ // Send start upload message to host
+ await this.controller.sendTo({ hostId: host_id }, new lib.InstancePushSaveRequest({
+ instanceId: instance_id,
stream_id: stream.id,
save: filename,
- });
+ }));
await ready;
@@ -115,69 +112,63 @@ module.exports = async function migrateInstanceRequestHandler(message, request)
};
}));
- // Unassign instance from origin slave
- await libLink.messages.unassignInstance.send(originSlaveConnection, {
- instance_id,
- });
+ // Unassign instance from origin host
+ await originHostConnection.send(new lib.InstanceUnassignInternalRequest(instance_id));
try {
- // Assign instance to destination slave
- instance.config.set("instance.assigned_slave", slave_id);
- await libLink.messages.assignInstance.send(destinationSlaveConnection, {
- instance_id,
- serialized_config: instance.config.serialize("slave"),
- });
+ // Assign instance to destination host
+ instance.config.set("instance.assigned_host", host_id);
+ await destinationHostConnection.send(new lib.InstanceAssignInternalRequest({
+ instanceId: instance_id,
+ config: instance.config.toRemote("host"),
+ }));
} catch (e) {
- // Reassign instance to origin slave
- instance.config.set("instance.assigned_slave", originSlaveId);
- await libLink.messages.assignInstance.send(originSlaveConnection, {
- instance_id,
- serialized_config: instance.config.serialize("slave"),
- });
+ // Reassign instance to origin host
+ instance.config.set("instance.assigned_host", originHostId);
+
+ await originHostConnection.send(new lib.InstanceAssignInternalRequest({
+ instanceId: instance_id,
+ config: instance.config.toRemote("host"),
+ }));
throw e;
}
try {
- // Start transfer of files to slave
+ // Start transfer of files to host
for (let preparedUpload of preparedUploads) {
const { stream_id, filename } = preparedUpload;
logger.info(`Transferring ${preparedUpload.filename}`);
- // Make the other slave download the file
- await libLink.messages.pullSave.send(destinationSlaveConnection, {
+ // Make the other host download the file
+ await destinationHostConnection.send(new lib.InstancePullSaveRequest({
instance_id,
stream_id,
- filename,
- });
+ name: filename,
+ }));
}
} catch (e) {
- // Unassign instance from destination slave
- await libLink.messages.unassignInstance.send(destinationSlaveConnection, {
- instance_id,
- });
+ // Unassign instance from destination host
+ await destinationHostConnection.send(new lib.InstanceUnassignInternalRequest(instance_id));
- // Assign instance to origin slave
- instance.config.set("instance.assigned_slave", originSlaveId);
- await libLink.messages.assignInstance.send(originSlaveConnection, {
- instance_id,
- serialized_config: instance.config.serialize("slave"),
- });
+ // Assign instance to origin host
+ instance.config.set("instance.assigned_host", originHostId);
+ await originHostConnection.send(new lib.InstanceAssignInternalRequest({
+ instanceId: instance_id,
+ config: instance.config.toRemote("host"),
+ }));
throw e;
}
// Restart the instance if we stopped it
if (originalStatus === "running") {
- await libLink.messages.startInstance.send(destinationSlaveConnection, {
- instance_id,
+ await this.controller.sendTo({ instanceId: instance_id }, new lib.InstanceStartRequest({
save: null,
- });
+ }));
}
// Clean up the leftover files
- await libLink.messages.deleteInstance.send(originSlaveConnection, {
- instance_id,
- });
+ await originHostConnection.send(new lib.InstanceDeleteInternalRequest(instance_id));
return { status: "success" };
};
diff --git a/src/request_handlers/createFactionGridRequestHandler.js b/src/request_handlers/createFactionGridRequestHandler.js
index 75e5e1c..3686e81 100644
--- a/src/request_handlers/createFactionGridRequestHandler.js
+++ b/src/request_handlers/createFactionGridRequestHandler.js
@@ -7,7 +7,7 @@ module.exports = async function createRequestHandler(message) {
// name_prefix: "Gridworld",
// use_edge_transports: true,
// x_size: 500, y_size: 500,
- // slave: slave_id - should be picked automatically from connected slaves
+ // host: host_id - should be picked automatically from connected hosts
// }
// Create a new gridworld. We also need to store the x_size and y_size somewhere.
@@ -15,7 +15,7 @@ module.exports = async function createRequestHandler(message) {
if (!message.data.use_edge_transports) { return; }
const grid = createFactionGrid({
plugin: this,
- slaveId: message.data.slave,
+ hostId: message.data.host,
x_size: message.data.x_size,
y_size: message.data.y_size,
});
diff --git a/src/request_handlers/createFactionRequestHandler.js b/src/request_handlers/createFactionRequestHandler.js
index 7d969c9..6763ece 100644
--- a/src/request_handlers/createFactionRequestHandler.js
+++ b/src/request_handlers/createFactionRequestHandler.js
@@ -1,4 +1,7 @@
"use strict";
+
+const messages = require("../../messages");
+
module.exports = async function createFactionRequestHandler(message, request, link) {
const new_faction = {
faction_id: message.data.faction_id,
@@ -13,11 +16,13 @@ module.exports = async function createFactionRequestHandler(message, request, li
this.factionsDatastore.set(message.data.faction_id, new_faction);
// Propagate changes to all online instances
- this.broadcastEventToSlaves(this.info.messages.factionUpdate, { faction: new_faction });
+ this.controller.sendTo("allInstances", new messages.FactionUpdate({ faction: new_faction }));
// Propagate changes to listening web clients
for (let sub of this.subscribedControlLinks) {
- if (sub.faction_list) { this.info.messages.factionUpdate.send(sub.link, { faction: new_faction }); }
+ if (sub.faction_list) {
+ sub.link.send(new messages.FactionUpdate({ faction: new_faction }));
+ }
}
return {
diff --git a/src/request_handlers/factionChangeMemberRoleRequestHandler.js b/src/request_handlers/factionChangeMemberRoleRequestHandler.js
index 7357cad..5299795 100644
--- a/src/request_handlers/factionChangeMemberRoleRequestHandler.js
+++ b/src/request_handlers/factionChangeMemberRoleRequestHandler.js
@@ -1,4 +1,7 @@
"use strict";
+
+const messages = require("../../messages");
+
module.exports = async function factionChangeMemberRoleRequestHandler(message, request, link) {
const faction = this.factionsDatastore.get(message.data.faction_id);
if (faction) {
@@ -16,11 +19,13 @@ module.exports = async function factionChangeMemberRoleRequestHandler(message, r
member.role = message.data.role;
// Propagate changes to all online instances
- this.broadcastEventToSlaves(this.info.messages.factionUpdate, { faction: faction });
+ this.controller.sendTo("allInstances", new messages.FactionUpdate({ faction: faction }));
// Propagate changes to listening web clients
for (let sub of this.subscribedControlLinks) {
- if (sub.faction_list) { this.info.messages.factionUpdate.send(sub.link, { faction: faction }); }
+ if (sub.faction_list) {
+ sub.link.send(new messages.FactionUpdate({ faction: faction }));
+ }
}
return {
diff --git a/src/request_handlers/factionInvitePlayerRequestHandler.js b/src/request_handlers/factionInvitePlayerRequestHandler.js
index be4cf4c..b74c6ab 100644
--- a/src/request_handlers/factionInvitePlayerRequestHandler.js
+++ b/src/request_handlers/factionInvitePlayerRequestHandler.js
@@ -20,11 +20,13 @@ module.exports = async function factionInvitePlayerRequestHandler(message, reque
});
// Propagate changes to all online instances
- this.broadcastEventToSlaves(this.info.messages.factionUpdate, { faction: faction });
+ this.controller.sendTo("allInstances", new messages.FactionUpdate({ faction: faction }));
// Propagate changes to listening web clients
for (let sub of this.subscribedControlLinks) {
- if (sub.faction_list) { this.info.messages.factionUpdate.send(sub.link, { faction: faction }); }
+ if (sub.faction_list) {
+ sub.link.send(new messages.FactionUpdate({ faction: faction }));
+ }
}
return {
diff --git a/src/request_handlers/getMapDataRequestHandler.js b/src/request_handlers/getMapDataRequestHandler.js
index f8f4dfa..343fbdc 100644
--- a/src/request_handlers/getMapDataRequestHandler.js
+++ b/src/request_handlers/getMapDataRequestHandler.js
@@ -1,6 +1,6 @@
"use strict";
module.exports = async function getMapDataRequestHandler() {
- const instances = [...this.master.instances]
+ const instances = [...this.controller.instances]
.filter(instance => instance[1].config.get("gridworld.is_lobby_server") === false);
return {
map_data: instances.map(instance => ({
diff --git a/src/request_handlers/joinFactionRequestHandler.js b/src/request_handlers/joinFactionRequestHandler.js
index 793eacd..2ac82c8 100644
--- a/src/request_handlers/joinFactionRequestHandler.js
+++ b/src/request_handlers/joinFactionRequestHandler.js
@@ -37,9 +37,13 @@ module.exports = async function joinFactionEventHandler(message) {
let member = oldFaction.members.find(m => m.name.toLowerCase() === player.toLowerCase());
if (member) {
oldFaction.members.splice(oldFaction.members.indexOf(member), 1);
- this.broadcastEventToSlaves(this.info.messages.factionUpdate, { faction: oldFaction });
+ this.controller.sendTo("allInstances", new messages.FactionUpdate({ faction: faction }));
+
+ // Propagate changes to listening web clients
for (let sub of this.subscribedControlLinks) {
- if (sub.faction_list) { this.info.messages.factionUpdate.send(sub.link, { faction: oldFaction }); }
+ if (sub.faction_list) {
+ sub.link.send(new messages.FactionUpdate({ faction: faction }));
+ }
}
}
}
@@ -59,11 +63,13 @@ module.exports = async function joinFactionEventHandler(message) {
}
// Propagate changes to all online instances
- this.broadcastEventToSlaves(this.info.messages.factionUpdate, { faction: faction });
+ this.controller.sendTo("allInstances", new messages.FactionUpdate({ faction: faction }));
// Propagate changes to listening web clients
for (let sub of this.subscribedControlLinks) {
- if (sub.faction_list) { this.info.messages.factionUpdate.send(sub.link, { faction: faction }); }
+ if (sub.faction_list) {
+ sub.link.send(new messages.FactionUpdate({ faction: faction }));
+ }
}
return {
diff --git a/src/request_handlers/joinGridworldRequestHandler.js b/src/request_handlers/joinGridworldRequestHandler.js
index 42fd0e6..00713fc 100644
--- a/src/request_handlers/joinGridworldRequestHandler.js
+++ b/src/request_handlers/joinGridworldRequestHandler.js
@@ -1,5 +1,5 @@
"use strict";
-const { libLink } = require("@clusterio/lib");
+const lib = require("@clusterio/lib");
const mapFilter = require("../util/mapFilter");
const mapFind = require("../util/mapFind");
@@ -9,14 +9,14 @@ const worldPositionToInstance = require("../worldgen/util/worldPositionToInstanc
module.exports = async function joinGridworldRequestHandler(message, request, link) {
const player_name = message.data.player_name;
- // Get player profile from master
- const player = this.master.userManager.users.get(player_name);
+ // Get player profile from controller
+ const player = this.controller.userManager.users.get(player_name);
// Get player faction
const faction = mapFind(this.factionsDatastore, f => f.members.find(member => member.name.toLowerCase() === player_name.toLowerCase()));
// Get all instances in the current grid
- const instances = mapFilter(this.master.instances, instance => instance.config.get("gridworld.grid_id") === message.data.grid_id);
+ const instances = mapFilter(this.controller.instances, instance => instance.config.get("gridworld.grid_id") === message.data.grid_id);
const response = {
ok: false,
@@ -51,7 +51,7 @@ module.exports = async function joinGridworldRequestHandler(message, request, li
} else {
// If the player doesn't have a faction, send them to the factionless spawn
// Factionless spawn is 25,25
- const position = worldPositionToInstance(25, 25, message.data.grid_id, this.master.instances);
+ const position = worldPositionToInstance(25, 25, message.data.grid_id, this.controller.instances);
if (!position.instance) {
// No instance found for factionless spawn, create a new one
const instance_id = (await createServer({
@@ -60,7 +60,7 @@ module.exports = async function joinGridworldRequestHandler(message, request, li
y: position.grid_y_position,
grid_id: message.data.grid_id,
})).instanceId;
- const instance = this.master.instances.get(instance_id);
+ const instance = this.controller.instances.get(instance_id);
response.ok = true;
response.message = "Created new instance";
@@ -81,18 +81,17 @@ module.exports = async function joinGridworldRequestHandler(message, request, li
// Ensure the instance we are connecting to is started
if (instance_to_connect_to) {
- const slaveId = instance_to_connect_to.config.get("instance.assigned_slave");
- let slaveConnection = this.master.wsServer.slaveConnections.get(slaveId);
+ const hostId = instance_to_connect_to.config.get("instance.assigned_host");
// Instance status
if (instance_to_connect_to.status !== "running") {
- await libLink.messages.startInstance.send(slaveConnection, {
- instance_id: instance_to_connect_to.config.get("instance.id"),
- save: null,
- });
+ await this.controller.sendTo(
+ { instanceId: instance_to_connect_to.config.get("instance.id") },
+ new lib.InstanceStartRequest({ save: null })
+ );
}
- const slave = this.master.slaves.get(slaveId);
- response.connection_address = `${slave.public_address}:${instance_to_connect_to.game_port || instance_to_connect_to.config.get("factorio.game_port")}`;
+ const host = this.controller.hosts.get(hostId);
+ response.connection_address = `${host.public_address}:${instance_to_connect_to.game_port || instance_to_connect_to.config.get("factorio.game_port")}`;
}
// Return response to client
diff --git a/src/request_handlers/leaveFactionRequestHandler.js b/src/request_handlers/leaveFactionRequestHandler.js
index e1d756f..8a740cb 100644
--- a/src/request_handlers/leaveFactionRequestHandler.js
+++ b/src/request_handlers/leaveFactionRequestHandler.js
@@ -1,4 +1,7 @@
"use strict";
+
+const messages = require("../../messages");
+
module.exports = async function leaveFactionRequestHandler(message, request, link) {
const faction = this.factionsDatastore.get(message.data.faction_id);
if (faction) {
@@ -6,11 +9,13 @@ module.exports = async function leaveFactionRequestHandler(message, request, lin
faction.members = faction.members.filter(member => member.name.toLowerCase() !== message.data.player_name.toLowerCase());
// Propagate changes to all online instances
- this.broadcastEventToSlaves(this.info.messages.factionUpdate, { faction: faction });
+ this.controller.sendTo("allInstances", new messages.FactionUpdate({ faction: faction }));
// Propagate changes to listening web clients
for (let sub of this.subscribedControlLinks) {
- if (sub.faction_list) { this.info.messages.factionUpdate.send(sub.link, { faction: faction }); }
+ if (sub.faction_list) {
+ sub.link.send(new messages.FactionUpdate({ faction: faction }));
+ }
}
return {
diff --git a/src/request_handlers/performEdgeTeleportRequestHandler.js b/src/request_handlers/performEdgeTeleportRequestHandler.js
index 46defee..f31ffcc 100644
--- a/src/request_handlers/performEdgeTeleportRequestHandler.js
+++ b/src/request_handlers/performEdgeTeleportRequestHandler.js
@@ -1,5 +1,5 @@
"use strict";
-const { libLink } = require("@clusterio/lib");
+const lib = require("@clusterio/lib");
const mapFilter = require("../util/mapFilter");
const mapFind = require("../util/mapFind");
@@ -18,8 +18,8 @@ const worldPositionToInstance = require("../worldgen/util/worldPositionToInstanc
module.exports = async function joinGridworldRequestHandler(message) {
const player_name = message.data.player_name;
- // Get player profile from master
- const player = this.master.userManager.users.get(player_name);
+ // Get player profile from controller
+ const player = this.controller.userManager.users.get(player_name);
// Get player faction
// TODO: Sync faction data to destination instance
@@ -30,7 +30,7 @@ module.exports = async function joinGridworldRequestHandler(message) {
message.data.player_x_position,
message.data.player_y_position,
message.data.grid_id,
- this.master.instances
+ this.controller.instances
);
let instance_to_connect_to = null;
@@ -56,7 +56,7 @@ module.exports = async function joinGridworldRequestHandler(message) {
y: instance_specification.grid_y_position,
grid_id: message.data.grid_id,
})).instanceId;
- const instance = this.master.instances.get(instance_id);
+ const instance = this.controller.instances.get(instance_id);
response.ok = true;
response.message = "Created new instance";
@@ -76,8 +76,8 @@ module.exports = async function joinGridworldRequestHandler(message) {
// Ensure the instance we are connecting to is started
if (instance_to_connect_to) {
- const slaveId = instance_to_connect_to.config.get("instance.assigned_slave");
- let slaveConnection = this.master.wsServer.slaveConnections.get(slaveId);
+ const hostId = instance_to_connect_to.config.get("instance.assigned_host");
+ let hostConnection = this.controller.wsServer.hostConnections.get(hostId);
// Instance status
if (instance_to_connect_to.status !== "running") {
try {
@@ -88,14 +88,15 @@ module.exports = async function joinGridworldRequestHandler(message) {
message: "You do not have permission to start servers through exploration",
};
}
- await libLink.messages.startInstance.send(slaveConnection, {
- instance_id: instance_to_connect_to.config.get("instance.id"),
- save: null,
- });
+ // Start the instance
+ await this.controller.sendTo(
+ { instanceId: instance_to_connect_to.config.get("instance.id") },
+ new lib.InstanceStartRequest({ save: null })
+ );
}
- const slave = this.master.slaves.get(slaveId);
- response.connection_address = `${slave.public_address}:${instance_to_connect_to.game_port || instance_to_connect_to.config.get("factorio.game_port")}`;
+ const host = this.controller.hosts.get(hostId);
+ response.connection_address = `${host.public_address}:${instance_to_connect_to.game_port || instance_to_connect_to.config.get("factorio.game_port")}`;
}
// Return response to client
diff --git a/src/request_handlers/refreshTileDataRequestHandler.js b/src/request_handlers/refreshTileDataRequestHandler.js
index 8b068a3..5cb44ea 100644
--- a/src/request_handlers/refreshTileDataRequestHandler.js
+++ b/src/request_handlers/refreshTileDataRequestHandler.js
@@ -2,36 +2,37 @@
const path = require("path");
const sharp = require("sharp");
-const { libLink } = require("@clusterio/lib");
-const libErrors = require("@clusterio/lib/errors");
+const lib = require("@clusterio/lib");
const { zoomOutLevel } = require("./../tileZoomFunctions");
-const info = require("./../../info");
+const info = require("./../../index");
+const messages = require("../../messages");
module.exports = async function refreshTileDataRequestHandler(message) {
- let instance = this.master.instances.get(message.data.instance_id);
+ const instanceId = message.data.instance_id;
+ let instance = this.controller.instances.get(message.data.instance_id);
if (!instance) {
- throw new libErrors.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
+ throw new lib.RequestError(`Instance with ID ${message.data.instance_id} does not exist`);
}
- let slaveId = instance.config.get("instance.assigned_slave");
- if (!slaveId) {
- throw new libErrors.RequestError("Instance is not assigned to a slave");
+ let hostId = instance.config.get("instance.assigned_host");
+ if (!hostId) {
+ throw new lib.RequestError("Instance is not assigned to a host");
}
- let slaveConnection = this.master.wsServer.slaveConnections.get(slaveId);
- if (!slaveConnection) {
- throw new libErrors.RequestError("Instance is assigned to a slave that is not connected");
+ let hostConnection = this.controller.wsServer.hostConnections.get(hostId);
+ if (!hostConnection) {
+ throw new lib.RequestError("Instance is assigned to a host that is not connected");
}
// If the instance is stopped, temporarily start it.
let originalStatus = instance.status;
if (instance.status === "stopped") {
// Start instance
- await libLink.messages.startInstance.send(slaveConnection, {
- instance_id: message.data.instance_id,
- save: null,
- });
+ await this.controller.sendTo(
+ { instanceId },
+ new lib.InstanceStartRequest({ save: null })
+ );
}
// Get bounds
@@ -62,13 +63,11 @@ module.exports = async function refreshTileDataRequestHandler(message) {
for (let i = 0; i < chunks.length; i++) {
let chunk = chunks[i];
- let data = await info.messages.getTileData.send(slaveConnection, {
- instance_id: message.data.instance_id,
- ...chunk,
- });
+ // Get data from instance
+ let data = await hostConnection.sendTo({ instanceId }, new messages.GetTileData(chunk));
if (data.tile_data[0].includes("Cannot execute command")) {
- this.logger.warn(`Getting tile data failed for instance ${message.data.instance_id} at ${chunk.position_a} to ${chunk.position_b} with error: ${data.tile_data[0]}`);
+ this.logger.warn(`Getting tile data failed for instance ${instanceId} at ${chunk.position_a} to ${chunk.position_b} with error: ${data.tile_data[0]}`);
} else {
// Create raw array of pixels
let rawPixels = Uint8Array.from(
@@ -93,9 +92,11 @@ module.exports = async function refreshTileDataRequestHandler(message) {
}
if (originalStatus === "stopped") {
// Stop instance again
- await libLink.messages.stopInstance.send(slaveConnection, {
- instance_id: message.data.instance_id,
- });
+ await this.controller.sendTo(
+ { instanceId },
+ new lib.InstanceStopRequest()
+ );
+ await hostConnection.sendTo({ instanceId }, new lib.InstanceStopRequest());
}
// Create zoomed out tiles
for (let i = 0; i < chunks.length; i++) {
diff --git a/src/request_handlers/setWebSubscriptionRequestHandler.js b/src/request_handlers/setWebSubscriptionRequestHandler.js
index 00bef9e..ed4b4c4 100644
--- a/src/request_handlers/setWebSubscriptionRequestHandler.js
+++ b/src/request_handlers/setWebSubscriptionRequestHandler.js
@@ -1,16 +1,18 @@
"use strict";
-async function transmitInitialFactionsData(master, link) {
+const messages = require("../../messages");
+
+async function transmitInitialFactionsData(controller, link) {
// Transmit a full copy of the data to the new client
- for (let [id, faction] of master.factionsDatastore) {
- await master.info.messages.factionUpdate.send(link, { faction });
+ for (let [id, faction] of controller.factionsDatastore) {
+ await link.send(new messages.FactionUpdate({ faction }));
}
}
-async function transmitInitialPlayerPositionsData(master, link) {
- // Transmit a full copy of the data to the new client
- // for (let [id, player] of master.gridworldDatastore) {
- // await master.info.messages.playerPositionUpdate.send(link, { player });
+async function transmitInitialPlayerPositionsData(controller, link) {
+ // TODO: Transmit a full copy of the data to the new client
+ // for (let [id, player] of controller.gridworldDatastore) {
+ // await controller.info.messages.playerPositionUpdate.send(link, { player });
// }
}
diff --git a/src/request_handlers/startInstanceRequestHandler.js b/src/request_handlers/startInstanceRequestHandler.js
deleted file mode 100644
index 6762a71..0000000
--- a/src/request_handlers/startInstanceRequestHandler.js
+++ /dev/null
@@ -1,6 +0,0 @@
-"use strict";
-const { libLink } = require("@clusterio/lib");
-
-module.exports = async function startInstanceRequestHandler(message, request, link) {
- return libLink.messages.startInstance.send(link, message.data);
-};
diff --git a/src/request_handlers/updateEdgeTransportEdgesRequestHandler.js b/src/request_handlers/updateEdgeTransportEdgesRequestHandler.js
index 5c0c18d..d014d7b 100644
--- a/src/request_handlers/updateEdgeTransportEdgesRequestHandler.js
+++ b/src/request_handlers/updateEdgeTransportEdgesRequestHandler.js
@@ -16,12 +16,12 @@ module.exports = async function updateEdgeTransportsEdges(message) {
// instance_id: instance_id,
// }
- const instance = this.master.instances.get(message.data.instance_id);
+ const instance = this.controller.instances.get(message.data.instance_id);
const x = instance.config.get("gridworld.grid_x_position");
const y = instance.config.get("gridworld.grid_y_position");
const grid_id = instance.config.get("gridworld.grid_id");
// Get x_size and y_size from lobby server
- const lobby_server = mapFind(this.master.instances, i => i.config.get("gridworld.grid_id") === grid_id
+ const lobby_server = mapFind(this.controller.instances, i => i.config.get("gridworld.grid_id") === grid_id
&& i.config.get("gridworld.is_lobby_server")
);
const x_size = lobby_server.config.get("gridworld.grid_x_size");
@@ -33,7 +33,7 @@ module.exports = async function updateEdgeTransportsEdges(message) {
y_size,
x,
y,
- instances: this.master.instances,
+ instances: this.controller.instances,
grid_id,
});
@@ -43,7 +43,7 @@ module.exports = async function updateEdgeTransportsEdges(message) {
x + edge_target_position_offets[edge.id][0],
y + edge_target_position_offets[edge.id][1],
];
- const target_instance = this.master.instances.get(edge.target_instance);
+ const target_instance = this.controller.instances.get(edge.target_instance);
if (
target_instance.config.get("gridworld.grid_id") === grid_id
&& target_instance.config.get("gridworld.grid_x_position") === target_position[0]
diff --git a/src/request_handlers/updateFactionRequestHandler.js b/src/request_handlers/updateFactionRequestHandler.js
index bb39f45..9788fff 100644
--- a/src/request_handlers/updateFactionRequestHandler.js
+++ b/src/request_handlers/updateFactionRequestHandler.js
@@ -1,4 +1,7 @@
"use strict";
+
+const messages = require("../../messages");
+
module.exports = async function updateFactionRequestHandler(message, request, link) {
const faction = this.factionsDatastore.get(message.data.faction_id);
if (faction) {
@@ -8,11 +11,13 @@ module.exports = async function updateFactionRequestHandler(message, request, li
this.factionsDatastore.set(message.data.faction_id, faction);
// Propagate changes to all online instances
- this.broadcastEventToSlaves(this.info.messages.factionUpdate, { faction: faction });
+ await this.controller.sendTo("allInstances", new messages.FactionUpdate({ faction: faction }));
// Propagate changes to listening web clients
for (let sub of this.subscribedControlLinks) {
- if (sub.faction_list) { this.info.messages.factionUpdate.send(sub.link, { faction: faction }); }
+ if (sub.faction_list) {
+ sub.link.send(new messages.FactionUpdate({ faction: faction }));
+ }
}
return {
diff --git a/src/util/slaveGetNextFreePort.js b/src/util/hostGetNextFreePort.js
similarity index 65%
rename from src/util/slaveGetNextFreePort.js
rename to src/util/hostGetNextFreePort.js
index 581b03c..843ca59 100644
--- a/src/util/slaveGetNextFreePort.js
+++ b/src/util/hostGetNextFreePort.js
@@ -3,8 +3,8 @@
const mapFilter = require("./mapFilter");
const mapFind = require("./mapFind");
-module.exports = function slaveGetNextFreePort(master, slave_id) {
- const instances = mapFilter(master.instances, instance => instance.config.get("instance.assigned_slave") === slave_id || true);
+module.exports = function hostGetNextFreePort(controller, host_id) {
+ const instances = mapFilter(controller.instances, instance => instance.config.get("instance.assigned_host") === host_id || true);
let lowestPort = 10000;
// Find next free port
let port = lowestPort;
diff --git a/src/worldgen/assignInstance.js b/src/worldgen/assignInstance.js
index a1ebb48..5251482 100644
--- a/src/worldgen/assignInstance.js
+++ b/src/worldgen/assignInstance.js
@@ -1,42 +1,50 @@
"use strict";
-const { libLink, libErrors } = require("@clusterio/lib");
+const lib = require("@clusterio/lib");
-module.exports = async function assignInstance(plugin, instance_id, slave_id) {
+module.exports = async function assignInstance(plugin, instanceId, hostId) {
// Code lifted from ControlConnection.js assignInstanceCommandRequestHandler()
- let instance = plugin.master.instances.get(instance_id);
+ let instance = plugin.controller.getRequestInstance(instanceId);
if (!instance) {
- throw new libErrors.RequestError(`Instance with ID ${instance_id} does not exist`);
+ throw new libErrors.RequestError(`Instance with ID ${instanceId} does not exist`);
}
- // Check if target slave is connected
- let newSlaveConnection;
- if (slave_id !== null) {
- newSlaveConnection = plugin.master.wsServer.slaveConnections.get(slave_id);
- if (!newSlaveConnection) {
- // The case of the slave not getting the assign instance message
+ // Check if target host is connected
+ let newHostConnection;
+ if (hostId !== undefined) {
+ newHostConnection = plugin.controller.wsServer.hostConnections.get(hostId);
+ if (!newHostConnection) {
+ // The case of the host not getting the assign instance message
// still have to be handled, so it's not a requirement that the
- // target slave be connected to the master while doing the
+ // target host be connected to the controller while doing the
// assignment, but it is IMHO a better user experience if this
// is the case.
- throw new libErrors.RequestError("Target slave is not connected to the master server");
+ throw new lib.RequestError("Target host is not connected to the controller");
}
}
- // Unassign from currently assigned slave if it is connected.
- let currentAssignedSlave = instance.config.get("instance.assigned_slave");
- if (currentAssignedSlave !== null && slave_id !== currentAssignedSlave) {
- let oldSlaveConnection = plugin.master.wsServer.slaveConnections.get(currentAssignedSlave);
- if (oldSlaveConnection && !oldSlaveConnection.connector.closing) {
- await libLink.messages.unassignInstance.send(oldSlaveConnection, { instance_id });
+ // Unassign from currently assigned host if it is connected.
+ let currentAssignedHost = instance.config.get("instance.assigned_host");
+ if (currentAssignedHost !== null && hostId !== currentAssignedHost) {
+ let oldHostConnection = plugin.controller.wsServer.hostConnections.get(currentAssignedHost);
+ if (oldHostConnection && !oldHostConnection.connector.closing) {
+ await oldHostConnection.send(new lib.InstanceUnassignInternalRequest(instanceId));
}
}
+ // Remove saves recorded from currently assigned host if any
+ // this.clearSavesOfInstance(instanceId); // Not sure if we want this, wasn't in pre v14 code.
+ // If we do need it, we might as well use plugin.controller.instanceAssign(instanceId, hostId);
+
// Assign to target
- instance.config.set("instance.assigned_slave", slave_id);
- if (slave_id !== null) {
- await libLink.messages.assignInstance.send(newSlaveConnection, {
- instance_id,
- serialized_config: instance.config.serialize("slave"),
- });
+ instance.config.set("instance.assigned_host", hostId ?? null);
+ // "fieldChanged" event handler will set this.instancesDirty
+ if (hostId !== undefined && newHostConnection) {
+ await newHostConnection.send(
+ new lib.InstanceAssignInternalRequest(instanceId, instance.config.toRemote("host"))
+ );
+ } else {
+ instance.status = "unassigned";
+ instance.updatedAtMs = Date.now();
+ plugin.controller.instanceDetailsUpdated([instance]);
}
};
diff --git a/src/worldgen/createInstance.js b/src/worldgen/createInstance.js
index c6826e2..b14b1bd 100644
--- a/src/worldgen/createInstance.js
+++ b/src/worldgen/createInstance.js
@@ -3,7 +3,7 @@ const { libConfig, libPlugin, libErrors } = require("@clusterio/lib");
module.exports = async function createInstance(plugin, name, x, y, x_size, y_size, grid_id, game_port) {
plugin.logger.info("Creating instance", name);
- let instanceConfig = new libConfig.InstanceConfig("master");
+ let instanceConfig = new libConfig.InstanceConfig("controller");
await instanceConfig.init();
instanceConfig.set("instance.name", name);
instanceConfig.set("gridworld.grid_id", grid_id);
@@ -16,7 +16,7 @@ module.exports = async function createInstance(plugin, name, x, y, x_size, y_siz
}
let instanceId = instanceConfig.get("instance.id");
- if (plugin.master.instances.has(instanceId)) {
+ if (plugin.controller.instances.has(instanceId)) {
throw new libErrors.RequestError(`Instance with ID ${instanceId} already exists`);
}
@@ -24,8 +24,8 @@ module.exports = async function createInstance(plugin, name, x, y, x_size, y_siz
let settings = {
...instanceConfig.get("factorio.settings"),
- "name": `${plugin.master.config.get("master.name")} - ${name}`,
- "description": `Clusterio instance for ${plugin.master.config.get("master.name")}`,
+ "name": `${plugin.controller.config.get("controller.name")} - ${name}`,
+ "description": `Clusterio instance for ${plugin.controller.config.get("controller.name")}`,
"tags": ["clusterio"],
"max_players": 0,
"visibility": { "public": true, "lan": true },
@@ -47,8 +47,8 @@ module.exports = async function createInstance(plugin, name, x, y, x_size, y_siz
instanceConfig.set("factorio.settings", settings);
let instance = { config: instanceConfig, status: "unassigned" };
- plugin.master.instances.set(instanceId, instance);
- await libPlugin.invokeHook(plugin.master.plugins, "onInstanceStatusChanged", instance, null);
- plugin.master.addInstanceHooks(instance);
+ plugin.controller.instances.set(instanceId, instance);
+ await libPlugin.invokeHook(plugin.controller.plugins, "onInstanceStatusChanged", instance, null);
+ plugin.controller.addInstanceHooks(instance);
return instanceConfig.get("instance.id");
};
diff --git a/src/worldgen/createLobbyServer.js b/src/worldgen/createLobbyServer.js
index e39f724..9325618 100644
--- a/src/worldgen/createLobbyServer.js
+++ b/src/worldgen/createLobbyServer.js
@@ -3,11 +3,11 @@ const { libConfig, libPlugin, libErrors } = require("@clusterio/lib");
const assignInstance = require("./assignInstance");
const createSave = require("./createSave");
-module.exports = async function createLobbyServer(plugin, slaveId, x_size, y_size) {
+module.exports = async function createLobbyServer(plugin, hostId, x_size, y_size) {
// Create instance
plugin.logger.info("Creating lobby server");
const name = "Gridworld lobby server";
- let instanceConfig = new libConfig.InstanceConfig("master");
+ let instanceConfig = new libConfig.InstanceConfig("controller");
await instanceConfig.init();
instanceConfig.set("instance.name", name);
instanceConfig.set("instance.auto_start", true);
@@ -18,7 +18,7 @@ module.exports = async function createLobbyServer(plugin, slaveId, x_size, y_siz
instanceConfig.set("factorio.game_port", 10000);
let instanceId = instanceConfig.get("instance.id");
- if (plugin.master.instances.has(instanceId)) {
+ if (plugin.controller.instances.has(instanceId)) {
throw new libErrors.RequestError(`Instance with ID ${instanceId} already exists`);
}
@@ -26,8 +26,8 @@ module.exports = async function createLobbyServer(plugin, slaveId, x_size, y_siz
let settings = {
...instanceConfig.get("factorio.settings"),
- "name": `${plugin.master.config.get("master.name")} - ${name}`,
- "description": `Clusterio instance for ${plugin.master.config.get("master.name")}`,
+ "name": `${plugin.controller.config.get("controller.name")} - ${name}`,
+ "description": `Clusterio instance for ${plugin.controller.config.get("controller.name")}`,
"tags": ["clusterio", "gridworld"],
"max_players": 0,
"visibility": { "public": true, "lan": true },
@@ -49,19 +49,19 @@ module.exports = async function createLobbyServer(plugin, slaveId, x_size, y_siz
instanceConfig.set("factorio.settings", settings);
let instance = { config: instanceConfig, status: "unassigned" };
- plugin.master.instances.set(instanceId, instance);
- await libPlugin.invokeHook(plugin.master.plugins, "onInstanceStatusChanged", instance, null);
- plugin.master.addInstanceHooks(instance);
+ plugin.controller.instances.set(instanceId, instance);
+ await libPlugin.invokeHook(plugin.controller.plugins, "onInstanceStatusChanged", instance, null);
+ plugin.controller.addInstanceHooks(instance);
const instance_id = instanceConfig.get("instance.id");
- // Assign instance to a slave (using first slave as a placeholder)
- await assignInstance(plugin, instance_id, slaveId);
+ // Assign instance to a host (using first host as a placeholder)
+ await assignInstance(plugin, instance_id, hostId);
// Create map
await createSave(
plugin,
instance_id,
- plugin.master.config.get("gridworld.gridworld_seed"),
- plugin.master.config.get("gridworld.gridworld_map_exchange_string")
+ plugin.controller.config.get("gridworld.gridworld_seed"),
+ plugin.controller.config.get("gridworld.gridworld_map_exchange_string")
);
return instance;
};
diff --git a/src/worldgen/createSave.js b/src/worldgen/createSave.js
index ce7a141..eaf6a55 100644
--- a/src/worldgen/createSave.js
+++ b/src/worldgen/createSave.js
@@ -1,22 +1,21 @@
"use strict";
-const { libLink } = require("@clusterio/lib");
+const lib = require("@clusterio/lib");
const loadMapSettings = require("./../loadMapSettings");
module.exports = async function createSave(plugin, instance_id, seed_orig, mapExchangeString) {
- let instance = plugin.master.instances.get(instance_id);
- let slave_id = instance.config.get("instance.assigned_slave");
+ let instance = plugin.controller.instances.get(instance_id);
+ let host_id = instance.config.get("instance.assigned_host");
let { seed, mapGenSettings, mapSettings } = await loadMapSettings({
seed: seed_orig,
mapExchangeString,
});
- let slaveConnection = plugin.master.wsServer.slaveConnections.get(slave_id);
- return await libLink.messages.createSave.send(slaveConnection, {
- instance_id,
+ let hostConnection = plugin.controller.wsServer.hostConnections.get(host_id);
+ return await hostConnection.sendTo({ instanceId: instance_id }, new lib.InstanceCreateSaveRequest({
name: "Gridworld",
seed,
- map_gen_settings: mapGenSettings,
- map_settings: mapSettings,
- });
+ mapGenSettings: mapGenSettings,
+ mapSettings: mapSettings,
+ }));
};
diff --git a/src/worldgen/factionGrid/createFactionGrid.js b/src/worldgen/factionGrid/createFactionGrid.js
index b447a42..1a01192 100644
--- a/src/worldgen/factionGrid/createFactionGrid.js
+++ b/src/worldgen/factionGrid/createFactionGrid.js
@@ -3,12 +3,12 @@ const createLobbyServer = require("../createLobbyServer");
module.exports = async function createFactionGrid({
plugin,
- slaveId,
+ hostId,
x_size,
y_size,
}) {
// Create lobby server
- let lobbyInstance = await createLobbyServer(plugin, slaveId, x_size, y_size);
+ let lobbyInstance = await createLobbyServer(plugin, hostId, x_size, y_size);
let grid_id = lobbyInstance.config.get("gridworld.grid_id");
return {
grid_id,
diff --git a/src/worldgen/factionGrid/createServer.js b/src/worldgen/factionGrid/createServer.js
index 7397548..009b3f5 100644
--- a/src/worldgen/factionGrid/createServer.js
+++ b/src/worldgen/factionGrid/createServer.js
@@ -7,52 +7,52 @@ const getEdges = require("../getEdges");
const packagejson = require("../../../package.json");
const mapFind = require("../../util/mapFind");
const mapFilter = require("../../util/mapFilter");
-const slaveGetNextFreePort = require("../../util/slaveGetNextFreePort");
+const hostGetNextFreePort = require("../../util/hostGetNextFreePort");
module.exports = async function createServer({
plugin,
- slaveId,
+ hostId,
x,
y,
grid_id,
}) {
// Get x_size and y_size from lobby server
- const lobby_server = mapFind(plugin.master.instances, instance => instance.config.get("gridworld.grid_id") === grid_id
+ const lobby_server = mapFind(plugin.controller.instances, instance => instance.config.get("gridworld.grid_id") === grid_id
&& instance.config.get("gridworld.is_lobby_server")
);
const x_size = lobby_server.config.get("gridworld.grid_x_size");
const y_size = lobby_server.config.get("gridworld.grid_y_size");
- // Find slave with free capacity
- if (slaveId === undefined) {
- // Get slaves with gridworld installed
- const slaves = mapFilter(plugin.master.slaves, slave => slave.plugins.gridworld === packagejson.version);
- const outdatedSlaves = mapFilter(plugin.master.slaves, slave => slave.plugins.gridworld !== packagejson.version);
- if (outdatedSlaves.length > 0) {
- plugin.logger.warn(`Found ${outdatedSlaves.length} slaves with outdated gridworld plugin, please update them: ${outdatedSlaves.map(slave => slave.name).join(", ")}`);
+ // Find host with free capacity
+ if (hostId === undefined) {
+ // Get hosts with gridworld installed
+ const hosts = mapFilter(plugin.controller.hosts, host => host.plugins.gridworld === packagejson.version);
+ const outdatedHosts = mapFilter(plugin.controller.hosts, host => host.plugins.gridworld !== packagejson.version);
+ if (outdatedHosts.length > 0) {
+ plugin.logger.warn(`Found ${outdatedHosts.length} hosts with outdated gridworld plugin, please update them: ${outdatedHosts.map(host => host.name).join(", ")}`);
}
- // Get slave with lowest load
- const instances = mapFilter(plugin.master.instances, instance => instance.config.get("instance.assigned_slave") !== undefined);
- const slaveLoads = [...slaves].map(([_, slave]) => ({
- slaveId: slave.id,
- load: mapFilter(instances, instance => instance.config.get("instance.assigned_slave") === slave.id).length,
+ // Get host with lowest load
+ const instances = mapFilter(plugin.controller.instances, instance => instance.config.get("instance.assigned_host") !== undefined);
+ const hostLoads = [...hosts].map(([_, host]) => ({
+ hostId: host.id,
+ load: mapFilter(instances, instance => instance.config.get("instance.assigned_host") === host.id).length,
}));
- slaveId = slaveLoads.sort((a, b) => a.load - b.load)[0].slaveId;
+ hostId = hostLoads.sort((a, b) => a.load - b.load)[0].hostId;
}
// Create instance
- const instance_game_port = slaveGetNextFreePort(plugin.master, slaveId);
+ const instance_game_port = hostGetNextFreePort(plugin.controller, hostId);
const instanceId = await createInstance(plugin, `Grid square ${Math.floor(Math.random() * 2 ** 16).toString()}`, x, y, x_size, y_size, grid_id, instance_game_port);
- // Assign instance to slave
- await assignInstance(plugin, instanceId, slaveId);
+ // Assign instance to host
+ await assignInstance(plugin, instanceId, hostId);
// Create savefile
await createSave(
plugin,
instanceId,
- plugin.master.config.get("gridworld.gridworld_seed"),
- plugin.master.config.get("gridworld.gridworld_map_exchange_string")
+ plugin.controller.config.get("gridworld.gridworld_seed"),
+ plugin.controller.config.get("gridworld.gridworld_map_exchange_string")
);
return {
diff --git a/web/components/CreateGridworldForm.jsx b/web/components/CreateGridworldForm.jsx
index 847209e..21f40da 100644
--- a/web/components/CreateGridworldForm.jsx
+++ b/web/components/CreateGridworldForm.jsx
@@ -1,11 +1,12 @@
import React, { useContext, useState } from "react";
import { useHistory } from "react-router";
-import { ControlContext, useSlaveList } from "@clusterio/web_ui";
+import { ControlContext, useHostList } from "@clusterio/web_ui";
import info from "../../info";
import "../index.css";
import { Form, Input, Button, Select, InputNumber, Checkbox } from "antd";
+import messages from "../../messages";
const { Option } = Select;
const layout = {
@@ -20,12 +21,12 @@ function NewGridworldForm() {
let history = useHistory();
let control = useContext(ControlContext);
let [loading, setLoading] = useState();
- let [slaveList] = useSlaveList();
+ let [hostList] = useHostList();
async function onFinish(values) {
// console.log("Success:", values);
setLoading(true);
- await info.messages.createFactionGrid.send(control, values);
+ await control.send(new messages.CreateFactionGrid(values));
setLoading(false);
await new Promise(resolve => setTimeout(resolve, 1500));
history.push("/gridworld");
@@ -70,14 +71,14 @@ function NewGridworldForm() {
Migrate an instance to a different slave
+Migrate an instance to a different host
- The migration process will stop the instance for the duration of the transfer. Ensure the target slave has enabled - the same plugins as the source slave. + The migration process will stop the instance for the duration of the transfer. Ensure the target host has enabled + the same plugins as the source host.
-