diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 870be0f9..9fa851c4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,8 +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 `CLUSTERIO` to your clusterio checkout, the lint needs it to resolve `modules/clusterio/*`. emmylua does not normalise `..` in a library path, so it cannot be written relative to this repo. -- Lua is checked with [emmylua](https://github.com/EmmyLuaLs/emmylua-analyzer-rust), configured by `.emmyrc.json`. Install the EmmyLua extension rather than sumneko, and let the factoriomod-debug extension write your machine local library paths to `.luarc.json`, which is git ignored. Note that an inline cast must be written `--[[@as T]]`, the spaced form is not parsed. +- 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. diff --git a/exp_commands/module/commands/help.lua b/exp_commands/module/commands/help.lua index 2a6c3b15..bb8c6c8b 100644 --- a/exp_commands/module/commands/help.lua +++ b/exp_commands/module/commands/help.lua @@ -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 "" - assert(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 diff --git a/exp_gui/module/control.lua b/exp_gui/module/control.lua index 0b5003a3..6c7114ec 100644 --- a/exp_gui/module/control.lua +++ b/exp_gui/module/control.lua @@ -116,8 +116,8 @@ end --- @param player LuaPlayer --- @return LuaGuiElement function Gui.get_top_element(define, player) - local value = assert(assert(player_elements[player.index]).top[define.name], "Element is not on the top flow") - return value + 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 @@ -125,8 +125,8 @@ end --- @param player LuaPlayer --- @return LuaGuiElement function Gui.get_left_element(define, player) - local value = assert(assert(player_elements[player.index]).left[define.name], "Element is not on the left flow") - return value + 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 @@ -134,8 +134,8 @@ end --- @param player LuaPlayer --- @return LuaGuiElement function Gui.get_relative_element(define, player) - local value = assert(assert(player_elements[player.index]).relative[define.name], "Element is not on the relative flow") - return value + 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 diff --git a/exp_gui/module/elements.lua b/exp_gui/module/elements.lua index aa343a1d..b4dbd472 100644 --- a/exp_gui/module/elements.lua +++ b/exp_gui/module/elements.lua @@ -319,8 +319,7 @@ Elements.screen_frame = Gui.define("screen_frame") --- @param screen_frame LuaGuiElement --- @return LuaGuiElement function Elements.screen_frame.get_button_flow(screen_frame) - local value = assert(Elements.screen_frame.data[assert(screen_frame.parent)], "Screen frame has no button flow") - return value + 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 diff --git a/exp_gui/module/prototype.lua b/exp_gui/module/prototype.lua index ee4a4fa0..07890a2d 100644 --- a/exp_gui/module/prototype.lua +++ b/exp_gui/module/prototype.lua @@ -168,8 +168,7 @@ end --- @param name string --- @return ExpElement function ExpElement.get(name) - local value = assert(ExpElement._elements[name], "ExpElement is not defined: " .. tostring(name)) - return value + return (assert(ExpElement._elements[name], "ExpElement is not defined: " .. tostring(name))) end --- Create a new instance of this element definition diff --git a/exp_legacy/module/expcore/datastore.lua b/exp_legacy/module/expcore/datastore.lua index 07fe28d5..08fe4de1 100644 --- a/exp_legacy/module/expcore/datastore.lua +++ b/exp_legacy/module/expcore/datastore.lua @@ -150,6 +150,8 @@ local Storage = require("modules/exp_util/storage") local DatastoreManager = {} local Datastores = {} --- @type table +local Data = {} + --- @class Datastore --- @field name string --- @field value_name string @@ -163,7 +165,7 @@ local Datastores = {} --- @type table --- @field events table --- @field data table local Datastore = {} -local Data = {} + local copy = table.deep_copy local trace = debug.traceback local table_to_json = helpers.table_to_json diff --git a/exp_legacy/module/expcore/external.lua b/exp_legacy/module/expcore/external.lua index c139179c..be8fb078 100644 --- a/exp_legacy/module/expcore/external.lua +++ b/exp_legacy/module/expcore/external.lua @@ -50,8 +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.") - local value = assert(ext.servers, "No server list was found, please ensure that the external service is running") - return value + 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 @@ -86,8 +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") - local value = assert(servers[server_id], "No details found for server with id: " .. tostring(server_id)) - return value + return (assert(servers[server_id], "No details found for server with id: " .. tostring(server_id))) end --[[-- Gets the details of the given server @@ -101,8 +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") - local value = assert(servers[server_id], "No details found for server with id: " .. tostring(server_id)) - return value + return (assert(servers[server_id], "No details found for server with id: " .. tostring(server_id))) end --[[-- Gets the status of the given server diff --git a/exp_legacy/module/expcore/roles.lua b/exp_legacy/module/expcore/roles.lua index b010ad50..641eeaea 100644 --- a/exp_legacy/module/expcore/roles.lua +++ b/exp_legacy/module/expcore/roles.lua @@ -376,8 +376,7 @@ function Roles.get_player_highest_role(player) end end - local value = assert(highest, "Player has no roles") - return value + return (assert(highest, "Player has no roles")) end --- Assignment. diff --git a/exp_scenario/module/commands/artillery.lua b/exp_scenario/module/commands/artillery.lua index e0a5bdf3..9f93732b 100644 --- a/exp_scenario/module/commands/artillery.lua +++ b/exp_scenario/module/commands/artillery.lua @@ -15,7 +15,7 @@ local abs = math.abs local commands = {} --- @param player LuaPlayer ---- @param area ExpUtil_AABB.Box +--- @param area BoundingBox.struct --- @return boolean local function location_break(player, area) local surface = player.surface -- Allow remote view diff --git a/exp_scenario/module/commands/protected_entities.lua b/exp_scenario/module/commands/protected_entities.lua index f2c71df2..7f906413 100644 --- a/exp_scenario/module/commands/protected_entities.lua +++ b/exp_scenario/module/commands/protected_entities.lua @@ -37,7 +37,7 @@ end --- Get the key used in protected_areas --- TODO expose this from EntityProtection ---- @param area ExpUtil_AABB.Box +--- @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,7 +49,7 @@ end local function show_protected_entity(player, entity) local key = get_entity_key(entity) if renders[player.index][key] then return end - local selection_box = entity.selection_box --[[@as ExpUtil_AABB.Box]] + local selection_box = entity.selection_box local rb = selection_box.right_bottom local position = entity.position renders[player.index][key] = rendering.draw_sprite{ @@ -69,7 +69,7 @@ end --- Show a protected area to a player --- @param player LuaPlayer --- @param surface LuaSurface ---- @param area ExpUtil_AABB.Box +--- @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 diff --git a/exp_scenario/module/commands/roles.lua b/exp_scenario/module/commands/roles.lua index 7cbfd8d0..b8a510ad 100644 --- a/exp_scenario/module/commands/roles.lua +++ b/exp_scenario/module/commands/roles.lua @@ -55,8 +55,7 @@ Commands.new("get-roles", { "exp-commands_roles.description-get" }) end local last = #roles_formatted - --- @diagnostic disable-next-line: need-check-nil - roles_formatted[last] = roles_formatted[last][2] + roles_formatted[last] = assert(roles_formatted[last])[2] return Commands.status.success(response) end) diff --git a/exp_scenario/module/control/deconstruction_log.lua b/exp_scenario/module/control/deconstruction_log.lua index 5d1743be..b6d2b05d 100644 --- a/exp_scenario/module/control/deconstruction_log.lua +++ b/exp_scenario/module/control/deconstruction_log.lua @@ -42,7 +42,7 @@ local function format_position(pos) end --- Convert an area to a string ---- @param area ExpUtil_AABB.Box +--- @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,8 +137,7 @@ 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 gun_index = player.character.selected_gun_index - --- @cast gun_index uint + 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 diff --git a/exp_scenario/module/control/degrading_tiles.lua b/exp_scenario/module/control/degrading_tiles.lua index 7707c0e8..dc3a1b11 100644 --- a/exp_scenario/module/control/degrading_tiles.lua +++ b/exp_scenario/module/control/degrading_tiles.lua @@ -32,7 +32,7 @@ local function degrade_entity(entity) local tiles = {} local surface = entity.surface - local bounding_box = entity.bounding_box --[[@as ExpUtil_AABB.Box]] + 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 diff --git a/exp_scenario/module/control/mine_depletion.lua b/exp_scenario/module/control/mine_depletion.lua index 7b5be7b5..f8a6cb55 100644 --- a/exp_scenario/module/control/mine_depletion.lua +++ b/exp_scenario/module/control/mine_depletion.lua @@ -167,7 +167,7 @@ local function try_deconstruct_miner(entity) create_entity(create_entity_param) -- Find all the entities to connect to - local bounding_box = entity.bounding_box --[[@as ExpUtil_AABB.Box]] + local bounding_box = entity.bounding_box local search_area = { { bounding_box.left_top.x - 1, bounding_box.left_top.y - 1 }, { bounding_box.right_bottom.x + 1, bounding_box.right_bottom.y + 1 }, diff --git a/exp_scenario/module/control/station_auto_name.lua b/exp_scenario/module/control/station_auto_name.lua index de8e5595..96b8fc09 100644 --- a/exp_scenario/module/control/station_auto_name.lua +++ b/exp_scenario/module/control/station_auto_name.lua @@ -57,7 +57,7 @@ local function rename_station(event) -- Find the closest resource local icon = "" local item_name = "" - local bounding_box = entity.bounding_box --[[@as ExpUtil_AABB.Box]] + local bounding_box = entity.bounding_box local resources = entity.surface.find_entities_filtered{ position = entity.position, radius = 250, type = "resource" } if #resources > 0 then local closest_recourse --- @type LuaEntity? @@ -66,7 +66,7 @@ local function rename_station(event) -- Check which recourse is closest for _, resource in ipairs(resources) do - local resource_box = resource.bounding_box --[[@as ExpUtil_AABB.Box]] + 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) diff --git a/exp_scenario/module/gui/module_inserter.lua b/exp_scenario/module/gui/module_inserter.lua index 74e1b287..33011cec 100644 --- a/exp_scenario/module/gui/module_inserter.lua +++ b/exp_scenario/module/gui/module_inserter.lua @@ -427,7 +427,7 @@ local function on_entity_settings_pasted(event) -- Attempt to rotate a machine to match the source machine if (source.name == destination.name or source.prototype.fast_replaceable_group == destination.prototype.fast_replaceable_group) then if source.supports_direction and destination.supports_direction and source.type ~= "transport-belt" then - local destination_box = destination.bounding_box --[[@as ExpUtil_AABB.Box]] + local destination_box = destination.bounding_box local ltx = destination_box.left_top.x local lty = destination_box.left_top.y diff --git a/exp_scenario/module/gui/rocket_info.lua b/exp_scenario/module/gui/rocket_info.lua index 7265238d..d7999db3 100644 --- a/exp_scenario/module/gui/rocket_info.lua +++ b/exp_scenario/module/gui/rocket_info.lua @@ -433,8 +433,7 @@ function Elements.progress_table.add_row(progress_table, row_data) progress.style.padding = { 0, 2 } progress.style.font_color = row_data.color - local unit_number = row_data.entity.unit_number - --- @cast unit_number uint + local unit_number = row_data.entity.unit_number --[[@as uint]] rows[unit_number] = { x = x, y = y, progress = progress } end @@ -457,8 +456,7 @@ 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 unit_number = row_data.entity.unit_number - --- @cast unit_number uint + 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 @@ -624,8 +622,7 @@ end function Elements.container.add_silo(entity) local force = entity.force --[[@as LuaForce]] local silos = Elements.container._get_force_data(force).silos - local unit_number = entity.unit_number - --- @cast unit_number uint + local unit_number = entity.unit_number --[[@as uint]] silos[unit_number] = { entity = entity, launched = 0, @@ -661,9 +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 - --- @cast force 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) @@ -678,7 +674,6 @@ local function on_cargo_pod_finished_ascending(event) -- Append the launch tick into the times array local times = Elements.container.get_launch_times(force) - --- @cast rockets_launched uint times[rockets_launched] = event.tick -- Discard the launch time that is no longer needed by any rolling average unless it is a milestone diff --git a/exp_util/module/aabb.lua b/exp_util/module/aabb.lua index 9ac567d6..7b985702 100644 --- a/exp_util/module/aabb.lua +++ b/exp_util/module/aabb.lua @@ -7,31 +7,26 @@ local ceil = math.ceil local min = math.min local max = math.max ---- An axis aligned bounding box using named members, the shorthand form is not supported ---- @class ExpUtil_AABB.Box ---- @field left_top MapPosition.struct ---- @field right_bottom MapPosition.struct - --- @class ExpUtil_AABB local AABB = {} --- Check if an area is valid ---- @param aabb ExpUtil_AABB.Box +--- @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 ExpUtil_AABB.Box +--- @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 ExpUtil_AABB.Box ---- @return ExpUtil_AABB.Box +--- @param aabb BoundingBox.struct +--- @return BoundingBox.struct function AABB.clone(aabb) return { left_top = { x = aabb.left_top.x, y = aabb.left_top.y }, @@ -40,8 +35,8 @@ function AABB.clone(aabb) end --- Expand an area to be integer aligned, expanding away from 0 ---- @param aabb ExpUtil_AABB.Box ---- @return ExpUtil_AABB.Box +--- @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) }, @@ -50,8 +45,8 @@ function AABB.expand(aabb) end --- Contract an area to be integer aligned, contracting towards 0 ---- @param aabb ExpUtil_AABB.Box ---- @return ExpUtil_AABB.Box +--- @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) }, @@ -60,9 +55,9 @@ function AABB.contract(aabb) end --- Expand an area to include all other areas ---- @param aabb ExpUtil_AABB.Box ---- @param ... ExpUtil_AABB.Box ---- @return ExpUtil_AABB.Box +--- @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 @@ -75,9 +70,9 @@ function AABB.union(aabb, ...) end --- Contract an area to include to the overlap of all areas ---- @param aabb ExpUtil_AABB.Box ---- @param ... ExpUtil_AABB.Box ---- @return ExpUtil_AABB.Box? # 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 @@ -93,7 +88,7 @@ function AABB.intersect(aabb, ...) end --- Check if a point is contained within an area ---- @param aabb ExpUtil_AABB.Box +--- @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) @@ -102,8 +97,8 @@ function AABB.contains_point(aabb, point) end --- Check if an area is fulling contained within another area ---- @param aabb ExpUtil_AABB.Box ---- @param other ExpUtil_AABB.Box +--- @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) diff --git a/exp_util/module/flying_text.lua b/exp_util/module/flying_text.lua index 9ec23028..180cd77e 100644 --- a/exp_util/module/flying_text.lua +++ b/exp_util/module/flying_text.lua @@ -42,7 +42,7 @@ 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 bounding_box = entity.bounding_box --[[@as ExpUtil_AABB.Box]] + 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 } @@ -64,7 +64,7 @@ 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 bounding_box = entity.bounding_box --[[@as ExpUtil_AABB.Box]] + 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 } @@ -86,7 +86,7 @@ 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 bounding_box = entity.bounding_box --[[@as ExpUtil_AABB.Box]] + 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 }