Protocol 2.0 + 2.1 — account provisioning, world-state streams, Town Cryer news #7
@@ -345,7 +345,9 @@ Full character sheet: stats, all trained skills, worn equipment with flattened i
|
||||
{ "serial":"0x4002B3","layer":"OneHanded","itemId":5046,"hue":0,"cliloc":1023721,
|
||||
"weapon":{"minDamage":16,"maxDamage":18},
|
||||
"mods":{"WeaponDamage":50,"HitLightning":40} }
|
||||
]
|
||||
],
|
||||
"titles": { "selected": 0, "fameKarma": "Lord", "skill": "Grandmaster Swordsman",
|
||||
"reward": ["1154060", "The Bold"] }
|
||||
}
|
||||
```
|
||||
|
||||
@@ -353,6 +355,7 @@ Field notes:
|
||||
- `skills[].base` is trained value, `value` includes item/temp bonuses, `cap` is the cap. **Do not assume `base <= cap`** — GM characters can exceed it.
|
||||
- `equipment[].mods` is a flattened map of every non-zero AOS attribute on the item (weapon or armor). Empty `{}` for plain items.
|
||||
- Item names are usually **clilocs**, not strings: use `name` when present, otherwise resolve `cliloc` against a UO cliloc table on the site.
|
||||
- `titles` (Protocol 2.0): `selected` is the index into `reward` currently displayed (`-1` if none). `fameKarma`/`skill` are computed display titles, omitted when the character has none. `reward` entries may be a **cliloc number as a string** or a literal string — resolve numeric ones against your cliloc table, same as item names.
|
||||
- Errors: unknown account → **404** `{"kind":"bridge.error","reason":"unknown account"}`; bad slot → **404**/**400** similarly.
|
||||
|
||||
### Account roster
|
||||
|
||||
@@ -383,8 +383,8 @@ If the website mirrors rosters/links (it does — `store.record_link`), it must
|
||||
1. ~~**Guilds + governors.**~~ **Built (2026-07-17), compiles clean both sides.** `BridgeSocial.cs` (guild sweep + `JoinGuild` → `guild.update`/`guild.remove`/`guild.join`) and `BridgeGovernance.cs` (city sweep → `city.update`, gated on `CityLoyaltySystem.Enabled`), `GuildSweepSeconds` (60s) / `CitySweepSeconds` (300s) config, both wired into `[bridge reload|sweepnow|status`. Sidecar `guilds`/`governors` board tables + `GET /guilds`, `/governors` served from the store (the §12.2 snapshot rule). Shared `BridgeJson.Actor` writer (serial/name/acct/webId/player). **Deviation from the §10 sketch:** the wire uses full-state `guild.update`/`city.update` upserts (website derives "created"/"governor changed" from the board) rather than discrete `guild.created`/`city.governor` events — this avoids a reconnect re-emit looking like a storm of creations, matching the proven `champ.update` model. *Live end-to-end run still pending.*
|
||||
2. ~~**Presence.**~~ **Built (2026-07-17), compiles clean both sides.** `BridgePresence.cs`: a `presence.online` sweep (total + per-facet + per-region, emitted on change) and real-time `region.enter` (`EventSink.OnEnterRegion`, player-filtered). `PresenceSweepSeconds` (30s), wired into `[bridge`. `GET /online` serves the latest snapshot from the event store (population series via `/history?kind=presence.online`). *Live run pending.*
|
||||
3. ~~**Housing registry.**~~ **Built (2026-07-17), compiles clean both sides.** `BridgeHousing.cs`: a house sweep over `BaseHouse.AllHouses` → `house.update`/`house.remove` (owner, region, location, decay, co-owners, friends, price), complementing the existing `house.decay` transition feed. `HousingSweepSeconds` (300s), wired into `[bridge`. Sidecar `houses` board + `GET /houses`. (Stock ServUO has no "for sale" flag, so this is owner→houses; `price` is the placement value, not a listing.) *Live run pending.*
|
||||
4. **Titles.** `char.profile` `titles` block (§10.3) — no new stream, folds into `BridgeProfile`.
|
||||
5. **Factions/VvV** — only after confirming which system the shard runs; stream just the enabled one.
|
||||
4. ~~**Titles.**~~ **Built (2026-07-17), compiles clean.** `char.profile` gains a `titles` block (`selected`, `fameKarma`, `skill`, `reward[]`) from `PlayerMobile` accessors — no new stream, folds into `BridgeProfile`. *Live run pending.*
|
||||
5. **Factions/VvV** — **deferred** (owner decision): only after confirming which system the shard runs; stream just the enabled one.
|
||||
|
||||
Cross-cutting, lands with Phase 1: the **protocol bump to 2** (§12.1) and the **snapshot-companion rule** (§12.2). The provisioning siblings (§12.3) and mirror-hygiene (§12.4) attach to Part A's phasing since they extend the `account.*` surface.
|
||||
|
||||
|
||||
@@ -98,9 +98,55 @@ namespace Server.Custom.Bridge
|
||||
}
|
||||
sb.Append(']');
|
||||
|
||||
WriteTitles(sb, m);
|
||||
|
||||
return sb.End();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The titles a character holds (docs/PROTOCOL_2.md §10.3). `selected` is the index into
|
||||
/// `reward` currently displayed (-1 if none). `fameKarma` and `skill` are the computed
|
||||
/// display titles (may be absent). `reward` is the raw reward-title list — an entry may be
|
||||
/// a cliloc number (as a string) or a literal string; resolve clilocs website-side.
|
||||
/// </summary>
|
||||
private static void WriteTitles(StringBuilder sb, PlayerMobile m)
|
||||
{
|
||||
sb.Append(",\"titles\":{\"selected\":").Append(m.SelectedTitle);
|
||||
|
||||
var fameKarma = m.FameKarmaTitle;
|
||||
if (!String.IsNullOrEmpty(fameKarma))
|
||||
{
|
||||
sb.Append(",\"fameKarma\":");
|
||||
BridgeJson.Escape(sb, fameKarma);
|
||||
}
|
||||
|
||||
var skill = m.PaperdollSkillTitle;
|
||||
if (!String.IsNullOrEmpty(skill))
|
||||
{
|
||||
sb.Append(",\"skill\":");
|
||||
BridgeJson.Escape(sb, skill);
|
||||
}
|
||||
|
||||
sb.Append(",\"reward\":[");
|
||||
var rewards = m.RewardTitles;
|
||||
if (rewards != null)
|
||||
{
|
||||
bool first = true;
|
||||
for (int i = 0; i < rewards.Count; i++)
|
||||
{
|
||||
var r = rewards[i];
|
||||
if (r == null)
|
||||
continue;
|
||||
|
||||
if (!first) sb.Append(',');
|
||||
first = false;
|
||||
|
||||
BridgeJson.Escape(sb, Convert.ToString(r, System.Globalization.CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
sb.Append("]}");
|
||||
}
|
||||
|
||||
private static bool IsGearLayer(Layer layer)
|
||||
{
|
||||
switch (layer)
|
||||
|
||||
Reference in New Issue
Block a user