Skip to content

Commit b965baa

Browse files
committed
Simplify attributes and adopt Lua object parents
1 parent 7afa29a commit b965baa

74 files changed

Lines changed: 1728 additions & 6528 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,10 @@ if(BUILD_TESTING)
351351
"${CMAKE_SOURCE_DIR}/game/lua/object_logic/example.lua"
352352
"${CMAKE_SOURCE_DIR}/game/lua/object_logic/counter.lua"
353353
"${CMAKE_SOURCE_DIR}/game/lua/object_logic/events/enter_notice.lua"
354+
"${CMAKE_SOURCE_DIR}/game/lua/object_logic/default_thing.lua"
355+
"${CMAKE_SOURCE_DIR}/game/lua/object_logic/default_room.lua"
356+
"${CMAKE_SOURCE_DIR}/game/lua/object_logic/default_exit.lua"
357+
"${CMAKE_SOURCE_DIR}/game/lua/object_logic/default_player.lua"
354358
"${CMAKE_SOURCE_DIR}/game/lua/global_logic/example.lua"
355359
"${CMAKE_SOURCE_DIR}/game/lua/global_logic/who.lua")
356360

TODO

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22

33
## MUX Todos in the /src/ dir
44

5-
* Make `examine` an alias for `look` for non-Wizards
65
* Do we still need master rooms?
7-
* Remove $-command checking
86
* Do we still need object ownership?
9-
* Remove attribute flags?
7+
* Remove attribute flags and vattrs? vattr.c
108
* verbs.c and verbs.h can probably be crunched elsewhere
119
* Offer a non-privileged way to change your own password.
1210
* Add bad names list
@@ -16,6 +14,14 @@
1614
* Maybe: Figure out external RPC
1715
* Maybe: Figure out external event streaming. Websockets?
1816

17+
## DB schema stuff
18+
19+
* objects
20+
* expand powers fields into bools
21+
* expand flags fields into bools
22+
* drop parent
23+
* add luaparent and move from attribute
24+
1925
## Lua Todos
2026

2127
* Add `@luastatus` for effective-module inspection,

docs/content/en/docs/concepts/source-layout.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@ The MUX server is organized by responsibility beneath `src/mux`.
1010
- `server` contains platform definitions, configuration parsing, server state,
1111
lifecycle, logging, timers, signals, and file caches.
1212
- `support` contains reusable containers, buffer helpers, and string utilities.
13-
- `database` owns game objects, attributes, flags, powers, locks, and virtual
14-
attributes.
13+
- `database` owns game objects, exact-name Lua storage, flags, and powers.
1514
- `world` owns player, object, matching, movement, and presentation behavior.
1615
- `commands` owns command dispatch, queues, evaluation, and macros.
17-
- `communication` owns channels, communications attributes, and speech.
16+
- `communication` owns channels and speech.
1817
- `network` owns client descriptors, Telnet, sockets, and event scheduling.
1918
- `persistence` owns SQLite-backed MUX data.
2019
- `lua` owns the Lua runtime integration.
@@ -40,12 +39,12 @@ long-lived resources in dependency order:
4039
| Owner | Contains or depends on | Passed to |
4140
| --- | --- | --- |
4241
| `MuxServer` | Configuration, `BtechContext`, and all owners below | Startup and shutdown |
43-
| `GameDatabase` | Object array, cached names, attribute-number index, allocation bounds, freelist, and mark buffer | Database, persistence, world, and command code |
44-
| `PersistenceContext` | Borrowed configuration, database, vattrs, channels, macros, snapshot counters, and an owned bounded SQLite extension registry | Snapshot loading and writing |
42+
| `GameDatabase` | Object array, cached names, native subsystem state, exact-name Lua storage, allocation bounds, freelist, and mark buffer | Database, persistence, world, and command code |
43+
| `PersistenceContext` | Borrowed configuration, database, channels, macros, snapshot counters, and an owned bounded SQLite extension registry | Snapshot loading and writing |
4544
| `MacroRegistry` | Player macro sets and their capacity | Macro commands and commac persistence |
4645
| `ChannelRegistry` | Channel-name index and channel count | Comsys commands, functions, and commac persistence |
4746
| `CommandRegistry` | Built-in commands, prefixes, macros, functions, and user-function ordering | Command dispatch, evaluation, and configuration aliases |
48-
| `WorldIndexes` | Attribute, flag, power, player, forward-list, and parent-command indexes | Database, world, and command modules |
47+
| `WorldIndexes` | Flag, power, and player indexes | Database, world, and command modules |
4948
| `AccessControlStore` | Allowed, forbidden, and suspect sites plus disallowed player names | Configuration, connection, and player creation paths |
5049
| `WorldContext` | Borrowed database, configuration, world indexes, access-control store, and descriptor registry | Object, matching, lock, and world-facing command operations |
5150
| `ObjectList` | Results for one search or wildcard-attribute operation | Created and destroyed by the calling operation |
@@ -70,7 +69,6 @@ long-lived resources in dependency order:
7069
| `PlayerCache` | Per-player queue accounting | Queue and player operations |
7170
| `FileCache` | Connect, reject, quit, and rotating connection text | Network and file-list commands |
7271
| `HelpIndex` | Parsed article metadata rooted at one help directory | Help rendering and commands |
73-
| `VattrStore` | Dynamic attribute definitions and their string pool | Database persistence and attribute commands |
7472

7573
Core MUX and BTech source files no longer access the old `mudstate` or
7674
`mudconf` aliases. Context headers mark non-owning members as borrowed;

docs/content/en/docs/configuration/stompymux-toml.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,21 @@ anything pulled in through `include`.
2626
| `[flags]` | Flags set on new players/exits/rooms/robots/things (`player`, `exit`, `room`, `robot`, `thing` arrays). |
2727
| `[security]` | Password hashing and login rate limiting (see below). |
2828
| `[sites]` | Site ACLs: `forbid`, `suspect`, `trust`, `permit` arrays of `{ address, mask }` tables. |
29-
| `[access.*]` | Per-command/function/attribute permission tables (`commands`, `functions`, `attrs`, `attr_commands`, `lists`, `config`, plus the `user_attrs` array). |
30-
| `[aliases.*]` | Command/flag/function/attribute alias tables (`commands`, `flags`, `functions`, `attrs`). |
29+
| `[access.*]` | Per-command/function permission tables (`commands`, `functions`, `lists`, and `config`). |
30+
| `[aliases.*]` | Command, flag, and function alias tables (`commands`, `flags`, and `functions`). |
3131
| `[names]` | `bad`/`good` player-name lists. |
3232
| `[logging]` | `log` and `log_options` bitmask arrays. |
3333

3434
Most directives are plain scalars (`port = 5555`, `fork_dump = true`). A few
3535
directives take other shapes:
3636

37-
- **Flag/bitmask directives** (`[flags]`, `[logging]`, `user_attrs`) are TOML
37+
- **Flag/bitmask directives** (`[flags]` and `[logging]`) are TOML
3838
arrays of strings. `logging.log` is negatable: prefix an entry with `!` to
3939
clear a bit that's on by default (e.g. `log = ["!accounting", "bugs"]`).
4040
- **Alias directives** (`[aliases.*]`) are tables mapping the alias to its
4141
target, e.g. `"@ch" = "@chown"`.
42-
- **Access directives** (`[access.*]`, excluding `user_attrs`) are tables
43-
mapping a command/function/attribute name to one or more permissions, e.g.
42+
- **Access directives** (`[access.*]`) are tables
43+
mapping a command or function name to one or more permissions, e.g.
4444
`encrypt = "wizard"` or `"@dig" = ["wizard", "need_location"]`.
4545
- Building commands are restricted to Wizards. There is no global building
4646
toggle or `global_build` command-access permission.
@@ -50,6 +50,24 @@ directives take other shapes:
5050
An unrecognized key is logged to stderr and skipped rather than aborting the
5151
whole file; a syntax error in the TOML itself aborts loading.
5252

53+
## Default Lua parents
54+
55+
The `[mux]` section can assign an object-logic module to each newly created
56+
object type:
57+
58+
| Parameter | Shipped value | Applies to |
59+
| --- | --- | --- |
60+
| `default_thing_lua_parent` | `default_thing.lua` | Things |
61+
| `default_room_lua_parent` | `default_room.lua` | Rooms |
62+
| `default_exit_lua_parent` | `default_exit.lua` | Exits |
63+
| `default_player_lua_parent` | `default_player.lua` | Players and robots |
64+
65+
Paths are relative to `game/lua/object_logic`. Empty values disable automatic
66+
assignment for that type. Configuration changes apply only to objects created
67+
afterward and never backfill the database. `@clone` preserves the source
68+
object's Lua parent, including an empty one, instead of using the configured
69+
type default.
70+
5371
## Password and login security
5472

5573
Passwords are stored as Argon2id hashes through the vendored libsodium library.

docs/content/en/docs/scripting/overview.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ lua/
1818

1919
Attach a module to an object with the wizard-only `@lua/parent
2020
<object>=<path>.lua`; the path is relative to `object_logic`, and omitting it
21-
clears the attachment. The closest attachment in the object's ordinary MUX
22-
parent chain is active. See [Object scripting](scripting-objects/) for the
21+
clears the attachment. Each object uses only its own direct attachment. See
22+
[Object scripting](scripting-objects/) for the
2323
full module contract, the native event catalog, and how load errors are
2424
handled.
2525

@@ -32,8 +32,8 @@ after every local or zone Lua command has declined the command. See
3232
## Module contract
3333

3434
Each module returns a table with optional `commands`, `schedules`, and `flows`
35-
entries; object modules may also provide `events`, `locks`, and successful
36-
action `messages`. A command entry pairs a native Lua `pattern` with a
35+
entries; object modules may also provide `events`, `locks`, successful action
36+
`messages`, and appearance functions. A command entry pairs a native Lua `pattern` with a
3737
`handler(ctx, ...)`; returning `true` handles the command, `false` or `nil`
3838
lets other matching continue. See [Commands](commands/) for pattern syntax
3939
and the handler context table.
@@ -45,8 +45,8 @@ descriptor - the interactive counterpart to `commands` for menus, prompts,
4545
and confirmations. See [Interactive flows](flows/).
4646

4747
Object and global modules can also declare `schedules`: named entries with
48-
five-field UTC cron expressions. Object schedules run once for every object
49-
that effectively inherits the Lua parent; global schedules run once per
48+
five-field UTC cron expressions. Object schedules run once for every directly
49+
attached object; global schedules run once per
5050
matching module entry. Scheduled jobs receive deterministic jitter and do not
5151
replay missed minutes. Inspect active schedules with the wizard-only
5252
`@lua/schedule` command.
@@ -64,8 +64,9 @@ exposed.
6464
## The `mux` API
6565

6666
The `mux` table is the only server interface exposed to Lua modules:
67-
`attr_get`, `attr_set`, `notify`, `command`, `connected_players`,
68-
`who_summary`, and `flow_start`. Queued commands execute as `#1` after the
67+
`attr_get`, `attr_set`, `contents`, `contents_visible`, `exits`,
68+
`exits_visible`, `object_description`, `object_name`, `object_type`, `notify`, `command`,
69+
`connected_players`, `who_summary`, and `flow_start`. Queued commands execute as `#1` after the
6970
current handler completes. See the
7071
[`mux` package reference](packages/mux/) for the full API.
7172

docs/content/en/docs/scripting/packages/mux.md

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,83 @@ callback context to identify the object and enactor that triggered them.
1414

1515
## `mux.attr_get(object, name)`
1616

17-
Returns the string value of an attribute, or `nil` when the attribute is absent
18-
or has an empty value.
17+
Returns the string value of a dynamic storage entry, or `nil` when it is
18+
absent. Names are exact and case-sensitive, so `Title` and `title` are distinct.
1919

2020
```lua
2121
local title = mux.attr_get(ctx.object, "Title") or "Untitled"
2222
```
2323

24-
`object` must be a valid dbref and `name` must name an existing attribute.
25-
Passing an invalid object raises a Lua error.
24+
`object` must be a valid dbref. Passing an invalid object raises a Lua error.
2625

2726
## `mux.attr_set(object, name, value)`
2827

29-
Sets an attribute to a string value. The attribute is created when necessary.
28+
Sets a dynamic storage entry to a string value. The entry is created when
29+
necessary; an empty value deletes it. Names must begin with a letter, may use
30+
the server's printable attribute-name characters, and are limited to 255 bytes.
3031

3132
```lua
3233
mux.attr_set(ctx.object, "LuaCount", "42")
3334
```
3435

35-
`object` must be a valid dbref. Lua cannot use this function to set
36-
`Luaparent`; use the wizard-only `@lua/parent` command instead.
36+
`object` must be a valid dbref. Dynamic entries have no flags, owners,
37+
inheritance, reserved names, or native server behavior.
38+
39+
## `mux.contents(object)`
40+
41+
Returns an array of dbrefs directly contained by a room, thing, or player in
42+
native database order. The result is deliberately unfiltered.
43+
44+
```lua
45+
for _, member in ipairs(mux.contents(ctx.object)) do
46+
if mux.contents_visible(ctx.object, ctx.enactor, member) then
47+
mux.notify(ctx.enactor, mux.object_name(member))
48+
end
49+
end
50+
```
51+
52+
## `mux.contents_visible(container, viewer, member)`
53+
54+
Returns whether native `look` would display `member` in `container` to
55+
`viewer`, including location darkness, object darkness, disconnected-player,
56+
self, and examinability rules. `member` must be directly contained by
57+
`container`.
58+
59+
## `mux.exits(object)`
60+
61+
Returns an unfiltered array of exits directly attached to a room, thing, or
62+
player in native database order. Legacy MUX parent exits are not inherited.
63+
64+
```lua
65+
for _, exit in ipairs(mux.exits(ctx.object)) do
66+
if mux.exits_visible(ctx.object, ctx.enactor, exit) then
67+
mux.notify(ctx.enactor, mux.object_name(exit))
68+
end
69+
end
70+
```
71+
72+
## `mux.exits_visible(location, viewer, exit)`
73+
74+
Returns whether native `look` would display a directly attached exit to the
75+
viewer. The exit must belong directly to `location`.
76+
77+
## `mux.object_name(object)`
78+
79+
Returns the object's stored name. Exit names include their semicolon-separated
80+
aliases.
81+
82+
## `mux.object_description(object)`
83+
84+
Returns the object's native MUX `description` value, or `nil` when it is not
85+
set. This is separate from the exact-name dynamic storage read by
86+
`mux.attr_get`.
87+
88+
## `mux.object_type(object)`
89+
90+
Returns `room`, `thing`, `exit`, or `player`.
91+
92+
All object arguments must be valid, non-garbage dbrefs. Passing a container of
93+
the wrong type or a member that is not directly attached raises a Lua error.
3794

3895
## `mux.notify(object, message)`
3996

@@ -95,7 +152,9 @@ running, or `module` has no `first_step` in its `flows` table.
95152

96153
## Availability and limits
97154

98-
The `mux` table is the only server interface exposed to Lua modules. The Lua
155+
The `mux` table is the only server interface exposed to Lua modules. Runtime
156+
database functions, including object enumeration and identity, are unavailable
157+
during `@lua/check`. The Lua
99158
sandbox does not expose filesystem, operating-system, debugger, FFI, coroutine,
100159
or dynamic code-loading APIs. Handler instruction and state-memory limits still
101160
apply while using these functions.

docs/content/en/docs/scripting/scripting-objects.md

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,16 @@ The path is relative to `object_logic`; for example,
1818
cannot escape into `global_logic` or `packages`. Omit the path to clear an
1919
attachment.
2020

21-
The closest `Luaparent` in an object's normal MUX parent chain supplies the
22-
active module. Reload all attached modules and their dependencies atomically
21+
The `[mux]` settings `default_thing_lua_parent`, `default_room_lua_parent`,
22+
`default_exit_lua_parent`, and `default_player_lua_parent` assign direct Lua
23+
parents to newly created objects of each type. Paths use the same
24+
`object_logic`-relative format as `@lua/parent`; robots use the player default.
25+
Changing a default does not update existing objects. Clones preserve the
26+
source object's Lua parent (or its lack of one) rather than receiving the type
27+
default.
28+
29+
An object uses only the `Luaparent` attached directly to it. Lua modules are
30+
not inherited through other objects. Reload all attached modules and their dependencies atomically
2331
with `@lua/reload`; a failed reload leaves the current Lua state running.
2432
Use [`@lua/check`](validating-and-reloading/) to validate every Lua module
2533
before reloading.
@@ -31,16 +39,17 @@ and are treated as handled.
3139
Restore the file or update `Luaparent`, then use `@lua/reload` to activate the
3240
repair. `@lua/reload` itself remains atomic and rejects a missing attachment.
3341

34-
When a Wizard uses `@examine` on an object, the output identifies its effective
35-
Lua parent and attachment object, then lists its command patterns, events,
42+
When a Wizard uses `@examine` on an object, the output identifies its direct
43+
Lua parent, then lists its appearance functions, command patterns, events,
3644
schedule names, message providers, and locks. Use `@lua/viewparent <dbref>` to
3745
display that module's raw source, or `@lua/viewparent <path>.lua` to inspect an
3846
object-logic module directly by path.
3947

4048
## Module contract
4149

4250
An object module returns a table with optional `commands`, `events`, `locks`,
43-
`messages`, and `schedules` tables.
51+
`messages`, and `schedules` tables, plus optional `internal_appearance` and
52+
`external_appearance` functions.
4453
Command entries use native Lua patterns and a handler:
4554

4655
```lua
@@ -64,6 +73,25 @@ Object event functions use the native Lua event names listed below. Event names
6473
are validated by `@lua/check`; an unknown name or non-function value is an
6574
error.
6675

76+
## Custom appearances
77+
78+
`internal_appearance(ctx)` and `external_appearance(ctx)` may return a string
79+
to replace all native `look` output for the object. Returning `nil` or no value
80+
uses the native name, description, contents, and exits. An empty string is a
81+
valid override that displays nothing.
82+
83+
Rooms always use `internal_appearance`, including a Wizard looking at a room
84+
remotely. Other objects use the internal function when the viewer is physically
85+
inside the object and the external function otherwise. A successful override
86+
suppresses the native name, description, contents, exits, and transparent-exit
87+
continuation. The normal room look lock and `on_describe` event still run.
88+
89+
The context has the usual `object`, `enactor`, `cause`, and optional
90+
`descriptor` fields, plus `appearance`, whose value is
91+
`internal_appearance` or `external_appearance`. Runtime errors, invalid return
92+
types, embedded NUL bytes, and oversized strings are logged and fall back to
93+
the native appearance.
94+
6795
## Object locks
6896

6997
Define locks as functions in the module's `locks` table. The supported keys
@@ -186,7 +214,7 @@ messages come from the structured lock result or the native defaults.
186214
Movement also invokes the applicable cross-location message providers, which
187215
do not have corresponding events.
188216

189-
Connection events run for the player's effective module, the master room and
217+
Connection events run for the player's attached module, the master room and
190218
its contents, and the applicable zone object or zone-room contents. Both
191219
receive `ctx.descriptor`. `on_connect` also receives boolean `ctx.reconnect`;
192220
`on_disconnect` receives string `ctx.reason` and runs only for the final active
@@ -217,12 +245,12 @@ schedules = {
217245
name = "hourly_notice",
218246
cron = "0 * * * *",
219247
handler = function(ctx)
220-
-- ctx.scope == "object" and ctx.object is the effective object.
248+
-- ctx.scope == "object" and ctx.object is the attached object.
221249
end,
222250
},
223251
}
224252
```
225253

226-
A shared `Luaparent` runs each matching schedule once for every object that
227-
inherits it. Use the wizard-only `@lua/schedule` command to inspect active
228-
schedules and their effective objects.
254+
A shared module path runs each matching schedule once for every object directly
255+
attached to it. Use the wizard-only `@lua/schedule` command to inspect active
256+
schedules and their attached objects.

docs/content/en/docs/scripting/validating-and-reloading.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ and global logic modules into service.
3737
## Inspecting schedules
3838

3939
Wizards can use `@lua/schedule` to list scheduled object modules with their
40-
effective-object counts and scheduled global logic modules. Pass an object to
41-
show its effective Lua parent, a relative `object_logic` path to show its
42-
schedules and inheriting objects, or `global_logic/<path>.lua` to inspect one
40+
directly attached object counts and scheduled global logic modules. Pass an object to
41+
show its direct Lua parent, a relative `object_logic` path to show its
42+
schedules and attached objects, or `global_logic/<path>.lua` to inspect one
4343
global module.

0 commit comments

Comments
 (0)