├── exp_gui ├── web │ └── index.tsx ├── module │ ├── module_exports.lua │ ├── module.json │ ├── styles.lua │ └── locale │ │ ├── zh-CN.cfg │ │ ├── zh-TW.cfg │ │ └── en.cfg ├── docs │ └── toolbox.png ├── tsconfig.browser.json ├── tsconfig.node.json ├── tsconfig.json ├── index.ts ├── instance.ts ├── webpack.config.js └── package.json ├── exp_util ├── web │ └── index.tsx ├── module │ ├── locale │ │ ├── en.cfg │ │ ├── zh-CN.cfg │ │ └── zh-TW.cfg │ ├── module.json │ └── include │ │ ├── require.lua │ │ ├── package.lua │ │ ├── math.lua │ │ └── flow_precision.lua ├── tsconfig.browser.json ├── tsconfig.node.json ├── tsconfig.json ├── instance.ts ├── index.ts ├── webpack.config.js └── package.json ├── exp_commands ├── web │ └── index.tsx ├── tsconfig.browser.json ├── tsconfig.node.json ├── tsconfig.json ├── index.ts ├── instance.ts ├── module │ ├── module.json │ ├── commands │ │ ├── sudo.lua │ │ └── ipc.lua │ └── locale │ │ ├── zh-CN.cfg │ │ ├── zh-TW.cfg │ │ └── en.cfg ├── webpack.config.js └── package.json ├── exp_legacy ├── web │ └── index.tsx ├── module │ ├── modules │ │ ├── gui │ │ │ ├── logo.png │ │ │ ├── _role_updates.lua │ │ │ └── debug │ │ │ │ └── model.lua │ │ ├── data │ │ │ ├── language.lua │ │ │ ├── alt-view.lua │ │ │ ├── toolbar.lua │ │ │ ├── greetings.lua │ │ │ ├── quickbar.lua │ │ │ ├── player-colours.lua │ │ │ ├── tag.lua │ │ │ └── personal-logistic.lua │ │ └── graftorio │ │ │ ├── statics.lua │ │ │ ├── require.lua │ │ │ └── general.lua │ ├── config │ │ ├── lawnmower.lua │ │ ├── graftorio.lua │ │ ├── station_auto_name.lua │ │ ├── miner.lua │ │ ├── inventory_clear.lua │ │ ├── pollution_grading.lua │ │ ├── join_messages.lua │ │ ├── deconlog.lua │ │ ├── discord_alerts.lua │ │ ├── popup_messages.lua │ │ ├── gui │ │ │ ├── tasks.lua │ │ │ ├── science.lua │ │ │ └── rockets.lua │ │ ├── compilatron.lua │ │ ├── preset_player_quickbar.lua │ │ ├── repair.lua │ │ ├── afk_kick.lua │ │ ├── death_logger.lua │ │ ├── nukeprotect.lua │ │ ├── logging.lua │ │ ├── _file_loader.lua │ │ ├── protection.lua │ │ ├── preset_player_colours.lua │ │ ├── warnings.lua │ │ ├── module.lua │ │ └── statistics.lua │ ├── module.json │ ├── module_exports.lua │ ├── locale │ │ ├── zh-CN │ │ │ ├── expcore.cfg │ │ │ ├── addons.cfg │ │ │ └── data.cfg │ │ ├── zh-TW │ │ │ ├── expcore.cfg │ │ │ ├── addons.cfg │ │ │ └── data.cfg │ │ └── en │ │ │ ├── expcore.cfg │ │ │ └── addons.cfg │ ├── control.lua │ └── utils │ │ └── event.lua ├── tsconfig.node.json ├── tsconfig.browser.json ├── tsconfig.json ├── index.ts ├── instance.ts ├── webpack.config.js └── package.json ├── exp_server_ups ├── web │ └── index.tsx ├── module │ ├── locale │ │ ├── zh-CN.cfg │ │ ├── zh-TW.cfg │ │ └── en.cfg │ ├── module_exports.lua │ └── module.json ├── tsconfig.node.json ├── tsconfig.browser.json ├── tsconfig.json ├── webpack.config.js ├── index.ts ├── package.json └── instance.ts ├── .npmrc ├── .gitignore ├── .npmignore ├── exp_scenario ├── .gitignore ├── .npmignore ├── tsconfig.node.json ├── tsconfig.browser.json ├── tsconfig.json ├── controller.ts ├── instance.ts ├── module │ ├── module.json │ ├── commands │ │ ├── debug.lua │ │ ├── _rcon.lua │ │ ├── me.lua │ │ ├── vlayer.lua │ │ ├── admin_chat.lua │ │ ├── clear_inventory.lua │ │ ├── _authorities.lua │ │ ├── spectate.lua │ │ ├── enemy.lua │ │ ├── bot_queue.lua │ │ ├── trains.lua │ │ ├── kill.lua │ │ ├── locate.lua │ │ ├── jail.lua │ │ ├── ratio.lua │ │ ├── lawnmower.lua │ │ ├── repair.lua │ │ ├── rainbow.lua │ │ ├── roles.lua │ │ └── research.lua │ └── control │ │ ├── pollution_grading.lua │ │ ├── inventory_clear.lua │ │ ├── inserter_pickup.lua │ │ ├── bonus.lua │ │ ├── report_jail.lua │ │ ├── chat_popup.lua │ │ ├── protection_jail.lua │ │ ├── research.lua │ │ ├── damage_popups.lua │ │ ├── nuke_protection.lua │ │ ├── chat_auto_reply.lua │ │ ├── custom_start.lua │ │ ├── afk_kick.lua │ │ └── extra_logging.lua ├── index.ts ├── webpack.config.js ├── package.json ├── web │ └── index.tsx └── messages.ts ├── exp_groups ├── tsconfig.node.json ├── tsconfig.json ├── tsconfig.browser.json ├── module │ └── module.json ├── webpack.config.js ├── package.json ├── index.ts └── web │ ├── index.tsx │ └── components │ └── groupTree.tsx ├── package.json ├── tsconfig.base.json ├── tsconfig.node.json ├── tsconfig.json ├── tsconfig.browser.json ├── pnpm-workspace.yaml ├── .github ├── ISSUE_TEMPLATE │ ├── FeatureRequest.md │ ├── DesyncReport.md │ ├── CrashReport.md │ └── BugReport.md └── workflows │ └── fmtk.yml ├── CONTRIBUTING.md ├── LICENSE └── type.patch.lua /exp_gui/web/index.tsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /exp_util/web/index.tsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /exp_commands/web/index.tsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /exp_legacy/web/index.tsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /exp_server_ups/web/index.tsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers=false 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | .vscode 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | webpack.config.js 2 | dist/web/build 3 | dist/browser 4 | -------------------------------------------------------------------------------- /exp_scenario/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /exp_gui/module/module_exports.lua: -------------------------------------------------------------------------------- 1 | return require("modules/exp_gui/control") 2 | -------------------------------------------------------------------------------- /exp_scenario/.npmignore: -------------------------------------------------------------------------------- 1 | webpack.config.js 2 | dist/web/build 3 | dist/browser 4 | -------------------------------------------------------------------------------- /exp_server_ups/module/locale/zh-CN.cfg: -------------------------------------------------------------------------------- 1 | [exp_server-ups] 2 | description=啟動 UPS 顯示 -------------------------------------------------------------------------------- /exp_server_ups/module/locale/zh-TW.cfg: -------------------------------------------------------------------------------- 1 | [exp_server-ups] 2 | description=啟動 UPS 顯示 -------------------------------------------------------------------------------- /exp_server_ups/module/locale/en.cfg: -------------------------------------------------------------------------------- 1 | [exp_server-ups] 2 | description=Toggle the server UPS display. -------------------------------------------------------------------------------- /exp_gui/docs/toolbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/explosivegaming/ExpCluster/HEAD/exp_gui/docs/toolbox.png -------------------------------------------------------------------------------- /exp_util/module/locale/en.cfg: -------------------------------------------------------------------------------- 1 | time-symbol-days-short=__1__d 2 | rich-text-color-tag=[color=__1__,__2__,__3__]__4__[/color] -------------------------------------------------------------------------------- /exp_util/module/locale/zh-CN.cfg: -------------------------------------------------------------------------------- 1 | time-symbol-days-short=__1__日 2 | rich-text-color-tag=[color=__1__,__2__,__3__]__4__[/color] 3 | -------------------------------------------------------------------------------- /exp_util/module/locale/zh-TW.cfg: -------------------------------------------------------------------------------- 1 | time-symbol-days-short=__1__日 2 | rich-text-color-tag=[color=__1__,__2__,__3__]__4__[/color] 3 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/gui/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/explosivegaming/ExpCluster/HEAD/exp_legacy/module/modules/gui/logo.png -------------------------------------------------------------------------------- /exp_groups/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.node.json", 3 | "include": ["./**/*.ts"], 4 | "exclude": ["test/*", "./dist/*"], 5 | } 6 | -------------------------------------------------------------------------------- /exp_gui/tsconfig.browser.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.browser.json", 3 | "include": [ "web/**/*.tsx", "web/**/*.ts", "package.json" ], 4 | } 5 | -------------------------------------------------------------------------------- /exp_gui/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.node.json", 3 | "include": ["./**/*.ts"], 4 | "exclude": ["test/*", "./dist/*"], 5 | } 6 | -------------------------------------------------------------------------------- /exp_legacy/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.node.json", 3 | "include": ["./**/*.ts"], 4 | "exclude": ["test/*", "./dist/*"], 5 | } 6 | -------------------------------------------------------------------------------- /exp_util/tsconfig.browser.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.browser.json", 3 | "include": [ "web/**/*.tsx", "web/**/*.ts", "package.json" ], 4 | } 5 | -------------------------------------------------------------------------------- /exp_util/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.node.json", 3 | "include": ["./**/*.ts"], 4 | "exclude": ["test/*", "./dist/*"], 5 | } 6 | -------------------------------------------------------------------------------- /exp_commands/tsconfig.browser.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.browser.json", 3 | "include": [ "web/**/*.tsx", "web/**/*.ts", "package.json" ], 4 | } 5 | -------------------------------------------------------------------------------- /exp_commands/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.node.json", 3 | "include": ["./**/*.ts"], 4 | "exclude": ["test/*", "./dist/*"], 5 | } 6 | -------------------------------------------------------------------------------- /exp_legacy/module/config/lawnmower.lua: -------------------------------------------------------------------------------- 1 | --- Settings for lawnmower 2 | -- @config lawnmower 3 | 4 | return { 5 | destroy_decoratives = false, 6 | } 7 | -------------------------------------------------------------------------------- /exp_legacy/tsconfig.browser.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.browser.json", 3 | "include": [ "web/**/*.tsx", "web/**/*.ts", "package.json" ], 4 | } 5 | -------------------------------------------------------------------------------- /exp_scenario/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.node.json", 3 | "include": ["./**/*.ts"], 4 | "exclude": ["test/*", "./dist/*"], 5 | } 6 | -------------------------------------------------------------------------------- /exp_server_ups/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.node.json", 3 | "include": ["./**/*.ts"], 4 | "exclude": ["test/*", "./dist/*"], 5 | } 6 | -------------------------------------------------------------------------------- /exp_server_ups/tsconfig.browser.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.browser.json", 3 | "include": [ "web/**/*.tsx", "web/**/*.ts", "package.json" ], 4 | } 5 | -------------------------------------------------------------------------------- /exp_groups/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.browser.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /exp_gui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.node.json" }, 5 | { "path": "./tsconfig.browser.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /exp_legacy/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.node.json" }, 5 | { "path": "./tsconfig.browser.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /exp_util/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.node.json" }, 5 | { "path": "./tsconfig.browser.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /exp_commands/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.node.json" }, 5 | { "path": "./tsconfig.browser.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /exp_groups/tsconfig.browser.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.browser.json", 3 | "include": [ "web/**/*.tsx", "web/**/*.ts", "messages.ts", "package.json" ], 4 | } 5 | -------------------------------------------------------------------------------- /exp_scenario/tsconfig.browser.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.browser.json", 3 | "include": [ "web/**/*.tsx", "web/**/*.ts", "messages.ts", "package.json" ], 4 | } 5 | -------------------------------------------------------------------------------- /exp_scenario/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.browser.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /exp_server_ups/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.node.json" }, 5 | { "path": "./tsconfig.browser.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /exp_legacy/module/config/graftorio.lua: -------------------------------------------------------------------------------- 1 | return { 2 | modules = { 3 | ["forcestats"] = true, 4 | ["logistorage"] = false, 5 | ["other"] = true, 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /exp_server_ups/module/module_exports.lua: -------------------------------------------------------------------------------- 1 | 2 | -- Access the exports from other modules using require("modules/exp_server_ups") 3 | return require("modules/exp_server_ups/control").elements.server_ups 4 | -------------------------------------------------------------------------------- /exp_groups/module/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exp_groups", 3 | "load": [ 4 | "control.lua" 5 | ], 6 | "require": [ 7 | ], 8 | "dependencies": { 9 | "clusterio": "*", 10 | "exp_util": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /exp_legacy/module/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exp_legacy", 3 | "load": [ 4 | "control.lua" 5 | ], 6 | "require": [ 7 | ], 8 | "dependencies": { 9 | "clusterio": "*", 10 | "exp_util": "*", 11 | "exp_gui": "*" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /exp_scenario/controller.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | import { BaseControllerPlugin, InstanceInfo } from "@clusterio/controller"; 3 | 4 | export class ControllerPlugin extends BaseControllerPlugin { 5 | async init() { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "files": [], 5 | "scripts": { 6 | "build": "tsc --build", 7 | "watch": "tsc --build --watch" 8 | }, 9 | "devDependencies": { 10 | "typescript": "catalog:" 11 | } 12 | } -------------------------------------------------------------------------------- /exp_scenario/instance.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | import { BaseInstancePlugin } from "@clusterio/host"; 3 | 4 | export class InstancePlugin extends BaseInstancePlugin { 5 | async init() { 6 | } 7 | 8 | async onStart() { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /exp_legacy/module/config/station_auto_name.lua: -------------------------------------------------------------------------------- 1 | return { 2 | --[[ 3 | __icon__ 4 | __item_name__ 5 | __backer_name__ 6 | __direction__ 7 | __x__ 8 | __y__ 9 | ]] 10 | station_name = "[L] __icon__", 11 | } 12 | -------------------------------------------------------------------------------- /exp_scenario/module/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exp_scenario", 3 | "load": [ 4 | ], 5 | "require": [ 6 | "control.lua" 7 | ], 8 | "dependencies": { 9 | "clusterio": "*", 10 | "exp_util": "*", 11 | "exp_gui": "*", 12 | "exp_commands": "*" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /exp_gui/index.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | 3 | export const plugin: lib.PluginDeclaration = { 4 | name: "exp_gui", 5 | title: "exp_gui", 6 | description: "Example Description. Plugin. Change me in index.ts", 7 | instanceEntrypoint: "./dist/node/instance", 8 | }; 9 | -------------------------------------------------------------------------------- /exp_legacy/module/module_exports.lua: -------------------------------------------------------------------------------- 1 | --- Can contain anything you want to allow other plugins to have access to, this example exposes the control file 2 | -- Access the exports from other modules using require("modules/exp_legacy") 3 | return require("modules/exp_legacy/control") 4 | -------------------------------------------------------------------------------- /exp_server_ups/module/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exp_server_ups", 3 | "load": [ 4 | "control.lua" 5 | ], 6 | "require": [ 7 | ], 8 | "dependencies": { 9 | "clusterio": "*", 10 | "exp_commands": "*", 11 | "exp_util": "*", 12 | "exp_gui": "*" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /exp_legacy/index.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | 3 | export const plugin: lib.PluginDeclaration = { 4 | name: "exp_legacy", 5 | title: "exp_legacy", 6 | description: "Example Description. Plugin. Change me in index.ts", 7 | instanceEntrypoint: "./dist/node/instance", 8 | }; 9 | -------------------------------------------------------------------------------- /exp_commands/index.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | 3 | export const plugin: lib.PluginDeclaration = { 4 | name: "exp_commands", 5 | title: "exp_commands", 6 | description: "Example Description. Plugin. Change me in index.ts", 7 | instanceEntrypoint: "./dist/node/instance", 8 | }; 9 | -------------------------------------------------------------------------------- /exp_legacy/module/config/miner.lua: -------------------------------------------------------------------------------- 1 | --- Settings for miner 2 | -- @config miner 3 | 4 | return { 5 | fluid = true, --- @setting fluid When true, checks for for fluid pipes when removing miners 6 | chest = true, --- @setting chest When true, checks for for chest when removing miners 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "declaration": true, 5 | "declarationMap": true, 6 | "incremental": true, 7 | "sourceMap": true, 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "resolveJsonModule": true, 11 | "skipLibCheck": true, 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "lib": ["es2023"], 5 | "module": "node16", 6 | "moduleResolution": "node16", 7 | "target": "es2022", 8 | "forceConsistentCasingInFileNames": true, 9 | "outDir": "${configDir}/dist/node", 10 | }, 11 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./exp_commands/" }, 5 | { "path": "./exp_groups/" }, 6 | { "path": "./exp_gui/" }, 7 | { "path": "./exp_legacy/" }, 8 | { "path": "./exp_scenario/" }, 9 | { "path": "./exp_server_ups/" }, 10 | { "path": "./exp_util/" }, 11 | ], 12 | } 13 | -------------------------------------------------------------------------------- /exp_gui/module/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exp_gui", 3 | "load": [ 4 | "data.lua", 5 | "iter.lua", 6 | "prototype.lua", 7 | "control.lua" 8 | ], 9 | "require": [ 10 | "elements.lua", 11 | "styles.lua", 12 | "toolbar.lua" 13 | ], 14 | "dependencies": { 15 | "clusterio": "*", 16 | "exp_util": "*" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.browser.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "lib": ["dom", "es2023"], 5 | "module": "es2022", 6 | "moduleResolution": "bundler", 7 | "target": "es2022", 8 | "jsx": "react-jsx", 9 | "noEmitOnError": true, 10 | "outDir": "${configDir}/dist/browser", 11 | }, 12 | } -------------------------------------------------------------------------------- /exp_gui/instance.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | import { BaseInstancePlugin } from "@clusterio/host"; 3 | 4 | export class InstancePlugin extends BaseInstancePlugin { 5 | // This class is empty because an instance plugin must be defined for a module to be injected 6 | // This requirement may change in the future to allow for standalone modules 7 | } 8 | -------------------------------------------------------------------------------- /exp_legacy/module/config/inventory_clear.lua: -------------------------------------------------------------------------------- 1 | --- Config to control when players items are removed, this is a list of event names that will trigger inventory clear 2 | -- @config inventory_clear 3 | 4 | local events = defines.events 5 | return { 6 | events.on_player_banned, 7 | events.on_player_kicked, 8 | -- events.on_player_left_game 9 | } 10 | -------------------------------------------------------------------------------- /exp_util/module/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exp_util", 3 | "load": [ 4 | "include/package.lua", 5 | "include/require.lua", 6 | "storage.lua", 7 | "selection.lua", 8 | "async.lua" 9 | ], 10 | "require": [ 11 | "include/math.lua", 12 | "include/table.lua" 13 | ], 14 | "dependencies": { 15 | "clusterio": "*" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /exp_commands/instance.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | import { BaseInstancePlugin } from "@clusterio/host"; 3 | 4 | export class InstancePlugin extends BaseInstancePlugin { 5 | // This class is empty because an instance plugin must be defined for a module to be injected 6 | // This requirement may change in the future to allow for standalone modules 7 | } 8 | -------------------------------------------------------------------------------- /exp_legacy/instance.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | import { BaseInstancePlugin } from "@clusterio/host"; 3 | 4 | export class InstancePlugin extends BaseInstancePlugin { 5 | // This class is empty because an instance plugin must be defined for a module to be injected 6 | // This requirement may change in the future to allow for standalone modules 7 | } 8 | -------------------------------------------------------------------------------- /exp_util/instance.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | import { BaseInstancePlugin } from "@clusterio/host"; 3 | 4 | export class InstancePlugin extends BaseInstancePlugin { 5 | // This class is empty because an instance plugin must be defined for a module to be injected 6 | // This requirement may change in the future to allow for standalone modules 7 | } 8 | -------------------------------------------------------------------------------- /exp_util/index.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | 3 | export const plugin: lib.PluginDeclaration = { 4 | name: "exp_util", 5 | title: "ExpGaming Module Utilities", 6 | description: "Provides extensions and overrides of base Lua library functions, and provides utility modules for improved module compatibly", 7 | instanceEntrypoint: "./dist/node/instance", 8 | }; 9 | -------------------------------------------------------------------------------- /exp_gui/module/styles.lua: -------------------------------------------------------------------------------- 1 | --- @class Gui 2 | local Gui = require("modules/exp_gui") 3 | 4 | --- @class Gui.styles 5 | local styles = {} 6 | Gui.styles = styles 7 | 8 | function styles.sprite(style) 9 | style = style or {} 10 | if not style.padding then 11 | style.padding = -2 12 | end 13 | return style 14 | end 15 | 16 | return styles 17 | -------------------------------------------------------------------------------- /exp_gui/module/locale/zh-CN.cfg: -------------------------------------------------------------------------------- 1 | [exp-gui] 2 | clear-left-flow=收起所有打開的介面。 3 | close-toolbar=__CONTROL_LEFT_CLICK__: 按鍵設定\n__CONTROL_RIGHT_CLICK__: 關閉工具列 4 | open-toolbar=__CONTROL_LEFT_CLICK__: 按鍵設定\n__CONTROL_RIGHT_CLICK__: 開啟工具列 5 | 6 | [exp-gui_toolbar-settings] 7 | main-caption=工具列 8 | main-tooltip=工具列設定\n使用核取方塊來設定喜愛項目 9 | reset=重置全部 10 | toggle=切換喜愛項目 11 | move-up=上移 12 | move-down=下移 13 | -------------------------------------------------------------------------------- /exp_gui/module/locale/zh-TW.cfg: -------------------------------------------------------------------------------- 1 | [exp-gui] 2 | clear-left-flow=收起所有打開的介面。 3 | close-toolbar=__CONTROL_LEFT_CLICK__: 按鍵設定\n__CONTROL_RIGHT_CLICK__: 關閉工具列 4 | open-toolbar=__CONTROL_LEFT_CLICK__: 按鍵設定\n__CONTROL_RIGHT_CLICK__: 開啟工具列 5 | 6 | [exp-gui_toolbar-settings] 7 | main-caption=工具列 8 | main-tooltip=工具列設定\n使用核取方塊來設定喜愛項目 9 | reset=重置全部 10 | toggle=切換喜愛項目 11 | move-up=上移 12 | move-down=下移 13 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/gui/_role_updates.lua: -------------------------------------------------------------------------------- 1 | local Gui = require("modules/exp_gui") 2 | local Roles = require("modules.exp_legacy.expcore.roles") 3 | local Event = require("modules/exp_legacy/utils/event") 4 | 5 | --- @diagnostic disable invisible 6 | Event.add(Roles.events.on_role_assigned, Gui._ensure_consistency) 7 | Event.add(Roles.events.on_role_unassigned, Gui._ensure_consistency) 8 | -------------------------------------------------------------------------------- /exp_commands/module/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exp_commands", 3 | "load": [ 4 | "module_exports.lua" 5 | ], 6 | "require": [ 7 | "commands/types.lua", 8 | "commands/authorities.lua", 9 | "commands/help.lua", 10 | "commands/rcon.lua", 11 | "commands/sudo.lua", 12 | "commands/ipc.lua" 13 | ], 14 | "dependencies": { 15 | "clusterio": "*", 16 | "exp_util": "*" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/debug.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Debug 2 | Adds a command that opens the debug frame 3 | ]] 4 | 5 | local DebugView = require("modules.exp_legacy.modules.gui.debug.main_view") --- @dep modules.gui.debug.main_view 6 | local Commands = require("modules/exp_commands") 7 | 8 | --- Opens the debug gui. 9 | Commands.new("debug", { "exp-commands_debug.description" }) 10 | :register(DebugView.open_debug) 11 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "*" 3 | 4 | catalog: 5 | "@clusterio/lib": ^2.0.0-alpha.21 6 | "@clusterio/web_ui": ^2.0.0-alpha.21 7 | "@sinclair/typebox": ^0.30.4 8 | "@types/node": ^20.14.9 9 | "@types/react": ^18.2.21 10 | "typescript": ^5.5.3 11 | "antd": ^5.13.0 12 | "react": ^18.2.0 13 | "react-dom": ^18.2.0 14 | "webpack": ^5.98.0 15 | "webpack-cli": ^5.1.4 16 | "webpack-merge": ^5.9.0 17 | -------------------------------------------------------------------------------- /exp_gui/module/locale/en.cfg: -------------------------------------------------------------------------------- 1 | 2 | [exp-gui] 3 | clear-left-flow=Hide all open windows. 4 | close-toolbar=__CONTROL_LEFT_CLICK__: Toggle Settings\n__CONTROL_RIGHT_CLICK__: Close Toolbar 5 | open-toolbar=__CONTROL_LEFT_CLICK__: Toggle Settings\n__CONTROL_RIGHT_CLICK__: Open Toolbar 6 | 7 | [exp-gui_toolbar-settings] 8 | main-caption=Toolbox 9 | main-tooltip=Toolbox Settings\nUse the checkboxes to select favourites 10 | reset=Reset All 11 | toggle=Toggle Favourites 12 | move-up=Move Up 13 | move-down=Move Down 14 | -------------------------------------------------------------------------------- /exp_legacy/module/config/pollution_grading.lua: -------------------------------------------------------------------------------- 1 | --- This controls how pollution is viewed on the map 2 | -- @config Pollution-Grading 3 | 4 | return { 5 | reference_point = { x = 0, y = 0 }, --- @setting reference_point where pollution is read from 6 | max_scalar = 0.5, --- @setting max_scalar the scale between true max and max 7 | min_scalar = 0.17, --- @setting min_scalar the scale between the lowest max and min 8 | update_delay = 15, --- @setting update_delay time in minutes between view updates 9 | } 10 | -------------------------------------------------------------------------------- /exp_legacy/module/config/join_messages.lua: -------------------------------------------------------------------------------- 1 | return { 2 | Cooldude2606 = "Lua lets you set metatables on numbers, did you know that? Cooldude2606 knows this.", 3 | samy115 = "Tremble in fear as the banhammer is now here, its owner: samy115", 4 | XenoCyber = '"Fire Fire Fire" oops wrong game, have no fear XenoCyber is here', 5 | HunterOfGames = "Unable to support HunterOfGames. You must construct additional miners.", 6 | ookl = 'ookl says: "Pineapples are amazing, hello everyone!"', 7 | arty714 = "Arty\'s Potato made it!", 8 | } 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FeatureRequest.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a new idea to be worked on 4 | title: '' 5 | labels: Feature Request 6 | assignees: '' 7 | 8 | --- 9 | 10 | TL;DR: a few words about what the feature is 11 | 12 | ### Details 13 | 14 | A detailed description of what the new feature is. 15 | 16 | ### Possible methods 17 | 18 | Any ideas you have had about how to implement the feature or any problems that may arise. 19 | 20 | ### Additional context 21 | 22 | Add any other context or screenshots about the feature request here. 23 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/_rcon.lua: -------------------------------------------------------------------------------- 1 | --[[-- Command Rcon - ExpCore 2 | Adds rcon interfaces for the legacy exp core 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local add_static, add_dynamic = Commands.add_rcon_static, Commands.add_rcon_dynamic 7 | 8 | add_static("Gui", require("modules/exp_gui")) 9 | 10 | add_static("Group", require("modules.exp_legacy.expcore.permission_groups")) 11 | add_static("Roles", require("modules.exp_legacy.expcore.roles")) 12 | add_static("Datastore", require("modules.exp_legacy.expcore.datastore")) 13 | add_static("External", require("modules.exp_legacy.expcore.external")) 14 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/me.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Me 2 | Adds a command that adds * around your message in the chat 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local format_text = Commands.format_rich_text_color_locale 7 | 8 | --- Sends an action message in the chat 9 | Commands.new("me", { "exp-commands_me.description" }) 10 | :argument("action", { "exp-commands_me.arg-action" }, Commands.types.string) 11 | :enable_auto_concatenation() 12 | :register(function(player, action) 13 | game.print(format_text({ "exp-commands_me.response", player.name, action, }, player.chat_color)) 14 | end) 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/DesyncReport.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Desync report 3 | about: Report a desync, latest version of scenario only including patches 4 | title: '' 5 | labels: Bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Versions 11 | 12 | Factorio: X.Y.Z 13 | ExpCluster: X.Y.Z 14 | 15 | ### Desync description 16 | 17 | A clear and concise description of what you believe causes the desync. 18 | 19 | ### Reproduction method 20 | 21 | Steps to reproduce the behaviour: 22 | 23 | 1. Go to '...' 24 | 2. Click on '....' 25 | 3. Scroll down to '....' 26 | 4. See error in log 27 | 28 | ### Additional context 29 | 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/CrashReport.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Error report 3 | about: Report a bug which cases the game to crash, or any other issue with an explicit stacktrace 4 | title: '' 5 | labels: Crash 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Versions 11 | 12 | Factorio: X.Y.Z 13 | ExpCluster: X.Y.Z 14 | 15 | ### Error message 16 | 17 | ```log 18 | error message and stacktrace back 19 | ``` 20 | 21 | ### Reproduction method 22 | 23 | Steps to reproduce the behaviour: 24 | 25 | 1. Go to '...' 26 | 2. Click on '....' 27 | 3. Scroll down to '....' 28 | 4. See error in log 29 | 30 | ### Additional context 31 | 32 | Add any other context about the problem here. 33 | 34 | ### Screenshots 35 | 36 | If applicable, add screenshots to help explain your problem. 37 | -------------------------------------------------------------------------------- /exp_legacy/module/config/deconlog.lua: -------------------------------------------------------------------------------- 1 | --- This config controls whether actions such as deconning by players without sufficient permissions is logged or not 2 | -- @config Deconlog 3 | 4 | return { 5 | decon_area = true, --- @setting decon_area whether to log when an area is being deconstructed 6 | built_entity = true, --- @setting built_entity whether to log when an entity is built 7 | mined_entity = true, --- @setting mined_entity whether to log when an entity is mined 8 | fired_rocket = true, --- @setting fired_nuke whether to log when a rocket is fired 9 | fired_explosive_rocket = true, --- @setting fired_nuke whether to log when a explosive rocket is fired 10 | fired_nuke = true, --- @setting fired_nuke whether to log when a nuke is fired 11 | } 12 | -------------------------------------------------------------------------------- /exp_legacy/module/config/discord_alerts.lua: -------------------------------------------------------------------------------- 1 | --- Config file used to enable and disable different push messages for discord 2 | -- @config Discord-Alerts 3 | 4 | return { 5 | show_playtime = true, 6 | entity_protection = true, 7 | player_reports = true, 8 | player_warnings = true, 9 | player_bans = true, 10 | player_mutes = true, 11 | player_kicks = true, 12 | player_promotes = false, 13 | player_jail = true, 14 | ["config"] = true, 15 | ["purge"] = true, 16 | ["c"] = true, 17 | ["command"] = true, 18 | ["silent-command"] = true, 19 | ["measured-command"] = true, 20 | ["banlist"] = true, 21 | ["permissions"] = true, 22 | ["editor"] = true, 23 | ["cheat"] = true, 24 | ["open"] = false, 25 | } 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BugReport.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug which does not crash the game, any bug from the latest major scenario version 4 | title: '' 5 | labels: Bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Versions 11 | 12 | Factorio: X.Y.Z 13 | ExpCluster: X.Y.Z 14 | 15 | ### Bug description 16 | 17 | A clear and concise description of what the bug is. 18 | 19 | ### Reproduction method 20 | 21 | Steps to reproduce the behaviour: 22 | 23 | 1. Go to '...' 24 | 2. Click on '....' 25 | 3. Scroll down to '....' 26 | 4. See error in log 27 | 28 | ### Expected behaviour 29 | 30 | A clear and concise description of what you expected to happen. 31 | 32 | ### Screenshots 33 | 34 | If applicable, add screenshots to help explain your problem. 35 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/vlayer.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - VLayer 2 | Adds a virtual layer to store power to save space. 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local vlayer = require("modules.exp_legacy.modules.control.vlayer") 7 | 8 | --- Print all vlayer information 9 | Commands.new("vlayer-info", { "exp-commands_vlayer.description" }) 10 | :register(function(player) 11 | local index = 3 12 | local response = { "", "exp-commands_vlayer.title" } --- @type LocalisedString 13 | for title, value in pairs(vlayer.get_circuits()) do 14 | response[index] = { "exp-commands_vlayer.result", title, value } 15 | index = index + 1 16 | end 17 | return Commands.status.success(response) 18 | end) 19 | -------------------------------------------------------------------------------- /exp_legacy/module/config/popup_messages.lua: -------------------------------------------------------------------------------- 1 | --- A combination of config settings for different popup values like chat and damage 2 | -- @config Popup-Messages 3 | 4 | return { 5 | show_player_messages = true, --- @setting show_player_messages weather a message in chat will make a popup above them 6 | show_player_mentions = true, --- @setting show_player_mentions weather a mentioned player will have a popup when mentioned in chat 7 | show_player_damage = true, --- @setting show_player_damage weather to show damage done by players 8 | show_player_health = true, --- @setting show_player_health weather to show player health when attacked 9 | damage_location_variance = 0.8, --- @setting damage_location_variance how close to the eade of an entity the popups will appear 10 | } 11 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/data/language.lua: -------------------------------------------------------------------------------- 1 | --- Stores the language used to join the server 2 | -- @data Language 3 | 4 | local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event 5 | local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data 6 | local LocalLanguage = PlayerData.Statistics:combine("LocalLanguage") 7 | LocalLanguage:set_default("Unknown") 8 | 9 | local function set_locale(event) 10 | local player = game.players[event.player_index] 11 | LocalLanguage:set(player, player.locale) 12 | end 13 | 14 | --- Set the players language when they join and change language 15 | Event.add(defines.events.on_player_created, set_locale) 16 | Event.add(defines.events.on_player_joined_game, set_locale) 17 | Event.add(defines.events.on_player_locale_changed, set_locale) 18 | -------------------------------------------------------------------------------- /exp_gui/webpack.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const path = require("path"); 3 | const webpack = require("webpack"); 4 | const { merge } = require("webpack-merge"); 5 | 6 | const common = require("@clusterio/web_ui/webpack.common"); 7 | 8 | module.exports = (env = {}) => merge(common(env), { 9 | context: __dirname, 10 | entry: "./web/index.tsx", 11 | output: { 12 | path: path.resolve(__dirname, "dist", "web"), 13 | }, 14 | plugins: [ 15 | new webpack.container.ModuleFederationPlugin({ 16 | name: "exp_gui", 17 | library: { type: "window", name: "plugin_exp_gui" }, 18 | exposes: { 19 | "./": "./index.ts", 20 | "./package.json": "./package.json", 21 | "./web": "./web/index.tsx", 22 | }, 23 | shared: { 24 | "@clusterio/lib": { import: false }, 25 | "@clusterio/web_ui": { import: false }, 26 | }, 27 | }), 28 | ], 29 | }); 30 | -------------------------------------------------------------------------------- /exp_util/webpack.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const path = require("path"); 3 | const webpack = require("webpack"); 4 | const { merge } = require("webpack-merge"); 5 | 6 | const common = require("@clusterio/web_ui/webpack.common"); 7 | 8 | module.exports = (env = {}) => merge(common(env), { 9 | context: __dirname, 10 | entry: "./web/index.tsx", 11 | output: { 12 | path: path.resolve(__dirname, "dist", "web"), 13 | }, 14 | plugins: [ 15 | new webpack.container.ModuleFederationPlugin({ 16 | name: "exp_util", 17 | library: { type: "window", name: "plugin_exp_util" }, 18 | exposes: { 19 | "./": "./index.ts", 20 | "./package.json": "./package.json", 21 | "./web": "./web/index.tsx", 22 | }, 23 | shared: { 24 | "@clusterio/lib": { import: false }, 25 | "@clusterio/web_ui": { import: false }, 26 | }, 27 | }), 28 | ], 29 | }); 30 | -------------------------------------------------------------------------------- /exp_legacy/webpack.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const path = require("path"); 3 | const webpack = require("webpack"); 4 | const { merge } = require("webpack-merge"); 5 | 6 | const common = require("@clusterio/web_ui/webpack.common"); 7 | 8 | module.exports = (env = {}) => merge(common(env), { 9 | context: __dirname, 10 | entry: "./web/index.tsx", 11 | output: { 12 | path: path.resolve(__dirname, "dist", "web"), 13 | }, 14 | plugins: [ 15 | new webpack.container.ModuleFederationPlugin({ 16 | name: "exp_legacy", 17 | library: { type: "window", name: "plugin_exp_legacy" }, 18 | exposes: { 19 | "./": "./index.ts", 20 | "./package.json": "./package.json", 21 | "./web": "./web/index.tsx", 22 | }, 23 | shared: { 24 | "@clusterio/lib": { import: false }, 25 | "@clusterio/web_ui": { import: false }, 26 | }, 27 | }), 28 | ], 29 | }); 30 | -------------------------------------------------------------------------------- /exp_commands/webpack.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const path = require("path"); 3 | const webpack = require("webpack"); 4 | const { merge } = require("webpack-merge"); 5 | 6 | const common = require("@clusterio/web_ui/webpack.common"); 7 | 8 | module.exports = (env = {}) => merge(common(env), { 9 | context: __dirname, 10 | entry: "./web/index.tsx", 11 | output: { 12 | path: path.resolve(__dirname, "dist", "web"), 13 | }, 14 | plugins: [ 15 | new webpack.container.ModuleFederationPlugin({ 16 | name: "exp_commands", 17 | library: { type: "window", name: "plugin_exp_commands" }, 18 | exposes: { 19 | "./": "./index.ts", 20 | "./package.json": "./package.json", 21 | "./web": "./web/index.tsx", 22 | }, 23 | shared: { 24 | "@clusterio/lib": { import: false }, 25 | "@clusterio/web_ui": { import: false }, 26 | }, 27 | }), 28 | ], 29 | }); 30 | -------------------------------------------------------------------------------- /exp_server_ups/webpack.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const path = require("path"); 3 | const webpack = require("webpack"); 4 | const { merge } = require("webpack-merge"); 5 | 6 | const common = require("@clusterio/web_ui/webpack.common"); 7 | 8 | module.exports = (env = {}) => merge(common(env), { 9 | context: __dirname, 10 | entry: "./web/index.tsx", 11 | output: { 12 | path: path.resolve(__dirname, "dist", "web"), 13 | }, 14 | plugins: [ 15 | new webpack.container.ModuleFederationPlugin({ 16 | name: "exp_server_ups", 17 | library: { type: "window", name: "plugin_exp_server_ups" }, 18 | exposes: { 19 | "./": "./index.ts", 20 | "./package.json": "./package.json", 21 | "./web": "./web/index.tsx", 22 | }, 23 | shared: { 24 | "@clusterio/lib": { import: false }, 25 | "@clusterio/web_ui": { import: false }, 26 | }, 27 | }), 28 | ], 29 | }); 30 | -------------------------------------------------------------------------------- /exp_scenario/module/control/pollution_grading.lua: -------------------------------------------------------------------------------- 1 | --[[-- Control - Pollution Grading 2 | Makes pollution look much nice of the map, ie not one big red mess 3 | ]] 4 | 5 | local config = require("modules.exp_legacy.config.pollution_grading") 6 | 7 | local function check_surfaces() 8 | local max_reference = 0 9 | for _, surface in pairs(game.surfaces) do 10 | local reference = surface.get_pollution(config.reference_point) 11 | if reference > max_reference then 12 | max_reference = reference 13 | end 14 | end 15 | 16 | local max = max_reference * config.max_scalar 17 | local min = max * config.min_scalar 18 | local settings = game.map_settings.pollution 19 | settings.expected_max_per_chunk = max 20 | settings.min_to_show_per_chunk = min 21 | end 22 | 23 | return { 24 | on_nth_tick = { 25 | [config.update_delay * 3600] = check_surfaces, 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /exp_scenario/module/control/inventory_clear.lua: -------------------------------------------------------------------------------- 1 | --[[-- Control - Inventory Clear 2 | Will move players items to spawn when they are banned or kicked, option to clear on leave 3 | ]] 4 | 5 | local ExpUtil = require("modules/exp_util") 6 | local events = require("modules.exp_legacy.config.inventory_clear") 7 | 8 | --- @param event { player_index: number } 9 | local function clear_items(event) 10 | local player = assert(game.get_player(event.player_index)) 11 | local inventory = assert(player.get_main_inventory()) 12 | ExpUtil.transfer_inventory_to_surface{ 13 | inventory = inventory, 14 | surface = game.planets.nauvis.surface, 15 | name = "iron-chest", 16 | allow_creation = true, 17 | } 18 | end 19 | 20 | local event_handlers = {} 21 | for _, event_name in ipairs(events) do 22 | event_handlers[event_name] = clear_items 23 | end 24 | 25 | return { 26 | events = event_handlers, 27 | } 28 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | All are welcome to make bug reports, feature requests, and pull requests for our scenario. We do not require you to have any coding knowledge to make bug reports and feature requests. If you have any questions ask us in our discord. 4 | 5 | For developers wanting to add features please follow these guidelines: 6 | 7 | - All lua code is documented using ldoc. 8 | - Changes should be made on your own fork and merged into `main` through a pull request. 9 | - Each pull request should be limited to one feature or a few bug fixes and link to the related issue page. 10 | - Pull requests are automatically linted and documentation checked. 11 | - Pull requests are manually reviewed to maintain code and language quality. 12 | - New features should have the branch names: `feature/feature-name` 13 | - Bug fixes should have the branch names: `fix/bug-name` 14 | - Commits should have meaningful messages. 15 | -------------------------------------------------------------------------------- /exp_legacy/module/config/gui/tasks.lua: -------------------------------------------------------------------------------- 1 | --- Config file for the tasks gui 2 | -- @config Tasks 3 | 4 | return { 5 | -- Adding tasks 6 | allow_add_task = "all", --- @setting allow_add_task dictates who is allowed to add new tasks; values: all, admin, expcore.roles, none 7 | expcore_roles_allow_add_task = "gui/task-list/add", --- @setting expcore_roles_allow_add_task if expcore.roles is used then this is the required permission 8 | 9 | -- Editing tasks 10 | allow_edit_task = "expcore.roles", --- @setting allow_edit_task dictates who is allowed to edit existing tasks; values: all, admin, expcore.roles, none 11 | expcore_roles_allow_edit_task = "gui/task-list/edit", --- @setting expcore_roles_allow_edit_task if expcore.roles is used then this is the required permission 12 | user_can_edit_own_tasks = true, --- @settings if true then the user who made the task can edit it regardless of the allow_edit_task setting 13 | } 14 | -------------------------------------------------------------------------------- /exp_legacy/module/config/gui/science.lua: -------------------------------------------------------------------------------- 1 | --- Config file for the science info gui 2 | -- @config Science 3 | 4 | return { 5 | -- list of all science packs to be shown in the gui 6 | show_eta = true, --- @setting show_eta when true the eta for research completion will be shown 7 | color_cutoff = 0.8, --- @setting color_cutoff the amount that production can fall before the text changes color 8 | color_flux = 0.1, --- @setting color_flux the amount of fluctuation allowed in production before the icon changes color 9 | "automation-science-pack", 10 | "logistic-science-pack", 11 | "military-science-pack", 12 | "chemical-science-pack", 13 | "production-science-pack", 14 | "utility-science-pack", 15 | "space-science-pack", 16 | "metallurgic-science-pack", 17 | "agricultural-science-pack", 18 | "electromagnetic-science-pack", 19 | "cryogenic-science-pack", 20 | "promethium-science-pack", 21 | } 22 | -------------------------------------------------------------------------------- /exp_scenario/index.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | import * as Messages from "./messages"; 3 | 4 | lib.definePermission({ 5 | name: "exp_scenario.config.view", 6 | title: "View ExpScenario Config", 7 | description: "View the config for all submodules of ExpScenario", 8 | }); 9 | 10 | lib.definePermission({ 11 | name: "exp_scenario.config.edit", 12 | title: "Edit ExpScenario Config", 13 | description: "Edit the config for all submodules of ExpScenario", 14 | }); 15 | 16 | declare module "@clusterio/lib" { 17 | 18 | } 19 | 20 | export const plugin: lib.PluginDeclaration = { 21 | name: "exp_scenario", 22 | title: "exp_scenario", 23 | description: "Example Description. Plugin. Change me in index.ts", 24 | controllerEntrypoint: "./dist/node/controller", 25 | instanceEntrypoint: "./dist/node/instance", 26 | 27 | messages: [ 28 | ], 29 | 30 | webEntrypoint: "./web", 31 | routes: [ 32 | "/exp_scenario", 33 | ], 34 | }; 35 | -------------------------------------------------------------------------------- /exp_legacy/module/config/compilatron.lua: -------------------------------------------------------------------------------- 1 | --- Config file for the compliatrons including where they spawn and what messages they show 2 | -- @config Compilatron 3 | 4 | return { 5 | message_cycle = 60 * 15, --- @setting message_cycle 15 seconds default, how often (in ticks) the messages will cycle 6 | locations = { 7 | ["Spawn"] = { 8 | spawn_position = { x = 0, y = 0 }, 9 | spawn_surface = "nauvis", 10 | entity_name = "small-biter", 11 | messages = { 12 | { "info.website" }, 13 | { "info.read-readme" }, 14 | { "info.discord" }, 15 | { "info.softmod" }, 16 | { "info.redmew" }, 17 | { "info.custom-commands" }, 18 | { "info.status" }, 19 | { "info.lhd" }, 20 | { "info.github" }, 21 | { "info.patreon" }, 22 | }, 23 | } 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /exp_legacy/module/config/preset_player_quickbar.lua: -------------------------------------------------------------------------------- 1 | --- Preset quickbar items that players can load 2 | -- @config Preset-Player-Quickbar 3 | 4 | return { 5 | dangerarea = { "transport-belt", "underground-belt", "splitter", "pipe", "pipe-to-ground", "inserter", "fast-inserter", "long-handed-inserter", "stack-inserter", "roboport", "small-electric-pole", "medium-electric-pole", "big-electric-pole", "substation", nil, "rail", "rail-signal", "rail-chain-signal", "landfill", "cliff-explosives", "fast-transport-belt", "fast-underground-belt", "fast-splitter", "pipe", "pipe-to-ground", "fast-inserter", "long-handed-inserter", "stack-inserter", "stack-filter-inserter", "roboport", [81] = "red-wire", [82] = "green-wire", [83] = "arithmetic-combinator", [84] = "decider-combinator", [85] = "constant-combinator", [86] = "power-switch", [91] = "active-provider-chest", [92] = "passive-provider-chest", [93] = "storage-chest", [94] = "buffer-chest", [95] = "requester-chest", [96] = "roboport" }, 6 | } 7 | -------------------------------------------------------------------------------- /exp_groups/webpack.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const path = require("path"); 3 | const webpack = require("webpack"); 4 | const { merge } = require("webpack-merge"); 5 | 6 | const common = require("@clusterio/web_ui/webpack.common"); 7 | 8 | module.exports = (env = {}) => merge(common(env), { 9 | context: __dirname, 10 | entry: "./web/index.tsx", 11 | output: { 12 | path: path.resolve(__dirname, "dist", "web"), 13 | }, 14 | plugins: [ 15 | new webpack.container.ModuleFederationPlugin({ 16 | name: "exp_groups", 17 | library: { type: "window", name: "plugin_exp_groups" }, 18 | exposes: { 19 | "./": "./index.ts", 20 | "./package.json": "./package.json", 21 | "./web": "./web/index.tsx", 22 | }, 23 | shared: { 24 | "@clusterio/lib": { import: false }, 25 | "@clusterio/web_ui": { import: false }, 26 | "antd": { import: false }, 27 | "react": { import: false }, 28 | "react-dom": { import: false }, 29 | }, 30 | }), 31 | ], 32 | }); 33 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/admin_chat.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Admin Chat 2 | Adds a command that allows admins to talk in a private chat 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local format_player_name = Commands.format_player_name_locale 7 | 8 | --- Sends a message in chat that only admins can see 9 | Commands.new("admin-chat", { "exp-commands_admin-chat.description" }) 10 | :argument("message", { "exp-commands_admin-chat.arg-message" }, Commands.types.string) 11 | :enable_auto_concatenation() 12 | :add_aliases{ "ac" } 13 | :add_flags{ "admin_only" } 14 | :register(function(player, message) 15 | --- @cast message string 16 | local player_name = format_player_name(player) 17 | for _, next_player in ipairs(game.connected_players) do 18 | if next_player.admin then 19 | next_player.print{ "exp-commands_admin-chat.format", player_name, message } 20 | end 21 | end 22 | end) 23 | -------------------------------------------------------------------------------- /exp_scenario/webpack.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const path = require("path"); 3 | const webpack = require("webpack"); 4 | const { merge } = require("webpack-merge"); 5 | 6 | const common = require("@clusterio/web_ui/webpack.common"); 7 | 8 | module.exports = (env = {}) => merge(common(env), { 9 | context: __dirname, 10 | entry: "./web/index.tsx", 11 | output: { 12 | path: path.resolve(__dirname, "dist", "web"), 13 | }, 14 | plugins: [ 15 | new webpack.container.ModuleFederationPlugin({ 16 | name: "exp_scenario", 17 | library: { type: "window", name: "plugin_exp_scenario" }, 18 | exposes: { 19 | "./": "./index.ts", 20 | "./package.json": "./package.json", 21 | "./web": "./web/index.tsx", 22 | }, 23 | shared: { 24 | "@clusterio/lib": { import: false }, 25 | "@clusterio/web_ui": { import: false }, 26 | "antd": { import: false }, 27 | "react": { import: false }, 28 | "react-dom": { import: false }, 29 | }, 30 | }), 31 | ], 32 | }); 33 | -------------------------------------------------------------------------------- /exp_legacy/module/config/repair.lua: -------------------------------------------------------------------------------- 1 | --- Config file for the repair command 2 | -- @config Repair 3 | 4 | return { 5 | disallow = { --- @setting disallow items in this list will never be repaired 6 | ["loader"] = true, 7 | ["fast-loader"] = true, 8 | ["express-loader"] = true, 9 | ["electric-energy-interface"] = true, 10 | ["infinity-chest"] = true, 11 | }, 12 | max_range = 50, --- @setting max_range the max range that can be used with the repair command 13 | allow_blueprint_repair = false, --- @setting allow_blueprint_repair when true will allow blueprints (things not destroyed by biters) to be build instantly using the repair command 14 | allow_ghost_revive = true, --- @setting allow_ghost_revive when true will allow ghosts (things destroyed by biters) to be build instantly using the repair command 15 | allow_heal_entities = true, --- @setting allow_heal_entities when true will heal entities to full health that are within range 16 | } 17 | -------------------------------------------------------------------------------- /exp_server_ups/index.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | 3 | declare module "@clusterio/lib" { 4 | export interface InstanceConfigFields { 5 | "exp_server_ups.update_interval": number; 6 | "exp_server_ups.average_interval": number; 7 | } 8 | } 9 | 10 | export const plugin: lib.PluginDeclaration = { 11 | name: "exp_server_ups", 12 | title: "ExpGaming - Server UPS", 13 | description: "Clusterio plugin providing in game server ups counter", 14 | 15 | instanceEntrypoint: "./dist/node/instance", 16 | instanceConfigFields: { 17 | "exp_server_ups.update_interval": { 18 | title: "Update Interval", 19 | description: "Frequency at which updates are exchanged with factorio (ms)", 20 | type: "number", 21 | initialValue: 1000, 22 | }, 23 | "exp_server_ups.average_interval": { 24 | title: "Average Interval", 25 | description: "Number of update intervals to average updates per second across", 26 | type: "number", 27 | initialValue: 60 28 | }, 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /exp_util/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@expcluster/lib_util", 3 | "version": "0.1.0", 4 | "description": "Clusterio plugin providing Lua libraries and other utilities.", 5 | "author": "Cooldude2606 ", 6 | "license": "MIT", 7 | "repository": "explosivegaming/ExpCluster", 8 | "main": "dist/node/index.js", 9 | "scripts": { 10 | "prepare": "tsc --build && webpack-cli --env production" 11 | }, 12 | "engines": { 13 | "node": ">=18" 14 | }, 15 | "peerDependencies": { 16 | "@clusterio/lib": "catalog:" 17 | }, 18 | "devDependencies": { 19 | "@clusterio/lib": "catalog:", 20 | "@types/node": "catalog:", 21 | "typescript": "catalog:", 22 | "webpack": "catalog:", 23 | "webpack-cli": "catalog:", 24 | "webpack-merge": "catalog:" 25 | }, 26 | "dependencies": { 27 | "@sinclair/typebox": "catalog:" 28 | }, 29 | "publishConfig": { 30 | "access": "public" 31 | }, 32 | "keywords": [ 33 | "clusterio", 34 | "clusterio-plugin", 35 | "factorio" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /exp_legacy/module/locale/zh-CN/expcore.cfg: -------------------------------------------------------------------------------- 1 | [expcore-roles] 2 | error-log-format-flag=[ERROR] roleFlag/__1__ :: __2__ 3 | error-log-format-assign=[ERROR] rolePromote/__1__ :: __2__ 4 | game-message-assign=__1__ 已被 __3__ 指派到身分組 __2__ 5 | game-message-unassign=__1__ 已被 __3__ 取消指派到身分組 __2__ 6 | reject-role=無效的身分組。 7 | reject-player-role=用戶已有更高的身分組。 8 | 9 | [expcore-data] 10 | description-preference=允許寫入資料。 11 | description-data=把用戶資料寫入電腦 12 | arg-option="All", "Statistics", "Settings", "Required" 之中 13 | set-preference=你的喜好已設定為 __1__ 。在你重新加入前將不會有任何改動。 14 | get-preference=你的喜好為 __1__ 。使用 /set-preference 來更改,使用 /save-data 來獲得一份資料副本。 15 | get-data=你的個人資料已寫入: factorio/script_output/expgaming_player_data.json 16 | data-failed=無法載入你的個人資料,任何改動將不會保存。 17 | data-restore=已載入你的個人資料,所有改動將會被保存。 18 | preference=儲存喜好 19 | preference-tooltip=那種資料將在退出時保存 20 | preference-value-tooltip=使用 /set-preference 來更換儲存喜好 21 | preference-All=所有資料都會被儲存 22 | preference-Statistics=只有數據, 設定和資料會被儲存 23 | preference-Settings=只有設定和資料會被儲存 24 | preference-Required=只有需要的資料會被儲存 25 | -------------------------------------------------------------------------------- /exp_legacy/module/locale/zh-TW/expcore.cfg: -------------------------------------------------------------------------------- 1 | [expcore-roles] 2 | error-log-format-flag=[ERROR] roleFlag/__1__ :: __2__ 3 | error-log-format-assign=[ERROR] rolePromote/__1__ :: __2__ 4 | game-message-assign=__1__ 已被 __3__ 指派到身分組 __2__ 5 | game-message-unassign=__1__ 已被 __3__ 取消指派到身分組 __2__ 6 | reject-role=無效的身分組。 7 | reject-player-role=用戶已有更高的身分組。 8 | 9 | [expcore-data] 10 | description-preference=允許寫入資料。 11 | description-data=把用戶資料寫入電腦 12 | arg-option="All", "Statistics", "Settings", "Required" 之中 13 | set-preference=你的喜好已設定為 __1__ 。在你重新加入前將不會有任何改動。 14 | get-preference=你的喜好為 __1__ 。使用 /set-preference 來更改,使用 /save-data 來獲得一份資料副本。 15 | get-data=你的個人資料已寫入: factorio/script_output/expgaming_player_data.json 16 | data-failed=無法載入你的個人資料,任何改動將不會保存。 17 | data-restore=已載入你的個人資料,所有改動將會被保存。 18 | preference=儲存喜好 19 | preference-tooltip=那種資料將在退出時保存 20 | preference-value-tooltip=使用 /set-preference 來更換儲存喜好 21 | preference-All=所有資料都會被儲存 22 | preference-Statistics=只有數據, 設定和資料會被儲存 23 | preference-Settings=只有設定和資料會被儲存 24 | preference-Required=只有需要的資料會被儲存 25 | -------------------------------------------------------------------------------- /exp_gui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@expcluster/lib_gui", 3 | "version": "0.1.0", 4 | "description": "Clusterio plugin providing a Lua GUI definition library.", 5 | "author": "Cooldude2606 ", 6 | "license": "MIT", 7 | "repository": "explosivegaming/ExpCluster", 8 | "main": "dist/node/index.js", 9 | "scripts": { 10 | "prepare": "tsc --build && webpack-cli --env production" 11 | }, 12 | "engines": { 13 | "node": ">=18" 14 | }, 15 | "peerDependencies": { 16 | "@clusterio/lib": "catalog:" 17 | }, 18 | "devDependencies": { 19 | "@clusterio/lib": "catalog:", 20 | "@types/node": "catalog:", 21 | "typescript": "catalog:", 22 | "webpack": "catalog:", 23 | "webpack-cli": "catalog:", 24 | "webpack-merge": "catalog:" 25 | }, 26 | "dependencies": { 27 | "@expcluster/lib_util": "workspace:^", 28 | "@sinclair/typebox": "catalog:" 29 | }, 30 | "publishConfig": { 31 | "access": "public" 32 | }, 33 | "keywords": [ 34 | "clusterio", 35 | "clusterio-plugin", 36 | "factorio" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /exp_legacy/module/config/afk_kick.lua: -------------------------------------------------------------------------------- 1 | local Roles = require("modules.exp_legacy.expcore.roles") 2 | 3 | return { 4 | admin_as_active = true, --- @setting admin_as_active When true admins will be treated as active regardless of afk time 5 | trust_as_active = true, --- @setting trust_as_active When true trusted players (by playtime) will be treated as active regardless of afk time 6 | afk_time = 3600 * 10, --- @setting afk_time The time in ticks that must pass for a player to be considered afk 7 | kick_time = 3600 * 30, --- @setting kick_time The time in ticks that must pass without any active players for all players to be kicked 8 | trust_time = 3600 * 60 * 10, --- @setting trust_time The time in ticks that a player must be online for to count as trusted 9 | update_time = 3600 * 30, --- @setting update_time How often in ticks the script checks for active players 10 | custom_active_check = function(player) 11 | return Roles.get_player_highest_role(player).index <= Roles.get_role_from_any("Veteran").index 12 | end, 13 | } 14 | -------------------------------------------------------------------------------- /exp_commands/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@expcluster/lib_commands", 3 | "version": "0.1.0", 4 | "description": "Clusterio plugin providing a Lua command processing library.", 5 | "author": "Cooldude2606 ", 6 | "license": "MIT", 7 | "repository": "explosivegaming/ExpCluster", 8 | "main": "dist/node/index.js", 9 | "scripts": { 10 | "prepare": "tsc --build && webpack-cli --env production" 11 | }, 12 | "engines": { 13 | "node": ">=18" 14 | }, 15 | "peerDependencies": { 16 | "@clusterio/lib": "catalog:" 17 | }, 18 | "devDependencies": { 19 | "@clusterio/lib": "catalog:", 20 | "@types/node": "catalog:", 21 | "typescript": "catalog:", 22 | "webpack": "catalog:", 23 | "webpack-cli": "catalog:", 24 | "webpack-merge": "catalog:" 25 | }, 26 | "dependencies": { 27 | "@expcluster/lib_util": "workspace:^", 28 | "@sinclair/typebox": "catalog:" 29 | }, 30 | "publishConfig": { 31 | "access": "public" 32 | }, 33 | "keywords": [ 34 | "clusterio", 35 | "clusterio-plugin", 36 | "factorio" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/clear_inventory.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Clear Inventory 2 | Adds a command that allows admins to clear people's inventory 3 | ]] 4 | 5 | local ExpUtil = require("modules/exp_util") 6 | local transfer_inventory = ExpUtil.transfer_inventory_to_surface 7 | 8 | local Commands = require("modules/exp_commands") 9 | 10 | --- Clears a players inventory 11 | Commands.new("clear-inventory", { "exp-commands_clear-inventory.description" }) 12 | :argument("player", { "exp-commands_clear-inventory.arg-player" }, Commands.types.lower_role_player) 13 | :add_flags{ "admin_only" } 14 | :register(function(player, other_player) 15 | local inventory = other_player.get_main_inventory() 16 | if not inventory then 17 | return Commands.status.error{ "expcore-commands.reject-player-alive" } 18 | end 19 | 20 | transfer_inventory{ 21 | inventory = inventory, 22 | surface = game.planets.nauvis.surface, 23 | name = "iron-chest", 24 | allow_creation = true, 25 | } 26 | end) 27 | -------------------------------------------------------------------------------- /exp_groups/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@expcluster/permission_groups", 3 | "private": true, 4 | "version": "0.0.0", 5 | "description": "Example Description. Package. Change me in package.json", 6 | "main": "dist/node/index.js", 7 | "scripts": { 8 | "$prepare": "tsc --build && webpack-cli --env production" 9 | }, 10 | "engines": { 11 | "node": ">=18" 12 | }, 13 | "peerDependencies": { 14 | "@clusterio/lib": "^2.0.0-alpha.19" 15 | }, 16 | "devDependencies": { 17 | "@clusterio/lib": "^2.0.0-alpha.20", 18 | "@clusterio/web_ui": "^2.0.0-alpha.20.b", 19 | "@types/fs-extra": "^11.0.4", 20 | "@types/node": "^20.4.5", 21 | "@types/react": "^18.2.21", 22 | "antd": "^5.13.0", 23 | "react": "^18.2.0", 24 | "react-dom": "^18.2.0", 25 | "typescript": "^5.5.3", 26 | "webpack": "^5.98.0", 27 | "webpack-cli": "^5.1.4", 28 | "webpack-merge": "^5.9.0" 29 | }, 30 | "dependencies": { 31 | "@sinclair/typebox": "^0.30.4", 32 | "fs-extra": "^11.2.0" 33 | }, 34 | "publishConfig": { 35 | "access": "public" 36 | }, 37 | "keywords": [ 38 | "clusterio", 39 | "factorio" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/data/alt-view.lua: -------------------------------------------------------------------------------- 1 | --- Stores if you use alt mode or not and auto applies it 2 | -- @data Alt-View 3 | 4 | local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event 5 | 6 | --- Stores the visible state of alt mode 7 | local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data 8 | local UsesAlt = PlayerData.Settings:combine("UsesAlt") 9 | UsesAlt:set_default(false) 10 | UsesAlt:set_metadata{ 11 | stringify = function(value) return value and "Visible" or "Hidden" end, 12 | } 13 | 14 | --- When your data loads apply alt view if you have it enabled 15 | UsesAlt:on_load(function(player_name, uses_alt) 16 | local player = game.players[player_name] 17 | if uses_alt ~= nil then 18 | player.game_view_settings.show_entity_info = uses_alt 19 | end 20 | end) 21 | 22 | --- When alt view is toggled update this 23 | Event.add(defines.events.on_player_toggled_alt_mode, function(event) 24 | local player = game.players[event.player_index] 25 | UsesAlt:set(player, player.game_view_settings.show_entity_info) 26 | end) 27 | -------------------------------------------------------------------------------- /exp_legacy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@expcluster/legacy", 3 | "version": "0.1.0", 4 | "description": "Clusterio plugin implementing the legacy v6 scenario updated for factorio 2.0", 5 | "author": "Cooldude2606 ", 6 | "license": "MIT", 7 | "repository": "explosivegaming/ExpCluster", 8 | "main": "dist/node/index.js", 9 | "scripts": { 10 | "prepare": "tsc --build && webpack-cli --env production" 11 | }, 12 | "engines": { 13 | "node": ">=18" 14 | }, 15 | "peerDependencies": { 16 | "@clusterio/lib": "catalog:" 17 | }, 18 | "devDependencies": { 19 | "@clusterio/lib": "catalog:", 20 | "@types/node": "catalog:", 21 | "typescript": "catalog:", 22 | "webpack": "catalog:", 23 | "webpack-cli": "catalog:", 24 | "webpack-merge": "catalog:" 25 | }, 26 | "dependencies": { 27 | "@expcluster/lib_commands": "workspace:^", 28 | "@expcluster/lib_util": "workspace:^", 29 | "@sinclair/typebox": "catalog:" 30 | }, 31 | "publishConfig": { 32 | "access": "public" 33 | }, 34 | "keywords": [ 35 | "clusterio", 36 | "clusterio-plugin", 37 | "factorio" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /exp_scenario/module/control/inserter_pickup.lua: -------------------------------------------------------------------------------- 1 | --[[-- Control Insert Pickup 2 | Automatically pick up the items in the inserts hand when you mine it 3 | ]] 4 | 5 | local controllers_with_inventory = { 6 | [defines.controllers.character] = true, 7 | [defines.controllers.god] = true, 8 | [defines.controllers.editor] = true, 9 | } 10 | 11 | --- @param event EventData.on_player_mined_entity 12 | local function on_player_mined_entity(event) 13 | local entity = event.entity 14 | if not entity.valid or entity.type ~= "inserter" or entity.drop_target then 15 | return 16 | end 17 | 18 | local item_entity = entity.surface.find_entity("item-on-ground", entity.drop_position) 19 | 20 | if item_entity then 21 | local player = assert(game.get_player(event.player_index)) 22 | if controllers_with_inventory[player.controller_type] then 23 | player.mine_entity(item_entity) 24 | end 25 | end 26 | end 27 | 28 | local e = defines.events 29 | 30 | return { 31 | events = { 32 | [e.on_player_mined_entity] = on_player_mined_entity 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /exp_server_ups/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@expcluster/server_ups", 3 | "version": "0.1.0", 4 | "description": "Clusterio plugin providing in game server ups counter", 5 | "author": "Cooldude2606 ", 6 | "license": "MIT", 7 | "repository": "explosivegaming/ExpCluster", 8 | "main": "dist/node/index.js", 9 | "scripts": { 10 | "prepare": "tsc --build && webpack-cli --env production" 11 | }, 12 | "engines": { 13 | "node": ">=18" 14 | }, 15 | "peerDependencies": { 16 | "@clusterio/lib": "catalog:" 17 | }, 18 | "devDependencies": { 19 | "typescript": "catalog:", 20 | "@types/node": "catalog:", 21 | "@clusterio/lib": "catalog:", 22 | "webpack": "catalog:", 23 | "webpack-cli": "catalog:", 24 | "webpack-merge": "catalog:" 25 | }, 26 | "dependencies": { 27 | "@sinclair/typebox": "catalog:", 28 | "@expcluster/lib_util": "workspace:^", 29 | "@expcluster/lib_gui": "workspace:^", 30 | "@expcluster/lib_commands": "workspace:^" 31 | }, 32 | "publishConfig": { 33 | "access": "public" 34 | }, 35 | "keywords": [ 36 | "clusterio", 37 | "clusterio-plugin", 38 | "factorio" 39 | ] 40 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Explosive Gaming 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/graftorio/statics.lua: -------------------------------------------------------------------------------- 1 | local general = require("modules.exp_legacy.modules.graftorio.general") 2 | 3 | local lib = {} 4 | 5 | --- @class StaticStatistics 6 | --- @field tick uint 7 | --- @field online_players string[] 8 | --- @field mods table 9 | --- @field seed table 10 | 11 | lib.collect_statics = function() 12 | local stats = {} 13 | stats.tick = game.tick 14 | 15 | stats.online_players = {} 16 | for _, player in pairs(game.connected_players) do 17 | table.insert(stats.online_players, player.name) 18 | end 19 | 20 | stats.mods = {} 21 | for name, version in pairs(script.active_mods) do 22 | stats.mods[name] = version 23 | end 24 | 25 | -- reason behind this is that the map gen settings can be changed during runtime so just get them fresh 26 | stats.seed = {} 27 | for _, surface in pairs(game.surfaces) do 28 | stats.seed[surface.name] = surface.map_gen_settings.seed 29 | end 30 | 31 | for _, force in pairs(game.forces) do 32 | general.data.output[force.name].other = stats 33 | end 34 | end 35 | 36 | return lib 37 | -------------------------------------------------------------------------------- /exp_legacy/module/locale/zh-CN/addons.cfg: -------------------------------------------------------------------------------- 1 | [links] 2 | discord=https://discord.explosivegaming.nl 3 | website=https://www.explosivegaming.nl 4 | status=https://status.explosivegaming.nl 5 | github=https://github.com/explosivegaming/ExpCluster 6 | patreon=https://www.patreon.com/ExpGaming 7 | 8 | [info] 9 | players-online=現在有 __1__ 人在線 10 | total-map-time=地圖時間為 __1__ 11 | discord=加入社群: https://discord.explosivegaming.nl 12 | website=訪問網站: https://www.explosivegaming.nl 13 | status=伺服器狀態: https://status.explosivegaming.nl 14 | github=增加功能或回報錯誤: https://github.com/explosivegaming/ExpCluster 15 | patreon=支持我們: https://www.patreon.com/ExpGaming 16 | custom-commands=這裹使用了自制指令,如 /tag 和 /me。可使用 /chelp 查看更多。 17 | read-readme=確保你已閱讀相關資訊。按左上 i 圖標可再次查看。 18 | softmod=這裹用了自設情境,是一種軟裝模組。 19 | redmew= 20 | lhd=列車必須是左則通行。這是本服務器長久以來的規則。 21 | 22 | [warnings] 23 | received=你已被 __1__ 警告了,現在共有 __2__ 個警告。 __3__ 24 | pre-kick=這是在被踢離之前的最後警告。 25 | kick=你已因為被警告太多次而被請離,不過你之後還是可以回來的。 26 | pre-pre-ban=按照你的行為,你有可能會被封禁。 27 | pre-ban=這是在被封禁之前的最後警告。 28 | ban=你已因為被警告太多次而被封禁; 可以到 __1__ 申訴. 29 | script-warning=這是系統發出的自動警告 (__1__/__2__) 30 | script-warning-removed=系統發出的自動警告已失效 (__1__/__2__) 31 | script-warning-limit=__1__ 已被系統發出了一則自動警告。 32 | -------------------------------------------------------------------------------- /exp_legacy/module/locale/zh-TW/addons.cfg: -------------------------------------------------------------------------------- 1 | [links] 2 | discord=https://discord.explosivegaming.nl 3 | website=https://www.explosivegaming.nl 4 | status=https://status.explosivegaming.nl 5 | github=https://github.com/explosivegaming/ExpCluster 6 | patreon=https://www.patreon.com/ExpGaming 7 | 8 | [info] 9 | players-online=現在有 __1__ 人在線 10 | total-map-time=地圖時間為 __1__ 11 | discord=加入社群: https://discord.explosivegaming.nl 12 | website=訪問網站: https://www.explosivegaming.nl 13 | status=伺服器狀態: https://status.explosivegaming.nl 14 | github=增加功能或回報錯誤: https://github.com/explosivegaming/ExpCluster 15 | patreon=支持我們: https://www.patreon.com/ExpGaming 16 | custom-commands=這裹使用了自制指令,如 /tag 和 /me。可使用 /chelp 查看更多。 17 | read-readme=確保你已閱讀相關資訊。按左上 i 圖標可再次查看。 18 | softmod=這裹用了自設情境,是一種軟裝模組。 19 | redmew= 20 | lhd=列車必須是左則通行。這是本服務器長久以來的規則。 21 | 22 | [warnings] 23 | received=你已被 __1__ 警告了,現在共有 __2__ 個警告。 __3__ 24 | pre-kick=這是在被踢離之前的最後警告。 25 | kick=你已因為被警告太多次而被請離,不過你之後還是可以回來的。 26 | pre-pre-ban=按照你的行為,你有可能會被封禁。 27 | pre-ban=這是在被封禁之前的最後警告。 28 | ban=你已因為被警告太多次而被封禁; 可以到 __1__ 申訴. 29 | script-warning=這是系統發出的自動警告 (__1__/__2__) 30 | script-warning-removed=系統發出的自動警告已失效 (__1__/__2__) 31 | script-warning-limit=__1__ 已被系統發出了一則自動警告。 32 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/_authorities.lua: -------------------------------------------------------------------------------- 1 | --[[-- Command Authorities - Roles 2 | Adds a permission authority for exp roles 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local add, allow, deny = Commands.add_permission_authority, Commands.status.success, Commands.status.unauthorised 7 | 8 | local Roles = require("modules/exp_legacy/expcore/roles") 9 | local player_allowed = Roles.player_allowed 10 | 11 | local authorities = {} 12 | 13 | --- If a command has the flag "character_only" then the command can only be used outside of remote view 14 | authorities.exp_permission = 15 | add(function(player, command) 16 | if not player_allowed(player, command.flags.exp_permission or ("command/" .. command.name)) then 17 | return deny{ "exp-commands-authorities_role.deny" } 18 | else 19 | return allow() 20 | end 21 | end) 22 | 23 | Roles.define_flag_trigger("is_system", function(player, state) 24 | if state then 25 | Commands.unlock_system_commands(player.name) 26 | else 27 | Commands.lock_system_commands(player.name) 28 | end 29 | end) 30 | 31 | return authorities 32 | -------------------------------------------------------------------------------- /exp_legacy/module/config/death_logger.lua: -------------------------------------------------------------------------------- 1 | --- This config controls what happens when a player dies mostly about map markers and item collection; 2 | -- allow_teleport_to_body_command and allow_collect_bodies_command can be over ridden if command_auth_runtime_disable is present; 3 | -- if not present then the commands will not be loaded into the game 4 | -- @config Death-Logger 5 | 6 | return { 7 | collect_corpses = true, --- @setting collect_corpses enables items being returned to the spawn point in chests upon corpse expiring 8 | show_map_markers = true, --- @setting show_map_markers shows markers on the map where bodies are 9 | clean_map_markers = false, 10 | include_time_of_death = true, --- @setting include_time_of_death weather to include the time of death on the map marker 11 | map_icon = nil, --- @setting map_icon the icon that the map marker shows; nil means no icon; format as a SingleID 12 | show_light_at_corpse = true, --- @setting show_light_at_corpse if a light should be rendered at the corpse 13 | show_line_to_corpse = true, --- @setting show_line_to_corpse if a line should be rendered from you to your corpse 14 | period_check_map_tags = 60 * 60 * 5, 15 | } 16 | -------------------------------------------------------------------------------- /exp_legacy/module/config/nukeprotect.lua: -------------------------------------------------------------------------------- 1 | return { 2 | inventories = { 3 | { 4 | inventory = defines.inventory.character_ammo, 5 | event = defines.events.on_player_ammo_inventory_changed, 6 | items = { 7 | ["atomic-bomb"] = true, 8 | }, 9 | }, 10 | { 11 | inventory = defines.inventory.character_armor, 12 | event = defines.events.on_player_armor_inventory_changed, 13 | items = {}, 14 | }, 15 | { 16 | inventory = defines.inventory.character_guns, 17 | event = defines.events.on_player_gun_inventory_changed, 18 | items = {}, 19 | }, 20 | { 21 | inventory = defines.inventory.character_main, 22 | event = defines.events.on_player_main_inventory_changed, 23 | items = { 24 | ["atomic-bomb"] = true, 25 | }, 26 | }, 27 | }, 28 | ignore_permission = "bypass-nukeprotect", -- @setting ignore_permission The permission that nukeprotect will ignore 29 | ignore_admins = true, -- @setting ignore_admins Ignore admins, true by default. Allows usage outside of the roles module 30 | } 31 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/spectate.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Spectate 2 | Adds commands relating to spectate and follow 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local Spectate = require("modules.exp_legacy.modules.control.spectate") --- @dep modules.control.spectate 7 | 8 | --- Toggles spectator mode for the caller 9 | Commands.new("spectate", { "exp-commands_spectate.description-spectate" }) 10 | :register(function(player) 11 | if Spectate.is_spectating(player) then 12 | Spectate.stop_spectate(player) 13 | else 14 | Spectate.start_spectate(player) 15 | end 16 | end) 17 | 18 | --- Enters follow mode for the caller, following the given player. 19 | Commands.new("follow", { "exp-commands_spectate.description-follow" }) 20 | :argument("player", { "exp-commands_spectate.arg-player" }, Commands.types.player_online) 21 | :add_aliases{ "f" } 22 | :register(function(player, other_player) 23 | --- @cast other_player LuaPlayer 24 | if player == other_player then 25 | return Commands.status.invalid_input{ "exp-commands_spectate.follow-self" } 26 | else 27 | Spectate.start_follow(player, other_player) 28 | end 29 | end) 30 | -------------------------------------------------------------------------------- /exp_util/module/include/require.lua: -------------------------------------------------------------------------------- 1 | -- luacheck:ignore global require 2 | --- @diagnostic disable 3 | 4 | local package = require("modules/exp_util/include/package") 5 | local loaded = package.loaded 6 | local _require = require 7 | 8 | -- This replace function is used to avoid additional lines in stack traces during control stage 9 | local function replace() 10 | require = function(path) 11 | --- @cast path string 12 | if package.lifecycle == package.lifecycle_stage.runtime then 13 | local replaced = path:gsub("%.", "/") 14 | if not replaced:match("^__(.-)__") then 15 | replaced = "__level__/" .. replaced 16 | end 17 | if not replaced:match(".lua$") then 18 | replaced = replaced .. ".lua" 19 | end 20 | return loaded[path] 21 | or loaded[replaced] 22 | or error("Can only require files at runtime that have been required in the control stage.", 2) 23 | else 24 | return _require(path) 25 | end 26 | end 27 | end 28 | 29 | return setmetatable({ 30 | on_init = replace, 31 | on_load = replace, 32 | }, { 33 | __call = _require, 34 | }) 35 | -------------------------------------------------------------------------------- /exp_scenario/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@expcluster/scenario", 3 | "version": "0.1.0", 4 | "description": "Clusterio plugin implementing the Explosive Gaming scenario.", 5 | "author": "Cooldude2606 ", 6 | "license": "MIT", 7 | "repository": "explosivegaming/ExpCluster", 8 | "main": "dist/node/index.js", 9 | "scripts": { 10 | "prepare": "tsc --build && webpack-cli --env production" 11 | }, 12 | "engines": { 13 | "node": ">=18" 14 | }, 15 | "peerDependencies": { 16 | "@clusterio/lib": "catalog:" 17 | }, 18 | "devDependencies": { 19 | "@clusterio/lib": "catalog:", 20 | "@clusterio/web_ui": "catalog:", 21 | "@types/node": "catalog:", 22 | "@types/react": "catalog:", 23 | "antd": "catalog:", 24 | "react": "catalog:", 25 | "react-dom": "catalog:", 26 | "typescript": "catalog:", 27 | "webpack": "catalog:", 28 | "webpack-cli": "catalog:", 29 | "webpack-merge": "catalog:" 30 | }, 31 | "dependencies": { 32 | "@expcluster/lib_commands": "workspace:^", 33 | "@expcluster/lib_util": "workspace:^", 34 | "@sinclair/typebox": "catalog:" 35 | }, 36 | "publishConfig": { 37 | "access": "public" 38 | }, 39 | "keywords": [ 40 | "clusterio", 41 | "clusterio-plugin", 42 | "factorio" 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/graftorio/require.lua: -------------------------------------------------------------------------------- 1 | local Commands = require("modules/exp_commands") 2 | local config = require("modules.exp_legacy.config.graftorio") 3 | local statics = require("modules.exp_legacy.modules.graftorio.statics") 4 | local general = require("modules.exp_legacy.modules.graftorio.general") 5 | local forcestats = nil 6 | 7 | local table_to_json = helpers.table_to_json 8 | 9 | if config.modules.forcestats then 10 | forcestats = require("modules.exp_legacy.modules.graftorio.forcestats") 11 | end 12 | 13 | Commands.new("collectdata", "Collect data for RCON usage") 14 | :optional("location", "", Commands.types.string) -- Not sure what this is for, i didn't write this 15 | :register(function() 16 | -- this must be first as it overwrites the stats 17 | -- also makes the .other table for all forces 18 | statics.collect_statics() 19 | if config.modules.other then 20 | general.collect_other() 21 | end 22 | if config.modules.forcestats then 23 | --- @cast forcestats -nil 24 | forcestats.collect_production() 25 | forcestats.collect_loginet() 26 | end 27 | return Commands.status.success(table_to_json(general.data.output)) 28 | end) 29 | -------------------------------------------------------------------------------- /exp_commands/module/commands/sudo.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Sudo 2 | System command to execute a command as another player using their permissions (except for permissions group actions) 3 | 4 | --- Run the example command as another player 5 | -- As Cooldude2606: /repeat 5 6 | /_system-sudo Cooldude2606 repeat 5 7 | ]] 8 | 9 | local Commands = require("modules/exp_commands") 10 | 11 | Commands.new("_sudo", { "exp-commands_sudo.description" }) 12 | :argument("player", { "exp-commands_sudo.arg-player" }, Commands.types.player) 13 | :argument("command", { "exp-commands_sudo.arg-command" }, Commands.types.key_of(Commands.registered_commands)) 14 | :optional("arguments", { "exp-commands_sudo.arg-arguments" }, Commands.types.string) 15 | :enable_auto_concatenation() 16 | :add_flags{ "system_only" } 17 | :register(function(_player, player, command, parameter) 18 | --- @cast player LuaPlayer 19 | --- @cast command ExpCommand 20 | --- @cast parameter string 21 | 22 | --- @diagnostic disable-next-line: invisible 23 | return Commands._event_handler{ 24 | name = command.name, 25 | tick = game.tick, 26 | player_index = player.index, 27 | parameter = parameter, 28 | } 29 | end) 30 | -------------------------------------------------------------------------------- /exp_legacy/module/config/logging.lua: -------------------------------------------------------------------------------- 1 | --- Settings for logging 2 | -- @config logging 3 | 4 | return { 5 | file_name = "log/logging.log", 6 | rocket_launch_display = { 7 | [1] = true, 8 | [2] = true, 9 | [5] = true, 10 | [10] = true, 11 | [20] = true, 12 | [50] = true, 13 | [100] = true, 14 | [200] = true, 15 | }, 16 | rocket_launch_display_rate = 500, 17 | disconnect_reason = { 18 | [defines.disconnect_reason.quit] = "left the game", 19 | [defines.disconnect_reason.dropped] = "was dropped from the game", 20 | [defines.disconnect_reason.reconnect] = "is reconnecting", 21 | [defines.disconnect_reason.wrong_input] = "was having a wrong input", 22 | [defines.disconnect_reason.desync_limit_reached] = "had desync limit reached", 23 | [defines.disconnect_reason.cannot_keep_up] = "cannot keep up", 24 | [defines.disconnect_reason.afk] = "was afk", 25 | [defines.disconnect_reason.kicked] = "was kicked", 26 | [defines.disconnect_reason.kicked_and_deleted] = "was kicked and deleted", 27 | [defines.disconnect_reason.banned] = "was banned", 28 | [defines.disconnect_reason.switching_servers] = "is switching servers", 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/enemy.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Enemy 2 | Adds a commands of handling the enemy force, such as killing all or disabling them 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | 7 | --- Kill all enemies 8 | Commands.new("kill-enemies", { "exp-commands_enemy.description-kill" }) 9 | :add_aliases{ "kill-biters" } 10 | :add_flags{ "admin_only" } 11 | :register(function(player) 12 | game.forces["enemy"].kill_all_units() 13 | game.print{ "exp-commands_enemy.kill", player.name } 14 | end) 15 | 16 | --- Remove all enemies on a surface 17 | Commands.new("remove-enemies", { "exp-commands_enemy.description-remove" }) 18 | :optional("surface", { "exp-commands_enemy.arg-surface" }, Commands.types.surface) 19 | :add_aliases{ "remove-biters" } 20 | :add_flags{ "admin_only" } 21 | :defaults{ 22 | surface = function(player) return player.surface end 23 | } 24 | :register(function(player, surface) 25 | for _, entity in pairs(surface.find_entities_filtered{ force = "enemy" }) do 26 | entity.destroy() 27 | end 28 | -- surface.map_gen_settings.autoplace_controls["enemy-base"].size = "none" -- TODO make this work for SA 29 | game.print{ "exp-commands_enemy.remove", player.name } 30 | end) 31 | -------------------------------------------------------------------------------- /exp_commands/module/commands/ipc.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - IPC 2 | System command which sends an object to the clustorio api, should be used for debugging / echo commands 3 | 4 | --- Send a message on your custom channel, message is a json string 5 | /_ipc myChannel { "myProperty": "foo", "playerName": "Cooldude2606" } 6 | ]] 7 | 8 | local Commands = require("modules/exp_commands") 9 | local Clustorio = require("modules/clusterio/api") 10 | 11 | local json_to_table = helpers.json_to_table 12 | 13 | Commands.add_rcon_static("Clustorio", Clustorio) 14 | Commands.add_rcon_static("ipc", Clustorio.send_json) 15 | 16 | Commands.new("_ipc", { "exp-commands_ipc.description" }) 17 | :argument("channel", { "exp-commands_ipc.arg-channel" }, Commands.types.string) 18 | :argument("message", { "exp-commands_ipc.arg-message" }, Commands.types.string) 19 | :enable_auto_concatenation() 20 | :add_flags{ "system_only" } 21 | :register(function(_player, channel, message) 22 | --- @cast channel string 23 | --- @cast message string 24 | 25 | local tbl = json_to_table(message) 26 | if tbl == nil then 27 | return Commands.status.invalid_input("Invalid json string") 28 | else 29 | Clustorio.send_json(channel, tbl) 30 | return Commands.status.success() 31 | end 32 | end) 33 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/data/toolbar.lua: -------------------------------------------------------------------------------- 1 | local Gui = require("modules/exp_gui") 2 | local PlayerData = require("modules.exp_legacy.expcore.player_data") 3 | 4 | -- Used to store the state of the toolbar when a player leaves 5 | local ToolbarState = PlayerData.Settings:combine("ToolbarState") 6 | ToolbarState:set_metadata{ 7 | stringify = function() 8 | return "Toolbar is saved on exit" 9 | end, 10 | } 11 | 12 | --- Uncompress the data to be more useable 13 | ToolbarState:on_load(function(player_name, value) 14 | -- If there is no value, do nothing 15 | if value == nil then return end 16 | -- Old format, we discard it [ string[], string[], string[], boolean ] 17 | if type(value) ~= "string" then return end 18 | 19 | local decompressed = helpers.json_to_table(assert(helpers.decode_string(value), "Failed String Decode")) 20 | local player = assert(game.get_player(player_name)) 21 | Gui.toolbar.set_state(player, decompressed --[[ @as Gui.ToolbarState ]]) 22 | 23 | return nil -- We don't save the state, use Gui.toolbar.get_state 24 | end) 25 | 26 | --- Save the current state of the players toolbar menu 27 | ToolbarState:on_save(function(player_name, _) 28 | local player = assert(game.get_player(player_name)) 29 | local value = Gui.toolbar.get_state(player) 30 | return helpers.encode_string(helpers.table_to_json(value)) 31 | end) 32 | -------------------------------------------------------------------------------- /exp_legacy/module/config/_file_loader.lua: -------------------------------------------------------------------------------- 1 | --- This contains a list of all files that will be loaded and the order they are loaded in; 2 | -- to stop a file from loading add "--" in front of it, remove the "--" to have the file be loaded; 3 | -- config files should be loaded after all modules are loaded; 4 | -- core files should be required by modules and not be present in this list; 5 | -- @config File-Loader 6 | return { 7 | "expcore.player_data", -- must be loaded first to register event handlers 8 | 9 | -- Control 10 | "modules.control.vlayer", 11 | 12 | --- Data 13 | "modules.data.statistics", 14 | "modules.data.player-colours", 15 | "modules.data.greetings", 16 | "modules.data.quickbar", 17 | "modules.data.alt-view", 18 | "modules.data.tag", 19 | -- 'modules.data.bonus', 20 | "modules.data.personal-logistic", 21 | "modules.data.language", 22 | --"modules.data.toolbar", 23 | 24 | --- GUI 25 | "modules.gui.readme", 26 | "modules.gui.rocket-info", 27 | "modules.gui.warp-list", 28 | "modules.gui.player-list", 29 | "modules.gui.vlayer", 30 | "modules.gui._role_updates", 31 | 32 | "modules.graftorio.require", -- graftorio 33 | --- Config Files 34 | "config.expcore.permission_groups", -- loads some predefined permission groups 35 | "config.expcore.roles", -- loads some predefined roles 36 | } 37 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/bot_queue.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Bot queue 2 | Adds a command that allows viewing and changing the construction queue limits 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | 7 | --- Get / Set the current values for the bot queue 8 | Commands.new("set-bot-queue", { "exp-commands_bot-queue.description" }) 9 | :optional("amount", { "exp-commands_bot-queue.arg-amount" }, Commands.types.integer_range(1, 20)) 10 | :add_aliases{ "bot-queue" } 11 | :add_flags{ "admin_only" } 12 | :register(function(player, amount) 13 | if amount then 14 | player.force.max_successful_attempts_per_tick_per_construction_queue = 3 * amount 15 | player.force.max_failed_attempts_per_tick_per_construction_queue = 5 * amount 16 | game.print{ 17 | "exp-commands_bot-queue.set", 18 | player.force.max_successful_attempts_per_tick_per_construction_queue, 19 | player.force.max_failed_attempts_per_tick_per_construction_queue, 20 | } 21 | return Commands.status.success() 22 | end 23 | 24 | return Commands.status.success{ 25 | "exp-commands_bot-queue.get", 26 | player.force.max_successful_attempts_per_tick_per_construction_queue, 27 | player.force.max_failed_attempts_per_tick_per_construction_queue, 28 | } 29 | end) 30 | -------------------------------------------------------------------------------- /exp_scenario/module/control/bonus.lua: -------------------------------------------------------------------------------- 1 | --[[ Control - Bonus 2 | Various bonus related event handlers 3 | 4 | TODO Refactor this fully, this is temp to get it out of the player bonus gui file 5 | ]] 6 | 7 | local Roles = require("modules/exp_legacy/expcore/roles") 8 | local config = require("modules/exp_legacy/config/bonus") 9 | 10 | --- @param event EventData.on_force_created 11 | local function apply_force_bonus(event) 12 | local force = event.force 13 | for k, v in pairs(config.force_bonus) do 14 | force[k] = v.initial_value 15 | end 16 | end 17 | 18 | --- @param event EventData.on_surface_created 19 | local function apply_surface_bonus(event) 20 | local surface = assert(game.get_surface(event.surface_index)) 21 | for k, v in pairs(config.surface_bonus) do 22 | surface[k] = v.initial_value 23 | end 24 | end 25 | 26 | --- @param event EventData.on_player_died 27 | local function fast_respawn(event) 28 | local player = assert(game.get_player(event.player_index)) 29 | if Roles.player_has_flag(player, "instant-respawn") then 30 | player.ticks_to_respawn = 120 31 | end 32 | end 33 | 34 | local e = defines.events 35 | 36 | return { 37 | events = { 38 | [e.on_force_created] = apply_force_bonus, 39 | [e.on_surface_created] = apply_surface_bonus, 40 | [e.on_player_died] = fast_respawn, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /exp_legacy/module/config/protection.lua: -------------------------------------------------------------------------------- 1 | return { 2 | ignore_admins = true, --- @setting ignore_admins If admins are ignored by the protection filter 3 | ignore_permission = "bypass-entity-protection", --- @setting ignore_permission Players with this permission will be ignored by the protection filter, leave nil if expcore.roles is not used 4 | repeat_count = 5, --- @setting repeat_count Number of protected entities that must be removed within repeat_lifetime in order to trigger repeated removal protection 5 | repeat_lifetime = 3600 * 20, --- @setting repeat_lifetime The length of time, in ticks, that protected removals will be remembered for 6 | refresh_rate = 3600 * 5, --- @setting refresh_rate How often the age of protected removals are checked against repeat_lifetime 7 | always_protected_names = { --- @setting always_protected_names Names of entities which are always protected 8 | 9 | }, 10 | always_protected_types = { --- @setting always_protected_types Types of entities which are always protected 11 | "boiler", "generator", "offshore-pump", "power-switch", "reactor", "rocket-silo", 12 | }, 13 | always_trigger_repeat_names = { --- @setting always_trigger_repeat_names Names of entities which always trigger repeated removal protection 14 | 15 | }, 16 | always_trigger_repeat_types = { --- @setting always_trigger_repeat_types Types of entities which always trigger repeated removal protection 17 | "reactor", "rocket-silo", 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /exp_util/module/include/package.lua: -------------------------------------------------------------------------------- 1 | -- luacheck:ignore global package 2 | 3 | --- Enum values for the different lifecycle stages within a factorio module 4 | -- Info on the data lifecycle and how we use it: https://lua-api.factorio.com/latest/auxiliary/data-lifecycle.html 5 | -- We start in control stage and so values 1 thorough 3 are only present for completeness 6 | package.lifecycle_stage = { 7 | settings = 1, 8 | data = 2, 9 | migration = 3, 10 | control = 4, 11 | init = 5, 12 | load = 6, 13 | config_change = 7, 14 | runtime = 8, 15 | } 16 | 17 | --- Stores the current lifecycle stage we are in, compare values against package.lifecycle_stage 18 | --- See also: https://forums.factorio.com/viewtopic.php?f=28&t=115622 19 | package.lifecycle = package.lifecycle_stage.control 20 | 21 | return setmetatable({ 22 | on_init = function() package.lifecycle = package.lifecycle_stage.init end, 23 | on_load = function() package.lifecycle = package.lifecycle_stage.load end, 24 | on_configuration_changed = function() package.lifecycle = package.lifecycle_stage.config_change end, 25 | events = { 26 | [defines.events.on_player_joined_game] = function() package.lifecycle = package.lifecycle_stage.runtime end, 27 | [defines.events.on_singleplayer_init] = function() package.lifecycle = package.lifecycle_stage.runtime end, 28 | [defines.events.on_multiplayer_init] = function() package.lifecycle = package.lifecycle_stage.runtime end, 29 | }, 30 | }, { 31 | __index = package, 32 | }) 33 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/trains.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Set Automatic Train 2 | Adds a command that set all train back to automatic 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local format_player_name = Commands.format_player_name_locale 7 | local format_number = require("util").format_number 8 | 9 | --- @class ExpCommand_Trains.commands 10 | local commands = {} 11 | 12 | --- Set all trains to automatic 13 | --- @class ExpCommand_Artillery.commands.artillery: ExpCommand 14 | --- @overload fun(player: LuaPlayer, surface: LuaSurface?, force: LuaForce?) 15 | commands.set_trains_to_automatic = Commands.new("set-trains-to-automatic", { "exp-commands_trains.description" }) 16 | :optional("surface", { "exp-commands_trains.arg-surface" }, Commands.types.surface) 17 | :optional("force", { "exp-commands_trains.arg-force" }, Commands.types.force) 18 | :register(function(player, surface, force) 19 | --- @cast surface LuaSurface? 20 | --- @cast force LuaForce? 21 | local trains = game.train_manager.get_trains{ 22 | stock = "locomotive", 23 | has_passenger = false, 24 | is_manual = true, 25 | is_moving = false, 26 | surface = surface, 27 | force = force, 28 | } 29 | 30 | for _, train in ipairs(trains) do 31 | train.manual_mode = false 32 | end 33 | 34 | game.print{ "exp-commands_trains.response", format_player_name(player), format_number(#trains, false) } 35 | end) --[[ @as any ]] 36 | 37 | return { 38 | commands = commands, 39 | } 40 | -------------------------------------------------------------------------------- /exp_legacy/module/locale/en/expcore.cfg: -------------------------------------------------------------------------------- 1 | [expcore-roles] 2 | error-log-format-flag=[ERROR] roleFlag/__1__ :: __2__ 3 | error-log-format-assign=[ERROR] rolePromote/__1__ :: __2__ 4 | game-message-assign=__1__ has been assigned to __2__ by __3__ 5 | game-message-unassign=__1__ has been unassigned from __2__ by __3__ 6 | reject-role=Invalid Role Name. 7 | reject-player-role=Player has a higher role. 8 | 9 | [expcore-data] 10 | description-preference=Allows you to set/get your data saving preference. 11 | description-data=Writes all your player data to a file on your computer. 12 | arg-option=One of "All", "Statistics", "Settings", "Required" 13 | set-preference=You data saving preference has been set to __1__. Existing data will not be effected until you rejoin. 14 | get-preference=You data saving preference is __1__. Use /set-preference to change this. Use /save-data to get a local copy of your data. 15 | get-data=Your player data has been writen to file, location: factorio/script_output/expgaming_player_data.json 16 | data-failed=Your player data has failed to load. Any changes to your data will not be saved. 17 | data-restore=Your player data has been restored and changes will now save when you leave. 18 | preference=Saving Preference 19 | preference-tooltip=Which categories will be saved when you leave the game 20 | preference-value-tooltip=Change by using /set-preference 21 | preference-All=All data will be saved 22 | preference-Statistics=Only statistics, settings, and required data will be saved 23 | preference-Settings=Only settings and required data will be saved 24 | preference-Required=Only required data will be saved -------------------------------------------------------------------------------- /exp_scenario/module/commands/kill.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Kill 2 | Adds a command that allows players to kill themselves and others 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | 7 | local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles 8 | local highest_role = Roles.get_player_highest_role 9 | 10 | --- Kills yourself or another player. 11 | Commands.new("kill", { "exp-commands_kill.description" }) 12 | :optional("player", { "exp-commands_kill.arg-player" }, Commands.types.lower_role_player_alive) 13 | :defaults{ 14 | player = function(player) 15 | return player.character and player.character.health > 0 and player or nil 16 | end 17 | } 18 | :register(function(player, other_player) 19 | --- @cast other_player LuaPlayer? 20 | if other_player == nil then 21 | -- Can only be nil if the target is the player and they are already dead 22 | return Commands.status.error{ "exp-commands_kill.already-dead" } 23 | elseif (other_player == player) or (highest_role(player).index < highest_role(other_player).index) then 24 | -- You can always kill yourself or can kill lower role players 25 | if script.active_mods["space-age"] then 26 | other_player.surface.create_entity{ name = "lightning", position = { other_player.position.x, other_player.position.y - 16 }, target = other_player.character } 27 | end 28 | other_player.character.die() 29 | else 30 | return Commands.status.unauthorised{ "exp-commands_kill.lower-role" } 31 | end 32 | end) 33 | -------------------------------------------------------------------------------- /exp_commands/module/locale/zh-CN.cfg: -------------------------------------------------------------------------------- 1 | [exp-commands] 2 | help=__1__- __2____3__ 3 | usage=/__1__ __2__ 4 | aliases=\n 別名: __1__ 5 | argument=<__1__> 6 | optional=[__1__] 7 | argument-verbose=\n <__1__> - __2__ 8 | optional-verbose=\n [__1__] - __2__ 9 | success=指令完成。 10 | error=指令運行失敗: __1__ 11 | error-default=檢查指令參數。 12 | unauthorized=未授權: __1__ 13 | unauthorized-default=由於權限不足,存取被拒絕。 14 | invalid-usage=參數數量和用法錯誤,參考: __1__ 15 | invalid-input=輸入錯誤: 確保格式正確。 16 | invalid-argument=參數錯誤 "__1__"; __2__ 17 | internal-error=內部錯誤,請聯絡管理員: __1__ 18 | 19 | [exp-commands-parse] 20 | string-options=選項錯誤, 必須是以下之一: __1__ 21 | string-max-length=長度錯誤, 最長: __1__ 22 | number=數字錯誤。 23 | number-range=範圍錯誤, 最小 (含): __1__, 最大 (含): __2__ 24 | player=用戶名稱錯誤, __1__ ,可嘗試使用 Tab 鍵自動完成 25 | player-online=用戶已下線。 26 | player-alive=用戶已死亡。 27 | force=勢力名稱錯誤。 28 | surface=地表名稱錯誤。 29 | planet=星球名稱錯誤。 30 | color=顏色名稱錯誤。 31 | 32 | [exp-commands-authorities] 33 | character-only=該命令不能在遠端視圖中使用。 34 | remote-only=該命令只能在遠端視圖中使用。 35 | admin-only=此命令僅適用於管理員。 36 | system-only=用戶無法運行此命令。 37 | disabled=此命令目前已停用。 38 | 39 | [exp-commands_help] 40 | description=列出和查找指令 41 | arg-keyword=關鍵詞 42 | arg-page=頁數 43 | header="__1__" 的幫助: 44 | footer=[__1__ 項已找到: 頁 __2__ ,共 __3__] 45 | format=/__1__ __2__ __3__ 46 | aliases=別名: __1__ 47 | out-of-range=__1__ 不是正確的頁數。 最後為: __2__ 48 | no-results=沒找到指令 49 | 50 | [exp-commands_ipc] 51 | description=在選定的頻道上發送 IPC 訊息 52 | arg-channel=傳送的通道 53 | arg-message=在 IPC 通道上傳送的訊息 54 | 55 | [exp-commands_rcon] 56 | description=在自訂環境中執行任意指令 57 | arg-invocation=要運行的指令 58 | 59 | [exp-commands_sudo] 60 | description=以其他用戶身分執行命令 61 | arg-player=執行命令的用戶 62 | arg-command=執行的指令 63 | arg-arguments=指令參數 64 | -------------------------------------------------------------------------------- /exp_commands/module/locale/zh-TW.cfg: -------------------------------------------------------------------------------- 1 | [exp-commands] 2 | help=__1__- __2____3__ 3 | usage=/__1__ __2__ 4 | aliases=\n 別名: __1__ 5 | argument=<__1__> 6 | optional=[__1__] 7 | argument-verbose=\n <__1__> - __2__ 8 | optional-verbose=\n [__1__] - __2__ 9 | success=指令完成。 10 | error=指令運行失敗: __1__ 11 | error-default=檢查指令參數。 12 | unauthorized=未授權: __1__ 13 | unauthorized-default=由於權限不足,存取被拒絕。 14 | invalid-usage=參數數量和用法錯誤,參考: __1__ 15 | invalid-input=輸入錯誤: 確保格式正確。 16 | invalid-argument=參數錯誤 "__1__"; __2__ 17 | internal-error=內部錯誤,請聯絡管理員: __1__ 18 | 19 | [exp-commands-parse] 20 | string-options=選項錯誤, 必須是以下之一: __1__ 21 | string-max-length=長度錯誤, 最長: __1__ 22 | number=數字錯誤。 23 | number-range=範圍錯誤, 最小 (含): __1__, 最大 (含): __2__ 24 | player=用戶名稱錯誤, __1__ ,可嘗試使用 Tab 鍵自動完成 25 | player-online=用戶已下線。 26 | player-alive=用戶已死亡。 27 | force=勢力名稱錯誤。 28 | surface=地表名稱錯誤。 29 | planet=星球名稱錯誤。 30 | color=顏色名稱錯誤。 31 | 32 | [exp-commands-authorities] 33 | character-only=該命令不能在遠端視圖中使用。 34 | remote-only=該命令只能在遠端視圖中使用。 35 | admin-only=此命令僅適用於管理員。 36 | system-only=用戶無法運行此命令。 37 | disabled=此命令目前已停用。 38 | 39 | [exp-commands_help] 40 | description=列出和查找指令 41 | arg-keyword=關鍵詞 42 | arg-page=頁數 43 | header="__1__" 的幫助: 44 | footer=[__1__ 項已找到: 頁 __2__ ,共 __3__] 45 | format=/__1__ __2__ __3__ 46 | aliases=別名: __1__ 47 | out-of-range=__1__ 不是正確的頁數。 最後為: __2__ 48 | no-results=沒找到指令 49 | 50 | [exp-commands_ipc] 51 | description=在選定的頻道上發送 IPC 訊息 52 | arg-channel=傳送的通道 53 | arg-message=在 IPC 通道上傳送的訊息 54 | 55 | [exp-commands_rcon] 56 | description=在自訂環境中執行任意指令 57 | arg-invocation=要運行的指令 58 | 59 | [exp-commands_sudo] 60 | description=以其他用戶身分執行命令 61 | arg-player=執行命令的用戶 62 | arg-command=執行的指令 63 | arg-arguments=指令參數 64 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/locate.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Locate 2 | Adds a command that will return the last location of a player 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local format_player_name = Commands.format_player_name_locale 7 | 8 | local format = string.format 9 | 10 | --- Open remote view at a players last location 11 | Commands.new("locate", { "exp-commands_locate.description" }) 12 | :add_aliases{ "last-location", "find" } 13 | :argument("player", { "exp-commands_locate.arg-player" }, Commands.types.player) 14 | :optional("remote", { "exp-commands_locate.arg-remote" }, Commands.types.boolean) 15 | :register(function(player, other_player, remote) 16 | --- @cast other_player LuaPlayer 17 | --- @cast remote boolean? 18 | local surface = other_player.physical_surface 19 | local position = other_player.physical_position 20 | if remote and other_player.controller_type == defines.controllers.remote then 21 | surface = other_player.surface 22 | position = other_player.position 23 | end 24 | 25 | if player.index > 0 then 26 | -- This check allows rcon to use the command 27 | player.set_controller{ 28 | type = defines.controllers.remote, 29 | surface = surface, 30 | position = position, 31 | } 32 | end 33 | 34 | return Commands.status.success{ 35 | "exp-commands_locate.response", 36 | format_player_name(other_player), 37 | format("%.1f", position.x), 38 | format("%.1f", position.y), 39 | } 40 | end) 41 | -------------------------------------------------------------------------------- /exp_scenario/module/control/report_jail.lua: -------------------------------------------------------------------------------- 1 | --[[-- Control - Report Jail 2 | When a player is reported, the player is automatically jailed if the combined playtime of the reporters exceeds the reported player 3 | ]] 4 | 5 | local ExpUtil = require("modules/exp_util") 6 | local Jail = require("modules.exp_legacy.modules.control.jail") 7 | local Reports = require("modules.exp_legacy.modules.control.reports") 8 | 9 | local max = math.max 10 | local format_player_name = ExpUtil.format_player_name_locale 11 | 12 | --- Returns the playtime of the reporter. Used when calculating the total playtime of all reporters 13 | --- @param player LuaPlayer 14 | --- @param by_player_name string 15 | --- @param reason string 16 | --- @return number 17 | local function reporter_playtime(player, by_player_name, reason) 18 | local by_player = game.get_player(by_player_name) 19 | return by_player and by_player.online_time or 0 20 | end 21 | 22 | --- Check if the player has too many reports against them (based on playtime) 23 | local function on_player_reported(event) 24 | local player = assert(game.get_player(event.player_index)) 25 | local total_playtime = Reports.count_reports(player, reporter_playtime) 26 | 27 | -- Total time greater than the players own time, or 30 minutes, which ever is greater 28 | if Reports.count_reports(player) > 1 and total_playtime > max(player.online_time * 2, 108000) then 29 | Jail.jail_player(player, "", "Reported by too many players, please wait for a moderator.") 30 | game.print{ "exp_report-jail.chat-jailed", format_player_name(player) } 31 | end 32 | end 33 | 34 | return { 35 | events = { 36 | [Reports.events.on_player_reported] = on_player_reported, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /exp_scenario/module/control/chat_popup.lua: -------------------------------------------------------------------------------- 1 | --[[-- Control - Chat Popup 2 | Creates flying text entities when a player sends a message in chat 3 | ]] 4 | 5 | local FlyingText = require("modules/exp_util/flying_text") 6 | local config = require("modules.exp_legacy.config.popup_messages") 7 | 8 | local lower = string.lower 9 | local find = string.find 10 | 11 | --- Create a chat bubble when a player types a message 12 | --- @param event EventData.on_console_chat 13 | local function on_console_chat(event) 14 | if not event.player_index then return end 15 | local player = assert(game.get_player(event.player_index)) 16 | local name = player.name 17 | 18 | -- Sends the message as text above them 19 | if config.show_player_messages then 20 | FlyingText.create_as_player{ 21 | target_player = player, 22 | text = { "exp_chat-popup.flying-text-message", name, event.message }, 23 | } 24 | end 25 | 26 | if not config.show_player_mentions then return end 27 | 28 | -- Loops over online players to see if they name is included 29 | local search_string = lower(event.message) 30 | for _, mentioned_player in ipairs(game.connected_players) do 31 | if mentioned_player.index ~= player.index then 32 | if find(search_string, lower(mentioned_player.name), 1, true) then 33 | FlyingText.create_as_player{ 34 | target_player = mentioned_player, 35 | text = { "exp_chat-popup.flying-text-ping", name }, 36 | } 37 | end 38 | end 39 | end 40 | end 41 | 42 | local e = defines.events 43 | 44 | return { 45 | events = { 46 | [e.on_console_chat] = on_console_chat, 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /exp_legacy/module/config/preset_player_colours.lua: -------------------------------------------------------------------------------- 1 | --- Preset colours that players get when they join the server, if not in the list then will be given a random colour (which isnt disallowed) 2 | -- @config Preset-Player-Colours 3 | 4 | return { 5 | players = { --- @setting players list of all players and the colour in rgb256 that they will recive upon joining 6 | PHIDIAS0303 = { r = 255, g = 255, b = 255 }, 7 | BADgamerNL = { r = 255, g = 20, b = 147 }, 8 | arty714 = { r = 150, g = 68, b = 161 }, 9 | Cooldude2606 = { r = 57, g = 192, b = 207 }, 10 | mark9064 = { r = 99, g = 0, b = 255 }, 11 | eissturm = { r = 25, g = 25, b = 112 }, 12 | Sakama = { r = 20, g = 213, b = 80 }, 13 | freek18 = { r = 50, g = 0, b = 255 }, 14 | aldldl = { r = 0, g = 131, b = 255 }, 15 | NAD4X4 = { r = 135, g = 206, b = 250 }, 16 | cydes = { r = 82, g = 249, b = 155 }, 17 | UUBlueFire = { r = 0, g = 204, b = 255 }, 18 | CmonMate497 = { r = 103, g = 224, b = 194 }, 19 | s4sh = { r = 255, g = 120, b = 0 }, 20 | ArPiiX = { r = 0, g = 255, b = 0 }, 21 | NextIdea = { r = 255, g = 255, b = 255 }, 22 | hamsterbryan = { r = 0, g = 255, b = 0 }, 23 | XenoCyber = { r = 0, g = 128, b = 255 }, 24 | }, 25 | disallow = { --- @setting disallow colours which will not given to players; the value does not matter it is only the key which is checked 26 | black = { r = 0, g = 0, b = 0 }, 27 | white = { r = 255, g = 255, b = 255 }, 28 | success = { r = 0, g = 255, b = 0 }, 29 | warning = { r = 255, g = 255, b = 0 }, 30 | fail = { r = 255, g = 0, b = 0 }, 31 | info = { r = 255, g = 255, b = 255 }, 32 | }, 33 | } 34 | -------------------------------------------------------------------------------- /exp_scenario/module/control/protection_jail.lua: -------------------------------------------------------------------------------- 1 | --[[-- Control - Projection Jail 2 | When a player triggers protection multiple times they are automatically jailed 3 | ]] 4 | 5 | local ExpUtil = require("modules/exp_util") 6 | local Storage = require("modules/exp_util/storage") 7 | local Jail = require("modules.exp_legacy.modules.control.jail") 8 | local Protection = require("modules.exp_legacy.modules.control.protection") 9 | 10 | local format_player_name = ExpUtil.format_player_name_locale 11 | 12 | --- Stores how many times the repeat violation was triggered 13 | --- @type table 14 | local repeat_count = {} 15 | Storage.register(repeat_count, function(tbl) 16 | repeat_count = tbl 17 | end) 18 | 19 | --- When a protection is triggered increment their counter and jail if needed 20 | local function on_repeat_violation(event) 21 | local player = assert(game.get_player(event.player_index)) 22 | 23 | -- Increment the counter 24 | local count = (repeat_count[player.index] or 0) + 1 25 | repeat_count[player.index] = count 26 | 27 | -- Jail if needed 28 | if count >= 3 then 29 | Jail.jail_player(player, "", "Removed too many protected entities, please wait for a moderator.") 30 | game.print{ "exp_protection-jail.chat-jailed", format_player_name(player) } 31 | end 32 | end 33 | 34 | --- Clear the counter when they leave the game (stops a build up of data) 35 | --- @param event EventData.on_player_left_game 36 | local function on_player_left_game(event) 37 | repeat_count[event.player_index] = nil 38 | end 39 | 40 | local e = defines.events 41 | 42 | return { 43 | events = { 44 | [Protection.events.on_repeat_violation] = on_repeat_violation, 45 | [e.on_player_left_game] = on_player_left_game, 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /exp_scenario/module/control/research.lua: -------------------------------------------------------------------------------- 1 | --[[ Control - Research 2 | Various research related event handlers 3 | 4 | TODO Refactor this fully, this is temp to get it out of the research times gui file 5 | ]] 6 | 7 | local config = require("modules/exp_legacy/config/research") 8 | 9 | --- @param event EventData.on_research_finished 10 | local function on_research_finished(event) 11 | local research_name = event.research.name 12 | if config.bonus_inventory.enabled and config.bonus_inventory.res[research_name] then 13 | event.research.force[config.bonus_inventory.name] = math.min((event.research.level - 1) * config.bonus_inventory.rate, config.bonus_inventory.limit) 14 | end 15 | 16 | if config.pollution_ageing_by_research and config.bonus_inventory.res[research_name] then 17 | game.map_settings.pollution.ageing = math.min(10, event.research.level / 5) 18 | end 19 | end 20 | 21 | --- @param event EventData.on_research_started 22 | local function on_research_started(event) 23 | if config.limit_res[event.research.name] and event.research.level > config.limit_res[event.research.name] then 24 | event.research.enabled = false 25 | event.research.visible_when_disabled = true 26 | local rq = event.research.force.research_queue 27 | 28 | for i = #rq, 1, -1 do 29 | if rq[i] == event.research.name then 30 | table.remove(rq, i) 31 | end 32 | end 33 | 34 | event.research.force.cancel_current_research() 35 | event.research.force.research_queue = rq 36 | end 37 | end 38 | 39 | local e = defines.events 40 | 41 | return { 42 | events = { 43 | [e.on_research_finished] = on_research_finished, 44 | [e.on_research_started] = on_research_started, 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/gui/debug/model.lua: -------------------------------------------------------------------------------- 1 | local Gui = require("modules.exp_legacy.utils.gui") --- @dep utils.gui 2 | local ExpUtil = require("modules/exp_util") 3 | 4 | local concat = table.concat 5 | local inspect = table.inspect 6 | local pcall = pcall 7 | local loadstring = loadstring --- @diagnostic disable-line 8 | local rawset = rawset 9 | 10 | local Public = {} 11 | 12 | local inspect_process = ExpUtil.safe_value 13 | 14 | local inspect_options = { process = inspect_process } 15 | function Public.dump(data) 16 | return inspect(data, inspect_options) 17 | end 18 | 19 | local dump = Public.dump 20 | 21 | function Public.dump_ignore_builder(ignore) 22 | local function process(item) 23 | if ignore[item] then 24 | return nil 25 | end 26 | 27 | return inspect_process(item) 28 | end 29 | 30 | local options = { process = process } 31 | return function(data) 32 | return inspect(data, options) 33 | end 34 | end 35 | 36 | function Public.dump_function(func) 37 | local res = { "upvalues:\n", "no longer available" } 38 | 39 | local i = 1 40 | --[[while true do 41 | local n, v = debug.getupvalue(func, i) 42 | 43 | if n == nil then 44 | break 45 | elseif n ~= "_ENV" then 46 | res[#res + 1] = n 47 | res[#res + 1] = " = " 48 | res[#res + 1] = dump(v) 49 | res[#res + 1] = "\n" 50 | end 51 | 52 | i = i + 1 53 | end]] 54 | 55 | return concat(res) 56 | end 57 | 58 | function Public.dump_text(text, player) 59 | local func = loadstring("return " .. text) 60 | if not func then 61 | return false 62 | end 63 | 64 | local suc, var = pcall(func) 65 | 66 | if not suc then 67 | return false 68 | end 69 | 70 | return true, dump(var) 71 | end 72 | 73 | return Public 74 | -------------------------------------------------------------------------------- /exp_scenario/module/control/damage_popups.lua: -------------------------------------------------------------------------------- 1 | --[[-- Control - Damage PopUps 2 | Displays the amount of dmg that is done by players to entities; 3 | also shows player health when a player is attacked 4 | ]] 5 | 6 | local FlyingText = require("modules/exp_util/flying_text") 7 | local config = require("modules.exp_legacy.config.popup_messages") 8 | 9 | local random = math.random 10 | local floor = math.floor 11 | local max = math.max 12 | 13 | --- Called when entity entity is damaged including the player character 14 | --- @param event EventData.on_entity_damaged 15 | local function on_entity_damaged(event) 16 | local message 17 | local cause = event.cause 18 | local entity = event.entity 19 | 20 | -- Check which message to display 21 | if config.show_player_health and entity.name == "character" then 22 | message = { "exp_damage-popup.flying-text-health", floor(entity.health) } 23 | elseif config.show_player_damage and entity.name ~= "character" and cause and cause.name == "character" then 24 | message = { "exp_damage-popup.flying-text-damage", floor(event.original_damage_amount) } 25 | end 26 | 27 | -- Outputs the message as floating text 28 | if message then 29 | local entity_radius = max(1, entity.get_radius()) 30 | local offset = (random() - 0.5) * entity_radius * config.damage_location_variance 31 | local position = { x = entity.position.x + offset, y = entity.position.y - entity_radius } 32 | 33 | local health_percentage = entity.get_health_ratio() 34 | local color = { r = 1 - health_percentage, g = health_percentage, b = 0 } 35 | 36 | FlyingText.create{ 37 | text = message, 38 | position = position, 39 | color = color, 40 | } 41 | end 42 | end 43 | 44 | local e = defines.events 45 | 46 | return { 47 | events = { 48 | [e.on_entity_damaged] = on_entity_damaged, 49 | }, 50 | } 51 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/data/greetings.lua: -------------------------------------------------------------------------------- 1 | --- Greets players on join 2 | -- @data Greetings 3 | 4 | local config = require("modules.exp_legacy.config.join_messages") --- @dep config.join_messages 5 | local Commands = require("modules/exp_commands") 6 | 7 | --- Stores the join message that the player have 8 | local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data 9 | local CustomMessages = PlayerData.Settings:combine("JoinMessage") 10 | CustomMessages:set_metadata{ 11 | permission = "command/join-message", 12 | } 13 | 14 | --- When a players data loads show their message 15 | CustomMessages:on_load(function(player_name, player_message) 16 | local player = game.players[player_name] 17 | local custom_message = player_message or config[player_name] 18 | if custom_message then 19 | game.print(custom_message, { color = player.color }) 20 | else 21 | player.print{ "join-message.greet", { "links.discord" } } 22 | end 23 | end) 24 | 25 | --- Set your custom join message 26 | Commands.new("set-join-message", { "join-message.description-add" }) 27 | :optional("message", false, Commands.types.string_max_length(255)) 28 | :enable_auto_concatenation() 29 | :add_aliases{ "join-message" } 30 | :register(function(player, message) 31 | --- @cast message string? 32 | if message then 33 | CustomMessages:set(player, message) 34 | return Commands.status.success{ "join-message.message-set" } 35 | else 36 | return Commands.status.success{ "join-message.message-get", CustomMessages:get(player) } 37 | end 38 | end) 39 | 40 | --- Removes your custom join message 41 | Commands.new("remove-join-message", { "join-message.description-remove" }) 42 | :register(function(player) 43 | CustomMessages:remove(player) 44 | return Commands.status.success{ "join-message.message-cleared" } 45 | end) 46 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/graftorio/general.lua: -------------------------------------------------------------------------------- 1 | local Event = require("modules/exp_legacy/utils/event") 2 | local Storage = require("modules/exp_util/storage") 3 | 4 | local lib = {} 5 | 6 | lib.data = { 7 | output = {}, 8 | } 9 | 10 | Storage.register(lib.data, function(tbl) 11 | lib.data = tbl 12 | end) 13 | 14 | --- @class Statistics 15 | --- @field production ProductionStatistics? 16 | --- @field robots RobotStatistics? 17 | --- @field other OtherStatistics? 18 | --- @field research Research[]? 19 | 20 | Event.on_init(function() 21 | --- @type table 22 | lib.data.output = {} 23 | for _, force in pairs(game.forces) do 24 | lib.data.output[force.name] = {} 25 | end 26 | end) 27 | 28 | --- @class OtherStatistics 29 | --- @field tick uint 30 | --- @field evolution EvolutionStatistics 31 | 32 | --- @class EvolutionStatistics 33 | --- @field evolution_factor double 34 | --- @field evolution_factor_by_pollution double 35 | --- @field evolution_factor_by_time double 36 | --- @field evolution_factor_by_killing_spawners double 37 | 38 | lib.collect_other = function() 39 | for _, force in pairs(game.forces) do 40 | --- @type OtherStatistics 41 | local other = lib.data.output[force.name].other or {} 42 | 43 | other.evolution = { 44 | evolution_factor = force.get_evolution_factor(game.surfaces[1]), 45 | evolution_factor_by_pollution = force.get_evolution_factor_by_pollution(game.surfaces[1]), 46 | evolution_factor_by_time = force.get_evolution_factor_by_time(game.surfaces[1]), 47 | evolution_factor_by_killing_spawners = force.get_evolution_factor_by_killing_spawners(game.surfaces[1]), 48 | } 49 | for k, v in pairs(other) do 50 | lib.data.output[force.name].other[k] = v 51 | end 52 | end 53 | end 54 | 55 | Event.add(defines.events.on_force_created, function(evt) 56 | lib.data.output[evt.force.name] = {} 57 | end) 58 | 59 | Event.add(defines.events.on_forces_merged, function(evt) 60 | lib.data.output[evt.source_name] = nil 61 | end) 62 | 63 | return lib 64 | -------------------------------------------------------------------------------- /exp_legacy/module/locale/en/addons.cfg: -------------------------------------------------------------------------------- 1 | [links] 2 | discord=https://discord.explosivegaming.nl 3 | website=https://www.explosivegaming.nl 4 | status=https://status.explosivegaming.nl 5 | github=https://github.com/explosivegaming/ExpCluster 6 | patreon=https://www.patreon.com/ExpGaming 7 | 8 | [info] 9 | players-online=There are __1__ players online 10 | total-map-time=This map has been on for __1__ 11 | discord=Join us on our discord at: https://discord.explosivegaming.nl 12 | website=Please visit our website at: https://www.explosivegaming.nl 13 | status=Want to check if out servers are down? Visit: https://status.explosivegaming.nl 14 | github=Want to help improve our server with some extra features? Help us at: https://github.com/explosivegaming/ExpCluster 15 | patreon=Consider supporting our server at: https://www.patreon.com/ExpGaming 16 | custom-commands=We use custom commands, such as /tag and /me, use /chelp for more info. 17 | read-readme=Make sure you have read the information gui (It can be found through the info mark on the top left) 18 | softmod=We run a softmod on our servers. A softmod is a custom scenario that runs on this server, an example is the player list. 19 | redmew=We don't talk about redmew here; they beat us to 1000 members ;-; 20 | lhd=All trains must be LHD! This is a long standing rule on our servers, please respect this. 21 | 22 | [warnings] 23 | received=You received a warning from __1__. You have __2__ warnings. __3__ 24 | pre-kick=This is your last warning before you are kicked. 25 | kick=You were kicked for having too many warnings; you may rejoin if you wish. 26 | pre-pre-ban=You are close to receiving a ban; successful ban appeals are unlikely. 27 | pre-ban=This your LAST warning before you are BANNED! Successful ban appeals are unlikely. 28 | ban=You were banned for having too many warnings; visit __1__ to request a ban appeal. 29 | script-warning=You are receiving script warnings; if you recive too many you will receive a permanent warning (__1__/__2__) 30 | script-warning-removed=A script warning has expired (__1__/__2__) 31 | script-warning-limit=__1__ has received a permanent warning from the script. 32 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/jail.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Jail 2 | Adds a commands that allow admins to jail and unjail 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local format_player_name = Commands.format_player_name_locale 7 | 8 | local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail 9 | 10 | --- Puts a player into jail and removes all other roles. 11 | Commands.new("jail", { "exp-commands_jail.description" }) 12 | :argument("player", { "exp-commands_jail.arg-player" }, Commands.types.lower_role_player) 13 | :optional("reason", { "exp-commands_jail.arg-reason" }, Commands.types.string) 14 | :enable_auto_concatenation() 15 | :register(function(player, other_player, reason) 16 | --- @cast other_player LuaPlayer 17 | --- @cast reason string? 18 | if not reason then 19 | reason = "None Given." 20 | end 21 | 22 | local player_name = format_player_name(player) 23 | local other_player_name = format_player_name(other_player) 24 | if Jail.jail_player(other_player, player.name, reason) then 25 | game.print{ "exp-commands_jail.jailed", other_player_name, player_name, reason } 26 | else 27 | return Commands.status.error{ "exp-commands_jail.already-jailed", other_player_name } 28 | end 29 | end) 30 | 31 | --- Removes a player from jail and restores their old roles. 32 | Commands.new("unjail", { "exp-commands_unjail.description" }) 33 | :argument("player", { "exp-commands_unjail.arg-player" }, Commands.types.lower_role_player) 34 | :register(function(player, other_player) 35 | --- @cast other_player LuaPlayer 36 | local player_name = format_player_name(player) 37 | local other_player_name = format_player_name(other_player) 38 | if Jail.unjail_player(other_player, player.name) then 39 | game.print{ "exp-commands_unjail.unjailed", other_player_name, player_name } 40 | else 41 | return Commands.status.error{ "exp-commands_unjail.not-jailed", other_player_name } 42 | end 43 | end) 44 | -------------------------------------------------------------------------------- /exp_legacy/module/control.lua: -------------------------------------------------------------------------------- 1 | --- Please go to ./config if you want to change settings, each file is commented with what it does 2 | -- if it is not in ./config then you should not attempt to change it unless you know what you are doing 3 | -- all files which are loaded (including the config files) are present in ./config/file_loader.lua 4 | -- this file is the landing point for all scenarios please DO NOT edit directly, further comments are to aid development 5 | 6 | log("[START] -----| Explosive Gaming Scenario Loader |-----") 7 | log("[INFO] Setting up lua environment") 8 | 9 | -- Please go to config/file_loader.lua to edit the files that are loaded 10 | log("[INFO] Reading loader config") 11 | local files = require("modules.exp_legacy.config._file_loader") 12 | 13 | -- Error handler for loading files 14 | local errors = {} 15 | local error_count = 0 16 | local error_format = "[ERROR] %s :: %s" 17 | local currently_loading = nil 18 | local function error_handler(err) 19 | error_count = error_count + 1 20 | if err:find("module " .. currently_loading .. " not found;", nil, true) then 21 | log("[ERROR] File not found: " .. currently_loading) 22 | errors[error_count] = error_format:format(currently_loading, err) 23 | else 24 | log("[ERROR] Failed to load: " .. currently_loading) 25 | errors[error_count] = debug.traceback(error_format:format(currently_loading, err)) 26 | end 27 | return err 28 | end 29 | 30 | -- Loads all files from the config and logs that they are loaded 31 | local total_file_count = string.format("%3d", #files) 32 | for index, path in pairs(files) do 33 | currently_loading = path 34 | log(string.format("[INFO] Loading file %3d/%s (%s)", index, total_file_count, path)) 35 | xpcall(require, error_handler, "modules.exp_legacy." .. path) 36 | end 37 | 38 | -- Logs all errors again to make it make it easy to find 39 | log("[INFO] All files loaded with " .. error_count .. " errors:") 40 | for _, error in ipairs(errors) do log(error) end 41 | 42 | log("[END] -----| Explosive Gaming Scenario Loader |-----") 43 | 44 | --- Register all event handlers via event handler 45 | local Event = require("modules/exp_legacy/utils/event") 46 | return Event.real_handlers 47 | -------------------------------------------------------------------------------- /exp_scenario/module/control/nuke_protection.lua: -------------------------------------------------------------------------------- 1 | --[[-- Control - Nuke Protection 2 | Disable new players from having certain items in their inventory, most commonly nukes 3 | ]] 4 | 5 | local ExpUtil = require("modules/exp_util") 6 | local Roles = require("modules.exp_legacy.expcore.roles") 7 | local config = require("modules.exp_legacy.config.nukeprotect") 8 | 9 | --- Check all items in the given inventory 10 | --- @param player LuaPlayer 11 | --- @param type defines.inventory 12 | --- @param banned_items string[] 13 | local function check_items(player, type, banned_items) 14 | -- If the player has perms to be ignored, then they should be 15 | if config.ignore_permission and Roles.player_allowed(player, config.ignore_permission) then return end 16 | if config.ignore_admins and player.admin then return end 17 | 18 | local items = {} --- @type LuaItemStack[] 19 | local inventory = assert(player.get_inventory(type)) 20 | -- Check what items the player has 21 | for i = 1, #inventory do 22 | local item = inventory[i] 23 | if item.valid_for_read and banned_items[item.name] then 24 | player.print{ "exp_nuke-protection.chat-found", item.prototype.localised_name } 25 | items[#items + 1] = item 26 | end 27 | end 28 | 29 | -- Move any items they aren't allowed 30 | ExpUtil.move_items_to_surface{ 31 | items = items, 32 | surface = game.planets.nauvis.surface, 33 | allow_creation = true, 34 | name = "iron-chest", 35 | } 36 | end 37 | 38 | --- Add event handlers for the different inventories 39 | local events = {} 40 | for index, inventory in ipairs(config.inventories) do 41 | if next(inventory.items) then 42 | local assert_msg = "invalid event, no player index, index: " .. index 43 | --- @param event { player_index: number } 44 | events[inventory.event] = function(event) 45 | local player_index = assert(event.player_index, assert_msg) 46 | local player = assert(game.get_player(player_index)) 47 | if player and player.valid then 48 | check_items(player, inventory.inventory, inventory.items) 49 | end 50 | end 51 | end 52 | end 53 | 54 | return { 55 | events = events, 56 | } 57 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/ratio.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Ratio 2 | Adds a command to calculate the number of machines needed to fulfil a desired production 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | 7 | Commands.new("ratio", { "exp-commands_ratio.description" }) 8 | :optional("items-per-second", { "exp-commands_ratio.arg-items-per-second" }, Commands.types.number) 9 | :register(function(player, items_per_second) 10 | --- @cast items_per_second number? 11 | 12 | local machine = player.selected 13 | if not machine then 14 | return Commands.status.error{ "exp-commands_ratio.not-selecting" } 15 | end 16 | 17 | if machine.type ~= "assembling-machine" and machine.type ~= "furnace" then 18 | return Commands.status.error{ "exp-commands_ratio.not-selecting" } 19 | end 20 | 21 | local recipe = machine.get_recipe() 22 | if not recipe then 23 | return Commands.status.error{ "exp-commands_ratio.not-selecting" } 24 | end 25 | 26 | local products = recipe.products 27 | local ingredients = recipe.ingredients 28 | local crafts_per_second = machine.crafting_speed * machine.productivity_bonus / recipe.energy 29 | 30 | local amount_of_machines = 1 31 | if items_per_second then 32 | amount_of_machines = math.ceil(products[1].amount * crafts_per_second) 33 | end 34 | 35 | for _, ingredient in ipairs(ingredients) do 36 | Commands.print{ 37 | ingredient.type == "item" and "exp-commands_ratio.item-out" or "exp-commands_ratio.fluid-out", 38 | math.round(ingredient.amount * crafts_per_second, 3), 39 | ingredient.name 40 | } 41 | end 42 | 43 | for i, product in ipairs(products) do 44 | Commands.print{ 45 | product.type == "item" and "exp-commands_ratio.item-out" or "exp-commands_ratio.fluid-out", 46 | math.round(product.amount * crafts_per_second, 3), 47 | product.name 48 | } 49 | end 50 | 51 | if amount_of_machines ~= 1 then 52 | Commands.print{ "exp-commands_ratio.machine-count", amount_of_machines } 53 | end 54 | end) 55 | -------------------------------------------------------------------------------- /exp_server_ups/instance.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | import { BaseInstancePlugin } from "@clusterio/host"; 3 | 4 | export class InstancePlugin extends BaseInstancePlugin { 5 | private updateInterval?: ReturnType; 6 | private gameTimes: number[] = []; 7 | 8 | async onStart() { 9 | if (!this.instance.config.get("factorio.settings")["auto_pause"]) { 10 | this.setInterval(); 11 | } 12 | } 13 | 14 | onExit() { 15 | this.clearInterval(); 16 | } 17 | 18 | async onInstanceConfigFieldChanged(field: string, curr: unknown): Promise { 19 | if (field === "exp_server_ups.update_interval") { 20 | this.clearInterval(); 21 | this.setInterval(); 22 | } else if (field === "exp_server_ups.average_interval") { 23 | this.gameTimes.splice(curr as number); 24 | } 25 | } 26 | 27 | async onPlayerEvent(event: lib.PlayerEvent): Promise { 28 | if (event.type === "join") { 29 | this.setInterval(); 30 | } else if (event.type === "leave" && this.instance.playersOnline.size == 0 && this.instance.config.get("factorio.settings")["auto_pause"]) { 31 | this.clearInterval(); 32 | } 33 | } 34 | 35 | setInterval() { 36 | if (!this.updateInterval) { 37 | this.updateInterval = setInterval(this.updateUps.bind(this), this.instance.config.get("exp_server_ups.update_interval")); 38 | } 39 | } 40 | 41 | clearInterval() { 42 | if (this.updateInterval) { 43 | clearInterval(this.updateInterval); 44 | this.updateInterval = undefined; 45 | } 46 | } 47 | 48 | async updateUps() { 49 | let ups = 0; 50 | const collected = this.gameTimes.length - 1; 51 | if (collected > 0) { 52 | const minTick = this.gameTimes[0]; 53 | const maxTick = this.gameTimes[collected]; 54 | const interval = this.instance.config.get("exp_server_ups.update_interval") / 1000; 55 | ups = (maxTick - minTick) / (collected * interval); 56 | } 57 | 58 | try { 59 | const newGameTime = await this.sendRcon(`/_rcon return exp_server_ups.refresh(${ups})`); 60 | this.gameTimes.push(Number(newGameTime)); 61 | } catch (error: any) { 62 | this.logger.error(`Failed to receive new game time: ${error}`); 63 | } 64 | 65 | if (collected > this.instance.config.get("exp_server_ups.average_interval")) { 66 | this.gameTimes.shift(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /exp_legacy/module/config/warnings.lua: -------------------------------------------------------------------------------- 1 | --- Config file for the warning system, this is very similar to reports but is for the use of moderators rather than normal users. 2 | -- @config Warnings 3 | 4 | return { 5 | actions = { --- @setting actions what actions are taking at number of warnings 6 | -- if a localized string is used then __1__ will by_player_name and __2__ will be the current warning count (auto inserted) 7 | { "warnings.received", "" }, 8 | { "warnings.received", "" }, 9 | { "warnings.received", { "warnings.pre-kick" } }, 10 | function(player, by_player_name, number_of_warnings) 11 | local str = { 12 | "You received a warning from ", 13 | by_player_name, 14 | ". You have ", 15 | number_of_warnings, 16 | " warnings. You were kicked for having too many warnings; you may rejoin if you wish.", 17 | } 18 | game.kick_player(player, table.concat(str, "")) -- Does not support locale strings 19 | -- game.kick_player(player, { "warnings.received", by_player_name, number_of_warnings, { "warnings.kick" } }) 20 | end, 21 | { "warnings.received", { "warnings.pre-pre-ban" } }, 22 | { "warnings.received", { "warnings.pre-ban" } }, 23 | function(player, by_player_name, number_of_warnings) 24 | local str = { 25 | "You received a warning from ", 26 | by_player_name, 27 | ". You have ", 28 | number_of_warnings, 29 | " warnings. You were banned for having too many warnings; visit https://www.explosivegaming.nl to request a ban appeal.", 30 | } 31 | game.kick_player(player, table.concat(str, "")) -- Does not support locale strings 32 | -- game.ban_player(player, { "warnings.received", by_player_name, number_of_warnings, { "warnings.ban", { "links.website" } } }) 33 | end, 34 | }, 35 | script_warning_cool_down = 30, --- @setting script_warning_cool_down time for a script warning (given by script) to be removed (in minutes) 36 | script_warning_limit = 5, --- @setting script_warning_limit the number of script warnings (given by script) that are allowed before full warnings are given 37 | } 38 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/lawnmower.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Lawnmower 2 | Adds a command that clean up biter corpse and nuclear hole 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local config = require("modules.exp_legacy.config.lawnmower") --- @dep config.lawnmower 7 | 8 | Commands.new("lawnmower", { "exp-commands_lawnmower.description" }) 9 | :argument("range", { "exp-commands_lawnmower.arg-range" }, Commands.types.integer_range(1, 200)) 10 | :register(function(player, range) 11 | --- @cast range number 12 | local surface = player.surface 13 | 14 | -- Intentionally left as player.position to allow use in remote view 15 | local entities = surface.find_entities_filtered{ position = player.position, radius = range, type = "corpse" } 16 | for _, entity in pairs(entities) do 17 | if (entity.name ~= "transport-caution-corpse" and entity.name ~= "invisible-transport-caution-corpse") then 18 | entity.destroy() 19 | end 20 | end 21 | 22 | local replace_tiles = {} 23 | local tiles = surface.find_tiles_filtered{ position = player.position, radius = range, name = { "nuclear-ground" } } 24 | for i, tile in pairs(tiles) do 25 | replace_tiles[i] = { name = "grass-1", position = tile.position } 26 | end 27 | 28 | surface.set_tiles(replace_tiles) 29 | surface.destroy_decoratives{ position = player.position, radius = range } 30 | end) 31 | 32 | --- @param event EventData.on_built_entity | EventData.on_robot_built_entity | EventData.script_raised_built | EventData.script_raised_revive 33 | local function destroy_decoratives(event) 34 | local entity = event.entity 35 | if entity.type ~= "entity-ghost" and entity.type ~= "tile-ghost" and entity.prototype.selectable_in_game then 36 | entity.surface.destroy_decoratives{ area = entity.selection_box } 37 | end 38 | end 39 | 40 | local e = defines.events 41 | local events = {} 42 | 43 | if config.destroy_decoratives then 44 | events[e.on_built_entity] = destroy_decoratives 45 | events[e.on_robot_built_entity] = destroy_decoratives 46 | events[e.script_raised_built] = destroy_decoratives 47 | events[e.script_raised_revive] = destroy_decoratives 48 | end 49 | 50 | return { 51 | events = events 52 | } 53 | -------------------------------------------------------------------------------- /exp_scenario/web/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { 2 | useContext, useEffect, useState, 3 | useCallback, useSyncExternalStore, 4 | } from "react"; 5 | 6 | // import { 7 | // 8 | // } from "antd"; 9 | 10 | import { 11 | BaseWebPlugin, PageLayout, PageHeader, Control, ControlContext, notifyErrorHandler, 12 | } from "@clusterio/web_ui"; 13 | 14 | import { 15 | PluginExampleEvent, PluginExampleRequest, 16 | ExampleSubscribableUpdate, ExampleSubscribableValue, 17 | } from "../messages"; 18 | 19 | import * as lib from "@clusterio/lib"; 20 | 21 | function MyTemplatePage() { 22 | const control = useContext(ControlContext); 23 | const plugin = control.plugins.get("exp_scenario") as WebPlugin; 24 | const [subscribableData, synced] = plugin.useSubscribableData(); 25 | 26 | return 27 | 28 | Synced: {String(synced)} Data: {JSON.stringify([...subscribableData.values()])} 29 | ; 30 | } 31 | 32 | export class WebPlugin extends BaseWebPlugin { 33 | subscribableData = new lib.EventSubscriber(ExampleSubscribableUpdate, this.control); 34 | 35 | async init() { 36 | this.pages = [ 37 | { 38 | path: "/exp_scenario", 39 | sidebarName: "exp_scenario", 40 | // This permission is client side only, so it must match the permission string of a resource request to be secure 41 | // An undefined value means that the page will always be visible 42 | permission: "exp_scenario.example.permission.subscribe", 43 | content: , 44 | }, 45 | ]; 46 | 47 | this.control.handle(PluginExampleEvent, this.handlePluginExampleEvent.bind(this)); 48 | this.control.handle(PluginExampleRequest, this.handlePluginExampleRequest.bind(this)); 49 | } 50 | 51 | useSubscribableData() { 52 | const control = useContext(ControlContext); 53 | const subscribe = useCallback((callback: () => void) => this.subscribableData.subscribe(callback), [control]); 54 | return useSyncExternalStore(subscribe, () => this.subscribableData.getSnapshot()); 55 | } 56 | 57 | async handlePluginExampleEvent(event: PluginExampleEvent) { 58 | this.logger.info(JSON.stringify(event)); 59 | } 60 | 61 | async handlePluginExampleRequest(request: PluginExampleRequest) { 62 | this.logger.info(JSON.stringify(request)); 63 | return { 64 | myResponseString: request.myString, 65 | myResponseNumbers: request.myNumberArray, 66 | }; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/repair.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Repair 2 | Adds a command that allows an admin to repair and revive a large area 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local config = require("modules.exp_legacy.config.repair") --- @dep config.repair 7 | 8 | --- Repairs entities on your force around you 9 | Commands.new("repair", { "exp-commands_repair.description" }) 10 | :argument("range", { "exp-commands_repair.arg-range" }, Commands.types.integer_range(1, config.max_range)) 11 | :register(function(player, range) 12 | --- @cast range number 13 | local force = player.force 14 | local surface = player.surface -- Allow remote view 15 | local position = player.position -- Allow remote view 16 | local response = { "" } --- @type LocalisedString 17 | 18 | if config.allow_ghost_revive then 19 | local revive_count = 0 20 | local entities = surface.find_entities_filtered{ 21 | type = "entity-ghost", 22 | position = position, 23 | radius = range, 24 | force = force, 25 | } 26 | 27 | local param = { raise_revive = true } --- @type LuaEntity.silent_revive_param 28 | for _, entity in ipairs(entities) do 29 | if not config.disallow[entity.ghost_name] and (config.allow_blueprint_repair or entity.created_by_corpse) then 30 | revive_count = revive_count + 1 31 | entity.silent_revive(param) 32 | end 33 | end 34 | 35 | response[#response + 1] = { "exp-commands_repair.response-revive", revive_count } 36 | end 37 | 38 | if config.allow_heal_entities then 39 | local healed_count = 0 40 | local entities = surface.find_entities_filtered{ 41 | position = position, 42 | radius = range, 43 | force = force, 44 | } 45 | 46 | for _, entity in ipairs(entities) do 47 | if entity.health and entity.max_health and entity.health ~= entity.max_health then 48 | healed_count = healed_count + 1 49 | entity.health = entity.max_health 50 | end 51 | end 52 | 53 | response[#response + 1] = { "exp-commands_repair.response-heal", healed_count } 54 | end 55 | 56 | return Commands.status.success(response) 57 | end) 58 | -------------------------------------------------------------------------------- /exp_scenario/module/control/chat_auto_reply.lua: -------------------------------------------------------------------------------- 1 | --[[-- Control - Chat Auto Reply 2 | Adds auto replies to chat messages, as well as chat commands 3 | ]] 4 | 5 | local Roles = require("modules.exp_legacy.expcore.roles") 6 | local config = require("modules.exp_legacy.config.chat_reply") 7 | local prefix = config.command_prefix 8 | local prefix_len = string.len(prefix) 9 | 10 | local find = string.find 11 | local sub = string.sub 12 | 13 | --- Check if a message has any trigger words 14 | --- @param event EventData.on_console_chat 15 | local function on_console_chat(event) 16 | if not event.player_index then return end 17 | local player = assert(game.get_player(event.player_index)) 18 | local message = event.message:lower():gsub("%s+", "") 19 | 20 | -- Check if the player can chat commands 21 | local commands_allowed = true 22 | if config.command_admin_only and not player.admin then commands_allowed = false end 23 | if config.command_permission and not Roles.player_allowed(player, config.command_permission) then commands_allowed = false end 24 | 25 | -- Check if a key word appears in the message 26 | for key_word, reply in pairs(config.messages) do 27 | local start_pos = find(message, key_word) 28 | if start_pos then 29 | local is_command = sub(message, start_pos - prefix_len - 1, start_pos - 1) == prefix 30 | if type(reply) == "function" then 31 | reply = reply(player, is_command) 32 | end 33 | 34 | if is_command and commands_allowed then 35 | game.print{ "exp_chat-auto-reply.chat-reply", reply } 36 | elseif is_command then 37 | player.print{ "exp_chat-auto-reply.chat-disallowed" } 38 | elseif not commands_allowed then 39 | player.print{ "exp_chat-auto-reply.chat-reply", reply } 40 | end 41 | end 42 | end 43 | 44 | if not commands_allowed then return end 45 | 46 | -- Check if a command appears in the message 47 | for key_word, reply in pairs(config.commands) do 48 | if find(message, prefix .. key_word) then 49 | if type(reply) == "function" then 50 | reply = reply(player, true) 51 | end 52 | game.print{ "exp_chat-auto-reply.chat-reply", reply } 53 | end 54 | end 55 | end 56 | 57 | local e = defines.events 58 | 59 | return { 60 | events = { 61 | [e.on_console_chat] = on_console_chat, 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /exp_commands/module/locale/en.cfg: -------------------------------------------------------------------------------- 1 | [exp-commands] 2 | help=__1__- __2____3__ 3 | usage=/__1__ __2__ 4 | aliases=\n Aliaies: __1__ 5 | argument=<__1__> 6 | optional=[__1__] 7 | argument-verbose=\n <__1__> - __2__ 8 | optional-verbose=\n [__1__] - __2__ 9 | success=Command Complete. 10 | error=Command failed to run: __1__ 11 | error-default=Please check you gave the correct arguments. 12 | unauthorized=Unauthorized: __1__ 13 | unauthorized-default=Access is denied due to insufficient permissions. 14 | invalid-usage=Wrong number of arguments, usage: __1__ 15 | invalid-input=Invalid input: Please ensure everything is formated correctly. 16 | invalid-argument=Invalid argument "__1__"; __2__ 17 | internal-error=Internal Error, Please contact an admin: __1__ 18 | 19 | [exp-commands-parse] 20 | string-options=Invalid Option, Must be one of: __1__ 21 | string-max-length=Invalid Length, Max: __1__ 22 | number=Invalid Number. 23 | number-range=Invalid Range, Min (inclusive): __1__, Max (inclusive): __2__ 24 | player=Invalid Player Name, __1__ ,try using tab key to auto-complete the name 25 | player-online=Player is offline. 26 | player-alive=Player is dead. 27 | force=Invalid Force Name. 28 | surface=Invalid Surface Name. 29 | planet=Invalid Planet Name. 30 | color=Invalid Color Name. 31 | 32 | [exp-commands-authorities] 33 | character-only=This command can not be used in remote view. 34 | remote-only=This command can only be used in remote view. 35 | admin-only=This command is for game admins only. 36 | system-only=This command can not be ran by players. 37 | disabled=This command is currently disabled. 38 | 39 | [exp-commands_help] 40 | description=List and search all commands for a keyword 41 | arg-keyword=The keyword to search for 42 | arg-page=The results page to display 43 | header=Help results for "__1__": 44 | footer=[__1__ results found: page __2__ of __3__] 45 | format=/__1__ __2__ __3__ 46 | aliases=Aliaies: __1__ 47 | out-of-range=__1__ is an invalid page number. Last page: __2__ 48 | no-results=No commands were found 49 | 50 | [exp-commands_ipc] 51 | description=Send an IPC message on the selected channel 52 | arg-channel=The channel to send the IPC message on 53 | arg-message=The message to send on the IPC channel 54 | 55 | [exp-commands_rcon] 56 | description=Execute arbitrary code within a custom environment 57 | arg-invocation=The code to run 58 | 59 | [exp-commands_sudo] 60 | description=Run a command as another player 61 | arg-player=The player to run the command as 62 | arg-command=The command to run 63 | arg-arguments=The arguments to pass to the command 64 | -------------------------------------------------------------------------------- /type.patch.lua: -------------------------------------------------------------------------------- 1 | ---@meta 2 | 3 | ---@class script 4 | script = { 5 | ---Raise an event. Only events generated with [LuaBootstrap::generate\_event\_name](https://lua-api.factorio.com/latest/classes/LuaBootstrap.html#generate_event_name) and the following can be raised: 6 | --- 7 | ---Events that can be raised manually: 8 | --- 9 | ---* [on\_console\_chat](https://lua-api.factorio.com/latest/events.html#on_console_chat) 10 | ---* [on\_player\_crafted\_item](https://lua-api.factorio.com/latest/events.html#on_player_crafted_item) 11 | ---* [on\_player\_fast\_transferred](https://lua-api.factorio.com/latest/events.html#on_player_fast_transferred) 12 | ---* [on\_biter\_base\_built](https://lua-api.factorio.com/latest/events.html#on_biter_base_built) 13 | ---* [on\_market\_item\_purchased](https://lua-api.factorio.com/latest/events.html#on_market_item_purchased) 14 | ---* [script\_raised\_built](https://lua-api.factorio.com/latest/events.html#script_raised_built) 15 | ---* [script\_raised\_destroy](https://lua-api.factorio.com/latest/events.html#script_raised_destroy) 16 | ---* [script\_raised\_revive](https://lua-api.factorio.com/latest/events.html#script_raised_revive) 17 | ---* [script\_raised\_teleported](https://lua-api.factorio.com/latest/events.html#script_raised_teleported) 18 | ---* [script\_raised\_set\_tiles](https://lua-api.factorio.com/latest/events.html#script_raised_set_tiles) 19 | --- 20 | ---### Example 21 | --- 22 | ---``` 23 | ----- Raise the on_console_chat event with the desired message 'from' the first player 24 | ---local data = {player_index = 1, message = "Hello friends!"} 25 | ---script.raise_event(defines.events.on_console_chat, data) 26 | ---``` 27 | --- 28 | ---[View Documentation](https://lua-api.factorio.com/latest/classes/LuaBootstrap.html#raise_event) 29 | --- 30 | --- Type patched in 2.0.28: [Bug Report](https://forums.factorio.com/viewtopic.php?f=233&t=125062) 31 | --- Changed "event" from "string | integer" to "LuaEventType" 32 | --- Resolved in 2.0.29, this patch will be removed was version is stable 33 | ---@param event LuaEventType ID or name of the event to raise. 34 | ---@param data table Table with extra data that will be passed to the event handler. Any invalid LuaObjects will silently stop the event from being raised. 35 | raise_event = function(event, data) end; 36 | } 37 | 38 | ---@class LuaObject:userdata 39 | --https://github.com/justarandomgeek/vscode-factoriomod-debug/issues/165 40 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/data/quickbar.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands Module - Quickbar 2 | - Adds a command that allows players to load Quickbar presets 3 | @data Quickbar 4 | ]] 5 | 6 | local Commands = require("modules/exp_commands") 7 | local config = require("modules.exp_legacy.config.preset_player_quickbar") --- @dep config.preset_player_quickbar 8 | 9 | --- Stores the quickbar filters for a player 10 | local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data 11 | local PlayerFilters = PlayerData.Settings:combine("QuickbarFilters") 12 | PlayerFilters:set_metadata{ 13 | permission = "command/save-quickbar", 14 | stringify = function(value) 15 | if not value then return "No filters set" end 16 | local count = 0 17 | for _ in pairs(value) do count = count + 1 end 18 | 19 | return count .. " filters set" 20 | end, 21 | } 22 | 23 | --- Loads your quickbar preset 24 | PlayerFilters:on_load(function(player_name, filters) 25 | if not filters then filters = config[player_name] end 26 | if not filters then return end 27 | local player = game.players[player_name] 28 | for i, item_name in pairs(filters) do 29 | if item_name ~= nil and item_name ~= "" then 30 | player.set_quick_bar_slot(i, item_name) 31 | end 32 | end 33 | end) 34 | 35 | local ignored_items = { 36 | ["blueprint"] = true, 37 | ["blueprint-book"] = true, 38 | ["deconstruction-planner"] = true, 39 | ["spidertron-remote"] = true, 40 | ["upgrade-planner"] = true, 41 | } 42 | 43 | --- Saves your quickbar preset to the script-output folder 44 | Commands.new("save-quickbar", "Saves your Quickbar preset items to file") 45 | :add_aliases{ "save-toolbar" } 46 | :register(function(player) 47 | local filters = {} 48 | 49 | for i = 1, 100 do 50 | local slot = player.get_quick_bar_slot(i) 51 | -- Need to filter out blueprint and blueprint books because the slot is a LuaItemPrototype and does not contain a way to export blueprint data 52 | if slot ~= nil then 53 | local ignored = ignored_items[slot.name] 54 | if ignored ~= true then 55 | filters[i] = slot.name 56 | end 57 | end 58 | end 59 | 60 | if next(filters) then 61 | PlayerFilters:set(player, filters) 62 | else 63 | PlayerFilters:remove(player) 64 | end 65 | 66 | return Commands.status.success{ "quickbar.saved" } 67 | end) 68 | -------------------------------------------------------------------------------- /exp_groups/index.ts: -------------------------------------------------------------------------------- 1 | import * as lib from "@clusterio/lib"; 2 | import * as Messages from "./messages"; 3 | 4 | lib.definePermission({ 5 | name: "exp_groups.create_delete_groups", 6 | title: "Create and delete permission groups", 7 | description: "Create and delete permission groups.", 8 | }); 9 | 10 | lib.definePermission({ 11 | name: "exp_groups.reorder_groups", 12 | title: "Reorder permission groups", 13 | description: "Reorder groups and link them to user roles.", 14 | }); 15 | 16 | lib.definePermission({ 17 | name: "exp_groups.modify_permissions", 18 | title: "Modify permission groups", 19 | description: "Modify game permissions for groups.", 20 | }); 21 | 22 | lib.definePermission({ 23 | name: "exp_groups.assign_players", 24 | title: "Change player group", 25 | description: "Change the permission group of a player", 26 | }); 27 | 28 | lib.definePermission({ 29 | name: "exp_groups.list", 30 | title: "View permission groups", 31 | description: "View permission groups.", 32 | }); 33 | 34 | lib.definePermission({ 35 | name: "exp_groups.list.subscribe", 36 | title: "Subscribe to permission group updates", 37 | description: "Subscribe to permission group updates.", 38 | }); 39 | 40 | declare module "@clusterio/lib" { 41 | export interface ControllerConfigFields { 42 | "exp_groups.allow_role_inconsistency": boolean; 43 | } 44 | export interface InstanceConfigFields { 45 | "exp_groups.sync_permission_groups": boolean; 46 | } 47 | } 48 | 49 | export const plugin: lib.PluginDeclaration = { 50 | name: "exp_groups", 51 | title: "exp_groups", 52 | description: "Create, modify, and link factorio permission groups to clusterio user roles.", 53 | 54 | controllerEntrypoint: "./dist/node/controller", 55 | controllerConfigFields: { 56 | "exp_groups.allow_role_inconsistency": { 57 | title: "Allow User Role Inconsistency", 58 | description: "When true, users can be assgined to any group regardless of their roles", 59 | type: "boolean", 60 | initialValue: false, 61 | }, 62 | }, 63 | 64 | instanceEntrypoint: "./dist/node/instance", 65 | instanceConfigFields: { 66 | "exp_groups.sync_permission_groups": { 67 | title: "Sync Permission Groups", 68 | description: "When true, the instance cannot deviate from the global group settings and will be hidden from the sellection dropdown.", 69 | type: "boolean", 70 | initialValue: true, 71 | }, 72 | }, 73 | 74 | messages: [ 75 | Messages.PermissionGroupEditEvent, 76 | Messages.PermissionStringsUpdate, 77 | Messages.PermissionGroupUpdate, 78 | ], 79 | 80 | webEntrypoint: "./web", 81 | routes: [ 82 | "/exp_groups", 83 | ], 84 | }; 85 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/rainbow.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Rainbow 2 | Adds a command that prints your message in rainbow font 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local format_player_name = Commands.format_player_name_locale 7 | local format_text = Commands.format_rich_text_color 8 | 9 | --- Wraps one component into the next 10 | --- @param c1 number 11 | --- @param c2 number 12 | --- @return number, number 13 | local function step_component(c1, c2) 14 | if c1 < 0 then 15 | return 0, c2 + c1 16 | elseif c1 > 1 then 17 | return 1, c2 - c1 + 1 18 | else 19 | return c1, c2 20 | end 21 | end 22 | 23 | --- Wraps all components of a colour ensuring it remains valid 24 | --- @param color Color 25 | --- @return Color 26 | local function step_color(color) 27 | color.r, color.g = step_component(color.r, color.g) 28 | color.g, color.b = step_component(color.g, color.b) 29 | color.b, color.r = step_component(color.b, color.r) 30 | color.r = step_component(color.r, 0) 31 | return color 32 | end 33 | 34 | --- Get the next colour in the rainbow by the given step 35 | --- @param color Color 36 | --- @param step number 37 | --- @return Color 38 | local function next_color(color, step) 39 | step = step or 0.1 40 | local new_color = { r = 0, g = 0, b = 0 } 41 | if color.b == 0 and color.r ~= 0 then 42 | new_color.r = color.r - step 43 | new_color.g = color.g + step 44 | elseif color.r == 0 and color.g ~= 0 then 45 | new_color.g = color.g - step 46 | new_color.b = color.b + step 47 | elseif color.g == 0 and color.b ~= 0 then 48 | new_color.b = color.b - step 49 | new_color.r = color.r + step 50 | end 51 | return step_color(new_color) 52 | end 53 | 54 | --- Sends an rainbow message in the chat 55 | Commands.new("rainbow", { "exp-commands_rainbow.description" }) 56 | :argument("message", { "exp-commands_rainbow.arg-message" }, Commands.types.string) 57 | :enable_auto_concatenation() 58 | :register(function(player, message) 59 | local color_step = 3 / message:len() 60 | if color_step > 1 then color_step = 1 end 61 | local current_color = { r = 1, g = 0, b = 0 } 62 | 63 | game.print{ 64 | "exp-commands_rainbow.response", 65 | format_player_name(player), 66 | message:gsub("%S", function(letter) 67 | local rtn = format_text(letter, current_color) 68 | current_color = next_color(current_color, color_step) 69 | return rtn 70 | end) 71 | } 72 | end) 73 | -------------------------------------------------------------------------------- /exp_util/module/include/math.lua: -------------------------------------------------------------------------------- 1 | -- luacheck:ignore global math 2 | 3 | local floor = math.floor 4 | local abs = math.abs 5 | 6 | --- Constant value representing the square root of 2 7 | math.sqrt2 = math.sqrt(2) 8 | 9 | --- Constant value representing the reciprocal of square root of 2 10 | math.inv_sqrt2 = 1 / math.sqrt2 11 | 12 | --- Constant value representing the value of Tau aka 2*Pi 13 | math.tau = 2 * math.pi 14 | 15 | --- Rounds a number to certain number of decimal places, does not work on significant figures 16 | --- @param num number The number to be rounded 17 | --- @param idp number? The number of decimal places to round to 18 | --- @return number 19 | math.round = function(num, idp) 20 | local mult = 10 ^ (idp or 0) 21 | return floor(num * mult + 0.5) / mult 22 | end 23 | 24 | --- Clamp a number better a minimum and maximum value, preserves NaN (not the same as nil) 25 | --- @param num number The number to be clamped 26 | --- @param min number The lower bound of the accepted range 27 | --- @param max number The upper bound of the accepted range 28 | --- @return number 29 | math.clamp = function(num, min, max) 30 | if num < min then 31 | return min 32 | elseif num > max then 33 | return max 34 | else 35 | return num 36 | end 37 | end 38 | 39 | --- Returns the slope / gradient of a line given two points on the line 40 | --- @param x1 number The X coordinate of the first point on the line 41 | --- @param y1 number The Y coordinate of the first point on the line 42 | --- @param x2 number The X coordinate of the second point on the line 43 | --- @param y2 number The Y coordinate of the second point on the line 44 | --- @return number 45 | math.slope = function(x1, y1, x2, y2) 46 | return abs((y2 - y1) / (x2 - x1)) 47 | end 48 | 49 | --- Returns the y-intercept of a line given ibe point on the line and its slope 50 | --- @param x number The X coordinate of point on the line 51 | --- @param y number The Y coordinate of point on the line 52 | --- @param slope number The slope / gradient of the line 53 | --- @return number 54 | math.y_intercept = function(x, y, slope) 55 | return y - (slope * x) 56 | end 57 | 58 | local deg_to_rad = math.tau / 360 59 | --- Returns the angle x (given in radians) in degrees 60 | --- @param x number 61 | --- @return number 62 | math.degrees = function(x) 63 | return x * deg_to_rad 64 | end 65 | 66 | --- Returns the sign of the input value 67 | --- @param x number 68 | --- @return number 69 | math.sign = function(x) 70 | return x < 0 and -1 or 0 71 | end 72 | 73 | return math 74 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/data/player-colours.lua: -------------------------------------------------------------------------------- 1 | --- Gives players random colours when they join, also applies preset colours to those who have them 2 | -- @data Player-Colours 3 | 4 | local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event 5 | local Colours = require("modules/exp_util/include/color") 6 | local config = require("modules.exp_legacy.config.preset_player_colours") --- @dep config.preset_player_colours 7 | 8 | --- Stores the colour that the player wants 9 | local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data 10 | local PlayerColours = PlayerData.Settings:combine("Colour") 11 | PlayerColours:set_metadata{ 12 | stringify = function(value) 13 | if not value then return "None set" end 14 | local c = value[1] 15 | return string.format("Red: %d Green: %d Blue: %d", c[1], c[2], c[3]) 16 | end, 17 | } 18 | 19 | --- Used to compact player colours to take less space 20 | local floor = math.floor 21 | local function compact(colour) 22 | return { 23 | floor(colour.r * 255), 24 | floor(colour.g * 255), 25 | floor(colour.b * 255), 26 | } 27 | end 28 | 29 | --- Returns a colour that is a bit lighter than the one given 30 | local function lighten(c) 31 | return { r = 255 - (255 - c.r) * 0.5, g = 255 - (255 - c.g) * 0.5, b = 255 - (255 - c.b) * 0.5, a = 255 } 32 | end 33 | 34 | --- When your data loads apply the players colour, or a random on if none is saved 35 | PlayerColours:on_load(function(player_name, player_colour) 36 | if not player_colour then 37 | local preset = config.players[player_name] 38 | if preset then 39 | player_colour = { preset, lighten(preset) } 40 | else 41 | local colour_name = "white" 42 | while config.disallow[colour_name] do 43 | colour_name = table.get_random(Colours, true) 44 | end 45 | 46 | player_colour = { Colours[colour_name], lighten(Colours[colour_name]) } 47 | end 48 | end 49 | 50 | local player = game.players[player_name] 51 | player.color = player_colour[1] 52 | player.chat_color = player_colour[2] 53 | end) 54 | 55 | --- Save the players color when they use the color command 56 | Event.add(defines.events.on_console_command, function(event) 57 | if event.command ~= "color" then return end 58 | if event.parameters == "" then return end 59 | if not event.player_index then return end 60 | local player = game.players[event.player_index] 61 | if not player or not player.valid then return end 62 | PlayerColours:set(player, { compact(player.color), compact(player.chat_color) }) 63 | end) 64 | -------------------------------------------------------------------------------- /exp_scenario/module/control/custom_start.lua: -------------------------------------------------------------------------------- 1 | --[[-- Control - Custom Start 2 | Changes the starting script and the items given on first join depending on factory production levels 3 | ]] 4 | 5 | local config = require("modules.exp_legacy.config.advanced_start") 6 | local floor = math.floor 7 | 8 | --- Give a player their starting items 9 | --- @param player LuaPlayer 10 | local function give_starting_items(player) 11 | local get_prod_stats = player.force.get_item_production_statistics(player.physical_surface) 12 | local get_input_count = get_prod_stats.get_input_count 13 | local insert_param = { name = "", count = 0 } 14 | local insert = player.insert 15 | for item_name, insert_amount in pairs(config.items) do 16 | insert_param.name = item_name 17 | if type(insert_amount) == "function" then 18 | local count = insert_amount(get_input_count(item_name), get_input_count, player) 19 | if count >= 1 then 20 | insert_param.count = floor(count) 21 | insert(insert_param) 22 | end 23 | elseif insert_amount >= 1 then 24 | insert_param.count = floor(insert_amount) 25 | insert(insert_param) 26 | end 27 | end 28 | end 29 | 30 | --- Calls remote interfaces to configure the base game scenarios 31 | local function on_init() 32 | game.forces.player.friendly_fire = config.friendly_fire 33 | game.map_settings.enemy_expansion.enabled = config.enemy_expansion 34 | if remote.interfaces["freeplay"] then 35 | remote.call("freeplay", "set_created_items", {}) 36 | remote.call("freeplay", "set_disable_crashsite", config.disable_crashsite) 37 | remote.call("freeplay", "set_skip_intro", config.skip_intro) 38 | remote.call("freeplay", "set_chart_distance", config.chart_radius) 39 | end 40 | if remote.interfaces["silo_script"] then 41 | remote.call("silo_script", "set_no_victory", config.skip_victory) 42 | end 43 | if remote.interfaces["space_finish_script"] then 44 | remote.call("space_finish_script", "set_no_victory", config.skip_victory) 45 | end 46 | end 47 | 48 | --- Give a player starting items when they first join 49 | --- @param event EventData.on_player_created 50 | local function on_player_created(event) 51 | -- We can't trust on_init to work for clusterio 52 | if event.player_index == 1 then on_init() end 53 | give_starting_items(assert(game.get_player(event.player_index))) 54 | end 55 | 56 | local e = defines.events 57 | 58 | return { 59 | on_init = on_init, 60 | events = { 61 | [e.on_player_created] = on_player_created, 62 | }, 63 | give_starting_items = give_starting_items, 64 | } 65 | -------------------------------------------------------------------------------- /exp_legacy/module/utils/event.lua: -------------------------------------------------------------------------------- 1 | local ExpUtil = require("modules/exp_util") 2 | 3 | local Event = { 4 | real_handlers = { 5 | events = {}, 6 | on_nth_tick = {}, 7 | on_init = nil, 8 | on_load = nil, 9 | }, 10 | handlers = { 11 | events = {}, 12 | on_nth_tick = {}, 13 | on_init = nil, 14 | on_load = nil, 15 | }, 16 | } 17 | 18 | local function call_handlers_factory(handlers) 19 | return function(event) 20 | for _, handler in ipairs(handlers) do 21 | handler(event) 22 | end 23 | end 24 | end 25 | 26 | function Event.add(event_name, handler) 27 | ExpUtil.assert_not_runtime() 28 | ExpUtil.assert_argument_type(event_name, "number", 1, "event_name") 29 | ExpUtil.assert_argument_type(handler, "function", 2, "handler") 30 | 31 | local handlers = Event.handlers.events[event_name] 32 | if not handlers then 33 | handlers = {} 34 | Event.handlers.events[event_name] = handlers 35 | Event.real_handlers.events[event_name] = call_handlers_factory(handlers) 36 | end 37 | 38 | handlers[#handlers + 1] = handler 39 | end 40 | 41 | function Event.on_nth_tick(tick, handler) 42 | ExpUtil.assert_not_runtime() 43 | ExpUtil.assert_argument_type(tick, "number", 1, "tick") 44 | ExpUtil.assert_argument_type(handler, "function", 2, "handler") 45 | 46 | local handlers = Event.handlers.on_nth_tick[tick] 47 | if not handlers then 48 | handlers = {} 49 | Event.handlers.on_nth_tick[tick] = handlers 50 | Event.real_handlers.on_nth_tick[tick] = call_handlers_factory(handlers) 51 | end 52 | 53 | handlers[#handlers + 1] = handler 54 | end 55 | 56 | function Event.on_init(handler) 57 | ExpUtil.assert_not_runtime() 58 | ExpUtil.assert_argument_type(handler, "function", 1, "handler") 59 | 60 | local handlers = Event.handlers.on_init 61 | if not handlers then 62 | handlers = {} 63 | Event.handlers.on_init = handlers 64 | Event.real_handlers.on_init = call_handlers_factory(handlers) 65 | end 66 | 67 | handlers[#handlers + 1] = handler 68 | Event.add(defines.events.on_singleplayer_init, handler) 69 | Event.add(defines.events.on_multiplayer_init, handler) 70 | end 71 | 72 | function Event.on_load(handler) 73 | ExpUtil.assert_not_runtime() 74 | ExpUtil.assert_argument_type(handler, "function", 1, "handler") 75 | 76 | local handlers = Event.handlers.on_load 77 | if not handlers then 78 | handlers = {} 79 | Event.handlers.on_load = handlers 80 | Event.real_handlers.on_load = call_handlers_factory(handlers) 81 | end 82 | 83 | handlers[#handlers + 1] = handler 84 | end 85 | 86 | return Event 87 | -------------------------------------------------------------------------------- /exp_util/module/include/flow_precision.lua: -------------------------------------------------------------------------------- 1 | --[[-- ExpUtil - Flow Precision 2 | Simple lookup tables for working with flow precisions 3 | ]] 4 | 5 | local fp = defines.flow_precision_index 6 | 7 | --- @class ExpUtil_FlowPrecision 8 | return { 9 | --- The defines index 10 | index = fp, 11 | --- The number of ticks represented by a precision index 12 | --- @type table 13 | ticks = { 14 | [fp.five_seconds] = 300, 15 | [fp.one_minute] = 3600, 16 | [fp.ten_minutes] = 36000, 17 | [fp.one_hour] = 216000, 18 | [fp.ten_hours] = 2160000, 19 | [fp.fifty_hours] = 10800000, 20 | [fp.two_hundred_fifty_hours] = 54000000, 21 | [fp.one_thousand_hours] = 216000000, 22 | }, 23 | --- The next larger interval precision index 24 | --- @type table 25 | next = { 26 | [fp.five_seconds] = fp.one_minute, 27 | [fp.one_minute] = fp.ten_minutes, 28 | [fp.ten_minutes] = fp.one_hour, 29 | [fp.one_hour] = fp.ten_hours, 30 | [fp.ten_hours] = fp.fifty_hours, 31 | [fp.fifty_hours] = fp.two_hundred_fifty_hours, 32 | [fp.two_hundred_fifty_hours] = fp.one_thousand_hours, 33 | [fp.one_thousand_hours] = fp.one_thousand_hours, 34 | }, 35 | --- The previous smaller interval precision index 36 | --- @type table 37 | prev = { 38 | [fp.five_seconds] = fp.five_seconds, 39 | [fp.one_minute] = fp.five_seconds, 40 | [fp.ten_minutes] = fp.one_minute, 41 | [fp.one_hour] = fp.ten_minutes, 42 | [fp.ten_hours] = fp.one_hour, 43 | [fp.fifty_hours] = fp.ten_hours, 44 | [fp.two_hundred_fifty_hours] = fp.fifty_hours, 45 | [fp.one_thousand_hours] = fp.two_hundred_fifty_hours, 46 | }, 47 | --- The multiplicative increase to the next larger interval 48 | --- @type table 49 | next_change = { 50 | [fp.five_seconds] = 60, 51 | [fp.one_minute] = 10, 52 | [fp.ten_minutes] = 6, 53 | [fp.one_hour] = 10, 54 | [fp.ten_hours] = 5, 55 | [fp.fifty_hours] = 5, 56 | [fp.two_hundred_fifty_hours] = 4, 57 | [fp.one_thousand_hours] = 1, 58 | }, 59 | --- The multiplicative decrease to the previous smaller interval 60 | --- @type table 61 | prev_change = { 62 | [fp.five_seconds] = 1, 63 | [fp.one_minute] = 60, 64 | [fp.ten_minutes] = 10, 65 | [fp.one_hour] = 6, 66 | [fp.ten_hours] = 10, 67 | [fp.fifty_hours] = 5, 68 | [fp.two_hundred_fifty_hours] = 5, 69 | [fp.one_thousand_hours] = 4, 70 | }, 71 | } 72 | -------------------------------------------------------------------------------- /exp_legacy/module/config/gui/rockets.lua: -------------------------------------------------------------------------------- 1 | --- This file controls what will show in each section of the rocket info gui 2 | -- @config Rockets 3 | 4 | return { 5 | stats = { --- @setting stats The data that will show in the stats section 6 | show_stats = true, --- @setting show_stats false will hide this section all together 7 | show_first_rocket = true, --- @setting show_first_rocket false will not show when the first rocket was launched 8 | show_last_rocket = true, --- @setting show_last_rocket false will not show when the last rocket was launched 9 | show_fastest_rocket = true, --- @setting show_fastest_rocket false will not show the time taken for the fastest rocket 10 | show_total_rockets = true, --- @setting show_total_rockets false will not show the total number of rockets launched 11 | show_game_avg = true, --- @setting show_game_avg false will hide the avg across the entire map time 12 | rolling_avg = { --- @setting rolling_avg each number will be one statistic; 5 means the avg time taken for the last 5 rockets 13 | 5, 10, 25, 14 | }, 15 | }, 16 | milestones = { --- @setting milestones each number will be one statistic; 5 means the time that the 5th rocket was launched 17 | show_milestones = true, --- @setting show_milestones false will hide this section all together 18 | 1, 19 | 2, 20 | 5, 21 | 10, 22 | 20, 23 | 50, 24 | 100, 25 | 200, 26 | 500, 27 | 1000, 28 | 1500, 29 | 2000, 30 | 2500, 31 | 3000, 32 | 3500, 33 | 4000, 34 | 4500, 35 | 5000, 36 | }, 37 | progress = { --- @setting progress The data and buttons in the build progress section 38 | show_progress = true, --- @setting show_progress false will hide this section altogether 39 | allow_zoom_to_map = true, --- @setting allow_zoom_to_map false will disable the zoom to map feature 40 | allow_remote_launch = true, --- @setting allow_remote_launch false removes the remote launch button for all players 41 | remote_launch_admins_only = false, --- @setting remote_launch_admins_only true will remove the remote launch button for all non (game) admins 42 | remote_launch_role_permission = "gui/rocket-info/remote_launch", --- @setting remote_launch_role_permission value used by custom permission system to allow or disallow the button 43 | allow_toggle_active = true, --- @setting allow_toggle_active false removes the remote toggle auto launch button for all players 44 | toggle_active_admins_only = false, --- @setting toggle_active_admins_only true will remove the toggle auto launch button for all non (game) admins 45 | toggle_active_role_permission = "gui/rocket-info/toggle-active", --- @setting toggle_active_role_permission value used by custom permission system to allow or disallow the button 46 | }, 47 | } 48 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/roles.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Roles 2 | Adds a commands that allow interaction with the role system 3 | ]] 4 | 5 | local Commands = require("modules/exp_commands") 6 | local format_player_name = Commands.format_player_name_locale 7 | local format_text = Commands.format_rich_text_color_locale 8 | 9 | local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles 10 | local get_roles_ordered = Roles.get_roles_ordered 11 | local get_player_roles = Roles.get_player_roles 12 | 13 | --- Assigns a role to a player 14 | Commands.new("assign-role", { "exp-commands_roles.description-assign" }) 15 | :argument("player", { "exp-commands_roles.arg-player-assign" }, Commands.types.lower_role_player) 16 | :argument("role", { "exp-commands_roles.arg-role-assign" }, Commands.types.lower_role) 17 | :add_aliases{ "assign" } 18 | :add_flags{ "admin_only" } 19 | :register(function(player, other_player, role) 20 | --- @cast other_player LuaPlayer 21 | --- @cast role any -- TODO 22 | Roles.assign_player(other_player, role, player.name) 23 | end) 24 | 25 | --- Unassigns a role to a player 26 | Commands.new("unassign-role", { "exp-commands_roles.description-unassign" }) 27 | :argument("player", { "exp-commands_roles.arg-player-unassign" }, Commands.types.lower_role_player) 28 | :argument("role", { "exp-commands_roles.arg-role-unassign" }, Commands.types.lower_role) 29 | :add_aliases{ "unassign" } 30 | :add_flags{ "admin_only" } 31 | :register(function(player, other_player, role) 32 | --- @cast other_player LuaPlayer 33 | --- @cast role any -- TODO 34 | Roles.unassign_player(other_player, role, player.name) 35 | end) 36 | 37 | --- Lists all roles in they correct order 38 | Commands.new("get-roles", { "exp-commands_roles.description-get" }) 39 | :optional("player", { "exp-commands_roles.arg-player-get" }, Commands.types.player) 40 | :add_aliases{ "roles" } 41 | :register(function(player, other_player) 42 | --- @cast other_player LuaPlayer? 43 | local roles = get_roles_ordered() 44 | local roles_formatted = { "" } --- @type LocalisedString 45 | local response = { "exp-commands_roles.list-roles", roles_formatted } 46 | if other_player then 47 | roles = get_player_roles(other_player) 48 | response[1] = "exp-commands_roles.list-player" 49 | response[3] = format_player_name(other_player) 50 | end 51 | 52 | for index, role in ipairs(roles) do 53 | local role_name = format_text(role.name, role.custom_color or Commands.color.white) 54 | roles_formatted[index + 1] = { "exp-commands_roles.list-element", role_name } 55 | end 56 | 57 | local last = #roles_formatted 58 | --- @diagnostic disable-next-line nil-check 59 | roles_formatted[last] = roles_formatted[last][2] 60 | 61 | return Commands.status.success(response) 62 | end) 63 | -------------------------------------------------------------------------------- /exp_legacy/module/config/module.lua: -------------------------------------------------------------------------------- 1 | return { 2 | module_slots_per_row = 4, 3 | module_slot_max = 8, 4 | copy_paste_module = true, 5 | copy_paste_rotation = false, 6 | machines = { 7 | }, 8 | machine_sets = { 9 | ["base"] = { 10 | ["electric-mining-drill"] = { 11 | ["module"] = "efficiency-module", 12 | ["prod"] = true, 13 | }, 14 | ["pumpjack"] = { 15 | ["module"] = "efficiency-module", 16 | ["prod"] = true, 17 | }, 18 | ["assembling-machine-2"] = { 19 | ["module"] = "productivity-module", 20 | ["prod"] = true, 21 | }, 22 | ["assembling-machine-3"] = { 23 | ["module"] = "productivity-module-3", 24 | ["prod"] = true, 25 | }, 26 | ["electric-furnace"] = { 27 | ["module"] = "productivity-module-3", 28 | ["prod"] = true, 29 | }, 30 | ["beacon"] = { 31 | ["module"] = "speed-module-3", 32 | ["prod"] = false, 33 | }, 34 | ["oil-refinery"] = { 35 | ["module"] = "productivity-module-3", 36 | ["prod"] = true, 37 | }, 38 | ["chemical-plant"] = { 39 | ["module"] = "productivity-module-3", 40 | ["prod"] = true, 41 | }, 42 | ["centrifuge"] = { 43 | ["module"] = "productivity-module-3", 44 | ["prod"] = true, 45 | }, 46 | ["lab"] = { 47 | ["module"] = "productivity-module-3", 48 | ["prod"] = true, 49 | }, 50 | ["rocket-silo"] = { 51 | ["module"] = "productivity-module-3", 52 | ["prod"] = true, 53 | } 54 | }, 55 | ["space-age"] = { 56 | ["big-mining-drill"] = { 57 | ["module"] = "efficiency-module", 58 | ["prod"] = true, 59 | }, 60 | ["biochamber"] = { 61 | ["module"] = "efficiency-module", 62 | ["prod"] = true, 63 | }, 64 | ["electromagnetic-plant"] = { 65 | ["module"] = "productivity-module-3", 66 | ["prod"] = true, 67 | }, 68 | ["cryogenic-plant"] = { 69 | ["module"] = "productivity-module-3", 70 | ["prod"] = true, 71 | }, 72 | ["biolab"] = { 73 | ["module"] = "productivity-module-3", 74 | ["prod"] = true, 75 | }, 76 | ["foundry"] = { 77 | ["module"] = "productivity-module-3", 78 | ["prod"] = true, 79 | }, 80 | ["recycler"] = { 81 | ["module"] = "quality-module-3", 82 | ["prod"] = true, 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /exp_scenario/messages.ts: -------------------------------------------------------------------------------- 1 | import { plainJson, jsonArray, JsonBoolean, JsonNumber, JsonString, StringEnum } from "@clusterio/lib"; 2 | import { Type, Static } from "@sinclair/typebox"; 3 | 4 | export class PluginExampleEvent { 5 | declare ["constructor"]: typeof PluginExampleEvent; 6 | static type = "event" as const; 7 | static src = ["host", "control"] as const; 8 | static dst = ["controller", "host", "instance"] as const; 9 | static plugin = "exp_scenario" as const; 10 | static permission = "exp_scenario.example.permission.event"; 11 | 12 | constructor( 13 | public myString: string, 14 | public myNumberArray: number[], 15 | ) { 16 | } 17 | 18 | static jsonSchema = Type.Object({ 19 | "myString": Type.String(), 20 | "myNumberArray": Type.Array(Type.Number()), 21 | }); 22 | 23 | static fromJSON(json: Static) { 24 | return new PluginExampleEvent(json.myString, json.myNumberArray); 25 | } 26 | } 27 | 28 | export class PluginExampleRequest { 29 | declare ["constructor"]: typeof PluginExampleRequest; 30 | static type = "request" as const; 31 | static src = ["host", "control"] as const; 32 | static dst = ["controller", "host", "instance"] as const; 33 | static plugin = "exp_scenario" as const; 34 | static permission = "exp_scenario.example.permission.request"; 35 | 36 | constructor( 37 | public myString: string, 38 | public myNumberArray: number[], 39 | ) { 40 | } 41 | 42 | static jsonSchema = Type.Object({ 43 | "myString": Type.String(), 44 | "myNumberArray": Type.Array(Type.Number()), 45 | }); 46 | 47 | static fromJSON(json: Static) { 48 | return new PluginExampleRequest(json.myString, json.myNumberArray); 49 | } 50 | 51 | static Response = plainJson(Type.Object({ 52 | "myResponseString": Type.String(), 53 | "myResponseNumbers": Type.Array(Type.Number()), 54 | })); 55 | } 56 | 57 | export class ExampleSubscribableValue { 58 | constructor( 59 | public id: string, 60 | public updatedAtMs: number, 61 | public isDeleted: boolean, 62 | ) { 63 | } 64 | 65 | static jsonSchema = Type.Object({ 66 | id: Type.String(), 67 | updatedAtMs: Type.Number(), 68 | isDeleted: Type.Boolean(), 69 | }); 70 | 71 | static fromJSON(json: Static) { 72 | return new this(json.id, json.updatedAtMs, json.isDeleted); 73 | } 74 | } 75 | 76 | export class ExampleSubscribableUpdate { 77 | declare ["constructor"]: typeof ExampleSubscribableUpdate; 78 | static type = "event" as const; 79 | static src = "controller" as const; 80 | static dst = "control" as const; 81 | static plugin = "exp_scenario" as const; 82 | static permission = "exp_scenario.example.permission.subscribe"; 83 | 84 | constructor( 85 | public updates: ExampleSubscribableValue[], 86 | ) { } 87 | 88 | static jsonSchema = Type.Object({ 89 | "updates": Type.Array(ExampleSubscribableValue.jsonSchema), 90 | }); 91 | 92 | static fromJSON(json: Static) { 93 | return new this(json.updates.map(update => ExampleSubscribableValue.fromJSON(update))); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /exp_scenario/module/control/afk_kick.lua: -------------------------------------------------------------------------------- 1 | --[[-- Control -- AFK Kick 2 | Kicks players when all players on the server are afk 3 | ]] 4 | 5 | local Async = require("modules/exp_util/async") 6 | local Storage = require("modules/exp_util/storage") 7 | local config = require("modules.exp_legacy.config.afk_kick") 8 | 9 | --- @type { last_active: number } 10 | local script_data = { last_active = 0 } 11 | Storage.register(script_data, function(tbl) 12 | script_data = tbl 13 | end) 14 | 15 | --- Kicks an afk player, used to add a delay so the gui has time to appear 16 | local afk_kick_player_async = 17 | Async.register(function(player) 18 | if game.tick - script_data.last_active < config.kick_time then return end 19 | game.kick_player(player, "AFK while no active players on the server") 20 | end) 21 | 22 | --- Check if there is an active player 23 | local function has_active_player() 24 | for _, player in ipairs(game.connected_players) do 25 | if player.afk_time < config.afk_time 26 | or config.admin_as_active and player.admin 27 | or config.trust_as_active and player.online_time > config.trust_time 28 | or config.custom_active_check and config.custom_active_check(player) then 29 | script_data.last_active = game.tick 30 | return true 31 | end 32 | end 33 | 34 | return false 35 | end 36 | 37 | --- Check for an active player every update_time number of ticks 38 | local function check_afk_players() 39 | -- Check for active players 40 | if has_active_player() then return end 41 | 42 | -- Check if players should be kicked 43 | if game.tick - script_data.last_active < config.kick_time then return end 44 | 45 | -- Kick time exceeded, kick all players 46 | for _, player in ipairs(game.connected_players) do 47 | -- Add a frame to say why the player was kicked 48 | local frame = player.gui.screen.add{ 49 | type = "frame", 50 | name = "afk-kick", 51 | caption = { "exp_afk-kick.kick-message" }, 52 | } 53 | 54 | local uis = player.display_scale 55 | local res = player.display_resolution 56 | frame.location = { 57 | x = res.width * (0.5 - 0.11 * uis), 58 | y = res.height * (0.5 - 0.14 * uis), 59 | } 60 | 61 | -- Kick the player, some delay needed allow the gui to show 62 | afk_kick_player_async:start_after(60, player) 63 | end 64 | end 65 | 66 | --- Remove the screen gui if it is present 67 | --- @param event EventData.on_player_joined_game 68 | local function on_player_joined_game(event) 69 | local player = assert(game.get_player(event.player_index)) 70 | local frame = player.gui.screen["afk-kick"] 71 | if frame and frame.valid then frame.destroy() end 72 | end 73 | 74 | local e = defines.events 75 | 76 | return { 77 | events = { 78 | [e.on_player_joined_game] = on_player_joined_game, 79 | }, 80 | on_nth_tick = { 81 | [config.update_time] = check_afk_players, 82 | }, 83 | has_active_player = has_active_player, 84 | } 85 | -------------------------------------------------------------------------------- /exp_legacy/module/config/statistics.lua: -------------------------------------------------------------------------------- 1 | --- A list of all tracked statistics and the events which trigger them 2 | -- @config Statistics 3 | 4 | local e = defines.events -- order as per lua api as it was easier just to go down the list 5 | return { 6 | MapsPlayed = true, --- @setting MapsPlayed If the number of maps which a player has played should be tracked 7 | Playtime = true, --- @setting Playtime If playtime is tracked for a player, play time measured in minutes 8 | AfkTime = true, --- @setting AfkTime If afk time is tracked for a player, play time measured in minutes, afk is once a player does nothing for 5 minutes 9 | DistanceTravelled = true, --- @setting DistanceTravelled If distance Travelled is checked, only counts if not afk 10 | MachinesRemoved = true, --- @setting MachinesRemoved If removed machines are tracked, includes marked for decon and player mined entity 11 | TreesDestroyed = true, --- @setting OreMined If ore mined is tracked for a player, includes marked for decon and player mined entity but only trees 12 | OreMined = true, --- @setting OreMined If ore mined is tracked for a player, includes player mined entity but only ore 13 | DamageDealt = true, --- @setting DamageDealt If damage dealt is tracked for a player, includes any damage to entities not on the same force or neutral 14 | Kills = true, --- @setting Kills If kills are tracked for a player, includes all kills not on same force or neutral 15 | RocketsLaunched = true, --- @setting RocketsLaunched If the number of rockets launched should be tracked, done for all players on the force 16 | ResearchCompleted = true, --- @setting ResearchCompleted If the number of researches completed should be tracked, done for all players on the force 17 | counters = { --- @setting counters Simple statistics that just go up by one each time an event happens 18 | MachinesBuilt = e.on_built_entity, 19 | MapTagsMade = e.on_chart_tag_added, 20 | ChatMessages = e.on_console_chat, 21 | CommandsUsed = e.on_console_command, 22 | ItemsPickedUp = e.on_picked_up_item, 23 | TilesBuilt = e.on_player_built_tile, 24 | ItemsCrafted = e.on_player_crafted_item, 25 | DeconstructionPlannerUsed = e.on_player_deconstructed_area, 26 | Deaths = e.on_player_died, 27 | JoinCount = e.on_player_joined_game, 28 | TilesRemoved = e.on_player_mined_tile, 29 | CapsulesUsed = e.on_player_used_capsule, 30 | EntityRepaired = e.on_player_repaired_entity, 31 | }, 32 | display_order = { --- @setting display_order The order that the statistics should be shown in when in a gui or command 33 | "Playtime", "AfkTime", 34 | "MapsPlayed", "JoinCount", 35 | "ChatMessages", "CommandsUsed", 36 | "RocketsLaunched", "ResearchCompleted", 37 | "MachinesBuilt", "MachinesRemoved", 38 | "TilesBuilt", "TilesRemoved", 39 | "TreesDestroyed", "OreMined", 40 | "ItemsCrafted", "ItemsPickedUp", 41 | "Kills", "Deaths", 42 | "DamageDealt", "DistanceTravelled", 43 | "CapsulesUsed", "EntityRepaired", 44 | "DeconstructionPlannerUsed", "MapTagsMade", 45 | }, 46 | } 47 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/data/tag.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands Module - Tag 2 | - Adds a command that allows players to have a custom tag after their name 3 | @data Tag 4 | ]] 5 | 6 | local Commands = require("modules/exp_commands") 7 | local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles 8 | 9 | --- Stores the tag for a player 10 | local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data 11 | local PlayerTags = PlayerData.Settings:combine("Tag") 12 | local PlayerTagColors = PlayerData.Settings:combine("TagColor") 13 | PlayerTags:set_metadata{ 14 | permission = "command/tag", 15 | } 16 | PlayerTagColors:set_metadata{ 17 | permission = "command/tag-color", 18 | } 19 | 20 | local set_tag = function(player, tag, color) 21 | if tag == nil or tag == "" then 22 | player.tag = "" 23 | elseif color then 24 | player.tag = "- [color=" .. color .. "]" .. tag .. "[/color]" 25 | else 26 | player.tag = "- " .. tag 27 | end 28 | end 29 | 30 | --- When your tag is updated then apply the changes 31 | PlayerTags:on_update(function(player_name, player_tag) 32 | local player = game.players[player_name] 33 | local player_tag_color = PlayerTagColors:get(player) 34 | 35 | set_tag(player, player_tag, player_tag_color) 36 | end) 37 | 38 | --- When your tag color is updated then apply the changes 39 | PlayerTagColors:on_update(function(player_name, player_tag_color) 40 | local player = game.players[player_name] 41 | local player_tag = PlayerTags:get(player) 42 | 43 | set_tag(player, player_tag, player_tag_color) 44 | end) 45 | 46 | --- Sets your player tag. 47 | Commands.new("tag", "Sets your player tag.") 48 | :argument("tag", "", Commands.types.string_max_length(20)) 49 | :enable_auto_concatenation() 50 | :register(function(player, tag) 51 | --- @cast tag string 52 | PlayerTags:set(player, tag) 53 | end) 54 | 55 | --- Sets your player tag color. 56 | Commands.new("tag-color", "Sets your player tag color.") 57 | :argument("color", "", Commands.types.color) 58 | :enable_auto_concatenation() 59 | :register(function(player, color) 60 | --- @cast color Color 61 | PlayerTagColors:set(player, color) 62 | end) 63 | 64 | --- Clears your tag. Or another player if you are admin. 65 | Commands.new("tag-clear", "Clears your tag. Or another player if you are admin.") 66 | :optional("player", "", Commands.types.lower_role_player) 67 | :defaults{ 68 | player = function(player) return player end 69 | } 70 | :register(function(player, other_player) 71 | --- @cast other_player LuaPlayer 72 | if other_player == player then 73 | -- No player given so removes your tag 74 | PlayerTags:remove(other_player) 75 | elseif Roles.player_allowed(player, "command/clear-tag/always") then 76 | -- Player given and user is admin so clears that player's tag 77 | PlayerTags:remove(other_player) 78 | else 79 | -- User is not admin and tried to clear another users tag 80 | return Commands.status.unauthorised() 81 | end 82 | end) 83 | -------------------------------------------------------------------------------- /exp_scenario/module/commands/research.lua: -------------------------------------------------------------------------------- 1 | --[[-- Commands - Research 2 | Adds a command to enable automatic research queueing 3 | ]] 4 | 5 | local Storage = require("modules/exp_util/storage") 6 | local Commands = require("modules/exp_commands") 7 | local format_player_name = Commands.format_player_name_locale 8 | 9 | local config = require("modules.exp_legacy.config.research") --- @dep config.research 10 | 11 | --- @class ExpCommands_Research.commands 12 | local commands = {} 13 | 14 | local research = { 15 | res_queue_enable = false 16 | } 17 | 18 | Storage.register(research, function(tbl) 19 | research = tbl 20 | end) 21 | 22 | --- @param force LuaForce 23 | --- @param silent boolean True when no message should be printed 24 | local function queue_research(force, silent) 25 | local res_q = force.research_queue 26 | local res = force.technologies[config.bonus_inventory.log[config.mod_set].name] 27 | 28 | if #res_q < config.queue_amount then 29 | for i = #res_q, config.queue_amount - 1 do 30 | force.add_research(res) 31 | 32 | if not silent then 33 | game.print{ "exp-commands_research.queue", res.name, res.level + i } 34 | end 35 | end 36 | end 37 | end 38 | 39 | --- @param state boolean? use nil to toggle current state 40 | --- @return boolean # New auto research state 41 | local function set_auto_research(state) 42 | local new_state 43 | if state == nil then 44 | new_state = not research.res_queue_enable 45 | else 46 | new_state = state ~= false 47 | end 48 | 49 | research.res_queue_enable = new_state 50 | return new_state 51 | end 52 | 53 | --- Sets the auto research state 54 | --- @class ExpCommand_Artillery.commands.artillery: ExpCommand 55 | --- @overload fun(player: LuaPlayer, state: boolean?) 56 | commands.set_auto_research = Commands.new("set-auto-research", { "exp-commands_research.description" }) 57 | :optional("state", { "exp-commands_research.arg-state" }, Commands.types.boolean) 58 | :add_aliases{ "auto-research" } 59 | :register(function(player, state) 60 | --- @cast state boolean? 61 | local enabled = set_auto_research(state) 62 | 63 | if enabled then 64 | queue_research(player.force --[[@as LuaForce]], true) 65 | end 66 | 67 | local player_name = format_player_name(player) 68 | game.print{ "exp-commands_research.auto-research", player_name, enabled } 69 | end) --[[ @as any ]] 70 | 71 | --- @param event EventData.on_research_finished 72 | local function on_research_finished(event) 73 | if not research.res_queue_enable then return end 74 | 75 | local force = event.research.force 76 | local log_research = assert(config.bonus_inventory.log[config.mod_set], "Unknown mod set: " .. tostring(config.mod_set)) 77 | local technology = assert(force.technologies[log_research.name], "Unknown technology: " .. tostring(log_research.name)) 78 | if technology.level > log_research.level then 79 | queue_research(force, event.by_script) 80 | end 81 | end 82 | 83 | local e = defines.events 84 | 85 | return { 86 | commands = commands, 87 | events = { 88 | [e.on_research_finished] = on_research_finished, 89 | }, 90 | } 91 | -------------------------------------------------------------------------------- /exp_groups/web/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { 2 | useContext, useEffect, useState, 3 | useCallback, useSyncExternalStore, 4 | } from "react"; 5 | 6 | // import { 7 | // 8 | // } from "antd"; 9 | 10 | import { 11 | BaseWebPlugin, PageLayout, PageHeader, Control, ControlContext, notifyErrorHandler, 12 | useInstances, 13 | } from "@clusterio/web_ui"; 14 | 15 | import { PermissionGroupUpdate, PermissionInstanceId, PermissionStringsUpdate } from "../messages"; 16 | 17 | import * as lib from "@clusterio/lib"; 18 | 19 | import { GroupTree } from "./components/groupTree"; 20 | 21 | function MyTemplatePage() { 22 | const control = useContext(ControlContext); 23 | const plugin = control.plugins.get("exp_groups") as WebPlugin; 24 | const [permissionStrings, permissionStringsSynced] = plugin.usePermissionStrings(); 25 | const [permissionGroups, permissionGroupsSynced] = plugin.usePermissionGroups(); 26 | const [instances, instancesSync] = useInstances(); 27 | 28 | let [roles, setRoles] = useState([]); 29 | 30 | useEffect(() => { 31 | control.send(new lib.RoleListRequest()).then(newRoles => { 32 | setRoles(newRoles); 33 | }).catch(notifyErrorHandler("Error fetching role list")); 34 | }, []); 35 | 36 | return 37 | 38 | Permission Strings: {String(permissionStringsSynced)} {JSON.stringify([...permissionStrings.values()])}
39 | Permission Groups: {String(permissionGroupsSynced)} {JSON.stringify([...permissionGroups.values()])}
40 | Instances: {String(instancesSync)} {JSON.stringify([...instances.values()].map(instance => [instance.id, instance.name]))}
41 | Roles: {JSON.stringify([...roles.values()].map(role => [role.id, role.name]))}
42 | 43 |
; 44 | } 45 | 46 | export class WebPlugin extends BaseWebPlugin { 47 | permissionStrings = new lib.EventSubscriber(PermissionStringsUpdate, this.control); 48 | permissionGroups = new lib.EventSubscriber(PermissionGroupUpdate, this.control); 49 | 50 | async init() { 51 | this.pages = [ 52 | { 53 | path: "/exp_groups", 54 | sidebarName: "exp_groups", 55 | permission: "exp_groups.list", 56 | content: , 57 | }, 58 | ]; 59 | } 60 | 61 | useInstancePermissionStrings(instanceId?: PermissionInstanceId) { 62 | const [permissionStrings, synced] = this.usePermissionStrings(); 63 | return [instanceId !== undefined ? permissionStrings.get(instanceId) : undefined, synced] as const; 64 | } 65 | 66 | usePermissionStrings() { 67 | const control = useContext(ControlContext); 68 | const subscribe = useCallback((callback: () => void) => this.permissionStrings.subscribe(callback), [control]); 69 | return useSyncExternalStore(subscribe, () => this.permissionStrings.getSnapshot()); 70 | } 71 | 72 | useInstancePermissionGroups(instanceId?: PermissionInstanceId) { 73 | const [permissionGroups, synced] = this.usePermissionGroups(); 74 | return [instanceId !== undefined ? [...permissionGroups.values()].filter(group => group.instanceId === instanceId) : undefined, synced] as const; 75 | } 76 | 77 | usePermissionGroups() { 78 | const control = useContext(ControlContext); 79 | const subscribe = useCallback((callback: () => void) => this.permissionGroups.subscribe(callback), [control]); 80 | return useSyncExternalStore(subscribe, () => this.permissionGroups.getSnapshot()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /exp_scenario/module/control/extra_logging.lua: -------------------------------------------------------------------------------- 1 | --[[-- Addon Logging 2 | Log some extra events to a separate file 3 | ]] 4 | 5 | local config = require("modules.exp_legacy.config.logging") 6 | local config_res = require("modules.exp_legacy.config.research") 7 | 8 | local concat = table.concat 9 | local write_file = helpers.write_file 10 | 11 | --- Add a line to the log file 12 | --- @param ... string 13 | local function add_log_line(...) 14 | write_file(config.file_name, concat({ ... }, " ") .. "\n", true, 0) 15 | end 16 | 17 | --- Add a line to the log file 18 | --- @param line LocalisedString 19 | local function add_log_line_locale(line) 20 | write_file(config.file_name, line, true, 0) 21 | end 22 | 23 | --- @param event EventData.on_cargo_pod_finished_ascending 24 | local function on_cargo_pod_finished_ascending(event) 25 | if event.launched_by_rocket then 26 | local force = event.cargo_pod.force 27 | if force.rockets_launched >= config.rocket_launch_display_rate and force.rockets_launched % config.rocket_launch_display_rate == 0 then 28 | add_log_line("[ROCKET]", force.rockets_launched, "rockets launched") 29 | elseif config.rocket_launch_display[force.rockets_launched] then 30 | add_log_line("[ROCKET]", force.rockets_launched, "rockets launched") 31 | end 32 | end 33 | end 34 | 35 | --- @param event EventData.on_pre_player_died 36 | local function on_pre_player_died(event) 37 | local player = assert(game.get_player(event.player_index)) 38 | local cause = event.cause 39 | if cause then 40 | local by_player = event.cause.player 41 | add_log_line("[DEATH]", player.name, "died because of", by_player and by_player.name or event.cause.name) 42 | else 43 | add_log_line("[DEATH]", player.name, "died because of unknown reason") 44 | end 45 | end 46 | 47 | --- @param event EventData.on_research_finished 48 | local function on_research_finished(event) 49 | if event.by_script then 50 | return 51 | end 52 | 53 | local inf_research_level = config_res.inf_res[config_res.mod_set][event.research.name] 54 | if inf_research_level and event.research.level >= inf_research_level then 55 | add_log_line_locale{ "", "[RES] ", event.research.prototype.localised_name, " at level ", event.research.level - 1, "has been researched\n" } 56 | else 57 | add_log_line_locale{ "", "[RES] ", event.research.prototype.localised_name, "has been researched\n" } 58 | end 59 | end 60 | 61 | --- @param event EventData.on_player_joined_game 62 | local function on_player_joined_game(event) 63 | local player = assert(game.get_player(event.player_index)) 64 | add_log_line("[JOIN]", player.name, "joined the game") 65 | end 66 | 67 | --- @param event EventData.on_player_left_game 68 | local function on_player_left_game(event) 69 | local player = assert(game.get_player(event.player_index)) 70 | add_log_line("[LEAVE]", game.players[event.player_index].name, config.disconnect_reason[event.reason]) 71 | end 72 | 73 | local e = defines.events 74 | 75 | return { 76 | events = { 77 | [e.on_cargo_pod_finished_ascending] = on_cargo_pod_finished_ascending, 78 | [e.on_pre_player_died] = on_pre_player_died, 79 | [e.on_research_finished] = on_research_finished, 80 | [e.on_player_joined_game] = on_player_joined_game, 81 | [e.on_player_left_game] = on_player_left_game, 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /.github/workflows/fmtk.yml: -------------------------------------------------------------------------------- 1 | name: FMTK Lint 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | lint: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: pnpm/action-setup@v4 13 | with: 14 | version: 10 15 | - uses: actions/setup-node@v4 16 | with: 17 | node-version: lts/* 18 | cache: "pnpm" 19 | - name: Install FMTK 20 | run: | 21 | pnpm install factoriomod-debug 22 | pnpm exec fmtk luals-addon 23 | jq '.["workspace.library"] += ["${{ github.workspace }}/factorio/library"] | .["runtime.plugin"] = "${{ github.workspace }}/factorio/plugin.lua"' .luarc.json > temp.luarc.json 24 | jq -s '.[0] * .[1].settings' temp.luarc.json ${{ github.workspace }}/factorio/config.json > check.luarc.json 25 | - name: Install LuaLS 26 | run: | 27 | wget https://github.com/LuaLS/lua-language-server/releases/download/3.15.0/lua-language-server-3.15.0-linux-x64.tar.gz -q -O lusls.tar.gz 28 | mkdir luals && tar -xf lusls.tar.gz -C luals && rm lusls.tar.gz 29 | - name: Run Lint Report 30 | shell: bash 31 | run: | 32 | ./luals/bin/lua-language-server --check=. --logpath=. --configpath=check.luarc.json --checklevel=Information --check_out_path=check.json 33 | 34 | # Credit to https://github.com/Krealle/luals-check-action/blob/main/action.yml 35 | # Although some minor fixes were needed 36 | 37 | # Format and print the messages (would be nice to format as a table, but that's too complex for jq) 38 | cat check.json | \ 39 | jq -r \ 40 | 'to_entries | map(.key as $file | .value[] | 41 | { 42 | file: $file | sub("file://${{ github.workspace }}/./"; ""), 43 | code: .code, 44 | line: .range.start.line, 45 | message: (.message | split("\n") 46 | | map(if startswith("- ") then .[2:] else . end) 47 | | join("\n")), 48 | severity: (if .severity <= 1 then "ERR" else "WARN" end) 49 | }) | 50 | map("**[\(.severity)] \(.code):** \(.file)#L\(.line)
\(.message)") | .[]' \ 51 | > $GITHUB_STEP_SUMMARY 52 | 53 | echo "" 54 | 55 | # Github Annotations (limited to 10) 56 | cat check.json | \ 57 | jq -r \ 58 | 'to_entries | map(.key as $file | .value[] | 59 | { 60 | file: $file | sub("file://${{ github.workspace }}/./"; ""), 61 | title: .code, 62 | line: .range.start.line, 63 | endLine: .range.end.line, 64 | col: .range.start.character, 65 | endColumn: .range.end.character, 66 | message: .message | gsub("\n"; "%0A"; "m"), 67 | level: (if .severity <= 1 then "error" else "warning" end) 68 | }) | 69 | map("::\(.level) file=\(.file),line=\(.line+1),endLine=\(.line+1),col=\(.col+1),endColumn=\(.endColumn+1),title=\(.title)::\(.message) (\(.title))") | .[]' 70 | 71 | if [[ $(wc -l < check.json) > 1 ]] ; then 72 | exit 1 73 | else 74 | echo "✅ All checks succeeded!" | tee $GITHUB_STEP_SUMMARY 75 | fi 76 | -------------------------------------------------------------------------------- /exp_groups/web/components/groupTree.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { Tree } from 'antd'; 3 | import type { TreeDataNode, TreeProps } from 'antd'; 4 | 5 | const defaultData: TreeDataNode[] = [ 6 | { 7 | title: "Group 1", 8 | key: "G-1", 9 | icon: false, 10 | children: [ 11 | { 12 | title: "Role 1", 13 | key: "R-1" 14 | }, 15 | { 16 | title: "Role 2", 17 | key: "R-2" 18 | }, 19 | { 20 | title: "Role 3", 21 | key: "R-3" 22 | } 23 | ] 24 | }, 25 | { 26 | title: "Group 2", 27 | key: "G-2", 28 | icon: false, 29 | children: [ 30 | { 31 | title: "Role 4", 32 | key: "R-4" 33 | }, 34 | { 35 | title: "Role 5", 36 | key: "R-5" 37 | } 38 | ] 39 | }, 40 | { 41 | title: "Default", 42 | key: "G-3", 43 | icon: false, 44 | children: [ 45 | { 46 | title: "Role 6", 47 | key: "R-6" 48 | } 49 | ] 50 | } 51 | ]; 52 | 53 | export function GroupTree() { 54 | const [gData, setGData] = useState(defaultData); 55 | 56 | const onDrop: TreeProps['onDrop'] = (info) => { 57 | const dropKey = info.node.key; 58 | const dragKey = info.dragNode.key; 59 | const dropPos = info.node.pos.split('-'); 60 | const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]); // the drop position relative to the drop node, inside 0, top -1, bottom 1 61 | 62 | const findKey = ( 63 | data: TreeDataNode[], 64 | key: React.Key, 65 | callback: (node: TreeDataNode, i: number, data: TreeDataNode[]) => void, 66 | ) => { 67 | for (let i = 0; i < data.length; i++) { 68 | if (data[i].key === key) { 69 | return callback(data[i], i, data); 70 | } 71 | if (data[i].children) { 72 | findKey(data[i].children!, key, callback); 73 | } 74 | } 75 | }; 76 | 77 | const data = [...gData] 78 | 79 | // Find dragObject 80 | let dragObj: TreeDataNode; 81 | findKey(data, dragKey, (item, index, arr) => { 82 | arr.splice(index, 1); 83 | dragObj = item; 84 | }); 85 | 86 | if (!info.dropToGap) { 87 | // Drop on the content 88 | findKey(data, dropKey, (item) => { 89 | item.children = item.children || []; 90 | // where to insert. New item was inserted to the start of the array in this example, but can be anywhere 91 | item.children.unshift(dragObj); 92 | }); 93 | } else { 94 | let ar: TreeDataNode[] = []; 95 | let i: number; 96 | findKey(data, dropKey, (_item, index, arr) => { 97 | ar = arr; 98 | i = index; 99 | }); 100 | if (dropPosition === -1) { 101 | // Drop on the top of the drop node 102 | ar.splice(i!, 0, dragObj!); 103 | } else { 104 | // Drop on the bottom of the drop node 105 | ar.splice(i! + 1, 0, dragObj!); 106 | } 107 | } 108 | 109 | setGData(data) 110 | }; 111 | 112 | const allowDrop: TreeProps['allowDrop'] = ({dragNode, dropNode, dropPosition}) => { 113 | const dragType = (dragNode.key as string).charAt(0); 114 | const dropType = (dropNode.key as string).charAt(0); 115 | return dropType === dragType && dropPosition != 0 || dragType === "R" && dropType === "G" && dropPosition == 0 116 | } 117 | 118 | return ( 119 | 128 | ); 129 | }; 130 | -------------------------------------------------------------------------------- /exp_legacy/module/modules/data/personal-logistic.lua: -------------------------------------------------------------------------------- 1 | local Commands = require("modules/exp_commands") 2 | local config = require("modules.exp_legacy.config.personal_logistic") --- @dep config.personal-logistic 3 | 4 | ---@param target LuaEntity | LuaPlayer 5 | ---@param amount number 6 | local function pl(target, amount) 7 | local c 8 | local s 9 | 10 | --- @cast target any Remove cast once implemented 11 | error("Needs updating to use 2.0 logistics") 12 | 13 | if target.object_name == "LuaPlayer" then 14 | c = target.clear_personal_logistic_slot 15 | s = target.set_personal_logistic_slot 16 | else 17 | c = target.clear_vehicle_logistic_slot 18 | s = target.set_vehicle_logistic_slot 19 | end 20 | 21 | for _, v in pairs(config.request) do 22 | c(config.start + v.key) 23 | end 24 | 25 | if (amount < 0) then 26 | return 27 | end 28 | 29 | local stats = target.force.get_item_production_statistics(target.surface) 30 | 31 | for k, v in pairs(config.request) do 32 | local v_min = math.ceil(v.min * amount) 33 | local v_max = math.ceil(v.max * amount) 34 | 35 | if v.stack ~= nil and v.stack ~= 1 and v.type ~= "weapon" then 36 | v_min = math.floor(v_min / v.stack) * v.stack 37 | v_max = math.ceil(v_max / v.stack) * v.stack 38 | end 39 | 40 | if v.upgrade_of == nil then 41 | if v.type ~= nil then 42 | if stats.get_input_count(k) < config.production_required[v.type] then 43 | if v_min > 0 then 44 | if v_min == v_max then 45 | v_min = math.floor((v_max * 0.5) / v.stack) * v.stack 46 | end 47 | else 48 | v_min = 0 49 | end 50 | end 51 | end 52 | 53 | s(config.start + v.key, { name = k, min = v_min, max = v_max }) 54 | else 55 | if v.type ~= nil then 56 | if stats.get_input_count(k) >= config.production_required[v.type] then 57 | s(config.start + v.key, { name = k, min = v_min, max = v_max }) 58 | local vuo = v.upgrade_of 59 | 60 | while (vuo ~= nil) do 61 | s(config.start + config.request[vuo].key, { name = vuo, min = 0, max = 0 }) 62 | vuo = config.request[vuo].upgrade_of 63 | end 64 | else 65 | s(config.start + v.key, { name = k, min = 0, max = v_max }) 66 | end 67 | end 68 | end 69 | end 70 | end 71 | 72 | Commands.new("personal-logistic", "Set Personal Logistic (-1 to cancel all) (Select spidertron to edit spidertron)") 73 | :argument("amount", "", Commands.types.integer_range(-1, 10)) 74 | :add_aliases{ "pl" } 75 | :add_flags{ "disabled" } -- Remove once implemented above 76 | :register(function(player, amount) 77 | --- @cast amount number 78 | if player.force.technologies["logistic-robotics"].researched then 79 | if player.selected ~= nil then 80 | if player.selected.name == "spidertron" then 81 | pl(player.selected, amount / 10) 82 | end 83 | else 84 | pl(player, amount / 10) 85 | end 86 | else 87 | return Commands.status.error("Personal Logistic not researched") 88 | end 89 | end) 90 | -------------------------------------------------------------------------------- /exp_legacy/module/locale/zh-CN/data.cfg: -------------------------------------------------------------------------------- 1 | [join-message] 2 | description-add=設定 / 取得你的加入信息。 3 | description-remove=移除你的加入信息。 4 | arg-message=你的加入信息。 5 | greet=[color=0,1,0] 歡迎來到 EXP 的服務器! 若果你喜歡本服務器可加入 DISCORD: __1__ [/color] 6 | message-set=你的加入信息已更新。 7 | message-get=你的加入信息為: __1__ 8 | message-cleared=你的加入信息已清除。 9 | 10 | [quickbar] 11 | saved=你的工具列已儲存。 12 | 13 | [exp-required] 14 | Warnings=警告 15 | Warnings-tooltip=你所有收到的警告 16 | Warnings-value-tooltip=你所有收到的警告 17 | 18 | [exp-settings] 19 | Colour=顏色 20 | Colour-tooltip=你的人物顏色 21 | Colour-value-tooltip=使用 /color 來更換你的人物顏色 22 | JoinMessage=加入信息 23 | JoinMessage-tooltip=你加入時所顯示的信息 24 | JoinMessage-value-tooltip=使用 /join-message 來更換加入信息 25 | QuickbarFilters=快捷欄 26 | QuickbarFilters-tooltip=快捷欄的選項 27 | QuickbarFilters-value-tooltip=使用 /save-quickbar 來更換快捷欄的選項 28 | UsesAlt=細節模式 29 | UsesAlt-tooltip=你加入時是否使用細節模式 30 | UsesAlt-value-tooltip=按下 __CONTROL__show-info__ 來更改 31 | UsesServerUps=服務器更新數 (SUPS) 32 | UsesServerUps-tooltip=現在是否顯示服務器更新數 (SUPS) 33 | UsesServerUps-value-tooltip=使用 /server-ups 來更換顯示 34 | Tag=你的人物標籤 35 | Tag-tooltip=你的人物標籤 36 | Tag-value-tooltip=使用 /tag 來更換你的人物標籤 37 | TagColor=人物標籤顏色 38 | TagColor-tooltip=你的人物標籤顏色 39 | TagColor-value-tooltip=使用 /tag-color 來更換你的人物標籤顏色 40 | Bonus=人物附加屬性 41 | Bonus-tooltip=你的人物附加屬性 42 | Bonus-value-tooltip=使用 /bonus 來更改 43 | HasEnabledDecon=快速拆除樹木 44 | ToolbarState=工具箱 45 | ToolbarState-tooltip=次序和喜愛項目 46 | ToolbarState-value-tooltip=此值在離開時自動計算 47 | 48 | [exp-statistics] 49 | MapsPlayed=地圖遊玩次數 50 | MapsPlayed-tooltip=你在本服務器遊玩過的地圖數 51 | JoinCount=登入次數 52 | JoinCount-tooltip=你在本服務器遊玩的次數 53 | Playtime=遊玩時間 54 | Playtime-tooltip=你在本服務器遊玩的時間 55 | AfkTime=掛機時間 56 | AfkTime-tooltip=你在本服務器掛機的時間 57 | ChatMessages=傳送信息次數 58 | ChatMessages-tooltip=你在本服務器發送信息的次數 59 | CommandsUsed=使用指令次數 60 | CommandsUsed-tooltip=你在本服務器使用指令的次數 61 | RocketsLaunched=火箭發射次數 62 | RocketsLaunched-tooltip=你在本服務器在線時所發射過火箭的次數 63 | ResearchCompleted=研究次數 64 | ResearchCompleted-tooltip=你在本服務器在線時完成研究的次數 65 | MachinesBuilt=機器建造次數 66 | MachinesBuilt-tooltip=你在本服務器建造過機器的次數 67 | MachinesRemoved=機器拆除次數 68 | MachinesRemoved-tooltip=你在本服務器拆除過機器的次數 69 | TilesBuilt=地磚建造次數 70 | TilesBuilt-tooltip=你在本服務器建造過地磚的次數 71 | TilesRemoved=地磚拆除次數 72 | TilesRemoved-tooltip=你在本服務器拆除過地磚的次數 73 | TreesDestroyed=樹木拆除次數 74 | TreesDestroyed-tooltip=你在本服務器拆除過樹木的次數 75 | OreMined=挖礦次數 76 | OreMined-tooltip=你在本服務器挖掘礦的次數 77 | ItemsCrafted=物品合成數 78 | ItemsCrafted-tooltip=你在本服務器合成過物品的次數 79 | ItemsPickedUp=物品拾起數 80 | ItemsPickedUp-tooltip=你在本服務器起過物品的次數 81 | Kills=撃殺數 82 | Kills-tooltip=你在本服務器殺過的敵人數量 83 | Deaths=死亡次數 84 | Deaths-tooltip=你在本服務器死過的數量 85 | DamageDealt=傷害量 86 | DamageDealt-tooltip=你在本伺服器對敵人所造成的傷害量 87 | DistanceTravelled=移動距離 88 | DistanceTravelled-tooltip=你在本服務器的總移動距離 89 | CapsulesUsed=膠囊使用次數 90 | CapsulesUsed-tooltip=你在本服務器使用過膠囊的次數 91 | EntityRepaired=機器維修次數 92 | EntityRepaired-tooltip=你在本服務器維修過機器的次數 93 | DeconstructionPlannerUsed=拆除規劃器使用次數 94 | DeconstructionPlannerUsed-tooltip=你在本服務器使用過拆除規劃器的次數 95 | MapTagsMade=地圖標籤數量 96 | MapTagsMade-tooltip=你在本服務器放過的地圖標籤數量 97 | DamageDeathRatio=傷害死亡比 98 | DamageDeathRatio-tooltip=傷害除以死亡 99 | KillDeathRatio=撃殺死亡比 100 | KillDeathRatio-tooltip=撃殺除以死亡 101 | SessionTime=平均遊玩時間 102 | SessionTime-tooltip=平均遊玩時間 103 | BuildRatio=建築比 104 | BuildRatio-tooltip=建築次數除以拆除次數 105 | RocketPerHour=每小時火箭發射次數 106 | RocketPerHour-tooltip=火箭發射次數除以遊玩時間 107 | TreeKillPerMinute=每分鐘樹木拆除數 108 | TreeKillPerMinute-tooltip=樹木拆除數除以遊玩時間 109 | NetPlayTime=淨遊玩時間 110 | NetPlayTime-tooltip=遊玩時間減掛機時間 111 | AFKTimeRatio=掛機時間比 112 | AFKTimeRatio-tooltip=掛機時間除以遊玩時間 113 | Locale=語言 114 | Locale-tooltip=用戶介面語言 115 | -------------------------------------------------------------------------------- /exp_legacy/module/locale/zh-TW/data.cfg: -------------------------------------------------------------------------------- 1 | [join-message] 2 | description-add=設定 / 取得你的加入信息。 3 | description-remove=移除你的加入信息。 4 | arg-message=你的加入信息。 5 | greet=[color=0,1,0] 歡迎來到 EXP 的服務器! 若果你喜歡本服務器可加入 DISCORD: __1__ [/color] 6 | message-set=你的加入信息已更新。 7 | message-get=你的加入信息為: __1__ 8 | message-cleared=你的加入信息已清除。 9 | 10 | [quickbar] 11 | saved=你的工具列已儲存。 12 | 13 | [exp-required] 14 | Warnings=警告 15 | Warnings-tooltip=你所有收到的警告 16 | Warnings-value-tooltip=你所有收到的警告 17 | 18 | [exp-settings] 19 | Colour=顏色 20 | Colour-tooltip=你的人物顏色 21 | Colour-value-tooltip=使用 /color 來更換你的人物顏色 22 | JoinMessage=加入信息 23 | JoinMessage-tooltip=你加入時所顯示的信息 24 | JoinMessage-value-tooltip=使用 /join-message 來更換加入信息 25 | QuickbarFilters=快捷欄 26 | QuickbarFilters-tooltip=快捷欄的選項 27 | QuickbarFilters-value-tooltip=使用 /save-quickbar 來更換快捷欄的選項 28 | UsesAlt=細節模式 29 | UsesAlt-tooltip=你加入時是否使用細節模式 30 | UsesAlt-value-tooltip=按下 __CONTROL__show-info__ 來更改 31 | UsesServerUps=服務器更新數 (SUPS) 32 | UsesServerUps-tooltip=現在是否顯示服務器更新數 (SUPS) 33 | UsesServerUps-value-tooltip=使用 /server-ups 來更換顯示 34 | Tag=你的人物標籤 35 | Tag-tooltip=你的人物標籤 36 | Tag-value-tooltip=使用 /tag 來更換你的人物標籤 37 | TagColor=人物標籤顏色 38 | TagColor-tooltip=你的人物標籤顏色 39 | TagColor-value-tooltip=使用 /tag-color 來更換你的人物標籤顏色 40 | Bonus=人物附加屬性 41 | Bonus-tooltip=你的人物附加屬性 42 | Bonus-value-tooltip=使用 /bonus 來更改 43 | HasEnabledDecon=快速拆除樹木 44 | ToolbarState=工具箱 45 | ToolbarState-tooltip=次序和喜愛項目 46 | ToolbarState-value-tooltip=此值在離開時自動計算 47 | 48 | [exp-statistics] 49 | MapsPlayed=地圖遊玩次數 50 | MapsPlayed-tooltip=你在本服務器遊玩過的地圖數 51 | JoinCount=登入次數 52 | JoinCount-tooltip=你在本服務器遊玩的次數 53 | Playtime=遊玩時間 54 | Playtime-tooltip=你在本服務器遊玩的時間 55 | AfkTime=掛機時間 56 | AfkTime-tooltip=你在本服務器掛機的時間 57 | ChatMessages=傳送信息次數 58 | ChatMessages-tooltip=你在本服務器發送信息的次數 59 | CommandsUsed=使用指令次數 60 | CommandsUsed-tooltip=你在本服務器使用指令的次數 61 | RocketsLaunched=火箭發射次數 62 | RocketsLaunched-tooltip=你在本服務器在線時所發射過火箭的次數 63 | ResearchCompleted=研究次數 64 | ResearchCompleted-tooltip=你在本服務器在線時完成研究的次數 65 | MachinesBuilt=機器建造次數 66 | MachinesBuilt-tooltip=你在本服務器建造過機器的次數 67 | MachinesRemoved=機器拆除次數 68 | MachinesRemoved-tooltip=你在本服務器拆除過機器的次數 69 | TilesBuilt=地磚建造次數 70 | TilesBuilt-tooltip=你在本服務器建造過地磚的次數 71 | TilesRemoved=地磚拆除次數 72 | TilesRemoved-tooltip=你在本服務器拆除過地磚的次數 73 | TreesDestroyed=樹木拆除次數 74 | TreesDestroyed-tooltip=你在本服務器拆除過樹木的次數 75 | OreMined=挖礦次數 76 | OreMined-tooltip=你在本服務器挖掘礦的次數 77 | ItemsCrafted=物品合成數 78 | ItemsCrafted-tooltip=你在本服務器合成過物品的次數 79 | ItemsPickedUp=物品拾起數 80 | ItemsPickedUp-tooltip=你在本服務器起過物品的次數 81 | Kills=撃殺數 82 | Kills-tooltip=你在本服務器殺過的敵人數量 83 | Deaths=死亡次數 84 | Deaths-tooltip=你在本服務器死過的數量 85 | DamageDealt=傷害量 86 | DamageDealt-tooltip=你在本伺服器對敵人所造成的傷害量 87 | DistanceTravelled=移動距離 88 | DistanceTravelled-tooltip=你在本服務器的總移動距離 89 | CapsulesUsed=膠囊使用次數 90 | CapsulesUsed-tooltip=你在本服務器使用過膠囊的次數 91 | EntityRepaired=機器維修次數 92 | EntityRepaired-tooltip=你在本服務器維修過機器的次數 93 | DeconstructionPlannerUsed=拆除規劃器使用次數 94 | DeconstructionPlannerUsed-tooltip=你在本服務器使用過拆除規劃器的次數 95 | MapTagsMade=地圖標籤數量 96 | MapTagsMade-tooltip=你在本服務器放過的地圖標籤數量 97 | DamageDeathRatio=傷害死亡比 98 | DamageDeathRatio-tooltip=傷害除以死亡 99 | KillDeathRatio=撃殺死亡比 100 | KillDeathRatio-tooltip=撃殺除以死亡 101 | SessionTime=平均遊玩時間 102 | SessionTime-tooltip=平均遊玩時間 103 | BuildRatio=建築比 104 | BuildRatio-tooltip=建築次數除以拆除次數 105 | RocketPerHour=每小時火箭發射次數 106 | RocketPerHour-tooltip=火箭發射次數除以遊玩時間 107 | TreeKillPerMinute=每分鐘樹木拆除數 108 | TreeKillPerMinute-tooltip=樹木拆除數除以遊玩時間 109 | NetPlayTime=淨遊玩時間 110 | NetPlayTime-tooltip=遊玩時間減掛機時間 111 | AFKTimeRatio=掛機時間比 112 | AFKTimeRatio-tooltip=掛機時間除以遊玩時間 113 | Locale=語言 114 | Locale-tooltip=用戶介面語言 115 | --------------------------------------------------------------------------------