Merge branch 'explosivegaming:main' into aperx

This commit is contained in:
2026-08-10 20:35:30 +09:00
committed by GitHub
97 changed files with 781 additions and 2434 deletions
+34
View File
@@ -0,0 +1,34 @@
{
"$schema": "https://raw.githubusercontent.com/EmmyLuaLs/emmylua-analyzer-rust/refs/heads/main/crates/emmylua_code_analysis/resources/schema.json",
"runtime": {
"version": "Lua5.2",
"requirePattern": [ "?", "?.lua" ]
},
"workspace": {
"$comment-moduleMap": "Replaces the fmtk --clusterio-modules plugin, rewrites each file's own module path rather than the require string",
"$comment-library": "clusterio is outside this repo, set CLUSTERIO to your checkout. The factorio typedefs come from .luarc.json, which the factoriomod-debug extension manages",
"library": [ "$CLUSTERIO/packages/host" ],
"ignoreDir": [ ".github", "web", "dist", "factorio" ],
"ignoreGlobs": [ "**/node_modules/**", "**/dist/**", "**/campaigns/**" ],
"moduleMap": [
{ "pattern": "^([^.]+)\\.module\\.module_exports$", "replace": "modules.$1" },
{ "pattern": "^([^.]+)\\.module\\.(.+)$", "replace": "modules.$1.$2" }
]
},
"doc": {
"privateName": [ "__*" ]
},
"$comment-disable": "Carried over from the luals config, which had these as editor only rather than checked in ci",
"$comment-unnecessary-if": "Disabled by the config fmtk generates for itself, the api union types make it unreliable",
"diagnostics": {
"globals": [ "__DebugAdapter", "__Profiler" ],
"disable": [
"assign-type-mismatch",
"param-type-mismatch",
"preferred-local-alias",
"unnecessary-assert",
"unnecessary-if",
"unused"
]
}
}
+94 -76
View File
@@ -1,76 +1,94 @@
name: FMTK Lint name: Lua Lint
on: on:
push: push:
pull_request: pull_request:
jobs: env:
lint: EMMYLUA_CHECK_VERSION: "0.24.0"
runs-on: ubuntu-latest CLUSTERIO: ${{ github.workspace }}/.clusterio
steps:
- uses: actions/checkout@v4 jobs:
- uses: pnpm/action-setup@v4 lint:
with: runs-on: ubuntu-latest
version: 10 steps:
- uses: actions/setup-node@v4 - uses: actions/checkout@v4
with: - name: Checkout clusterio modules
node-version: lts/* uses: actions/checkout@v4
- name: Install FMTK with:
run: | repository: clusterio/clusterio
# Pinned: 2.1.4+ generates typedefs targeting EmmyLua that LuaLS misreads path: .clusterio
pnpm install factoriomod-debug@2.1.3 sparse-checkout: packages/host/modules
pnpm exec fmtk luals-addon sparse-checkout-cone-mode: false
jq '.["workspace.library"] += ["${{ github.workspace }}/factorio/library"] | .["runtime.plugin"] = "${{ github.workspace }}/factorio/plugin.lua"' .luarc.json > temp.luarc.json - uses: pnpm/action-setup@v4
jq -s '.[0] * .[1].settings' temp.luarc.json ${{ github.workspace }}/factorio/config.json > check.luarc.json with:
- name: Install LuaLS version: 10
run: | - uses: actions/setup-node@v4
wget https://github.com/LuaLS/lua-language-server/releases/download/3.18.2/lua-language-server-3.18.2-linux-x64.tar.gz -q -O lusls.tar.gz with:
mkdir luals && tar -xf lusls.tar.gz -C luals && rm lusls.tar.gz node-version: lts/*
- name: Run Lint Report - name: Generate Factorio typedefs
shell: bash run: |
run: | pnpm install factoriomod-debug
./luals/bin/lua-language-server --check=. --logpath=. --configpath=check.luarc.json --checklevel=Information --check_out_path=check.json pnpm exec fmtk luals-addon "$RUNNER_TEMP"
- name: Install emmylua_check
# Credit to https://github.com/Krealle/luals-check-action/blob/main/action.yml run: |
# Although some minor fixes were needed curl -fsSL "https://github.com/EmmyLuaLs/emmylua-analyzer-rust/releases/download/${EMMYLUA_CHECK_VERSION}/emmylua_check-linux-x64.tar.gz" \
| tar -xz -C "$RUNNER_TEMP"
# Format and print the messages (would be nice to format as a table, but that's too complex for jq) - name: Run Lint Report
cat check.json | \ shell: bash
jq -r \ run: |
'to_entries | map(.key as $file | .value[] | # The typedefs are generated per run, clusterio comes from CLUSTERIO above
{ jq -n --arg lib "$RUNNER_TEMP/factorio/library" \
file: $file | sub("file://${{ github.workspace }}/./"; ""), '{ workspace: { library: [ $lib ], ignoreGlobs: [ ".clusterio/**" ] } }' \
code: .code, > "$RUNNER_TEMP/ci.emmyrc.json"
line: .range.start.line,
message: (.message | split("\n") # Exits non zero on error severity, so the gate below is used instead
| map(if startswith("- ") then .[2:] else . end) "$RUNNER_TEMP/emmylua_check" . --config ".emmyrc.json,$RUNNER_TEMP/ci.emmyrc.json" \
| join("\n")), --output-format json --output check.json || true
severity: (if .severity <= 1 then "ERR" else "WARN" end)
}) | # Credit to https://github.com/Krealle/luals-check-action/blob/main/action.yml
map("**[\(.severity)] \(.code):** \(.file)#L\(.line)<br><code>\(.message)</code>") | .[]' \ # Although some minor fixes were needed
> $GITHUB_STEP_SUMMARY
# Format and print the messages (would be nice to format as a table, but that's too complex for jq)
echo "" jq -r --arg root "$PWD/" \
'.[] | (.file | ltrimstr($root)) as $file | .diagnostics[] |
# Github Annotations (limited to 10) {
cat check.json | \ file: $file,
jq -r \ code: .code,
'to_entries | map(.key as $file | .value[] | line: .range.start.line,
{ message: (.message | split("\n")
file: $file | sub("file://${{ github.workspace }}/./"; ""), | map(if startswith("- ") then .[2:] else . end)
title: .code, | join("\n")),
line: .range.start.line, severity: (if .severity <= 1 then "ERR" else "WARN" end)
endLine: .range.end.line, } |
col: .range.start.character, "**[\(.severity)] \(.code):** \(.file)#L\(.line + 1)<br><code>\(.message)</code>"' \
endColumn: .range.end.character, check.json > "$GITHUB_STEP_SUMMARY"
message: .message | gsub("\n"; "%0A"; "m"),
level: (if .severity <= 1 then "error" else "warning" end) echo ""
}) |
map("::\(.level) file=\(.file),line=\(.line+1),endLine=\(.line+1),col=\(.col+1),endColumn=\(.endColumn+1),title=\(.title)::\(.message) (\(.title))") | .[]' # Github Annotations (limited to 10)
jq -r --arg root "$PWD/" \
if [[ $(wc -l < check.json) > 1 ]] ; then '.[] | (.file | ltrimstr($root)) as $file | .diagnostics[] |
exit 1 {
else file: $file,
echo "✅ All checks succeeded!" | tee $GITHUB_STEP_SUMMARY title: .code,
fi line: .range.start.line,
endLine: .range.end.line,
col: .range.start.character,
endColumn: .range.end.character,
message: (.message | gsub("\n"; "%0A"; "m")),
level: (if .severity <= 1 then "error" else "warning" end)
} |
"::\(.level) file=\(.file),line=\(.line + 1),endLine=\(.endLine + 1),col=\(.col + 1),endColumn=\(.endColumn + 1),title=\(.title)::\(.message) (\(.title))"' \
check.json
# An entry is emitted for every file checked, including clean ones, so
# the gate counts diagnostics and asserts the workspace was actually read
if [[ $(jq 'length' check.json) -lt 100 ]] ; then
echo "::error::Only $(jq 'length' check.json) files were checked, expected the whole workspace"
exit 1
elif [[ $(jq '[.[].diagnostics[]] | length' check.json) -gt 0 ]] ; then
exit 1
else
echo "✅ All checks succeeded!" | tee "$GITHUB_STEP_SUMMARY"
fi
+1
View File
@@ -1,3 +1,4 @@
dist/ dist/
node_modules/ node_modules/
.vscode .vscode
.luarc.json
-103
View File
@@ -1,103 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
"workspace.ignoreDir": [
".vscode", ".github", "luals", "factorio", "web"
],
"completion.requireSeparator": "/",
"runtime.pluginArgs": [
"--clusterio-modules"
],
"doc": {
"regengine": "glob",
"privateName": [ "__*" ],
"packageName": [ "_*" ]
},
"type": {
"checkTableShape": true,
"inferParamType": true
},
"$comment-name-style-check": "Disabled below until config issue fixed: https://github.com/LuaLS/lua-language-server/issues/2643",
"$comment-type-mismatch": "Disabled unless opened due to performance concerns, time reduced to 10s from 400s",
"diagnostics": {
"unusedLocalExclude": [ "_*", "i", "j", "k", "v" ],
"groupFileStatus": {
"ambiguity": "Any",
"await": "None",
"codestyle": "Opened",
"conventions": "Any",
"duplicate": "Any",
"global": "Any",
"luadoc": "Opened",
"redefined": "Opened",
"strict": "Any",
"strong": "Any",
"type-check": "Any",
"unbalanced": "Opened",
"unused": "Opened"
},
"neededFileStatus": {
"no-unknown": "None!",
"spell-check": "None!",
"name-style-check": "None!",
"assign-type-mismatch": "Opened!",
"return-type-mismatch": "Opened!",
"param-type-mismatch": "Opened!"
}
},
"nameStyle.config": {
"local_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}],
"module_local_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}, {
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "upper_snake_case"
}, {
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "pascal_case"
}],
"function_param_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}],
"function_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}],
"local_function_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}],
"table_field_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}],
"global_variable_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}, {
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "upper_snake_case"
}],
"module_name_style": [ "pascal_case", "snake_case" ],
"require_module_name_style": [ "pascal_case", "snake_case" ],
"class_name_style": "pascal_case",
"const_variable_name_style": "upper_snake_case"
},
"format.defaultConfig": {
"continuation_indent.in_expr": "0"
}
}
+2
View File
@@ -5,6 +5,8 @@ All are welcome to make bug reports, feature requests, and pull requests for our
For developers wanting to add features please follow these guidelines: For developers wanting to add features please follow these guidelines:
- All lua code is documented using ldoc. - All lua code is documented using ldoc.
- Set the `CLUSTERIO` environment variable to your clusterio development install path, the lint needs it to resolve `modules/clusterio/*`.
- Lua is checked with [emmylua](https://github.com/EmmyLuaLs/emmylua-analyzer-rust), configured by `.emmyrc.json`. Install the EmmyLua extension rather than sumnekolua / luals, and use factoriomod-debug to generate the factorio api types. Note that an inline cast must be written `--[[@as T]]`, the spaced form is not parsed.
- Changes should be made on your own fork and merged into `main` through a pull request. - Changes should be made on your own fork and merged into `main` through a pull request.
- Each pull request should be limited to one feature or a few bug fixes and link to the related issue page. - Each pull request should be limited to one feature or a few bug fixes and link to the related issue page.
- Pull requests are automatically linted and documentation checked. - Pull requests are automatically linted and documentation checked.
+3 -3
View File
@@ -10,7 +10,7 @@ The default permission authorities controlled by the flags: admin_only, system_o
local Storage = require("modules/exp_util/storage") local Storage = require("modules/exp_util/storage")
local Commands = require("modules/exp_commands") --- @class Commands local Commands = require("modules/exp_commands") --- @class (partial) Commands
local add, allow, deny = Commands.add_permission_authority, Commands.status.success, Commands.status.unauthorised local add, allow, deny = Commands.add_permission_authority, Commands.status.success, Commands.status.unauthorised
local authorities = {} local authorities = {}
@@ -28,13 +28,13 @@ end)
--- Allow a player access to system commands, use for debug purposes only --- Allow a player access to system commands, use for debug purposes only
--- @param player_name string? The name of the player to give access to, default is the current player --- @param player_name string? The name of the player to give access to, default is the current player
function Commands.unlock_system_commands(player_name) function Commands.unlock_system_commands(player_name)
system_players[player_name or game.player.name] = true system_players[player_name or assert(game.player).name] = true
end end
--- Remove access from system commands for a player, use for debug purposes only --- Remove access from system commands for a player, use for debug purposes only
--- @param player_name string? The name of the player to give access to, default is the current player --- @param player_name string? The name of the player to give access to, default is the current player
function Commands.lock_system_commands(player_name) function Commands.lock_system_commands(player_name)
system_players[player_name or game.player.name] = nil system_players[player_name or assert(game.player).name] = nil
end end
--- Get a list of all players who have system commands unlocked --- Get a list of all players who have system commands unlocked
+6 -6
View File
@@ -25,18 +25,18 @@ end)
--- @param page_size number The number of requests to show per page --- @param page_size number The number of requests to show per page
--- @return LocalisedString[][], number --- @return LocalisedString[][], number
local function format_as_pages(commands, page_size) local function format_as_pages(commands, page_size)
local pages = { {} } local current_page = {}
local pages = { current_page }
local page_length = 0 local page_length = 0
local current_page = 1
local total = 0 local total = 0
for _, command in pairs(commands) do for _, command in pairs(commands) do
total = total + 1 total = total + 1
page_length = page_length + 1 page_length = page_length + 1
if page_length > page_size then if page_length > page_size then
current_page = current_page + 1
pages[current_page] = {}
page_length = 1 page_length = 1
current_page = {}
pages[#pages + 1] = current_page
end end
local description local description
@@ -48,7 +48,7 @@ local function format_as_pages(commands, page_size)
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 } current_page[page_length] = { "exp-commands_help.format", command.name, description, aliases }
end end
return pages, total return pages, total
@@ -71,7 +71,7 @@ Commands.new("commands", { "exp-commands_help.description" })
page = as_number page = as_number
end end
keyword = keyword:lower() keyword = tostring(keyword):lower()
local pages, found local pages, found
if cache and cache.keyword == keyword then if cache and cache.keyword == keyword then
-- Cached value found, no search is needed -- Cached value found, no search is needed
+1 -3
View File
@@ -12,7 +12,7 @@ local ExpUtil = require("modules/exp_util")
local Async = require("modules/exp_util/async") local Async = require("modules/exp_util/async")
local Storage = require("modules/exp_util/storage") local Storage = require("modules/exp_util/storage")
local Commands = require("modules/exp_commands") --- @class Commands local Commands = require("modules/exp_commands") --- @class (partial) Commands
local rcon_env = {} --- @type table<string, any> local rcon_env = {} --- @type table<string, any>
local rcon_static = {} --- @type table<string, any> local rcon_static = {} --- @type table<string, any>
@@ -21,12 +21,10 @@ setmetatable(rcon_static, { __index = _G })
setmetatable(rcon_env, { __index = rcon_static }) setmetatable(rcon_env, { __index = rcon_static })
--- Some common static values which can be added now --- Some common static values which can be added now
--- @diagnostic disable: name-style-check
rcon_static.Async = Async rcon_static.Async = Async
rcon_static.ExpUtil = ExpUtil rcon_static.ExpUtil = ExpUtil
rcon_static.Commands = Commands rcon_static.Commands = Commands
rcon_static.print = Commands.print rcon_static.print = Commands.print
--- @diagnostic enable: name-style-check
--- Some common callback values which are useful when a player uses the command --- Some common callback values which are useful when a player uses the command
--- @alias ExpCommand.RconDynamic fun(player: LuaPlayer?): any --- @alias ExpCommand.RconDynamic fun(player: LuaPlayer?): any
+1 -1
View File
@@ -19,7 +19,7 @@ Commands.new("_sudo", { "exp-commands_sudo.description" })
--- @cast command ExpCommand --- @cast command ExpCommand
--- @cast parameter string --- @cast parameter string
--- @diagnostic disable-next-line: invisible --- @diagnostic disable-next-line: access-invisible
return Commands._event_handler{ return Commands._event_handler{
name = command.name, name = command.name,
tick = game.tick, tick = game.tick,
+1 -1
View File
@@ -25,7 +25,7 @@ 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 = {} --- @class Commands.types local types = {} --- @class (partial) Commands.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
types.boolean = types.boolean =
+18 -14
View File
@@ -61,7 +61,7 @@ local Search = require("modules/exp_commands/search")
--- @type LuaPlayer? --- @type LuaPlayer?
local _print_player local _print_player
--- @class Commands --- @class (partial) Commands
local Commands = { local Commands = {
color = ExpUtil.color, color = ExpUtil.color,
format_rich_text_color = ExpUtil.format_rich_text_color, format_rich_text_color = ExpUtil.format_rich_text_color,
@@ -84,7 +84,7 @@ local Commands = {
--- Contains the different status values a command can return --- Contains the different status values a command can return
Commands.status = {} Commands.status = {}
--- @class Commands.types: table<string, Commands.InputParser | Commands.InputParserFactory> --- @class (partial) Commands.types: table<string, Commands.InputParser<any> | Commands.InputParserFactory<any>>
--- Stores all input parsers and validators for different data types --- Stores all input parsers and validators for different data types
Commands.types = {} Commands.types = {}
@@ -103,7 +103,7 @@ end
--- @class Commands.Argument --- @class Commands.Argument
--- @field name string The name of the argument --- @field name string The name of the argument
--- @field description LocalisedString? The description of the argument --- @field description LocalisedString? The description of the argument
--- @field input_parser Commands.InputParser The input parser for the argument --- @field input_parser Commands.InputParser<any> The input parser for the argument
--- @field optional boolean True when the argument is optional --- @field optional boolean True when the argument is optional
--- @field default any? The default value of the argument --- @field default any? The default value of the argument
@@ -159,7 +159,7 @@ Commands.server = setmetatable({
Commands.error("Command does not support rcon usage, requires LuaPlayer." .. key) Commands.error("Command does not support rcon usage, requires LuaPlayer." .. key)
error("Command does not support rcon usage, requires LuaPlayer." .. key) error("Command does not support rcon usage, requires LuaPlayer." .. key)
end, end,
}) --[[ @as LuaPlayer ]] }) --[[@as LuaPlayer]]
--- Status Returns. --- Status Returns.
-- Return values used by command callbacks -- Return values used by command callbacks
@@ -170,7 +170,8 @@ Commands.server = setmetatable({
--- @param msg LocalisedString? An optional message to be included when a command completes (only has an effect in command callbacks) --- @param msg LocalisedString? An optional message to be included when a command completes (only has an effect in command callbacks)
--- @return Commands.Status, LocalisedString # Should be returned directly without modification --- @return Commands.Status, LocalisedString # Should be returned directly without modification
function Commands.status.success(msg) function Commands.status.success(msg)
return Commands.status.success, msg == nil and { "exp-commands.success" } or msg if msg == nil then return Commands.status.success, { "exp-commands.success" } end
return Commands.status.success, msg
end end
--- Used to signal an error has occurred in a command, data type parser, or permission authority --- Used to signal an error has occurred in a command, data type parser, or permission authority
@@ -178,7 +179,8 @@ end
--- @param msg LocalisedString? An optional error message to be included in the output, a generic message is used if not provided --- @param msg LocalisedString? An optional error message to be included in the output, a generic message is used if not provided
--- @return Commands.Status, LocalisedString # Should be returned directly without modification --- @return Commands.Status, LocalisedString # Should be returned directly without modification
function Commands.status.error(msg) function Commands.status.error(msg)
return Commands.status.error, { "exp-commands.error", msg == nil and { "exp-commands.error-default" } or msg } if msg == nil then msg = { "exp-commands.error-default" } end
return Commands.status.error, { "exp-commands.error", msg }
end end
--- Used to signal the player is unauthorised to use a command, primarily used by permission authorities but can be used in a command callback --- Used to signal the player is unauthorised to use a command, primarily used by permission authorities but can be used in a command callback
@@ -186,7 +188,8 @@ end
--- @param msg LocalisedString? An optional error message to be included in the output, a generic message is used if not provided --- @param msg LocalisedString? An optional error message to be included in the output, a generic message is used if not provided
--- @return Commands.Status, LocalisedString # Should be returned directly without modification --- @return Commands.Status, LocalisedString # Should be returned directly without modification
function Commands.status.unauthorised(msg) function Commands.status.unauthorised(msg)
return Commands.status.unauthorised, { "exp-commands.unauthorized", msg == nil and { "exp-commands.unauthorized-default" } or msg } if msg == nil then msg = { "exp-commands.unauthorized-default" } end
return Commands.status.unauthorised, { "exp-commands.unauthorized", msg }
end end
--- Used to signal the player provided invalid input to an command, primarily used by data type parsers but can be used in a command callback --- Used to signal the player provided invalid input to an command, primarily used by data type parsers but can be used in a command callback
@@ -194,15 +197,16 @@ end
--- @param msg LocalisedString? An optional error message to be included in the output, a generic message is used if not provided --- @param msg LocalisedString? An optional error message to be included in the output, a generic message is used if not provided
--- @return Commands.Status, LocalisedString # Should be returned directly without modification --- @return Commands.Status, LocalisedString # Should be returned directly without modification
function Commands.status.invalid_input(msg) function Commands.status.invalid_input(msg)
return Commands.status.invalid_input, msg == nil and { "exp-commands.invalid-input" } or msg if msg == nil then return Commands.status.invalid_input, { "exp-commands.invalid-input" } end
return Commands.status.invalid_input, msg
end end
--- Used to signal an internal error has occurred, this is reserved for internal use only --- Used to signal an internal error has occurred, this is reserved for internal use only
--- @param msg LocalisedString A message detailing the error which has occurred, will be logged and outputted --- @param msg LocalisedString? A message detailing the error which has occurred, will be logged and outputted
--- @return Commands.Status, LocalisedString # Should be returned directly without modification --- @return Commands.Status, LocalisedString # Should be returned directly without modification
--- @package --- @package
function Commands.status.internal_error(msg) function Commands.status.internal_error(msg)
return Commands.status.internal_error, { "exp-commands.internal-error", msg } return Commands.status.internal_error, { "exp-commands.internal-error", msg or "" }
end end
--- @type table<Commands.Status, string> --- @type table<Commands.Status, string>
@@ -281,7 +285,7 @@ end
--- @alias Commands.InputParserFactory<T> fun(...: any): Commands.InputParser<T> --- @alias Commands.InputParserFactory<T> 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 --- @generic T : Commands.InputParser<any> | Commands.InputParserFactory<any>
--- @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 T 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 T # The function which was provided as the second argument --- @return T # The function which was provided as the second argument
@@ -295,7 +299,7 @@ function Commands.add_data_type(data_type, 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 | Commands.InputParser | Commands.InputParserFactory The data type or input parser you want to remove the input parser for --- @param data_type string | Commands.InputParser<any> | Commands.InputParserFactory<any> 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 for k, v in pairs(Commands.types) do
@@ -433,7 +437,7 @@ end
--- Add a new required argument to the command of the given data type --- Add a new required argument to the command of the given data type
--- @param name string The name of the argument being added --- @param name string The name of the argument being added
--- @param description LocalisedString? The description of the argument being added --- @param description LocalisedString? The description of the argument being added
--- @param input_parser Commands.InputParser The input parser to be used for the argument --- @param input_parser Commands.InputParser<any> The input parser to be used for the argument
--- @return ExpCommand --- @return ExpCommand
function Commands._prototype:argument(name, description, input_parser) function Commands._prototype:argument(name, description, input_parser)
assert_command_mutable(self) assert_command_mutable(self)
@@ -454,7 +458,7 @@ end
--- Add a new optional argument to the command of the given data type --- Add a new optional argument to the command of the given data type
--- @param name string The name of the argument being added --- @param name string The name of the argument being added
--- @param description LocalisedString? The description of the argument being added --- @param description LocalisedString? The description of the argument being added
--- @param input_parser Commands.InputParser The input parser to be used for the argument --- @param input_parser Commands.InputParser<any> The input parser to be used for the argument
--- @return ExpCommand --- @return ExpCommand
function Commands._prototype:optional(name, description, input_parser) function Commands._prototype:optional(name, description, input_parser)
assert_command_mutable(self) assert_command_mutable(self)
+3 -2
View File
@@ -3,7 +3,7 @@ local Search = {}
local Storage = require("modules/exp_util/storage") local Storage = require("modules/exp_util/storage")
--- Setup the storage to contain the pending translations and the completed ones --- Setup the storage to contain the pending translations and the completed ones
local pending = {} --- @type { [1]: string, [2]: string }[] local pending = {} --- @type table<uint, [string, string]>
local translations = {} --- @type table<string, table<string, string>> local translations = {} --- @type table<string, table<string, string>>
Storage.register({ Storage.register({
pending, pending,
@@ -50,6 +50,7 @@ function Search.prepare(custom_commands)
name = name, name = name,
description = locale_desc, description = locale_desc,
help_text = locale_desc, help_text = locale_desc,
usage = locale_desc,
aliases = {}, aliases = {},
} }
end end
@@ -65,7 +66,7 @@ function Search.on_player_locale_changed(event)
local ids = player.request_translations(required_translations) local ids = player.request_translations(required_translations)
assert(ids, "Translation ids was nil") assert(ids, "Translation ids was nil")
for i, command_name in ipairs(command_names) do for i, command_name in ipairs(command_names) do
pending[ids[i]] = { locale, command_name } pending[assert(ids[i])] = { locale, command_name }
end end
end end
end end
+1 -1
View File
@@ -3,7 +3,7 @@ Adds permission group syncing to clusterio
]] ]]
local clusterio_api = require("modules/clusterio/api") local clusterio_api = require("modules/clusterio/api")
local compat = require("modules/clusterio/compat") local compat = require("modules/clusterio/compat") --[[@as LibCompat]]
--- Top level module table, contains event handlers and public methods --- Top level module table, contains event handlers and public methods
--- @class ExpGroups --- @class ExpGroups
+1 -1
View File
@@ -5,7 +5,7 @@ Therefore, we advise that this should be the only file in your module to expose
Typically this would be your control file as shown in the example below Typically this would be your control file as shown in the example below
]] ]]
--- @diagnostic disable: global-element --- @diagnostic disable: global-in-non-module
-- Access using `/sc exp_groups.foo()` -- Access using `/sc exp_groups.foo()`
exp_groups = require("modules/exp_groups/control") exp_groups = require("modules/exp_groups/control")
+17 -12
View File
@@ -16,7 +16,7 @@ Storage.register(player_elements, function(tbl)
player_elements = tbl player_elements = tbl
end) end)
--- @class Gui --- @class (partial) Gui
local Gui = { local Gui = {
define = ExpElement.new, define = ExpElement.new,
from_argument = ExpElement.from_argument, from_argument = ExpElement.from_argument,
@@ -46,9 +46,11 @@ end
--- @return LuaPlayer --- @return LuaPlayer
function Gui.get_player(input) function Gui.get_player(input)
if type(input) == "table" and not input.player_index then if type(input) == "table" and not input.player_index then
return assert(game.get_player(input.element.player_index)) --- @cast input { element: LuaGuiElement }
return (assert(game.get_player(input.element.player_index)))
end end
return assert(game.get_player(input.player_index)) --- @cast input LuaGuiElement | { player_index: uint }
return (assert(game.get_player(input.player_index)))
end end
--- Toggle the enable state of an element --- Toggle the enable state of an element
@@ -88,7 +90,7 @@ end
--- @param define ExpElement --- @param define ExpElement
--- @param visible Gui.VisibleCallback | boolean | nil --- @param visible Gui.VisibleCallback | boolean | nil
function Gui.add_top_element(define, visible) function Gui.add_top_element(define, visible)
assert(Gui.top_elements[define.name] == nil, "Element is already added to the top flow") assert(Gui.top_elements[define] == nil, "Element is already added to the top flow")
Gui.top_elements[define] = visible or false Gui.top_elements[define] = visible or false
end end
@@ -96,7 +98,7 @@ end
--- @param define ExpElement --- @param define ExpElement
--- @param visible Gui.VisibleCallback | boolean | nil --- @param visible Gui.VisibleCallback | boolean | nil
function Gui.add_left_element(define, visible) function Gui.add_left_element(define, visible)
assert(Gui.left_elements[define.name] == nil, "Element is already added to the left flow") assert(Gui.left_elements[define] == nil, "Element is already added to the left flow")
Gui.left_elements[define] = visible or false Gui.left_elements[define] = visible or false
end end
@@ -105,7 +107,7 @@ end
--- @param define ExpElement --- @param define ExpElement
--- @param visible Gui.VisibleCallback | boolean | nil --- @param visible Gui.VisibleCallback | boolean | nil
function Gui.add_relative_element(define, visible) function Gui.add_relative_element(define, visible)
assert(Gui.relative_elements[define.name] == nil, "Element is already added to the relative flow") assert(Gui.relative_elements[define] == nil, "Element is already added to the relative flow")
Gui.relative_elements[define] = visible or false Gui.relative_elements[define] = visible or false
end end
@@ -114,7 +116,8 @@ end
--- @param player LuaPlayer --- @param player LuaPlayer
--- @return LuaGuiElement --- @return LuaGuiElement
function Gui.get_top_element(define, player) function Gui.get_top_element(define, player)
return assert(player_elements[player.index].top[define.name], "Element is not on the top flow") local elements = assert(player_elements[player.index])
return (assert(elements.top[define.name], "Element is not on the top flow"))
end end
--- Register a element define to be drawn to the left flow on join --- Register a element define to be drawn to the left flow on join
@@ -122,7 +125,8 @@ end
--- @param player LuaPlayer --- @param player LuaPlayer
--- @return LuaGuiElement --- @return LuaGuiElement
function Gui.get_left_element(define, player) function Gui.get_left_element(define, player)
return assert(player_elements[player.index].left[define.name], "Element is not on the left flow") local elements = assert(player_elements[player.index])
return (assert(elements.left[define.name], "Element is not on the left flow"))
end end
--- Register a element define to be drawn to the relative flow on join --- Register a element define to be drawn to the relative flow on join
@@ -130,7 +134,8 @@ end
--- @param player LuaPlayer --- @param player LuaPlayer
--- @return LuaGuiElement --- @return LuaGuiElement
function Gui.get_relative_element(define, player) function Gui.get_relative_element(define, player)
return assert(player_elements[player.index].relative[define.name], "Element is not on the relative flow") local elements = assert(player_elements[player.index])
return (assert(elements.relative[define.name], "Element is not on the relative flow"))
end end
--- Ensure all the correct elements are visible and exist --- Ensure all the correct elements are visible and exist
@@ -188,9 +193,9 @@ function Gui._ensure_consistency(event)
-- This check isn't needed, but allows the toolbar file to be deleted without modifying any lib code -- This check isn't needed, but allows the toolbar file to be deleted without modifying any lib code
if Gui.toolbar then if Gui.toolbar then
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
Gui.toolbar._create_elements(player) Gui.toolbar._create_elements(player)
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
Gui.toolbar._ensure_consistency(player) Gui.toolbar._ensure_consistency(player)
end end
end end
@@ -211,7 +216,7 @@ local function on_gui_opened(event)
if visible then if visible then
event.element = element event.element = element
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
define:raise_event(event) define:raise_event(event)
end end
end end
+6 -2
View File
@@ -62,6 +62,7 @@ local GuiData = {
--- @field player_data table<uint, any> --- @field player_data table<uint, any>
--- @field force_data table<uint, any> --- @field force_data table<uint, any>
--- @field global_data table --- @field global_data table
--- @field [DataKey] any
-- This class has no prototype methods -- This class has no prototype methods
-- Same as raw but __index ensures the values exist -- Same as raw but __index ensures the values exist
@@ -89,13 +90,16 @@ function GuiData._metatable.__index(self, key)
assert(type(key) == "userdata", "Index type '" .. ExpUtil.get_class_name(key) .. "' given to GuiData. Must be of type userdata.") assert(type(key) == "userdata", "Index type '" .. ExpUtil.get_class_name(key) .. "' given to GuiData. Must be of type userdata.")
local object_name = key.object_name --- @diagnostic disable-line assign-type-mismatch local object_name = key.object_name --- @diagnostic disable-line assign-type-mismatch
if object_name == "LuaGuiElement" then if object_name == "LuaGuiElement" then
--- @cast key LuaGuiElement
local data = self._raw.element_data local data = self._raw.element_data
local player_elements = data and data[key.player_index] local player_elements = data and data[key.player_index]
return player_elements and player_elements[key.index] return player_elements and player_elements[key.index]
elseif object_name == "LuaPlayer" then elseif object_name == "LuaPlayer" then
--- @cast key LuaPlayer
local data = self._raw.player_data local data = self._raw.player_data
return data and data[key.index] return data and data[key.index]
elseif object_name == "LuaForce" then elseif object_name == "LuaForce" then
--- @cast key LuaForce
local data = self._raw.force_data local data = self._raw.force_data
return data and data[key.index] return data and data[key.index]
else else
@@ -153,7 +157,7 @@ end
--- @param scope string --- @param scope string
--- @return GuiData --- @return GuiData
function GuiData.get(scope) function GuiData.get(scope)
return GuiData._scopes[scope] --[[ @as GuiData ]] return GuiData._scopes[scope] --[[@as GuiData]]
end end
--- Used to clean up data from destroyed elements --- Used to clean up data from destroyed elements
@@ -168,7 +172,7 @@ local function on_object_destroyed(event)
for _, scope in pairs(registered_scopes) do for _, scope in pairs(registered_scopes) do
local data = scope._raw.element_data local data = scope._raw.element_data
local player_elements = data and data[player_index] local player_elements = data and data[player_index]
if player_elements then if data and player_elements then
player_elements[element_index] = nil player_elements[element_index] = nil
if not next(player_elements) then if not next(player_elements) then
data[player_index] = nil data[player_index] = nil
+17 -17
View File
@@ -1,4 +1,4 @@
--- @class Gui --- @class (partial) Gui
local Gui = require("modules/exp_gui") local Gui = require("modules/exp_gui")
--- @class Gui.elements --- @class Gui.elements
@@ -28,7 +28,7 @@ Elements.aligned_flow = Gui.define("aligned_flow")
vertically_stretchable = vertical_align ~= "center", vertically_stretchable = vertical_align ~= "center",
horizontally_stretchable = horizontal_align ~= "center", horizontally_stretchable = horizontal_align ~= "center",
} }
end) --[[ @as any ]] end) --[[@as any]]
--- A solid horizontal white bar element --- A solid horizontal white bar element
--- @class Gui.elements.bar: ExpElement --- @class Gui.elements.bar: ExpElement
@@ -48,11 +48,11 @@ Elements.bar = Gui.define("bar")
else else
style.horizontally_stretchable = true style.horizontally_stretchable = true
end end
end) --[[ @as any ]] end) --[[@as any]]
--- A label which is centered --- A label which is centered
--- @class Gui.elements.centered_label: ExpElement --- @class Gui.elements.centered_label: ExpElement
--- @overload fun(parent: LuaGuiElement, width: number, caption: LocalisedString, tooltip: LocalisedString?): LuaGuiElement --- @overload fun(parent: LuaGuiElement, width: number, caption: LocalisedString?, tooltip: LocalisedString?): LuaGuiElement
Elements.centered_label = Gui.define("centered_label") Elements.centered_label = Gui.define("centered_label")
:draw{ :draw{
type = "label", type = "label",
@@ -63,7 +63,7 @@ Elements.centered_label = Gui.define("centered_label")
horizontal_align = "center", horizontal_align = "center",
single_line = false, single_line = false,
width = Gui.from_argument(1), width = Gui.from_argument(1),
} --[[ @as any ]] } --[[@as any]]
--- A label which has two white bars on either side of it --- A label which has two white bars on either side of it
--- @class Gui.elements.title_label: ExpElement --- @class Gui.elements.title_label: ExpElement
@@ -91,7 +91,7 @@ Elements.title_label = Gui.define("title_label")
Elements.bar(flow) Elements.bar(flow)
return label return label
end) --[[ @as any ]] end) --[[@as any]]
--- A fixed size vertical scroll pane --- A fixed size vertical scroll pane
--- @class Gui.elements.scroll_pane: ExpElement --- @class Gui.elements.scroll_pane: ExpElement
@@ -109,7 +109,7 @@ Elements.scroll_pane = Gui.define("scroll_pane")
padding = { 1, 3 }, padding = { 1, 3 },
maximal_height = Gui.from_argument(1), maximal_height = Gui.from_argument(1),
horizontally_stretchable = true, horizontally_stretchable = true,
} --[[ @as any ]] } --[[@as any]]
--- A fixed size vertical scroll pane containing a table --- A fixed size vertical scroll pane containing a table
--- @class Gui.elements.scroll_table: ExpElement --- @class Gui.elements.scroll_table: ExpElement
@@ -132,7 +132,7 @@ Elements.scroll_table = Gui.define("scroll_table")
cell_padding = 1, cell_padding = 1,
vertical_align = "center", vertical_align = "center",
horizontally_stretchable = true, horizontally_stretchable = true,
} --[[ @as any ]] } --[[@as any]]
--- A container frame --- A container frame
--- @class Gui.elements.container: ExpElement --- @class Gui.elements.container: ExpElement
@@ -159,13 +159,13 @@ Elements.container = Gui.define("container")
vertically_stretchable = false, vertically_stretchable = false,
horizontally_stretchable = false, horizontally_stretchable = false,
minimal_width = Gui.from_argument(1), minimal_width = Gui.from_argument(1),
} --[[ @as any ]] } --[[@as any]]
--- Get the root element of a container --- Get the root element of a container
--- @param container LuaGuiElement --- @param container LuaGuiElement
--- @return LuaGuiElement --- @return LuaGuiElement
function Elements.container.get_root_element(container) function Elements.container.get_root_element(container)
return container.parent return assert(container.parent)
end end
--- A frame within a container --- A frame within a container
@@ -183,7 +183,7 @@ Elements.subframe_base = Gui.define("container_subframe")
padding = { 3, 6, 0, 6 }, padding = { 3, 6, 0, 6 },
use_header_filler = false, use_header_filler = false,
horizontally_stretchable = true, horizontally_stretchable = true,
} --[[ @as any ]] } --[[@as any]]
--- @class Gui.elements.header.opts --- @class Gui.elements.header.opts
--- @field name string? --- @field name string?
@@ -212,7 +212,7 @@ Elements.header = Gui.define("container_header")
subframe.add{ type = "empty-widget" }.style.horizontally_stretchable = true subframe.add{ type = "empty-widget" }.style.horizontally_stretchable = true
return subframe return subframe
end) --[[ @as any ]] end) --[[@as any]]
--- @class Gui.elements.footer.opts --- @class Gui.elements.footer.opts
--- @field name string? --- @field name string?
@@ -241,7 +241,7 @@ Elements.footer = Gui.define("container_footer")
subframe.add{ type = "empty-widget" }.style.horizontally_stretchable = true subframe.add{ type = "empty-widget" }.style.horizontally_stretchable = true
return subframe return subframe
end) --[[ @as any ]] end) --[[@as any]]
--- A button used to destroy its target when clicked, intended for screen frames --- A button used to destroy its target when clicked, intended for screen frames
--- @class Gui.elements.screen_frame_close: ExpElement --- @class Gui.elements.screen_frame_close: ExpElement
@@ -259,7 +259,7 @@ Elements.screen_frame_close = Gui.define("screen_frame_close")
:on_click(function(def, player, element, event) :on_click(function(def, player, element, event)
--- @cast def Gui.elements.screen_frame_close --- @cast def Gui.elements.screen_frame_close
Gui.destroy_if_valid(def.data[element]) Gui.destroy_if_valid(def.data[element])
end) --[[ @as any ]] end) --[[@as any]]
--- A draggable frame with close button and button flow --- A draggable frame with close button and button flow
--- @class Gui.elements.screen_frame: ExpElement --- @class Gui.elements.screen_frame: ExpElement
@@ -313,20 +313,20 @@ Elements.screen_frame = Gui.define("screen_frame")
direction = "vertical", direction = "vertical",
style = "inside_shallow_frame_packed", style = "inside_shallow_frame_packed",
} }
end) --[[ @as any ]] end) --[[@as any]]
--- Get the button flow for a screen frame --- Get the button flow for a screen frame
--- @param screen_frame LuaGuiElement --- @param screen_frame LuaGuiElement
--- @return LuaGuiElement --- @return LuaGuiElement
function Elements.screen_frame.get_button_flow(screen_frame) function Elements.screen_frame.get_button_flow(screen_frame)
return assert(Elements.screen_frame.data[screen_frame.parent], "Screen frame has no button flow") return (assert(Elements.screen_frame.data[assert(screen_frame.parent)], "Screen frame has no button flow"))
end end
--- Get the root element of a screen frame --- Get the root element of a screen frame
--- @param screen_frame LuaGuiElement --- @param screen_frame LuaGuiElement
--- @return LuaGuiElement --- @return LuaGuiElement
function Elements.screen_frame.get_root_element(screen_frame) function Elements.screen_frame.get_root_element(screen_frame)
return screen_frame.parent return assert(screen_frame.parent)
end end
return Elements return Elements
+1 -3
View File
@@ -166,7 +166,6 @@ end
function GuiIter.get_tracked_elements(scope, filter) function GuiIter.get_tracked_elements(scope, filter)
local class_name = ExpUtil.get_class_name(filter) local class_name = ExpUtil.get_class_name(filter)
if class_name == "nil" then if class_name == "nil" then
--- @cast filter nil
return GuiIter.all_elements(scope) return GuiIter.all_elements(scope)
elseif class_name == "LuaPlayer" then elseif class_name == "LuaPlayer" then
--- @cast filter LuaPlayer --- @cast filter LuaPlayer
@@ -189,7 +188,6 @@ end
function GuiIter.get_online_elements(scope, filter) function GuiIter.get_online_elements(scope, filter)
local class_name = ExpUtil.get_class_name(filter) local class_name = ExpUtil.get_class_name(filter)
if class_name == "nil" then if class_name == "nil" then
--- @cast filter nil
return GuiIter.filtered_elements(scope, game.connected_players) return GuiIter.filtered_elements(scope, game.connected_players)
elseif class_name == "LuaPlayer" then elseif class_name == "LuaPlayer" then
--- @cast filter LuaPlayer --- @cast filter LuaPlayer
@@ -235,7 +233,7 @@ end
function GuiIter.remove_element(scope, player_index, element_index) function GuiIter.remove_element(scope, player_index, element_index)
local scope_elements = registered_scopes[scope] local scope_elements = registered_scopes[scope]
if not scope_elements then return end if not scope_elements then return end
local player_elements = registered_scopes[player_index] local player_elements = scope_elements[player_index]
if not player_elements then return end if not player_elements then return end
player_elements[element_index] = nil player_elements[element_index] = nil
end end
+5 -3
View File
@@ -43,6 +43,8 @@ ExpElement.events = {}
--- @field _force_data ExpElement.PostDrawCallback? --- @field _force_data ExpElement.PostDrawCallback?
--- @field _global_data ExpElement.PostDrawCallback? --- @field _global_data ExpElement.PostDrawCallback?
--- @field _events table<defines.events, ExpElement.EventHandler<EventData>[]> --- @field _events table<defines.events, ExpElement.EventHandler<EventData>[]>
--- @field _has_handlers boolean
--- @field _track_elements boolean
--- @overload fun(parent: LuaGuiElement, ...: any): LuaGuiElement --- @overload fun(parent: LuaGuiElement, ...: any): LuaGuiElement
ExpElement._prototype = { ExpElement._prototype = {
_track_elements = false, _track_elements = false,
@@ -158,7 +160,7 @@ function ExpElement.new(name)
}, },
} }
ExpElement._elements[element_name] = instance --[[ @as ExpElement ]] ExpElement._elements[element_name] = instance --[[@as ExpElement]]
return setmetatable(instance, ExpElement._metatable) return setmetatable(instance, ExpElement._metatable)
end end
@@ -166,7 +168,7 @@ end
--- @param name string --- @param name string
--- @return ExpElement --- @return ExpElement
function ExpElement.get(name) function ExpElement.get(name)
return assert(ExpElement._elements[name], "ExpElement is not defined: " .. tostring(name)) return (assert(ExpElement._elements[name], "ExpElement is not defined: " .. tostring(name)))
end end
--- Create a new instance of this element definition --- Create a new instance of this element definition
@@ -460,7 +462,7 @@ function ExpElement._prototype:raise_event(event)
for _, handler in ipairs(handlers) do for _, handler in ipairs(handlers) do
-- All gui elements will contain player and element, other events might have these as nil -- All gui elements will contain player and element, other events might have these as nil
-- Therefore only the signature of on_event has these values as optional -- Therefore only the signature of on_event has these values as optional
handler(self, player --[[ @as LuaPlayer ]], event.element, event --[[ @as EventData ]]) handler(self, player --[[@as LuaPlayer]], event.element, event --[[@as EventData]])
end end
end end
+1 -1
View File
@@ -1,4 +1,4 @@
--- @class Gui --- @class (partial) Gui
local Gui = require("modules/exp_gui") local Gui = require("modules/exp_gui")
--- @class Gui.styles --- @class Gui.styles
+18 -16
View File
@@ -1,5 +1,5 @@
--- @class Gui --- @class (partial) Gui
local Gui = require("modules/exp_gui") local Gui = require("modules/exp_gui")
local ExpElement = require("modules/exp_gui/prototype") local ExpElement = require("modules/exp_gui/prototype")
local mod_gui = require("mod-gui") local mod_gui = require("mod-gui")
@@ -29,7 +29,7 @@ Toolbar.on_gui_button_toggled = script.generate_event_name()
--- @class _ExpElement._prototype --- @class _ExpElement._prototype
--- @field on_button_toggled ExpElement.OnEventAdder<EventData.on_gui_button_toggled> --- @field on_button_toggled ExpElement.OnEventAdder<EventData.on_gui_button_toggled>
--- @diagnostic disable-next-line: invisible, inject-field --- @diagnostic disable-next-line: access-invisible, inject-field
function ExpElement._prototype.on_button_toggled(self, handler) function ExpElement._prototype.on_button_toggled(self, handler)
return self:on_event(Toolbar.on_gui_button_toggled, handler) return self:on_event(Toolbar.on_gui_button_toggled, handler)
end end
@@ -85,7 +85,7 @@ function Toolbar.set_button_toggled_state(define, player, state, _from_left)
button.style = state and toolbar_button_active_style or toolbar_button_default_style button.style = state and toolbar_button_active_style or toolbar_button_default_style
-- Make the extra required adjustments -- Make the extra required adjustments
local style = button.style local style = button.style --[[@as LuaStyle]]
style.minimal_width = original_width style.minimal_width = original_width
style.maximal_height = original_height style.maximal_height = original_height
if button.type == "sprite-button" then if button.type == "sprite-button" then
@@ -335,9 +335,10 @@ Below here is the toolbar settings GUI and its associated functions
--- @param dst LuaGuiElement --- @param dst LuaGuiElement
local function copy_style(src, dst) local function copy_style(src, dst)
dst.style = src.style.name dst.style = src.style.name
dst.style.height = toolbar_button_small local style = dst.style --[[@as LuaStyle]]
dst.style.width = toolbar_button_small style.height = toolbar_button_small
dst.style.padding = -2 style.width = toolbar_button_small
style.padding = -2
end end
--- Reorder the buttons relative to each other, this will update the datastore --- Reorder the buttons relative to each other, this will update the datastore
@@ -350,7 +351,7 @@ local function move_toolbar_button(player, item, offset)
-- Swap the position in the list -- Swap the position in the list
local list = assert(item.parent) local list = assert(item.parent)
local other_item = list.children[new_index] local other_item = assert(list.children[new_index])
list.swap_children(old_index, new_index) list.swap_children(old_index, new_index)
-- Swap the position in the top flow, offset by 1 because of settings button -- Swap the position in the top flow, offset by 1 because of settings button
@@ -365,7 +366,7 @@ local function move_toolbar_button(player, item, offset)
local other_element = Gui.get_left_element(other_left_element, player) local other_element = Gui.get_left_element(other_left_element, player)
local left_index = element.get_index_in_parent() local left_index = element.get_index_in_parent()
local other_index = other_element.get_index_in_parent() local other_index = other_element.get_index_in_parent()
element.parent.swap_children(left_index, other_index) assert(element.parent).swap_children(left_index, other_index)
end end
-- If we are moving in/out of first/last place we need to update the move buttons -- If we are moving in/out of first/last place we need to update the move buttons
@@ -393,7 +394,7 @@ end
--- @param player LuaPlayer --- @param player LuaPlayer
--- @param order Gui.ToolbarOrder --- @param order Gui.ToolbarOrder
function Toolbar.set_order(player, order) function Toolbar.set_order(player, order)
local list = elements.toolbar_settings.data[player] --[[ @as LuaGuiElement ]] local list = elements.toolbar_settings.data[player] --[[@as LuaGuiElement]]
local left_flow = Gui.get_left_flow(player) local left_flow = Gui.get_left_flow(player)
local top_flow = Gui.get_top_flow(player) local top_flow = Gui.get_top_flow(player)
@@ -466,7 +467,7 @@ end
function Toolbar.get_state(player) function Toolbar.get_state(player)
-- Get the order of toolbar buttons -- Get the order of toolbar buttons
local order = {} local order = {}
local list = elements.toolbar_settings.data[player] --[[ @as LuaGuiElement ]] local list = elements.toolbar_settings.data[player] --[[@as LuaGuiElement]]
for index, item in pairs(list.children) do for index, item in pairs(list.children) do
order[index] = { name = item.name, favourite = elements.toolbar_list_item.data[item].set_favourite.state } order[index] = { name = item.name, favourite = elements.toolbar_list_item.data[item].set_favourite.state }
end end
@@ -487,7 +488,7 @@ end
--- @param player LuaPlayer --- @param player LuaPlayer
function Toolbar._create_elements(player) function Toolbar._create_elements(player)
-- Add any missing items to the gui -- Add any missing items to the gui
local toolbar_list = elements.toolbar_settings.data[player] --[[ @as LuaGuiElement ]] local toolbar_list = elements.toolbar_settings.data[player] --[[@as LuaGuiElement]]
local previous_last_index = #toolbar_list.children_names local previous_last_index = #toolbar_list.children_names
for define in pairs(Gui.top_elements) do for define in pairs(Gui.top_elements) do
if define ~= elements.close_toolbar and toolbar_list[define.name] == nil then if define ~= elements.close_toolbar and toolbar_list[define.name] == nil then
@@ -499,7 +500,8 @@ function Toolbar._create_elements(player)
-- Reset the state of the previous last child -- Reset the state of the previous last child
local children = toolbar_list.children local children = toolbar_list.children
if previous_last_index > 0 then if previous_last_index > 0 then
elements.toolbar_list_item.data[children[previous_last_index]].move_item_down.enabled = true local previous_last = assert(children[previous_last_index])
elements.toolbar_list_item.data[previous_last].move_item_down.enabled = true
end end
-- Set the state of the move buttons for the first and last element -- Set the state of the move buttons for the first and last element
@@ -513,7 +515,7 @@ end
--- @param player LuaPlayer --- @param player LuaPlayer
function Toolbar._ensure_consistency(player) function Toolbar._ensure_consistency(player)
-- Update the toolbar buttons -- Update the toolbar buttons
local list = elements.toolbar_settings.data[player] --[[ @as LuaGuiElement ]] local list = elements.toolbar_settings.data[player] --[[@as LuaGuiElement]]
for _, button in ipairs(toolbar_buttons) do for _, button in ipairs(toolbar_buttons) do
-- Update the visible state based on if the player is allowed the button -- Update the visible state based on if the player is allowed the button
local element = Gui.get_top_element(button, player) local element = Gui.get_top_element(button, player)
@@ -619,7 +621,7 @@ elements.move_item_up = Gui.define("move_item_up")
size = toolbar_button_small, size = toolbar_button_small,
}) })
:on_click(function(def, player, element) :on_click(function(def, player, element)
local item = assert(element.parent.parent) local item = assert(assert(element.parent).parent)
move_toolbar_button(player, item, -1) move_toolbar_button(player, item, -1)
end) end)
@@ -634,7 +636,7 @@ elements.move_item_down = Gui.define("move_item_down")
size = toolbar_button_small, size = toolbar_button_small,
}) })
:on_click(function(def, player, element) :on_click(function(def, player, element)
local item = assert(element.parent.parent) local item = assert(assert(element.parent).parent)
move_toolbar_button(player, item, 1) move_toolbar_button(player, item, 1)
end) end)
@@ -658,7 +660,7 @@ elements.set_favourite = Gui.define("set_favourite")
width = 180, width = 180,
} }
:on_checked_state_changed(function(def, player, element) :on_checked_state_changed(function(def, player, element)
local define = ExpElement.get(element.tags.element_name --[[ @as string ]]) local define = ExpElement.get(element.tags.element_name --[[@as string]])
local top_element = Gui.get_top_element(define, player) local top_element = Gui.get_top_element(define, player)
local had_visible = Toolbar.has_visible_buttons(player) local had_visible = Toolbar.has_visible_buttons(player)
top_element.visible = element.state top_element.visible = element.state
+2
View File
@@ -24,6 +24,7 @@ local afk_time_units = {
} }
return { return {
--- @type table<string, LocalisedString | fun(player: LuaPlayer, is_command: boolean): LocalisedString>
messages = { --- @setting messages will trigger when ever the word is said messages = { --- @setting messages will trigger when ever the word is said
["discord"] = { "info.discord" }, ["discord"] = { "info.discord" },
["expgaming"] = { "info.website" }, ["expgaming"] = { "info.website" },
@@ -66,6 +67,7 @@ return {
command_admin_only = false, --- @setting command_admin_only when true will only allow chat commands for admins command_admin_only = false, --- @setting command_admin_only when true will only allow chat commands for admins
command_permission = "command/chat-commands", --- @setting command_permission the permission used to allow command prefixes command_permission = "command/chat-commands", --- @setting command_permission the permission used to allow command prefixes
command_prefix = "!", --- @setting command_prefix prefix used for commands below and to print to all players (if enabled above) command_prefix = "!", --- @setting command_prefix prefix used for commands below and to print to all players (if enabled above)
--- @type table<string, LocalisedString | fun(player: LuaPlayer, is_command: boolean): LocalisedString>
commands = { --- @setting commands will trigger only when command prefix is given commands = { --- @setting commands will trigger only when command prefix is given
["dev"] = { "exp_chat-auto-reply.reply-dev" }, ["dev"] = { "exp_chat-auto-reply.reply-dev" },
["magic"] = { "exp_chat-auto-reply.reply-magic" }, ["magic"] = { "exp_chat-auto-reply.reply-magic" },
@@ -15,7 +15,8 @@ local Colors = require("modules/exp_util/include/color")
local format_player_name = ExpUtil.format_player_name_locale local format_player_name = ExpUtil.format_player_name_locale
--- Accessors injected by the gui so the actions can read the selected player and set the selected action --- Accessors injected by the gui so the actions can read the selected player and set the selected action
local get_selected_player, set_selected_action local get_selected_player --- @type fun(player: LuaPlayer): LuaPlayer
local set_selected_action --- @type fun(player: LuaPlayer, action: string?)
local function set_accessors(player_getter, action_setter) local function set_accessors(player_getter, action_setter)
get_selected_player, set_selected_action = player_getter, action_setter get_selected_player, set_selected_action = player_getter, action_setter
end end
@@ -31,7 +32,7 @@ end
-- gets the action player and a coloured name for the action to be used on -- gets the action player and a coloured name for the action to be used on
local function get_action_player(player) local function get_action_player(player)
local selected_player = get_selected_player(player) --[[ @as LuaPlayer ]] local selected_player = get_selected_player(player) --[[@as LuaPlayer]]
local selected_player_color = format_player_name(selected_player) local selected_player_color = format_player_name(selected_player)
return selected_player, selected_player_color return selected_player, selected_player_color
end end
+6 -6
View File
@@ -87,7 +87,7 @@ return {
amount = 4000, amount = 4000,
size = { 26, 27 }, size = { 26, 27 },
-- offset = {-64,-32} -- offset = {-64,-32}
offset = { -64, -64 }, offset = { x = -64, y = -64 },
}, },
{ {
enabled = false, enabled = false,
@@ -95,7 +95,7 @@ return {
amount = 4000, amount = 4000,
size = { 26, 27 }, size = { 26, 27 },
-- offset = {-64, 0} -- offset = {-64, 0}
offset = { 64, -64 }, offset = { x = 64, y = -64 },
}, },
{ {
enabled = false, enabled = false,
@@ -103,7 +103,7 @@ return {
amount = 4000, amount = 4000,
size = { 22, 20 }, size = { 22, 20 },
-- offset = {-64, 32} -- offset = {-64, 32}
offset = { -64, 64 }, offset = { x = -64, y = 64 },
}, },
{ {
enabled = false, enabled = false,
@@ -111,7 +111,7 @@ return {
amount = 4000, amount = 4000,
size = { 22, 20 }, size = { 22, 20 },
-- offset = {-64, -64} -- offset = {-64, -64}
offset = { 64, 64 }, offset = { x = 64, y = 64 },
}, },
{ {
enabled = false, enabled = false,
@@ -119,7 +119,7 @@ return {
amount = 4000, amount = 4000,
size = { 22, 20 }, size = { 22, 20 },
-- offset = {-64, -96} -- offset = {-64, -96}
offset = { 0, 64 }, offset = { x = 0, y = 64 },
}, },
}, },
}, },
@@ -132,7 +132,7 @@ return {
num_patches = 4, num_patches = 4,
amount = 4000000, amount = 4000000,
-- offset = {-80, -12}, -- offset = {-80, -12},
offset = { -12, 64 }, offset = { x = -12, y = 64 },
-- offset_next = {0, 6} -- offset_next = {0, 6}
offset_next = { 6, 0 }, offset_next = { 6, 0 },
}, },
+14
View File
@@ -35,6 +35,20 @@ return {
storage_output = 1, -- >0 allows for item teleportation (allowed_items only) storage_output = 1, -- >0 allows for item teleportation (allowed_items only)
}, },
--- @class Vlayer.ItemProperties
--- @field starting_value number
--- @field required_area number
--- @field production number?
--- @field discharge number?
--- @field capacity number?
--- @field surface_area number?
--- @field fuel_value number?
--- @field power boolean?
--- @field modded boolean? Set when the item is registered from a modded equivalent
--- @field base_game_equivalent string?
--- @field multiplier number?
--- @type table<string, Vlayer.ItemProperties>
allowed_items = { --- @setting allowed_items List of all items allowed in vlayer storage and their properties allowed_items = { --- @setting allowed_items List of all items allowed in vlayer storage and their properties
--[[ --[[
Allowed properties: Allowed properties:
+1
View File
@@ -2,6 +2,7 @@
-- @config Warnings -- @config Warnings
return { return {
--- @type (LocalisedString[] | fun(player: LuaPlayer, by_player_name: string, number_of_warnings: number))[]
actions = { --- @setting actions what actions are taking at number of warnings actions = { --- @setting actions what actions are taking at number of warnings
-- if a localized string is used then __1__ will by_player_name and __2__ will be the current warning count (auto inserted) -- if a localized string is used then __1__ will by_player_name and __2__ will be the current warning count (auto inserted)
{ "warnings.received", "" }, { "warnings.received", "" },
+16 -2
View File
@@ -149,9 +149,23 @@ PlayerData.Statistics:combine('JoinCount')
local Storage = require("modules/exp_util/storage") local Storage = require("modules/exp_util/storage")
local DatastoreManager = {} local DatastoreManager = {}
local Datastores = {} local Datastores = {} --- @type table<string, Datastore>
local Datastore = {}
local Data = {} local Data = {}
--- @class Datastore
--- @field name string
--- @field value_name string
--- @field auto_save boolean
--- @field save_to_disk boolean
--- @field propagate_changes boolean
--- @field serializer function | false
--- @field parent Datastore | false
--- @field children table<string, Datastore>
--- @field metadata table
--- @field events table<string, function[]>
--- @field data table
local Datastore = {}
local copy = table.deep_copy local copy = table.deep_copy
local trace = debug.traceback local trace = debug.traceback
local table_to_json = helpers.table_to_json local table_to_json = helpers.table_to_json
+10 -8
View File
@@ -14,7 +14,8 @@ end
]] ]]
local ext, var local ext --- @type table<string, any>
local var --- @type table<string, any>
local concat = table.concat local concat = table.concat
local External = {} local External = {}
@@ -29,12 +30,13 @@ end
]] ]]
function External.valid() function External.valid()
if storage.ext == nil then return false end local stored = storage.ext
if ext == storage.ext and var == ext.var then if stored == nil then return false end
if ext == stored and var == ext.var then
return var ~= nil return var ~= nil
else else
ext = storage.ext ext = stored
var = ext.var var = stored.var
return var ~= nil return var ~= nil
end end
end end
@@ -48,7 +50,7 @@ local servers = External.get_servers()
]] ]]
function External.get_servers() function External.get_servers()
assert(ext, "No external data was found, use External.valid() to ensure external data exists.") assert(ext, "No external data was found, use External.valid() to ensure external data exists.")
return assert(ext.servers, "No server list was found, please ensure that the external service is running") return (assert(ext.servers, "No server list was found, please ensure that the external service is running"))
end end
--[[-- Gets a table of all the servers filtered by name, key is the server id, value is the server details --[[-- Gets a table of all the servers filtered by name, key is the server id, value is the server details
@@ -83,7 +85,7 @@ function External.get_current_server()
assert(ext, "No external data was found, use External.valid() to ensure external data exists.") assert(ext, "No external data was found, use External.valid() to ensure external data exists.")
local servers = assert(ext.servers, "No server list was found, please ensure that the external service is running") local servers = assert(ext.servers, "No server list was found, please ensure that the external service is running")
local server_id = assert(ext.current, "No current id was found, please ensure that the external service is running") local server_id = assert(ext.current, "No current id was found, please ensure that the external service is running")
return assert(servers[server_id], "No details found for server with id: " .. tostring(server_id)) return (assert(servers[server_id], "No details found for server with id: " .. tostring(server_id)))
end end
--[[-- Gets the details of the given server --[[-- Gets the details of the given server
@@ -97,7 +99,7 @@ local server = External.get_server_details('eu-01')
function External.get_server_details(server_id) function External.get_server_details(server_id)
assert(ext, "No external data was found, use External.valid() to ensure external data exists.") assert(ext, "No external data was found, use External.valid() to ensure external data exists.")
local servers = assert(ext.servers, "No server list was found, please ensure that the external service is running") local servers = assert(ext.servers, "No server list was found, please ensure that the external service is running")
return assert(servers[server_id], "No details found for server with id: " .. tostring(server_id)) return (assert(servers[server_id], "No details found for server with id: " .. tostring(server_id)))
end end
--[[-- Gets the status of the given server --[[-- Gets the status of the given server
@@ -142,7 +142,7 @@ group:set_action('toggle_map_editor', false)
]] ]]
function PermissionsGroups._prototype:set_action(action, state) function PermissionsGroups._prototype:set_action(action, state)
local input_action = defines.input_action[action] --[[ @as defines.input_action? ]] local input_action = defines.input_action[action] --[[@as defines.input_action?]]
if input_action == nil then input_action = action end if input_action == nil then input_action = action end
assert(type(input_action) == "number", tostring(action) .. " is not a valid input action") assert(type(input_action) == "number", tostring(action) .. " is not a valid input action")
self.actions[input_action] = state self.actions[input_action] = state
+1 -1
View File
@@ -55,7 +55,7 @@ PlayerData:set_serializer(Datastore.name_serializer) -- use player name
--- Store and enum for the data saving preference --- Store and enum for the data saving preference
local DataSavingPreference = PlayerData:combine("DataSavingPreference") local DataSavingPreference = PlayerData:combine("DataSavingPreference")
local PreferenceEnum = { "All", "Statistics", "Settings", "Required" } local PreferenceEnum = { "All", "Statistics", "Settings", "Required" } --- @type table<string | number, string | number>
for k, v in ipairs(PreferenceEnum) do PreferenceEnum[v] = k end for k, v in ipairs(PreferenceEnum) do PreferenceEnum[v] = k end
DataSavingPreference:set_default("All") DataSavingPreference:set_default("All")
+31 -12
View File
@@ -117,11 +117,28 @@ local Groups = require("modules.exp_legacy.expcore.permission_groups")
local Colours = ExpUtil.color local Colours = ExpUtil.color
local write_json = ExpUtil.write_json local write_json = ExpUtil.write_json
--- @class Roles.Role
--- @field name string
--- @field short_hand string
--- @field index number Position within the role order
--- @field allowed_actions table<string, boolean>
--- @field allow_all_actions boolean
--- @field flags table<string, boolean>
--- @field disallowed_actions table<string, boolean>?
--- @field permission_group ([boolean, string] | string)?
--- @field custom_tag string?
--- @field custom_color Color?
--- @field parent string?
--- @field block_auto_assign boolean?
--- @field auto_assign_condition function?
--- @field set_allow_all fun(self: Roles.Role, state: boolean?): Roles.Role Defined on Roles._prototype
local Roles = { local Roles = {
_prototype = {}, _prototype = {},
config = { config = {
order = {}, -- Contains the order of the roles, lower index is better order = {}, --- @type string[] Contains the order of the roles, lower index is better
roles = {}, -- Contains the raw info for the roles, indexed by role name roles = {}, --- @type table<string, Roles.Role> Contains the raw info for the roles, indexed by role name
flags = {}, -- Contains functions that run when a flag is added/removed from a player flags = {}, -- Contains functions that run when a flag is added/removed from a player
internal = {}, -- Contains all internally accessed roles, such as root, default internal = {}, -- Contains all internally accessed roles, such as root, default
players = {}, -- Contains the roles that players have players = {}, -- Contains the roles that players have
@@ -200,7 +217,7 @@ function Roles.debug()
local output = "" local output = ""
for index, role_name in ipairs(Roles.config.order) do for index, role_name in ipairs(Roles.config.order) do
local role = Roles.config.roles[role_name] local role = Roles.config.roles[role_name]
local color = role.custom_color or Colours.white local color = (role.custom_color or Colours.white) --[[@as Color.struct]]
local color_str = string.format("[color=%d, %d, %d]", color.r, color.g, color.b) local color_str = string.format("[color=%d, %d, %d]", color.r, color.g, color.b)
output = output .. string.format("\n%s %s) %s[/color]", color_str, index, serpent.line(role)) output = output .. string.format("\n%s %s) %s[/color]", color_str, index, serpent.line(role))
end end
@@ -287,6 +304,7 @@ local role = Roles.get_role_by_name(2)
]] ]]
function Roles.get_role_by_order(index) function Roles.get_role_by_order(index)
local name = Roles.config.order[index] local name = Roles.config.order[index]
if not name then return end
return Roles.config.roles[name] return Roles.config.roles[name]
end end
@@ -348,16 +366,17 @@ end
local role = Roles.get_player_highest_role(game.player) local role = Roles.get_player_highest_role(game.player)
]] ]]
--- @return Roles.Role
function Roles.get_player_highest_role(player) function Roles.get_player_highest_role(player)
local roles = Roles.get_player_roles(player) local roles = Roles.get_player_roles(player)
local highest local highest --- @type Roles.Role?
for _, role in ipairs(roles) do for _, role in ipairs(roles) do
if not highest or role.index < highest.index then if not highest or role.index < highest.index then
highest = role highest = role
end end
end end
return highest return (assert(highest, "Player has no roles"))
end end
--- Assignment. --- Assignment.
@@ -458,7 +477,7 @@ function Roles.unassign_player(player, roles, by_player_name, skip_checks, silen
-- If the player has a role that needs to defer the role changes, save the roles that need to be unassigned later into a table -- If the player has a role that needs to defer the role changes, save the roles that need to be unassigned later into a table
local defer_changes = Roles.player_has_flag(player, "defer_role_changes") local defer_changes = Roles.player_has_flag(player, "defer_role_changes")
if defer_changes then if defer_changes and valid_player then
local assign_later = Roles.config.deferred_roles[valid_player.name] or {} local assign_later = Roles.config.deferred_roles[valid_player.name] or {}
for _, role in ipairs(role_objects) do for _, role in ipairs(role_objects) do
local role_change = assign_later[role.name] local role_change = assign_later[role.name]
@@ -719,7 +738,7 @@ local role = Roles.new_role('Moderator', 'Mod')
]] ]]
function Roles.new_role(name, short_hand) function Roles.new_role(name, short_hand)
ExpUtil.assert_not_runtime() ExpUtil.assert_not_runtime()
if Roles.config.roles[name] then return error("Role name is non unique") end if Roles.config.roles[name] then error("Role name is non unique") end
local role = setmetatable({ local role = setmetatable({
name = name, name = name,
short_hand = short_hand or name, short_hand = short_hand or name,
@@ -894,10 +913,9 @@ role:set_permission_group('Admin')
function Roles._prototype:set_permission_group(name, use_factorio_api) function Roles._prototype:set_permission_group(name, use_factorio_api)
ExpUtil.assert_not_runtime() ExpUtil.assert_not_runtime()
if use_factorio_api then if use_factorio_api then
self.permission_group = { true, name } self.permission_group = { true, name } --[[@as [boolean, string] ]]
else else
local group = Groups.get_group_by_name(name) assert(Groups.get_group_by_name(name), "Permission group not found: " .. name)
if not group then return end
self.permission_group = name self.permission_group = name
end end
return self return self
@@ -1115,8 +1133,9 @@ local function role_update(event)
-- Updates the players permission group -- Updates the players permission group
local highest = Roles.get_player_highest_role(player) local highest = Roles.get_player_highest_role(player)
if highest.permission_group then if highest.permission_group then
if highest.permission_group[1] then local permission_group = highest.permission_group --[[@as [boolean, string] ]]
local group = game.permissions.get_group(highest.permission_group[2]) if permission_group[1] then
local group = game.permissions.get_group(permission_group[2])
if group then if group then
Groups.add_to_permission_group_async(group, player) Groups.add_to_permission_group_async(group, player)
end end
@@ -34,7 +34,7 @@ for _, config_key in ipairs{ "always_protected_names", "always_protected_types",
end end
-- Require roles if a permission is assigned in the config -- Require roles if a permission is assigned in the config
local Roles local Roles --- @type table<string, any>
if config.ignore_permission then if config.ignore_permission then
Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
end end
@@ -4,7 +4,7 @@ local Gui = require("modules/exp_gui")
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
----- Locals ----- ----- Locals -----
local follow_label -- Gui constructor local follow_label --- @type ExpElement Gui constructor
local following = {} local following = {}
local spectating = {} local spectating = {}
local Public = {} local Public = {}
+19 -18
View File
@@ -14,10 +14,10 @@ local mega = 1000000
local vlayer = {} local vlayer = {}
local vlayer_data = { local vlayer_data = {
entity_interfaces = { entity_interfaces = {
energy = {}, energy = {}, --- @type LuaEntity[]
circuit = {}, circuit = {}, --- @type LuaEntity[]
storage_input = {}, storage_input = {}, --- @type LuaEntity[]
storage_output = {}, storage_output = {}, --- @type LuaEntity[]
}, },
properties = { properties = {
total_surface_area = 0, total_surface_area = 0,
@@ -28,10 +28,10 @@ local vlayer_data = {
capacity = 0, capacity = 0,
}, },
storage = { storage = {
items = {}, items = {}, --- @type table<string, number>
power_items = {}, power_items = {}, --- @type table<string, { value: number, count: number }>
energy = 0, energy = 0,
unallocated = {}, unallocated = {}, --- @type table<string, number>
}, },
surface = table.deep_copy(config.surface), surface = table.deep_copy(config.surface),
} }
@@ -45,7 +45,7 @@ for name, properties in pairs(config.allowed_items) do
if properties.power then if properties.power then
vlayer_data.storage.power_items[name] = { vlayer_data.storage.power_items[name] = {
value = properties.fuel_value * 1000000, value = assert(properties.fuel_value) * 1000000,
count = 0, count = 0,
} }
end end
@@ -361,7 +361,7 @@ local function handle_input_interfaces()
if not interface.valid then if not interface.valid then
vlayer_data.entity_interfaces.storage_input[index] = nil vlayer_data.entity_interfaces.storage_input[index] = nil
else else
local inventory = interface.get_inventory(defines.inventory.chest) local inventory = assert(interface.get_inventory(defines.inventory.chest))
for _, v in pairs(inventory.get_contents()) do for _, v in pairs(inventory.get_contents()) do
if config.allowed_items[v.name] then if config.allowed_items[v.name] then
@@ -384,8 +384,9 @@ local function handle_input_interfaces()
if count_deduct and count_add then if count_deduct and count_add then
if config.allowed_items[v.name].modded then if config.allowed_items[v.name].modded then
local modded_item = assert(config.modded_items[v.name])
if config.modded_auto_downgrade then if config.modded_auto_downgrade then
vlayer.insert_item(config.modded_items[v.name].base_game_equivalent, count_add * config.modded_items[v.name].multiplier) vlayer.insert_item(modded_item.base_game_equivalent, count_add * modded_item.multiplier)
else else
vlayer.insert_item(v.name, count_add) vlayer.insert_item(v.name, count_add)
end end
@@ -439,14 +440,14 @@ local function handle_output_interfaces()
if not interface.valid then if not interface.valid then
vlayer_data.entity_interfaces.storage_output[index] = nil vlayer_data.entity_interfaces.storage_output[index] = nil
else else
local inventory = interface.get_inventory(defines.inventory.chest) local inventory = assert(interface.get_inventory(defines.inventory.chest))
local inventory_request_sections = interface.get_logistic_sections().sections local inventory_request_sections = assert(interface.get_logistic_sections()).sections
for i = 1, #inventory_request_sections do for i = 1, #inventory_request_sections do
for _, v in pairs(inventory_request_sections[i].filters) do for _, v in pairs(inventory_request_sections[i].filters) do
if v.value and config.allowed_items[v.value.name] then if v.value and config.allowed_items[v.value.name] then
local current_amount = inventory.get_item_count(v.value.name) local current_amount = inventory.get_item_count(v.value.name)
local request_amount = math.min(v.min - current_amount, vlayer_data.storage.items[v.value.name]) local request_amount = math.min(assert(v.min) - current_amount, vlayer_data.storage.items[v.value.name])
if request_amount > 0 and inventory.can_insert{ name = v.value.name, count = request_amount } then if request_amount > 0 and inventory.can_insert{ name = v.value.name, count = request_amount } then
local removed_item_count = vlayer.remove_item(v.value.name, request_amount) local removed_item_count = vlayer.remove_item(v.value.name, request_amount)
@@ -582,11 +583,11 @@ local function handle_circuit_interfaces()
if not interface.valid then if not interface.valid then
vlayer_data.entity_interfaces.circuit[index] = nil vlayer_data.entity_interfaces.circuit[index] = nil
else else
local circuit_oc = interface.get_or_create_control_behavior() local control = interface.get_or_create_control_behavior() --[[@as LuaConstantCombinatorControlBehavior]]
if circuit_oc.sections_count == 0 then if control.sections_count == 0 then
circuit_oc.add_section() control.add_section()
end end
circuit_oc = circuit_oc.sections[1] local circuit_oc = assert(control.sections[1])
local signal_index = 1 local signal_index = 1
local circuit = vlayer.get_circuits() local circuit = vlayer.get_circuits()
@@ -617,7 +618,7 @@ local function handle_circuit_interfaces()
-- Clear remaining signals to prevent outdated values being present (caused by count > 0 check) -- Clear remaining signals to prevent outdated values being present (caused by count > 0 check)
for clear_index = signal_index, #circuit do for clear_index = signal_index, #circuit do
if not circuit_oc.get_slot(clear_index).signal then if not circuit_oc.get_slot(clear_index).value then
break -- There are no more signals to clear break -- There are no more signals to clear
end end
@@ -107,7 +107,7 @@ function Warnings.add_warning(player, by_player_name, reason)
reason = reason or "None given." reason = reason or "None given."
local warning_count local warning_count --- @type number
PlayerWarnings:update(player.name, function(_, warnings) PlayerWarnings:update(player.name, function(_, warnings)
local warning = { local warning = {
by_player_name = by_player_name, by_player_name = by_player_name,
+1 -1
View File
@@ -18,7 +18,7 @@ ToolbarState:on_load(function(player_name, value)
local decompressed = helpers.json_to_table(assert(helpers.decode_string(value), "Failed String Decode")) local decompressed = helpers.json_to_table(assert(helpers.decode_string(value), "Failed String Decode"))
local player = assert(game.get_player(player_name)) local player = assert(game.get_player(player_name))
Gui.toolbar.set_state(player, decompressed --[[ @as Gui.ToolbarState ]]) Gui.toolbar.set_state(player, decompressed --[[@as Gui.ToolbarState]])
return nil -- We don't save the state, use Gui.toolbar.get_state return nil -- We don't save the state, use Gui.toolbar.get_state
end) end)
@@ -126,19 +126,19 @@ lib.collect_loginet = function()
end end
if config.modules.logistorage then if config.modules.logistorage then
for name, v in pairs(network.get_contents()) do for _, item in pairs(network.get_contents()) do
stats.items[name] = (stats.items[name] or 0) + v stats.items[item.name] = (stats.items[item.name] or 0) + item.count
end end
-- pickups and deliveries of items -- pickups and deliveries of items
for _, point_list in pairs{ network.provider_points, network.requester_points, network.storage_points } do for _, point_list in pairs{ network.provider_points, network.requester_points, network.storage_points } do
for _, point in pairs(point_list) do for _, point in pairs(point_list) do
for name, qty in pairs(point.targeted_items_pickup) do for _, item in pairs(point.targeted_items_pickup) do
stats.pickups[name] = (stats.pickups[name] or 0) + qty stats.pickups[item.name] = (stats.pickups[item.name] or 0) + item.count
end end
for name, qty in pairs(point.targeted_items_deliver) do for _, item in pairs(point.targeted_items_deliver) do
stats.deliveries[name] = (stats.deliveries[name] or 0) + qty stats.deliveries[item.name] = (stats.deliveries[item.name] or 0) + item.count
end end
end end
end end
@@ -2,6 +2,6 @@ local Gui = require("modules/exp_gui")
local Roles = require("modules.exp_legacy.expcore.roles") local Roles = require("modules.exp_legacy.expcore.roles")
local Event = require("modules/exp_legacy/utils/event") local Event = require("modules/exp_legacy/utils/event")
--- @diagnostic disable invisible --- @diagnostic disable: access-invisible
Event.add(Roles.events.on_role_assigned, Gui._ensure_consistency) Event.add(Roles.events.on_role_assigned, Gui._ensure_consistency)
Event.add(Roles.events.on_role_unassigned, Gui._ensure_consistency) Event.add(Roles.events.on_role_unassigned, Gui._ensure_consistency)
+15 -13
View File
@@ -22,9 +22,9 @@ local function aabb_align_expand(aabb)
} }
end end
local vlayer_container local vlayer_container --- @type ExpElement
local vlayer_gui_control_type local vlayer_gui_control_type --- @type ExpElement
local vlayer_gui_control_list local vlayer_gui_control_list --- @type ExpElement
local vlayer_control_type_list = { local vlayer_control_type_list = {
[1] = "energy", [1] = "energy",
@@ -87,10 +87,10 @@ SelectArea:on_selection(function(event)
local container = Gui.get_left_element(vlayer_container, player) local container = Gui.get_left_element(vlayer_container, player)
local disp = container.frame["vlayer_st_2"].disp.table local disp = container.frame["vlayer_st_2"].disp.table
local target = vlayer_control_type_list[disp[vlayer_gui_control_type.name].selected_index] local target = vlayer_control_type_list[disp[vlayer_gui_control_type.name].selected_index]
local entities local entities --- @type LuaEntity[]
if config.power_on_space and event.surface and event.surface.platform and target == "energy" then if config.power_on_space and event.surface and event.surface.platform and target == "energy" then
if player.force.technologies[config.power_on_space_research.name].level >= config.power_on_space_research.level then if (player.force --[[@as LuaForce]]).technologies[config.power_on_space_research.name].level >= config.power_on_space_research.level then
entities = event.surface.find_entities_filtered{ area = area, name = "constant-combinator", force = player.force } entities = event.surface.find_entities_filtered{ area = area, name = "constant-combinator", force = player.force }
else else
player.print{ "vlayer.power-on-space-research", config.power_on_space_research.name, config.power_on_space_research.level } player.print{ "vlayer.power-on-space-research", config.power_on_space_research.name, config.power_on_space_research.level }
@@ -116,7 +116,7 @@ SelectArea:on_selection(function(event)
local e_pos = { x = string.format("%.1f", e.position.x), y = string.format("%.1f", e.position.y) } local e_pos = { x = string.format("%.1f", e.position.x), y = string.format("%.1f", e.position.y) }
local e_circ = nil -- e.get_wire_connectors{ or_create = false } local e_circ = nil -- e.get_wire_connectors{ or_create = false }
if e.name and e.name == "steel-chest" and (not e.get_inventory(defines.inventory.chest).is_empty()) then if e.name and e.name == "steel-chest" and (not assert(e.get_inventory(defines.inventory.chest)).is_empty()) then
player.print{ "vlayer.steel-chest-empty" } player.print{ "vlayer.steel-chest-empty" }
return return
end end
@@ -325,7 +325,9 @@ local function vlayer_gui_list_refresh(player)
local interface = vlayer.get_interfaces()[vlayer_control_type_list[target]] local interface = vlayer.get_interfaces()[vlayer_control_type_list[target]]
for i = 1, vlayer.get_interface_counts()[vlayer_control_type_list[target]], 1 do for i = 1, vlayer.get_interface_counts()[vlayer_control_type_list[target]], 1 do
table.insert(full_list, i .. " X " .. interface[i].position.x .. " Y " .. interface[i].position.y) local entity = assert(interface[i])
local entity_position = entity.position
table.insert(full_list, i .. " X " .. entity_position.x .. " Y " .. entity_position.y)
end end
disp[vlayer_gui_control_list.name].items = full_list disp[vlayer_gui_control_list.name].items = full_list
@@ -379,14 +381,13 @@ local vlayer_gui_control_see = Gui.define("vlayer_gui_control_see")
}:style{ }:style{
width = 200, width = 200,
}:on_click(function(def, player, element, event) }:on_click(function(def, player, element, event)
local target = element.parent[vlayer_gui_control_type.name].selected_index local target = assert(element.parent)[vlayer_gui_control_type.name].selected_index
local n = element.parent[vlayer_gui_control_list.name].selected_index local n = assert(element.parent)[vlayer_gui_control_list.name].selected_index
if target and vlayer_control_type_list[target] and n > 0 then if target and vlayer_control_type_list[target] and n > 0 then
local i = vlayer.get_interfaces() local i = vlayer.get_interfaces()
local entity = i[vlayer_control_type_list[target]][n] local entity = i[vlayer_control_type_list[target]][n]
if entity and entity.valid then if entity and entity.valid then
local player = Gui.get_player(event)
player.set_controller{ type = defines.controllers.remote, position = entity.position, surface = entity.surface } player.set_controller{ type = defines.controllers.remote, position = entity.position, surface = entity.surface }
player.print{ "vlayer.result-interface-location", { "vlayer.control-type-" .. vlayer_control_type_list[target]:gsub("_", "-") }, pos_to_gps_string(entity.position, entity.surface.name) } player.print{ "vlayer.result-interface-location", { "vlayer.control-type-" .. vlayer_control_type_list[target]:gsub("_", "-") }, pos_to_gps_string(entity.position, entity.surface.name) }
end end
@@ -423,14 +424,15 @@ local vlayer_gui_control_remove = Gui.define("vlayer_gui_control_remove")
}:style{ }:style{
width = 200, width = 200,
}:on_click(function(def, player, element) }:on_click(function(def, player, element)
local target = element.parent[vlayer_gui_control_type.name].selected_index local target = assert(element.parent)[vlayer_gui_control_type.name].selected_index
local n = element.parent[vlayer_gui_control_list.name].selected_index local n = assert(element.parent)[vlayer_gui_control_list.name].selected_index
if target and vlayer_control_type_list[target] and n > 0 then if target and vlayer_control_type_list[target] and n > 0 then
local i = vlayer.get_interfaces() local i = vlayer.get_interfaces()
if i and i[vlayer_control_type_list[target]] then if i and i[vlayer_control_type_list[target]] then
local interface_type, interface_surface, interface_position = vlayer.remove_interface(i[vlayer_control_type_list[target]][n].surface, i[vlayer_control_type_list[target]][n].position) local entity = assert(i[vlayer_control_type_list[target]][n])
local interface_type, interface_surface, interface_position = vlayer.remove_interface(entity.surface, entity.position)
if interface_type then if interface_type then
game.print{ "vlayer.interface-result", player.name, pos_to_gps_string(interface_position, interface_surface.name), { "vlayer.result-remove" }, { "vlayer.control-type-" .. interface_type } } game.print{ "vlayer.interface-result", player.name, pos_to_gps_string(interface_position, interface_surface.name), { "vlayer.result-remove" }, { "vlayer.control-type-" .. interface_type } }
+20 -16
View File
@@ -180,7 +180,7 @@ local warp_icon_button = Gui.define("warp_icon_button")
:style(Styles.sprite32) :style(Styles.sprite32)
:on_click(function(def, player, element) :on_click(function(def, player, element)
if element.type == "choose-elem-button" then return end if element.type == "choose-elem-button" then return end
local warp_id = element.parent.caption local warp_id = assert(element.parent).caption
Warps.teleport_player(warp_id, player) Warps.teleport_player(warp_id, player)
-- Reset the warp cooldown if the player does not have unlimited warps -- Reset the warp cooldown if the player does not have unlimited warps
@@ -226,7 +226,7 @@ local warp_label = Gui.define("warp_label")
horizontally_stretchable = true, horizontally_stretchable = true,
} }
:on_click(function(def, player, element) :on_click(function(def, player, element)
local warp_id = element.parent.caption local warp_id = assert(element.parent).caption
local warp = Warps.get_warp(warp_id) local warp = Warps.get_warp(warp_id)
player.set_controller{ type = defines.controllers.remote, position = warp.position, surface = warp.surface } player.set_controller{ type = defines.controllers.remote, position = warp.position, surface = warp.surface }
end) end)
@@ -271,9 +271,9 @@ local warp_textfield = Gui.define("warp_textfield")
right_margin = 2, right_margin = 2,
} }
:on_confirmed(function(def, player, element) :on_confirmed(function(def, player, element)
local warp_id = element.parent.caption local warp_id = assert(element.parent).caption
local warp_name = element.text local warp_name = element.text
local warp_icon = element.parent.parent["icon-" .. warp_id][warp_icon_editing.name].elem_value --[[ @as SignalID ]] local warp_icon = assert(element.parent).parent["icon-" .. warp_id][warp_icon_editing.name].elem_value --[[@as SignalID]]
if warp_icon.type == nil then warp_icon.type = "item" end if warp_icon.type == nil then warp_icon.type = "item" end
Warps.set_editing(warp_id, player.name) Warps.set_editing(warp_id, player.name)
Warps.update_warp(warp_id, warp_name, warp_icon, player.name) Warps.update_warp(warp_id, warp_name, warp_icon, player.name)
@@ -291,9 +291,13 @@ local confirm_edit_button = Gui.define("confirm_edit_button")
} }
:style(Styles.sprite22) :style(Styles.sprite22)
:on_click(function(def, player, element) :on_click(function(def, player, element)
local warp_id = element.parent.caption local parent = assert(element.parent)
local warp_name = element.parent.parent["name-" .. warp_id][warp_textfield.name].text local grandparent = assert(parent.parent)
local warp_icon = element.parent.parent["icon-" .. warp_id][warp_icon_editing.name].elem_value --[[ @as SignalID ]] local warp_id = parent.caption --[[@as string]]
local name_flow = grandparent["name-" .. warp_id]
local icon_flow = grandparent["icon-" .. warp_id]
local warp_name = name_flow[warp_textfield.name].text
local warp_icon = icon_flow[warp_icon_editing.name].elem_value --[[@as SignalID]]
if warp_icon.type == nil then warp_icon.type = "item" end if warp_icon.type == nil then warp_icon.type = "item" end
Warps.set_editing(warp_id, player.name) Warps.set_editing(warp_id, player.name)
Warps.update_warp(warp_id, warp_name, warp_icon, player.name) Warps.update_warp(warp_id, warp_name, warp_icon, player.name)
@@ -311,7 +315,7 @@ local cancel_edit_button = Gui.define("cancel_edit_button")
} }
:style(Styles.sprite22) :style(Styles.sprite22)
:on_click(function(def, player, element) :on_click(function(def, player, element)
local warp_id = element.parent.caption local warp_id = assert(element.parent).caption
-- Check if this is the first edit, if so remove the warp. -- Check if this is the first edit, if so remove the warp.
local warp = Warps.get_warp(warp_id) local warp = Warps.get_warp(warp_id)
if warp.updates == 1 then if warp.updates == 1 then
@@ -333,7 +337,7 @@ local remove_warp_button = Gui.define("remove_warp_button")
} }
:style(Styles.sprite22) :style(Styles.sprite22)
:on_click(function(def, player, element) :on_click(function(def, player, element)
local warp_id = element.parent.caption local warp_id = assert(element.parent).caption
Warps.remove_warp(warp_id) Warps.remove_warp(warp_id)
end) end)
@@ -349,7 +353,7 @@ local edit_warp_button = Gui.define("edit_warp_button")
} }
:style(Styles.sprite22) :style(Styles.sprite22)
:on_click(function(def, player, element) :on_click(function(def, player, element)
local warp_id = element.parent.caption local warp_id = assert(element.parent).caption
Warps.set_editing(warp_id, player.name, true) Warps.set_editing(warp_id, player.name, true)
end) end)
@@ -429,8 +433,8 @@ local function update_warp_elements(element, warp, warp_player_is_on, on_cooldow
-- Check if button element is valid -- Check if button element is valid
if not element or not element.valid then return end if not element or not element.valid then return end
local label_style = element.parent.parent["name-" .. warp.warp_id][warp_label.name].style local label_style = assert(element.parent).parent["name-" .. warp.warp_id][warp_label.name].style
local warp_status_element = element.parent.parent["name-" .. warp.warp_id][warp_status.name] local warp_status_element = assert(element.parent).parent["name-" .. warp.warp_id][warp_status.name]
-- If player is not on a warp -- If player is not on a warp
if not warp_player_is_on then if not warp_player_is_on then
@@ -669,7 +673,7 @@ warp_list_container = Gui.define("warp_list_container")
-- Draw the scroll table for the warps -- Draw the scroll table for the warps
local scroll_table = Gui.elements.scroll_table(container, 250, 3, "scroll") local scroll_table = Gui.elements.scroll_table(container, 250, 3, "scroll")
-- Set the scroll panel to always show the scrollbar (not doing this will result in a changing gui size) -- Set the scroll panel to always show the scrollbar (not doing this will result in a changing gui size)
scroll_table.parent.vertical_scroll_policy = "always" assert(scroll_table.parent).vertical_scroll_policy = "always"
-- Change the style of the scroll table -- Change the style of the scroll table
local scroll_table_style = scroll_table.style local scroll_table_style = scroll_table.style
@@ -778,7 +782,7 @@ Event.on_nth_tick(math.floor(60 / config.update_smoothing), function()
end end
-- Check if the force has any warps -- Check if the force has any warps
local closest_warp = nil local closest_warp = nil --- @type { warp_id: string, name: string }?
local closest_distance = nil local closest_distance = nil
if #warp_ids > 0 then if #warp_ids > 0 then
local surface = player.surface local surface = player.surface
@@ -838,7 +842,7 @@ end)
Event.add(defines.events.on_player_created, function(event) Event.add(defines.events.on_player_created, function(event)
-- If the force has no spawn then make a spawn warp -- If the force has no spawn then make a spawn warp
local player = game.players[event.player_index] local player = game.players[event.player_index]
local force = player.force local force = player.force --[[@as LuaForce]]
local spawn_id = Warps.get_spawn_warp_id(force.name) local spawn_id = Warps.get_spawn_warp_id(force.name)
if not spawn_id then if not spawn_id then
local spawn_position = force.get_spawn_position(player.surface) local spawn_position = force.get_spawn_position(player.surface)
@@ -870,7 +874,7 @@ local function role_update_event(event)
-- Check if user has permission to add warps -- Check if user has permission to add warps
local allow_add_warp = check_player_permissions(player, "allow_add_warp") local allow_add_warp = check_player_permissions(player, "allow_add_warp")
-- Update container size depending on whether the player is allowed to add warps -- Update container size depending on whether the player is allowed to add warps
frame.parent.style.width = allow_add_warp and 268 or 220 assert(frame.parent).style.width = allow_add_warp and 268 or 220
-- Update the warps, in case the user can now edit them -- Update the warps, in case the user can now edit them
local scroll_table = frame.scroll.table local scroll_table = frame.scroll.table
+7 -7
View File
@@ -12,7 +12,7 @@ made with `assign_player_local`.
]] ]]
local clusterio_api = require("modules/clusterio/api") local clusterio_api = require("modules/clusterio/api")
local compat = require("modules/clusterio/compat") local compat = require("modules/clusterio/compat") --[[@as LibCompat]]
local Async = require("modules/exp_util/async") local Async = require("modules/exp_util/async")
--- @class ExpRoles --- @class ExpRoles
@@ -284,7 +284,7 @@ local server_role = setmetatable({
--- @param player LuaPlayer | string | nil --- @param player LuaPlayer | string | nil
--- @return ExpRoles.Role[] --- @return ExpRoles.Role[]
function ExpRoles.get_player_roles(player) function ExpRoles.get_player_roles(player)
local player_name = type(player) == "table" and player.name or player --[[ @as string? ]] local player_name = type(player) == "table" and player.name or player --[[@as string?]]
-- The server is not a player and is allowed to do anything -- The server is not a player and is allowed to do anything
if player_name == nil then return { server_role } end if player_name == nil then return { server_role } end
@@ -399,7 +399,7 @@ end
--- @param self ExpRoles.Role --- @param self ExpRoles.Role
--- @param action string --- @param action string
--- @return boolean --- @return boolean
function Role:is_allowed(action) function Role.is_allowed(self, action)
local allowed = self.allowed_actions local allowed = self.allowed_actions
return allowed["core.admin"] or allowed[permission_from_action(action)] or false return allowed["core.admin"] or allowed[permission_from_action(action)] or false
end end
@@ -408,7 +408,7 @@ end
--- @param self ExpRoles.Role --- @param self ExpRoles.Role
--- @param name string --- @param name string
--- @return boolean --- @return boolean
function Role:has_flag(name) function Role.has_flag(self, name)
return self.allowed_actions[permission_from_flag(name)] or false return self.allowed_actions[permission_from_flag(name)] or false
end end
@@ -416,7 +416,7 @@ end
--- @param self ExpRoles.Role --- @param self ExpRoles.Role
--- @param online boolean? When given, filter by connected state --- @param online boolean? When given, filter by connected state
--- @return LuaPlayer[] --- @return LuaPlayer[]
function Role:get_players(online) function Role.get_players(self, online)
local players = {} local players = {}
for player_name, role_names in pairs(ExpRoles.config.players) do for player_name, role_names in pairs(ExpRoles.config.players) do
for _, role_name in pairs(role_names) do for _, role_name in pairs(role_names) do
@@ -437,7 +437,7 @@ end
--- @param self ExpRoles.Role --- @param self ExpRoles.Role
--- @param message LocalisedString --- @param message LocalisedString
--- @return number # Number of players the message was sent to --- @return number # Number of players the message was sent to
function Role:print(message) function Role.print(self, message)
local players = self:get_players(true) local players = self:get_players(true)
for _, player in pairs(players) do for _, player in pairs(players) do
player.print(message) player.print(message)
@@ -678,7 +678,7 @@ end
--- @param silent boolean? --- @param silent boolean?
--- @param sync boolean --- @param sync boolean
local function change_player_roles(player, roles, change_type, by_player_name, silent, sync) local function change_player_roles(player, roles, change_type, by_player_name, silent, sync)
local player_name = type(player) == "table" and player.name or player --[[ @as string? ]] local player_name = type(player) == "table" and player.name or player --[[@as string?]]
if not player_name then return end if not player_name then return end
local role_objects = resolve_roles(roles) local role_objects = resolve_roles(roles)
+6 -1
View File
@@ -9,7 +9,10 @@ had, and event_handler expects `events` to be the handlers to register.
local clusterio_api = require("modules/clusterio/api") local clusterio_api = require("modules/clusterio/api")
local ExpRoles = require("modules/exp_roles/control") local ExpRoles = require("modules/exp_roles/control")
return { --- @class ExpRoles.EventHandlers
--- @field on_load fun()
--- @field events table<defines.events, fun(event: EventData)>
local handlers = {
on_load = ExpRoles.on_load, on_load = ExpRoles.on_load,
events = { events = {
[clusterio_api.events.on_server_startup] = ExpRoles.on_server_startup, [clusterio_api.events.on_server_startup] = ExpRoles.on_server_startup,
@@ -17,3 +20,5 @@ return {
[defines.events.on_player_joined_game] = ExpRoles.on_player_joined_game, [defines.events.on_player_joined_game] = ExpRoles.on_player_joined_game,
}, },
} }
return handlers
+1 -1
View File
@@ -4,7 +4,7 @@ However, sometimes you need globals, for example to access functions within rcon
Therefore, we advise that this should be the only file in your module to expose globals Therefore, we advise that this should be the only file in your module to expose globals
]] ]]
--- @diagnostic disable: global-element --- @diagnostic disable: global-in-non-module
-- Access using `/sc exp_roles.foo()` -- Access using `/sc exp_roles.foo()`
exp_roles = require("modules/exp_roles/control") exp_roles = require("modules/exp_roles/control")
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -18,7 +18,7 @@ local valid, invalid = Commands.status.success, Commands.status.invalid_input
local Roles = require("modules.exp_legacy.expcore.roles") local Roles = require("modules.exp_legacy.expcore.roles")
local highest_role = Roles.get_player_highest_role local highest_role = Roles.get_player_highest_role
local types = {} --- @class Commands.types local types = {} --- @class (partial) Commands.types
--- A role defined by exp roles --- A role defined by exp roles
types.role = add("role", Commands.types.key_of(Roles.config.roles)) types.role = add("role", Commands.types.key_of(Roles.config.roles))
+7 -6
View File
@@ -15,11 +15,11 @@ local abs = math.abs
local commands = {} local commands = {}
--- @param player LuaPlayer --- @param player LuaPlayer
--- @param area BoundingBox --- @param area BoundingBox.struct
--- @return boolean --- @return boolean
local function location_break(player, area) local function location_break(player, area)
local surface = player.surface -- Allow remote view local surface = player.surface -- Allow remote view
local is_charted = player.force.is_chunk_charted local is_charted = (player.force --[[@as LuaForce]]).is_chunk_charted
if is_charted(surface, { x = floor(area.left_top.x / 32), y = floor(area.left_top.y / 32) }) then if is_charted(surface, { x = floor(area.left_top.x / 32), y = floor(area.left_top.y / 32) }) then
return true return true
elseif is_charted(surface, { x = floor(area.left_top.x / 32), y = floor(area.right_bottom.y / 32) }) then elseif is_charted(surface, { x = floor(area.left_top.x / 32), y = floor(area.right_bottom.y / 32) }) then
@@ -43,7 +43,7 @@ commands.artillery = Commands.new("artillery", { "exp-commands_artillery.descrip
end end
SelectArea:start(player) SelectArea:start(player)
return Commands.status.success{ "exp-commands_artillery.enter" } return Commands.status.success{ "exp-commands_artillery.enter" }
end) --[[ @as any ]] end) --[[@as any]]
--- when an area is selected to add protection to the area --- when an area is selected to add protection to the area
SelectArea:on_selection(function(event) SelectArea:on_selection(function(event)
@@ -63,13 +63,14 @@ SelectArea:on_selection(function(event)
} }
local count = 0 local count = 0
local hits = {} --- @type MapPosition[] local hits = {} --- @type MapPosition.struct[]
for _, entity in ipairs(entities) do for _, entity in ipairs(entities) do
local skip = false local skip = false
local entity_position = entity.position
for _, pos in ipairs(hits) do for _, pos in ipairs(hits) do
local x = abs(entity.position.x - pos.x) local x = abs(entity_position.x - pos.x)
local y = abs(entity.position.y - pos.y) local y = abs(entity_position.y - pos.y)
if x * x + y * y < 36 then if x * x + y * y < 36 then
skip = true skip = true
break break
+1 -1
View File
@@ -41,7 +41,7 @@ local function get_server_id(server)
elseif status == "Offline" then elseif status == "Offline" then
return false, { "exp-commands_connect.offline", server_details.name } return false, { "exp-commands_connect.offline", server_details.name }
end end
return true, server_id return true, server_id --[[@as string]]
elseif server_count_before > 0 then elseif server_count_before > 0 then
return false, { "exp-commands_connect.wrong-version", concat(server_names_before, ", ") } return false, { "exp-commands_connect.wrong-version", concat(server_names_before, ", ") }
else else
+1 -1
View File
@@ -25,7 +25,7 @@ Commands.new("kill", { "exp-commands_kill.description" })
if script.active_mods["space-age"] then if script.active_mods["space-age"] then
other_player.surface.create_entity{ name = "lightning", position = { other_player.position.x, other_player.position.y - 16 }, target = other_player.character } other_player.surface.create_entity{ name = "lightning", position = { other_player.position.x, other_player.position.y - 16 }, target = other_player.character }
end end
other_player.character.die() assert(other_player.character).die()
else else
return Commands.status.unauthorised{ "exp-commands_kill.lower-role" } return Commands.status.unauthorised{ "exp-commands_kill.lower-role" }
end end
+1 -1
View File
@@ -22,7 +22,7 @@ commands.lawnmower = Commands.new("lawnmower", { "exp-commands_lawnmower.descrip
SelectArea:start(player) SelectArea:start(player)
return Commands.status.success{ "exp-commands_lawnmower.enter" } return Commands.status.success{ "exp-commands_lawnmower.enter" }
end) --[[ @as any ]] end) --[[@as any]]
--- When an area is selected to be handled --- When an area is selected to be handled
SelectArea:on_selection(function(event) SelectArea:on_selection(function(event)
@@ -37,7 +37,7 @@ end
--- Get the key used in protected_areas --- Get the key used in protected_areas
--- TODO expose this from EntityProtection --- TODO expose this from EntityProtection
--- @param area BoundingBox --- @param area BoundingBox.struct
--- @return string --- @return string
local function get_area_key(area) local function get_area_key(area)
return format_string("%i,%i", floor(area.left_top.x), floor(area.left_top.y)) return format_string("%i,%i", floor(area.left_top.x), floor(area.left_top.y))
@@ -49,13 +49,15 @@ end
local function show_protected_entity(player, entity) local function show_protected_entity(player, entity)
local key = get_entity_key(entity) local key = get_entity_key(entity)
if renders[player.index][key] then return end if renders[player.index][key] then return end
local rb = entity.selection_box.right_bottom local selection_box = entity.selection_box
local rb = selection_box.right_bottom
local position = entity.position
renders[player.index][key] = rendering.draw_sprite{ renders[player.index][key] = rendering.draw_sprite{
sprite = "utility/notification", sprite = "utility/notification",
target = entity, target = entity,
target_offset = { target_offset = {
(rb.x - entity.position.x) * 0.75, (rb.x - position.x) * 0.75,
(rb.y - entity.position.y) * 0.75, (rb.y - position.y) * 0.75,
}, },
x_scale = 2, x_scale = 2,
y_scale = 2, y_scale = 2,
@@ -67,7 +69,7 @@ end
--- Show a protected area to a player --- Show a protected area to a player
--- @param player LuaPlayer --- @param player LuaPlayer
--- @param surface LuaSurface --- @param surface LuaSurface
--- @param area BoundingBox --- @param area BoundingBox.struct
local function show_protected_area(player, surface, area) local function show_protected_area(player, surface, area)
local key = get_area_key(area) local key = get_area_key(area)
if renders[player.index][key] then return end if renders[player.index][key] then return end
@@ -7,7 +7,7 @@ local Storage = require("modules/exp_util/storage")
--- Storage variables --- Storage variables
local active_players = {} --- @type table<number, boolean> Stores all players in in protected mode local active_players = {} --- @type table<number, boolean> Stores all players in in protected mode
local map_tags = {} --- @type table<number, boolean> Stores all protected map tags local map_tags = {} --- @type table<string, boolean> Stores all protected map tags
Storage.register({ Storage.register({
active_players = active_players, active_players = active_players,
+10 -4
View File
@@ -6,6 +6,12 @@ local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale local format_player_name = Commands.format_player_name_locale
local format_text = Commands.format_rich_text_color local format_text = Commands.format_rich_text_color
--- A colour with every channel set, Color.struct leaves them optional
--- @class ExpCommands_Rainbow.Color
--- @field r number
--- @field g number
--- @field b number
--- Wraps one component into the next --- Wraps one component into the next
--- @param c1 number --- @param c1 number
--- @param c2 number --- @param c2 number
@@ -21,8 +27,8 @@ local function step_component(c1, c2)
end end
--- Wraps all components of a colour ensuring it remains valid --- Wraps all components of a colour ensuring it remains valid
--- @param color Color --- @param color ExpCommands_Rainbow.Color
--- @return Color --- @return ExpCommands_Rainbow.Color
local function step_color(color) local function step_color(color)
color.r, color.g = step_component(color.r, color.g) color.r, color.g = step_component(color.r, color.g)
color.g, color.b = step_component(color.g, color.b) color.g, color.b = step_component(color.g, color.b)
@@ -32,9 +38,9 @@ local function step_color(color)
end end
--- Get the next colour in the rainbow by the given step --- Get the next colour in the rainbow by the given step
--- @param color Color --- @param color ExpCommands_Rainbow.Color
--- @param step number --- @param step number
--- @return Color --- @return ExpCommands_Rainbow.Color
local function next_color(color, step) local function next_color(color, step)
step = step or 0.1 step = step or 0.1
local new_color = { r = 0, g = 0, b = 0 } local new_color = { r = 0, g = 0, b = 0 }
+2 -2
View File
@@ -29,7 +29,7 @@ Commands.new("ratio", { "exp-commands_ratio.description" })
local amount_of_machines = 1 local amount_of_machines = 1
if items_per_second then if items_per_second then
amount_of_machines = math.ceil(products[1].amount * crafts_per_second) amount_of_machines = math.ceil(assert(assert(products[1]).amount) * crafts_per_second)
end end
for _, ingredient in ipairs(ingredients) do for _, ingredient in ipairs(ingredients) do
@@ -43,7 +43,7 @@ Commands.new("ratio", { "exp-commands_ratio.description" })
for i, product in ipairs(products) do for i, product in ipairs(products) do
Commands.print{ Commands.print{
product.type == "item" and "exp-commands_ratio.item-out" or "exp-commands_ratio.fluid-out", product.type == "item" and "exp-commands_ratio.item-out" or "exp-commands_ratio.fluid-out",
math.round(product.amount * crafts_per_second, 3), math.round(assert(product.amount) * crafts_per_second, 3),
product.name product.name
} }
end end
+8 -5
View File
@@ -11,7 +11,10 @@ local player_has_flag = Roles.player_has_flag
local Reports = require("modules.exp_legacy.modules.control.reports") --- @dep modules.control.reports local Reports = require("modules.exp_legacy.modules.control.reports") --- @dep modules.control.reports
--- @type Commands.InputParser --- @param input string
--- @param player LuaPlayer
--- @return Commands.Status
--- @return LuaPlayer | LocalisedString
local function reportable_player(input, player) local function reportable_player(input, player)
local success, status, result = parse_input(input, player, Commands.types.player) local success, status, result = parse_input(input, player, Commands.types.player)
if not success then return status, result end if not success then return status, result end
@@ -40,11 +43,11 @@ Commands.new("create-report", { "exp-commands_reports.description-create" })
if Reports.report_player(other_player, player.name, reason) then if Reports.report_player(other_player, player.name, reason) then
local user_message = { "exp-commands_reports.response", other_player_name, reason } local user_message = { "exp-commands_reports.response", other_player_name, reason }
local admin_message = { "exp-commands_reports.response-admin", other_player_name, player_name, reason } local admin_message = { "exp-commands_reports.response-admin", other_player_name, player_name, reason }
for _, player in ipairs(game.connected_players) do for _, connected_player in ipairs(game.connected_players) do
if player.admin then if connected_player.admin then
player.print(admin_message) connected_player.print(admin_message)
else else
player.print(user_message) connected_player.print(user_message)
end end
end end
else else
+2 -3
View File
@@ -42,7 +42,7 @@ Commands.new("get-roles", { "exp-commands_roles.description-get" })
--- @cast other_player LuaPlayer? --- @cast other_player LuaPlayer?
local roles = get_roles_ordered() local roles = get_roles_ordered()
local roles_formatted = { "" } --- @type LocalisedString local roles_formatted = { "" } --- @type LocalisedString
local response = { "exp-commands_roles.list-roles", roles_formatted } local response = { "exp-commands_roles.list-roles", roles_formatted } --[[@as LocalisedString]]
if other_player then if other_player then
roles = get_player_roles(other_player) roles = get_player_roles(other_player)
response[1] = "exp-commands_roles.list-player" response[1] = "exp-commands_roles.list-player"
@@ -55,8 +55,7 @@ Commands.new("get-roles", { "exp-commands_roles.description-get" })
end end
local last = #roles_formatted local last = #roles_formatted
--- @diagnostic disable-next-line nil-check roles_formatted[last] = assert(roles_formatted[last])[2]
roles_formatted[last] = roles_formatted[last][2]
return Commands.status.success(response) return Commands.status.success(response)
end) end)
+7 -3
View File
@@ -10,7 +10,10 @@ local format_player_name = Commands.format_player_name_locale
local format_number = require("util").format_number local format_number = require("util").format_number
--- A player who is of a lower role than the executing player --- A player who is of a lower role than the executing player
--- @type Commands.InputParser --- @param input string
--- @param player LuaPlayer
--- @return Commands.Status
--- @return LuaItemPrototype | LocalisedString
local function parse_item(input, player) local function parse_item(input, player)
-- First Case - internal name is given -- First Case - internal name is given
-- Second Case - rich text is given -- Second Case - rich text is given
@@ -88,7 +91,7 @@ local function sort_results(results, func)
end end
end end
return sorted return sorted --[[@as SearchResult[] ]]
end end
local display_players_time_format = ExpUtil.format_time_factory_locale{ format = "short", hours = true, minutes = true } local display_players_time_format = ExpUtil.format_time_factory_locale{ format = "short", hours = true, minutes = true }
@@ -146,7 +149,8 @@ Commands.new("search-online", { "exp-commands_search.description-online" })
end) end)
--- Return the amount of an item a player has --- Return the amount of an item a player has
--- @type SortFunction --- @param data SearchResult
--- @return number
local function sort_by_count(data) local function sort_by_count(data)
return data.count return data.count
end end
+1 -1
View File
@@ -69,7 +69,7 @@ commands.clear_blueprints = Commands.new("clear-blueprints", { "exp-commands_sur
SelectArea:start(player) SelectArea:start(player)
return Commands.status.success{ "exp-commands_surface.enter" } return Commands.status.success{ "exp-commands_surface.enter" }
end) --[[ @as any ]] end) --[[@as any]]
--- When an area is selected --- When an area is selected
SelectArea:on_selection(function(event) SelectArea:on_selection(function(event)
+4 -4
View File
@@ -34,7 +34,7 @@ commands.teleport = Commands.new("teleport", { "exp-commands_teleport.descriptio
elseif not teleport_player(other_player, target_player.physical_surface, target_player.physical_position) then elseif not teleport_player(other_player, target_player.physical_surface, target_player.physical_position) then
return Commands.status.error{ "exp-commands_teleport.unavailable" } return Commands.status.error{ "exp-commands_teleport.unavailable" }
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Teleports a player to you. --- Teleports a player to you.
--- @class ExpCommands_Teleport.commands.bring: ExpCommand --- @class ExpCommands_Teleport.commands.bring: ExpCommand
@@ -49,7 +49,7 @@ commands.bring = Commands.new("bring", { "exp-commands_teleport.description-brin
elseif not teleport_player(other_player, player.physical_surface, player.physical_position) then elseif not teleport_player(other_player, player.physical_surface, player.physical_position) then
return Commands.status.error{ "exp-commands_teleport.unavailable" } return Commands.status.error{ "exp-commands_teleport.unavailable" }
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Teleports you to a player. --- Teleports you to a player.
--- @class ExpCommands_Teleport.commands.goto: ExpCommand --- @class ExpCommands_Teleport.commands.goto: ExpCommand
@@ -64,7 +64,7 @@ commands["goto"] = Commands.new("goto", { "exp-commands_teleport.description-got
elseif not teleport_player(player, other_player.physical_surface, other_player.physical_position) then elseif not teleport_player(player, other_player.physical_surface, other_player.physical_position) then
return Commands.status.error{ "exp-commands_teleport.unavailable" } return Commands.status.error{ "exp-commands_teleport.unavailable" }
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Teleport to spawn --- Teleport to spawn
--- @class ExpCommands_Teleport.commands.spawn: ExpCommand --- @class ExpCommands_Teleport.commands.spawn: ExpCommand
@@ -92,7 +92,7 @@ commands.spawn = Commands.new("spawn", { "exp-commands_teleport.description-spaw
else else
return Commands.status.unauthorised() return Commands.status.unauthorised()
end end
end) --[[ @as any ]] end) --[[@as any]]
return { return {
commands = commands, commands = commands,
+2 -2
View File
@@ -10,7 +10,7 @@ local format_number = require("util").format_number
local commands = {} local commands = {}
--- Set all trains to automatic --- Set all trains to automatic
--- @class ExpCommand_Artillery.commands.artillery: ExpCommand --- @class ExpCommand_Trains.commands.set_trains_to_automatic: ExpCommand
--- @overload fun(player: LuaPlayer, surface: LuaSurface?, force: LuaForce?) --- @overload fun(player: LuaPlayer, surface: LuaSurface?, force: LuaForce?)
commands.set_trains_to_automatic = Commands.new("set-trains-to-automatic", { "exp-commands_trains.description" }) commands.set_trains_to_automatic = Commands.new("set-trains-to-automatic", { "exp-commands_trains.description" })
:optional("surface", { "exp-commands_trains.arg-surface" }, Commands.types.surface) :optional("surface", { "exp-commands_trains.arg-surface" }, Commands.types.surface)
@@ -32,7 +32,7 @@ commands.set_trains_to_automatic = Commands.new("set-trains-to-automatic", { "ex
end end
game.print{ "exp-commands_trains.response", format_player_name(player), format_number(#trains, false) } game.print{ "exp-commands_trains.response", format_player_name(player), format_number(#trains, false) }
end) --[[ @as any ]] end) --[[@as any]]
return { return {
commands = commands, commands = commands,
+3 -3
View File
@@ -35,7 +35,7 @@ Commands.new("get-warnings", { "exp-commands_warnings.description-get" })
local warnings = Warnings.get_warnings(player) local warnings = Warnings.get_warnings(player)
local script_warnings = Warnings.get_script_warnings(player) local script_warnings = Warnings.get_script_warnings(player)
local other_player_name = format_player_name(other_player) local other_player_name = format_player_name(other_player)
Commands.print{ "exp-commands_warnings.player-title", other_player_name, #warnings, #script_warnings, config.temp_warning_limit } Commands.print{ "exp-commands_warnings.player-title", other_player_name, #warnings, #script_warnings, config.script_warning_limit }
for _, warning in pairs(warnings) do for _, warning in pairs(warnings) do
local by_player_name_formatted = format_player_name(warning.by_player_name) local by_player_name_formatted = format_player_name(warning.by_player_name)
Commands.print{ "exp-commands_warnings.list-element-player", by_player_name_formatted, warning.reason } Commands.print{ "exp-commands_warnings.list-element-player", by_player_name_formatted, warning.reason }
@@ -47,12 +47,12 @@ Commands.new("get-warnings", { "exp-commands_warnings.description-get" })
for player_name, player_warnings in pairs(warnings) do for player_name, player_warnings in pairs(warnings) do
local player_name_formatted = format_player_name(player_name) local player_name_formatted = format_player_name(player_name)
local script_warning_count = script_warnings[player_name] and #script_warnings[player_name] or 0 local script_warning_count = script_warnings[player_name] and #script_warnings[player_name] or 0
Commands.print{ "exp-commands_warnings.list-element", player_name_formatted, #player_warnings, script_warning_count, config.temp_warning_limit } Commands.print{ "exp-commands_warnings.list-element", player_name_formatted, #player_warnings, script_warning_count, config.script_warning_limit }
end end
for player_name, player_warnings in pairs(script_warnings) do for player_name, player_warnings in pairs(script_warnings) do
if not warnings[player_name] then if not warnings[player_name] then
local player_name_formatted = format_player_name(player_name) local player_name_formatted = format_player_name(player_name)
Commands.print{ "exp-commands_warnings.list-element", player_name_formatted, 0, #player_warnings, config.temp_warning_limit } Commands.print{ "exp-commands_warnings.list-element", player_name_formatted, 0, #player_warnings, config.script_warning_limit }
end end
end end
end end
+2 -2
View File
@@ -36,7 +36,7 @@ commands.waterfill = Commands.new("waterfill", { "exp-commands_waterfill.descrip
SelectArea:start(player) SelectArea:start(player)
return Commands.status.success{ "exp-commands_waterfill.enter" } return Commands.status.success{ "exp-commands_waterfill.enter" }
end end
end) --[[ @as any ]] end) --[[@as any]]
--- When an area is selected to be converted to water --- When an area is selected to be converted to water
SelectArea:on_selection(function(event) SelectArea:on_selection(function(event)
@@ -70,7 +70,7 @@ SelectArea:on_selection(function(event)
if #chests > 0 then if #chests > 0 then
for _, chest in pairs(chests) do for _, chest in pairs(chests) do
tile_count = tile_count + 1 tile_count = tile_count + 1
if chest.get_inventory(defines.inventory.chest).is_empty() and tile_count <= item_count_total then if assert(chest.get_inventory(defines.inventory.chest)).is_empty() and tile_count <= item_count_total then
tiles_to_make[tile_count] = { name = tile_to_apply, position = { chest.position.x, chest.position.y } } tiles_to_make[tile_count] = { name = tile_to_apply, position = { chest.position.x, chest.position.y } }
chest.destroy() chest.destroy()
else else
+1 -1
View File
@@ -8,7 +8,7 @@ local floor = math.floor
--- Give a player their starting items --- Give a player their starting items
--- @param player LuaPlayer --- @param player LuaPlayer
local function give_starting_items(player) local function give_starting_items(player)
local get_prod_stats = player.force.get_item_production_statistics(player.physical_surface) local get_prod_stats = (player.force --[[@as LuaForce]]).get_item_production_statistics(player.physical_surface)
local get_input_count = get_prod_stats.get_input_count local get_input_count = get_prod_stats.get_input_count
local insert_param = { name = "", count = 0 } local insert_param = { name = "", count = 0 }
local insert = player.insert local insert = player.insert
@@ -26,11 +26,12 @@ local function on_entity_damaged(event)
-- Outputs the message as floating text -- Outputs the message as floating text
if message then if message then
local entity_position = entity.position
local entity_radius = max(1, entity.get_radius()) local entity_radius = max(1, entity.get_radius())
local offset = (random() - 0.5) * entity_radius * config.damage_location_variance local offset = (random() - 0.5) * entity_radius * config.damage_location_variance
local position = { x = entity.position.x + offset, y = entity.position.y - entity_radius } local position = { x = entity_position.x + offset, y = entity_position.y - entity_radius }
local health_percentage = entity.get_health_ratio() local health_percentage = assert(entity.get_health_ratio())
local color = { r = 1 - health_percentage, g = health_percentage, b = 0 } local color = { r = 1 - health_percentage, g = health_percentage, b = 0 }
FlyingText.create{ FlyingText.create{
@@ -31,7 +31,7 @@ local function create_map_tag(corpse_data)
message = message .. " at " .. time message = message .. " at " .. time
end end
corpse_data.tag = player.force.add_chart_tag(corpse_data.corpse.surface, { corpse_data.tag = (player.force --[[@as LuaForce]]).add_chart_tag(corpse_data.corpse.surface, {
position = corpse_data.corpse.position, position = corpse_data.corpse.position,
icon = config.map_icon, icon = config.map_icon,
text = message, text = message,
@@ -42,7 +42,7 @@ local function format_position(pos)
end end
--- Convert an area to a string --- Convert an area to a string
--- @param area BoundingBox --- @param area BoundingBox.struct
--- @return string --- @return string
local function format_area(area) local function format_area(area)
return format_string("%.1f,%.1f,%.1f,%.1f", area.left_top.x, area.left_top.y, area.right_bottom.x, area.right_bottom.y) return format_string("%.1f,%.1f,%.1f,%.1f", area.left_top.x, area.left_top.y, area.right_bottom.x, area.right_bottom.y)
@@ -137,7 +137,8 @@ local function on_player_ammo_inventory_changed(event)
if not player or not player.character then return end if not player or not player.character then return end
local character_ammo = assert(player.get_inventory(defines.inventory.character_ammo)) local character_ammo = assert(player.get_inventory(defines.inventory.character_ammo))
local item = character_ammo[player.character.selected_gun_index] local gun_index = player.character.selected_gun_index --[[@as uint]]
local item = character_ammo[gun_index]
if not item or not item.valid or not item.valid_for_read then if not item or not item.valid or not item.valid_for_read then
return return
end end
@@ -16,10 +16,9 @@ end
--- Replace a tile with the next tile in the degrade chain --- Replace a tile with the next tile in the degrade chain
--- @param surface LuaSurface --- @param surface LuaSurface
--- @param position MapPosition --- @param position MapPosition.struct
local function degrade_tile(surface, position) local function degrade_tile(surface, position)
--- @diagnostic disable-next-line Incorrect Api Type: https://forums.factorio.com/viewtopic.php?f=233&t=109145&p=593761&hilit=get_tile#p593761 local tile = surface.get_tile(position.x, position.y)
local tile = surface.get_tile(position)
local tile_name = tile.name local tile_name = tile.name
local degrade_tile_name = config.degrade_order[tile_name] local degrade_tile_name = config.degrade_order[tile_name]
if not degrade_tile_name then return end if not degrade_tile_name then return end
@@ -33,8 +32,9 @@ local function degrade_entity(entity)
local tiles = {} local tiles = {}
local surface = entity.surface local surface = entity.surface
local left_top = entity.bounding_box.left_top local bounding_box = entity.bounding_box
local right_bottom = entity.bounding_box.right_bottom local left_top = bounding_box.left_top
local right_bottom = bounding_box.right_bottom
for x = left_top.x, right_bottom.x do for x = left_top.x, right_bottom.x do
for y = left_top.y, right_bottom.y do for y = left_top.y, right_bottom.y do
local tile = surface.get_tile(x, y) local tile = surface.get_tile(x, y)
@@ -58,11 +58,10 @@ end
--- Gets the average tile strengths around position --- Gets the average tile strengths around position
--- @param surface LuaSurface --- @param surface LuaSurface
--- @param position MapPosition --- @param position MapPosition.struct
--- @return number? --- @return number?
local function get_tile_strength(surface, position) local function get_tile_strength(surface, position)
--- @diagnostic disable-next-line Incorrect Api Type: https://forums.factorio.com/viewtopic.php?f=233&t=109145&p=593761&hilit=get_tile#p593761 local tile = surface.get_tile(position.x, position.y)
local tile = surface.get_tile(position)
local tile_name = tile.name local tile_name = tile.name
local strength = config.strengths[tile_name] local strength = config.strengths[tile_name]
if not strength then return end if not strength then return end
@@ -31,15 +31,15 @@ local function append_playtime(player_name)
end end
--- Get the player name from an event --- Get the player name from an event
--- @param event { player_index: number, by_player_name: string? } --- @param event { player_index: uint, by_player_name: string? }
--- @return string, string --- @return string, string?
local function get_player_name(event) local function get_player_name(event)
local player = game.players[event.player_index] local player = game.players[event.player_index]
return player.name, event.by_player_name return player.name, event.by_player_name
end end
--- Convert a colour value into hex --- Convert a colour value into hex
--- @param color Color.0 --- @param color Color.struct
--- @return string --- @return string
local function to_hex(color) local function to_hex(color)
local hex_digits = "0123456789ABCDEF" local hex_digits = "0123456789ABCDEF"
@@ -53,7 +53,7 @@ local function to_hex(color)
end end
--- Emit the requires json to file for the given event arguments --- Emit the requires json to file for the given event arguments
--- @param opts { title: string?, color: (Color.0 | string)?, description: string?, tick: number?, fields: { name: string, value: string, inline: boolean? }[] } --- @param opts { title: string?, color: (Color.struct | string)?, description: string?, tick: number?, fields: { name: string, value: string, inline: boolean? }[] }
local function emit_event(opts) local function emit_event(opts)
local admins_online = 0 local admins_online = 0
local players_online = 0 local players_online = 0
@@ -23,7 +23,7 @@ end
--- @param event EventData.on_cargo_pod_finished_ascending --- @param event EventData.on_cargo_pod_finished_ascending
local function on_cargo_pod_finished_ascending(event) local function on_cargo_pod_finished_ascending(event)
if event.launched_by_rocket then if event.launched_by_rocket then
local force = event.cargo_pod.force local force = event.cargo_pod.force --[[@as LuaForce]]
if force.rockets_launched >= config.rocket_launch_display_rate and force.rockets_launched % config.rocket_launch_display_rate == 0 then if force.rockets_launched >= config.rocket_launch_display_rate and force.rockets_launched % config.rocket_launch_display_rate == 0 then
add_log_line("[ROCKET]", force.rockets_launched, "rockets launched") add_log_line("[ROCKET]", force.rockets_launched, "rockets launched")
elseif config.rocket_launch_display[force.rockets_launched] then elseif config.rocket_launch_display[force.rockets_launched] then
@@ -38,7 +38,7 @@ local function on_pre_player_died(event)
local cause = event.cause local cause = event.cause
if cause then if cause then
if cause.type == "character" then if cause.type == "character" then
add_log_line("[DEATH]", player.name, "died because of", cause.player.name) add_log_line("[DEATH]", player.name, "died because of", assert(cause.player).name)
else else
add_log_line("[DEATH]", player.name, "died because of", cause.name) add_log_line("[DEATH]", player.name, "died because of", cause.name)
end end
@@ -22,7 +22,7 @@ local min = math.min
--- @field trees LuaEntity[] --- @field trees LuaEntity[]
--- @field tree_count number --- @field tree_count number
--- @field permission "fast" | "allow" | "disallow" --- @field permission "fast" | "allow" | "disallow"
--- @field task Async.AsyncReturn --- @field task Async.AsyncReturn<any>
local cache --- @type TreeDeconCache? local cache --- @type TreeDeconCache?
@@ -77,14 +77,15 @@ local function get_player_cache(player_index)
-- Create a new cache if the previous on is in use -- Create a new cache if the previous on is in use
if not cache or cache.task and not cache.task.completed then if not cache or cache.task and not cache.task.completed then
cache = {} --[[@as any]] --- @diagnostic disable-next-line: missing-fields
cache = {} --[[@as TreeDeconCache]]
end end
local player = assert(game.get_player(player_index)) local player = assert(game.get_player(player_index))
cache.tick = game.tick cache.tick = game.tick
cache.player_index = player_index cache.player_index = player_index
cache.player = player cache.player = player
cache.force = player.force --[[ @as LuaForce ]] cache.force = player.force --[[@as LuaForce]]
cache.tree_count = 0 cache.tree_count = 0
cache.trees = {} cache.trees = {}
cache.permission = get_permission(player) cache.permission = get_permission(player)
+2 -2
View File
@@ -6,7 +6,7 @@ local Async = require("modules/exp_util/async")
local Storage = require("modules/exp_util/storage") local Storage = require("modules/exp_util/storage")
local config = require("modules.exp_legacy.config.compilatron") local config = require("modules.exp_legacy.config.compilatron")
--- @type table<string, Async.AsyncReturn> --- @type table<string, Async.AsyncReturn<any>>
local persistent_locations = {} local persistent_locations = {}
Storage.register(persistent_locations, function(tbl) Storage.register(persistent_locations, function(tbl)
persistent_locations = tbl persistent_locations = tbl
@@ -55,7 +55,7 @@ local speech_bubble_task =
--- @param entity LuaEntity the entity which will have messages spawn from it --- @param entity LuaEntity the entity which will have messages spawn from it
--- @param messages LocalisedString[] the messages which should be shown --- @param messages LocalisedString[] the messages which should be shown
--- @param starting_index number? the message index to start at, default 1 --- @param starting_index number? the message index to start at, default 1
--- @return Async.AsyncReturn --- @return Async.AsyncReturn<any>
local function register_entity(entity, messages, starting_index) local function register_entity(entity, messages, starting_index)
return speech_bubble_task{ return speech_bubble_task{
entity = entity, entity = entity,
@@ -68,12 +68,13 @@ local function try_deconstruct_output_chest(entity)
end end
-- Get all adjacent mining drills and inserters -- Get all adjacent mining drills and inserters
local target_position = target.position
local entities = target.surface.find_entities_filtered{ local entities = target.surface.find_entities_filtered{
type = { "mining-drill", "inserter" }, type = { "mining-drill", "inserter" },
to_be_deconstructed = false, to_be_deconstructed = false,
area = { area = {
{ target.position.x - 1, target.position.y - 1 }, left_top = { x = target_position.x - 1, y = target_position.y - 1 },
{ target.position.x + 1, target.position.y + 1 } right_bottom = { x = target_position.x + 1, y = target_position.y + 1 },
}, },
} }
@@ -250,16 +251,17 @@ local function on_resource_depleted(event)
local drills = resource.surface.find_entities_filtered{ local drills = resource.surface.find_entities_filtered{
type = "mining-drill", type = "mining-drill",
area = { area = {
{ position.x - max_mining_radius, position.y - max_mining_radius }, left_top = { x = position.x - max_mining_radius, y = position.y - max_mining_radius },
{ position.x + max_mining_radius, position.y + max_mining_radius }, right_bottom = { x = position.x + max_mining_radius, y = position.y + max_mining_radius },
}, },
} }
-- Check which could have reached this resource -- Check which could have reached this resource
for _, drill in pairs(drills) do for _, drill in pairs(drills) do
local radius = drill.prototype.mining_drill_radius local radius = drill.prototype.mining_drill_radius
local dx = math.abs(drill.position.x - position.x) local drill_position = drill.position
local dy = math.abs(drill.position.y - position.y) local dx = math.abs(drill_position.x - position.x)
local dy = math.abs(drill_position.y - position.y)
if dx <= radius and dy <= radius then if dx <= radius and dy <= radius then
try_deconstruct_miner(drill) try_deconstruct_miner(drill)
end end
+15 -14
View File
@@ -7,11 +7,11 @@ local config = require("modules.exp_legacy.config.spawn_area")
--- Apply an offset to a LuaPosition --- Apply an offset to a LuaPosition
--- @param position MapPosition --- @param position MapPosition
--- @param offset MapPosition --- @param offset MapPosition
--- @return MapPosition.0 --- @return MapPosition.struct
local function apply_offset(position, offset) local function apply_offset(position, offset)
return { return {
x = (position.x or position[1]) + (offset.x or offset[1]), x = position.x + offset.x,
y = (position.y or position[2]) + (offset.y or offset[2]) y = position.y + offset.y,
} }
end end
@@ -21,8 +21,8 @@ end
--- @param x_index number --- @param x_index number
--- @param y_index number --- @param y_index number
local function apply_offset_to_array(positions, offset, x_index, y_index) local function apply_offset_to_array(positions, offset, x_index, y_index)
local x = (offset.x or offset[1]) local x = offset.x
local y = (offset.y or offset[2]) local y = offset.y
for _, position in ipairs(positions) do for _, position in ipairs(positions) do
position[x_index] = position[x_index] + x position[x_index] = position[x_index] + x
position[y_index] = position[y_index] + y position[y_index] = position[y_index] + y
@@ -149,11 +149,13 @@ local function create_entities(surface, offset)
local pos = apply_offset({ entity_details[2], entity_details[3] }, offset) local pos = apply_offset({ entity_details[2], entity_details[3] }, offset)
local entity = surface.create_entity{ name = entity_details[1], position = pos, force = "neutral" } local entity = surface.create_entity{ name = entity_details[1], position = pos, force = "neutral" }
if entity and config.entities.protected then if entity then
protect_entity(entity) if config.entities.protected then
end protect_entity(entity)
end
entity.operable = config.entities.operable entity.operable = config.entities.operable
end
end end
end end
@@ -164,8 +166,7 @@ local function clear_spawn_area(surface, offset)
local get_tile = surface.get_tile local get_tile = surface.get_tile
-- Make sure a non water tile is used for filling -- Make sure a non water tile is used for filling
--- @diagnostic disable-next-line Incorrect Api Type: https://forums.factorio.com/viewtopic.php?f=233&t=109145&p=593761&hilit=get_tile#p593761 local starting_tile = get_tile(offset.x, offset.y)
local starting_tile = get_tile(offset)
local fill_tile = starting_tile.collides_with("player") and "landfill" or starting_tile.name local fill_tile = starting_tile.collides_with("player") and "landfill" or starting_tile.name
local fill_radius = config.spawn_area.landfill_radius local fill_radius = config.spawn_area.landfill_radius
local fill_radius_sqr = fill_radius ^ 2 local fill_radius_sqr = fill_radius ^ 2
@@ -185,8 +186,7 @@ local function clear_spawn_area(surface, offset)
if dst < tile_radius_sqr then if dst < tile_radius_sqr then
-- If it is inside the decon radius always set the tile -- If it is inside the decon radius always set the tile
tiles_to_make[#tiles_to_make + 1] = { name = decon_tile, position = pos } tiles_to_make[#tiles_to_make + 1] = { name = decon_tile, position = pos }
--- @diagnostic disable-next-line Incorrect Api Type: https://forums.factorio.com/viewtopic.php?f=233&t=109145&p=593761&hilit=get_tile#p593761 elseif dst < fill_radius_sqr and get_tile(pos.x, pos.y).collides_with("player") then
elseif dst < fill_radius_sqr and get_tile(pos).collides_with("player") then
-- If it is inside the fill radius only set the tile if it is water -- If it is inside the fill radius only set the tile if it is water
tiles_to_make[#tiles_to_make + 1] = { name = fill_tile, position = pos } tiles_to_make[#tiles_to_make + 1] = { name = fill_tile, position = pos }
end end
@@ -278,7 +278,8 @@ local function on_player_created(event)
if config.resource_patches.enabled then create_resource_patches(surface, offset) end if config.resource_patches.enabled then create_resource_patches(surface, offset) end
if config.turrets.enabled then update_turrets() end if config.turrets.enabled then update_turrets() end
player.force.set_spawn_position(offset, surface) local force = player.force --[[@as LuaForce]]
force.set_spawn_position(offset, surface)
player.teleport(offset, surface) player.teleport(offset, surface)
end end
@@ -66,8 +66,9 @@ local function rename_station(event)
-- Check which recourse is closest -- Check which recourse is closest
for _, resource in ipairs(resources) do for _, resource in ipairs(resources) do
local dx = px - resource.bounding_box.left_top.x local resource_box = resource.bounding_box
local dy = py - resource.bounding_box.left_top.y local dx = px - resource_box.left_top.x
local dy = py - resource_box.left_top.y
local distance = (dx * dx) + (dy * dy) local distance = (dx * dx) + (dy * dy)
if distance < closest_distance then if distance < closest_distance then
closest_distance = distance closest_distance = distance
@@ -78,7 +79,8 @@ local function rename_station(event)
-- Set the item name and icon -- Set the item name and icon
if closest_recourse then if closest_recourse then
item_name = closest_recourse.name:gsub("^%l", string.upper):gsub("-", " ") -- remove dashes and making first letter capital item_name = closest_recourse.name:gsub("^%l", string.upper):gsub("-", " ") -- remove dashes and making first letter capital
local product = closest_recourse.prototype.mineable_properties.products[1] local products = assert(closest_recourse.prototype.mineable_properties.products)
local product = assert(products[1])
icon = string.format("[img=%s.%s]", product.type, product.name) icon = string.format("[img=%s.%s]", product.type, product.name)
end end
end end
+9 -9
View File
@@ -49,7 +49,7 @@ Elements.toggle_section_button = Gui.define("autofill/toggle_section_button")
element.sprite = "utility/expand" element.sprite = "utility/expand"
element.tooltip = { "exp-gui_autofill.tooltip-toggle-section-expand" } element.tooltip = { "exp-gui_autofill.tooltip-toggle-section-expand" }
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Toggle if an entity will be autofilled when played --- Toggle if an entity will be autofilled when played
--- @class ExpGui_Autofill.elements.toggle_entity_button: ExpElement --- @class ExpGui_Autofill.elements.toggle_entity_button: ExpElement
@@ -88,7 +88,7 @@ Elements.toggle_entity_button = Gui.define("autofill/toggle_entity_button")
style.padding = 0 style.padding = 0
style.height = 22 style.height = 22
style.width = 22 style.width = 22
end) --[[ @as any ]] end) --[[@as any]]
--- Toggle if an item will be inserted into an entity --- Toggle if an item will be inserted into an entity
--- @class ExpGui_Autofill.elements.toggle_item_button: ExpElement --- @class ExpGui_Autofill.elements.toggle_item_button: ExpElement
@@ -127,7 +127,7 @@ Elements.toggle_item_button = Gui.define("autofill/toggle_item_button")
style.padding = -2 style.padding = -2
style.height = 32 style.height = 32
style.width = 32 style.width = 32
end) --[[ @as any ]] end) --[[@as any]]
--- The amount of an item to insert --- The amount of an item to insert
--- @class ExpGui_Autofill.elements.amount_textfield: ExpElement --- @class ExpGui_Autofill.elements.amount_textfield: ExpElement
@@ -165,7 +165,7 @@ Elements.amount_textfield = Gui.define("autofill/amount_textfield")
element.text = tostring(clamped) element.text = tostring(clamped)
player.print{ "exp-gui_autofill.invalid", clamped, rich_img("item", item_settings.name), rich_img("entity", item_settings.entity) } player.print{ "exp-gui_autofill.invalid", clamped, rich_img("item", item_settings.name), rich_img("entity", item_settings.entity) }
end end
end) --[[ @as any ]] end) --[[@as any]]
--- A disabled version of the autofill settings used as a filler --- A disabled version of the autofill settings used as a filler
Elements.disabled_autofill_setting = Gui.define("autofill/empty_autofill_setting") Elements.disabled_autofill_setting = Gui.define("autofill/empty_autofill_setting")
@@ -221,9 +221,9 @@ Elements.section = Gui.define("autofill/section")
end) end)
:on_click(function(def, player, element, event) :on_click(function(def, player, element, event)
--- @cast def ExpGui_Autofill.elements.section --- @cast def ExpGui_Autofill.elements.section
event.element = def.data[element] --[[ @as LuaGuiElement ]] event.element = def.data[element] --[[@as LuaGuiElement]]
Elements.toggle_section_button:raise_event(event) Elements.toggle_section_button:raise_event(event)
end) --[[ @as any ]] end) --[[@as any]]
--- Add an item category to a section, at most three can exist --- Add an item category to a section, at most three can exist
--- @param section LuaGuiElement --- @param section LuaGuiElement
@@ -238,7 +238,7 @@ function Elements.section.add_category(section, category_name)
category.style.vertical_spacing = 1 category.style.vertical_spacing = 1
local ctn = 0 local ctn = 0
local entity_settings = Elements.section.data[section] --[[ @as ExpGui_Autofill.entity_settings ]] local entity_settings = Elements.section.data[section] --[[@as ExpGui_Autofill.entity_settings]]
for _, item_data in pairs(entity_settings.items) do for _, item_data in pairs(entity_settings.items) do
if item_data.category == category_name then if item_data.category == category_name then
Elements.toggle_item_button(category, item_data) Elements.toggle_item_button(category, item_data)
@@ -265,7 +265,7 @@ end
--- Container added to the left gui flow --- Container added to the left gui flow
--- @class ExpGui_Autofill.elements.container: ExpElement --- @class ExpGui_Autofill.elements.container: ExpElement
--- @field data table<string, ExpGui_Autofill.entity_settings> --- @field data table<LuaPlayer, table<string, ExpGui_Autofill.entity_settings>>
Elements.container = Gui.define("autofill/container") Elements.container = Gui.define("autofill/container")
:draw(function(def, parent) :draw(function(def, parent)
--- @cast def ExpGui_Autofill.elements.container --- @cast def ExpGui_Autofill.elements.container
@@ -312,7 +312,7 @@ Elements.container = Gui.define("autofill/container")
end end
return container.parent return container.parent
end) --[[ @as any ]] end) --[[@as any]]
--- Get the autofill settings for a player --- Get the autofill settings for a player
--- @param player LuaPlayer --- @param player LuaPlayer
@@ -27,7 +27,7 @@ function Public.show(container)
local left_panel_style = left_panel.style local left_panel_style = left_panel.style
left_panel_style.width = 300 left_panel_style.width = 300
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
for element_name in pairs(ExpElement._elements) do for element_name in pairs(ExpElement._elements) do
local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = element_name } local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = element_name }
Gui.set_data(header, element_name) Gui.set_data(header, element_name)
@@ -92,18 +92,18 @@ Gui.on_click(
input_text_box.text = concat{ "ExpElement._elements[\"", element_name, "\"]" } input_text_box.text = concat{ "ExpElement._elements[\"", element_name, "\"]" }
input_text_box.style.font_color = Color.black input_text_box.style.font_color = Color.black
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
local define = ExpElement._elements[element_name] local define = ExpElement._elements[element_name]
local content = dump({ local content = dump({
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
debug = define._debug, debug = define._debug,
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
has_handlers = define._has_handlers, has_handlers = define._has_handlers,
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
track_elements = define._track_elements, track_elements = define._track_elements,
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
elements = ExpIter._scopes[element_name], elements = ExpIter._scopes[element_name],
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
data = ExpData._scopes[element_name]._raw, data = ExpData._scopes[element_name]._raw,
}) or "nil" }) or "nil"
right_panel.text = content right_panel.text = content
+1 -1
View File
@@ -4,7 +4,7 @@ local ExpUtil = require("modules/exp_util")
local concat = table.concat local concat = table.concat
local inspect = table.inspect local inspect = table.inspect
local pcall = pcall local pcall = pcall
local loadstring = loadstring --- @diagnostic disable-line local loadstring = load
local rawset = rawset local rawset = rawset
local Public = {} local Public = {}
@@ -24,7 +24,7 @@ function Public.show(container)
local left_panel_style = left_panel.style local left_panel_style = left_panel.style
left_panel_style.width = 300 left_panel_style.width = 300
--- @diagnostic disable-next-line invisible --- @diagnostic disable-next-line: access-invisible
for token_id in pairs(Storage._registered) do for token_id in pairs(Storage._registered) do
local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = token_id } local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = token_id }
Gui.set_data(header, token_id) Gui.set_data(header, token_id)
+2 -3
View File
@@ -22,11 +22,10 @@ Elements.online_player_dropdown = Gui.define("player_dropdown")
end) end)
:style{ :style{
height = 24, height = 24,
} --[[ @as any ]] } --[[@as any]]
--- To help with caching and avoid context changes the player list from the previous update is remembered --- To help with caching and avoid context changes the player list from the previous update is remembered
--- @type (string?)[] do local _player_names = {} --- @type (string?)[]
do local _player_names = {}
--- Updates the player name list after a join or leave --- Updates the player name list after a join or leave
--- @return (string?)[] --- @return (string?)[]
function Elements.online_player_dropdown._update_player_names() function Elements.online_player_dropdown._update_player_names()
+13 -13
View File
@@ -78,7 +78,7 @@ Elements.create_selection_planner = Gui.define("module_inserter/create_selection
:on_click(function(def, player, element) :on_click(function(def, player, element)
--- @cast def ExpGui_ModuleInserter.elements.create_selection_planner --- @cast def ExpGui_ModuleInserter.elements.create_selection_planner
SelectArea:start(player, def.data[element]) SelectArea:start(player, def.data[element])
end) --[[ @as any ]] end) --[[@as any]]
--- Used to select the machine to apply modules to --- Used to select the machine to apply modules to
--- @class ExpGui_ModuleInserter.elements.machine_selector: ExpElement --- @class ExpGui_ModuleInserter.elements.machine_selector: ExpElement
@@ -98,7 +98,7 @@ Elements.machine_selector = Gui.define("module_inserter/machine_selector")
:on_elem_changed(function(def, player, element, event) :on_elem_changed(function(def, player, element, event)
--- @cast def ExpGui_ModuleInserter.elements.machine_selector --- @cast def ExpGui_ModuleInserter.elements.machine_selector
local element_data = def.data[element] local element_data = def.data[element]
local machine_name = element.elem_value --[[ @as string? ]] local machine_name = element.elem_value --[[@as string?]]
if not machine_name then if not machine_name then
if element_data.on_last_row then if element_data.on_last_row then
Elements.module_table.reset_row(element_data.module_table, element) Elements.module_table.reset_row(element_data.module_table, element)
@@ -112,7 +112,7 @@ Elements.machine_selector = Gui.define("module_inserter/machine_selector")
Elements.module_table.add_row(element_data.module_table) Elements.module_table.add_row(element_data.module_table)
end end
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Used to select the modules to be applied --- Used to select the modules to be applied
Elements.module_selector = Gui.define("module_inserter/module_selector") Elements.module_selector = Gui.define("module_inserter/module_selector")
@@ -140,7 +140,7 @@ Elements.module_table = Gui.define("module_inserter/module_table")
local slots_per_row = config.module_slots_per_row + 1 local slots_per_row = config.module_slots_per_row + 1
return Gui.elements.scroll_table(parent, 280, slots_per_row) return Gui.elements.scroll_table(parent, 280, slots_per_row)
end) end)
:element_data{} --[[ @as any ]] :element_data{} --[[@as any]]
--- Get all the rows in a module table --- Get all the rows in a module table
--- @param module_table LuaGuiElement --- @param module_table LuaGuiElement
@@ -177,7 +177,7 @@ end
--- @param machine_selector LuaGuiElement --- @param machine_selector LuaGuiElement
function Elements.module_table.remove_row(module_table, machine_selector) function Elements.module_table.remove_row(module_table, machine_selector)
local rows = Elements.module_table.data[module_table] local rows = Elements.module_table.data[module_table]
local row = rows[machine_selector.index] local row = assert(rows[machine_selector.index])
rows[machine_selector.index] = nil rows[machine_selector.index] = nil
Gui.destroy_if_valid(machine_selector) Gui.destroy_if_valid(machine_selector)
for _, separator in pairs(row.row_separators) do for _, separator in pairs(row.row_separators) do
@@ -193,7 +193,7 @@ end
--- @param machine_selector LuaGuiElement --- @param machine_selector LuaGuiElement
function Elements.module_table.reset_row(module_table, machine_selector) function Elements.module_table.reset_row(module_table, machine_selector)
local rows = Elements.module_table.data[module_table] local rows = Elements.module_table.data[module_table]
local row = rows[machine_selector.index] local row = assert(rows[machine_selector.index])
for _, separator in pairs(row.row_separators) do for _, separator in pairs(row.row_separators) do
separator.visible = false separator.visible = false
@@ -211,9 +211,9 @@ end
--- @param machine_name string --- @param machine_name string
function Elements.module_table.refresh_row(module_table, machine_selector, machine_name) function Elements.module_table.refresh_row(module_table, machine_selector, machine_name)
local rows = Elements.module_table.data[module_table] local rows = Elements.module_table.data[module_table]
local row = rows[machine_selector.index] local row = assert(rows[machine_selector.index])
local active_module_count = prototypes.entity[machine_name].module_inventory_size local active_module_count = assert(prototypes.entity[machine_name].module_inventory_size)
local visible_row_count = math.ceil(active_module_count / config.module_slots_per_row) local visible_row_count = math.ceil(active_module_count / config.module_slots_per_row)
local visible_module_count = visible_row_count * config.module_slots_per_row local visible_module_count = visible_row_count * config.module_slots_per_row
local module_elem_value = { name = config.machines[machine_name].module } local module_elem_value = { name = config.machines[machine_name].module }
@@ -277,8 +277,8 @@ local function apply_planners_in_area(player, area, machine_name, planner_with_p
-- Bounding box table to be reused in the loop below -- Bounding box table to be reused in the loop below
--- @type BoundingBox --- @type BoundingBox
local param_area = { local param_area = {
left_top = {}, left_top = { x = 0, y = 0 },
right_bottom = {} right_bottom = { x = 0, y = 0 },
} }
-- Update area param table to be reused in the loop below -- Update area param table to be reused in the loop below
@@ -334,7 +334,7 @@ SelectArea:on_selection(function(event, module_table)
} }
for _, row in pairs(Elements.module_table.get_rows(module_table)) do for _, row in pairs(Elements.module_table.get_rows(module_table)) do
local machine_name = row.machine_selector.elem_value --[[ @as string? ]] local machine_name = row.machine_selector.elem_value --[[@as string?]]
if not machine_name then if not machine_name then
goto continue goto continue
end end
@@ -348,8 +348,8 @@ SelectArea:on_selection(function(event, module_table)
-- Get all the modules selected -- Get all the modules selected
for i = 1, entity_prototype.module_inventory_size do for i = 1, entity_prototype.module_inventory_size do
local module_selector = module_selectors[i] local module_selector = assert(module_selectors[i])
local module = module_selector.elem_value --[[ @as { name: string, quality: string }? ]] local module = module_selector.elem_value --[[@as { name: string, quality: string }?]]
if module then if module then
-- Module selected, add it the module arrays -- Module selected, add it the module arrays
local no_prod_name = module.name:gsub("productivity", "efficiency") local no_prod_name = module.name:gsub("productivity", "efficiency")
+14 -12
View File
@@ -22,13 +22,16 @@ local Elements = {}
--- @field _cost_scale number --- @field _cost_scale number
--- For perf calculate the division of scale against cost ahead of time --- For perf calculate the division of scale against cost ahead of time
for _, bonus_data in pairs(config.player_bonus) do --- @type table<string, ExpGui_PlayerBonus.bonus_data>
local player_bonus = config.player_bonus
for _, bonus_data in pairs(player_bonus) do
bonus_data._cost_scale = bonus_data.cost / bonus_data.scale bonus_data._cost_scale = bonus_data.cost / bonus_data.scale
end end
--- Progress bar which displays how much of a bonus has been used --- Progress bar which displays how much of a bonus has been used
--- @class ExpGui_PlayerBonus.elements.bonus_used: ExpElement --- @class ExpGui_PlayerBonus.elements.bonus_used: ExpElement
--- @field data number --- @field data table<LuaGuiElement, number>
--- @overload fun(parent: LuaGuiElement): LuaGuiElement --- @overload fun(parent: LuaGuiElement): LuaGuiElement
Elements.bonus_used = Gui.define("player_bonus/bonus_used") Elements.bonus_used = Gui.define("player_bonus/bonus_used")
:track_all_elements() :track_all_elements()
@@ -44,11 +47,10 @@ Elements.bonus_used = Gui.define("player_bonus/bonus_used")
font = "heading-2", font = "heading-2",
color = { 1, 0, 0 }, color = { 1, 0, 0 },
} }
:element_data(0) --[[ @as any ]] :element_data(0) --[[@as any]]
--- Value is cached to save perf --- Value is cached to save perf
--- @type table<number, number> do local _points_limit = {} --- @type table<number, number>
do local _points_limit = {}
--- Clear the cache for points limit --- Clear the cache for points limit
--- @param player LuaPlayer --- @param player LuaPlayer
function Elements.bonus_used._clear_points_limit_cache(player) function Elements.bonus_used._clear_points_limit_cache(player)
@@ -145,7 +147,7 @@ Elements.reset_button = Gui.define("player_bonus/reset_button")
Elements.bonus_table.reset_sliders(element_data.bonus_table) Elements.bonus_table.reset_sliders(element_data.bonus_table)
local bonus_cost = Elements.bonus_table.calculate_cost(element_data.bonus_table) local bonus_cost = Elements.bonus_table.calculate_cost(element_data.bonus_table)
Elements.bonus_used.refresh(element_data.bonus_used, bonus_cost) Elements.bonus_used.refresh(element_data.bonus_used, bonus_cost)
end) --[[ @as any ]] end) --[[@as any]]
--- Link an apply button to this reset button so that it will be disabled after being pressed --- Link an apply button to this reset button so that it will be disabled after being pressed
--- @param reset_button LuaGuiElement --- @param reset_button LuaGuiElement
@@ -186,7 +188,7 @@ Elements.apply_button = Gui.define("player_bonus/apply_button")
Elements.bonus_table.save_sliders(element_data.bonus_table) Elements.bonus_table.save_sliders(element_data.bonus_table)
Elements.container.apply_player_bonus(player) Elements.container.apply_player_bonus(player)
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Link an apply button to this reset button so that it will be disabled after being pressed --- Link an apply button to this reset button so that it will be disabled after being pressed
--- @param apply_button LuaGuiElement --- @param apply_button LuaGuiElement
@@ -207,7 +209,7 @@ Elements.bonus_table_label = Gui.define("player_bonus/table_label")
} }
:style{ :style{
width = Gui.from_argument(3, 70), width = Gui.from_argument(3, 70),
} --[[ @as any ]] } --[[@as any]]
--- @class ExpGui_PlayerBonus.elements.bonus_slider.elements --- @class ExpGui_PlayerBonus.elements.bonus_slider.elements
--- @field bonus_used LuaGuiElement --- @field bonus_used LuaGuiElement
@@ -265,7 +267,7 @@ Elements.bonus_slider = Gui.define("player_bonus/bonus_slider")
element_data.label.caption = Elements.bonus_slider.calculate_slider_caption(bonus_data, value) element_data.label.caption = Elements.bonus_slider.calculate_slider_caption(bonus_data, value)
element_data.apply_button.enabled = Elements.bonus_used.update(element_data.bonus_used, value_change * bonus_data._cost_scale) element_data.apply_button.enabled = Elements.bonus_used.update(element_data.bonus_used, value_change * bonus_data._cost_scale)
element_data.reset_button.enabled = true element_data.reset_button.enabled = true
end) --[[ @as any ]] end) --[[@as any]]
--- Get the caption of the slider label --- Get the caption of the slider label
--- @param bonus_data ExpGui_PlayerBonus.bonus_data --- @param bonus_data ExpGui_PlayerBonus.bonus_data
@@ -311,7 +313,7 @@ Elements.bonus_table = Gui.define("player_bonus/bonus_table")
:draw(function(_, parent) :draw(function(_, parent)
return Gui.elements.scroll_table(parent, 300, 3) return Gui.elements.scroll_table(parent, 300, 3)
end) end)
:element_data{} --[[ @as any ]] :element_data{} --[[@as any]]
--- Adds a row to the milestone table --- Adds a row to the milestone table
--- @param bonus_table LuaGuiElement --- @param bonus_table LuaGuiElement
@@ -378,7 +380,7 @@ Elements.container = Gui.define("player_bonus/container")
Elements.bonus_used.refresh(elements.bonus_used, bonus_cost) Elements.bonus_used.refresh(elements.bonus_used, bonus_cost)
return Gui.elements.container.get_root_element(container) return Gui.elements.container.get_root_element(container)
end) --[[ @as any ]] end) --[[@as any]]
--- Set the bonus value for a player --- Set the bonus value for a player
--- @param player LuaPlayer --- @param player LuaPlayer
@@ -442,7 +444,7 @@ end
function Elements.container.calculate_cost(player) function Elements.container.calculate_cost(player)
local cost = 0 local cost = 0
local player_data = Elements.container.data[player] local player_data = Elements.container.data[player]
for _, bonus_data in pairs(config.player_bonus) do for _, bonus_data in pairs(player_bonus) do
cost = cost + (player_data[bonus_data.name] or 0) * bonus_data._cost_scale cost = cost + (player_data[bonus_data.name] or 0) * bonus_data._cost_scale
end end
return cost return cost
+11 -11
View File
@@ -48,14 +48,14 @@ Elements.open_action_bar = Gui.define("player_list/open_action_bar")
--- @cast def ExpGui_PlayerList.elements.open_action_bar --- @cast def ExpGui_PlayerList.elements.open_action_bar
Elements.container.toggle_selected_player(player, def.data[element]) Elements.container.toggle_selected_player(player, def.data[element])
Elements.player_table.refresh_player(player) Elements.player_table.refresh_player(player)
end) --[[ @as any ]] end) --[[@as any]]
--- Set whether an open action bar button shows as highlighted --- Set whether an open action bar button shows as highlighted
--- @param open_button LuaGuiElement --- @param open_button LuaGuiElement
--- @param highlighted boolean --- @param highlighted boolean
function Elements.open_action_bar.set_highlight(open_button, highlighted) function Elements.open_action_bar.set_highlight(open_button, highlighted)
open_button.style = highlighted and "tool_button" or "frame_button" open_button.style = highlighted and "tool_button" or "frame_button"
local style = open_button.style local style = open_button.style --[[@as LuaStyle]]
style.padding = -2 style.padding = -2
style.width = 8 style.width = 8
style.height = 14 style.height = 14
@@ -80,7 +80,7 @@ Elements.close_action_bar = Gui.define("player_list/close_action_bar")
:on_click(function(_, player) :on_click(function(_, player)
Elements.container.set_selected_player(player, nil) Elements.container.set_selected_player(player, nil)
Elements.player_table.refresh_player(player) Elements.player_table.refresh_player(player)
end) --[[ @as any ]] end) --[[@as any]]
--- Button used to confirm a reason --- Button used to confirm a reason
--- @class ExpGui_PlayerList.elements.reason_confirm: ExpElement --- @class ExpGui_PlayerList.elements.reason_confirm: ExpElement
@@ -102,14 +102,14 @@ Elements.reason_confirm = Gui.define("player_list/reason_confirm")
local action_name = Elements.container.get_selected_action(player) local action_name = Elements.container.get_selected_action(player)
local button_data = action_name and config.buttons[action_name] local button_data = action_name and config.buttons[action_name]
if button_data and button_data.reason_callback then if button_data and button_data.reason_callback then
local reason = element.parent.entry.text local reason = assert(element.parent).entry.text --[[@as string?]]
if reason == nil or not reason:find("%S") then reason = "no reason given" end if reason == nil or not reason:find("%S") then reason = "no reason given" end
button_data.reason_callback(player, reason) button_data.reason_callback(player, reason)
end end
element.parent.entry.text = "" assert(element.parent).entry.text = ""
Elements.container.set_selected_player(player, nil) Elements.container.set_selected_player(player, nil)
Elements.player_table.refresh_player(player) Elements.player_table.refresh_player(player)
end) --[[ @as any ]] end) --[[@as any]]
--- Clickable player name label, left click opens the map and right click toggles the action bar --- Clickable player name label, left click opens the map and right click toggles the action bar
--- @class ExpGui_PlayerList.elements.player_name_label: ExpElement --- @class ExpGui_PlayerList.elements.player_name_label: ExpElement
@@ -142,7 +142,7 @@ Elements.player_name_label = Gui.define("player_list/player_name_label")
Elements.container.toggle_selected_player(player, selected_player) Elements.container.toggle_selected_player(player, selected_player)
Elements.player_table.refresh_player(player) Elements.player_table.refresh_player(player)
end end
end) --[[ @as any ]] end) --[[@as any]]
--- @class ExpGui_PlayerList.elements.player_table.row --- @class ExpGui_PlayerList.elements.player_table.row
--- @field open_button LuaGuiElement --- @field open_button LuaGuiElement
@@ -165,7 +165,7 @@ Elements.player_table = Gui.define("player_list/player_table")
end) end)
:style{ :style{
padding = { 1, 0, 1, 2 }, padding = { 1, 0, 1, 2 },
} --[[ @as any ]] } --[[@as any]]
--- Store the action and reason bars associated with a player table --- Store the action and reason bars associated with a player table
--- @param player_table LuaGuiElement --- @param player_table LuaGuiElement
@@ -342,7 +342,7 @@ Elements.action_bar = Gui.define("player_list/action_bar")
:style{ :style{
height = 35, height = 35,
padding = { 1, 3 }, padding = { 1, 3 },
} --[[ @as any ]] } --[[@as any]]
--- Update the action bar buttons to match the selection for a player, hidden when nothing is selected --- Update the action bar buttons to match the selection for a player, hidden when nothing is selected
--- @param action_bar LuaGuiElement --- @param action_bar LuaGuiElement
@@ -390,7 +390,7 @@ Elements.reason_bar = Gui.define("player_list/reason_bar")
:style{ :style{
height = 35, height = 35,
padding = { -1, 3 }, padding = { -1, 3 },
} --[[ @as any ]] } --[[@as any]]
--- Update the reason bar visibility to match the selection, shown only while an action awaits a reason --- Update the reason bar visibility to match the selection, shown only while an action awaits a reason
--- @param reason_bar LuaGuiElement --- @param reason_bar LuaGuiElement
@@ -420,7 +420,7 @@ Elements.container = Gui.define("player_list/container")
Elements.player_table.rebuild(player_table, row_data) Elements.player_table.rebuild(player_table, row_data)
return Gui.elements.container.get_root_element(container) return Gui.elements.container.get_root_element(container)
end) --[[ @as any ]] end) --[[@as any]]
--- Get or create the selection state for a player --- Get or create the selection state for a player
--- @param player LuaPlayer --- @param player LuaPlayer
+3 -3
View File
@@ -93,7 +93,7 @@ Elements.table_label = Gui.define("player_stats/table_label")
} }
:style{ :style{
width = Gui.from_argument("width"), width = Gui.from_argument("width"),
} --[[ @as any ]] } --[[@as any]]
--- Data table that shows all data for a player --- Data table that shows all data for a player
--- @class ExpGui_PlayerStats.elements.player_stats_table: ExpElement --- @class ExpGui_PlayerStats.elements.player_stats_table: ExpElement
@@ -139,7 +139,7 @@ Elements.player_stats_table = Gui.define("player_stats/data_table")
def.data[data_table] = labels def.data[data_table] = labels
return data_table return data_table
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh a data table with the most recent stats for a player --- Refresh a data table with the most recent stats for a player
--- @param data_table LuaGuiElement --- @param data_table LuaGuiElement
@@ -185,7 +185,7 @@ Elements.player_dropdown = Gui.define("player_stats/player_dropdown")
local data_table = def.data[element] local data_table = def.data[element]
local target_player = ElementsExtra.online_player_dropdown.get_selected(element) local target_player = ElementsExtra.online_player_dropdown.get_selected(element)
Elements.player_stats_table.refresh(data_table, target_player) Elements.player_stats_table.refresh(data_table, target_player)
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh all stats tables associated with a player dropdown --- Refresh all stats tables associated with a player dropdown
function Elements.player_dropdown.refresh_online() function Elements.player_dropdown.refresh_online()
+9 -8
View File
@@ -9,6 +9,7 @@ local Roles = require("modules/exp_legacy/expcore/roles")
local Elements = {} local Elements = {}
--- The flow precision values in the same order as production_precision_dropdown.items --- The flow precision values in the same order as production_precision_dropdown.items
--- @type defines.flow_precision_index[]
local precision_indexes = { local precision_indexes = {
defines.flow_precision_index.five_seconds, defines.flow_precision_index.five_seconds,
defines.flow_precision_index.one_minute, defines.flow_precision_index.one_minute,
@@ -94,7 +95,7 @@ Elements.item_selector = Gui.define("production_stats/item_selector")
element_data.on_last_row = false element_data.on_last_row = false
Elements.production_table.add_row(element_data.production_table) Elements.production_table.add_row(element_data.production_table)
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Label used for every element in the production table --- Label used for every element in the production table
Elements.table_label = Gui.define("production_stats/table_label") Elements.table_label = Gui.define("production_stats/table_label")
@@ -129,7 +130,7 @@ Elements.production_table = Gui.define("production_stats/production_table")
:track_all_elements() :track_all_elements()
:draw(function(def, parent) :draw(function(def, parent)
local scroll_table = Gui.elements.scroll_table(parent, 304, 4) local scroll_table = Gui.elements.scroll_table(parent, 304, 4)
local display_alignments = scroll_table.style.column_alignments local display_alignments = assert(scroll_table.style.column_alignments)
for i = 2, 4 do for i = 2, 4 do
display_alignments[i] = "right" display_alignments[i] = "right"
end end
@@ -144,7 +145,7 @@ Elements.production_table = Gui.define("production_stats/production_table")
Elements.table_label(scroll_table, { "exp-gui_production-stats.caption-net" }, { "exp-gui_production-stats.tooltip-per-second" }, "heading_2_label") Elements.table_label(scroll_table, { "exp-gui_production-stats.caption-net" }, { "exp-gui_production-stats.tooltip-per-second" }, "heading_2_label")
return scroll_table return scroll_table
end) --[[ @as any ]] end) --[[@as any]]
--- Calculate the row data for a production table --- Calculate the row data for a production table
--- @param force LuaForce --- @param force LuaForce
@@ -183,7 +184,7 @@ end
--- @param item_selector LuaGuiElement --- @param item_selector LuaGuiElement
function Elements.production_table.remove_row(production_table, item_selector) function Elements.production_table.remove_row(production_table, item_selector)
local rows = Elements.production_table.data[production_table].rows local rows = Elements.production_table.data[production_table].rows
local row = rows[item_selector.index] local row = assert(rows[item_selector.index])
rows[item_selector.index] = nil rows[item_selector.index] = nil
Gui.destroy_if_valid(item_selector) Gui.destroy_if_valid(item_selector)
for _, element in pairs(row) do for _, element in pairs(row) do
@@ -196,7 +197,7 @@ end
--- @param item_selector LuaGuiElement --- @param item_selector LuaGuiElement
function Elements.production_table.reset_row(production_table, item_selector) function Elements.production_table.reset_row(production_table, item_selector)
local rows = Elements.production_table.data[production_table].rows local rows = Elements.production_table.data[production_table].rows
local row = rows[item_selector.index] local row = assert(rows[item_selector.index])
row.production.caption = "0.00" row.production.caption = "0.00"
row.consumption.caption = "0.00" row.consumption.caption = "0.00"
row.net.caption = "0.00" row.net.caption = "0.00"
@@ -209,7 +210,7 @@ end
--- @param row_data ExpGui_ProductionStats.elements.production_table.row_data --- @param row_data ExpGui_ProductionStats.elements.production_table.row_data
function Elements.production_table.refresh_row(production_table, item_selector, row_data) function Elements.production_table.refresh_row(production_table, item_selector, row_data)
local rows = Elements.production_table.data[production_table].rows local rows = Elements.production_table.data[production_table].rows
local row = rows[item_selector.index] local row = assert(rows[item_selector.index])
row.production.caption = row_data.production row.production.caption = row_data.production
row.consumption.caption = row_data.consumption row.consumption.caption = row_data.consumption
row.net.caption = row_data.net row.net.caption = row_data.net
@@ -223,9 +224,9 @@ function Elements.production_table.refresh_online()
local precision_index = precision_indexes[element_data.precision_dropdown.selected_index] local precision_index = precision_indexes[element_data.precision_dropdown.selected_index]
for _, row in pairs(element_data.rows) do for _, row in pairs(element_data.rows) do
local item_selector = row.item_selector local item_selector = row.item_selector
local item_name = item_selector.elem_value --[[ @as string? ]] local item_name = item_selector.elem_value --[[@as string?]]
if item_name then if item_name then
local row_data = Elements.production_table.calculate_row_data(player.force --[[ @as LuaForce ]], player.surface, item_name, precision_index) local row_data = Elements.production_table.calculate_row_data(player.force --[[@as LuaForce]], player.surface, item_name, precision_index)
Elements.production_table.refresh_row(production_table, item_selector, row_data) Elements.production_table.refresh_row(production_table, item_selector, row_data)
end end
end end
+2 -2
View File
@@ -43,13 +43,13 @@ local function new_quick_action(command, on_click)
:style{ :style{
width = 160, width = 160,
} }
:on_click(on_click or function(def, player, element, event) :on_click(on_click or function(_def, player, _element, _event)
command(player) command(player)
end) end)
Elements[command_name] = element Elements[command_name] = element
Actions[command_name] = { Actions[command_name] = {
command = command --[[ @as ExpCommand ]], command = command --[[@as ExpCommand]],
element = element, element = element,
} }
end end
+20 -17
View File
@@ -47,7 +47,7 @@ Elements.title_table = Gui.define("readme/title_table")
cell_padding = 0, cell_padding = 0,
vertical_align = "center", vertical_align = "center",
horizontally_stretchable = true, horizontally_stretchable = true,
} --[[ @as any ]] } --[[@as any]]
--- Scroll pane used for title tables --- Scroll pane used for title tables
--- @class ExpGui_Readme.elements.title_table_scroll: ExpElement --- @class ExpGui_Readme.elements.title_table_scroll: ExpElement
@@ -64,7 +64,7 @@ Elements.title_table_scroll = Gui.define("readme/title_table_scroll")
padding = { 1, 3 }, padding = { 1, 3 },
maximal_height = scroll_height, maximal_height = scroll_height,
horizontally_stretchable = true, horizontally_stretchable = true,
} --[[ @as any ]] } --[[@as any]]
--- Sub content frame --- Sub content frame
--- @class ExpGui_Readme.elements.sub_content: ExpElement --- @class ExpGui_Readme.elements.sub_content: ExpElement
@@ -80,7 +80,7 @@ Elements.sub_content = Gui.define("readme/sub_content")
horizontal_align = "center", horizontal_align = "center",
padding = { 2, 2 }, padding = { 2, 2 },
top_margin = 2, top_margin = 2,
} --[[ @as any ]] } --[[@as any]]
--- @class ExpGui_Readme.elements.join_server.elements --- @class ExpGui_Readme.elements.join_server.elements
--- @field server_id string --- @field server_id string
@@ -119,7 +119,7 @@ Elements.join_server = Gui.define("readme/join_server")
--- @cast def ExpGui_Readme.elements.join_server --- @cast def ExpGui_Readme.elements.join_server
local server_id = def.data[button].server_id local server_id = def.data[button].server_id
External.request_connection(player, server_id, true) External.request_connection(player, server_id, true)
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh join server button --- Refresh join server button
--- @param button LuaGuiElement --- @param button LuaGuiElement
@@ -244,7 +244,7 @@ define_tab(
) )
return container return container
end) --[[ @as any ]] end) --[[@as any]]
) )
--- Rules tab --- Rules tab
@@ -261,14 +261,15 @@ define_tab(
local rules = Gui.elements.scroll_table(container, scroll_height, 1) local rules = Gui.elements.scroll_table(container, scroll_height, 1)
rules.style = "bordered_table" rules.style = "bordered_table"
rules.style.cell_padding = 4 local rules_style = rules.style --[[@as LuaStyle]]
rules_style.cell_padding = 4
for i = 1, 15 do for i = 1, 15 do
Gui.elements.centered_label(rules, frame_width - 30, { "exp-gui_readme.rules-" .. i }) Gui.elements.centered_label(rules, frame_width - 30, { "exp-gui_readme.rules-" .. i })
end end
return container return container
end) --[[ @as any ]] end) --[[@as any]]
) )
--- Commands tab --- Commands tab
@@ -287,7 +288,8 @@ define_tab(
local commands = Gui.elements.scroll_table(container, scroll_height, 2) local commands = Gui.elements.scroll_table(container, scroll_height, 2)
commands.style = "bordered_table" commands.style = "bordered_table"
commands.style.cell_padding = 0 local commands_style = commands.style --[[@as LuaStyle]]
commands_style.cell_padding = 0
for name, command in pairs(Commands.list_for_player(player)) do for name, command in pairs(Commands.list_for_player(player)) do
Gui.elements.centered_label(commands, 120, name) Gui.elements.centered_label(commands, 120, name)
@@ -295,7 +297,7 @@ define_tab(
end end
return container return container
end) --[[ @as any ]] end) --[[@as any]]
) )
--- Servers tab --- Servers tab
@@ -338,7 +340,7 @@ define_tab(
end end
return container return container
end) --[[ @as any ]] end) --[[@as any]]
) )
--- Backers tab --- Backers tab
@@ -359,32 +361,32 @@ define_tab(
roles = { "Senior Administrator", "Administrator" }, roles = { "Senior Administrator", "Administrator" },
title = { "exp-gui_readme.backers-management" }, title = { "exp-gui_readme.backers-management" },
width = 230, width = 230,
players = {}, players = {}, --- @type string[]
}, },
{ {
roles = { "Board Member", "Senior Backer" }, roles = { "Board Member", "Senior Backer" },
title = { "exp-gui_readme.backers-board" }, title = { "exp-gui_readme.backers-board" },
width = 145, width = 145,
players = {}, players = {}, --- @type string[]
}, },
{ {
roles = { "Sponsor", "Supporter" }, roles = { "Sponsor", "Supporter" },
title = { "exp-gui_readme.backers-backers" }, title = { "exp-gui_readme.backers-backers" },
width = 196, width = 196,
players = {}, players = {}, --- @type string[]
}, },
{ {
roles = { "Moderator", "Trainee" }, roles = { "Moderator", "Trainee" },
title = { "exp-gui_readme.backers-staff" }, title = { "exp-gui_readme.backers-staff" },
width = 235, width = 235,
players = {}, players = {}, --- @type string[]
}, },
{ {
roles = {}, roles = {},
time = 3 * 3600 * 60, time = 3 * 3600 * 60,
title = { "exp-gui_readme.backers-active" }, title = { "exp-gui_readme.backers-active" },
width = 235, width = 235,
players = {}, players = {}, --- @type string[]
}, },
} }
@@ -433,7 +435,7 @@ define_tab(
end end
return container return container
end) --[[ @as any ]] end) --[[@as any]]
) )
--- @class (exact) ExpGui_Readme.elements.readme_data.param table --- @class (exact) ExpGui_Readme.elements.readme_data.param table
@@ -599,7 +601,7 @@ define_tab(
end end
return container return container
end) --[[ @as any ]] end) --[[@as any]]
) )
--- @class ExpGui_Readme.elements.container.elements --- @class ExpGui_Readme.elements.container.elements
@@ -608,6 +610,7 @@ define_tab(
--- Main readme container --- Main readme container
--- @class ExpGui_Readme.elements.container: ExpElement --- @class ExpGui_Readme.elements.container: ExpElement
--- @field data table<LuaGuiElement, ExpGui_Readme.elements.container.elements> --- @field data table<LuaGuiElement, ExpGui_Readme.elements.container.elements>
--- @overload fun(parent: LuaGuiElement): LuaGuiElement
Elements.container = Gui.define("readme/container") Elements.container = Gui.define("readme/container")
:track_all_elements() :track_all_elements()
:draw(function(def, parent) :draw(function(def, parent)
@@ -72,7 +72,7 @@ Elements.clock_label = Gui.define("research_milestones/clock_label")
type = "label", type = "label",
caption = research_time_format_nil, caption = research_time_format_nil,
style = "heading_2_label", style = "heading_2_label",
} --[[ @as any ]] } --[[@as any]]
--- Update the clock label for all online players --- Update the clock label for all online players
function Elements.clock_label.refresh_online() function Elements.clock_label.refresh_online()
@@ -95,7 +95,7 @@ Elements.milestone_table_label = Gui.define("research_milestones/table_label")
minimal_width = Gui.from_argument(2, 70), minimal_width = Gui.from_argument(2, 70),
horizontal_align = Gui.from_argument(3, "right"), horizontal_align = Gui.from_argument(3, "right"),
font_color = font_color.neutral, font_color = font_color.neutral,
} --[[ @as any ]] } --[[@as any]]
--- @class ExpGui_ResearchMilestones.elements.milestone_table.row_elements --- @class ExpGui_ResearchMilestones.elements.milestone_table.row_elements
--- @field name LuaGuiElement --- @field name LuaGuiElement
@@ -124,10 +124,11 @@ Elements.milestone_table = Gui.define("research_milestones/milestone_table")
Elements.milestone_table_label(milestone_table, { "exp-gui_research-milestones.caption-difference" }) Elements.milestone_table_label(milestone_table, { "exp-gui_research-milestones.caption-difference" })
return milestone_table return milestone_table
end) end)
:element_data{} --[[ @as any ]] :element_data{} --[[@as any]]
do local _row_data = {} do local _row_data = {}
--- @type ExpGui_ResearchMilestones.elements.milestone_table.row_data --- @type ExpGui_ResearchMilestones.elements.milestone_table.row_data
--- @diagnostic disable-next-line: missing-fields
local empty_row_data = { color = font_color.positive } local empty_row_data = { color = font_color.positive }
--- Get the row data for a force and research --- Get the row data for a force and research
@@ -203,7 +204,7 @@ end
--- @param row_index number --- @param row_index number
--- @param row_data ExpGui_ResearchMilestones.elements.milestone_table.row_data --- @param row_data ExpGui_ResearchMilestones.elements.milestone_table.row_data
function Elements.milestone_table.refresh_row(milestone_table, row_index, row_data) function Elements.milestone_table.refresh_row(milestone_table, row_index, row_data)
local row = Elements.milestone_table.data[milestone_table][row_index] local row = assert(Elements.milestone_table.data[milestone_table][row_index])
row.name.caption = row_data.name row.name.caption = row_data.name
row.target.caption = row_data.target row.target.caption = row_data.target
row.achieved.caption = row_data.achieved row.achieved.caption = row_data.achieved
@@ -224,7 +225,7 @@ end
--- Refresh all the labels on the table --- Refresh all the labels on the table
--- @param milestone_table LuaGuiElement --- @param milestone_table LuaGuiElement
function Elements.milestone_table.refresh(milestone_table) function Elements.milestone_table.refresh(milestone_table)
local force = Gui.get_player(milestone_table).force --[[ @as LuaForce ]] local force = Gui.get_player(milestone_table).force --[[@as LuaForce]]
local start_index = Elements.container.calculate_starting_research_index(force) local start_index = Elements.container.calculate_starting_research_index(force)
for row_index = 1, display_size do for row_index = 1, display_size do
local row_data = Elements.milestone_table.calculate_row_data(force, start_index + row_index - 1) local row_data = Elements.milestone_table.calculate_row_data(force, start_index + row_index - 1)
@@ -234,7 +235,7 @@ end
--- Refresh all tables for a player --- Refresh all tables for a player
function Elements.milestone_table.refresh_player(player) function Elements.milestone_table.refresh_player(player)
local force = player.force --[[ @as LuaForce ]] local force = player.force --[[@as LuaForce]]
local start_index = Elements.container.calculate_starting_research_index(force) local start_index = Elements.container.calculate_starting_research_index(force)
for _, milestone_table in Elements.milestone_table:online_elements(player) do for _, milestone_table in Elements.milestone_table:online_elements(player) do
for row_index = 1, display_size do for row_index = 1, display_size do
@@ -269,10 +270,9 @@ Elements.container = Gui.define("research_milestones/container")
local milestone_table = Elements.milestone_table(container) local milestone_table = Elements.milestone_table(container)
Elements.clock_label(header) Elements.clock_label(header)
local force = Gui.get_player(parent).force local force = Gui.get_player(parent).force --[[@as LuaForce]]
def.data[force] = def.data[force] or {} -- used by start index and row data def.data[force] = def.data[force] or {} -- used by start index and row data
local force = Gui.get_player(parent).force --[[ @as LuaForce ]]
local start_index = Elements.container.calculate_starting_research_index(force) local start_index = Elements.container.calculate_starting_research_index(force)
for research_index = start_index, start_index + display_size - 1 do for research_index = start_index, start_index + display_size - 1 do
local row_data = Elements.milestone_table.calculate_row_data(force, research_index) local row_data = Elements.milestone_table.calculate_row_data(force, research_index)
@@ -296,7 +296,7 @@ end
--- @param research_index number --- @param research_index number
--- @return number --- @return number
function Elements.container.get_achieved_time(force, research_index) function Elements.container.get_achieved_time(force, research_index)
return Elements.container.data[force][research_index] return assert(Elements.container.data[force][research_index])
end end
--- Calculate the starting research index for a force --- Calculate the starting research index for a force
+27 -22
View File
@@ -90,7 +90,7 @@ Elements.toggle_section_button = Gui.define("rocket_info/toggle_section_button")
element.sprite = "utility/expand" element.sprite = "utility/expand"
element.tooltip = { "exp-gui_rocket-info.tooltip-toggle-section-expand" } element.tooltip = { "exp-gui_rocket-info.tooltip-toggle-section-expand" }
end end
end) --[[ @as any ]] end) --[[@as any]]
--- A clickable coordinate label which opens the silo location on the map when pressed --- A clickable coordinate label which opens the silo location on the map when pressed
--- @class ExpGui_RocketInfo.elements.position_label: ExpElement --- @class ExpGui_RocketInfo.elements.position_label: ExpElement
@@ -114,7 +114,7 @@ Elements.position_label = Gui.define("rocket_info/position_label")
local entity = def.data[element] local entity = def.data[element]
if not entity or not entity.valid then return end if not entity or not entity.valid then return end
player.set_controller{ type = defines.controllers.remote, position = entity.position, surface = entity.surface } player.set_controller{ type = defines.controllers.remote, position = entity.position, surface = entity.surface }
end) --[[ @as any ]] end) --[[@as any]]
--- Data table showing the launch statistics for a force --- Data table showing the launch statistics for a force
--- @class ExpGui_RocketInfo.elements.stats_table: ExpElement --- @class ExpGui_RocketInfo.elements.stats_table: ExpElement
@@ -125,7 +125,7 @@ Elements.stats_table = Gui.define("rocket_info/stats_table")
:element_data{} :element_data{}
:draw(function(def, parent) :draw(function(def, parent)
return Gui.elements.scroll_table(parent, 215, 2) return Gui.elements.scroll_table(parent, 215, 2)
end) --[[ @as any ]] end) --[[@as any]]
--- @class ExpGui_RocketInfo.elements.stats_table.row_data --- @class ExpGui_RocketInfo.elements.stats_table.row_data
--- @field key string Unique key used to look up the value label --- @field key string Unique key used to look up the value label
@@ -218,7 +218,7 @@ end
--- Refresh the stats table for a player, adding any rows that do not yet exist --- Refresh the stats table for a player, adding any rows that do not yet exist
--- @param player LuaPlayer --- @param player LuaPlayer
function Elements.stats_table.refresh_player(player) function Elements.stats_table.refresh_player(player)
local force = player.force --[[ @as LuaForce ]] local force = player.force --[[@as LuaForce]]
local row_data = Elements.stats_table.calculate_row_data(force) local row_data = Elements.stats_table.calculate_row_data(force)
for _, stats_table in Elements.stats_table:online_elements(player) do for _, stats_table in Elements.stats_table:online_elements(player) do
Elements.stats_table.refresh(stats_table, row_data) Elements.stats_table.refresh(stats_table, row_data)
@@ -243,7 +243,7 @@ Elements.milestones_table = Gui.define("rocket_info/milestones_table")
:element_data{} :element_data{}
:draw(function(def, parent) :draw(function(def, parent)
return Gui.elements.scroll_table(parent, 215, 2) return Gui.elements.scroll_table(parent, 215, 2)
end) --[[ @as any ]] end) --[[@as any]]
--- @class ExpGui_RocketInfo.elements.milestones_table.row_data --- @class ExpGui_RocketInfo.elements.milestones_table.row_data
--- @field milestone number The milestone this row represents --- @field milestone number The milestone this row represents
@@ -315,7 +315,7 @@ end
--- Refresh the milestones table for a player, adding rows as new milestones become visible --- Refresh the milestones table for a player, adding rows as new milestones become visible
--- @param player LuaPlayer --- @param player LuaPlayer
function Elements.milestones_table.refresh_player(player) function Elements.milestones_table.refresh_player(player)
local force = player.force --[[ @as LuaForce ]] local force = player.force --[[@as LuaForce]]
local row_data = Elements.stats_table.calculate_row_data(force) local row_data = Elements.stats_table.calculate_row_data(force)
for _, stats_table in Elements.stats_table:online_elements(player) do for _, stats_table in Elements.stats_table:online_elements(player) do
Elements.stats_table.refresh(stats_table, row_data) Elements.stats_table.refresh(stats_table, row_data)
@@ -359,7 +359,7 @@ Elements.progress_table = Gui.define("rocket_info/progress_table")
def.data[progress_table] = { rows = {}, no_silos = no_silos } def.data[progress_table] = { rows = {}, no_silos = no_silos }
return progress_table return progress_table
end) --[[ @as any ]] end) --[[@as any]]
--- @class ExpGui_RocketInfo.elements.progress_table.row_data --- @class ExpGui_RocketInfo.elements.progress_table.row_data
--- @field entity LuaEntity --- @field entity LuaEntity
@@ -404,9 +404,9 @@ end
--- @return ExpGui_RocketInfo.elements.progress_table.row_data[] --- @return ExpGui_RocketInfo.elements.progress_table.row_data[]
function Elements.progress_table.calculate_row_data_all(silo_data) function Elements.progress_table.calculate_row_data_all(silo_data)
local row_data = {} local row_data = {}
for unit_number, silo_data in pairs(silo_data) do for unit_number, silo in pairs(silo_data) do
if silo_data.entity.valid then if silo.entity.valid then
row_data[unit_number] = Elements.progress_table.calculate_row_data(silo_data) row_data[unit_number] = Elements.progress_table.calculate_row_data(silo)
else else
-- Prune silos that are no longer valid -- Prune silos that are no longer valid
silo_data[unit_number] = nil silo_data[unit_number] = nil
@@ -433,7 +433,8 @@ function Elements.progress_table.add_row(progress_table, row_data)
progress.style.padding = { 0, 2 } progress.style.padding = { 0, 2 }
progress.style.font_color = row_data.color progress.style.font_color = row_data.color
rows[row_data.entity.unit_number] = { x = x, y = y, progress = progress } local unit_number = row_data.entity.unit_number --[[@as uint]]
rows[unit_number] = { x = x, y = y, progress = progress }
end end
--- Remove a silo row from the progress table --- Remove a silo row from the progress table
@@ -455,7 +456,8 @@ end
--- @param row_data ExpGui_RocketInfo.elements.progress_table.row_data --- @param row_data ExpGui_RocketInfo.elements.progress_table.row_data
function Elements.progress_table.refresh_row(progress_table, row_data) function Elements.progress_table.refresh_row(progress_table, row_data)
local element_data = Elements.progress_table.data[progress_table] local element_data = Elements.progress_table.data[progress_table]
local row = element_data.rows[row_data.entity.unit_number] local unit_number = row_data.entity.unit_number --[[@as uint]]
local row = element_data.rows[unit_number]
row.x.caption = row_data.x row.x.caption = row_data.x
row.y.caption = row_data.y row.y.caption = row_data.y
row.progress.caption = row_data.caption row.progress.caption = row_data.caption
@@ -496,7 +498,7 @@ end
--- Refresh the progress table for a player, reconciling rows with the current set of silos --- Refresh the progress table for a player, reconciling rows with the current set of silos
--- @param player LuaPlayer --- @param player LuaPlayer
function Elements.progress_table.refresh_player(player) function Elements.progress_table.refresh_player(player)
local force = player.force --[[ @as LuaForce ]] local force = player.force --[[@as LuaForce]]
local silos = Elements.container.get_silos(force) local silos = Elements.container.get_silos(force)
local row_data = Elements.progress_table.calculate_row_data_all(silos) local row_data = Elements.progress_table.calculate_row_data_all(silos)
for _, progress_table in Elements.progress_table:online_elements(player) do for _, progress_table in Elements.progress_table:online_elements(player) do
@@ -539,7 +541,7 @@ Elements.container = Gui.define("rocket_info/container")
container.style.padding = 0 container.style.padding = 0
local player = Gui.get_player(parent) local player = Gui.get_player(parent)
local force = player.force --[[ @as LuaForce ]] local force = player.force --[[@as LuaForce]]
local force_data = def._get_force_data(force) local force_data = def._get_force_data(force)
if config.stats.show_stats then if config.stats.show_stats then
@@ -618,9 +620,10 @@ end
--- Add a silo to the list of current silos for a force --- Add a silo to the list of current silos for a force
--- @param entity LuaEntity --- @param entity LuaEntity
function Elements.container.add_silo(entity) function Elements.container.add_silo(entity)
local force = entity.force --[[ @as LuaForce ]] local force = entity.force --[[@as LuaForce]]
local silos = Elements.container._get_force_data(force).silos local silos = Elements.container._get_force_data(force).silos
silos[entity.unit_number] = { local unit_number = entity.unit_number --[[@as uint]]
silos[unit_number] = {
entity = entity, entity = entity,
launched = 0, launched = 0,
awaiting_reset = false, awaiting_reset = false,
@@ -630,9 +633,11 @@ end
--- Increment the launch count for a silo --- Increment the launch count for a silo
--- @param entity LuaEntity --- @param entity LuaEntity
function Elements.container.increment_silo(entity) function Elements.container.increment_silo(entity)
local force = entity.force --[[ @as LuaForce ]] local force = entity.force --[[@as LuaForce]]
local silos = Elements.container._get_force_data(force).silos local silos = Elements.container._get_force_data(force).silos
local silo_data = silos[entity.unit_number] local unit_number = entity.unit_number
--- @cast unit_number uint
local silo_data = silos[unit_number]
if not silo_data then return end if not silo_data then return end
silo_data.launched = silo_data.launched + 1 silo_data.launched = silo_data.launched + 1
silo_data.awaiting_reset = true silo_data.awaiting_reset = true
@@ -653,8 +658,8 @@ Gui.toolbar.create_button{
--- Record the launch and update the stats when a cargo pod finishes ascending --- Record the launch and update the stats when a cargo pod finishes ascending
--- @param event EventData.on_cargo_pod_finished_ascending --- @param event EventData.on_cargo_pod_finished_ascending
local function on_cargo_pod_finished_ascending(event) local function on_cargo_pod_finished_ascending(event)
local force = event.cargo_pod.force --[[ @as LuaForce ]] local force = event.cargo_pod.force --[[@as LuaForce]]
local rockets_launched = force.rockets_launched local rockets_launched = force.rockets_launched --[[@as number]]
-- Update the launch stats for the force -- Update the launch stats for the force
local stats = Elements.container.get_stats(force) local stats = Elements.container.get_stats(force)
@@ -686,7 +691,7 @@ end
--- @param event EventData.on_rocket_launch_ordered --- @param event EventData.on_rocket_launch_ordered
local function on_rocket_launch_ordered(event) local function on_rocket_launch_ordered(event)
Elements.container.increment_silo(event.rocket_silo) Elements.container.increment_silo(event.rocket_silo)
Elements.progress_table.refresh_force(event.rocket_silo.force --[[ @as LuaForce ]]) Elements.progress_table.refresh_force(event.rocket_silo.force --[[@as LuaForce]])
end end
--- Refresh the gui when a player joins the game as it may be outdated --- Refresh the gui when a player joins the game as it may be outdated
@@ -704,7 +709,7 @@ local function on_built(event)
local entity = event.entity local entity = event.entity
if not entity.valid or entity.name ~= "rocket-silo" then return end if not entity.valid or entity.name ~= "rocket-silo" then return end
Elements.container.add_silo(entity) Elements.container.add_silo(entity)
Elements.progress_table.refresh_force(entity.force --[[ @as LuaForce ]]) Elements.progress_table.refresh_force(entity.force --[[@as LuaForce]])
end end
--- Refresh the progress for all forces that own at least one silo --- Refresh the progress for all forces that own at least one silo
+24 -22
View File
@@ -79,7 +79,7 @@ Elements.production_label = Gui.define("science_production/production_label")
def.data[label] = suffix def.data[label] = suffix
return label return label
end) --[[ @as any ]] end) --[[@as any]]
--- @class Elements.production_label.display_data --- @class Elements.production_label.display_data
--- @field caption LocalisedString --- @field caption LocalisedString
@@ -109,7 +109,7 @@ function Elements.production_label.calculate_display_data(tooltip, value, cutoff
end end
local suffix, caption = format_number(value) local suffix, caption = format_number(value)
display_data = display_data or {} display_data = display_data or {} --[[@as Elements.production_label.display_data]]
display_data.caption = caption display_data.caption = caption
display_data.suffix = suffix display_data.suffix = suffix
display_data.tooltip = tooltip display_data.tooltip = tooltip
@@ -144,12 +144,12 @@ Elements.no_production_label = Gui.define("science_production/no_production_labe
padding = { 2, 4 }, padding = { 2, 4 },
single_line = false, single_line = false,
width = 200, width = 200,
} --[[ @as any ]] } --[[@as any]]
--- Refresh a no production label --- Refresh a no production label
--- @param no_production_label LuaGuiElement --- @param no_production_label LuaGuiElement
function Elements.no_production_label.refresh(no_production_label) function Elements.no_production_label.refresh(no_production_label)
local force = Gui.get_player(no_production_label).force --[[ @as LuaForce ]] local force = Gui.get_player(no_production_label).force --[[@as LuaForce]]
no_production_label.visible = not Elements.container.has_production(force) no_production_label.visible = not Elements.container.has_production(force)
end end
@@ -157,7 +157,7 @@ end
function Elements.no_production_label.refresh_online() function Elements.no_production_label.refresh_online()
local force_data = {} local force_data = {}
for player, no_production_label in Elements.no_production_label:online_elements() do for player, no_production_label in Elements.no_production_label:online_elements() do
local force = player.force --[[ @as LuaForce ]] local force = player.force --[[@as LuaForce]]
local visible = force_data[force.name] local visible = force_data[force.name]
if visible == nil then if visible == nil then
visible = not Elements.container.has_production(force) visible = not Elements.container.has_production(force)
@@ -193,10 +193,11 @@ Elements.science_table = Gui.define("science_production/science_table")
local science_table = Gui.elements.scroll_table(parent, 190, 4) local science_table = Gui.elements.scroll_table(parent, 190, 4)
local no_production_label = Elements.no_production_label(science_table) local no_production_label = Elements.no_production_label(science_table)
Elements.no_production_label.refresh(no_production_label) Elements.no_production_label.refresh(no_production_label)
science_table.style.column_alignments[3] = "right" local science_table_style = science_table.style --[[@as LuaStyle]]
science_table_style.column_alignments[3] = "right"
return science_table return science_table
end) end)
:element_data{} --[[ @as any ]] :element_data{} --[[@as any]]
--- Calculate the data needed to add or refresh a row --- Calculate the data needed to add or refresh a row
--- @param force LuaForce --- @param force LuaForce
@@ -220,7 +221,7 @@ function Elements.science_table.calculate_row_data(force, science_pack, row_data
end end
-- Return the pack data -- Return the pack data
row_data = row_data or {} row_data = row_data or {} --[[@as ExpGui_ScienceProduction.elements.science_table.row_data]]
row_data.visible = production.total.made > 0 row_data.visible = production.total.made > 0
row_data.science_pack = science_pack row_data.science_pack = science_pack
row_data.icon_style = icon_style row_data.icon_style = icon_style
@@ -280,7 +281,8 @@ function Elements.science_table.add_row(science_table, row_data)
column_count = 2, column_count = 2,
} }
delta_table.style.padding = 0 delta_table.style.padding = 0
delta_table.style.column_alignments[1] = "right" local delta_table_style = delta_table.style --[[@as LuaStyle]]
delta_table_style.column_alignments[1] = "right"
-- Draw the net production label -- Draw the net production label
local net = Elements.production_label(science_table, row_data.net) local net = Elements.production_label(science_table, row_data.net)
@@ -312,7 +314,8 @@ function Elements.science_table.refresh_row(science_table, row_data)
-- Update the icon -- Update the icon
local icon = row.icon local icon = row.icon
icon.style = row_data.icon_style icon.style = row_data.icon_style
icon.style.height = 55 local icon_style = icon.style --[[@as LuaStyle]]
icon_style.height = 55
-- Update the element visibility -- Update the element visibility
row.net_suffix.visible = true row.net_suffix.visible = true
@@ -326,8 +329,7 @@ function Elements.science_table.refresh_row(science_table, row_data)
Elements.production_label.refresh(row.used, row_data.used) Elements.production_label.refresh(row.used, row_data.used)
end end
--- @type table<string, { [string]: ExpGui_ScienceProduction.elements.science_table.row_data }> do local _row_data = {} --- @type table<string, table<number, ExpGui_ScienceProduction.elements.science_table.row_data>>
do local _row_data = {}
--- Refresh the production tables for all online players --- Refresh the production tables for all online players
function Elements.science_table.refresh_online() function Elements.science_table.refresh_online()
-- Refresh the row data for online forces -- Refresh the row data for online forces
@@ -361,7 +363,7 @@ Elements.eta_label = Gui.define("science_production/eta_label")
caption = clock_time_format_nil, caption = clock_time_format_nil,
tooltip = long_time_format_nil, tooltip = long_time_format_nil,
style = "frame_title", style = "frame_title",
} --[[ @as any ]] } --[[@as any]]
--- @class Elements.eta_label.display_data --- @class Elements.eta_label.display_data
--- @field caption LocalisedString --- @field caption LocalisedString
@@ -410,14 +412,13 @@ end
--- Refresh an eta label --- Refresh an eta label
--- @param eta_label LuaGuiElement --- @param eta_label LuaGuiElement
function Elements.eta_label.refresh(eta_label) function Elements.eta_label.refresh(eta_label)
local force = Gui.get_player(eta_label).force --[[ @as LuaForce ]] local force = Gui.get_player(eta_label).force --[[@as LuaForce]]
local display_data = Elements.eta_label.calculate_display_data(force) local display_data = Elements.eta_label.calculate_display_data(force)
eta_label.caption = display_data.caption eta_label.caption = display_data.caption
eta_label.tooltip = display_data.tooltip eta_label.tooltip = display_data.tooltip
end end
--- @type Elements.eta_label.display_data do local _display_data = {} --- @type table<string, Elements.eta_label.display_data>
do local _display_data = {}
--- Refresh the eta label for all online players --- Refresh the eta label for all online players
function Elements.eta_label.refresh_online() function Elements.eta_label.refresh_online()
-- Refresh the row data for online forces -- Refresh the row data for online forces
@@ -430,8 +431,10 @@ do local _display_data = {}
-- Update the eta labels -- Update the eta labels
for player, eta_label in Elements.eta_label:online_elements() do for player, eta_label in Elements.eta_label:online_elements() do
local display_data = _display_data[player.force.name] local display_data = _display_data[player.force.name]
eta_label.caption = display_data.caption if display_data then
eta_label.tooltip = display_data.tooltip eta_label.caption = display_data.caption
eta_label.tooltip = display_data.tooltip
end
end end
end end
end end
@@ -443,7 +446,7 @@ Elements.container = Gui.define("science_production/container")
local container = Gui.elements.container(parent) local container = Gui.elements.container(parent)
Gui.elements.header(container, { caption = { "exp-gui_science-production.caption-main" } }) Gui.elements.header(container, { caption = { "exp-gui_science-production.caption-main" } })
local force = Gui.get_player(parent).force --[[ @as LuaForce ]] local force = Gui.get_player(parent).force --[[@as LuaForce]]
local science_table = Elements.science_table(container) local science_table = Elements.science_table(container)
for _, science_pack in ipairs(config) do for _, science_pack in ipairs(config) do
--- @cast science_pack any --- @cast science_pack any
@@ -462,7 +465,7 @@ Elements.container = Gui.define("science_production/container")
end end
return Gui.elements.container.get_root_element(container) return Gui.elements.container.get_root_element(container)
end) --[[ @as any ]] end) --[[@as any]]
--- Cached mostly because they are long names --- Cached mostly because they are long names
local _fp_one_minute = defines.flow_precision_index.one_minute local _fp_one_minute = defines.flow_precision_index.one_minute
@@ -477,8 +480,7 @@ local _fp_one_hour = defines.flow_precision_index.one_hour
--- @field ten_minutes ExpGui_ScienceProduction._item_data --- @field ten_minutes ExpGui_ScienceProduction._item_data
--- @field one_hour ExpGui_ScienceProduction._item_data --- @field one_hour ExpGui_ScienceProduction._item_data
--- @type table<string, { [string]: ExpGui_ScienceProduction.item_production_data }> do local _production_data = {} --- @type table<string, { [string]: ExpGui_ScienceProduction.item_production_data }>
do local _production_data = {}
--- Get the production stats for a force --- Get the production stats for a force
--- @param flow_stats any --- @param flow_stats any
+6 -6
View File
@@ -25,7 +25,7 @@ Elements.player_dropdown = Gui.define("surveillance/player_dropdown")
local camera = def.data[element] local camera = def.data[element]
local target_player = assert(ElementsExtra.online_player_dropdown.get_selected(element)) local target_player = assert(ElementsExtra.online_player_dropdown.get_selected(element))
Elements.camera.set_target_player(camera, target_player) Elements.camera.set_target_player(camera, target_player)
end) --[[ @as any ]] end) --[[@as any]]
--- Button which sets the target of a camera to the current location --- Button which sets the target of a camera to the current location
--- @class ExpGui_Surveillance.elements.set_location_button: ExpElement --- @class ExpGui_Surveillance.elements.set_location_button: ExpElement
@@ -48,7 +48,7 @@ Elements.set_location_button = Gui.define("surveillance/set_location_button")
--- @cast def ExpGui_Surveillance.elements.set_location_button --- @cast def ExpGui_Surveillance.elements.set_location_button
local camera = def.data[element] local camera = def.data[element]
Elements.camera.set_target_position(camera, player.physical_surface_index, player.physical_position) Elements.camera.set_target_position(camera, player.physical_surface_index, player.physical_position)
end) --[[ @as any ]] end) --[[@as any]]
--- @class ExpGui_Surveillance.elements.type_dropdown.data --- @class ExpGui_Surveillance.elements.type_dropdown.data
--- @field player_dropdown LuaGuiElement --- @field player_dropdown LuaGuiElement
@@ -87,7 +87,7 @@ Elements.type_dropdown = Gui.define("surveillance/type_dropdown")
local target_player = ElementsExtra.online_player_dropdown.get_selected(element_data.player_dropdown) local target_player = ElementsExtra.online_player_dropdown.get_selected(element_data.player_dropdown)
Elements.camera.set_target_player(element_data.camera, target_player) Elements.camera.set_target_player(element_data.camera, target_player)
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh all online type dropdowns by cycling the associated player dropdown --- Refresh all online type dropdowns by cycling the associated player dropdown
function Elements.type_dropdown.refresh_online() function Elements.type_dropdown.refresh_online()
@@ -131,7 +131,7 @@ Elements.zoom_out_button = Gui.define("surveillance/zoom_out_button")
if camera.zoom > 0.2 then if camera.zoom > 0.2 then
camera.zoom = camera.zoom - 0.05 camera.zoom = camera.zoom - 0.05
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Buttons which increases zoom by 5% --- Buttons which increases zoom by 5%
--- @class ExpGui_Surveillance.elements.zoom_in_button: ExpElement --- @class ExpGui_Surveillance.elements.zoom_in_button: ExpElement
@@ -156,7 +156,7 @@ Elements.zoom_in_button = Gui.define("surveillance/zoom_in_button")
if camera.zoom < 2.0 then if camera.zoom < 2.0 then
camera.zoom = camera.zoom + 0.05 camera.zoom = camera.zoom + 0.05
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Camera which tracks a target with a physical_position and surface_index --- Camera which tracks a target with a physical_position and surface_index
--- @class ExpGui_Surveillance.elements.camera: ExpElement --- @class ExpGui_Surveillance.elements.camera: ExpElement
@@ -176,7 +176,7 @@ Elements.camera = Gui.define("surveillance/camera")
} }
:element_data( :element_data(
Gui.from_argument(1) Gui.from_argument(1)
) --[[ @as any ]] ) --[[@as any]]
--- Set the target player for the camera --- Set the target player for the camera
--- @param camera LuaGuiElement --- @param camera LuaGuiElement
+32 -27
View File
@@ -105,7 +105,7 @@ Elements.new_task_button = Gui.define("task_list/new_task_button")
body = "", body = "",
new = true, new = true,
}) })
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh the visibility based on player permissions --- Refresh the visibility based on player permissions
--- @param new_task_button LuaGuiElement --- @param new_task_button LuaGuiElement
@@ -154,7 +154,7 @@ Elements.view_task_button = Gui.define("task_list/view_task_button")
--- @cast def ExpGui_TaskList.element.view_task_button --- @cast def ExpGui_TaskList.element.view_task_button
local elements = def.data[view_task_button] local elements = def.data[view_task_button]
Elements.container.open_view_task(elements.container, elements.task) Elements.container.open_view_task(elements.container, elements.task)
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh the title and tooltip of the view task button --- Refresh the title and tooltip of the view task button
--- @param view_task_button LuaGuiElement --- @param view_task_button LuaGuiElement
@@ -187,19 +187,19 @@ Elements.no_tasks_header = Gui.define("task_list/no_tasks_header")
:style{ :style{
padding = { 2, 0 }, padding = { 2, 0 },
bottom_margin = 0, bottom_margin = 0,
} --[[ @as any ]] } --[[@as any]]
--- Refresh the visibility of the no tasks label --- Refresh the visibility of the no tasks label
--- @param no_tasks_header LuaGuiElement --- @param no_tasks_header LuaGuiElement
function Elements.no_tasks_header.refresh(no_tasks_header) function Elements.no_tasks_header.refresh(no_tasks_header)
local force = Gui.get_player(no_tasks_header).force --[[ @as LuaForce ]] local force = Gui.get_player(no_tasks_header).force --[[@as LuaForce]]
no_tasks_header.visible = not Elements.container.has_tasks(force) no_tasks_header.visible = not Elements.container.has_tasks(force)
end end
--- Refresh the visibility of the no tasks label --- Refresh the visibility of the no tasks label
--- @param player LuaPlayer --- @param player LuaPlayer
function Elements.no_tasks_header.refresh_player(player) function Elements.no_tasks_header.refresh_player(player)
local visible = not Elements.container.has_tasks(player.force --[[ @as LuaForce ]]) local visible = not Elements.container.has_tasks(player.force --[[@as LuaForce]])
for _, no_tasks_header in Elements.no_tasks_header:tracked_elements(player) do for _, no_tasks_header in Elements.no_tasks_header:tracked_elements(player) do
no_tasks_header.visible = visible no_tasks_header.visible = visible
end end
@@ -246,13 +246,13 @@ Elements.task_list = Gui.define("task_list/task_list")
return task_list return task_list
end) end)
:element_data{} --[[ @as any ]] :element_data{} --[[@as any]]
--- Adds a task to the task list --- Adds a task to the task list
--- @param task_list LuaGuiElement --- @param task_list LuaGuiElement
--- @param task ExpGui_TaskList.Task --- @param task ExpGui_TaskList.Task
function Elements.task_list.add_task(task_list, task) function Elements.task_list.add_task(task_list, task)
local container = assert(task_list.parent.parent.parent) local container = assert(assert(assert(task_list.parent).parent).parent)
local view_task_buttons = Elements.task_list.data[task_list] local view_task_buttons = Elements.task_list.data[task_list]
view_task_buttons[task.id] = Elements.view_task_button(task_list, task, container) view_task_buttons[task.id] = Elements.view_task_button(task_list, task, container)
end end
@@ -330,7 +330,7 @@ Elements.task_footer = Gui.define("task_list/task_footer")
height = 0, height = 0,
padding = 5, padding = 5,
use_header_filler = false, use_header_filler = false,
} --[[ @as any ]] } --[[@as any]]
--- @class ExpGui_TaskList.elements.close_task_button.elements --- @class ExpGui_TaskList.elements.close_task_button.elements
--- @field container LuaGuiElement --- @field container LuaGuiElement
@@ -354,7 +354,7 @@ Elements.close_task_button = Gui.define("task_list/close_task_button")
--- @cast def ExpGui_TaskList.element.close_task_button --- @cast def ExpGui_TaskList.element.close_task_button
local elements = def.data[close_task_button] local elements = def.data[close_task_button]
Elements.container.close_footers(elements.container) Elements.container.close_footers(elements.container)
end) --[[ @as any ]] end) --[[@as any]]
--- @class ExpGui_TaskList.elements.task_button.elements --- @class ExpGui_TaskList.elements.task_button.elements
--- @field task ExpGui_TaskList.Task? --- @field task ExpGui_TaskList.Task?
@@ -379,7 +379,7 @@ Elements.edit_task_button = Gui.define("task_list/edit_task_button")
--- @cast def ExpGui_TaskList.element.edit_task_button --- @cast def ExpGui_TaskList.element.edit_task_button
local elements = def.data[edit_task_button] local elements = def.data[edit_task_button]
Elements.container.open_edit_task(elements.container, assert(elements.task)) Elements.container.open_edit_task(elements.container, assert(elements.task))
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh the edit button --- Refresh the edit button
--- @param edit_task_button LuaGuiElement --- @param edit_task_button LuaGuiElement
@@ -415,9 +415,9 @@ Elements.delete_task_button = Gui.define("task_list/delete_task_button")
:on_click(function(def, player, delete_task_button) :on_click(function(def, player, delete_task_button)
--- @cast def ExpGui_TaskList.element.delete_task_button --- @cast def ExpGui_TaskList.element.delete_task_button
local elements = def.data[delete_task_button] local elements = def.data[delete_task_button]
Elements.container.remove_task(player.force --[[ @as LuaForce ]], elements.task) Elements.container.remove_task(player.force --[[@as LuaForce]], elements.task)
Elements.container.close_footers(elements.container) Elements.container.close_footers(elements.container)
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh the delete button --- Refresh the delete button
--- @param delete_task_button LuaGuiElement --- @param delete_task_button LuaGuiElement
@@ -477,7 +477,7 @@ Elements.view_task_footer = Gui.define("task_list/view_task_footer")
} }
return view_task_footer return view_task_footer
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh the view task with new task details --- Refresh the view task with new task details
--- @param view_task_footer LuaGuiElement --- @param view_task_footer LuaGuiElement
@@ -532,9 +532,9 @@ Elements.task_message_textfield = Gui.define("task_list/task_message_textfield")
} }
:on_text_changed(function(def, player, task_message_textfield) :on_text_changed(function(def, player, task_message_textfield)
--- @cast def ExpGui_TaskList.elements.task_message_textfield --- @cast def ExpGui_TaskList.elements.task_message_textfield
local confirm_task_button = def.data[task_message_textfield].confirm_task_button local confirm_task_button = assert(def.data[task_message_textfield].confirm_task_button)
confirm_task_button.enabled = string.len(task_message_textfield.text) > 5 confirm_task_button.enabled = string.len(task_message_textfield.text) > 5
end) --[[ @as any ]] end) --[[@as any]]
--- Set the confirm task button to update on text changed --- Set the confirm task button to update on text changed
--- @param task_message_textfield LuaGuiElement --- @param task_message_textfield LuaGuiElement
@@ -549,7 +549,7 @@ end
function Elements.task_message_textfield.refresh(task_message_textfield, task) function Elements.task_message_textfield.refresh(task_message_textfield, task)
local elements = Elements.task_message_textfield.data[task_message_textfield] local elements = Elements.task_message_textfield.data[task_message_textfield]
local message = task.new and "" or task.title .. "\n" .. task.body local message = task.new and "" or task.title .. "\n" .. task.body
elements.confirm_task_button.enabled = string.len(message) > 5 assert(elements.confirm_task_button).enabled = string.len(message) > 5
task_message_textfield.text = message task_message_textfield.text = message
task_message_textfield.focus() task_message_textfield.focus()
end end
@@ -590,13 +590,13 @@ Elements.confirm_task_button = Gui.define("task_list/confirm_task_button")
Elements.container.close_footers(elements.container) Elements.container.close_footers(elements.container)
local force = player.force --[[ @as LuaForce ]] local force = player.force --[[@as LuaForce]]
if task.new then if task.new then
Elements.container.add_task(force, task) Elements.container.add_task(force, task)
else else
Elements.container.refresh_force_online(force, task) Elements.container.refresh_force_online(force, task)
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh the confirm task button --- Refresh the confirm task button
--- @param confirm_task_button LuaGuiElement --- @param confirm_task_button LuaGuiElement
@@ -612,7 +612,7 @@ function Elements.confirm_task_button.parse(message)
-- Trim the spaces of the string -- Trim the spaces of the string
local trimmed = string.gsub(message, "^%s*(.-)%s*$", "%1") local trimmed = string.gsub(message, "^%s*(.-)%s*$", "%1")
local title, body = string.match(trimmed, "(.-)\n(.*)") local title, body = string.match(trimmed, "(.-)\n(.*)")
local parsed = { title = title, body = body } local parsed = { title = title, body = body } --[[@as { title: string, body: string }]]
if not title then if not title then
-- If it doesn't match the pattern return the str as a title -- If it doesn't match the pattern return the str as a title
parsed.title = trimmed parsed.title = trimmed
@@ -649,7 +649,7 @@ Elements.discard_task_button = Gui.define("task_list/discard_task_button")
else else
Elements.container.open_view_task(elements.container, task) Elements.container.open_view_task(elements.container, task)
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh the discard task button --- Refresh the discard task button
--- @param discard_task_button LuaGuiElement --- @param discard_task_button LuaGuiElement
@@ -696,7 +696,7 @@ Elements.edit_task_footer = Gui.define("task_list/edit_task_footer")
} }
return edit_task_footer return edit_task_footer
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh the view task with new task details --- Refresh the view task with new task details
--- @param edit_task_footer LuaGuiElement --- @param edit_task_footer LuaGuiElement
@@ -755,9 +755,14 @@ end
--- @field view_task_footer LuaGuiElement --- @field view_task_footer LuaGuiElement
--- @field edit_task_footer LuaGuiElement --- @field edit_task_footer LuaGuiElement
--- @class ExpGui_TaskList.elements.container.data
--- @field global_data { next_task_id: number }
--- @field [LuaGuiElement] ExpGui_TaskList.elements.container.elements
--- @field [LuaForce] ExpGui_TaskList.Task[]
--- Container added to the left gui flow --- Container added to the left gui flow
--- @class ExpGui_TaskList.elements.container: ExpElement --- @class ExpGui_TaskList.elements.container: ExpElement
--- @field data table<LuaForce, ExpGui_TaskList.Task[]> | table<LuaGuiElement, ExpGui_TaskList.elements.container.elements> | table<"global_data", { next_task_id: number }> --- @field data ExpGui_TaskList.elements.container.data
Elements.container = Gui.define("task_list/container") Elements.container = Gui.define("task_list/container")
:track_all_elements() :track_all_elements()
:draw(function(def, parent) :draw(function(def, parent)
@@ -781,7 +786,7 @@ Elements.container = Gui.define("task_list/container")
-- Add tasks to the list if there are any -- Add tasks to the list if there are any
local player = Gui.get_player(parent) local player = Gui.get_player(parent)
local force = player.force --[[ @as LuaForce ]] local force = player.force --[[@as LuaForce]]
local tasks = def.data[force] local tasks = def.data[force]
if tasks then if tasks then
for _, task in ipairs(tasks) do for _, task in ipairs(tasks) do
@@ -796,11 +801,11 @@ Elements.container = Gui.define("task_list/container")
elements.edit_task_footer.visible = false elements.edit_task_footer.visible = false
-- Set the data and return -- Set the data and return
def.data[root] = elements --[[ @as any ]] def.data[root] = elements --[[@as any]]
return root return root
end) end)
:global_data{ next_task_id = 1 } :global_data{ next_task_id = 1 }
:force_data{} --[[ @as any ]] :force_data{} --[[@as any]]
--- Check if a force has tasks --- Check if a force has tasks
--- @param force LuaForce --- @param force LuaForce
@@ -885,7 +890,7 @@ end
--- Refresh all tasks for a player --- Refresh all tasks for a player
--- @param player LuaPlayer --- @param player LuaPlayer
function Elements.container.refresh_player(player) function Elements.container.refresh_player(player)
local tasks = Elements.container.data[ player.force --[[ @as LuaForce ]] ] local tasks = Elements.container.data[ player.force --[[@as LuaForce]] ]
for _, container in Elements.container:tracked_elements(player) do for _, container in Elements.container:tracked_elements(player) do
local elements = Elements.container.data[container] local elements = Elements.container.data[container]
Elements.task_list.refresh_tasks(elements.task_list, tasks) Elements.task_list.refresh_tasks(elements.task_list, tasks)
@@ -908,7 +913,7 @@ end
--- Add the element to the left flow with a toolbar button --- Add the element to the left flow with a toolbar button
Gui.add_left_element(Elements.container, function(player) Gui.add_left_element(Elements.container, function(player)
return Elements.container.has_tasks(player.force --[[ @as LuaForce ]]) return Elements.container.has_tasks(player.force --[[@as LuaForce]])
end) end)
Gui.toolbar.create_button{ Gui.toolbar.create_button{
+1 -1
View File
@@ -42,7 +42,7 @@ Elements.server_ups = Gui.define("server_ups")
if not existing or not existing.valid then if not existing or not existing.valid then
def.data[player] = element -- Only set if previous is invalid def.data[player] = element -- Only set if previous is invalid
end end
end) --[[ @as any ]] end) --[[@as any]]
--- Refresh the caption for all online players --- Refresh the caption for all online players
--- @param ups number The UPS to be displayed --- @param ups number The UPS to be displayed
+18 -18
View File
@@ -11,22 +11,22 @@ local max = math.max
local AABB = {} local AABB = {}
--- Check if an area is valid --- Check if an area is valid
--- @param aabb BoundingBox --- @param aabb BoundingBox.struct
--- @return boolean # True if the area is valid --- @return boolean # True if the area is valid
function AABB.valid(aabb) function AABB.valid(aabb)
return aabb.left_top.x < aabb.right_bottom.x and aabb.left_top.y < aabb.right_bottom.y return aabb.left_top.x < aabb.right_bottom.x and aabb.left_top.y < aabb.right_bottom.y
end end
--- Returns the size of the area contained within an AABB --- Returns the size of the area contained within an AABB
--- @param aabb BoundingBox --- @param aabb BoundingBox.struct
--- @return number --- @return number
function AABB.size(aabb) function AABB.size(aabb)
return (aabb.right_bottom.x - aabb.left_top.x) * (aabb.right_bottom.y - aabb.left_top.y) return (aabb.right_bottom.x - aabb.left_top.x) * (aabb.right_bottom.y - aabb.left_top.y)
end end
--- Clone an area, allows for safe mutation of an input value --- Clone an area, allows for safe mutation of an input value
--- @param aabb BoundingBox --- @param aabb BoundingBox.struct
--- @return BoundingBox --- @return BoundingBox.struct
function AABB.clone(aabb) function AABB.clone(aabb)
return { return {
left_top = { x = aabb.left_top.x, y = aabb.left_top.y }, left_top = { x = aabb.left_top.x, y = aabb.left_top.y },
@@ -35,8 +35,8 @@ function AABB.clone(aabb)
end end
--- Expand an area to be integer aligned, expanding away from 0 --- Expand an area to be integer aligned, expanding away from 0
--- @param aabb BoundingBox --- @param aabb BoundingBox.struct
--- @return BoundingBox --- @return BoundingBox.struct
function AABB.expand(aabb) function AABB.expand(aabb)
return { return {
left_top = { x = floor(aabb.left_top.x), y = floor(aabb.left_top.y) }, left_top = { x = floor(aabb.left_top.x), y = floor(aabb.left_top.y) },
@@ -45,8 +45,8 @@ function AABB.expand(aabb)
end end
--- Contract an area to be integer aligned, contracting towards 0 --- Contract an area to be integer aligned, contracting towards 0
--- @param aabb BoundingBox --- @param aabb BoundingBox.struct
--- @return BoundingBox --- @return BoundingBox.struct
function AABB.contract(aabb) function AABB.contract(aabb)
return { return {
left_top = { x = ceil(aabb.left_top.x), y = ceil(aabb.left_top.y) }, left_top = { x = ceil(aabb.left_top.x), y = ceil(aabb.left_top.y) },
@@ -55,9 +55,9 @@ function AABB.contract(aabb)
end end
--- Expand an area to include all other areas --- Expand an area to include all other areas
--- @param aabb BoundingBox --- @param aabb BoundingBox.struct
--- @param ... BoundingBox --- @param ... BoundingBox.struct
--- @return BoundingBox --- @return BoundingBox.struct
function AABB.union(aabb, ...) function AABB.union(aabb, ...)
local rtn = AABB.clone(aabb) local rtn = AABB.clone(aabb)
for _, next_aabb in ipairs{ ... } do for _, next_aabb in ipairs{ ... } do
@@ -70,9 +70,9 @@ function AABB.union(aabb, ...)
end end
--- Contract an area to include to the overlap of all areas --- Contract an area to include to the overlap of all areas
--- @param aabb BoundingBox --- @param aabb BoundingBox.struct
--- @param ... BoundingBox --- @param ... BoundingBox.struct
--- @return BoundingBox? # Nil if there is no intersection --- @return BoundingBox.struct? # Nil if there is no intersection
function AABB.intersect(aabb, ...) function AABB.intersect(aabb, ...)
local rtn = AABB.clone(aabb) local rtn = AABB.clone(aabb)
for _, next_aabb in ipairs{ ... } do for _, next_aabb in ipairs{ ... } do
@@ -88,8 +88,8 @@ function AABB.intersect(aabb, ...)
end end
--- Check if a point is contained within an area --- Check if a point is contained within an area
--- @param aabb BoundingBox --- @param aabb BoundingBox.struct
--- @param point MapPosition --- @param point MapPosition.struct
--- @return boolean # True if the point is within or on the edge of the bounding box --- @return boolean # True if the point is within or on the edge of the bounding box
function AABB.contains_point(aabb, point) function AABB.contains_point(aabb, point)
return point.x >= aabb.left_top.x and point.y >= aabb.left_top.y return point.x >= aabb.left_top.x and point.y >= aabb.left_top.y
@@ -97,8 +97,8 @@ function AABB.contains_point(aabb, point)
end end
--- Check if an area is fulling contained within another area --- Check if an area is fulling contained within another area
--- @param aabb BoundingBox --- @param aabb BoundingBox.struct
--- @param other BoundingBox --- @param other BoundingBox.struct
--- @return boolean # True if the point is within or on the edge of the bounding box --- @return boolean # True if the point is within or on the edge of the bounding box
function AABB.contains_area(aabb, other) function AABB.contains_area(aabb, other)
return AABB.contains_point(aabb, other.left_top) and AABB.contains_point(aabb, other.right_bottom) return AABB.contains_point(aabb, other.left_top) and AABB.contains_point(aabb, other.right_bottom)
+18 -21
View File
@@ -93,8 +93,8 @@ local Async = {
Async.status = {} Async.status = {}
--- @class Async.AsyncFunction --- @class Async.AsyncFunction
--- @field id number The id of this async function --- @field id string The id of this async function
--- @operator call: Async.AsyncReturn --- @overload fun(...: any): Async.AsyncReturn<any>
Async._function_prototype = {} Async._function_prototype = {}
Async._function_metatable = { Async._function_metatable = {
@@ -104,10 +104,10 @@ Async._function_metatable = {
} }
--- @class Async.AsyncReturn<F> --- @class Async.AsyncReturn<F>
--- @field func_id number The id of the async function to be called --- @field func_id string The id of the async function to be called
--- @field args any[] The arguments to call the function with --- @field args any[] The arguments to call the function with
--- @field tick number? If present, the function will be called on this game tick --- @field tick number? If present, the function will be called on this game tick
--- @field next_id number? The id of the async function to be called with the return value --- @field next_id string? The id of the async function to be called with the return value
--- @field canceled boolean? True if the call has been canceled --- @field canceled boolean? True if the call has been canceled
--- @field completed boolean? True if the call has completed --- @field completed boolean? True if the call has completed
--- @field return_values any? The return values of the function call --- @field return_values any? The return values of the function call
@@ -123,20 +123,20 @@ script.register_metatable("AsyncReturn", Async._return_metatable)
--- Storage Variables --- Storage Variables
local resolve_next --- @type Async.AsyncReturn[] Stores a queue of async functions to be executed on the next tick local resolve_next --- @type Async.AsyncReturn<any>[] Stores a queue of async functions to be executed on the next tick
local resolve_queue --- @type Async.AsyncReturn[] Stores a queue of async functions to be executed on a later tick local resolve_queue --- @type Async.AsyncReturn<any>[] Stores a queue of async functions to be executed on a later tick
--- Insert an item into the priority queue --- Insert an item into the priority queue
--- @param pending Async.AsyncReturn --- @param pending Async.AsyncReturn<any>
--- @return Async.AsyncReturn --- @return Async.AsyncReturn<any>
local function add_to_next_tick(pending) local function add_to_next_tick(pending)
resolve_next[#resolve_next + 1] = pending resolve_next[#resolve_next + 1] = pending
return pending return pending
end end
--- Insert an item into the priority queue --- Insert an item into the priority queue
--- @param pending Async.AsyncReturn --- @param pending Async.AsyncReturn<any>
--- @return Async.AsyncReturn --- @return Async.AsyncReturn<any>
local function add_to_resolve_queue(pending) local function add_to_resolve_queue(pending)
local tick = pending.tick local tick = pending.tick
for index = #resolve_queue, 1, -1 do for index = #resolve_queue, 1, -1 do
@@ -191,7 +191,7 @@ end
--- Run an async function on the next tick, this is the default and can be used to bypass permission groups --- Run an async function on the next tick, this is the default and can be used to bypass permission groups
--- @param ... any The arguments to call the function with --- @param ... any The arguments to call the function with
--- @return Async.AsyncReturn --- @return Async.AsyncReturn<any>
function Async._function_prototype:start_soon(...) function Async._function_prototype:start_soon(...)
assert(Async._registered[self.id], "Async function is not registered") assert(Async._registered[self.id], "Async function is not registered")
Async._queue_pressure[self.id] = Async._queue_pressure[self.id] + 1 Async._queue_pressure[self.id] = Async._queue_pressure[self.id] + 1
@@ -204,7 +204,7 @@ end
--- Run an async function after the given number of ticks --- Run an async function after the given number of ticks
--- @param ticks number The number of ticks to call the function after --- @param ticks number The number of ticks to call the function after
--- @param ... any The arguments to call the function with --- @param ... any The arguments to call the function with
--- @return Async.AsyncReturn --- @return Async.AsyncReturn<any>
function Async._function_prototype:start_after(ticks, ...) function Async._function_prototype:start_after(ticks, ...)
ExpUtil.assert_argument_type(ticks, "number", 1, "ticks") ExpUtil.assert_argument_type(ticks, "number", 1, "ticks")
assert(ticks > 0, "Ticks must be a positive number") assert(ticks > 0, "Ticks must be a positive number")
@@ -219,7 +219,7 @@ end
--- Run an async function on the next tick if the function is not already queued, allows singleton task/thread behaviour --- Run an async function on the next tick if the function is not already queued, allows singleton task/thread behaviour
--- @param ... any The arguments to call the function with --- @param ... any The arguments to call the function with
--- @return Async.AsyncReturn | nil --- @return Async.AsyncReturn<any> | nil
function Async._function_prototype:start_task(...) function Async._function_prototype:start_task(...)
assert(Async._registered[self.id], "Async function is not registered") assert(Async._registered[self.id], "Async function is not registered")
if Async._queue_pressure[self.id] > 0 then return end if Async._queue_pressure[self.id] > 0 then return end
@@ -228,7 +228,7 @@ end
--- Run an async function on this tick, then queue it based on its return value --- Run an async function on this tick, then queue it based on its return value
--- @param ... any The arguments to call the function with --- @param ... any The arguments to call the function with
--- @return Async.AsyncReturn --- @return Async.AsyncReturn<any>
function Async._function_prototype:start_now(...) function Async._function_prototype:start_now(...)
assert(Async._registered[self.id], "Async function is not registered") assert(Async._registered[self.id], "Async function is not registered")
local status, rtn1, rtn2 = Async._registered[self.id](...) local status, rtn1, rtn2 = Async._registered[self.id](...)
@@ -261,7 +261,6 @@ local empty_table = setmetatable({}, {
--- Default status, will raise on_function_complete --- Default status, will raise on_function_complete
--- @param ... any The return value of the async call --- @param ... any The return value of the async call
--- @return Async.Status, any[] --- @return Async.Status, any[]
--- @type Async.Status
function Async.status.complete(...) function Async.status.complete(...)
if ... == nil then if ... == nil then
return Async.status.complete, empty_table return Async.status.complete, empty_table
@@ -272,7 +271,6 @@ end
--- Will queue the function to be called again on the next tick using the new arguments --- Will queue the function to be called again on the next tick using the new arguments
--- @param ... any The arguments to call the function with --- @param ... any The arguments to call the function with
--- @return Async.Status, any[] --- @return Async.Status, any[]
--- @type Async.Status
function Async.status.continue(...) function Async.status.continue(...)
if ... == nil then if ... == nil then
return Async.status.continue, empty_table return Async.status.continue, empty_table
@@ -284,7 +282,6 @@ end
--- @param ticks number The number of ticks to delay for --- @param ticks number The number of ticks to delay for
--- @param ... any The arguments to call the function with --- @param ... any The arguments to call the function with
--- @return Async.Status, number, any[] --- @return Async.Status, number, any[]
--- @type Async.Status
function Async.status.delay(ticks, ...) function Async.status.delay(ticks, ...)
ExpUtil.assert_argument_type(ticks, "number", 1, "ticks") ExpUtil.assert_argument_type(ticks, "number", 1, "ticks")
assert(ticks > 0, "Ticks must be a positive number") assert(ticks > 0, "Ticks must be a positive number")
@@ -296,11 +293,11 @@ end
--- Status Returns. --- Status Returns.
--- @type Async.AsyncReturn[], Async.AsyncReturn[] --- @type Async.AsyncReturn<any>[], Async.AsyncReturn<any>[]
local new_next, new_queue = {}, {} -- File scope to allow for reuse local new_next, new_queue = {}, {} -- File scope to allow for reuse
--- Executes an async function and processes the return value --- Executes an async function and processes the return value
--- @param pending Async.AsyncReturn --- @param pending Async.AsyncReturn<any>
--- @param tick number --- @param tick number
local function exec(pending, tick) local function exec(pending, tick)
local async_func = Async._registered[pending.func_id] local async_func = Async._registered[pending.func_id]
@@ -400,9 +397,9 @@ end
--- @package --- @package
function Async.on_init() function Async.on_init()
if storage.exp_async_next == nil then if storage.exp_async_next == nil then
--- @type Async.AsyncReturn[] --- @type Async.AsyncReturn<any>[]
storage.exp_async_next = {} storage.exp_async_next = {}
--- @type Async.AsyncReturn[] --- @type Async.AsyncReturn<any>[]
storage.exp_async_queue = {} storage.exp_async_queue = {}
end end
Async.on_load() Async.on_load()
+15 -9
View File
@@ -42,12 +42,14 @@ end
--- @param options FlyingText.create_above_entity_param --- @param options FlyingText.create_above_entity_param
function FlyingText.create_above_entity(options) function FlyingText.create_above_entity(options)
local entity = assert(options.target_entity, "A target entity is required") local entity = assert(options.target_entity, "A target entity is required")
local size_y = entity.bounding_box.left_top.y - entity.bounding_box.right_bottom.y local bounding_box = entity.bounding_box
local size_y = bounding_box.left_top.y - bounding_box.right_bottom.y
local position = entity.position
local offset = options.offset or { x = 0, y = 0 } local offset = options.offset or { x = 0, y = 0 }
options.position = { options.position = {
x = offset.x + entity.position.x, x = offset.x + position.x,
y = offset.y + entity.position.y + size_y * 0.25, y = offset.y + position.y + size_y * 0.25,
} }
FlyingText.create(options) FlyingText.create(options)
@@ -62,12 +64,14 @@ end
function FlyingText.create_above_player(options) function FlyingText.create_above_player(options)
local player = assert(options.target_player, "A target player is required") local player = assert(options.target_player, "A target player is required")
local entity = player.character; if not entity then return end local entity = player.character; if not entity then return end
local size_y = entity.bounding_box.left_top.y - entity.bounding_box.right_bottom.y local bounding_box = entity.bounding_box
local size_y = bounding_box.left_top.y - bounding_box.right_bottom.y
local position = entity.position
local offset = options.offset or { x = 0, y = 0 } local offset = options.offset or { x = 0, y = 0 }
options.position = { options.position = {
x = offset.x + entity.position.x, x = offset.x + position.x,
y = offset.y + entity.position.y + size_y * 0.25, y = offset.y + position.y + size_y * 0.25,
} }
FlyingText.create(options) FlyingText.create(options)
@@ -82,13 +86,15 @@ end
function FlyingText.create_as_player(options) function FlyingText.create_as_player(options)
local player = assert(options.target_player, "A target player is required") local player = assert(options.target_player, "A target player is required")
local entity = player.character; if not entity then return end local entity = player.character; if not entity then return end
local size_y = entity.bounding_box.left_top.y - entity.bounding_box.right_bottom.y local bounding_box = entity.bounding_box
local size_y = bounding_box.left_top.y - bounding_box.right_bottom.y
local position = entity.position
local offset = options.offset or { x = 0, y = 0 } local offset = options.offset or { x = 0, y = 0 }
options.color = player.chat_color options.color = player.chat_color
options.position = { options.position = {
x = offset.x + entity.position.x, x = offset.x + position.x,
y = offset.y + entity.position.y + size_y * 0.25, y = offset.y + position.y + size_y * 0.25,
} }
FlyingText.create(options) FlyingText.create(options)
+17 -15
View File
@@ -92,7 +92,7 @@ local assert_argument_fmt = "Bad argument #%d to %s; %s expected to be of type %
function ExpUtil.assert_argument_type(arg_value, type_name, arg_index, arg_name) function ExpUtil.assert_argument_type(arg_value, type_name, arg_index, arg_name)
local failed, actual_type = check_type(arg_value, type_name) local failed, actual_type = check_type(arg_value, type_name)
if failed then if failed then
local func_name = getinfo(2, "n").name or "<anonymous>" local func_name = assert(getinfo(2, "n")).name or "<anonymous>"
error(assert_argument_fmt:format(arg_index, func_name, arg_name or "Argument", type_name, actual_type), 2) error(assert_argument_fmt:format(arg_index, func_name, arg_name or "Argument", type_name, actual_type), 2)
end end
end end
@@ -136,7 +136,7 @@ end
--- @param level number? The level of the stack to get the file of, a value of 1 is the caller of this function --- @param level number? The level of the stack to get the file of, a value of 1 is the caller of this function
--- @return string # The relative filepath of the given stack frame --- @return string # The relative filepath of the given stack frame
function ExpUtil.safe_file_path(level) function ExpUtil.safe_file_path(level)
local debug_info = getinfo((level or 1) + 1, "Sn") local debug_info = assert(getinfo((level or 1) + 1, "Sn"))
local safe_source = debug_info.source:find("@__level__") local safe_source = debug_info.source:find("@__level__")
return safe_source == 1 and debug_info.short_src:sub(10, -5) or debug_info.source return safe_source == 1 and debug_info.short_src:sub(10, -5) or debug_info.source
end end
@@ -145,7 +145,7 @@ end
--- @param level number? The level of the stack to get the module of, a value of 1 is the caller of this function --- @param level number? The level of the stack to get the module of, a value of 1 is the caller of this function
--- @return string # The name of the module at the given stack frame --- @return string # The name of the module at the given stack frame
function ExpUtil.get_module_name(level) function ExpUtil.get_module_name(level)
local file_within_module = getinfo((level or 1) + 1, "S").short_src:sub(19, -5) local file_within_module = assert(getinfo((level or 1) + 1, "S")).short_src:sub(19, -5)
local next_slash = file_within_module:find("/") local next_slash = file_within_module:find("/")
if next_slash then if next_slash then
return file_within_module:sub(1, next_slash - 1) return file_within_module:sub(1, next_slash - 1)
@@ -159,7 +159,7 @@ end
--- @param raw boolean? When true there will not be any < > around the name --- @param raw boolean? When true there will not be any < > around the name
--- @return string # The name of the function at the given stack frame or provided as an argument --- @return string # The name of the function at the given stack frame or provided as an argument
function ExpUtil.get_function_name(func, raw) function ExpUtil.get_function_name(func, raw)
local debug_info = getinfo(func, "Sn") local debug_info = assert(getinfo(func, "Sn"))
local safe_source = debug_info.source:find("@__level__") local safe_source = debug_info.source:find("@__level__")
local file_name = safe_source == 1 and debug_info.source:sub(12, -5) or debug_info.source local file_name = safe_source == 1 and debug_info.source:sub(12, -5) or debug_info.source
local func_name = debug_info.name or debug_info.linedefined local func_name = debug_info.name or debug_info.linedefined
@@ -172,7 +172,7 @@ end
--- @param raw boolean? When true there will not be any < > around the name --- @param raw boolean? When true there will not be any < > around the name
--- @return string # The relative filepath of the given stack frame --- @return string # The relative filepath of the given stack frame
function ExpUtil.get_current_line(level, raw) function ExpUtil.get_current_line(level, raw)
local debug_info = getinfo((level or 1) + 1, "Snl") local debug_info = assert(getinfo((level or 1) + 1, "Snl"))
local safe_source = debug_info.source:find("@__level__") local safe_source = debug_info.source:find("@__level__")
local file_path = safe_source == 1 and debug_info.short_src:sub(10, -5) or debug_info.source local file_path = safe_source == 1 and debug_info.short_src:sub(10, -5) or debug_info.source
if raw then return file_path .. ":" .. debug_info.currentline end if raw then return file_path .. ":" .. debug_info.currentline end
@@ -207,7 +207,7 @@ end
function ExpUtil.auto_complete(options, input, use_key, rtn_key, use_pattern) function ExpUtil.auto_complete(options, input, use_key, rtn_key, use_pattern)
input = input:lower() input = input:lower()
local plain = use_pattern ~= true local plain = use_pattern ~= true
local found = {} --- @type { length: number, index: number, start: boolean, value: any } local found = {} --- @type { length: number?, index: number?, start: boolean?, value: any }
for k, v in pairs(options) do for k, v in pairs(options) do
local str = use_key and k or v local str = use_key and k or v
local index = str:lower():find(input, nil, plain) local index = str:lower():find(input, nil, plain)
@@ -284,7 +284,7 @@ function ExpUtil.format_any(value, options)
end end
return inspect(value, { depth = options.depth or 5, indent = "", newline = "", process = ExpUtil.safe_value }) return inspect(value, { depth = options.depth or 5, indent = "", newline = "", process = ExpUtil.safe_value })
end end
return formatted return formatted --[[@as LocalisedString]]
end end
--- @alias Common.format_time_param_format "short" | "long" | "clock" --- @alias Common.format_time_param_format "short" | "long" | "clock"
@@ -319,15 +319,15 @@ function ExpUtil.extract_time_units(ticks, units)
-- Remove units that are not requested -- Remove units that are not requested
if not units.days then if not units.days then
rtn.hours = rtn.hours + rtn.days * 24 rtn.hours = assert(rtn.hours) + assert(rtn.days) * 24
rtn.days = nil rtn.days = nil
end end
if not units.hours then if not units.hours then
rtn.minutes = rtn.minutes + rtn.hours * 60 rtn.minutes = assert(rtn.minutes) + assert(rtn.hours) * 60
rtn.hours = nil rtn.hours = nil
end end
if not units.minutes then if not units.minutes then
rtn.seconds = rtn.seconds + rtn.minutes * 60 rtn.seconds = assert(rtn.seconds) + assert(rtn.minutes) * 60
rtn.minutes = nil rtn.minutes = nil
end end
if not units.seconds then if not units.seconds then
@@ -487,7 +487,7 @@ function ExpUtil.get_storage_for_stack(options)
-- Find a valid entity from the search results -- Find a valid entity from the search results
local current, count, entities = cache.current, cache.count, cache.entities local current, count, entities = cache.current, cache.count, cache.entities
for i = 1, cache.count do for i = 1, cache.count do
local entity = entities[((current + i - 1) % count) + 1] local entity = assert(entities[((current + i - 1) % count) + 1])
if entity.can_insert(item) then if entity.can_insert(item) then
cache.current = current + 1 cache.current = current + 1
return entity return entity
@@ -522,7 +522,7 @@ end
--- Insert a copy of the given items into the found entities. If no entities are found then they will be created if possible. --- Insert a copy of the given items into the found entities. If no entities are found then they will be created if possible.
--- @param options Common.copy_items_to_surface_param --- @param options Common.copy_items_to_surface_param
--- @return LuaEntity # The last entity inserted into --- @return LuaEntity? # The last entity inserted into, nil if there were no items
function ExpUtil.copy_items_to_surface(options) function ExpUtil.copy_items_to_surface(options)
local entity local entity
for item_index = 1, #options.items do for item_index = 1, #options.items do
@@ -542,7 +542,7 @@ end
--- Insert a copy of the given items into the found entities. If no entities are found then they will be created if possible. --- Insert a copy of the given items into the found entities. If no entities are found then they will be created if possible.
--- @param options Common.move_items_to_surface_param --- @param options Common.move_items_to_surface_param
--- @return LuaEntity # The last entity inserted into --- @return LuaEntity? # The last entity inserted into, nil if there were no items
function ExpUtil.move_items_to_surface(options) function ExpUtil.move_items_to_surface(options)
local entity local entity
for item_index = 1, #options.items do for item_index = 1, #options.items do
@@ -551,7 +551,8 @@ function ExpUtil.move_items_to_surface(options)
options.item = item options.item = item
entity = ExpUtil.get_storage_for_stack(options) entity = ExpUtil.get_storage_for_stack(options)
entity.insert(options.item) entity.insert(options.item)
options.item.clear() local item_stack = options.item --[[@as LuaItemStack]]
item_stack.clear()
end end
end end
return entity return entity
@@ -563,7 +564,7 @@ end
--- Move the given inventory into the found entities. If no entities are found then they will be created if possible. --- Move the given inventory into the found entities. If no entities are found then they will be created if possible.
--- @param options Common.transfer_inventory_to_surface_param --- @param options Common.transfer_inventory_to_surface_param
--- @return LuaEntity # The last entity inserted into --- @return LuaEntity? # The last entity inserted into, nil if there were no items
function ExpUtil.transfer_inventory_to_surface(options) function ExpUtil.transfer_inventory_to_surface(options)
options.items = options.inventory options.items = options.inventory
local entity = ExpUtil.copy_items_to_surface(options) local entity = ExpUtil.copy_items_to_surface(options)
@@ -604,6 +605,7 @@ end
--- @return string --- @return string
function ExpUtil.comma_value(n) -- credit http://richard.warburton.it function ExpUtil.comma_value(n) -- credit http://richard.warburton.it
local left, num, right = string.match(n, "^([^%d]*%d)(%d*)(.-)$") local left, num, right = string.match(n, "^([^%d]*%d)(%d*)(.-)$")
assert(left and num and right)
return left .. (num:reverse():gsub("(%d%d%d)", "%1, "):reverse()) .. right return left .. (num:reverse():gsub("(%d%d%d)", "%1, "):reverse()) .. right
end end
+4 -4
View File
@@ -23,7 +23,7 @@ local Selection = {
--- @field player_index number --- @field player_index number
--- @field selection Selection.Active --- @field selection Selection.Active
--- @type table<string, { [defines.events]: Selection.event_handler[] }> --- @type table<string, { [defines.events]: Selection.event_handler<any>[] }>
_registered = {}, _registered = {},
--- @package --- @package
@@ -54,7 +54,7 @@ local selection_tool = { name = "selection-tool" }
--- @param player LuaPlayer --- @param player LuaPlayer
--- @return boolean? --- @return boolean?
local function has_selection_tool_in_hand(player) local function has_selection_tool_in_hand(player)
return player.cursor_stack and player.cursor_stack.valid_for_read and player.cursor_stack.name == "selection-tool" return assert(player.cursor_stack) and assert(player.cursor_stack).valid_for_read and assert(player.cursor_stack).name == "selection-tool"
end end
--- Give a selection tool to a player if they don't have one --- Give a selection tool to a player if they don't have one
@@ -62,7 +62,7 @@ end
local function give_selection_tool(player) local function give_selection_tool(player)
if has_selection_tool_in_hand(player) then return end if has_selection_tool_in_hand(player) then return end
player.clear_cursor() player.clear_cursor()
player.cursor_stack.set_stack(selection_tool) assert(player.cursor_stack).set_stack(selection_tool)
-- This does not work for selection planners, will make a feature request for it -- This does not work for selection planners, will make a feature request for it
--player.cursor_stack_temporary = true --player.cursor_stack_temporary = true
@@ -84,7 +84,7 @@ end
local function remove_selection_tool(player, old_character) local function remove_selection_tool(player, old_character)
-- Remove the selection tool -- Remove the selection tool
if has_selection_tool_in_hand(player) then if has_selection_tool_in_hand(player) then
player.cursor_stack.clear() assert(player.cursor_stack).clear()
else else
player.remove_item(selection_tool) player.remove_item(selection_tool)
end end
+8 -39
View File
@@ -1,39 +1,8 @@
---@meta ---@meta
---@class script --- The api documents MapPosition and BoundingBox as a union of the named form
script = { --- and a positional array, because both are accepted as input. Everything read
---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: --- back from the game uses the named form, and we always write it that way too,
--- --- so the positional variant is removed here.
---Events that can be raised manually: ---@alias MapPosition MapPosition.struct
--- ---@alias BoundingBox BoundingBox.struct
---* [on\_console\_chat](https://lua-api.factorio.com/latest/events.html#on_console_chat)
---* [on\_player\_crafted\_item](https://lua-api.factorio.com/latest/events.html#on_player_crafted_item)
---* [on\_player\_fast\_transferred](https://lua-api.factorio.com/latest/events.html#on_player_fast_transferred)
---* [on\_biter\_base\_built](https://lua-api.factorio.com/latest/events.html#on_biter_base_built)
---* [on\_market\_item\_purchased](https://lua-api.factorio.com/latest/events.html#on_market_item_purchased)
---* [script\_raised\_built](https://lua-api.factorio.com/latest/events.html#script_raised_built)
---* [script\_raised\_destroy](https://lua-api.factorio.com/latest/events.html#script_raised_destroy)
---* [script\_raised\_revive](https://lua-api.factorio.com/latest/events.html#script_raised_revive)
---* [script\_raised\_teleported](https://lua-api.factorio.com/latest/events.html#script_raised_teleported)
---* [script\_raised\_set\_tiles](https://lua-api.factorio.com/latest/events.html#script_raised_set_tiles)
---
---### Example
---
---```
----- Raise the on_console_chat event with the desired message 'from' the first player
---local data = {player_index = 1, message = "Hello friends!"}
---script.raise_event(defines.events.on_console_chat, data)
---```
---
---[View Documentation](https://lua-api.factorio.com/latest/classes/LuaBootstrap.html#raise_event)
---
--- Type patched in 2.0.28: [Bug Report](https://forums.factorio.com/viewtopic.php?f=233&t=125062)
--- Changed "event" from "string | integer" to "LuaEventType"
--- Resolved in 2.0.29, this patch will be removed was version is stable
---@param event LuaEventType ID or name of the event to raise.
---@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.
raise_event = function(event, data) end;
}
---@class LuaObject:userdata
--https://github.com/justarandomgeek/vscode-factoriomod-debug/issues/165