Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,9 @@ Explicitly out of scope for v1, to revisit later:
depends on this provider (co-developed with Jonas Ha) reaching a usable
state; SQLite remains the dev/default backend until then.
- **Hot-swap ruleset/plugin loading**: ruleset assemblies are loaded via a
compile-time project reference plus a startup assembly-scan (see
compile-time project reference plus explicit DI extension methods a
consumer calls at startup (see
[docs/engine-vs-ruleset.md](docs/engine-vs-ruleset.md)), not a MEF-style
drop-a-DLL-in-a-folder mechanism. True dynamic loading
drop-a-DLL-in-a-folder mechanism or an attribute-scan. True dynamic loading
(`AssemblyLoadContext`-based) is deferred until there's a real third party
wanting to redistribute a ruleset without a sharp-mud source checkout.
382 changes: 382 additions & 0 deletions docs/adr/0008-ruleset-scaffolding-tier.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,4 @@ the mechanics: numbering, status, and the index.
| [0005](0005-security-role-model-and-moderation-commands.md) | Security Role Model + Moderation Commands | Accepted |
| [0006](0006-nuget-package-distribution.md) | NuGet Package Distribution + Sample-Based Ruleset Extraction | Accepted |
| [0007](0007-narrow-meta-package-scope.md) | Narrow the `SharpMud` Meta-Package to Engine + Hosting + Persistence | Accepted |
| [0008](0008-ruleset-scaffolding-tier.md) | A Reusable RPG Scaffolding Tier Between `Engine` and Concrete Rulesets | Proposed |
9 changes: 9 additions & 0 deletions docs/engine-vs-ruleset.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,12 @@ revisit if guard logic keeps growing.
packages plus `SharpMud.Samples.Classic` as a reference consumer under
`samples/`. Implemented — this doc's project-structure listing above
reflects the current layout.
- `SharpMud.Samples.Classic` owning combat/stats scaffolding directly (not
just its own D&D-specific content) is addressed by
[ADR-0008](adr/0008-ruleset-scaffolding-tier.md) — a new
`SharpMud.Ruleset.Rpg` package for the reusable scaffolding, a new minimal
`SharpMud.Ruleset.Basic` package as a concrete quick-start leaf sibling to
Classic — both built directly on `SharpMud.Ruleset.Rpg`, neither depending
on the other — with Classic staying a still-unpackaged, richer sample. Not
yet implemented — this doc's project-structure listing above does not yet
reflect this.
279 changes: 279 additions & 0 deletions docs/plans/0008-ruleset-scaffolding-tier.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/plans/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,4 @@ isn't settled yet — don't do that.
| [0004](0004-session-state-machine-and-reconnect.md) | [ADR-0004](../adr/0004-session-state-machine-and-reconnect.md) | Done |
| [0005](0005-security-role-model-and-moderation-commands.md) | [ADR-0005](../adr/0005-security-role-model-and-moderation-commands.md) | Not Started |
| [0006](0006-nuget-package-distribution.md) | [ADR-0006](../adr/0006-nuget-package-distribution.md) | Done |
| [0008](0008-ruleset-scaffolding-tier.md) | [ADR-0008](../adr/0008-ruleset-scaffolding-tier.md) | Not Started |
63 changes: 46 additions & 17 deletions docs/research/wheelmud-findings.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,17 @@ directly rather than just "considered."

13 assemblies. The load-bearing split: `WheelMUD.Core` (engine) is completely
separate from `WarriorRogueMage` (a sample ruleset), and `WheelMUD.Universe`
(default world content) is separate from both.
is a third, independent sibling — checked directly against its actual file
list and `.csproj`: it's a library of generic, ruleset-agnostic *item-type*
behaviors (`WeaponBehavior`/`ArmorBehavior`/`PotionBehavior`/`ContainerBehavior`/
`CurrencyBehavior`/`PortalBehavior`/`LocksUnlocksBehavior`/etc.), not default
world/area content as an earlier version of this doc summarized. `Universe`
references only `Core`/`Data`/`Effects`, never `WarriorRogueMage`, and vice
versa; both are composed together only at `Main`. See
[ADR-0008](../adr/0008-ruleset-scaffolding-tier.md)'s Decisions for what this
means for sharp-mud (short version: nothing directly — sharp-mud already made
the equivalent call at the `Engine` tier itself, via `WearableBehavior`/
`EquippedBehavior`, rather than a separate package).

```
src/
Expand All @@ -31,7 +41,7 @@ src/
├── Server/ WheelMUD.Server — telnet networking, MCCP/MXP/NAWS
│ └── Telnet/
├── Data/, Data.RavenDb/ persistence (RavenDB document store)
├── Universe/ default world/area content bootstrap
├── Universe/ generic item-type behaviors (weapon/armor/potion/container/...)
├── WarriorRogueMage/ sample ruleset (stats/skills/races/combat) built entirely on Core
├── Main/, ServerHarness/ entry point / dev harness
└── Tests/
Expand Down Expand Up @@ -305,9 +315,10 @@ exports at priority 100 - a downstream game overriding one command exports at

**Not adopted** - `System.ComponentModel.Composition` is legacy tech, largely
superseded in modern .NET. We get the important property (ruleset assemblies
plug into the engine without the engine referencing them) from a reflection
scan over loaded assemblies plus standard DI registration instead - see
Decisions.
plug into the engine without the engine referencing them) from explicit,
package-level DI extension methods a consumer calls at startup
(`AddSharpMudRuleset(...)`, `AddSharpMudRpgRuleset(...)`,
`AddSharpMudBasicRuleset(...)`) instead - see Decisions.

## 9. Combat

Expand Down Expand Up @@ -368,17 +379,21 @@ update for the full design):
`MultipleParentsBehavior` mechanism described in §6, since the exit Thing
genuinely lives in both rooms' child lists at once.

2. **Ruleset plugins load via assembly-scan + DI, not MEF.** We get the
"engine doesn't reference ruleset code" property from reflection over
loaded assemblies (find types tagged `[GameAction]`/`[Behavior]` and
register them with the DI container at startup) instead of MEF's
`CompositionContainer`/`DirectoryCatalog`. This keeps the extensibility
property WheelMUD is built for while staying on the DI story
`docs/architecture.md` already committed to. True hot-swap-a-DLL-without-
rebuilding distribution (MEF's `DirectoryCatalog`) is not implemented yet -
`AssemblyLoadContext`-based dynamic loading can be added later if genuine
third-party redistribution (not just a separate project reference) is
needed.
2. **Ruleset plugins load via manual DI registration, not MEF and not
reflection/attribute-scanning.** We get the "engine doesn't reference
ruleset code" property from package-level DI extension methods a consumer
calls explicitly (`AddSharpMudRuleset(...)`, and per ADR-0008
`AddSharpMudRpgRuleset(...)`/`AddSharpMudBasicRuleset(...)`) instead of
MEF's `CompositionContainer`/`DirectoryCatalog` or reflection over loaded
Comment thread
ncipollina marked this conversation as resolved.
assemblies for tagged types. This keeps the extensibility property
WheelMUD is built for while staying on the explicit, no-MEF/no-dynamic-
loading DI story `docs/architecture.md` already committed to. True
hot-swap-a-DLL-without-rebuilding distribution (MEF's `DirectoryCatalog`)
is not implemented and not planned — `AssemblyLoadContext`-based dynamic
loading could be added later if genuine third-party redistribution (not
just a separate project reference) is ever needed, but manual DI
registration is the committed approach, not an interim step toward
scanning.

Additionally, the event system is simplified to one generic
`Publish<TEvent>(TEvent evt, EventScope scope) where TEvent : GameEvent`
Expand All @@ -390,7 +405,7 @@ don't require adding new delegate pairs to a growing interface.

3. **`Server/Telnet/`'s IAC/Q-Method negotiation is adopted, its byte-parser
class hierarchy is not** - see
[ADR-0002](../adr/0002-telnet-protocol-negotiation.md) (status: Proposed)
[ADR-0002](../adr/0002-telnet-protocol-negotiation.md) (status: Accepted)
for the full record. The RFC-1143 four-state negotiation tracking is
adopted near-verbatim; the 5-class persistent byte-parser state machine is
replaced with a single-call parser, since sharp-mud's read loop is already
Expand All @@ -410,6 +425,20 @@ don't require adding new delegate pairs to a growing interface.
[ADR-0005](../adr/0005-security-role-model-and-moderation-commands.md)/
[PLAN-0005](../plans/0005-security-role-model-and-moderation-commands.md).

5. **`Core.DiceService`/`Die`'s dice-rolling concept is adopted, its static
Comment thread
ncipollina marked this conversation as resolved.
singleton is not** - see
[ADR-0008](../adr/0008-ruleset-scaffolding-tier.md) for the full record.
WheelMUD treats "roll N-sided dice" as an engine-level concern
(`DiceService` lives in `WheelMUD.Core`, not `WarriorRogueMage`), which
sharp-mud agrees with in spirit, but `DiceService.Instance.GetDie(sides)`
is exactly the `XManager.Instance` static-singleton pattern §10 already
rejected, and has no multi-die/modifier (`2d6+3`) notation. sharp-mud
instead builds a small DI-registered dice-rolling abstraction ("N dice of
M sides plus a modifier") over the existing `IRandomSource` primitive, and
places it in `SharpMud.Ruleset.Rpg` rather than `SharpMud.Engine` - it's a
generic RPG mechanic, not bare randomness, so it doesn't belong at the
fully ruleset-agnostic engine tier the way WheelMUD's does.

Going forward, further reconciliation against WheelMUD (moderation/admin
tooling, session reconnect, world-building commands, and more) is tracked as
a sequenced roadmap in [ADR-0001](../adr/0001-wheelmud-reconciliation-roadmap.md)
Expand Down