mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 03:25:23 +09:00
Setup exp_scenario for commands
This commit is contained in:
@@ -62,7 +62,7 @@ end
|
|||||||
authorities.character_only =
|
authorities.character_only =
|
||||||
add(function(player, command)
|
add(function(player, command)
|
||||||
if command.flags.character_only and player.controller_type ~= defines.controllers.character then
|
if command.flags.character_only and player.controller_type ~= defines.controllers.character then
|
||||||
return deny{ "exp-commands-permissions.character-only" }
|
return deny{ "exp-commands-authorities.character-only" }
|
||||||
else
|
else
|
||||||
return allow()
|
return allow()
|
||||||
end
|
end
|
||||||
@@ -72,7 +72,7 @@ authorities.character_only =
|
|||||||
authorities.remote_only =
|
authorities.remote_only =
|
||||||
add(function(player, command)
|
add(function(player, command)
|
||||||
if command.flags.character_only and player.controller_type ~= defines.controllers.remote then
|
if command.flags.character_only and player.controller_type ~= defines.controllers.remote then
|
||||||
return deny{ "exp-commands-permissions.remote-only" }
|
return deny{ "exp-commands-authorities.remote-only" }
|
||||||
else
|
else
|
||||||
return allow()
|
return allow()
|
||||||
end
|
end
|
||||||
@@ -82,7 +82,7 @@ authorities.remote_only =
|
|||||||
authorities.admin_only =
|
authorities.admin_only =
|
||||||
add(function(player, command)
|
add(function(player, command)
|
||||||
if command.flags.admin_only and not player.admin then
|
if command.flags.admin_only and not player.admin then
|
||||||
return deny{ "exp-commands-permissions.admin-only" }
|
return deny{ "exp-commands-authorities.admin-only" }
|
||||||
else
|
else
|
||||||
return allow()
|
return allow()
|
||||||
end
|
end
|
||||||
@@ -92,7 +92,7 @@ authorities.admin_only =
|
|||||||
authorities.system_only =
|
authorities.system_only =
|
||||||
add(function(player, command)
|
add(function(player, command)
|
||||||
if command.flags.system_only and not system_players[player.name] then
|
if command.flags.system_only and not system_players[player.name] then
|
||||||
return deny{ "exp-commands-permissions.system-only" }
|
return deny{ "exp-commands-authorities.system-only" }
|
||||||
else
|
else
|
||||||
return allow()
|
return allow()
|
||||||
end
|
end
|
||||||
@@ -102,7 +102,7 @@ authorities.system_only =
|
|||||||
authorities.disabled =
|
authorities.disabled =
|
||||||
add(function(_player, command)
|
add(function(_player, command)
|
||||||
if disabled_commands[command.name] then
|
if disabled_commands[command.name] then
|
||||||
return deny{ "exp-commands-permissions.disabled" }
|
return deny{ "exp-commands-authorities.disabled" }
|
||||||
else
|
else
|
||||||
return allow()
|
return allow()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -45,19 +45,22 @@ local function format_as_pages(commands, page_size)
|
|||||||
description = command.description
|
description = command.description
|
||||||
end
|
end
|
||||||
|
|
||||||
local aliases = #command.aliases > 0 and { "exp-commands-help.aliases", table.concat(command.aliases, ", ") } or ""
|
local aliases = #command.aliases > 0 and { "exp-commands_help.aliases", table.concat(command.aliases, ", ") } or ""
|
||||||
pages[current_page][page_length] = { "exp-commands-help.format", command.name, description, aliases }
|
pages[current_page][page_length] = { "exp-commands_help.format", command.name, description, aliases }
|
||||||
end
|
end
|
||||||
|
|
||||||
return pages, total
|
return pages, total
|
||||||
end
|
end
|
||||||
|
|
||||||
Commands.new("commands", { "exp-commands-help.description" })
|
Commands.new("commands", { "exp-commands_help.description" })
|
||||||
:add_aliases{ "chelp", "helpp" }
|
:optional("keyword", { "exp-commands_help.arg-keyword" }, Commands.types.string)
|
||||||
:optional("keyword", { "exp-commands-help.arg-keyword" }, Commands.types.string)
|
:optional("page", { "exp-commands_help.arg-page" }, Commands.types.integer)
|
||||||
:optional("page", { "exp-commands-help.arg-page" }, Commands.types.integer)
|
|
||||||
:defaults{ keyword = "", page = 1 }
|
:defaults{ keyword = "", page = 1 }
|
||||||
|
:add_aliases{ "chelp", "helpp" }
|
||||||
:register(function(player, keyword, page)
|
:register(function(player, keyword, page)
|
||||||
|
--- @cast keyword string | number
|
||||||
|
--- @cast page number
|
||||||
|
|
||||||
-- Allow listing of all commands
|
-- Allow listing of all commands
|
||||||
local as_number = tonumber(keyword)
|
local as_number = tonumber(keyword)
|
||||||
local cache = search_cache[player.index]
|
local cache = search_cache[player.index]
|
||||||
@@ -81,20 +84,20 @@ Commands.new("commands", { "exp-commands-help.description" })
|
|||||||
|
|
||||||
-- Error if no pages found
|
-- Error if no pages found
|
||||||
if found == 0 then
|
if found == 0 then
|
||||||
return Commands.status.success{ "exp-commands-help.no-results" }
|
return Commands.status.success{ "exp-commands_help.no-results" }
|
||||||
end
|
end
|
||||||
|
|
||||||
local page_data = pages[page]
|
local page_data = pages[page]
|
||||||
if page_data == nil then
|
if page_data == nil then
|
||||||
-- Page number was out of range for this search
|
-- Page number was out of range for this search
|
||||||
return Commands.status.invalid_input{ "exp-commands-help.out-of-range", page, #pages }
|
return Commands.status.invalid_input{ "exp-commands_help.out-of-range", page, #pages }
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Print selected page to the player
|
-- Print selected page to the player
|
||||||
Commands.print{ "exp-commands-help.header", keyword == "" and "<all>" or keyword }
|
Commands.print{ "exp-commands_help.header", keyword == "" and "<all>" or keyword }
|
||||||
for _, command in pairs(page_data) do
|
for _, command in pairs(page_data) do
|
||||||
Commands.print(command)
|
Commands.print(command)
|
||||||
end
|
end
|
||||||
|
|
||||||
return Commands.status.success{ "exp-commands-help.footer", found, page, #pages }
|
return Commands.status.success{ "exp-commands_help.footer", found, page, #pages }
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -11,12 +11,15 @@ local Clustorio = require("modules/clusterio/api")
|
|||||||
|
|
||||||
local json_to_table = helpers.json_to_table
|
local json_to_table = helpers.json_to_table
|
||||||
|
|
||||||
Commands.new("_ipc", { "exp-commands-ipc.description" })
|
Commands.new("_ipc", { "exp-commands_ipc.description" })
|
||||||
:add_flags{ "system_only" }
|
:argument("channel", { "exp-commands_ipc.arg-channel" }, Commands.types.string)
|
||||||
|
:argument("message", { "exp-commands_ipc.arg-message" }, Commands.types.string)
|
||||||
:enable_auto_concatenation()
|
:enable_auto_concatenation()
|
||||||
:argument("channel", { "exp-commands-ipc.arg-channel" }, Commands.types.string)
|
:add_flags{ "system_only" }
|
||||||
:argument("message", { "exp-commands-ipc.arg-message" }, Commands.types.string)
|
|
||||||
:register(function(_player, channel, message)
|
:register(function(_player, channel, message)
|
||||||
|
--- @cast channel string
|
||||||
|
--- @cast message string
|
||||||
|
|
||||||
local tbl = json_to_table(message)
|
local tbl = json_to_table(message)
|
||||||
if tbl == nil then
|
if tbl == nil then
|
||||||
return Commands.status.invalid_input("Invalid json string")
|
return Commands.status.invalid_input("Invalid json string")
|
||||||
|
|||||||
@@ -61,11 +61,13 @@ function Commands.add_rcon_callback(name, callback)
|
|||||||
rcon_callbacks[name] = callback
|
rcon_callbacks[name] = callback
|
||||||
end
|
end
|
||||||
|
|
||||||
Commands.new("_rcon", { "exp-commands-rcon.description" })
|
Commands.new("_rcon", { "exp-commands_rcon.description" })
|
||||||
:add_flags{ "system_only" }
|
:argument("invocation", { "exp-commands_rcon.arg-invocation" }, Commands.types.string)
|
||||||
:enable_auto_concatenation()
|
:enable_auto_concatenation()
|
||||||
:argument("invocation", { "exp-commands-rcon.arg-invocation" }, Commands.types.string)
|
:add_flags{ "system_only" }
|
||||||
:register(function(player, invocation_string)
|
:register(function(player, invocation_string)
|
||||||
|
--- @cast invocation_string string
|
||||||
|
|
||||||
-- Construct the environment the command will run within
|
-- Construct the environment the command will run within
|
||||||
local env = setmetatable({}, { __index = rcon_env, __newindex = rcon_env })
|
local env = setmetatable({}, { __index = rcon_env, __newindex = rcon_env })
|
||||||
for name, callback in pairs(rcon_callbacks) do
|
for name, callback in pairs(rcon_callbacks) do
|
||||||
|
|||||||
@@ -9,13 +9,17 @@ System command to execute a command as another player using their permissions (e
|
|||||||
|
|
||||||
local Commands = require("modules/exp_commands")
|
local Commands = require("modules/exp_commands")
|
||||||
|
|
||||||
Commands.new("_sudo", { "exp-commands-sudo.description" })
|
Commands.new("_sudo", { "exp-commands_sudo.description" })
|
||||||
:add_flags{ "system_only" }
|
:argument("player", { "exp-commands_sudo.arg-player" }, Commands.types.player)
|
||||||
|
:argument("command", { "exp-commands_sudo.arg-command" }, Commands.types.key_of(Commands.registered_commands))
|
||||||
|
:argument("arguments", { "exp-commands_sudo.arg-arguments" }, Commands.types.string)
|
||||||
:enable_auto_concatenation()
|
:enable_auto_concatenation()
|
||||||
:argument("player", { "exp-commands-sudo.arg-player" }, Commands.types.player)
|
:add_flags{ "system_only" }
|
||||||
:argument("command", { "exp-commands-sudo.arg-command" }, Commands.types.string_key(Commands.registered_commands))
|
|
||||||
:argument("arguments", { "exp-commands-sudo.arg-arguments" }, Commands.types.string)
|
|
||||||
:register(function(_player, player, command, parameter)
|
:register(function(_player, player, command, parameter)
|
||||||
|
--- @cast player LuaPlayer
|
||||||
|
--- @cast command Commands.ExpCommand
|
||||||
|
--- @cast parameter string
|
||||||
|
|
||||||
--- @diagnostic disable-next-line: invisible
|
--- @diagnostic disable-next-line: invisible
|
||||||
return Commands._event_handler{
|
return Commands._event_handler{
|
||||||
name = command.name,
|
name = command.name,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ The default data types that are available to all commands
|
|||||||
Adds parsers for:
|
Adds parsers for:
|
||||||
boolean
|
boolean
|
||||||
string_options - options: array of strings
|
string_options - options: array of strings
|
||||||
string_key - map: table of string keys and any values
|
key_of - map: table of string keys and any values
|
||||||
string_max_length - maximum: number
|
string_max_length - maximum: number
|
||||||
number
|
number
|
||||||
integer
|
integer
|
||||||
@@ -19,188 +19,230 @@ Adds parsers for:
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local ExpUtil = require("modules/exp_util")
|
local ExpUtil = require("modules/exp_util")
|
||||||
|
local auto_complete = ExpUtil.auto_complete
|
||||||
|
|
||||||
local Commands = require("modules/exp_commands")
|
local Commands = require("modules/exp_commands")
|
||||||
local add, parse = Commands.add_data_type, Commands.parse_input
|
local add, parse = Commands.add_data_type, Commands.parse_input
|
||||||
local valid, invalid = Commands.status.success, Commands.status.invalid_input
|
local valid, invalid = Commands.status.success, Commands.status.invalid_input
|
||||||
|
|
||||||
|
local types = {}
|
||||||
|
|
||||||
--- A boolean value where true is one of: yes, y, true, 1
|
--- A boolean value where true is one of: yes, y, true, 1
|
||||||
add("boolean", function(input)
|
--- @type Commands.InputParser
|
||||||
input = input:lower()
|
types.boolean =
|
||||||
if input == "yes"
|
add("boolean", function(input)
|
||||||
or input == "y"
|
input = input:lower()
|
||||||
or input == "true"
|
if input == "yes"
|
||||||
or input == "1" then
|
or input == "y"
|
||||||
return valid(true)
|
or input == "true"
|
||||||
else
|
or input == "1" then
|
||||||
return valid(false)
|
return valid(true)
|
||||||
end
|
else
|
||||||
end)
|
return valid(false)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
--- A string, validation does nothing but it is a requirement
|
--- A string, validation does nothing but it is a requirement
|
||||||
--- @type Commands.InputParser
|
--- @type Commands.InputParser
|
||||||
add("string", function(input)
|
types.string =
|
||||||
return valid(input)
|
add("string", function(input)
|
||||||
end)
|
return valid(input)
|
||||||
|
end)
|
||||||
|
|
||||||
--- A string from a set of options, takes one argument which is an array of options
|
--- A string from a set of options, takes one argument which is an array of options
|
||||||
--- @param options string[] The options which can be selected
|
--- @type Commands.InputParserFactory
|
||||||
--- @return Commands.InputParser
|
types.enum =
|
||||||
add("string_array", function(options)
|
add("enum", function(options)
|
||||||
return function(input)
|
--- @cast options string[]
|
||||||
local option = ExpUtil.auto_complete(options, input)
|
return function(input)
|
||||||
if option == nil then
|
local option = auto_complete(options, input)
|
||||||
return invalid{ "exp-commands-parse.string-options", table.concat(options, ", ") }
|
if option == nil then
|
||||||
else
|
return invalid{ "exp-commands-parse.string-options", table.concat(options, ", ") }
|
||||||
return valid(option)
|
else
|
||||||
|
return valid(option)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
end)
|
|
||||||
|
|
||||||
--- A string which is the key of a table, takes one argument which is an map of string keys to values
|
--- A string which is the key of a table, takes one argument which is an map of string keys to values
|
||||||
--- @param map { [string]: any } The options which can be selected
|
--- @type Commands.InputParserFactory
|
||||||
--- @return Commands.InputParser
|
types.key_of =
|
||||||
add("string_key", function(map)
|
add("key_of", function(map)
|
||||||
return function(input)
|
--- @cast map { [string]: any }
|
||||||
local option = ExpUtil.auto_complete(map, input, true)
|
return function(input)
|
||||||
if option == nil then
|
local option = auto_complete(map, input, true)
|
||||||
return invalid{ "exp-commands-parse.string-options", table.concat(table.get_keys(map), ", ") }
|
if option == nil then
|
||||||
else
|
return invalid{ "exp-commands-parse.string-options", table.concat(table.get_keys(map), ", ") }
|
||||||
return valid(option)
|
else
|
||||||
|
return valid(option)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
end)
|
|
||||||
|
|
||||||
--- A string with a maximum length, takes one argument which is the maximum length of a string
|
--- A string with a maximum length, takes one argument which is the maximum length of a string
|
||||||
--- @param maximum number The maximum length of the input
|
--- @type Commands.InputParserFactory
|
||||||
--- @return Commands.InputParser
|
types.string_max_length =
|
||||||
add("string_max_length", function(maximum)
|
add("string_max_length", function(maximum)
|
||||||
return function(input)
|
--- @cast maximum number
|
||||||
if input:len() > maximum then
|
return function(input)
|
||||||
return invalid{ "exp-commands-parse.string-max-length", maximum }
|
if input:len() > maximum then
|
||||||
else
|
return invalid{ "exp-commands-parse.string-max-length", maximum }
|
||||||
return valid(input)
|
else
|
||||||
|
return valid(input)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
end)
|
|
||||||
|
|
||||||
--- A number
|
--- A number
|
||||||
add("number", function(input)
|
--- @type Commands.InputParser
|
||||||
local number = tonumber(input)
|
types.number =
|
||||||
if number == nil then
|
add("number", function(input)
|
||||||
return invalid{ "exp-commands-parse.number" }
|
local number = tonumber(input)
|
||||||
else
|
if number == nil then
|
||||||
return valid(number)
|
return invalid{ "exp-commands-parse.number" }
|
||||||
end
|
else
|
||||||
end)
|
return valid(number)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
--- An integer, number which has been floored
|
--- An integer, number which has been floored
|
||||||
add("integer", function(input)
|
--- @type Commands.InputParser
|
||||||
local number = tonumber(input)
|
types.integer =
|
||||||
if number == nil then
|
add("integer", function(input)
|
||||||
return invalid{ "exp-commands-parse.number" }
|
local number = tonumber(input)
|
||||||
else
|
if number == nil then
|
||||||
return valid(math.floor(number))
|
return invalid{ "exp-commands-parse.number" }
|
||||||
end
|
else
|
||||||
end)
|
return valid(math.floor(number))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
--- A number in a given inclusive range
|
--- A number in a given inclusive range
|
||||||
--- @param minimum number The minimum of the allowed range, inclusive
|
--- @type Commands.InputParserFactory
|
||||||
--- @param maximum number The maximum of the allowed range, inclusive
|
types.number_range =
|
||||||
--- @return Commands.InputParser
|
add("number_range", function(minimum, maximum)
|
||||||
add("number_range", function(minimum, maximum)
|
--- @cast minimum number
|
||||||
local parser_number = Commands.types.number
|
--- @cast maximum number
|
||||||
return function(input, player)
|
local parser_number = Commands.types.number
|
||||||
local success, status, result = parse(input, player, parser_number)
|
return function(input, player)
|
||||||
if not success then
|
local success, status, result = parse(input, player, parser_number)
|
||||||
return status, result
|
if not success then
|
||||||
elseif result < minimum or result > maximum then
|
return status, result
|
||||||
return invalid{ "exp-commands-parse.number-range", minimum, maximum }
|
elseif result < minimum or result > maximum then
|
||||||
else
|
return invalid{ "exp-commands-parse.number-range", minimum, maximum }
|
||||||
return valid(result)
|
else
|
||||||
|
return valid(result)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
end)
|
|
||||||
|
|
||||||
--- An integer in a given inclusive range
|
--- An integer in a given inclusive range
|
||||||
--- @param minimum number The minimum of the allowed range, inclusive
|
--- @type Commands.InputParserFactory
|
||||||
--- @param maximum number The maximum of the allowed range, inclusive
|
types.integer_range =
|
||||||
--- @return Commands.InputParser
|
add("integer_range", function(minimum, maximum)
|
||||||
add("integer_range", function(minimum, maximum)
|
--- @cast minimum number
|
||||||
local parser_integer = Commands.types.integer
|
--- @cast maximum number
|
||||||
return function(input, player)
|
local parser_integer = Commands.types.integer
|
||||||
local success, status, result = parse(input, player, parser_integer)
|
return function(input, player)
|
||||||
|
local success, status, result = parse(input, player, parser_integer)
|
||||||
|
if not success then
|
||||||
|
return status, result
|
||||||
|
elseif result < minimum or result > maximum then
|
||||||
|
return invalid{ "exp-commands-parse.number-range", minimum, maximum }
|
||||||
|
else
|
||||||
|
return valid(result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- A player who has joined the game at least once
|
||||||
|
--- @type Commands.InputParser
|
||||||
|
types.player =
|
||||||
|
add("player", function(input)
|
||||||
|
local player = game.get_player(input)
|
||||||
|
if player == nil then
|
||||||
|
return invalid{ "exp-commands-parse.player", input }
|
||||||
|
else
|
||||||
|
return valid(player)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- A player who is online
|
||||||
|
--- @type Commands.InputParser
|
||||||
|
types.player_online =
|
||||||
|
add("player_online", function(input, player)
|
||||||
|
local success, status, result = parse(input, player, Commands.types.player)
|
||||||
|
--- @cast result LuaPlayer
|
||||||
if not success then
|
if not success then
|
||||||
return status, result
|
return status, result
|
||||||
elseif result < minimum or result > maximum then
|
elseif result.connected == false then
|
||||||
return invalid{ "exp-commands-parse.number-range", minimum, maximum }
|
return invalid{ "exp-commands-parse.player-online" }
|
||||||
else
|
else
|
||||||
return valid(result)
|
return valid(result)
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
end)
|
|
||||||
|
|
||||||
--- A player who has joined the game at least once
|
|
||||||
add("player", function(input)
|
|
||||||
local player = game.get_player(input)
|
|
||||||
if player == nil then
|
|
||||||
return invalid{ "exp-commands-parse.player", input }
|
|
||||||
else
|
|
||||||
return valid(player)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- A player who is online
|
|
||||||
add("player_online", function(input, player)
|
|
||||||
local success, status, result = parse(input, player, Commands.types.player)
|
|
||||||
--- @cast result LuaPlayer
|
|
||||||
if not success then
|
|
||||||
return status, result
|
|
||||||
elseif result.connected == false then
|
|
||||||
return invalid{ "exp-commands-parse.player-online" }
|
|
||||||
else
|
|
||||||
return valid(result)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- A player who is online and alive
|
--- A player who is online and alive
|
||||||
add("player_alive", function(input, player)
|
--- @type Commands.InputParser
|
||||||
local success, status, result = parse(input, player, Commands.types.player_online)
|
types.player_online =
|
||||||
--- @cast result LuaPlayer
|
add("player_alive", function(input, player)
|
||||||
if not success then
|
local success, status, result = parse(input, player, Commands.types.player_online)
|
||||||
return status, result
|
--- @cast result LuaPlayer
|
||||||
elseif result.character == nil or result.character.health <= 0 then
|
if not success then
|
||||||
return invalid{ "exp-commands-parse.player-alive" }
|
return status, result
|
||||||
else
|
elseif result.character == nil or result.character.health <= 0 then
|
||||||
return valid(result)
|
return invalid{ "exp-commands-parse.player-alive" }
|
||||||
end
|
else
|
||||||
end)
|
return valid(result)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
--- A force within the game
|
--- A force within the game
|
||||||
add("force", function(input)
|
--- @type Commands.InputParser
|
||||||
local force = game.forces[input]
|
types.force =
|
||||||
if force == nil then
|
add("force", function(input)
|
||||||
return invalid{ "exp-commands-parse.force" }
|
local force = game.forces[input]
|
||||||
else
|
if force == nil then
|
||||||
return valid(force)
|
return invalid{ "exp-commands-parse.force" }
|
||||||
end
|
else
|
||||||
end)
|
return valid(force)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
--- A surface within the game
|
--- A surface within the game
|
||||||
add("surface", function(input)
|
--- @type Commands.InputParser
|
||||||
local surface = game.surfaces[input]
|
types.surface =
|
||||||
if surface == nil then
|
add("surface", function(input)
|
||||||
return invalid{ "exp-commands-parse.surface" }
|
local surface = game.surfaces[input]
|
||||||
else
|
if surface == nil then
|
||||||
return valid(surface)
|
return invalid{ "exp-commands-parse.surface" }
|
||||||
end
|
else
|
||||||
end)
|
return valid(surface)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- A planet within the game
|
||||||
|
--- @type Commands.InputParser
|
||||||
|
types.planet =
|
||||||
|
add("planet", function(input)
|
||||||
|
local surface = game.planets[input]
|
||||||
|
if surface == nil then
|
||||||
|
return invalid{ "exp-commands-parse.planet" }
|
||||||
|
else
|
||||||
|
return valid(surface)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
--- A name of a color from the predefined list, too many colours to use string-key
|
--- A name of a color from the predefined list, too many colours to use string-key
|
||||||
add("color", function(input)
|
--- @type Commands.InputParser
|
||||||
local color = ExpUtil.auto_complete(Commands.color, input, true)
|
types.color =
|
||||||
if color == nil then
|
add("color", function(input)
|
||||||
return invalid{ "exp-commands-parse.color" }
|
local color = auto_complete(Commands.color, input, true)
|
||||||
else
|
if color == nil then
|
||||||
return valid(color)
|
return invalid{ "exp-commands-parse.color" }
|
||||||
end
|
else
|
||||||
end)
|
return valid(color)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
return types
|
||||||
|
|||||||
@@ -27,16 +27,17 @@ player-online=Player is offline.
|
|||||||
player-alive=Player is dead.
|
player-alive=Player is dead.
|
||||||
force=Invalid Force Name.
|
force=Invalid Force Name.
|
||||||
surface=Invalid Surface Name.
|
surface=Invalid Surface Name.
|
||||||
|
planet=Invalid Planet Name.
|
||||||
color=Invalid Color Name.
|
color=Invalid Color Name.
|
||||||
|
|
||||||
[exp-commands-permissions]
|
[exp-commands-authorities]
|
||||||
character-only=This command can not be used in remote view.
|
character-only=This command can not be used in remote view.
|
||||||
remote-only=This command can only be used in remote view.
|
remote-only=This command can only be used in remote view.
|
||||||
admin-only=This command is for game admins only.
|
admin-only=This command is for game admins only.
|
||||||
system-only=This command can not be ran by players.
|
system-only=This command can not be ran by players.
|
||||||
disabled=This command is currently disabled.
|
disabled=This command is currently disabled.
|
||||||
|
|
||||||
[exp-commands-help]
|
[exp-commands_help]
|
||||||
description=List and search all commands for a keyword
|
description=List and search all commands for a keyword
|
||||||
arg-keyword=The keyword to search for
|
arg-keyword=The keyword to search for
|
||||||
arg-page=The results page to display
|
arg-page=The results page to display
|
||||||
@@ -47,16 +48,16 @@ aliases=Aliaies: __1__
|
|||||||
out-of-range=__1__ is an invalid page number. Last page: __2__
|
out-of-range=__1__ is an invalid page number. Last page: __2__
|
||||||
no-results=No commands were found
|
no-results=No commands were found
|
||||||
|
|
||||||
[exp-commands-ipc]
|
[exp-commands_ipc]
|
||||||
description=Send an IPC message on the selected channel
|
description=Send an IPC message on the selected channel
|
||||||
arg-channel=The channel to send the IPC message on
|
arg-channel=The channel to send the IPC message on
|
||||||
arg-message=The message to send on the IPC channel
|
arg-message=The message to send on the IPC channel
|
||||||
|
|
||||||
[exp-commands-rcon]
|
[exp-commands_rcon]
|
||||||
description=Execute arbitrary code within a custom environment
|
description=Execute arbitrary code within a custom environment
|
||||||
arg-invocation=The code to run
|
arg-invocation=The code to run
|
||||||
|
|
||||||
[exp-commands-sudo]
|
[exp-commands_sudo]
|
||||||
description=Run a command as another player
|
description=Run a command as another player
|
||||||
arg-player=The player to run the command as
|
arg-player=The player to run the command as
|
||||||
arg-command=The command to run
|
arg-command=The command to run
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ function Commands.on_init() Search.prepare(Commands.registered_commands) end
|
|||||||
--- @package
|
--- @package
|
||||||
function Commands.on_load() Search.prepare(Commands.registered_commands) end
|
function Commands.on_load() Search.prepare(Commands.registered_commands) end
|
||||||
|
|
||||||
--- @alias Commands.Callback fun(player: LuaPlayer, ...: any): Commands.Status?, LocalisedString?
|
--- @alias Commands.Callback fun(player: LuaPlayer, ...: any?): Commands.Status?, LocalisedString?
|
||||||
--- This is a default callback that should never be called
|
--- This is a default callback that should never be called
|
||||||
local function default_command_callback()
|
local function default_command_callback()
|
||||||
return Commands.status.internal_error("No callback registered")
|
return Commands.status.internal_error("No callback registered")
|
||||||
@@ -276,22 +276,29 @@ end
|
|||||||
--- @alias Commands.InputParserFactory fun(...: any): Commands.InputParser<T>
|
--- @alias Commands.InputParserFactory fun(...: any): Commands.InputParser<T>
|
||||||
|
|
||||||
--- Add a new input parser to the command library, this method validates that it does not already exist
|
--- Add a new input parser to the command library, this method validates that it does not already exist
|
||||||
|
--- @generic T : Commands.InputParser | Commands.InputParserFactory
|
||||||
--- @param data_type string The name of the data type the input parser reads in and validates, becomes a key of Commands.types
|
--- @param data_type string The name of the data type the input parser reads in and validates, becomes a key of Commands.types
|
||||||
--- @param input_parser Commands.InputParser | Commands.InputParserFactory The function used to parse and validate the data type
|
--- @param input_parser `T` The function used to parse and validate the data type
|
||||||
--- @return string # The data type passed as the first argument
|
--- @return T # The function which was provided as the second argument
|
||||||
function Commands.add_data_type(data_type, input_parser)
|
function Commands.add_data_type(data_type, input_parser)
|
||||||
if Commands.types[data_type] then
|
if Commands.types[data_type] then
|
||||||
local defined_at = ExpUtil.get_function_name(Commands.types[data_type], true)
|
local defined_at = ExpUtil.get_function_name(Commands.types[data_type], true)
|
||||||
error("Data type \"" .. tostring(data_type) .. "\" already has a parser registered: " .. defined_at, 2)
|
error("Data type \"" .. tostring(data_type) .. "\" already has a parser registered: " .. defined_at, 2)
|
||||||
end
|
end
|
||||||
Commands.types[data_type] = input_parser
|
Commands.types[data_type] = input_parser
|
||||||
return data_type
|
return input_parser
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Remove an input parser for a data type, must be the same string that was passed to add_input_parser
|
--- Remove an input parser for a data type, must be the same string that was passed to add_input_parser
|
||||||
--- @param data_type string The name of data type you want to remove the input parser for
|
--- @param data_type string | Commands.InputParser | Commands.InputParserFactory The data type or input parser you want to remove the input parser for
|
||||||
function Commands.remove_data_type(data_type)
|
function Commands.remove_data_type(data_type)
|
||||||
Commands.types[data_type] = nil
|
Commands.types[data_type] = nil
|
||||||
|
for k, v in pairs(Commands.types) do
|
||||||
|
if v == data_type then
|
||||||
|
Commands.types[k] = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Parse and validate an input string as a given data type
|
--- Parse and validate an input string as a given data type
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../../tsconfig.node.json",
|
"extends": "../tsconfig.node.json",
|
||||||
"references": [
|
|
||||||
{ "path": "../../../packages/lib/tsconfig.node.json" },
|
|
||||||
],
|
|
||||||
"include": ["./**/*.ts"],
|
"include": ["./**/*.ts"],
|
||||||
"exclude": ["test/*", "./dist/*"],
|
"exclude": ["test/*", "./dist/*"],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../../tsconfig.node.json",
|
"extends": "../tsconfig.node.json",
|
||||||
"references": [
|
|
||||||
{ "path": "../../../packages/lib/tsconfig.node.json" },
|
|
||||||
],
|
|
||||||
"include": ["./**/*.ts"],
|
"include": ["./**/*.ts"],
|
||||||
"exclude": ["test/*", "./dist/*"],
|
"exclude": ["test/*", "./dist/*"],
|
||||||
}
|
}
|
||||||
|
|||||||
3
exp_scenario/.gitignore
vendored
Normal file
3
exp_scenario/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
dist/
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
1697
exp_scenario/.luacheckrc
Normal file
1697
exp_scenario/.luacheckrc
Normal file
File diff suppressed because it is too large
Load Diff
3
exp_scenario/.npmignore
Normal file
3
exp_scenario/.npmignore
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
webpack.config.js
|
||||||
|
dist/web/build
|
||||||
|
dist/browser
|
||||||
7
exp_scenario/controller.ts
Normal file
7
exp_scenario/controller.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import * as lib from "@clusterio/lib";
|
||||||
|
import { BaseControllerPlugin, InstanceInfo } from "@clusterio/controller";
|
||||||
|
|
||||||
|
export class ControllerPlugin extends BaseControllerPlugin {
|
||||||
|
async init() {
|
||||||
|
}
|
||||||
|
}
|
||||||
37
exp_scenario/index.ts
Normal file
37
exp_scenario/index.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import * as lib from "@clusterio/lib";
|
||||||
|
import * as Messages from "./messages";
|
||||||
|
|
||||||
|
lib.definePermission({
|
||||||
|
name: "exp_scenario.config.view",
|
||||||
|
title: "View ExpScenario Config",
|
||||||
|
description: "View the config for all submodules of ExpScenario",
|
||||||
|
});
|
||||||
|
|
||||||
|
lib.definePermission({
|
||||||
|
name: "exp_scenario.config.edit",
|
||||||
|
title: "Edit ExpScenario Config",
|
||||||
|
description: "Edit the config for all submodules of ExpScenario",
|
||||||
|
});
|
||||||
|
|
||||||
|
declare module "@clusterio/lib" {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const plugin: lib.PluginDeclaration = {
|
||||||
|
name: "exp_scenario",
|
||||||
|
title: "exp_scenario",
|
||||||
|
description: "Example Description. Plugin. Change me in index.ts",
|
||||||
|
controllerEntrypoint: "./dist/node/controller",
|
||||||
|
instanceEntrypoint: "./dist/node/instance",
|
||||||
|
|
||||||
|
messages: [
|
||||||
|
Messages.PluginExampleEvent,
|
||||||
|
Messages.PluginExampleRequest,
|
||||||
|
Messages.ExampleSubscribableUpdate,
|
||||||
|
],
|
||||||
|
|
||||||
|
webEntrypoint: "./web",
|
||||||
|
routes: [
|
||||||
|
"/exp_scenario",
|
||||||
|
],
|
||||||
|
};
|
||||||
10
exp_scenario/instance.ts
Normal file
10
exp_scenario/instance.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import * as lib from "@clusterio/lib";
|
||||||
|
import { BaseInstancePlugin } from "@clusterio/host";
|
||||||
|
|
||||||
|
export class InstancePlugin extends BaseInstancePlugin {
|
||||||
|
async init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
async onStart() {
|
||||||
|
}
|
||||||
|
}
|
||||||
95
exp_scenario/messages.ts
Normal file
95
exp_scenario/messages.ts
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import { plainJson, jsonArray, JsonBoolean, JsonNumber, JsonString, StringEnum } from "@clusterio/lib";
|
||||||
|
import { Type, Static } from "@sinclair/typebox";
|
||||||
|
|
||||||
|
export class PluginExampleEvent {
|
||||||
|
declare ["constructor"]: typeof PluginExampleEvent;
|
||||||
|
static type = "event" as const;
|
||||||
|
static src = ["host", "control"] as const;
|
||||||
|
static dst = ["controller", "host", "instance"] as const;
|
||||||
|
static plugin = "exp_scenario" as const;
|
||||||
|
static permission = "exp_scenario.example.permission.event";
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public myString: string,
|
||||||
|
public myNumberArray: number[],
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static jsonSchema = Type.Object({
|
||||||
|
"myString": Type.String(),
|
||||||
|
"myNumberArray": Type.Array(Type.Number()),
|
||||||
|
});
|
||||||
|
|
||||||
|
static fromJSON(json: Static<typeof PluginExampleEvent.jsonSchema>) {
|
||||||
|
return new PluginExampleEvent(json.myString, json.myNumberArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PluginExampleRequest {
|
||||||
|
declare ["constructor"]: typeof PluginExampleRequest;
|
||||||
|
static type = "request" as const;
|
||||||
|
static src = ["host", "control"] as const;
|
||||||
|
static dst = ["controller", "host", "instance"] as const;
|
||||||
|
static plugin = "exp_scenario" as const;
|
||||||
|
static permission = "exp_scenario.example.permission.request";
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public myString: string,
|
||||||
|
public myNumberArray: number[],
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static jsonSchema = Type.Object({
|
||||||
|
"myString": Type.String(),
|
||||||
|
"myNumberArray": Type.Array(Type.Number()),
|
||||||
|
});
|
||||||
|
|
||||||
|
static fromJSON(json: Static<typeof PluginExampleRequest.jsonSchema>) {
|
||||||
|
return new PluginExampleRequest(json.myString, json.myNumberArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Response = plainJson(Type.Object({
|
||||||
|
"myResponseString": Type.String(),
|
||||||
|
"myResponseNumbers": Type.Array(Type.Number()),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ExampleSubscribableValue {
|
||||||
|
constructor(
|
||||||
|
public id: string,
|
||||||
|
public updatedAtMs: number,
|
||||||
|
public isDeleted: boolean,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static jsonSchema = Type.Object({
|
||||||
|
id: Type.String(),
|
||||||
|
updatedAtMs: Type.Number(),
|
||||||
|
isDeleted: Type.Boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
static fromJSON(json: Static<typeof this.jsonSchema>) {
|
||||||
|
return new this(json.id, json.updatedAtMs, json.isDeleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ExampleSubscribableUpdate {
|
||||||
|
declare ["constructor"]: typeof ExampleSubscribableUpdate;
|
||||||
|
static type = "event" as const;
|
||||||
|
static src = "controller" as const;
|
||||||
|
static dst = "control" as const;
|
||||||
|
static plugin = "exp_scenario" as const;
|
||||||
|
static permission = "exp_scenario.example.permission.subscribe";
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public updates: ExampleSubscribableValue[],
|
||||||
|
) { }
|
||||||
|
|
||||||
|
static jsonSchema = Type.Object({
|
||||||
|
"updates": Type.Array(ExampleSubscribableValue.jsonSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
static fromJSON(json: Static<typeof this.jsonSchema>) {
|
||||||
|
return new this(json.updates.map(update => ExampleSubscribableValue.fromJSON(update)));
|
||||||
|
}
|
||||||
|
}
|
||||||
19
exp_scenario/module/commands/authorities.lua
Normal file
19
exp_scenario/module/commands/authorities.lua
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
local Commands = require("modules/exp_commands")
|
||||||
|
local add, allow, deny = Commands.add_permission_authority, Commands.status.success, Commands.status.unauthorised
|
||||||
|
|
||||||
|
local Roles = require("modules/exp_legacy/expcore/roles")
|
||||||
|
|
||||||
|
local authorities = {}
|
||||||
|
|
||||||
|
--- If a command has the flag "character_only" then the command can only be used outside of remote view
|
||||||
|
authorities.exp_permission =
|
||||||
|
add(function(player, command)
|
||||||
|
if not Roles.player_allowed(player, command.flags.exp_permission or ("command/" .. command)) then
|
||||||
|
return deny{ "exp-commands-authorities_role.deny" }
|
||||||
|
else
|
||||||
|
return allow()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
return authorities
|
||||||
97
exp_scenario/module/commands/types.lua
Normal file
97
exp_scenario/module/commands/types.lua
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
|
||||||
|
--[[-- Command Types - Roles
|
||||||
|
The data types that are used with exp_roles
|
||||||
|
|
||||||
|
Adds parsers for:
|
||||||
|
role
|
||||||
|
lower_role
|
||||||
|
lower_role_player
|
||||||
|
lower_role_player_online
|
||||||
|
lower_role_player_alive
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Commands = require("modules/exp_commands")
|
||||||
|
local add, parse = Commands.add_data_type, Commands.parse_input
|
||||||
|
local valid, invalid = Commands.status.success, Commands.status.invalid_input
|
||||||
|
|
||||||
|
local Roles = require("modules.exp_legacy.expcore.roles")
|
||||||
|
local highest_role = Roles.get_player_highest_role
|
||||||
|
local key_of_roles = Commands.types.key_of(Roles.config.roles)
|
||||||
|
|
||||||
|
local types = {}
|
||||||
|
|
||||||
|
--- A role defined by exp roles
|
||||||
|
--- @type Commands.InputParser
|
||||||
|
types.role =
|
||||||
|
add("role", function(input, player)
|
||||||
|
local _, status, rtn = parse(input, player, key_of_roles)
|
||||||
|
return status, rtn
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- A role which is lower than the players highest role
|
||||||
|
--- @type Commands.InputParser
|
||||||
|
types.lower_role =
|
||||||
|
add("lower_role", function(input, player)
|
||||||
|
local success, status, result = parse(input, player, types.role)
|
||||||
|
if not success then return status, result end
|
||||||
|
--- @cast result any TODO role is not a defined type
|
||||||
|
|
||||||
|
local player_highest = highest_role(player)
|
||||||
|
if player_highest.index >= result.index then
|
||||||
|
return invalid{ "exp-commands-parse_role.lower-role" }
|
||||||
|
else
|
||||||
|
return valid(result)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- A player who is of a lower role than the executing player
|
||||||
|
--- @type Commands.InputParser
|
||||||
|
types.lower_role_player =
|
||||||
|
add("lower_role_player", function(input, player)
|
||||||
|
local success, status, result = parse(input, player, Commands.types.player)
|
||||||
|
if not success then return status, result end
|
||||||
|
--- @cast result LuaPlayer
|
||||||
|
|
||||||
|
local other_highest = highest_role(result)
|
||||||
|
local player_highest = highest_role(player)
|
||||||
|
if player_highest.index < other_highest.index then
|
||||||
|
return invalid{ "exp-commands-parse_role.lower-role-player" }
|
||||||
|
else
|
||||||
|
return valid(result)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- A player who is of a lower role than the executing player
|
||||||
|
--- @type Commands.InputParser
|
||||||
|
types.lower_role_player_online =
|
||||||
|
add("lower_role_player", function(input, player)
|
||||||
|
local success, status, result = parse(input, player, Commands.types.player_online)
|
||||||
|
if not success then return status, result end
|
||||||
|
--- @cast result LuaPlayer
|
||||||
|
|
||||||
|
local other_highest = highest_role(result)
|
||||||
|
local player_highest = highest_role(player)
|
||||||
|
if player_highest.index < other_highest.index then
|
||||||
|
return invalid{ "exp-commands-parse_role.lower-role-player" }
|
||||||
|
else
|
||||||
|
return valid(result)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- A player who is of a lower role than the executing player
|
||||||
|
types.lower_role_player_alive =
|
||||||
|
add("lower_role_player", function(input, player)
|
||||||
|
local success, status, result = parse(input, player, Commands.types.player_alive)
|
||||||
|
if not success then return status, result end
|
||||||
|
--- @cast result LuaPlayer
|
||||||
|
|
||||||
|
local other_highest = highest_role(result)
|
||||||
|
local player_highest = highest_role(player)
|
||||||
|
if player_highest.index < other_highest.index then
|
||||||
|
return invalid{ "exp-commands-parse_role.lower-role-player" }
|
||||||
|
else
|
||||||
|
return valid(result)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
return types
|
||||||
9
exp_scenario/module/control.lua
Normal file
9
exp_scenario/module/control.lua
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
--- Command Extensions
|
||||||
|
require("modules.exp_scenario/commands/types")
|
||||||
|
require("modules.exp_scenario/commands/authorities")
|
||||||
|
|
||||||
|
--- Commands
|
||||||
|
require("modules/exp_scenario/commands/admin_chat")
|
||||||
|
require("modules/exp_scenario/commands/bot_queues")
|
||||||
|
require("modules/exp_scenario/commands/cheat")
|
||||||
6
exp_scenario/module/locale/en.cfg
Normal file
6
exp_scenario/module/locale/en.cfg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[exp-commands-authorities_role]
|
||||||
|
deny=Unauthorized, Access is denied due to missing permissions
|
||||||
|
|
||||||
|
[exp-commands-parse_role]
|
||||||
|
lower-role=Role is higher than your highest.
|
||||||
|
lower-role-player=Player has a higher role.
|
||||||
13
exp_scenario/module/module.json
Normal file
13
exp_scenario/module/module.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "exp_scenario",
|
||||||
|
"load": [
|
||||||
|
],
|
||||||
|
"require": [
|
||||||
|
"control.lua"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"clusterio": "*",
|
||||||
|
"exp_util": "*",
|
||||||
|
"exp_commands": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
38
exp_scenario/package.json
Normal file
38
exp_scenario/package.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "exp_scenario",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Example Description. Package. Change me in package.json",
|
||||||
|
"main": "dist/node/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"prepare": "tsc --build && webpack-cli --env production"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@clusterio/lib": "workspace:*"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.5.3",
|
||||||
|
"@types/node": "^20.4.5",
|
||||||
|
"@types/react": "^18.2.21",
|
||||||
|
"antd": "^5.13.0",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"webpack": "^5.88.2",
|
||||||
|
"webpack-cli": "^5.1.4",
|
||||||
|
"webpack-merge": "^5.9.0",
|
||||||
|
"@clusterio/web_ui": "workspace:*",
|
||||||
|
"@clusterio/lib": "workspace:*"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@sinclair/typebox": "^0.30.4"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"clusterio",
|
||||||
|
"factorio"
|
||||||
|
]
|
||||||
|
}
|
||||||
4
exp_scenario/tsconfig.browser.json
Normal file
4
exp_scenario/tsconfig.browser.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.browser.json",
|
||||||
|
"include": [ "web/**/*.tsx", "web/**/*.ts", "messages.ts", "package.json" ],
|
||||||
|
}
|
||||||
7
exp_scenario/tsconfig.json
Normal file
7
exp_scenario/tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{ "path": "./tsconfig.browser.json" },
|
||||||
|
{ "path": "./tsconfig.node.json" }
|
||||||
|
]
|
||||||
|
}
|
||||||
5
exp_scenario/tsconfig.node.json
Normal file
5
exp_scenario/tsconfig.node.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.node.json",
|
||||||
|
"include": ["./**/*.ts"],
|
||||||
|
"exclude": ["test/*", "./dist/*"],
|
||||||
|
}
|
||||||
68
exp_scenario/web/index.tsx
Normal file
68
exp_scenario/web/index.tsx
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import React, {
|
||||||
|
useContext, useEffect, useState,
|
||||||
|
useCallback, useSyncExternalStore,
|
||||||
|
} from "react";
|
||||||
|
|
||||||
|
// import {
|
||||||
|
//
|
||||||
|
// } from "antd";
|
||||||
|
|
||||||
|
import {
|
||||||
|
BaseWebPlugin, PageLayout, PageHeader, Control, ControlContext, notifyErrorHandler,
|
||||||
|
} from "@clusterio/web_ui";
|
||||||
|
|
||||||
|
import {
|
||||||
|
PluginExampleEvent, PluginExampleRequest,
|
||||||
|
ExampleSubscribableUpdate, ExampleSubscribableValue,
|
||||||
|
} from "../messages";
|
||||||
|
|
||||||
|
import * as lib from "@clusterio/lib";
|
||||||
|
|
||||||
|
function MyTemplatePage() {
|
||||||
|
const control = useContext(ControlContext);
|
||||||
|
const plugin = control.plugins.get("exp_scenario") as WebPlugin;
|
||||||
|
const [subscribableData, synced] = plugin.useSubscribableData();
|
||||||
|
|
||||||
|
return <PageLayout nav={[{ name: "exp_scenario" }]}>
|
||||||
|
<PageHeader title="exp_scenario" />
|
||||||
|
Synced: {String(synced)} Data: {JSON.stringify([...subscribableData.values()])}
|
||||||
|
</PageLayout>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WebPlugin extends BaseWebPlugin {
|
||||||
|
subscribableData = new lib.EventSubscriber(ExampleSubscribableUpdate, this.control);
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
this.pages = [
|
||||||
|
{
|
||||||
|
path: "/exp_scenario",
|
||||||
|
sidebarName: "exp_scenario",
|
||||||
|
// This permission is client side only, so it must match the permission string of a resource request to be secure
|
||||||
|
// An undefined value means that the page will always be visible
|
||||||
|
permission: "exp_scenario.example.permission.subscribe",
|
||||||
|
content: <MyTemplatePage/>,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
this.control.handle(PluginExampleEvent, this.handlePluginExampleEvent.bind(this));
|
||||||
|
this.control.handle(PluginExampleRequest, this.handlePluginExampleRequest.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
useSubscribableData() {
|
||||||
|
const control = useContext(ControlContext);
|
||||||
|
const subscribe = useCallback((callback: () => void) => this.subscribableData.subscribe(callback), [control]);
|
||||||
|
return useSyncExternalStore(subscribe, () => this.subscribableData.getSnapshot());
|
||||||
|
}
|
||||||
|
|
||||||
|
async handlePluginExampleEvent(event: PluginExampleEvent) {
|
||||||
|
this.logger.info(JSON.stringify(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
async handlePluginExampleRequest(request: PluginExampleRequest) {
|
||||||
|
this.logger.info(JSON.stringify(request));
|
||||||
|
return {
|
||||||
|
myResponseString: request.myString,
|
||||||
|
myResponseNumbers: request.myNumberArray,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
32
exp_scenario/webpack.config.js
Normal file
32
exp_scenario/webpack.config.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
"use strict";
|
||||||
|
const path = require("path");
|
||||||
|
const webpack = require("webpack");
|
||||||
|
const { merge } = require("webpack-merge");
|
||||||
|
|
||||||
|
const common = require("@clusterio/web_ui/webpack.common");
|
||||||
|
|
||||||
|
module.exports = (env = {}) => merge(common(env), {
|
||||||
|
context: __dirname,
|
||||||
|
entry: "./web/index.tsx",
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, "dist", "web"),
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.container.ModuleFederationPlugin({
|
||||||
|
name: "exp_scenario",
|
||||||
|
library: { type: "window", name: "plugin_exp_scenario" },
|
||||||
|
exposes: {
|
||||||
|
"./": "./index.ts",
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
"./web": "./web/index.tsx",
|
||||||
|
},
|
||||||
|
shared: {
|
||||||
|
"@clusterio/lib": { import: false },
|
||||||
|
"@clusterio/web_ui": { import: false },
|
||||||
|
"antd": { import: false },
|
||||||
|
"react": { import: false },
|
||||||
|
"react-dom": { import: false },
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
@@ -1,11 +1,5 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../../tsconfig.node.json",
|
"extends": "../tsconfig.node.json",
|
||||||
"references": [
|
|
||||||
{ "path": "../../../packages/lib/tsconfig.node.json" },
|
|
||||||
],
|
|
||||||
"include": ["./**/*.ts"],
|
"include": ["./**/*.ts"],
|
||||||
"exclude": ["test/*", "./dist/*"],
|
"exclude": ["test/*", "./dist/*"],
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "dist/node",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|||||||
7
tsconfig.browser.json
Normal file
7
tsconfig.browser.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.browser.json",
|
||||||
|
"references": [
|
||||||
|
{ "path": "../../packages/lib/tsconfig.browser.json" },
|
||||||
|
{ "path": "../../packages/web_ui/tsconfig.browser.json" },
|
||||||
|
]
|
||||||
|
}
|
||||||
6
tsconfig.node.json
Normal file
6
tsconfig.node.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.node.json",
|
||||||
|
"references": [
|
||||||
|
{ "path": "../../packages/lib/tsconfig.node.json" },
|
||||||
|
],
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user