diff --git a/client.js b/client.js index 91476886..5a2f64a7 100644 --- a/client.js +++ b/client.js @@ -11,6 +11,7 @@ const link = require("lib/link"); const plugin = require("lib/plugin"); const errors = require("lib/errors"); const prometheus = require('lib/prometheus'); +const luaTools = require('lib/luaTools'); /** @@ -175,7 +176,7 @@ class Instance extends link.Link{ module = Object.assign({ version: plugin.info.version, - dependencies: {}, + dependencies: { 'clusterio': '*' }, path: modulePath, load: [], require: [], @@ -203,7 +204,7 @@ class Instance extends link.Link{ module = Object.assign({ path: path.join('modules', entry.name), - dependencies: {}, + dependencies: { 'clusterio': '*' }, load: [], require: [], }, module); @@ -218,12 +219,22 @@ class Instance extends link.Link{ }); await this.server.start(saveName); + await this.server.disableAchievements() + await this.updateInstanceData(); for (let pluginInstance of this.plugins.values()) { await pluginInstance.onStart(); } } + /** + * Update instance information on the Factorio side + */ + async updateInstanceData() { + let name = luaTools.escapeString(this.config.name); + await this.server.sendRcon(`/sc clusterio_private.update_instance(${this.config.id}, "${name}")`, true); + } + /** * Stop the instance */ diff --git a/docs/developing-for-clusterio.md b/docs/developing-for-clusterio.md index 31aaafc5..6fee72e7 100644 --- a/docs/developing-for-clusterio.md +++ b/docs/developing-for-clusterio.md @@ -223,7 +223,8 @@ The following entries are supported in the module.json file: node-semver package for a full description of what operators are supported. The events for dependencies is invoked before the events of the dependent, and starting an instance will fail if the - dependencies cannot be satisfied. + dependencies cannot be satisfied. If not specified it will default + to depending on `clusterio`. - `require`: Lua files to require in `control.lua`. This should only really be needed if you want to make a global function available for use in diff --git a/lib/luaTools.js b/lib/luaTools.js new file mode 100644 index 00000000..8165beb5 --- /dev/null +++ b/lib/luaTools.js @@ -0,0 +1,17 @@ +/** + * Escapes a string for inclusion into a lua string + */ +function escapeString(content) { + return content + .replace(/\\/g, "\\\\") + .replace(/"/g, '\\"') + .replace(/'/g, "\\'") + .replace(/\0/g, "\\0") + .replace(/\n/g, "\\n") + .replace(/\r/g, "\\r") + ; +} + +module.exports = { + escapeString, +} diff --git a/modules/clusterio/api.lua b/modules/clusterio/api.lua new file mode 100644 index 00000000..47339457 --- /dev/null +++ b/modules/clusterio/api.lua @@ -0,0 +1,17 @@ +local api = {} + + +-- Table of events raised by clusterio +api.events = { + -- Raised after the name and id of an instance has been updated + -- This may occur even if the id and name didn't change. + + -- Event data: + -- instance_id: The id of the instance. + -- instance_name: the name of the instance. + on_instance_updated = script.generate_event_name(), +} + + +return api + diff --git a/modules/clusterio/impl.lua b/modules/clusterio/impl.lua new file mode 100644 index 00000000..2f97ffba --- /dev/null +++ b/modules/clusterio/impl.lua @@ -0,0 +1,52 @@ +local api = require('modules/clusterio/api') + + +local impl = {} + +local function init() + if not global.clusterio then + global.clusterio = { + instance_id = nil, + instance_name = nil, + } + end +end + +-- Internal API +clusterio_private = {} +function clusterio_private.update_instance(new_id, new_name) + init() + global.clusterio.instance_id = new_id + global.clusterio.instance_name = new_name + script.raise_event(api.events.on_instance_updated, { + instance_id = new_id, + instance_name = new_name, + }) +end + + +function impl.add_remote_interface() + remote.add_interface('clusterio_api', { + -- Returns a table of events raised by clusterio + get_events = function() + return api.events + end, + + -- Returns the instance id the game is run under + -- This may change over time and/or be nil. + get_instance_id = function() + init() + return global.clusterio.instance_id + end, + + -- Returns the name of the instance the game runs under. + -- This may change over time and/or be nil. + get_instance_name = function() + init() + return global.clusterio.instance_name + end, + }) +end + + +return impl diff --git a/modules/clusterio/module.json b/modules/clusterio/module.json new file mode 100644 index 00000000..5ba34a15 --- /dev/null +++ b/modules/clusterio/module.json @@ -0,0 +1,6 @@ +{ + "name": "clusterio", + "version": "0.0.0", + "dependencies": {}, + "load": ["impl.lua"] +} diff --git a/plugins/global_chat/instance.js b/plugins/global_chat/instance.js index 40661eac..e44ed210 100644 --- a/plugins/global_chat/instance.js +++ b/plugins/global_chat/instance.js @@ -1,4 +1,5 @@ const plugin = require("lib/plugin"); +const luaTools = require("lib/luaTools"); /** @@ -8,20 +9,6 @@ function removeTags(content) { return content.replace(/(\[gps=-?\d+,-?\d+\]|\[train=\d+\])/g, ""); } -/** - * Escapes a string for inclusion into a lua string - */ -function escapeLuaString(content) { - return content - .replace(/\\/g, "\\\\") - .replace(/"/g, '\\"') - .replace(/'/g, "\\'") - .replace(/\0/g, "\\0") - .replace(/\n/g, "\\n") - .replace(/\r/g, "\\r") - ; -} - class InstancePlugin extends plugin.BaseInstancePlugin { constructor(...args) { super(...args); @@ -34,7 +21,7 @@ class InstancePlugin extends plugin.BaseInstancePlugin { async chatEventHandler(message) { // TODO check if cross server chat is enabled let content = `[${message.data.instance_name}] ${removeTags(message.data.content)}`; - await this.instance.server.sendRcon(`/sc game.print('${escapeLuaString(content)}')`, true); + await this.instance.server.sendRcon(`/sc game.print('${luaTools.escapeString(content)}')`, true); } async onOutput(output) { @@ -54,5 +41,4 @@ module.exports = { // For testing only _removeTags: removeTags, - _escapeLuaString: escapeLuaString, } diff --git a/plugins/global_chat/test/plugin.js b/plugins/global_chat/test/plugin.js index 0e1d3de0..28590068 100644 --- a/plugins/global_chat/test/plugin.js +++ b/plugins/global_chat/test/plugin.js @@ -19,30 +19,6 @@ describe("global_chat plugin", function() { }); }); - describe("escapeLuaSrting", function() { - it("should escape backslashes", function() { - assert.equal(instance._escapeLuaString("\\a"), "\\\\a"); - }); - it("should escape double quotes", function() { - assert.equal(instance._escapeLuaString('"a"'), '\\"a\\"'); - }); - it("should escape single quotes", function() { - assert.equal(instance._escapeLuaString("'a'"), "\\'a\\'"); - }); - it("should escape nul bytes", function() { - assert.equal(instance._escapeLuaString("a\0b"), "a\\0b"); - }); - it("should escape newlines", function() { - assert.equal(instance._escapeLuaString("a\nb"), "a\\nb"); - }); - it("should escape carriage return", function() { - assert.equal(instance._escapeLuaString("a\rb"), "a\\rb"); - }); - it("should escape all combined", function() { - assert.equal(instance._escapeLuaString("a\\b\"c'd\0e\nf\rg"), "a\\\\b\\\"c\\'d\\0e\\nf\\rg"); - }); - }); - describe("class InstancePlugin", function() { let instancePlugin; diff --git a/test/lib/luaTools.js b/test/lib/luaTools.js new file mode 100644 index 00000000..c1dd8d36 --- /dev/null +++ b/test/lib/luaTools.js @@ -0,0 +1,30 @@ +const assert = require('assert').strict; + +const luaTools = require('lib/luaTools'); + + +describe("lib/luaTools", function() { + describe("escapeString()", function() { + it("should escape backslashes", function() { + assert.equal(luaTools.escapeString("\\a"), "\\\\a"); + }); + it("should escape double quotes", function() { + assert.equal(luaTools.escapeString('"a"'), '\\"a\\"'); + }); + it("should escape single quotes", function() { + assert.equal(luaTools.escapeString("'a'"), "\\'a\\'"); + }); + it("should escape nul bytes", function() { + assert.equal(luaTools.escapeString("a\0b"), "a\\0b"); + }); + it("should escape newlines", function() { + assert.equal(luaTools.escapeString("a\nb"), "a\\nb"); + }); + it("should escape carriage return", function() { + assert.equal(luaTools.escapeString("a\rb"), "a\\rb"); + }); + it("should escape all combined", function() { + assert.equal(luaTools.escapeString("a\\b\"c'd\0e\nf\rg"), "a\\\\b\\\"c\\'d\\0e\\nf\\rg"); + }); + }); +});