mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 15:04:52 +09:00
Port globalChat to new plugin system
Port the globalChat plugin to the new plugin system. Since there's no config system yet the config options for it is removed.
This commit is contained in:
1 parent
bcceae687f
commit
b71c392b32
10 files changed
+199
-70
No files matched your search
@@ -50,7 +50,6 @@ sharedPlugins/*
|
||||
!sharedPlugins/inventoryImports/
|
||||
!sharedPlugins/UPSdisplay/
|
||||
!sharedPlugins/researchSync/
|
||||
!sharedPlugins/globalChat/
|
||||
!sharedPlugins/clusterioMod/
|
||||
!sharedPlugins/statisticsExporter/
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ Version 2.0.0
|
||||
- Removed oddball limits to slaves.json size.
|
||||
- Moved slave specific configuration into its own configuration file.
|
||||
- Removed unused binary option from plugin config.
|
||||
- Removed info and shout command from globalChat plugin
|
||||
- Removed mirrorAllChat and enableCrossServerShout configuration options for
|
||||
globalChat plugin.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
|
||||
@@ -40,8 +40,6 @@
|
||||
"useNeuralNetDoleDivider": true,
|
||||
"msBetweenCommands": 10,
|
||||
"allowRemoteCommandExecution": true,
|
||||
"enableCrossServerShout": true,
|
||||
"mirrorAllChat": false,
|
||||
"__comment7": "Autosave interval for items in the master storage in milliseconds. Defaults to one minute when set to 0 or not set.",
|
||||
"autosaveInterval": 600000,
|
||||
"__comment8": "This setting only affects the master. It makes every import for things that arent 'electricity' return a maximum of 0. Effectively disables teleport chests.",
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
let link = require("lib/link");
|
||||
let plugin = require("lib/plugin");
|
||||
|
||||
module.exports = {
|
||||
name: "global_chat",
|
||||
title: "Global Chat",
|
||||
description: "Forwards chat between instances.",
|
||||
version: "2.0.0-alpha",
|
||||
instanceEntrypoint: "instance",
|
||||
|
||||
messages: {
|
||||
chat: new link.Event({
|
||||
type: 'global_chat:chat',
|
||||
links: ['instance-slave', 'slave-master', 'master-slave', 'slave-instance'],
|
||||
forwardTo: 'master',
|
||||
broadcastTo: 'instance',
|
||||
eventProperties: {
|
||||
"instance_name": { type: "string" },
|
||||
"content": { type: "string" },
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
const plugin = require("lib/plugin");
|
||||
|
||||
|
||||
/**
|
||||
* Removes gps and train tags from messags
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
async init() {
|
||||
// XXX Nothing?
|
||||
}
|
||||
|
||||
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)}')`);
|
||||
}
|
||||
|
||||
async onOutput(output) {
|
||||
if (output.type === "action" && output.action === "CHAT") {
|
||||
this.info.messages.chat.send(this.instance, {
|
||||
instance_name: this.instance.name,
|
||||
content: output.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO implement info command in lua?
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
InstancePlugin,
|
||||
|
||||
// For testing only
|
||||
_removeTags: removeTags,
|
||||
_escapeLuaString: escapeLuaString,
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
const assert = require('assert').strict;
|
||||
|
||||
const mock = require('../../../test/mock');
|
||||
const lines = require('../../../test/lib/factorio/lines');
|
||||
const instance = require('../instance');
|
||||
const info = require('../info');
|
||||
|
||||
|
||||
describe("global_chat plugin", function() {
|
||||
describe("removeTags()", function() {
|
||||
it("should pass through an ordinary string", function() {
|
||||
assert.equal(instance._removeTags("string"), "string");
|
||||
});
|
||||
it("should strip out gps tag", function() {
|
||||
assert.equal(instance._removeTags("Look at [gps=12,-4]"), "Look at ");
|
||||
});
|
||||
it("should strip out train tag", function() {
|
||||
assert.equal(instance._removeTags("Train [train=1235]"), "Train ");
|
||||
});
|
||||
});
|
||||
|
||||
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;
|
||||
|
||||
before(async function() {
|
||||
instancePlugin = new instance.InstancePlugin(info, new mock.MockInstance());
|
||||
await instancePlugin.init();
|
||||
});
|
||||
|
||||
describe(".chatEventHandler()", function() {
|
||||
it("should send received chat as command", async function() {
|
||||
instancePlugin.instance.server.rconCommands = [];
|
||||
await instancePlugin.chatEventHandler({ data: { instance_name: "test", content: "User: message" } });
|
||||
assert.deepEqual(
|
||||
instancePlugin.instance.server.rconCommands,
|
||||
["/sc game.print('[test] User: message')"],
|
||||
);
|
||||
});
|
||||
});
|
||||
describe(".onOutput()", function() {
|
||||
it("should forward chat", async function() {
|
||||
let count = 0;
|
||||
for (let [_, output] of lines.testLines) {
|
||||
if (output.type === "action" && output.action === "CHAT") {
|
||||
instancePlugin.instance.connector.sentMessages = [];
|
||||
await instancePlugin.onOutput(output);
|
||||
assert(instancePlugin.instance.connector.sentMessages.length, "message was not sent");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
assert(count > 0, "no lines were tested");
|
||||
});
|
||||
it("should ignore regular output", async function() {
|
||||
let count = 0;
|
||||
for (let [_, output] of lines.testLines) {
|
||||
if (output.type !== "action" || output.action !== "CHAT") {
|
||||
instancePlugin.instance.connector.sentMessages = [];
|
||||
await instancePlugin.onOutput(output);
|
||||
assert(!instancePlugin.instance.connector.sentMessages.length, "message was sent");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
assert(count > 0, "no lines were tested");
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
@@ -1,9 +0,0 @@
|
||||
/*
|
||||
Clusterio plugin to allow for chat between instances.
|
||||
*/
|
||||
module.exports = {
|
||||
// Name of package. For display somewhere I guess.
|
||||
name: "globalChat",
|
||||
version: "1.0.0",
|
||||
description: "Clusterio plugin to allow for chat between instances.",
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
module.exports = class remoteCommands {
|
||||
constructor(mergedConfig, messageInterface, extras){
|
||||
this.messageInterface = messageInterface;
|
||||
this.config = mergedConfig;
|
||||
this.socket = extras.socket;
|
||||
this.instances = {};
|
||||
|
||||
this.socket.emit("registerChatReciever");
|
||||
|
||||
this.socket.on("gameChat", async data => {
|
||||
if(data.instanceID && data.instanceID != this.config.unique.toString()){
|
||||
if(data.data.includes("[CHAT]")
|
||||
// if this isn't used as an info command or something (reduce spam)
|
||||
&& !data.data.includes("!info")
|
||||
// check if we are allowed to cross chat at all, default to true
|
||||
&& (mergedConfig.enableCrossServerShout == undefined || mergedConfig.enableCrossServerShout)
|
||||
// check if we are supposed to relay this message
|
||||
&& (mergedConfig.mirrorAllChat || data.data.toLowerCase().includes("/shout") || data.data.toLowerCase().includes("!shout"))){
|
||||
let words = data.data.trim().split(" ");
|
||||
words.shift();
|
||||
words.shift();
|
||||
words.shift();
|
||||
let message = words.join(" ").replace(/[";]/g, " ").replace(/[']/g,"").replace("/shout ", "").replace("!shout ","").replace(/\[gps=.*?\]/g, "").replace(/\[train=.*?\]/g, "");
|
||||
|
||||
if(data.data.includes("[gps=")){
|
||||
//Nothing
|
||||
}else{
|
||||
this.messageInterface("/silent-command game.print('[" + data.instanceName + "] " + message + "')");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
async factorioOutput(data){
|
||||
try{
|
||||
this.socket.emit("gameChat", {
|
||||
instanceID: this.config.unique.toString(),
|
||||
instanceName: this.config.name,
|
||||
data,
|
||||
});
|
||||
if(data.includes("[CHAT]") && data.includes("!info")){
|
||||
let infoMessage = [
|
||||
"=== Server info ===",
|
||||
"Name: "+await this.getInstanceName(this.config.unique)+" ("+this.config.unique+")",
|
||||
];
|
||||
infoMessage.forEach((line, i) => {
|
||||
setTimeout(()=>this.messageInterface("/silent-command game.print('"+line+"')"),i*200);
|
||||
});
|
||||
}
|
||||
}catch(e){console.log(e)}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// These are libraries that does not have any units test, they are
|
||||
// required here in order to track coverage for them.
|
||||
|
||||
require('../index');
|
||||
+24
-2
@@ -1,5 +1,7 @@
|
||||
const events = require("events");
|
||||
|
||||
const link = require("lib/link");
|
||||
|
||||
|
||||
class MockSocket {
|
||||
constructor() {
|
||||
@@ -23,7 +25,7 @@ class MockSocket {
|
||||
close() {
|
||||
this.closeCalled = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class MockConnector extends events.EventEmitter {
|
||||
constructor() {
|
||||
@@ -50,9 +52,29 @@ class MockConnector extends events.EventEmitter {
|
||||
disconnect() {
|
||||
this.disconnectCalled = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class MockServer {
|
||||
constructor() {
|
||||
this.rconCommands = [];
|
||||
}
|
||||
|
||||
async sendRcon(command) {
|
||||
this.rconCommands.push(command);
|
||||
}
|
||||
}
|
||||
|
||||
class MockInstance extends link.Link {
|
||||
constructor() {
|
||||
super('instance', 'slave', new MockConnector());
|
||||
this.server = new MockServer();
|
||||
this.name = "test";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
MockSocket,
|
||||
MockConnector,
|
||||
MockInstance,
|
||||
};
|
||||
Reference in new issue
Block a user