Commit graph

15 commits

Author SHA1 Message Date
Stephen Dennis
2285fa54be chore(int64): quota, charges, queue counts stay full width after mux_atoi64 (#1402)
Maintainer direction: prefer int64_t over long/int for parsed softcode
and attribute integers so LLP64 and LP64 behave the same.

This first slice covers the leftovers called out on the issue:

- quota: store/show/set paths (avoids @quota/all 2^32 writing 0)
- A_CHARGES in set/levels/predicates (RUNOUT vs wrap-to-positive)
- semaphore counts and @ps/queue kick/warp parsing
- IDLETIMEOUT attribute seconds

Bounded API edges (RunTasks(int), optional int *pnum) clamp after the
full-width parse. pot: quota notify formats use %lld.
2026-07-28 19:40:41 -06:00
Stephen Dennis
9703d8c104 nls: format-string slices for create, set, and wiz (#1419)
Continue Phase 3 after the rob slice: mark player/staff tprintf,
mux_sprintf, and raw_broadcast format templates with M_() so whole
sentences like "%s created as room #%d." enter the catalogue.

Left as T(): softcode machine templates ("#%d") and the ANSI color
assembly ("%s%s%s") — not notify prose. Log-only "Strange object type"
stays T() as well.

Regenerate pot/xx/mo without fuzzy entries. Format and NLS guards green.
2026-07-27 15:04:54 +00:00
Stephen Dennis
9fca4a3921 nls: mark set.cpp notify prose with M_ (#1419)
Next notify slice: attribute/name/zone/lock/wipe player messages in
set.cpp (~73 sites, 54 unique msgids). Leave tprintf formats and the
@notify/quiet me command string as T(). Promote one half-mark
(did_it/default twin). Regenerate pot/xx (~113 catalog msgids).
2026-07-27 10:59:46 +00:00
Stephen Dennis
b5ee3b6f81 refactor: use UTF-8 text in user-facing string literals (#1513)
Replace ~900 typographic \xE2\x80\x.. escapes (curly quotes, en dashes)
and a few \xE2\x80\230 octal workarounds with real UTF-8 in message
strings under mux/modules and mux/src. Leave stringutil and convert
charset mapping tables as explicit byte sequences.
2026-07-26 21:52:48 -06:00
Stephen Dennis
2f106f200f fix(win32): migrate the remaining mux_atol callers to mux_atoi64 (#1373)
Completes the sweep the issue called for.  mux_atol returns long, which
is 32-bit on LLP64, so every caller silently truncated on Windows.  Two
of those were real defects (the truthiness family and cf_size, fixed in
the preceding commits); the rest were latent, waiting for a value large
enough to matter.

Rather than audit 290 sites for whether each can reach 2^31 today, use
the 64-bit parser everywhere and remove the class.  A dbref cannot
overflow now, but nothing stops a later caller passing that same site a
timestamp or a byte count.

Pure 1:1 substitution: 285 lines changed, and every removed line
contained mux_atol while every added line contains mux_atoi64.  No
control flow, no types, no behaviour beyond the wider parse.

This is a NO-OP on LP64 -- long is already 64-bit on Linux and macOS, so
the generated code there is unchanged.  It only widens the parse on
Windows.  Narrowing destinations are unaffected either way: `int x =
mux_atoi64(s)` truncates exactly as `int x = mux_atol(s)` did, on both
models.

Left alone: mux_atol itself in mathutil, its declaration, and three
comments that name it.  Callers that genuinely want 32-bit semantics can
still ask for them; none appear to.

Verified on Windows: full solution builds clean with no new warnings,
smoke is 1418 passed / 16 failed / 0 crashes / 306 of 306 dispatched --
identical to before the sweep, with the same 16 build-configuration
failures (exp3 module not loaded, hmac/digest behind UNIX_DIGEST).
Spot checks after the change: the boolean family returns 1 for multiples
of 2^32, cf_size round-trips 3000000000 and still reads -1 as unlimited,
and arithmetic, string and list functions are unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 10:12:35 -06:00
Stephen Dennis
72b1148dd5 fix(command): @include runs as includer, not source object (#1279)
Pass 12 (C3): do_include required only See_attr but executed the attribute
body as the source object via process_command_list_inline(thing, ...).
That is stronger than @trigger (Controls) and contradicts the comment that
include expands into the caller's action list.

Pass the includer as executor. Smoke TC011 locks VISUAL foreign-library
include so @set me= applies to the includer.

Closes #1279. Related #1280 (NOEVAL permit/ignore footgun, filed only).
2026-07-25 20:39:20 -06:00
Stephen Dennis
f068c5be21 engine: @dolist/now/break switch; ;| piping in inline command lists (#788)
Two follow-ups to the @dolist/now rewrite (37e18bef5):

- New /break switch: an @break inside the body still stops the loop,
  but with /break it also propagates to the enclosing command list,
  aborting the commands after the @dolist.  This restores the one
  ability the containment change removed (using a break inside the
  loop to abort the rest of a $-command), with sane loop-stop
  semantics, and mirrors @include (propagate by default, /nobreak to
  contain).  Without /now the switch is inert.

- ;| pipe segments now work in inline command lists.  The queued
  runner has always special-cased '|' after ';' to capture the
  previous command's output as %|; the inline loops in @dolist/now
  and @include treated such a segment as a literal command starting
  with '|' ("Huh?").  The splitting/pipe/break loop is factored into
  process_command_list_inline() in cque.cpp, shared by both callers
  and kept next to its queued twin so the semantics cannot drift.
  The inline list is its own pipe domain (save/restore of the
  enclosing pipe context), matching how each queued entry starts with
  a clean pipe state -- an inline list running inside a piped segment
  cannot corrupt the outer capture.

help @dolist documents /break and the ;| support.

Verified: default containment, /break propagation, and /break with no
inner break all behave as specified; pipes carry %| through inline
dolist and include bodies; smoke 1115/0/0 with three new test cases;
2x200 jit_diff clean.

Closes #788.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 09:00:21 -06:00
Stephen Dennis
900e3e3175 Convert ~75 atr_get/atr_pget sites to LBuf_Adopt across 17 files
Use the new LBuf_Adopt() macro to take RAII ownership of caller-owned
pool buffers returned by atr_get, atr_pget, and atr_get_LEN.  This
eliminates ~82 explicit free_lbuf calls and automatically covers
early-return paths that previously required careful manual placement
of the free.

Heaviest conversions: player.cpp (13), comsys.cpp (14), command.cpp (9).
Complex interleaved patterns (did_it charge/runout swaps, PureName
reassignment, process_cmdent loops) left manual for now.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:34:51 -06:00
Stephen Dennis
9b4c2946c2 Migrate ~55 alloc_lbuf/free_lbuf sites in large engine files to LBuf RAII
Fourth wave: ast (11), funceval (10), funceval2 (7), comsys (3),
speech (10), set (6), engine (7), command (10).  Covers the NOEVAL
handlers (cand/cor/if/switch/iter), function evaluators (ifelse,
letq, objeval, sortby, munge, while, sandbox), notify_check message
buffers, and command dispatch paths.  Buffers stored in fargs[]
arrays, returned through output pointers, or used in ping-pong swap
patterns are left manual.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:14:49 -06:00
Stephen Dennis
974964719c Convert all static scratch buffers to thread_local
43 static scratch-buffer arrays across 21 files (5 in mux/src, 38 in
mux/modules/) changed from `static` to `thread_local`. Under the
current single-threaded evaluator this is a zero-behavior-change swap
— `thread_local` storage has the same lifetime and zero-allocation
properties as `static` — but each thread gets its own copy, which
makes these functions safe for a future multi-threaded evaluator
without any locking.

Read-only constant tables (`aRadix64`, `aRadixPenn36`,
`aRadixPenn64`, `Empty`) left as `static` because they are immutable
shared data.

Affected areas:
  net.cpp        — queue_string co_buf, trimmed_site, dump_users NameField
  signals.cpp    — signal_desc
  stubslave.cpp  — Stub_PipePump
  attrcache.cpp  — sqlite_attr_buf
  boolexp.cpp    — parsestore
  command.cpp    — preserve_cmd, SpaceCompressCommand, LowerCaseCommand
  comsys.cpp     — NewTitle, Buffer, temp
  db.cpp         — tbuff, Buffer (x2)
  flags.cpp      — buff
  funceval.cpp   — textbuff
  functions.cpp  — TimeBuffer64, TimeBuffer80, Buffer
  help.cpp       — Line, Buffer
  mail.cpp       — aFolders, Buffer, res, szFittedMailAliasDesc
  match.cpp      — buffer
  player.cpp     — szSalt, buf (x2), buff
  plusemail.cpp   — buf
  predicates.cpp — Buf (x2), pName
  session.cpp    — szFittedDoing
  set.cpp        — pRestrictedKeyText
  unparse.cpp    — buf, boolexp_buf
  mail_mod.cpp   — result, res, buf

All 21 files verified with g++ -std=c++17 -fsyntax-only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 17:21:14 -06:00
Stephen Dennis
1bc324c022 Implement Phase 2 routing: per-zone tables with cross-zone meta-table
Partition the routing graph by Zone(room). Each zone has an independent
BFS table and generation counter, so topology changes in one zone do not
force rebuilds elsewhere. Rooms with no zone (NOTHING) are grouped into
a synthetic orphan zone.

Cross-zone routing uses a gateway-edge meta-table: exits that cross zone
boundaries are collected as GatewayEdge structs, and queries between
different zones run BFS over the zone graph to find the gateway chain,
then use local tables for intra-zone segments.

New API: route_invalidate_zone() and route_invalidate_meta() for
targeted invalidation. do_chzone() now invalidates both the old and new
zone plus the meta-table when a navigable room changes zones.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 03:53:13 -06:00
Stephen Dennis
a348e27f33 Implement Phase 1 routing: static unconditional next-hop tables
Add route() softcode function with BFS-based shortest-path routing
over rooms marked NAVIGABLE. The routing table stores only the next-hop
exit for each (source, dest) pair, compressed via diagonal elimination,
adjacent marking, and row redundancy. Lazy rebuild on generation-counter
mismatch triggered by topology changes (@dig, @destroy, @link, @open,
@unlink) and NAVIGABLE flag changes. SQLite schema v10 adds route_nodes,
route_table, route_meta tables for future persistence phases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 03:18:37 -06:00
Stephen Dennis
fe3cda5a79 Add PennMUSH and RhostMUSH feature adoption
PennMUSH: #lambda/#apply anonymous inline attributes, @include with
/nobreak /localize /clearregs, channel mogrifiers (MOGRIFY`BLOCK,
MESSAGE, FORMAT, OVERRIDE, NOBUFFER), cmogrifier().

RhostMUSH: between(), delextract(), garble(), caplist(), moon(),
soundex(), soundlike(), while(), crc32obj(), subnetmatch(),
wrapcolumns(), sandbox() with AST fallback for JIT compatibility.

21 new features/functions, 15 new smoke test files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:08:21 -06:00
Stephen Dennis
68e0c673e7 Feature: Add MSSP, GMCP, @protect, and benchmark()
Four new features identified from the TinyMUSH/PennMUSH/RhostMUSH survey:

MSSP (MUD Server Status Protocol, telnet option 70):
- Server sends structured key-value data (NAME, PLAYERS, UPTIME, PORT,
  CODEBASE, FAMILY) to MU* directory crawlers on IAC DO MSSP
- Stateless response via send_mssp() in telnet.cpp using g_dc config basket
- start_time_utc added to DRIVER_CONFIG for uptime calculation

GMCP (Generic MUD Communication Protocol, telnet option 201):
- Protocol negotiation: server offers WILL GMCP, tracks gmcp_enabled per DESC
- Inbound: GMCP subneg queued as synthetic "\x01GMCP" command, dispatched
  to handle_gmcp() which fires A_GMCP attribute with %0=package %1=json
- Outbound: gmcp(<player>, <package>, <json>) softcode function sends
  GMCP frames to all GMCP-enabled descriptors via SendGmcp COM method
- Full COM architecture: mux_IConnectionManager::SendGmcp in driver,
  send_gmcp() bridge in engine, CConnectionManager impl in modules.cpp

@protect (player name reservation):
- @protect[/add] <name>, @protect/del <name>, @protect/list [<player>]
- A_PROTECTNAME attribute (234) stores space-separated protected names
- protectname_check() hooked into create_player() and do_name()
- max_name_protect config param (default 5)

benchmark(<expression>, <iterations>):
- FN_NOEVAL, CA_PUBLIC, 10000 iteration cap
- Uses clock_gettime(CLOCK_MONOTONIC) / QueryPerformanceCounter
- Returns elapsed seconds as floating point

Also fixes: add unicode_tables.c to libmux.so LIBMUX_C_SRC (resolves
pre-existing tr_tolower_sbt etc. link errors).

505/505 smoke tests passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:08:55 -06:00
Stephen Dennis
4ff1398de1 Restructure mux/ directory: component-based layout with proper build root
Move from flat mux/src/ layout to clean component hierarchy:
- mux/ is now the autoconf/automake build root (configure.ac lives here)
- mux/include/ — shared headers used by multiple components
- mux/lib/ — libmux.so (core utilities, no game state)
- mux/src/ — netmux driver only (thin networking shell)
- mux/modules/engine/ — engine.so (game logic)
- mux/modules/{comsys,mail,exp3,sqlproxy,sqlslave}/ — external modules
- mux/ganl/ — GANL networking library
- mux/sqlite/ — SQLite amalgamation (builds libsqlite3.a)
- mux/announce/ — announce tool (was mux/src/tools/)

Build changes:
- SUBDIRS ordering: ganl sqlite lib src modules announce
- libmux.so gets -Wl,-soname,libmux.so; netmux links via -L -lmux
- engine.so links libsqlite3.a and libmux.so with -Wl,--no-undefined
- RPATH uses $ORIGIN for portable .so resolution
- Install hooks use absolute paths for game/bin symlinks

Bug fixes:
- engine.so mux_Register() now passes nullptr to mux_RegisterClassObjects
  (matches all other modules; libmux already has the factory via dlsym)
- DbConvert() now calls pcache_init() before db_write, fixing a latent
  crash (free(): invalid pointer) when exporting from SQLite databases

411/411 smoke tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:38:37 -06:00
Renamed from mux/src/set.cpp (Browse further)