Commit Graph
2969 Commits
Author SHA1 Message Date
bbassieandClaude Opus 5 f9ce3c4145 Assert row lookups and narrow force and style reads
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 0b31a70801 Type forward declared handlers and assert element parents
The player list action setter runs during control setup, before any of
the callbacks that use it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 aca8bc79ae Assert the vlayer gui lookups
Dropdowns are siblings of the button that reads them, and the loop
bounds come from the interface count.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 d44381bac1 Assert the vlayer gui lookups
Dropdowns are siblings of the button that reads them, and the loop
bounds come from the interface count.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 7d8de94c2f Assert row lookups and the position shorthand
spawn_area accepts both position forms on purpose, so it asserts that
one of the two is present rather than narrowing the type.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 b75e283fc0 Narrow the remaining position, box and colour reads
Color.struct leaves every channel optional, so the rainbow command
declares its own fully populated colour.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 981eed7f34 Assert module inserter row and selector lookups
Rows and selectors are created alongside the machine selector, so they
exist for anything already in the table.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 d25fc42538 Assert vlayer runtime invariants and type its storage
The interfaces are chests and constant combinators, so the inventory,
logistic sections and first circuit section always exist.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 7bb874f73f Describe the legacy role type
get_player_roles always returns at least the default or root role, so
get_player_highest_role never returns nil, and callers were right to
treat it that way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 ce3b490554 Assert the debug frames exist
`debug.getinfo` is optional, but these helpers always ask for a frame
which is on the stack.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 bad00a9cef Describe the task list element data by key type
A union of table types makes every lookup optional. Separate index
signatures on one class say the same thing without the nil.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 a4213dadf5 Narrow positions and bounding boxes at the boundary
Values read back from the game always use the named members, so they
are narrowed once where they enter a function rather than at each use.

`LuaControl.force` is a ForceID union, so reading a force only method
off it needs the cast the rest of the repo already uses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 3f46055b70 Enable need-check-nil and start the burn down
`Roles.new_role` returned the result of `error`, which made it nullable,
and `set_permission_group` returned nil for an unknown group, which
broke the config chain with an index error rather than saying so.

Positions and bounding boxes read back from the game always use the
named members, so they are narrowed once where they enter a function.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:43 +00:00
bbassieandClaude Opus 5 1868616a4d Note the emmylua setup for contributors
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 f39da0c585 Type the last of the forward declarations
Locals declared ahead of an assignment inside a callback were inferred
as nil at every use site.

The role event handlers are given a class so the table is not unified
with the other module handler tables.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 5aeafa0e11 Fix child lookups, cache keys and loadstring
`loadstring` was removed in Lua 5.2, `load` takes a string the same way.

Warp gui child lookups are optional, so they use the same assert the
rest of the repo does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 b07052307d Fix stale vlayer signals and index types
`LogisticFilter.signal` became `value` in 2.0, so the clear loop broke
on the first slot and outdated signals were left behind.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 4745b6de0b Give the role methods an explicit self
emmylua takes self from the owner table, so `@param self ExpRoles.Role`
only applies with dot syntax. Call sites still use a colon.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 19fd1eabbe Correct container data keys and callable overloads
Autofill stores the whole per entity map against a player.
The readme container is called as a define, so it needs the overload
the other element classes carry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 d78ae40c5d Correct partial table types
`_display_data` is a cache keyed by force name, not a single record.
The auto complete accumulator starts empty, so its fields are optional.
Game commands have no usage beyond their own help text.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 1387b8a2db Fix gui element registration and iter removal
The top, left and relative element tables are keyed by the define, but
the duplicate registration assert looked up `define.name`, so it never
fired.

GuiIter.remove_element indexed `registered_scopes` by player index
instead of the scope elements it had just fetched, so it removed
nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 589b876865 Fix a nil config read and two key types
`config.temp_warning_limit` does not exist, the warnings config defines
`script_warning_limit`, and the locale expects it as `__3__/__4__`, so
the command was printing nil.

map_tags is keyed by the force name joined to the tag number, and
custom_color is the Color union.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 164672602d Make the @as casts actually apply
emmylua only parses the inline cast as `--[[@as T]]`, the spaced form
`--[[ @as T ]]` is treated as a plain comment, so all 149 of them were
doing nothing.

LuaGuiElement.style is a union because a style name can be assigned to
it, so reading it back needs the cast.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 fd2f5a9589 Type the player bonus element data and config
`data` on an element is the GuiData store keyed by element, not the
value being stored.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 8ae1144585 Fix logistic network stats for the 2.0 api
`get_contents` and `targeted_items_pickup`/`_deliver` return lists of
ItemWithQualityCount in 2.0, they are no longer name keyed dictionaries,
so the logistorage stats were indexing by array position.

PreferenceEnum is bidirectional, matching what ExpUtil.enum returns.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 2032cadc1b Fix rocket info silo pruning and unit number keys
The prune loop shadowed its own parameter, so `silo_data[unit_number] =
nil` wrote into the entry instead of removing it from the table.

`unit_number` is optional on LuaEntity but always set for a silo. Note
that `--[[ @as ]]` does not narrow for an index expression, only
`@cast` does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 ecf236d831 Describe the Datastore type
The registry and the prototype were both bare tables, so every
`datastore:method()` call resolved to nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 ab89b9feca Type vlayer forward declarations and config entries
The gui element locals are declared at the top and assigned far below,
so emmylua inferred them as nil at every use site.

circuit_oc was reassigned from a control behaviour to a logistic
section, which hid every section method behind the wrong type.

allowed_items entries carry heterogeneous optional properties, now
described by a class.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 0bb92966eb Fix type annotations the linter found to be wrong
Async ids come from `get_function_name`, which returns a string, but
were documented as numbers.

`setmetatable` in clusterio's compat module loses `LibCompat` on the
module return, so the require is cast.

`GuiData.__index` accepts a `DataKey` but emmylua needs that as an
index signature on the class.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 c233a9ab06 Defer need-check-nil and clean up stale suppressions
emmylua deserialises an unknown diagnostic code to a catch all that
matches no checker, so every `invisible`, `nil-check` and
`global-element` suppression was silently doing nothing. Renamed to the
emmylua codes. `name-style-check` has no equivalent and is dropped, it
was already disabled under luals.

The `get_tile` suppressions referenced an api typedef bug from 2024
which no longer reproduces.

need-check-nil is deferred rather than disabled on merit: a third of the
407 findings come from MapPosition and BoundingBox being aliased as
`struct|[double, double]`, so every `entity.position.x` reads as
possibly nil. The rest need per site knowledge of runtime invariants.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 b9cfbc9036 Narrow aabb types and give generic aliases their type argument
The aabb functions all index the named members, so passing the
shorthand [MapPosition, MapPosition] form would error at runtime. The
annotations now say so.

emmylua requires a type argument on a generic alias, luals did not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 90f32699c7 Fix duplicate class and annotation placement lint errors
Classes contributed to by more than one file now carry the `partial`
attribute. trains.lua declared its command as `ExpCommand_Artillery`,
which was a copy paste.

`Color.0` and `MapPosition.0` became `.struct` in fmtk 2.1.6.

emmylua rejects `@type` on a function statement or a `do` block, so
those are moved onto the local or replaced by `@param` and `@return`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
bbassieandClaude Opus 5 c6da1fd9ac Replace the luals lint config with emmylua
fmtk 2.1.4 onwards generates typedefs targeting emmylua that luals
misreads, and every fmtk changelog since 2.1.5 states luals support is
being dropped. luals 3.18.2 is already the latest release, so there is
nothing to bump.

The `--clusterio-modules` plugin has no emmylua equivalent, as emmylua
has no plugin interface, so it is reimplemented as `workspace.moduleMap`.
Those rules rewrite each file's own module path rather than the require
string, hence the reversed direction.

type.patch.lua is obsolete: `raise_event` now takes `LuaEventType` in
the generated typedefs, and `LuaObject` has become `LuaObject.base`.
exp_scenario/.luacheckrc was already dead, luacheck is never invoked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:31:18 +00:00
70471c5085 Pin factoriomod-debug to 2.1.3 in the lint workflow (#449)
FMTK 2.1.4 onwards reshapes its generated typedefs for EmmyLua, which
LuaLS misreads: 2.1.4 changed dicts to table<K,V> (game.surfaces.nauvis
now reports undefined-field) and 2.1.5 changed LocalisedString to the
variadic tuple [string, LocalisedString...], which LuaLS 3.18.2 cannot
match against a plain string. Together those account for all 279
findings CI has reported since 2026-07-13; with 2.1.3 the check is
clean.

Upstream FMTK has announced it is dropping sumneko/LuaLS support in
favour of EmmyLua, so this pin is a stopgap until the check is ported
to emmylua_check.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 21:32:43 +01:00
Cooldude2606andGitHub a324388bc8 Merge pull request #448 from bbassie/feature/roles-plugin
Add exp_roles plugin and scenario permissions
2026-08-06 15:45:04 +01:00
Cooldude2606 486151723e Fix game properties UI on small screens 2026-08-06 09:55:45 +01:00
bbassieandClaude Opus 5 1943d8743d Left align the role property labels
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 07:19:36 +00:00
bbassieandClaude Opus 5 dcba1eef1c Address review on the roles plugin
- Use the core role permissions rather than defining new ones. Assignments are
  only sent between the controller and an instance, so they are no longer
  addressed to control and need no permission at all.
- Split the datastore reconciliation into ensureRoleMeta, sweepRoleMeta and
  applyAutoAssign, all run on init as well as when roles change. Properties left
  behind by a role deleted while the plugin was not running are now swept up,
  where before they would be inherited by the next role given that id.
- Use a switch in onControllerConfigFieldChanged, matching instance.ts.
- Resolve pending assignments on initialise. A pending role is either confirmed,
  and so now held by synced_players, or it never landed; either way it stops
  being held locally. Roles assigned with assign_player_local are untouched.
- Drop the emit_updates juggling in reject_assignment, sync is already false.
- Send each permission name once and reference it by index, see the benchmark in
  the pull request. Single role updates stay in the plain form.
- Lay the role properties out in columns, name the apply button for the section
  it belongs to, and give every field a tooltip.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 08:04:36 +00:00
phidiasandGitHub 4255522c57 Research Log (#447)
* Update research.lua

* Fix config file references in research milestones
2026-08-04 14:35:26 +01:00
bbassieandClaude Opus 5 fcfa174794 Fix LuaLS findings in the roles module
Checked with the same LuaLS version and factorio library CI uses. The module now
reports no findings; the 279 which remain are all pre-existing and main is
already failing on them.

Most were annotations rather than behaviour. Two are worth noting:

- The role prototype is now its own class which the role inherits, since
  defining methods on a table annotated as the role counted as injecting fields
  into it.
- The role change message is built from a literal locale key per branch. Building
  the key by concatenation gives a plain string where a localised string is
  wanted, which is the same finding the legacy module reports.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 09:39:04 +00:00
bbassieandClaude Opus 5 bbd3b7c1f2 Add exp_roles plugin to sync roles from the controller
Clusterio already stores roles, the permissions they grant, and which user holds
which role, along with a web UI for all three. What it does not have is the
properties a role only needs in game, or a way for an instance to learn about
any of it, since role and user updates are only sent to control connections.

This plugin fills both gaps. The controller keeps a record per role holding the
order, priority, short hand, tag, colour and auto assign threshold, created
automatically for any role which does not have one. It then rebroadcasts roles
and assignments on its own events so instances can follow them.

The lua module presents the same interface the legacy expcore.roles module did,
so the call sites can be moved over without being rewritten. Permission checks
translate the legacy action strings using the same mapping exp_scenario defines.

Two things replace features the legacy system had:

- Priority replaces disallow. Only the roles with the highest priority a player
  holds are considered, so Jail can suppress every other role including the
  default one, without needing to take roles away first.
- Assignments made in game are applied locally and then sent to the controller,
  which keeps assign_player synchronous for callers. A role which should never
  leave this map, such as one earned from time on the map, is assigned with
  assign_player_local instead.

Roles earned from online time across the cluster are granted by the controller
from the threshold on the role, using the online time clusterio already tracks.

Nothing requires this plugin yet; moving the call sites off expcore.roles and
removing the legacy config is left for a follow up.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 09:28:40 +00:00
bbassieandClaude Opus 5 e852abc309 Define scenario permissions for legacy role actions
The role system is moving onto clusterio's own roles and permissions, which
requires every in game action to exist as a real permission rather than a bare
string held only by the lua config.

Adds a permission for each of the 104 actions and 7 flags used by the legacy
role config. Names are derived from the legacy action by a deterministic
transform, exported so the lua side can apply the same mapping and keep existing
call sites working. Command descriptions are taken from the existing locale
entries so they match what players already see.

Actions held by the Guest role are marked grantByDefault, since the in game
default role and clusterio's default role are the same concept.

Role management actions have no scenario permission; they map onto
core.user.update_roles and core.role.list instead.

Also corrects the /unjail description, which was a copy of /jail.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 09:11:26 +00:00
Cooldude2606 a07be7b7ed Bump version in package jsons 2026-07-14 00:50:00 +01:00
Cooldude2606 50daa81a4a Fix require for /debug 2026-06-29 01:14:39 +01:00
phidiasandGitHub c4f9c97130 remove limit (#446)
* Update surface.lua

* .

* .
2026-06-28 21:53:43 +01:00
Cooldude2606andGitHub 4fe0e9c0a6 Add AABB.size (#445) 2026-06-27 14:02:49 +01:00
Cooldude2606andGitHub 27b1a34a83 Merge pull request #443 from Cooldude2606/fix/lint
Fixes many lint issues and other bugs
2026-06-26 15:58:47 +01:00
phidiasandGitHub 1f3689a0ac entity api change (#442)
* Update warps.lua

* .

* .
2026-06-26 15:45:46 +01:00
Cooldude2606 7890540a3e Final lint fixes 2026-06-26 15:40:53 +01:00
Cooldude2606 8b3c437847 Move debug GUI out of legacy 2026-06-26 15:22:06 +01:00