* docs: fully-expandable generated sidebar, replacing index.md link pages
Rework docs navigation so the sidebar expands to every page of every
reference tree, instead of terminating at generated index.md link lists:
- New docs/gen_sidebar.py (replaces gen_index.py + update_index.sh):
walks efun/, apply/, stdlib/, concepts/, driver/, cli/ and zh-CN/ and
emits sidebars.generated.json — a full Docusaurus category tree per
directory. Category landing pages are now `generated-index` card pages
(title/description/slug), so all generated index.md files are deleted.
--check mode verifies freshness; new .github/workflows/docs-sidebar.yml
runs it in CI.
- New docs/sidebar_meta.json holds curated presentation: category labels,
one-line descriptions (shown on the landing cards), explicit ordering
(driver/cli/concepts read top-down from user-facing to internals) and
per-page label overrides.
- sidebars.ts becomes a hand-authored skeleton (Getting Started, lpc/,
Historical) that splices in the generated trees.
Content reorganization (from a docs-wide review):
- Move misplaced efun pages out of efun/general: terminal/protocol efuns
(act_mxp, send_zmp, request_term_*) to interactive/, debugging efuns
(check_memory, dump_*, clear_debug_level, destructed_objects) to
internals/, shallow_inherit_list to system/.
- Delete stub duplicates superseded by complete pages elsewhere:
general/parse_{add_synonym,dump,my_rules,remove}, contrib/{shuffle,
element_of}.
Modernize key pages with MDX:
- index.mdx: landing page with a card grid linking each doc section.
- build.mdx: per-platform <Tabs> (Ubuntu/macOS/Windows/Alpine+Docker),
admonitions, VitePress [[toc]] leftover removed, stale per-platform CI
workflow links updated to the unified ci.yml.
- ffi-plan.md: GitHub-style [!CAUTION] alert converted to an admonition.
`npm run build` passes clean (onBrokenLinks: throw, no warnings).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0174GM2azvAHBmvyESwxm5om
* docs: serve the Chinese corpus through Docusaurus i18n
Move the zh-CN/ directory out of the default docs tree and into a proper
Docusaurus locale (i18n/zh-CN/docusaurus-plugin-content-docs/current/):
- The flat zh-CN/efun/ directory (333 pages) is re-homed to mirror the
categorized English layout (name-matched 1:1; `hash` maps to strings/
per its own frontmatter). apply/ pages map 1:1; the stray English-text
zh-CN/apply/master/view_errors.md documents a MudOS-era apply that no
longer exists in the driver and is dropped; stdlib/db/database_zh.md
becomes the i18n translation of stdlib/db/database.md; the Chinese
build guide becomes the translation of build.mdx.
- Untranslated pages automatically fall back to English content under
/zh-CN/, so the whole site is navigable in either locale from the new
navbar locale dropdown.
- Both locales share one sidebar. Generated sidebar items now carry
stable `key` fields (the directory/doc path) so translation keys are
unique (both efun/ and stdlib/ have an "Arrays" category, crypto and
strings both document `hash`). Category labels, generated-index
titles/descriptions, navbar and footer are translated in
i18n/zh-CN/...; theme UI strings come from Docusaurus' bundled
zh-Hans translations. Translated landing page at /zh-CN/.
- The "中文文档" sidebar section, the zh-CN tree in gen_sidebar.py /
sidebar_meta.json, and its slice of sidebars.generated.json are gone.
- Relative .md-file links on pages that render in both locales break
the localized build (the file->permalink map points at the localized
copy), so concepts/, the two socket_*_option pages and the config.md
generator now emit extension-less route links instead.
- zh interactive.md/objects.md get explicit slugs like their English
counterparts (a doc named after its parent directory is otherwise a
Docusaurus category-index doc, colliding with the generated-index
route).
`npm run build` builds both locales clean (onBrokenLinks: throw).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0174GM2azvAHBmvyESwxm5om
---------
Co-authored-by: Claude <noreply@anthropic.com>
6.5 KiB
| title |
|---|
| general / message_doc |
message_doc
the message() efun
message() is the FluffOS efun designed to make communication efuns more
generic. It attaches a classification (the message type) to every message so
that recipients can decide how to handle it, which in turn makes it
straightforward to communicate intelligently with capable clients.
Here is the manual page for message():
void message(mixed type, mixed message,
string | string * | object | object * target,
void | object | object * exclude);
message() calls receive_message(mixed type, mixed message) in all message
recipients (derived from the target list) excluding those in the exclude list.
This basically tells the objects the message through the receive_message apply.
The exclude argument is optional.
type is an arbitrary classification for the message. The driver does not
interpret it or forward it to the client on its own; it is simply passed along
to receive_message in each recipient, where your LPC code decides what to do
with it — for example, filtering out certain types, or forwarding it to a client
as part of some structured communication protocol. An example would be 'combat',
'shout', 'emergency', 'system', 'room description', etc.
message is the message to be sent, normally a string.
target is a list of objects to be sent the message. This can be either a
single object string or object pointer, or may be an array of either.
If a target is non-living, all objects in its environment will receive
the message.
exclude is a list of objects that should not receive the message. This
can be a single object pointer or an array of object pointers.
The most important element of this function is the type. Because every message
sent through message() carries one, the recipient's receive_message can
decide what to do per message — display it, discard it, filter by category, or
hand it to a client.
Note that this classification applies only to content sent via message(). The
traditional output efuns — say(), tell_object(), shout(), write(),
tell_room() — deliver their text through the catch_tell apply instead and
never reach receive_message. A mudlib that wants all of its output to be
classifiable typically routes that output through message() (often behind
simul_efuns), choosing whatever type names suit it, such as "shout", "say",
"tell", or "emote".
An example would be overriding the shout() efun in your simul_efun object
to use message():
void shout(string msg) {
object *exclude = ({});
if(this_player())
exclude += ({ this_player() });
message("shout", msg, users(), exclude);
}
Note the exclusion of this_player(). The built-in shout() and say() efuns
never echo back to the object performing the action (the command giver), so an
override that reproduces their behavior must keep that semantic and exclude
this_player() from the recipients.
Given this, let's say that you wanted to implement a quick and easy
earmuff ability (the ability to mask shouts). In your user (player)
object, you would have the function receive_message. Here's the
simplest implementation possible:
void receive_message(string type, string msg) {
receive(msg);
}
This simply takes all messages generated by the message() efun and
displays them to the user. However, you could imagine a simple
earmuffs implementation on top of this:
string *muffled = ({});
void muffle_type (string type)
{
muffled += ({ type });
}
void receive_message (string type, string msg)
{
if (member_array(type, muffled) == -1) {
receive(msg);
}
}
Now you can see that if a particular type is muffled (say, "shout" for example), the text never gets displayed, but for other types it does.
A single coarse type is rarely enough. Suppose a player muffles the "shout"
type, but an admin needs to announce that the system is going down in five
minutes. If that announcement is also sent (via message()) as type "shout",
the player misses it. This is why a mudlib usually defines a broader set of
types — for example a dedicated "broadcast" type for important announcements
that everyone should see, perhaps one that muffling is not permitted to block.
You can layer convenience simul_efuns on top of message() so that
writing content is as easy as the traditional write()/say() efuns
while still classifying every message. For example, an emote()
simul_efun that all soul commands use, passing the "emote" type, might
look like:
varargs int emote(object emoter, string self_message,
string other_message, mixed emotee,
string target_message, string modifier);
// emoter - the object doing the emoting
// self_message - the message displayed to the emoter
// other_message - the message displayed to the whole room
// emotee - the target of the emote (i.e. kick huthar)
// target_message - the message displayed to the emotee
// modifier - any extra modifier to tack on to the end of the
// emote string (i.e. adverbs: smiles happily,
// cheerfully, etc.) — only really complex soul
// commands need this
Talking to clients
Selective muffling is just one simple thing the type classification makes
possible. The larger payoff comes when the type is used to drive an out-of-band
client protocol: rather than only displaying the text, receive_message can
forward structured data to a capable client so it can route room descriptions,
conversation, combat, and status into separate windows or a status line.
When this document was originally written, no such standard existed, and it went
on to propose an ad-hoc "type:length:msg" text convention for a hypothetical
"smart client". That role is now filled by standardized out-of-band protocols
that FluffOS supports natively; use these rather than inventing your own wire
format:
- GMCP — Generic MUD Communication Protocol
- MSDP — Mud Server Data Protocol
- MXP — MUD eXtension Protocol
- MSP — MUD Sound Protocol
- ZMP — Zenith MUD Protocol
A typical pattern is to keep using message() with a meaningful type for
in-game classification, and have receive_message (or the relevant protocol
apply) hand a structured payload to the client through the appropriate efun,
such as send_gmcp().