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
on:
push:
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Install FMTK
run: |
# Pinned: 2.1.4+ generates typedefs targeting EmmyLua that LuaLS misreads
pnpm install factoriomod-debug@2.1.3
pnpm exec fmtk luals-addon
jq '.["workspace.library"] += ["${{ github.workspace }}/factorio/library"] | .["runtime.plugin"] = "${{ github.workspace }}/factorio/plugin.lua"' .luarc.json > temp.luarc.json
jq -s '.[0] * .[1].settings' temp.luarc.json ${{ github.workspace }}/factorio/config.json > check.luarc.json
- name: Install LuaLS
run: |
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
mkdir luals && tar -xf lusls.tar.gz -C luals && rm lusls.tar.gz
- name: Run Lint Report
shell: bash
run: |
./luals/bin/lua-language-server --check=. --logpath=. --configpath=check.luarc.json --checklevel=Information --check_out_path=check.json
# Credit to https://github.com/Krealle/luals-check-action/blob/main/action.yml
# Although some minor fixes were needed
# Format and print the messages (would be nice to format as a table, but that's too complex for jq)
cat check.json | \
jq -r \
'to_entries | map(.key as $file | .value[] |
{
file: $file | sub("file://${{ github.workspace }}/./"; ""),
code: .code,
line: .range.start.line,
message: (.message | split("\n")
| map(if startswith("- ") then .[2:] else . end)
| join("\n")),
severity: (if .severity <= 1 then "ERR" else "WARN" end)
}) |
map("**[\(.severity)] \(.code):** \(.file)#L\(.line)<br><code>\(.message)</code>") | .[]' \
> $GITHUB_STEP_SUMMARY
echo ""
# Github Annotations (limited to 10)
cat check.json | \
jq -r \
'to_entries | map(.key as $file | .value[] |
{
file: $file | sub("file://${{ github.workspace }}/./"; ""),
title: .code,
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)
}) |
map("::\(.level) file=\(.file),line=\(.line+1),endLine=\(.line+1),col=\(.col+1),endColumn=\(.endColumn+1),title=\(.title)::\(.message) (\(.title))") | .[]'
if [[ $(wc -l < check.json) > 1 ]] ; then
exit 1
else
echo "✅ All checks succeeded!" | tee $GITHUB_STEP_SUMMARY
fi
name: Lua Lint
on:
push:
pull_request:
env:
EMMYLUA_CHECK_VERSION: "0.24.0"
CLUSTERIO: ${{ github.workspace }}/.clusterio
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkout clusterio modules
uses: actions/checkout@v4
with:
repository: clusterio/clusterio
path: .clusterio
sparse-checkout: packages/host/modules
sparse-checkout-cone-mode: false
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Generate Factorio typedefs
run: |
pnpm install factoriomod-debug
pnpm exec fmtk luals-addon "$RUNNER_TEMP"
- name: Install emmylua_check
run: |
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"
- name: Run Lint Report
shell: bash
run: |
# The typedefs are generated per run, clusterio comes from CLUSTERIO above
jq -n --arg lib "$RUNNER_TEMP/factorio/library" \
'{ workspace: { library: [ $lib ], ignoreGlobs: [ ".clusterio/**" ] } }' \
> "$RUNNER_TEMP/ci.emmyrc.json"
# Exits non zero on error severity, so the gate below is used instead
"$RUNNER_TEMP/emmylua_check" . --config ".emmyrc.json,$RUNNER_TEMP/ci.emmyrc.json" \
--output-format json --output check.json || true
# Credit to https://github.com/Krealle/luals-check-action/blob/main/action.yml
# Although some minor fixes were needed
# Format and print the messages (would be nice to format as a table, but that's too complex for jq)
jq -r --arg root "$PWD/" \
'.[] | (.file | ltrimstr($root)) as $file | .diagnostics[] |
{
file: $file,
code: .code,
line: .range.start.line,
message: (.message | split("\n")
| map(if startswith("- ") then .[2:] else . end)
| join("\n")),
severity: (if .severity <= 1 then "ERR" else "WARN" end)
} |
"**[\(.severity)] \(.code):** \(.file)#L\(.line + 1)<br><code>\(.message)</code>"' \
check.json > "$GITHUB_STEP_SUMMARY"
echo ""
# Github Annotations (limited to 10)
jq -r --arg root "$PWD/" \
'.[] | (.file | ltrimstr($root)) as $file | .diagnostics[] |
{
file: $file,
title: .code,
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/
node_modules/
.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:
- 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.
- 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.
+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 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 authorities = {}
@@ -28,13 +28,13 @@ end)
--- 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
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
--- 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
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
--- 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
--- @return LocalisedString[][], number
local function format_as_pages(commands, page_size)
local pages = { {} }
local current_page = {}
local pages = { current_page }
local page_length = 0
local current_page = 1
local total = 0
for _, command in pairs(commands) do
total = total + 1
page_length = page_length + 1
if page_length > page_size then
current_page = current_page + 1
pages[current_page] = {}
page_length = 1
current_page = {}
pages[#pages + 1] = current_page
end
local description
@@ -48,7 +48,7 @@ local function format_as_pages(commands, page_size)
end
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
return pages, total
@@ -71,7 +71,7 @@ Commands.new("commands", { "exp-commands_help.description" })
page = as_number
end
keyword = keyword:lower()
keyword = tostring(keyword):lower()
local pages, found
if cache and cache.keyword == keyword then
-- 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 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_static = {} --- @type table<string, any>
@@ -21,12 +21,10 @@ setmetatable(rcon_static, { __index = _G })
setmetatable(rcon_env, { __index = rcon_static })
--- Some common static values which can be added now
--- @diagnostic disable: name-style-check
rcon_static.Async = Async
rcon_static.ExpUtil = ExpUtil
rcon_static.Commands = Commands
rcon_static.print = Commands.print
--- @diagnostic enable: name-style-check
--- Some common callback values which are useful when a player uses the command
--- @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 parameter string
--- @diagnostic disable-next-line: invisible
--- @diagnostic disable-next-line: access-invisible
return Commands._event_handler{
name = command.name,
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 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
types.boolean =
+18 -14
View File
@@ -61,7 +61,7 @@ local Search = require("modules/exp_commands/search")
--- @type LuaPlayer?
local _print_player
--- @class Commands
--- @class (partial) Commands
local Commands = {
color = ExpUtil.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
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
Commands.types = {}
@@ -103,7 +103,7 @@ end
--- @class Commands.Argument
--- @field name string The name 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 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)
error("Command does not support rcon usage, requires LuaPlayer." .. key)
end,
}) --[[ @as LuaPlayer ]]
}) --[[@as LuaPlayer]]
--- Status Returns.
-- 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)
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
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
--- 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
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
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
--- 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
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
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
--- 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
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
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
--- 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
--- @package
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
--- @type table<Commands.Status, string>
@@ -281,7 +285,7 @@ end
--- @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
--- @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 input_parser T The function used to parse and validate the data type
--- @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
--- 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)
Commands.types[data_type] = nil
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
--- @param name string The name 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
function Commands._prototype:argument(name, description, input_parser)
assert_command_mutable(self)
@@ -454,7 +458,7 @@ end
--- Add a new optional argument to the command of the given data type
--- @param name string The name 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
function Commands._prototype:optional(name, description, input_parser)
assert_command_mutable(self)
+3 -2
View File
@@ -3,7 +3,7 @@ local Search = {}
local Storage = require("modules/exp_util/storage")
--- 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>>
Storage.register({
pending,
@@ -50,6 +50,7 @@ function Search.prepare(custom_commands)
name = name,
description = locale_desc,
help_text = locale_desc,
usage = locale_desc,
aliases = {},
}
end
@@ -65,7 +66,7 @@ function Search.on_player_locale_changed(event)
local ids = player.request_translations(required_translations)
assert(ids, "Translation ids was nil")
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
+1 -1
View File
@@ -3,7 +3,7 @@ Adds permission group syncing to clusterio
]]
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
--- @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
]]
--- @diagnostic disable: global-element
--- @diagnostic disable: global-in-non-module
-- Access using `/sc exp_groups.foo()`
exp_groups = require("modules/exp_groups/control")
+17 -12
View File
@@ -16,7 +16,7 @@ Storage.register(player_elements, function(tbl)
player_elements = tbl
end)
--- @class Gui
--- @class (partial) Gui
local Gui = {
define = ExpElement.new,
from_argument = ExpElement.from_argument,
@@ -46,9 +46,11 @@ end
--- @return LuaPlayer
function Gui.get_player(input)
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
return assert(game.get_player(input.player_index))
--- @cast input LuaGuiElement | { player_index: uint }
return (assert(game.get_player(input.player_index)))
end
--- Toggle the enable state of an element
@@ -88,7 +90,7 @@ end
--- @param define ExpElement
--- @param visible Gui.VisibleCallback | boolean | nil
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
end
@@ -96,7 +98,7 @@ end
--- @param define ExpElement
--- @param visible Gui.VisibleCallback | boolean | nil
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
end
@@ -105,7 +107,7 @@ end
--- @param define ExpElement
--- @param visible Gui.VisibleCallback | boolean | nil
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
end
@@ -114,7 +116,8 @@ end
--- @param player LuaPlayer
--- @return LuaGuiElement
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
--- Register a element define to be drawn to the left flow on join
@@ -122,7 +125,8 @@ end
--- @param player LuaPlayer
--- @return LuaGuiElement
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
--- Register a element define to be drawn to the relative flow on join
@@ -130,7 +134,8 @@ end
--- @param player LuaPlayer
--- @return LuaGuiElement
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
--- 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
if Gui.toolbar then
--- @diagnostic disable-next-line invisible
--- @diagnostic disable-next-line: access-invisible
Gui.toolbar._create_elements(player)
--- @diagnostic disable-next-line invisible
--- @diagnostic disable-next-line: access-invisible
Gui.toolbar._ensure_consistency(player)
end
end
@@ -211,7 +216,7 @@ local function on_gui_opened(event)
if visible then
event.element = element
--- @diagnostic disable-next-line invisible
--- @diagnostic disable-next-line: access-invisible
define:raise_event(event)
end
end
+6 -2
View File
@@ -62,6 +62,7 @@ local GuiData = {
--- @field player_data table<uint, any>
--- @field force_data table<uint, any>
--- @field global_data table
--- @field [DataKey] any
-- This class has no prototype methods
-- 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.")
local object_name = key.object_name --- @diagnostic disable-line assign-type-mismatch
if object_name == "LuaGuiElement" then
--- @cast key LuaGuiElement
local data = self._raw.element_data
local player_elements = data and data[key.player_index]
return player_elements and player_elements[key.index]
elseif object_name == "LuaPlayer" then
--- @cast key LuaPlayer
local data = self._raw.player_data
return data and data[key.index]
elseif object_name == "LuaForce" then
--- @cast key LuaForce
local data = self._raw.force_data
return data and data[key.index]
else
@@ -153,7 +157,7 @@ end
--- @param scope string
--- @return GuiData
function GuiData.get(scope)
return GuiData._scopes[scope] --[[ @as GuiData ]]
return GuiData._scopes[scope] --[[@as GuiData]]
end
--- 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
local data = scope._raw.element_data
local player_elements = data and data[player_index]
if player_elements then
if data and player_elements then
player_elements[element_index] = nil
if not next(player_elements) then
data[player_index] = nil
+17 -17
View File
@@ -1,4 +1,4 @@
--- @class Gui
--- @class (partial) Gui
local Gui = require("modules/exp_gui")
--- @class Gui.elements
@@ -28,7 +28,7 @@ Elements.aligned_flow = Gui.define("aligned_flow")
vertically_stretchable = vertical_align ~= "center",
horizontally_stretchable = horizontal_align ~= "center",
}
end) --[[ @as any ]]
end) --[[@as any]]
--- A solid horizontal white bar element
--- @class Gui.elements.bar: ExpElement
@@ -48,11 +48,11 @@ Elements.bar = Gui.define("bar")
else
style.horizontally_stretchable = true
end
end) --[[ @as any ]]
end) --[[@as any]]
--- A label which is centered
--- @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")
:draw{
type = "label",
@@ -63,7 +63,7 @@ Elements.centered_label = Gui.define("centered_label")
horizontal_align = "center",
single_line = false,
width = Gui.from_argument(1),
} --[[ @as any ]]
} --[[@as any]]
--- A label which has two white bars on either side of it
--- @class Gui.elements.title_label: ExpElement
@@ -91,7 +91,7 @@ Elements.title_label = Gui.define("title_label")
Elements.bar(flow)
return label
end) --[[ @as any ]]
end) --[[@as any]]
--- A fixed size vertical scroll pane
--- @class Gui.elements.scroll_pane: ExpElement
@@ -109,7 +109,7 @@ Elements.scroll_pane = Gui.define("scroll_pane")
padding = { 1, 3 },
maximal_height = Gui.from_argument(1),
horizontally_stretchable = true,
} --[[ @as any ]]
} --[[@as any]]
--- A fixed size vertical scroll pane containing a table
--- @class Gui.elements.scroll_table: ExpElement
@@ -132,7 +132,7 @@ Elements.scroll_table = Gui.define("scroll_table")
cell_padding = 1,
vertical_align = "center",
horizontally_stretchable = true,
} --[[ @as any ]]
} --[[@as any]]
--- A container frame
--- @class Gui.elements.container: ExpElement
@@ -159,13 +159,13 @@ Elements.container = Gui.define("container")
vertically_stretchable = false,
horizontally_stretchable = false,
minimal_width = Gui.from_argument(1),
} --[[ @as any ]]
} --[[@as any]]
--- Get the root element of a container
--- @param container LuaGuiElement
--- @return LuaGuiElement
function Elements.container.get_root_element(container)
return container.parent
return assert(container.parent)
end
--- A frame within a container
@@ -183,7 +183,7 @@ Elements.subframe_base = Gui.define("container_subframe")
padding = { 3, 6, 0, 6 },
use_header_filler = false,
horizontally_stretchable = true,
} --[[ @as any ]]
} --[[@as any]]
--- @class Gui.elements.header.opts
--- @field name string?
@@ -212,7 +212,7 @@ Elements.header = Gui.define("container_header")
subframe.add{ type = "empty-widget" }.style.horizontally_stretchable = true
return subframe
end) --[[ @as any ]]
end) --[[@as any]]
--- @class Gui.elements.footer.opts
--- @field name string?
@@ -241,7 +241,7 @@ Elements.footer = Gui.define("container_footer")
subframe.add{ type = "empty-widget" }.style.horizontally_stretchable = true
return subframe
end) --[[ @as any ]]
end) --[[@as any]]
--- A button used to destroy its target when clicked, intended for screen frames
--- @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)
--- @cast def Gui.elements.screen_frame_close
Gui.destroy_if_valid(def.data[element])
end) --[[ @as any ]]
end) --[[@as any]]
--- A draggable frame with close button and button flow
--- @class Gui.elements.screen_frame: ExpElement
@@ -313,20 +313,20 @@ Elements.screen_frame = Gui.define("screen_frame")
direction = "vertical",
style = "inside_shallow_frame_packed",
}
end) --[[ @as any ]]
end) --[[@as any]]
--- Get the button flow for a screen frame
--- @param screen_frame LuaGuiElement
--- @return LuaGuiElement
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
--- Get the root element of a screen frame
--- @param screen_frame LuaGuiElement
--- @return LuaGuiElement
function Elements.screen_frame.get_root_element(screen_frame)
return screen_frame.parent
return assert(screen_frame.parent)
end
return Elements
+1 -3
View File
@@ -166,7 +166,6 @@ end
function GuiIter.get_tracked_elements(scope, filter)
local class_name = ExpUtil.get_class_name(filter)
if class_name == "nil" then
--- @cast filter nil
return GuiIter.all_elements(scope)
elseif class_name == "LuaPlayer" then
--- @cast filter LuaPlayer
@@ -189,7 +188,6 @@ end
function GuiIter.get_online_elements(scope, filter)
local class_name = ExpUtil.get_class_name(filter)
if class_name == "nil" then
--- @cast filter nil
return GuiIter.filtered_elements(scope, game.connected_players)
elseif class_name == "LuaPlayer" then
--- @cast filter LuaPlayer
@@ -235,7 +233,7 @@ end
function GuiIter.remove_element(scope, player_index, element_index)
local scope_elements = registered_scopes[scope]
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
player_elements[element_index] = nil
end
+5 -3
View File
@@ -43,6 +43,8 @@ ExpElement.events = {}
--- @field _force_data ExpElement.PostDrawCallback?
--- @field _global_data ExpElement.PostDrawCallback?
--- @field _events table<defines.events, ExpElement.EventHandler<EventData>[]>
--- @field _has_handlers boolean
--- @field _track_elements boolean
--- @overload fun(parent: LuaGuiElement, ...: any): LuaGuiElement
ExpElement._prototype = {
_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)
end
@@ -166,7 +168,7 @@ end
--- @param name string
--- @return ExpElement
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
--- Create a new instance of this element definition
@@ -460,7 +462,7 @@ function ExpElement._prototype:raise_event(event)
for _, handler in ipairs(handlers) do
-- 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
handler(self, player --[[ @as LuaPlayer ]], event.element, event --[[ @as EventData ]])
handler(self, player --[[@as LuaPlayer]], event.element, event --[[@as EventData]])
end
end
+1 -1
View File
@@ -1,4 +1,4 @@
--- @class Gui
--- @class (partial) Gui
local Gui = require("modules/exp_gui")
--- @class Gui.styles
+18 -16
View File
@@ -1,5 +1,5 @@
--- @class Gui
--- @class (partial) Gui
local Gui = require("modules/exp_gui")
local ExpElement = require("modules/exp_gui/prototype")
local mod_gui = require("mod-gui")
@@ -29,7 +29,7 @@ Toolbar.on_gui_button_toggled = script.generate_event_name()
--- @class _ExpElement._prototype
--- @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)
return self:on_event(Toolbar.on_gui_button_toggled, handler)
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
-- Make the extra required adjustments
local style = button.style
local style = button.style --[[@as LuaStyle]]
style.minimal_width = original_width
style.maximal_height = original_height
if button.type == "sprite-button" then
@@ -335,9 +335,10 @@ Below here is the toolbar settings GUI and its associated functions
--- @param dst LuaGuiElement
local function copy_style(src, dst)
dst.style = src.style.name
dst.style.height = toolbar_button_small
dst.style.width = toolbar_button_small
dst.style.padding = -2
local style = dst.style --[[@as LuaStyle]]
style.height = toolbar_button_small
style.width = toolbar_button_small
style.padding = -2
end
--- 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
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)
-- 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 left_index = 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
-- 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 order Gui.ToolbarOrder
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 top_flow = Gui.get_top_flow(player)
@@ -466,7 +467,7 @@ end
function Toolbar.get_state(player)
-- Get the order of toolbar buttons
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
order[index] = { name = item.name, favourite = elements.toolbar_list_item.data[item].set_favourite.state }
end
@@ -487,7 +488,7 @@ end
--- @param player LuaPlayer
function Toolbar._create_elements(player)
-- 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
for define in pairs(Gui.top_elements) do
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
local children = toolbar_list.children
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
-- Set the state of the move buttons for the first and last element
@@ -513,7 +515,7 @@ end
--- @param player LuaPlayer
function Toolbar._ensure_consistency(player)
-- 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
-- Update the visible state based on if the player is allowed the button
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,
})
: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)
end)
@@ -634,7 +636,7 @@ elements.move_item_down = Gui.define("move_item_down")
size = toolbar_button_small,
})
: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)
end)
@@ -658,7 +660,7 @@ elements.set_favourite = Gui.define("set_favourite")
width = 180,
}
: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 had_visible = Toolbar.has_visible_buttons(player)
top_element.visible = element.state
+2
View File
@@ -24,6 +24,7 @@ local afk_time_units = {
}
return {
--- @type table<string, LocalisedString | fun(player: LuaPlayer, is_command: boolean): LocalisedString>
messages = { --- @setting messages will trigger when ever the word is said
["discord"] = { "info.discord" },
["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_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)
--- @type table<string, LocalisedString | fun(player: LuaPlayer, is_command: boolean): LocalisedString>
commands = { --- @setting commands will trigger only when command prefix is given
["dev"] = { "exp_chat-auto-reply.reply-dev" },
["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
--- 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)
get_selected_player, set_selected_action = player_getter, action_setter
end
@@ -31,7 +32,7 @@ end
-- gets the action player and a coloured name for the action to be used on
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)
return selected_player, selected_player_color
end
+6 -6
View File
@@ -87,7 +87,7 @@ return {
amount = 4000,
size = { 26, 27 },
-- offset = {-64,-32}
offset = { -64, -64 },
offset = { x = -64, y = -64 },
},
{
enabled = false,
@@ -95,7 +95,7 @@ return {
amount = 4000,
size = { 26, 27 },
-- offset = {-64, 0}
offset = { 64, -64 },
offset = { x = 64, y = -64 },
},
{
enabled = false,
@@ -103,7 +103,7 @@ return {
amount = 4000,
size = { 22, 20 },
-- offset = {-64, 32}
offset = { -64, 64 },
offset = { x = -64, y = 64 },
},
{
enabled = false,
@@ -111,7 +111,7 @@ return {
amount = 4000,
size = { 22, 20 },
-- offset = {-64, -64}
offset = { 64, 64 },
offset = { x = 64, y = 64 },
},
{
enabled = false,
@@ -119,7 +119,7 @@ return {
amount = 4000,
size = { 22, 20 },
-- offset = {-64, -96}
offset = { 0, 64 },
offset = { x = 0, y = 64 },
},
},
},
@@ -132,7 +132,7 @@ return {
num_patches = 4,
amount = 4000000,
-- offset = {-80, -12},
offset = { -12, 64 },
offset = { x = -12, y = 64 },
-- offset_next = {0, 6}
offset_next = { 6, 0 },
},
+14
View File
@@ -35,6 +35,20 @@ return {
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 properties:
+1
View File
@@ -2,6 +2,7 @@
-- @config Warnings
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
-- if a localized string is used then __1__ will by_player_name and __2__ will be the current warning count (auto inserted)
{ "warnings.received", "" },
+16 -2
View File
@@ -149,9 +149,23 @@ PlayerData.Statistics:combine('JoinCount')
local Storage = require("modules/exp_util/storage")
local DatastoreManager = {}
local Datastores = {}
local Datastore = {}
local Datastores = {} --- @type table<string, Datastore>
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 trace = debug.traceback
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 External = {}
@@ -29,12 +30,13 @@ end
]]
function External.valid()
if storage.ext == nil then return false end
if ext == storage.ext and var == ext.var then
local stored = storage.ext
if stored == nil then return false end
if ext == stored and var == ext.var then
return var ~= nil
else
ext = storage.ext
var = ext.var
ext = stored
var = stored.var
return var ~= nil
end
end
@@ -48,7 +50,7 @@ local servers = External.get_servers()
]]
function External.get_servers()
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
--[[-- 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.")
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")
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
--[[-- 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)
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")
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
--[[-- 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)
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
assert(type(input_action) == "number", tostring(action) .. " is not a valid input action")
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
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
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 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 = {
_prototype = {},
config = {
order = {}, -- Contains the order of the roles, lower index is better
roles = {}, -- Contains the raw info for the roles, indexed by role name
order = {}, --- @type string[] Contains the order of the roles, lower index is better
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
internal = {}, -- Contains all internally accessed roles, such as root, default
players = {}, -- Contains the roles that players have
@@ -200,7 +217,7 @@ function Roles.debug()
local output = ""
for index, role_name in ipairs(Roles.config.order) do
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)
output = output .. string.format("\n%s %s) %s[/color]", color_str, index, serpent.line(role))
end
@@ -287,6 +304,7 @@ local role = Roles.get_role_by_name(2)
]]
function Roles.get_role_by_order(index)
local name = Roles.config.order[index]
if not name then return end
return Roles.config.roles[name]
end
@@ -348,16 +366,17 @@ end
local role = Roles.get_player_highest_role(game.player)
]]
--- @return Roles.Role
function Roles.get_player_highest_role(player)
local roles = Roles.get_player_roles(player)
local highest
local highest --- @type Roles.Role?
for _, role in ipairs(roles) do
if not highest or role.index < highest.index then
highest = role
end
end
return highest
return (assert(highest, "Player has no roles"))
end
--- 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
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 {}
for _, role in ipairs(role_objects) do
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)
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({
name = 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)
ExpUtil.assert_not_runtime()
if use_factorio_api then
self.permission_group = { true, name }
self.permission_group = { true, name } --[[@as [boolean, string] ]]
else
local group = Groups.get_group_by_name(name)
if not group then return end
assert(Groups.get_group_by_name(name), "Permission group not found: " .. name)
self.permission_group = name
end
return self
@@ -1115,8 +1133,9 @@ local function role_update(event)
-- Updates the players permission group
local highest = Roles.get_player_highest_role(player)
if highest.permission_group then
if highest.permission_group[1] then
local group = game.permissions.get_group(highest.permission_group[2])
local permission_group = highest.permission_group --[[@as [boolean, string] ]]
if permission_group[1] then
local group = game.permissions.get_group(permission_group[2])
if group then
Groups.add_to_permission_group_async(group, player)
end
@@ -34,7 +34,7 @@ for _, config_key in ipairs{ "always_protected_names", "always_protected_types",
end
-- Require roles if a permission is assigned in the config
local Roles
local Roles --- @type table<string, any>
if config.ignore_permission then
Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
end
@@ -4,7 +4,7 @@ local Gui = require("modules/exp_gui")
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
----- Locals -----
local follow_label -- Gui constructor
local follow_label --- @type ExpElement Gui constructor
local following = {}
local spectating = {}
local Public = {}
+19 -18
View File
@@ -14,10 +14,10 @@ local mega = 1000000
local vlayer = {}
local vlayer_data = {
entity_interfaces = {
energy = {},
circuit = {},
storage_input = {},
storage_output = {},
energy = {}, --- @type LuaEntity[]
circuit = {}, --- @type LuaEntity[]
storage_input = {}, --- @type LuaEntity[]
storage_output = {}, --- @type LuaEntity[]
},
properties = {
total_surface_area = 0,
@@ -28,10 +28,10 @@ local vlayer_data = {
capacity = 0,
},
storage = {
items = {},
power_items = {},
items = {}, --- @type table<string, number>
power_items = {}, --- @type table<string, { value: number, count: number }>
energy = 0,
unallocated = {},
unallocated = {}, --- @type table<string, number>
},
surface = table.deep_copy(config.surface),
}
@@ -45,7 +45,7 @@ for name, properties in pairs(config.allowed_items) do
if properties.power then
vlayer_data.storage.power_items[name] = {
value = properties.fuel_value * 1000000,
value = assert(properties.fuel_value) * 1000000,
count = 0,
}
end
@@ -361,7 +361,7 @@ local function handle_input_interfaces()
if not interface.valid then
vlayer_data.entity_interfaces.storage_input[index] = nil
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
if config.allowed_items[v.name] then
@@ -384,8 +384,9 @@ local function handle_input_interfaces()
if count_deduct and count_add then
if config.allowed_items[v.name].modded then
local modded_item = assert(config.modded_items[v.name])
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
vlayer.insert_item(v.name, count_add)
end
@@ -439,14 +440,14 @@ local function handle_output_interfaces()
if not interface.valid then
vlayer_data.entity_interfaces.storage_output[index] = nil
else
local inventory = interface.get_inventory(defines.inventory.chest)
local inventory_request_sections = interface.get_logistic_sections().sections
local inventory = assert(interface.get_inventory(defines.inventory.chest))
local inventory_request_sections = assert(interface.get_logistic_sections()).sections
for i = 1, #inventory_request_sections do
for _, v in pairs(inventory_request_sections[i].filters) do
if v.value and config.allowed_items[v.value.name] then
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
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
vlayer_data.entity_interfaces.circuit[index] = nil
else
local circuit_oc = interface.get_or_create_control_behavior()
if circuit_oc.sections_count == 0 then
circuit_oc.add_section()
local control = interface.get_or_create_control_behavior() --[[@as LuaConstantCombinatorControlBehavior]]
if control.sections_count == 0 then
control.add_section()
end
circuit_oc = circuit_oc.sections[1]
local circuit_oc = assert(control.sections[1])
local signal_index = 1
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)
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
end
@@ -107,7 +107,7 @@ function Warnings.add_warning(player, by_player_name, reason)
reason = reason or "None given."
local warning_count
local warning_count --- @type number
PlayerWarnings:update(player.name, function(_, warnings)
local warning = {
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 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
end)
@@ -126,19 +126,19 @@ lib.collect_loginet = function()
end
if config.modules.logistorage then
for name, v in pairs(network.get_contents()) do
stats.items[name] = (stats.items[name] or 0) + v
for _, item in pairs(network.get_contents()) do
stats.items[item.name] = (stats.items[item.name] or 0) + item.count
end
-- pickups and deliveries of items
for _, point_list in pairs{ network.provider_points, network.requester_points, network.storage_points } do
for _, point in pairs(point_list) do
for name, qty in pairs(point.targeted_items_pickup) do
stats.pickups[name] = (stats.pickups[name] or 0) + qty
for _, item in pairs(point.targeted_items_pickup) do
stats.pickups[item.name] = (stats.pickups[item.name] or 0) + item.count
end
for name, qty in pairs(point.targeted_items_deliver) do
stats.deliveries[name] = (stats.deliveries[name] or 0) + qty
for _, item in pairs(point.targeted_items_deliver) do
stats.deliveries[item.name] = (stats.deliveries[item.name] or 0) + item.count
end
end
end
@@ -2,6 +2,6 @@ local Gui = require("modules/exp_gui")
local Roles = require("modules.exp_legacy.expcore.roles")
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_unassigned, Gui._ensure_consistency)
+15 -13
View File
@@ -22,9 +22,9 @@ local function aabb_align_expand(aabb)
}
end
local vlayer_container
local vlayer_gui_control_type
local vlayer_gui_control_list
local vlayer_container --- @type ExpElement
local vlayer_gui_control_type --- @type ExpElement
local vlayer_gui_control_list --- @type ExpElement
local vlayer_control_type_list = {
[1] = "energy",
@@ -87,10 +87,10 @@ SelectArea:on_selection(function(event)
local container = Gui.get_left_element(vlayer_container, player)
local disp = container.frame["vlayer_st_2"].disp.table
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 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 }
else
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_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" }
return
end
@@ -325,7 +325,9 @@ local function vlayer_gui_list_refresh(player)
local interface = vlayer.get_interfaces()[vlayer_control_type_list[target]]
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
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{
width = 200,
}:on_click(function(def, player, element, event)
local target = element.parent[vlayer_gui_control_type.name].selected_index
local n = element.parent[vlayer_gui_control_list.name].selected_index
local target = assert(element.parent)[vlayer_gui_control_type.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
local i = vlayer.get_interfaces()
local entity = i[vlayer_control_type_list[target]][n]
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.print{ "vlayer.result-interface-location", { "vlayer.control-type-" .. vlayer_control_type_list[target]:gsub("_", "-") }, pos_to_gps_string(entity.position, entity.surface.name) }
end
@@ -423,14 +424,15 @@ local vlayer_gui_control_remove = Gui.define("vlayer_gui_control_remove")
}:style{
width = 200,
}:on_click(function(def, player, element)
local target = element.parent[vlayer_gui_control_type.name].selected_index
local n = element.parent[vlayer_gui_control_list.name].selected_index
local target = assert(element.parent)[vlayer_gui_control_type.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
local i = vlayer.get_interfaces()
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
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)
:on_click(function(def, player, element)
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)
-- 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,
}
: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)
player.set_controller{ type = defines.controllers.remote, position = warp.position, surface = warp.surface }
end)
@@ -271,9 +271,9 @@ local warp_textfield = Gui.define("warp_textfield")
right_margin = 2,
}
: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_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
Warps.set_editing(warp_id, 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)
:on_click(function(def, player, element)
local warp_id = element.parent.caption
local warp_name = element.parent.parent["name-" .. warp_id][warp_textfield.name].text
local warp_icon = element.parent.parent["icon-" .. warp_id][warp_icon_editing.name].elem_value --[[ @as SignalID ]]
local parent = assert(element.parent)
local grandparent = assert(parent.parent)
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
Warps.set_editing(warp_id, 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)
: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.
local warp = Warps.get_warp(warp_id)
if warp.updates == 1 then
@@ -333,7 +337,7 @@ local remove_warp_button = Gui.define("remove_warp_button")
}
:style(Styles.sprite22)
:on_click(function(def, player, element)
local warp_id = element.parent.caption
local warp_id = assert(element.parent).caption
Warps.remove_warp(warp_id)
end)
@@ -349,7 +353,7 @@ local edit_warp_button = Gui.define("edit_warp_button")
}
:style(Styles.sprite22)
: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)
end)
@@ -429,8 +433,8 @@ local function update_warp_elements(element, warp, warp_player_is_on, on_cooldow
-- Check if button element is valid
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 warp_status_element = element.parent.parent["name-" .. warp.warp_id][warp_status.name]
local label_style = assert(element.parent).parent["name-" .. warp.warp_id][warp_label.name].style
local warp_status_element = assert(element.parent).parent["name-" .. warp.warp_id][warp_status.name]
-- If player is not on a warp
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
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)
scroll_table.parent.vertical_scroll_policy = "always"
assert(scroll_table.parent).vertical_scroll_policy = "always"
-- Change the style of the scroll table
local scroll_table_style = scroll_table.style
@@ -778,7 +782,7 @@ Event.on_nth_tick(math.floor(60 / config.update_smoothing), function()
end
-- 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
if #warp_ids > 0 then
local surface = player.surface
@@ -838,7 +842,7 @@ end)
Event.add(defines.events.on_player_created, function(event)
-- If the force has no spawn then make a spawn warp
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)
if not spawn_id then
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
local allow_add_warp = check_player_permissions(player, "allow_add_warp")
-- 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
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 compat = require("modules/clusterio/compat")
local compat = require("modules/clusterio/compat") --[[@as LibCompat]]
local Async = require("modules/exp_util/async")
--- @class ExpRoles
@@ -284,7 +284,7 @@ local server_role = setmetatable({
--- @param player LuaPlayer | string | nil
--- @return ExpRoles.Role[]
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
if player_name == nil then return { server_role } end
@@ -399,7 +399,7 @@ end
--- @param self ExpRoles.Role
--- @param action string
--- @return boolean
function Role:is_allowed(action)
function Role.is_allowed(self, action)
local allowed = self.allowed_actions
return allowed["core.admin"] or allowed[permission_from_action(action)] or false
end
@@ -408,7 +408,7 @@ end
--- @param self ExpRoles.Role
--- @param name string
--- @return boolean
function Role:has_flag(name)
function Role.has_flag(self, name)
return self.allowed_actions[permission_from_flag(name)] or false
end
@@ -416,7 +416,7 @@ end
--- @param self ExpRoles.Role
--- @param online boolean? When given, filter by connected state
--- @return LuaPlayer[]
function Role:get_players(online)
function Role.get_players(self, online)
local players = {}
for player_name, role_names in pairs(ExpRoles.config.players) do
for _, role_name in pairs(role_names) do
@@ -437,7 +437,7 @@ end
--- @param self ExpRoles.Role
--- @param message LocalisedString
--- @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)
for _, player in pairs(players) do
player.print(message)
@@ -678,7 +678,7 @@ end
--- @param silent boolean?
--- @param sync boolean
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
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 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,
events = {
[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,
},
}
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
]]
--- @diagnostic disable: global-element
--- @diagnostic disable: global-in-non-module
-- Access using `/sc exp_roles.foo()`
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 highest_role = Roles.get_player_highest_role
local types = {} --- @class Commands.types
local types = {} --- @class (partial) Commands.types
--- A role defined by exp 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 = {}
--- @param player LuaPlayer
--- @param area BoundingBox
--- @param area BoundingBox.struct
--- @return boolean
local function location_break(player, area)
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
return true
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
SelectArea:start(player)
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
SelectArea:on_selection(function(event)
@@ -63,13 +63,14 @@ SelectArea:on_selection(function(event)
}
local count = 0
local hits = {} --- @type MapPosition[]
local hits = {} --- @type MapPosition.struct[]
for _, entity in ipairs(entities) do
local skip = false
local entity_position = entity.position
for _, pos in ipairs(hits) do
local x = abs(entity.position.x - pos.x)
local y = abs(entity.position.y - pos.y)
local x = abs(entity_position.x - pos.x)
local y = abs(entity_position.y - pos.y)
if x * x + y * y < 36 then
skip = true
break
+1 -1
View File
@@ -41,7 +41,7 @@ local function get_server_id(server)
elseif status == "Offline" then
return false, { "exp-commands_connect.offline", server_details.name }
end
return true, server_id
return true, server_id --[[@as string]]
elseif server_count_before > 0 then
return false, { "exp-commands_connect.wrong-version", concat(server_names_before, ", ") }
else
+1 -1
View File
@@ -25,7 +25,7 @@ Commands.new("kill", { "exp-commands_kill.description" })
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 }
end
other_player.character.die()
assert(other_player.character).die()
else
return Commands.status.unauthorised{ "exp-commands_kill.lower-role" }
end
+1 -1
View File
@@ -22,7 +22,7 @@ commands.lawnmower = Commands.new("lawnmower", { "exp-commands_lawnmower.descrip
SelectArea:start(player)
return Commands.status.success{ "exp-commands_lawnmower.enter" }
end) --[[ @as any ]]
end) --[[@as any]]
--- When an area is selected to be handled
SelectArea:on_selection(function(event)
@@ -37,7 +37,7 @@ end
--- Get the key used in protected_areas
--- TODO expose this from EntityProtection
--- @param area BoundingBox
--- @param area BoundingBox.struct
--- @return string
local function get_area_key(area)
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 key = get_entity_key(entity)
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{
sprite = "utility/notification",
target = entity,
target_offset = {
(rb.x - entity.position.x) * 0.75,
(rb.y - entity.position.y) * 0.75,
(rb.x - position.x) * 0.75,
(rb.y - position.y) * 0.75,
},
x_scale = 2,
y_scale = 2,
@@ -67,7 +69,7 @@ end
--- Show a protected area to a player
--- @param player LuaPlayer
--- @param surface LuaSurface
--- @param area BoundingBox
--- @param area BoundingBox.struct
local function show_protected_area(player, surface, area)
local key = get_area_key(area)
if renders[player.index][key] then return end
@@ -7,7 +7,7 @@ local Storage = require("modules/exp_util/storage")
--- Storage variables
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({
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_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
--- @param c1 number
--- @param c2 number
@@ -21,8 +27,8 @@ local function step_component(c1, c2)
end
--- Wraps all components of a colour ensuring it remains valid
--- @param color Color
--- @return Color
--- @param color ExpCommands_Rainbow.Color
--- @return ExpCommands_Rainbow.Color
local function step_color(color)
color.r, color.g = step_component(color.r, color.g)
color.g, color.b = step_component(color.g, color.b)
@@ -32,9 +38,9 @@ local function step_color(color)
end
--- Get the next colour in the rainbow by the given step
--- @param color Color
--- @param color ExpCommands_Rainbow.Color
--- @param step number
--- @return Color
--- @return ExpCommands_Rainbow.Color
local function next_color(color, step)
step = step or 0.1
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
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
for _, ingredient in ipairs(ingredients) do
@@ -43,7 +43,7 @@ Commands.new("ratio", { "exp-commands_ratio.description" })
for i, product in ipairs(products) do
Commands.print{
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
}
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
--- @type Commands.InputParser
--- @param input string
--- @param player LuaPlayer
--- @return Commands.Status
--- @return LuaPlayer | LocalisedString
local function reportable_player(input, player)
local success, status, result = parse_input(input, player, Commands.types.player)
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
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 }
for _, player in ipairs(game.connected_players) do
if player.admin then
player.print(admin_message)
for _, connected_player in ipairs(game.connected_players) do
if connected_player.admin then
connected_player.print(admin_message)
else
player.print(user_message)
connected_player.print(user_message)
end
end
else
+2 -3
View File
@@ -42,7 +42,7 @@ Commands.new("get-roles", { "exp-commands_roles.description-get" })
--- @cast other_player LuaPlayer?
local roles = get_roles_ordered()
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
roles = get_player_roles(other_player)
response[1] = "exp-commands_roles.list-player"
@@ -55,8 +55,7 @@ Commands.new("get-roles", { "exp-commands_roles.description-get" })
end
local last = #roles_formatted
--- @diagnostic disable-next-line nil-check
roles_formatted[last] = roles_formatted[last][2]
roles_formatted[last] = assert(roles_formatted[last])[2]
return Commands.status.success(response)
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
--- 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)
-- First Case - internal name is given
-- Second Case - rich text is given
@@ -88,7 +91,7 @@ local function sort_results(results, func)
end
end
return sorted
return sorted --[[@as SearchResult[] ]]
end
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)
--- Return the amount of an item a player has
--- @type SortFunction
--- @param data SearchResult
--- @return number
local function sort_by_count(data)
return data.count
end
+1 -1
View File
@@ -69,7 +69,7 @@ commands.clear_blueprints = Commands.new("clear-blueprints", { "exp-commands_sur
SelectArea:start(player)
return Commands.status.success{ "exp-commands_surface.enter" }
end) --[[ @as any ]]
end) --[[@as any]]
--- When an area is selected
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
return Commands.status.error{ "exp-commands_teleport.unavailable" }
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Teleports a player to you.
--- @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
return Commands.status.error{ "exp-commands_teleport.unavailable" }
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Teleports you to a player.
--- @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
return Commands.status.error{ "exp-commands_teleport.unavailable" }
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Teleport to spawn
--- @class ExpCommands_Teleport.commands.spawn: ExpCommand
@@ -92,7 +92,7 @@ commands.spawn = Commands.new("spawn", { "exp-commands_teleport.description-spaw
else
return Commands.status.unauthorised()
end
end) --[[ @as any ]]
end) --[[@as any]]
return {
commands = commands,
+2 -2
View File
@@ -10,7 +10,7 @@ local format_number = require("util").format_number
local commands = {}
--- 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?)
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)
@@ -32,7 +32,7 @@ commands.set_trains_to_automatic = Commands.new("set-trains-to-automatic", { "ex
end
game.print{ "exp-commands_trains.response", format_player_name(player), format_number(#trains, false) }
end) --[[ @as any ]]
end) --[[@as any]]
return {
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 script_warnings = Warnings.get_script_warnings(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
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 }
@@ -47,12 +47,12 @@ Commands.new("get-warnings", { "exp-commands_warnings.description-get" })
for player_name, player_warnings in pairs(warnings) do
local player_name_formatted = format_player_name(player_name)
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
for player_name, player_warnings in pairs(script_warnings) do
if not warnings[player_name] then
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
+2 -2
View File
@@ -36,7 +36,7 @@ commands.waterfill = Commands.new("waterfill", { "exp-commands_waterfill.descrip
SelectArea:start(player)
return Commands.status.success{ "exp-commands_waterfill.enter" }
end
end) --[[ @as any ]]
end) --[[@as any]]
--- When an area is selected to be converted to water
SelectArea:on_selection(function(event)
@@ -70,7 +70,7 @@ SelectArea:on_selection(function(event)
if #chests > 0 then
for _, chest in pairs(chests) do
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 } }
chest.destroy()
else
+1 -1
View File
@@ -8,7 +8,7 @@ local floor = math.floor
--- Give a player their starting items
--- @param player LuaPlayer
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 insert_param = { name = "", count = 0 }
local insert = player.insert
@@ -26,11 +26,12 @@ local function on_entity_damaged(event)
-- Outputs the message as floating text
if message then
local entity_position = entity.position
local entity_radius = max(1, entity.get_radius())
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 }
FlyingText.create{
@@ -31,7 +31,7 @@ local function create_map_tag(corpse_data)
message = message .. " at " .. time
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,
icon = config.map_icon,
text = message,
@@ -42,7 +42,7 @@ local function format_position(pos)
end
--- Convert an area to a string
--- @param area BoundingBox
--- @param area BoundingBox.struct
--- @return string
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)
@@ -137,7 +137,8 @@ local function on_player_ammo_inventory_changed(event)
if not player or not player.character then return end
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
return
end
@@ -16,10 +16,9 @@ end
--- Replace a tile with the next tile in the degrade chain
--- @param surface LuaSurface
--- @param position MapPosition
--- @param position MapPosition.struct
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)
local tile = surface.get_tile(position.x, position.y)
local tile_name = tile.name
local degrade_tile_name = config.degrade_order[tile_name]
if not degrade_tile_name then return end
@@ -33,8 +32,9 @@ local function degrade_entity(entity)
local tiles = {}
local surface = entity.surface
local left_top = entity.bounding_box.left_top
local right_bottom = entity.bounding_box.right_bottom
local bounding_box = entity.bounding_box
local left_top = bounding_box.left_top
local right_bottom = bounding_box.right_bottom
for x = left_top.x, right_bottom.x do
for y = left_top.y, right_bottom.y do
local tile = surface.get_tile(x, y)
@@ -58,11 +58,10 @@ end
--- Gets the average tile strengths around position
--- @param surface LuaSurface
--- @param position MapPosition
--- @param position MapPosition.struct
--- @return number?
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)
local tile = surface.get_tile(position.x, position.y)
local tile_name = tile.name
local strength = config.strengths[tile_name]
if not strength then return end
@@ -31,15 +31,15 @@ local function append_playtime(player_name)
end
--- Get the player name from an event
--- @param event { player_index: number, by_player_name: string? }
--- @return string, string
--- @param event { player_index: uint, by_player_name: string? }
--- @return string, string?
local function get_player_name(event)
local player = game.players[event.player_index]
return player.name, event.by_player_name
end
--- Convert a colour value into hex
--- @param color Color.0
--- @param color Color.struct
--- @return string
local function to_hex(color)
local hex_digits = "0123456789ABCDEF"
@@ -53,7 +53,7 @@ local function to_hex(color)
end
--- 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 admins_online = 0
local players_online = 0
@@ -23,7 +23,7 @@ end
--- @param event EventData.on_cargo_pod_finished_ascending
local function on_cargo_pod_finished_ascending(event)
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
add_log_line("[ROCKET]", force.rockets_launched, "rockets launched")
elseif config.rocket_launch_display[force.rockets_launched] then
@@ -38,7 +38,7 @@ local function on_pre_player_died(event)
local cause = event.cause
if cause 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
add_log_line("[DEATH]", player.name, "died because of", cause.name)
end
@@ -22,7 +22,7 @@ local min = math.min
--- @field trees LuaEntity[]
--- @field tree_count number
--- @field permission "fast" | "allow" | "disallow"
--- @field task Async.AsyncReturn
--- @field task Async.AsyncReturn<any>
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
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
local player = assert(game.get_player(player_index))
cache.tick = game.tick
cache.player_index = player_index
cache.player = player
cache.force = player.force --[[ @as LuaForce ]]
cache.force = player.force --[[@as LuaForce]]
cache.tree_count = 0
cache.trees = {}
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 config = require("modules.exp_legacy.config.compilatron")
--- @type table<string, Async.AsyncReturn>
--- @type table<string, Async.AsyncReturn<any>>
local persistent_locations = {}
Storage.register(persistent_locations, function(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 messages LocalisedString[] the messages which should be shown
--- @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)
return speech_bubble_task{
entity = entity,
@@ -68,12 +68,13 @@ local function try_deconstruct_output_chest(entity)
end
-- Get all adjacent mining drills and inserters
local target_position = target.position
local entities = target.surface.find_entities_filtered{
type = { "mining-drill", "inserter" },
to_be_deconstructed = false,
area = {
{ target.position.x - 1, target.position.y - 1 },
{ target.position.x + 1, target.position.y + 1 }
left_top = { x = target_position.x - 1, y = 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{
type = "mining-drill",
area = {
{ position.x - max_mining_radius, position.y - max_mining_radius },
{ position.x + max_mining_radius, position.y + max_mining_radius },
left_top = { x = position.x - max_mining_radius, y = 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
for _, drill in pairs(drills) do
local radius = drill.prototype.mining_drill_radius
local dx = math.abs(drill.position.x - position.x)
local dy = math.abs(drill.position.y - position.y)
local drill_position = drill.position
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
try_deconstruct_miner(drill)
end
+15 -14
View File
@@ -7,11 +7,11 @@ local config = require("modules.exp_legacy.config.spawn_area")
--- Apply an offset to a LuaPosition
--- @param position MapPosition
--- @param offset MapPosition
--- @return MapPosition.0
--- @return MapPosition.struct
local function apply_offset(position, offset)
return {
x = (position.x or position[1]) + (offset.x or offset[1]),
y = (position.y or position[2]) + (offset.y or offset[2])
x = position.x + offset.x,
y = position.y + offset.y,
}
end
@@ -21,8 +21,8 @@ end
--- @param x_index number
--- @param y_index number
local function apply_offset_to_array(positions, offset, x_index, y_index)
local x = (offset.x or offset[1])
local y = (offset.y or offset[2])
local x = offset.x
local y = offset.y
for _, position in ipairs(positions) do
position[x_index] = position[x_index] + x
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 entity = surface.create_entity{ name = entity_details[1], position = pos, force = "neutral" }
if entity and config.entities.protected then
protect_entity(entity)
end
if entity then
if config.entities.protected then
protect_entity(entity)
end
entity.operable = config.entities.operable
entity.operable = config.entities.operable
end
end
end
@@ -164,8 +166,7 @@ local function clear_spawn_area(surface, offset)
local get_tile = surface.get_tile
-- 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)
local starting_tile = get_tile(offset.x, offset.y)
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_sqr = fill_radius ^ 2
@@ -185,8 +186,7 @@ local function clear_spawn_area(surface, offset)
if dst < tile_radius_sqr then
-- If it is inside the decon radius always set the tile
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).collides_with("player") then
elseif dst < fill_radius_sqr and get_tile(pos.x, pos.y).collides_with("player") then
-- 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 }
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.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)
end
@@ -66,8 +66,9 @@ local function rename_station(event)
-- Check which recourse is closest
for _, resource in ipairs(resources) do
local dx = px - resource.bounding_box.left_top.x
local dy = py - resource.bounding_box.left_top.y
local resource_box = resource.bounding_box
local dx = px - resource_box.left_top.x
local dy = py - resource_box.left_top.y
local distance = (dx * dx) + (dy * dy)
if distance < closest_distance then
closest_distance = distance
@@ -78,7 +79,8 @@ local function rename_station(event)
-- Set the item name and icon
if closest_recourse then
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)
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.tooltip = { "exp-gui_autofill.tooltip-toggle-section-expand" }
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Toggle if an entity will be autofilled when played
--- @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.height = 22
style.width = 22
end) --[[ @as any ]]
end) --[[@as any]]
--- Toggle if an item will be inserted into an entity
--- @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.height = 32
style.width = 32
end) --[[ @as any ]]
end) --[[@as any]]
--- The amount of an item to insert
--- @class ExpGui_Autofill.elements.amount_textfield: ExpElement
@@ -165,7 +165,7 @@ Elements.amount_textfield = Gui.define("autofill/amount_textfield")
element.text = tostring(clamped)
player.print{ "exp-gui_autofill.invalid", clamped, rich_img("item", item_settings.name), rich_img("entity", item_settings.entity) }
end
end) --[[ @as any ]]
end) --[[@as any]]
--- A disabled version of the autofill settings used as a filler
Elements.disabled_autofill_setting = Gui.define("autofill/empty_autofill_setting")
@@ -221,9 +221,9 @@ Elements.section = Gui.define("autofill/section")
end)
:on_click(function(def, player, element, event)
--- @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)
end) --[[ @as any ]]
end) --[[@as any]]
--- Add an item category to a section, at most three can exist
--- @param section LuaGuiElement
@@ -238,7 +238,7 @@ function Elements.section.add_category(section, category_name)
category.style.vertical_spacing = 1
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
if item_data.category == category_name then
Elements.toggle_item_button(category, item_data)
@@ -265,7 +265,7 @@ end
--- Container added to the left gui flow
--- @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")
:draw(function(def, parent)
--- @cast def ExpGui_Autofill.elements.container
@@ -312,7 +312,7 @@ Elements.container = Gui.define("autofill/container")
end
return container.parent
end) --[[ @as any ]]
end) --[[@as any]]
--- Get the autofill settings for a player
--- @param player LuaPlayer
@@ -27,7 +27,7 @@ function Public.show(container)
local left_panel_style = left_panel.style
left_panel_style.width = 300
--- @diagnostic disable-next-line invisible
--- @diagnostic disable-next-line: access-invisible
for element_name in pairs(ExpElement._elements) do
local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = 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.style.font_color = Color.black
--- @diagnostic disable-next-line invisible
--- @diagnostic disable-next-line: access-invisible
local define = ExpElement._elements[element_name]
local content = dump({
--- @diagnostic disable-next-line invisible
--- @diagnostic disable-next-line: access-invisible
debug = define._debug,
--- @diagnostic disable-next-line invisible
--- @diagnostic disable-next-line: access-invisible
has_handlers = define._has_handlers,
--- @diagnostic disable-next-line invisible
--- @diagnostic disable-next-line: access-invisible
track_elements = define._track_elements,
--- @diagnostic disable-next-line invisible
--- @diagnostic disable-next-line: access-invisible
elements = ExpIter._scopes[element_name],
--- @diagnostic disable-next-line invisible
--- @diagnostic disable-next-line: access-invisible
data = ExpData._scopes[element_name]._raw,
}) or "nil"
right_panel.text = content
+1 -1
View File
@@ -4,7 +4,7 @@ local ExpUtil = require("modules/exp_util")
local concat = table.concat
local inspect = table.inspect
local pcall = pcall
local loadstring = loadstring --- @diagnostic disable-line
local loadstring = load
local rawset = rawset
local Public = {}
@@ -24,7 +24,7 @@ function Public.show(container)
local left_panel_style = left_panel.style
left_panel_style.width = 300
--- @diagnostic disable-next-line invisible
--- @diagnostic disable-next-line: access-invisible
for token_id in pairs(Storage._registered) do
local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = 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)
:style{
height = 24,
} --[[ @as any ]]
} --[[@as any]]
--- To help with caching and avoid context changes the player list from the previous update is remembered
--- @type (string?)[]
do local _player_names = {}
do local _player_names = {} --- @type (string?)[]
--- Updates the player name list after a join or leave
--- @return (string?)[]
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)
--- @cast def ExpGui_ModuleInserter.elements.create_selection_planner
SelectArea:start(player, def.data[element])
end) --[[ @as any ]]
end) --[[@as any]]
--- Used to select the machine to apply modules to
--- @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)
--- @cast def ExpGui_ModuleInserter.elements.machine_selector
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 element_data.on_last_row then
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)
end
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Used to select the modules to be applied
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
return Gui.elements.scroll_table(parent, 280, slots_per_row)
end)
:element_data{} --[[ @as any ]]
:element_data{} --[[@as any]]
--- Get all the rows in a module table
--- @param module_table LuaGuiElement
@@ -177,7 +177,7 @@ end
--- @param machine_selector LuaGuiElement
function Elements.module_table.remove_row(module_table, machine_selector)
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
Gui.destroy_if_valid(machine_selector)
for _, separator in pairs(row.row_separators) do
@@ -193,7 +193,7 @@ end
--- @param machine_selector LuaGuiElement
function Elements.module_table.reset_row(module_table, machine_selector)
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
separator.visible = false
@@ -211,9 +211,9 @@ end
--- @param machine_name string
function Elements.module_table.refresh_row(module_table, machine_selector, machine_name)
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_module_count = visible_row_count * config.module_slots_per_row
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
--- @type BoundingBox
local param_area = {
left_top = {},
right_bottom = {}
left_top = { x = 0, y = 0 },
right_bottom = { x = 0, y = 0 },
}
-- 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
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
goto continue
end
@@ -348,8 +348,8 @@ SelectArea:on_selection(function(event, module_table)
-- Get all the modules selected
for i = 1, entity_prototype.module_inventory_size do
local module_selector = module_selectors[i]
local module = module_selector.elem_value --[[ @as { name: string, quality: string }? ]]
local module_selector = assert(module_selectors[i])
local module = module_selector.elem_value --[[@as { name: string, quality: string }?]]
if module then
-- Module selected, add it the module arrays
local no_prod_name = module.name:gsub("productivity", "efficiency")
+14 -12
View File
@@ -22,13 +22,16 @@ local Elements = {}
--- @field _cost_scale number
--- 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
end
--- Progress bar which displays how much of a bonus has been used
--- @class ExpGui_PlayerBonus.elements.bonus_used: ExpElement
--- @field data number
--- @field data table<LuaGuiElement, number>
--- @overload fun(parent: LuaGuiElement): LuaGuiElement
Elements.bonus_used = Gui.define("player_bonus/bonus_used")
:track_all_elements()
@@ -44,11 +47,10 @@ Elements.bonus_used = Gui.define("player_bonus/bonus_used")
font = "heading-2",
color = { 1, 0, 0 },
}
:element_data(0) --[[ @as any ]]
:element_data(0) --[[@as any]]
--- Value is cached to save perf
--- @type table<number, number>
do local _points_limit = {}
do local _points_limit = {} --- @type table<number, number>
--- Clear the cache for points limit
--- @param player LuaPlayer
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)
local bonus_cost = Elements.bonus_table.calculate_cost(element_data.bonus_table)
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
--- @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.container.apply_player_bonus(player)
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Link an apply button to this reset button so that it will be disabled after being pressed
--- @param apply_button LuaGuiElement
@@ -207,7 +209,7 @@ Elements.bonus_table_label = Gui.define("player_bonus/table_label")
}
:style{
width = Gui.from_argument(3, 70),
} --[[ @as any ]]
} --[[@as any]]
--- @class ExpGui_PlayerBonus.elements.bonus_slider.elements
--- @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.apply_button.enabled = Elements.bonus_used.update(element_data.bonus_used, value_change * bonus_data._cost_scale)
element_data.reset_button.enabled = true
end) --[[ @as any ]]
end) --[[@as any]]
--- Get the caption of the slider label
--- @param bonus_data ExpGui_PlayerBonus.bonus_data
@@ -311,7 +313,7 @@ Elements.bonus_table = Gui.define("player_bonus/bonus_table")
:draw(function(_, parent)
return Gui.elements.scroll_table(parent, 300, 3)
end)
:element_data{} --[[ @as any ]]
:element_data{} --[[@as any]]
--- Adds a row to the milestone table
--- @param bonus_table LuaGuiElement
@@ -378,7 +380,7 @@ Elements.container = Gui.define("player_bonus/container")
Elements.bonus_used.refresh(elements.bonus_used, bonus_cost)
return Gui.elements.container.get_root_element(container)
end) --[[ @as any ]]
end) --[[@as any]]
--- Set the bonus value for a player
--- @param player LuaPlayer
@@ -442,7 +444,7 @@ end
function Elements.container.calculate_cost(player)
local cost = 0
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
end
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
Elements.container.toggle_selected_player(player, def.data[element])
Elements.player_table.refresh_player(player)
end) --[[ @as any ]]
end) --[[@as any]]
--- Set whether an open action bar button shows as highlighted
--- @param open_button LuaGuiElement
--- @param highlighted boolean
function Elements.open_action_bar.set_highlight(open_button, highlighted)
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.width = 8
style.height = 14
@@ -80,7 +80,7 @@ Elements.close_action_bar = Gui.define("player_list/close_action_bar")
:on_click(function(_, player)
Elements.container.set_selected_player(player, nil)
Elements.player_table.refresh_player(player)
end) --[[ @as any ]]
end) --[[@as any]]
--- Button used to confirm a reason
--- @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 button_data = action_name and config.buttons[action_name]
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
button_data.reason_callback(player, reason)
end
element.parent.entry.text = ""
assert(element.parent).entry.text = ""
Elements.container.set_selected_player(player, nil)
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
--- @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.player_table.refresh_player(player)
end
end) --[[ @as any ]]
end) --[[@as any]]
--- @class ExpGui_PlayerList.elements.player_table.row
--- @field open_button LuaGuiElement
@@ -165,7 +165,7 @@ Elements.player_table = Gui.define("player_list/player_table")
end)
:style{
padding = { 1, 0, 1, 2 },
} --[[ @as any ]]
} --[[@as any]]
--- Store the action and reason bars associated with a player table
--- @param player_table LuaGuiElement
@@ -342,7 +342,7 @@ Elements.action_bar = Gui.define("player_list/action_bar")
:style{
height = 35,
padding = { 1, 3 },
} --[[ @as any ]]
} --[[@as any]]
--- Update the action bar buttons to match the selection for a player, hidden when nothing is selected
--- @param action_bar LuaGuiElement
@@ -390,7 +390,7 @@ Elements.reason_bar = Gui.define("player_list/reason_bar")
:style{
height = 35,
padding = { -1, 3 },
} --[[ @as any ]]
} --[[@as any]]
--- Update the reason bar visibility to match the selection, shown only while an action awaits a reason
--- @param reason_bar LuaGuiElement
@@ -420,7 +420,7 @@ Elements.container = Gui.define("player_list/container")
Elements.player_table.rebuild(player_table, row_data)
return Gui.elements.container.get_root_element(container)
end) --[[ @as any ]]
end) --[[@as any]]
--- Get or create the selection state for a player
--- @param player LuaPlayer
+3 -3
View File
@@ -93,7 +93,7 @@ Elements.table_label = Gui.define("player_stats/table_label")
}
:style{
width = Gui.from_argument("width"),
} --[[ @as any ]]
} --[[@as any]]
--- Data table that shows all data for a player
--- @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
return data_table
end) --[[ @as any ]]
end) --[[@as any]]
--- Refresh a data table with the most recent stats for a player
--- @param data_table LuaGuiElement
@@ -185,7 +185,7 @@ Elements.player_dropdown = Gui.define("player_stats/player_dropdown")
local data_table = def.data[element]
local target_player = ElementsExtra.online_player_dropdown.get_selected(element)
Elements.player_stats_table.refresh(data_table, target_player)
end) --[[ @as any ]]
end) --[[@as any]]
--- Refresh all stats tables associated with a player dropdown
function Elements.player_dropdown.refresh_online()
+9 -8
View File
@@ -9,6 +9,7 @@ local Roles = require("modules/exp_legacy/expcore/roles")
local Elements = {}
--- The flow precision values in the same order as production_precision_dropdown.items
--- @type defines.flow_precision_index[]
local precision_indexes = {
defines.flow_precision_index.five_seconds,
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
Elements.production_table.add_row(element_data.production_table)
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Label used for every element in the production table
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()
:draw(function(def, parent)
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
display_alignments[i] = "right"
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")
return scroll_table
end) --[[ @as any ]]
end) --[[@as any]]
--- Calculate the row data for a production table
--- @param force LuaForce
@@ -183,7 +184,7 @@ end
--- @param item_selector LuaGuiElement
function Elements.production_table.remove_row(production_table, item_selector)
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
Gui.destroy_if_valid(item_selector)
for _, element in pairs(row) do
@@ -196,7 +197,7 @@ end
--- @param item_selector LuaGuiElement
function Elements.production_table.reset_row(production_table, item_selector)
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.consumption.caption = "0.00"
row.net.caption = "0.00"
@@ -209,7 +210,7 @@ end
--- @param row_data ExpGui_ProductionStats.elements.production_table.row_data
function Elements.production_table.refresh_row(production_table, item_selector, row_data)
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.consumption.caption = row_data.consumption
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]
for _, row in pairs(element_data.rows) do
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
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)
end
end
+2 -2
View File
@@ -43,13 +43,13 @@ local function new_quick_action(command, on_click)
:style{
width = 160,
}
:on_click(on_click or function(def, player, element, event)
:on_click(on_click or function(_def, player, _element, _event)
command(player)
end)
Elements[command_name] = element
Actions[command_name] = {
command = command --[[ @as ExpCommand ]],
command = command --[[@as ExpCommand]],
element = element,
}
end
+20 -17
View File
@@ -47,7 +47,7 @@ Elements.title_table = Gui.define("readme/title_table")
cell_padding = 0,
vertical_align = "center",
horizontally_stretchable = true,
} --[[ @as any ]]
} --[[@as any]]
--- Scroll pane used for title tables
--- @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 },
maximal_height = scroll_height,
horizontally_stretchable = true,
} --[[ @as any ]]
} --[[@as any]]
--- Sub content frame
--- @class ExpGui_Readme.elements.sub_content: ExpElement
@@ -80,7 +80,7 @@ Elements.sub_content = Gui.define("readme/sub_content")
horizontal_align = "center",
padding = { 2, 2 },
top_margin = 2,
} --[[ @as any ]]
} --[[@as any]]
--- @class ExpGui_Readme.elements.join_server.elements
--- @field server_id string
@@ -119,7 +119,7 @@ Elements.join_server = Gui.define("readme/join_server")
--- @cast def ExpGui_Readme.elements.join_server
local server_id = def.data[button].server_id
External.request_connection(player, server_id, true)
end) --[[ @as any ]]
end) --[[@as any]]
--- Refresh join server button
--- @param button LuaGuiElement
@@ -244,7 +244,7 @@ define_tab(
)
return container
end) --[[ @as any ]]
end) --[[@as any]]
)
--- Rules tab
@@ -261,14 +261,15 @@ define_tab(
local rules = Gui.elements.scroll_table(container, scroll_height, 1)
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
Gui.elements.centered_label(rules, frame_width - 30, { "exp-gui_readme.rules-" .. i })
end
return container
end) --[[ @as any ]]
end) --[[@as any]]
)
--- Commands tab
@@ -287,7 +288,8 @@ define_tab(
local commands = Gui.elements.scroll_table(container, scroll_height, 2)
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
Gui.elements.centered_label(commands, 120, name)
@@ -295,7 +297,7 @@ define_tab(
end
return container
end) --[[ @as any ]]
end) --[[@as any]]
)
--- Servers tab
@@ -338,7 +340,7 @@ define_tab(
end
return container
end) --[[ @as any ]]
end) --[[@as any]]
)
--- Backers tab
@@ -359,32 +361,32 @@ define_tab(
roles = { "Senior Administrator", "Administrator" },
title = { "exp-gui_readme.backers-management" },
width = 230,
players = {},
players = {}, --- @type string[]
},
{
roles = { "Board Member", "Senior Backer" },
title = { "exp-gui_readme.backers-board" },
width = 145,
players = {},
players = {}, --- @type string[]
},
{
roles = { "Sponsor", "Supporter" },
title = { "exp-gui_readme.backers-backers" },
width = 196,
players = {},
players = {}, --- @type string[]
},
{
roles = { "Moderator", "Trainee" },
title = { "exp-gui_readme.backers-staff" },
width = 235,
players = {},
players = {}, --- @type string[]
},
{
roles = {},
time = 3 * 3600 * 60,
title = { "exp-gui_readme.backers-active" },
width = 235,
players = {},
players = {}, --- @type string[]
},
}
@@ -433,7 +435,7 @@ define_tab(
end
return container
end) --[[ @as any ]]
end) --[[@as any]]
)
--- @class (exact) ExpGui_Readme.elements.readme_data.param table
@@ -599,7 +601,7 @@ define_tab(
end
return container
end) --[[ @as any ]]
end) --[[@as any]]
)
--- @class ExpGui_Readme.elements.container.elements
@@ -608,6 +610,7 @@ define_tab(
--- Main readme container
--- @class ExpGui_Readme.elements.container: ExpElement
--- @field data table<LuaGuiElement, ExpGui_Readme.elements.container.elements>
--- @overload fun(parent: LuaGuiElement): LuaGuiElement
Elements.container = Gui.define("readme/container")
:track_all_elements()
:draw(function(def, parent)
@@ -72,7 +72,7 @@ Elements.clock_label = Gui.define("research_milestones/clock_label")
type = "label",
caption = research_time_format_nil,
style = "heading_2_label",
} --[[ @as any ]]
} --[[@as any]]
--- Update the clock label for all online players
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),
horizontal_align = Gui.from_argument(3, "right"),
font_color = font_color.neutral,
} --[[ @as any ]]
} --[[@as any]]
--- @class ExpGui_ResearchMilestones.elements.milestone_table.row_elements
--- @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" })
return milestone_table
end)
:element_data{} --[[ @as any ]]
:element_data{} --[[@as any]]
do local _row_data = {}
--- @type ExpGui_ResearchMilestones.elements.milestone_table.row_data
--- @diagnostic disable-next-line: missing-fields
local empty_row_data = { color = font_color.positive }
--- Get the row data for a force and research
@@ -203,7 +204,7 @@ end
--- @param row_index number
--- @param row_data ExpGui_ResearchMilestones.elements.milestone_table.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.target.caption = row_data.target
row.achieved.caption = row_data.achieved
@@ -224,7 +225,7 @@ end
--- Refresh all the labels on the table
--- @param milestone_table LuaGuiElement
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)
for row_index = 1, display_size do
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
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)
for _, milestone_table in Elements.milestone_table:online_elements(player) 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)
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
local force = Gui.get_player(parent).force --[[ @as LuaForce ]]
local start_index = Elements.container.calculate_starting_research_index(force)
for research_index = start_index, start_index + display_size - 1 do
local row_data = Elements.milestone_table.calculate_row_data(force, research_index)
@@ -296,7 +296,7 @@ end
--- @param research_index number
--- @return number
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
--- 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.tooltip = { "exp-gui_rocket-info.tooltip-toggle-section-expand" }
end
end) --[[ @as any ]]
end) --[[@as any]]
--- A clickable coordinate label which opens the silo location on the map when pressed
--- @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]
if not entity or not entity.valid then return end
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
--- @class ExpGui_RocketInfo.elements.stats_table: ExpElement
@@ -125,7 +125,7 @@ Elements.stats_table = Gui.define("rocket_info/stats_table")
:element_data{}
:draw(function(def, parent)
return Gui.elements.scroll_table(parent, 215, 2)
end) --[[ @as any ]]
end) --[[@as any]]
--- @class ExpGui_RocketInfo.elements.stats_table.row_data
--- @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
--- @param player LuaPlayer
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)
for _, stats_table in Elements.stats_table:online_elements(player) do
Elements.stats_table.refresh(stats_table, row_data)
@@ -243,7 +243,7 @@ Elements.milestones_table = Gui.define("rocket_info/milestones_table")
:element_data{}
:draw(function(def, parent)
return Gui.elements.scroll_table(parent, 215, 2)
end) --[[ @as any ]]
end) --[[@as any]]
--- @class ExpGui_RocketInfo.elements.milestones_table.row_data
--- @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
--- @param player LuaPlayer
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)
for _, stats_table in Elements.stats_table:online_elements(player) do
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 }
return progress_table
end) --[[ @as any ]]
end) --[[@as any]]
--- @class ExpGui_RocketInfo.elements.progress_table.row_data
--- @field entity LuaEntity
@@ -404,9 +404,9 @@ end
--- @return ExpGui_RocketInfo.elements.progress_table.row_data[]
function Elements.progress_table.calculate_row_data_all(silo_data)
local row_data = {}
for unit_number, silo_data in pairs(silo_data) do
if silo_data.entity.valid then
row_data[unit_number] = Elements.progress_table.calculate_row_data(silo_data)
for unit_number, silo in pairs(silo_data) do
if silo.entity.valid then
row_data[unit_number] = Elements.progress_table.calculate_row_data(silo)
else
-- Prune silos that are no longer valid
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.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
--- Remove a silo row from the progress table
@@ -455,7 +456,8 @@ end
--- @param row_data ExpGui_RocketInfo.elements.progress_table.row_data
function Elements.progress_table.refresh_row(progress_table, row_data)
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.y.caption = row_data.y
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
--- @param player LuaPlayer
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 row_data = Elements.progress_table.calculate_row_data_all(silos)
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
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)
if config.stats.show_stats then
@@ -618,9 +620,10 @@ end
--- Add a silo to the list of current silos for a force
--- @param entity LuaEntity
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
silos[entity.unit_number] = {
local unit_number = entity.unit_number --[[@as uint]]
silos[unit_number] = {
entity = entity,
launched = 0,
awaiting_reset = false,
@@ -630,9 +633,11 @@ end
--- Increment the launch count for a silo
--- @param entity LuaEntity
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 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
silo_data.launched = silo_data.launched + 1
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
--- @param event EventData.on_cargo_pod_finished_ascending
local function on_cargo_pod_finished_ascending(event)
local force = event.cargo_pod.force --[[ @as LuaForce ]]
local rockets_launched = force.rockets_launched
local force = event.cargo_pod.force --[[@as LuaForce]]
local rockets_launched = force.rockets_launched --[[@as number]]
-- Update the launch stats for the force
local stats = Elements.container.get_stats(force)
@@ -686,7 +691,7 @@ end
--- @param event EventData.on_rocket_launch_ordered
local function on_rocket_launch_ordered(event)
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
--- 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
if not entity.valid or entity.name ~= "rocket-silo" then return end
Elements.container.add_silo(entity)
Elements.progress_table.refresh_force(entity.force --[[ @as LuaForce ]])
Elements.progress_table.refresh_force(entity.force --[[@as LuaForce]])
end
--- 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
return label
end) --[[ @as any ]]
end) --[[@as any]]
--- @class Elements.production_label.display_data
--- @field caption LocalisedString
@@ -109,7 +109,7 @@ function Elements.production_label.calculate_display_data(tooltip, value, cutoff
end
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.suffix = suffix
display_data.tooltip = tooltip
@@ -144,12 +144,12 @@ Elements.no_production_label = Gui.define("science_production/no_production_labe
padding = { 2, 4 },
single_line = false,
width = 200,
} --[[ @as any ]]
} --[[@as any]]
--- Refresh a no production label
--- @param no_production_label LuaGuiElement
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)
end
@@ -157,7 +157,7 @@ end
function Elements.no_production_label.refresh_online()
local force_data = {}
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]
if visible == nil then
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 no_production_label = Elements.no_production_label(science_table)
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
end)
:element_data{} --[[ @as any ]]
:element_data{} --[[@as any]]
--- Calculate the data needed to add or refresh a row
--- @param force LuaForce
@@ -220,7 +221,7 @@ function Elements.science_table.calculate_row_data(force, science_pack, row_data
end
-- 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.science_pack = science_pack
row_data.icon_style = icon_style
@@ -280,7 +281,8 @@ function Elements.science_table.add_row(science_table, row_data)
column_count = 2,
}
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
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
local icon = row.icon
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
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)
end
--- @type table<string, { [string]: ExpGui_ScienceProduction.elements.science_table.row_data }>
do local _row_data = {}
do local _row_data = {} --- @type table<string, table<number, ExpGui_ScienceProduction.elements.science_table.row_data>>
--- Refresh the production tables for all online players
function Elements.science_table.refresh_online()
-- 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,
tooltip = long_time_format_nil,
style = "frame_title",
} --[[ @as any ]]
} --[[@as any]]
--- @class Elements.eta_label.display_data
--- @field caption LocalisedString
@@ -410,14 +412,13 @@ end
--- Refresh an eta label
--- @param eta_label LuaGuiElement
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)
eta_label.caption = display_data.caption
eta_label.tooltip = display_data.tooltip
end
--- @type Elements.eta_label.display_data
do local _display_data = {}
do local _display_data = {} --- @type table<string, Elements.eta_label.display_data>
--- Refresh the eta label for all online players
function Elements.eta_label.refresh_online()
-- Refresh the row data for online forces
@@ -430,8 +431,10 @@ do local _display_data = {}
-- Update the eta labels
for player, eta_label in Elements.eta_label:online_elements() do
local display_data = _display_data[player.force.name]
eta_label.caption = display_data.caption
eta_label.tooltip = display_data.tooltip
if display_data then
eta_label.caption = display_data.caption
eta_label.tooltip = display_data.tooltip
end
end
end
end
@@ -443,7 +446,7 @@ Elements.container = Gui.define("science_production/container")
local container = Gui.elements.container(parent)
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)
for _, science_pack in ipairs(config) do
--- @cast science_pack any
@@ -462,7 +465,7 @@ Elements.container = Gui.define("science_production/container")
end
return Gui.elements.container.get_root_element(container)
end) --[[ @as any ]]
end) --[[@as any]]
--- Cached mostly because they are long names
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 one_hour ExpGui_ScienceProduction._item_data
--- @type table<string, { [string]: ExpGui_ScienceProduction.item_production_data }>
do local _production_data = {}
do local _production_data = {} --- @type table<string, { [string]: ExpGui_ScienceProduction.item_production_data }>
--- Get the production stats for a force
--- @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 target_player = assert(ElementsExtra.online_player_dropdown.get_selected(element))
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
--- @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
local camera = def.data[element]
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
--- @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)
Elements.camera.set_target_player(element_data.camera, target_player)
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Refresh all online type dropdowns by cycling the associated player dropdown
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
camera.zoom = camera.zoom - 0.05
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Buttons which increases zoom by 5%
--- @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
camera.zoom = camera.zoom + 0.05
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Camera which tracks a target with a physical_position and surface_index
--- @class ExpGui_Surveillance.elements.camera: ExpElement
@@ -176,7 +176,7 @@ Elements.camera = Gui.define("surveillance/camera")
}
:element_data(
Gui.from_argument(1)
) --[[ @as any ]]
) --[[@as any]]
--- Set the target player for the camera
--- @param camera LuaGuiElement
+32 -27
View File
@@ -105,7 +105,7 @@ Elements.new_task_button = Gui.define("task_list/new_task_button")
body = "",
new = true,
})
end) --[[ @as any ]]
end) --[[@as any]]
--- Refresh the visibility based on player permissions
--- @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
local elements = def.data[view_task_button]
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
--- @param view_task_button LuaGuiElement
@@ -187,19 +187,19 @@ Elements.no_tasks_header = Gui.define("task_list/no_tasks_header")
:style{
padding = { 2, 0 },
bottom_margin = 0,
} --[[ @as any ]]
} --[[@as any]]
--- Refresh the visibility of the no tasks label
--- @param no_tasks_header LuaGuiElement
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)
end
--- Refresh the visibility of the no tasks label
--- @param player LuaPlayer
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
no_tasks_header.visible = visible
end
@@ -246,13 +246,13 @@ Elements.task_list = Gui.define("task_list/task_list")
return task_list
end)
:element_data{} --[[ @as any ]]
:element_data{} --[[@as any]]
--- Adds a task to the task list
--- @param task_list LuaGuiElement
--- @param task ExpGui_TaskList.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]
view_task_buttons[task.id] = Elements.view_task_button(task_list, task, container)
end
@@ -330,7 +330,7 @@ Elements.task_footer = Gui.define("task_list/task_footer")
height = 0,
padding = 5,
use_header_filler = false,
} --[[ @as any ]]
} --[[@as any]]
--- @class ExpGui_TaskList.elements.close_task_button.elements
--- @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
local elements = def.data[close_task_button]
Elements.container.close_footers(elements.container)
end) --[[ @as any ]]
end) --[[@as any]]
--- @class ExpGui_TaskList.elements.task_button.elements
--- @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
local elements = def.data[edit_task_button]
Elements.container.open_edit_task(elements.container, assert(elements.task))
end) --[[ @as any ]]
end) --[[@as any]]
--- Refresh the edit button
--- @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)
--- @cast def ExpGui_TaskList.element.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)
end) --[[ @as any ]]
end) --[[@as any]]
--- Refresh the delete button
--- @param delete_task_button LuaGuiElement
@@ -477,7 +477,7 @@ Elements.view_task_footer = Gui.define("task_list/view_task_footer")
}
return view_task_footer
end) --[[ @as any ]]
end) --[[@as any]]
--- Refresh the view task with new task details
--- @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)
--- @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
end) --[[ @as any ]]
end) --[[@as any]]
--- Set the confirm task button to update on text changed
--- @param task_message_textfield LuaGuiElement
@@ -549,7 +549,7 @@ end
function Elements.task_message_textfield.refresh(task_message_textfield, task)
local elements = Elements.task_message_textfield.data[task_message_textfield]
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.focus()
end
@@ -590,13 +590,13 @@ Elements.confirm_task_button = Gui.define("task_list/confirm_task_button")
Elements.container.close_footers(elements.container)
local force = player.force --[[ @as LuaForce ]]
local force = player.force --[[@as LuaForce]]
if task.new then
Elements.container.add_task(force, task)
else
Elements.container.refresh_force_online(force, task)
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Refresh the confirm task button
--- @param confirm_task_button LuaGuiElement
@@ -612,7 +612,7 @@ function Elements.confirm_task_button.parse(message)
-- Trim the spaces of the string
local trimmed = string.gsub(message, "^%s*(.-)%s*$", "%1")
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 it doesn't match the pattern return the str as a title
parsed.title = trimmed
@@ -649,7 +649,7 @@ Elements.discard_task_button = Gui.define("task_list/discard_task_button")
else
Elements.container.open_view_task(elements.container, task)
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Refresh the discard task button
--- @param discard_task_button LuaGuiElement
@@ -696,7 +696,7 @@ Elements.edit_task_footer = Gui.define("task_list/edit_task_footer")
}
return edit_task_footer
end) --[[ @as any ]]
end) --[[@as any]]
--- Refresh the view task with new task details
--- @param edit_task_footer LuaGuiElement
@@ -755,9 +755,14 @@ end
--- @field view_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
--- @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")
:track_all_elements()
:draw(function(def, parent)
@@ -781,7 +786,7 @@ Elements.container = Gui.define("task_list/container")
-- Add tasks to the list if there are any
local player = Gui.get_player(parent)
local force = player.force --[[ @as LuaForce ]]
local force = player.force --[[@as LuaForce]]
local tasks = def.data[force]
if tasks then
for _, task in ipairs(tasks) do
@@ -796,11 +801,11 @@ Elements.container = Gui.define("task_list/container")
elements.edit_task_footer.visible = false
-- Set the data and return
def.data[root] = elements --[[ @as any ]]
def.data[root] = elements --[[@as any]]
return root
end)
:global_data{ next_task_id = 1 }
:force_data{} --[[ @as any ]]
:force_data{} --[[@as any]]
--- Check if a force has tasks
--- @param force LuaForce
@@ -885,7 +890,7 @@ end
--- Refresh all tasks for a player
--- @param player LuaPlayer
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
local elements = Elements.container.data[container]
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
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)
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
def.data[player] = element -- Only set if previous is invalid
end
end) --[[ @as any ]]
end) --[[@as any]]
--- Refresh the caption for all online players
--- @param ups number The UPS to be displayed
+18 -18
View File
@@ -11,22 +11,22 @@ local max = math.max
local AABB = {}
--- Check if an area is valid
--- @param aabb BoundingBox
--- @param aabb BoundingBox.struct
--- @return boolean # True if the area is valid
function AABB.valid(aabb)
return aabb.left_top.x < aabb.right_bottom.x and aabb.left_top.y < aabb.right_bottom.y
end
--- Returns the size of the area contained within an AABB
--- @param aabb BoundingBox
--- @param aabb BoundingBox.struct
--- @return number
function AABB.size(aabb)
return (aabb.right_bottom.x - aabb.left_top.x) * (aabb.right_bottom.y - aabb.left_top.y)
end
--- Clone an area, allows for safe mutation of an input value
--- @param aabb BoundingBox
--- @return BoundingBox
--- @param aabb BoundingBox.struct
--- @return BoundingBox.struct
function AABB.clone(aabb)
return {
left_top = { x = aabb.left_top.x, y = aabb.left_top.y },
@@ -35,8 +35,8 @@ function AABB.clone(aabb)
end
--- Expand an area to be integer aligned, expanding away from 0
--- @param aabb BoundingBox
--- @return BoundingBox
--- @param aabb BoundingBox.struct
--- @return BoundingBox.struct
function AABB.expand(aabb)
return {
left_top = { x = floor(aabb.left_top.x), y = floor(aabb.left_top.y) },
@@ -45,8 +45,8 @@ function AABB.expand(aabb)
end
--- Contract an area to be integer aligned, contracting towards 0
--- @param aabb BoundingBox
--- @return BoundingBox
--- @param aabb BoundingBox.struct
--- @return BoundingBox.struct
function AABB.contract(aabb)
return {
left_top = { x = ceil(aabb.left_top.x), y = ceil(aabb.left_top.y) },
@@ -55,9 +55,9 @@ function AABB.contract(aabb)
end
--- Expand an area to include all other areas
--- @param aabb BoundingBox
--- @param ... BoundingBox
--- @return BoundingBox
--- @param aabb BoundingBox.struct
--- @param ... BoundingBox.struct
--- @return BoundingBox.struct
function AABB.union(aabb, ...)
local rtn = AABB.clone(aabb)
for _, next_aabb in ipairs{ ... } do
@@ -70,9 +70,9 @@ function AABB.union(aabb, ...)
end
--- Contract an area to include to the overlap of all areas
--- @param aabb BoundingBox
--- @param ... BoundingBox
--- @return BoundingBox? # Nil if there is no intersection
--- @param aabb BoundingBox.struct
--- @param ... BoundingBox.struct
--- @return BoundingBox.struct? # Nil if there is no intersection
function AABB.intersect(aabb, ...)
local rtn = AABB.clone(aabb)
for _, next_aabb in ipairs{ ... } do
@@ -88,8 +88,8 @@ function AABB.intersect(aabb, ...)
end
--- Check if a point is contained within an area
--- @param aabb BoundingBox
--- @param point MapPosition
--- @param aabb BoundingBox.struct
--- @param point MapPosition.struct
--- @return boolean # True if the point is within or on the edge of the bounding box
function AABB.contains_point(aabb, point)
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
--- Check if an area is fulling contained within another area
--- @param aabb BoundingBox
--- @param other BoundingBox
--- @param aabb BoundingBox.struct
--- @param other BoundingBox.struct
--- @return boolean # True if the point is within or on the edge of the bounding box
function AABB.contains_area(aabb, other)
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 = {}
--- @class Async.AsyncFunction
--- @field id number The id of this async function
--- @operator call: Async.AsyncReturn
--- @field id string The id of this async function
--- @overload fun(...: any): Async.AsyncReturn<any>
Async._function_prototype = {}
Async._function_metatable = {
@@ -104,10 +104,10 @@ Async._function_metatable = {
}
--- @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 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 completed boolean? True if the call has completed
--- @field return_values any? The return values of the function call
@@ -123,20 +123,20 @@ script.register_metatable("AsyncReturn", Async._return_metatable)
--- Storage Variables
local resolve_next --- @type Async.AsyncReturn[] 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_next --- @type Async.AsyncReturn<any>[] Stores a queue of async functions to be executed on the next 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
--- @param pending Async.AsyncReturn
--- @return Async.AsyncReturn
--- @param pending Async.AsyncReturn<any>
--- @return Async.AsyncReturn<any>
local function add_to_next_tick(pending)
resolve_next[#resolve_next + 1] = pending
return pending
end
--- Insert an item into the priority queue
--- @param pending Async.AsyncReturn
--- @return Async.AsyncReturn
--- @param pending Async.AsyncReturn<any>
--- @return Async.AsyncReturn<any>
local function add_to_resolve_queue(pending)
local tick = pending.tick
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
--- @param ... any The arguments to call the function with
--- @return Async.AsyncReturn
--- @return Async.AsyncReturn<any>
function Async._function_prototype:start_soon(...)
assert(Async._registered[self.id], "Async function is not registered")
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
--- @param ticks number The number of ticks to call the function after
--- @param ... any The arguments to call the function with
--- @return Async.AsyncReturn
--- @return Async.AsyncReturn<any>
function Async._function_prototype:start_after(ticks, ...)
ExpUtil.assert_argument_type(ticks, "number", 1, "ticks")
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
--- @param ... any The arguments to call the function with
--- @return Async.AsyncReturn | nil
--- @return Async.AsyncReturn<any> | nil
function Async._function_prototype:start_task(...)
assert(Async._registered[self.id], "Async function is not registered")
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
--- @param ... any The arguments to call the function with
--- @return Async.AsyncReturn
--- @return Async.AsyncReturn<any>
function Async._function_prototype:start_now(...)
assert(Async._registered[self.id], "Async function is not registered")
local status, rtn1, rtn2 = Async._registered[self.id](...)
@@ -261,7 +261,6 @@ local empty_table = setmetatable({}, {
--- Default status, will raise on_function_complete
--- @param ... any The return value of the async call
--- @return Async.Status, any[]
--- @type Async.Status
function Async.status.complete(...)
if ... == nil then
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
--- @param ... any The arguments to call the function with
--- @return Async.Status, any[]
--- @type Async.Status
function Async.status.continue(...)
if ... == nil then
return Async.status.continue, empty_table
@@ -284,7 +282,6 @@ end
--- @param ticks number The number of ticks to delay for
--- @param ... any The arguments to call the function with
--- @return Async.Status, number, any[]
--- @type Async.Status
function Async.status.delay(ticks, ...)
ExpUtil.assert_argument_type(ticks, "number", 1, "ticks")
assert(ticks > 0, "Ticks must be a positive number")
@@ -296,11 +293,11 @@ end
--- 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
--- Executes an async function and processes the return value
--- @param pending Async.AsyncReturn
--- @param pending Async.AsyncReturn<any>
--- @param tick number
local function exec(pending, tick)
local async_func = Async._registered[pending.func_id]
@@ -400,9 +397,9 @@ end
--- @package
function Async.on_init()
if storage.exp_async_next == nil then
--- @type Async.AsyncReturn[]
--- @type Async.AsyncReturn<any>[]
storage.exp_async_next = {}
--- @type Async.AsyncReturn[]
--- @type Async.AsyncReturn<any>[]
storage.exp_async_queue = {}
end
Async.on_load()
+15 -9
View File
@@ -42,12 +42,14 @@ end
--- @param options FlyingText.create_above_entity_param
function FlyingText.create_above_entity(options)
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 }
options.position = {
x = offset.x + entity.position.x,
y = offset.y + entity.position.y + size_y * 0.25,
x = offset.x + position.x,
y = offset.y + position.y + size_y * 0.25,
}
FlyingText.create(options)
@@ -62,12 +64,14 @@ end
function FlyingText.create_above_player(options)
local player = assert(options.target_player, "A target player is required")
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 }
options.position = {
x = offset.x + entity.position.x,
y = offset.y + entity.position.y + size_y * 0.25,
x = offset.x + position.x,
y = offset.y + position.y + size_y * 0.25,
}
FlyingText.create(options)
@@ -82,13 +86,15 @@ end
function FlyingText.create_as_player(options)
local player = assert(options.target_player, "A target player is required")
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 }
options.color = player.chat_color
options.position = {
x = offset.x + entity.position.x,
y = offset.y + entity.position.y + size_y * 0.25,
x = offset.x + position.x,
y = offset.y + position.y + size_y * 0.25,
}
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)
local failed, actual_type = check_type(arg_value, type_name)
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)
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
--- @return string # The relative filepath of the given stack frame
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__")
return safe_source == 1 and debug_info.short_src:sub(10, -5) or debug_info.source
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
--- @return string # The name of the module at the given stack frame
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("/")
if next_slash then
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
--- @return string # The name of the function at the given stack frame or provided as an argument
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 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
@@ -172,7 +172,7 @@ end
--- @param raw boolean? When true there will not be any < > around the name
--- @return string # The relative filepath of the given stack frame
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 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
@@ -207,7 +207,7 @@ end
function ExpUtil.auto_complete(options, input, use_key, rtn_key, use_pattern)
input = input:lower()
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
local str = use_key and k or v
local index = str:lower():find(input, nil, plain)
@@ -284,7 +284,7 @@ function ExpUtil.format_any(value, options)
end
return inspect(value, { depth = options.depth or 5, indent = "", newline = "", process = ExpUtil.safe_value })
end
return formatted
return formatted --[[@as LocalisedString]]
end
--- @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
if not units.days then
rtn.hours = rtn.hours + rtn.days * 24
rtn.hours = assert(rtn.hours) + assert(rtn.days) * 24
rtn.days = nil
end
if not units.hours then
rtn.minutes = rtn.minutes + rtn.hours * 60
rtn.minutes = assert(rtn.minutes) + assert(rtn.hours) * 60
rtn.hours = nil
end
if not units.minutes then
rtn.seconds = rtn.seconds + rtn.minutes * 60
rtn.seconds = assert(rtn.seconds) + assert(rtn.minutes) * 60
rtn.minutes = nil
end
if not units.seconds then
@@ -487,7 +487,7 @@ function ExpUtil.get_storage_for_stack(options)
-- Find a valid entity from the search results
local current, count, entities = cache.current, cache.count, cache.entities
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
cache.current = current + 1
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.
--- @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)
local entity
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.
--- @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)
local entity
for item_index = 1, #options.items do
@@ -551,7 +551,8 @@ function ExpUtil.move_items_to_surface(options)
options.item = item
entity = ExpUtil.get_storage_for_stack(options)
entity.insert(options.item)
options.item.clear()
local item_stack = options.item --[[@as LuaItemStack]]
item_stack.clear()
end
end
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.
--- @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)
options.items = options.inventory
local entity = ExpUtil.copy_items_to_surface(options)
@@ -604,6 +605,7 @@ end
--- @return string
function ExpUtil.comma_value(n) -- credit http://richard.warburton.it
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
end
+4 -4
View File
@@ -23,7 +23,7 @@ local Selection = {
--- @field player_index number
--- @field selection Selection.Active
--- @type table<string, { [defines.events]: Selection.event_handler[] }>
--- @type table<string, { [defines.events]: Selection.event_handler<any>[] }>
_registered = {},
--- @package
@@ -54,7 +54,7 @@ local selection_tool = { name = "selection-tool" }
--- @param player LuaPlayer
--- @return boolean?
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
--- Give a selection tool to a player if they don't have one
@@ -62,7 +62,7 @@ end
local function give_selection_tool(player)
if has_selection_tool_in_hand(player) then return end
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
--player.cursor_stack_temporary = true
@@ -84,7 +84,7 @@ end
local function remove_selection_tool(player, old_character)
-- Remove the selection tool
if has_selection_tool_in_hand(player) then
player.cursor_stack.clear()
assert(player.cursor_stack).clear()
else
player.remove_item(selection_tool)
end
+8 -39
View File
@@ -1,39 +1,8 @@
---@meta
---@class script
script = {
---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:
---
---Events that can be raised manually:
---
---* [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
---@meta
--- The api documents MapPosition and BoundingBox as a union of the named form
--- and a positional array, because both are accepted as input. Everything read
--- back from the game uses the named form, and we always write it that way too,
--- so the positional variant is removed here.
---@alias MapPosition MapPosition.struct
---@alias BoundingBox BoundingBox.struct