using System; using AcDream.Core.Chat; using AcDream.Core.Combat; using AcDream.Core.Items; using AcDream.Core.Net.Messages; using AcDream.Core.Spells; namespace AcDream.Core.Net; /// /// Central registration point that wires every parsed GameEvent from /// into the appropriate Core state /// class (, , /// , ). /// /// /// Call once at startup (or on reconnect) passing the session's /// dispatcher + the state instances you want to feed. The wiring is /// additive — if you want to add a custom handler for a specific /// event, register it AFTER this helper so it overrides the default. /// /// /// /// This is the piece that makes Phase F.1's dispatcher go from "a /// thing that routes opcodes" to "a thing that actually populates /// client state so the UI can redraw". Without this glue every /// dispatcher handler had to be written by hand at each call site. /// /// public static class GameEventWiring { public static void WireAll( GameEventDispatcher dispatcher, ItemRepository items, CombatState combat, Spellbook spellbook, ChatLog chat) { ArgumentNullException.ThrowIfNull(dispatcher); ArgumentNullException.ThrowIfNull(items); ArgumentNullException.ThrowIfNull(combat); ArgumentNullException.ThrowIfNull(spellbook); ArgumentNullException.ThrowIfNull(chat); // ── Chat ────────────────────────────────────────────────── dispatcher.Register(GameEventType.ChannelBroadcast, e => { var p = GameEvents.ParseChannelBroadcast(e.Payload.Span); if (p is not null) chat.OnChannelBroadcast(p.Value.ChannelId, p.Value.SenderName, p.Value.Message); }); dispatcher.Register(GameEventType.Tell, e => { var p = GameEvents.ParseTell(e.Payload.Span); if (p is not null) chat.OnTellReceived(p.Value.SenderName, p.Value.Message, p.Value.SenderGuid); }); dispatcher.Register(GameEventType.CommunicationTransientString, e => { var p = GameEvents.ParseTransient(e.Payload.Span); if (p is not null) chat.OnSystemMessage(p.Value.Message, p.Value.ChatType); }); dispatcher.Register(GameEventType.PopupString, e => { var s = GameEvents.ParsePopupString(e.Payload.Span); if (s is not null) chat.OnPopup(s); }); // ── Combat ──────────────────────────────────────────────── dispatcher.Register(GameEventType.UpdateHealth, e => { var p = GameEvents.ParseUpdateHealth(e.Payload.Span); if (p is not null) combat.OnUpdateHealth(p.Value.TargetGuid, p.Value.HealthPercent); }); dispatcher.Register(GameEventType.VictimNotification, e => { var p = GameEvents.ParseVictimNotification(e.Payload.Span); if (p is not null) combat.OnVictimNotification( p.Value.AttackerName, p.Value.AttackerGuid, p.Value.DamageType, p.Value.Damage, p.Value.HitQuadrant, p.Value.Critical, p.Value.AttackType); }); dispatcher.Register(GameEventType.DefenderNotification, e => { var p = GameEvents.ParseDefenderNotification(e.Payload.Span); if (p is not null) combat.OnDefenderNotification( p.Value.AttackerName, p.Value.AttackerGuid, p.Value.DamageType, p.Value.Damage, p.Value.HitQuadrant, p.Value.Critical); }); dispatcher.Register(GameEventType.AttackerNotification, e => { var p = GameEvents.ParseAttackerNotification(e.Payload.Span); if (p is not null) combat.OnAttackerNotification( p.Value.DefenderName, p.Value.DamageType, p.Value.Damage, p.Value.DamagePercent); }); dispatcher.Register(GameEventType.EvasionAttackerNotification, e => { var name = GameEvents.ParseEvasionAttackerNotification(e.Payload.Span); if (name is not null) combat.OnEvasionAttackerNotification(name); }); dispatcher.Register(GameEventType.EvasionDefenderNotification, e => { var name = GameEvents.ParseEvasionDefenderNotification(e.Payload.Span); if (name is not null) combat.OnEvasionDefenderNotification(name); }); dispatcher.Register(GameEventType.AttackDone, e => { var p = GameEvents.ParseAttackDone(e.Payload.Span); if (p is not null) combat.OnAttackDone(p.Value.AttackSequence, p.Value.WeenieError); }); // ── Spells ──────────────────────────────────────────────── dispatcher.Register(GameEventType.MagicUpdateSpell, e => { var spellId = GameEvents.ParseMagicUpdateSpell(e.Payload.Span); if (spellId is not null) spellbook.OnSpellLearned(spellId.Value); }); dispatcher.Register(GameEventType.MagicRemoveSpell, e => { var spellId = GameEvents.ParseMagicRemoveSpell(e.Payload.Span); if (spellId is not null) spellbook.OnSpellForgotten(spellId.Value); }); dispatcher.Register(GameEventType.MagicUpdateEnchantment, e => { var p = GameEvents.ParseMagicUpdateEnchantment(e.Payload.Span); if (p is not null) spellbook.OnEnchantmentAdded( p.Value.SpellId, p.Value.LayerId, p.Value.Duration, p.Value.CasterGuid); }); dispatcher.Register(GameEventType.MagicRemoveEnchantment, e => { var p = GameEvents.ParseMagicRemoveEnchantment(e.Payload.Span); if (p is not null) spellbook.OnEnchantmentRemoved(p.Value.LayerId, p.Value.SpellId); }); dispatcher.Register(GameEventType.MagicDispelEnchantment, e => { var p = GameEvents.ParseMagicDispelEnchantment(e.Payload.Span); if (p is not null) spellbook.OnEnchantmentRemoved(p.Value.LayerId, p.Value.SpellId); }); dispatcher.Register(GameEventType.MagicPurgeEnchantments, _ => spellbook.OnPurgeAll()); // ── Inventory ───────────────────────────────────────────── dispatcher.Register(GameEventType.WieldObject, e => { var p = GameEvents.ParseWieldObject(e.Payload.Span); if (p is not null) items.MoveItem( p.Value.ItemGuid, newContainerId: p.Value.WielderGuid, newEquipLocation: (AcDream.Core.Items.EquipMask)p.Value.EquipLoc); }); dispatcher.Register(GameEventType.InventoryPutObjInContainer, e => { var p = GameEvents.ParsePutObjInContainer(e.Payload.Span); if (p is not null) items.MoveItem(p.Value.ItemGuid, p.Value.ContainerGuid, newSlot: (int)p.Value.Placement); }); dispatcher.Register(GameEventType.IdentifyObjectResponse, e => { var p = AppraiseInfoParser.TryParse(e.Payload.Span); if (p is null || !p.Value.Success) return; // Merge parsed properties into the item if we know about it. if (items.GetItem(p.Value.Guid) is not null) items.UpdateProperties(p.Value.Guid, p.Value.Properties); // Spell book from appraise: for ITEMS (caster / scrolls) this // lists cast-on-use effects; for players (PlayerDescription) // it's the whole learned spellbook. Both mutate the spellbook // by adding any not-yet-known ids. foreach (uint sid in p.Value.SpellBook) spellbook.OnSpellLearned(sid); }); } }