Generated reference. This page mirrors
Code/Licences/README.md, this module's source-of-truth documentation (Standards/02_DOCUMENTATION_STANDARDS.md §1). Edit it there, not here -- this file is regenerated on every docs build and any local edit is silently overwritten.
Licences¶
Purpose. A player-earned/purchased licence that gates carrying or using items of a
restricted category — legacy never had this at all
(Legacy/01_FEATURE_INVENTORY.md,
"❌ … New"). Built as ROADMAP.md Milestone
14's own
named build item, with a Firearms licence gating ItemCategory.Weapons as the exit
criterion's own worked example. See
Documentation/Architecture/28_LICENCES.md.
Responsibilities.
- LicenceDefinition — one configured licence: Id, DisplayName, Cost, and
GatedCategories (the ItemCategory values holding it permits). Content, not code, the
exact shape Needs's NeedDefinition already established for
NeedsConfiguration.Definitions.
- LicenceConfiguration — the operator-tunable catalog, following
05_CONFIGURATION.md's per-module
GameResource pattern. Seeded with one entry (firearms, cost 500, gating Weapons).
PostLoad refuses a duplicate id and refuses two definitions gating the same category —
every category has at most one owning licence.
- ILicenceService / LicenceStore — the catalog reader (Definitions, FindDefinition,
RequiredLicenceFor) and PurchaseAsync: the validate, grant, save, debit, publish
sequence — in that order, and why, per LicenceStore.PurchaseAsync's own doc comment
(mirrors PropertyStore.PurchaseAsync's ordering exactly). No dedicated persistence
document: a held licence is Character-scoped state, persisted as part of CharacterDocument
itself (Character.Licences/CharacterLicences, Characters), not
a separate collection this module owns.
- ItemLicenceGate — the actual gate: a plain, engine-agnostic static method
(IsPermitted(ItemDefinition, Character, ILicenceService, out missingLicenceId)) answering
whether a character may use an item, given its category. The real, wired call site is
CharacterInventoryComponent.RequestUseItem
(Inventories) — this milestone's exit criterion in code.
- LicenceGranted — published once a purchase's grant-and-save has landed, mirroring
Applejack.World.DoorPurchased's shape.
- LicencesModule — registers LicenceConfiguration and ILicenceService.
Not responsible for.
- Item templates, categories, or behaviours — Items owns
ItemDefinition/ItemCategory/Equippable; this module only reads them.
- Which categories are actually gated, beyond the seeded Firearms example — an operator edits
LicenceConfiguration's asset to add more (e.g. an alcohol licence gating
ItemCategory.Alcohol), no code change required.
- PoliceWeapons/IllegalWeapons gating. PoliceWeapons is a job-loadout concept (once Jobs'
per-job loadouts are real, that is the right gate, not a purchasable licence);
IllegalWeapons is illegal by definition — no licence should ever legitimise carrying one.
See 28_LICENCES.md §4
for the full reasoning.
- An admin free-grant command (e.g. /grantlicence). CharacterLicences.Grant/Revoke are
public and idempotent, the same shape PermissionSet.Grant/Revoke already has, so a future
admin command can reuse them directly — not built this pass, since PurchaseAsync alone
satisfies this milestone's "a way to purchase/grant a licence" build item. See "Future
improvements".
- Licence expiry or renewal. A held licence is permanent once granted, the same "no
independent tick/decay" scope CharacterProgression already keeps for biography/attributes/
skills — deliberately minimal for this milestone; see "Future improvements".
Dependencies. Core (IServiceRegistry, IServiceResolver, IEventBus, IGameLog,
IConfigurationInspector), Character (Character, CharacterId, ICharacterService,
CharacterLicences), Economy (IEconomyService), Items (ItemCategory, ItemDefinition, for
the configuration shape and the gate).
Public API.
- ILicenceService — Definitions, FindDefinition(string), RequiredLicenceFor(ItemCategory),
PurchaseAsync(Character, string).
- LicenceDefinition, LicenceConfiguration.
- ItemLicenceGate.IsPermitted(ItemDefinition, Character, ILicenceService, out string?).
- LicenceGranted event.
- Applejack.Characters.CharacterLicences (Character.Licences) — Held, Has, Grant,
Revoke. Declared in Characters, not here, per
ADR-0011 point
2's "own composed type alongside Character" precedent — this module reads it, it does not
own it.
Events published. LicenceGranted — once PurchaseAsync has granted and saved.
Persistence. None owned directly — see LicenceStore's own header comment. A held licence
persists as CharacterDocument.Licences (schema version 4,
Characters).
Future improvements.
- An admin free-grant command, once a fork actually needs "give this player a licence for
free" — the underlying CharacterLicences.Grant/Revoke calls are already there.
- Licence expiry/renewal, if a fork's design wants licences to lapse — would need its own
timestamp field on CharacterLicences, following AccountModeration.ExpiresAtUtc's
precedent, not invented from scratch.
- Gating a second existing check beyond "use an item" (e.g. a vendor refusing to sell a
restricted item to a licence-less buyer, once Vendors
exists) — ItemLicenceGate is already general enough (ItemDefinition in, bool out) to
reuse at a second call site with no redesign.