From aa59cd1992d52337cce57d3d89e39e5ee29285d0 Mon Sep 17 00:00:00 2001 From: Columbus Labs Date: Sun, 9 Aug 2026 16:35:13 -0400 Subject: [PATCH] fix: filter server-specific chat tags (#970) Co-authored-by: ColumbusLabs <287001685+ColumbusLabs@users.noreply.github.com> --- CHANGELOG.md | 1 + plugins/global_chat/instance.ts | 4 ++-- plugins/global_chat/test/plugin.js | 22 +++++++++++++++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ffa8b0b..14d7b789 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ Many thanks to the following for contributing to this release: ### Changes +- Global chat now filters server-specific GPS, blueprint, train, and train-stop rich-text tags before relaying messages between instances. [#593]() - Reworked the site layout into a fixed sidebar with a top bar. [#924]() - The builtin "recycler" mod is now included correctly as builtin. [#925]() - Mod `info.json` versions (a mod's version and its `factorio_version`) are now parsed leniently, matching how the game reads them, instead of being validated against a fixed list of Factorio versions. [#941]() diff --git a/plugins/global_chat/instance.ts b/plugins/global_chat/instance.ts index 2cfb2c6e..2a3fa4e6 100644 --- a/plugins/global_chat/instance.ts +++ b/plugins/global_chat/instance.ts @@ -3,13 +3,13 @@ import { BaseInstancePlugin } from "@clusterio/host"; import { ChatEvent } from "./messages"; /** - * Removes gps and train tags from messags + * Removes server-specific tags from messages. * * @param content - string to strip tags from. * @returns stripped string. */ function removeTags(content: string): string { - return content.replace(/(\[gps=-?\d+,-?\d+\]|\[train=\d+\])/g, ""); + return content.replace(/\[(?:gps|special-item|train|train-stop)=\S*?\]/gm, ""); } export class InstancePlugin extends BaseInstancePlugin { diff --git a/plugins/global_chat/test/plugin.js b/plugins/global_chat/test/plugin.js index 0d22c5e8..6436dc16 100644 --- a/plugins/global_chat/test/plugin.js +++ b/plugins/global_chat/test/plugin.js @@ -15,11 +15,23 @@ describe("global_chat plugin", 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 "); + assert.equal(instance._removeTags("Look at [gps=12,-4,nauvis]"), "Look at "); + }); + it("should strip out special item tag", function() { + assert.equal(instance._removeTags("Blueprint [special-item=0eNqV...]"), "Blueprint "); }); it("should strip out train tag", function() { assert.equal(instance._removeTags("Train [train=1235]"), "Train "); }); + it("should strip out train stop tag", function() { + assert.equal(instance._removeTags("Stop [train-stop=42]"), "Stop "); + }); + it("should preserve portable rich text tags", function() { + assert.equal( + instance._removeTags("[gps=12,-4][img=item.iron-plate] [item=iron-plate]"), + "[img=item.iron-plate] [item=iron-plate]", + ); + }); }); describe("class InstancePlugin", function() { @@ -39,6 +51,14 @@ describe("global_chat plugin", function() { ["/sc game.print('[test] User: message')"], ); }); + it("should filter server-specific tags from received chat", async function() { + instancePlugin.instance.server.rconCommands = []; + await instancePlugin.handleChatEvent(new ChatEvent("test", "Train [train=1235]")); + assert.deepEqual( + instancePlugin.instance.server.rconCommands, + ["/sc game.print('[test] Train ')"], + ); + }); }); describe(".onOutput()", function() { it("should forward chat", async function() {