From d6a31b12e3058912440a05bd03854bb1f4904517 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Wed, 29 Oct 2025 02:12:39 +0100 Subject: [PATCH] Add event publishing for inventory and combat interactions --- GameCore/Combat/DamageSystem.cs | 3 +++ GameCore/Combat/Effects/ConsumeAmmoCost.cs | 8 +++++++- GameCore/Combat/Effects/HitscanEffect.cs | 8 ++++++-- GameCore/Combat/ProjectileSystem.cs | 2 ++ GameCore/ECS/HitResult.cs | 6 +++++- GameCore/Events/EntityDamagedEvent.cs | 11 +++++++++++ GameCore/Events/HitscanImpactEvent.cs | 13 +++++++++++++ GameCore/Events/InstantItemUsedEvent.cs | 10 ++++++++++ GameCore/Events/InventoryItemChangedEvent.cs | 11 +++++++++++ GameCore/Events/ProjectileImpactEvent.cs | 10 ++++++++++ GameCore/Events/WeaponEquippedEvent.cs | 10 ++++++++++ GameCore/Inventory/InventorySystem.cs | 6 +++++- GameCore/Inventory/ItemAcquisitionSystem.cs | 1 + GameCore/Player/EquipmentSystem.cs | 2 ++ 14 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 GameCore/Events/EntityDamagedEvent.cs create mode 100644 GameCore/Events/HitscanImpactEvent.cs create mode 100644 GameCore/Events/InstantItemUsedEvent.cs create mode 100644 GameCore/Events/InventoryItemChangedEvent.cs create mode 100644 GameCore/Events/ProjectileImpactEvent.cs create mode 100644 GameCore/Events/WeaponEquippedEvent.cs diff --git a/GameCore/Combat/DamageSystem.cs b/GameCore/Combat/DamageSystem.cs index e8175ed..81b0bfc 100644 --- a/GameCore/Combat/DamageSystem.cs +++ b/GameCore/Combat/DamageSystem.cs @@ -34,5 +34,8 @@ public class DamageSystem : ISystem { var targetAttributes = _world.GetComponent(e.Target); targetAttributes?.ModifyValue(Attribute.Health, -e.Amount); + + var newHealth = targetAttributes?.GetValue(Attribute.Health) ?? 0f; + _world.PublishEvent(new EntityDamagedEvent(e.Target, newHealth, e.Amount)); } } \ No newline at end of file diff --git a/GameCore/Combat/Effects/ConsumeAmmoCost.cs b/GameCore/Combat/Effects/ConsumeAmmoCost.cs index 4138c06..d81e494 100644 --- a/GameCore/Combat/Effects/ConsumeAmmoCost.cs +++ b/GameCore/Combat/Effects/ConsumeAmmoCost.cs @@ -1,4 +1,5 @@ using GameCore.Combat.Interfaces; +using GameCore.Events; using GameCore.Inventory; namespace GameCore.Combat.Effects; @@ -8,7 +9,12 @@ public class ConsumeAmmoCost(string ammoId, int amount) : ICostEffect public void Execute(EffectContext context) { var inventory = context.World.GetComponent(context.Owner); - inventory?.RemoveItem(ammoId, amount); + if (inventory == null) return; + + inventory.RemoveItem(ammoId, amount); + + var newQuantity = inventory.GetItemCount(ammoId); + context.World.PublishEvent(new InventoryItemChangedEvent(context.Owner, ammoId, newQuantity)); } public bool CanAfford(EffectContext context) diff --git a/GameCore/Combat/Effects/HitscanEffect.cs b/GameCore/Combat/Effects/HitscanEffect.cs index c65decc..b804989 100644 --- a/GameCore/Combat/Effects/HitscanEffect.cs +++ b/GameCore/Combat/Effects/HitscanEffect.cs @@ -1,4 +1,5 @@ using GameCore.Combat.Interfaces; +using GameCore.Events; using GameCore.Input; namespace GameCore.Combat.Effects; @@ -12,8 +13,11 @@ public class HitscanEffect(float range) : IEffect if (input == null || weapon == null) return; - var targetPos = input.MuzzlePosition + input.MuzzleDirection * range; - var hit = context.World.WorldQuery.Raycast(input.MuzzlePosition, targetPos, context.Owner); + var fromPos = input.MuzzlePosition; + var targetPos = fromPos + input.MuzzleDirection * range; + var hit = context.World.WorldQuery.Raycast(fromPos, targetPos, context.Owner); + + context.World.PublishEvent(new HitscanImpactEvent(context.Owner, fromPos, targetPos, hit)); if (hit.DidHit) { diff --git a/GameCore/Combat/ProjectileSystem.cs b/GameCore/Combat/ProjectileSystem.cs index 52f3c68..3d1c329 100644 --- a/GameCore/Combat/ProjectileSystem.cs +++ b/GameCore/Combat/ProjectileSystem.cs @@ -1,6 +1,7 @@ using GameCore.Combat.Effects; using GameCore.ECS; using GameCore.ECS.Interfaces; +using GameCore.Events; using GameCore.Physics; namespace GameCore.Combat; @@ -24,6 +25,7 @@ public class ProjectileSystem : ISystem var hit = world.WorldQuery.Raycast(position.Position, newPosition, projectileData.Owner); if (hit.DidHit) { + world.PublishEvent(new ProjectileImpactEvent(projectile, hit)); var hitContext = new EffectContext { World = world, diff --git a/GameCore/ECS/HitResult.cs b/GameCore/ECS/HitResult.cs index a95dafa..e567190 100644 --- a/GameCore/ECS/HitResult.cs +++ b/GameCore/ECS/HitResult.cs @@ -1,7 +1,11 @@ +using GameCore.Math; + namespace GameCore.ECS; public struct HitResult { public bool DidHit; - public Entity HitEntity; + public Entity? HitEntity; + public Vector3 Position; + public Vector3 Normal; } \ No newline at end of file diff --git a/GameCore/Events/EntityDamagedEvent.cs b/GameCore/Events/EntityDamagedEvent.cs new file mode 100644 index 0000000..958f4aa --- /dev/null +++ b/GameCore/Events/EntityDamagedEvent.cs @@ -0,0 +1,11 @@ +using GameCore.ECS; +using GameCore.Events.Interfaces; + +namespace GameCore.Events; + +public readonly struct EntityDamagedEvent(Entity target, float newHealth, float damageTaken) : IEvent +{ + public readonly Entity Target = target; + public readonly float NewHealth = newHealth; + public readonly float DamageTaken = damageTaken; +} \ No newline at end of file diff --git a/GameCore/Events/HitscanImpactEvent.cs b/GameCore/Events/HitscanImpactEvent.cs new file mode 100644 index 0000000..e61ef45 --- /dev/null +++ b/GameCore/Events/HitscanImpactEvent.cs @@ -0,0 +1,13 @@ +using GameCore.ECS; +using GameCore.Events.Interfaces; +using GameCore.Math; + +namespace GameCore.Events; + +public readonly struct HitscanImpactEvent(Entity owner, Vector3 from, Vector3 to, HitResult hit) : IEvent +{ + public readonly Entity Owner = owner; + public readonly Vector3 From = from; + public readonly Vector3 To = to; + public readonly HitResult Hit = hit; +} \ No newline at end of file diff --git a/GameCore/Events/InstantItemUsedEvent.cs b/GameCore/Events/InstantItemUsedEvent.cs new file mode 100644 index 0000000..5071a11 --- /dev/null +++ b/GameCore/Events/InstantItemUsedEvent.cs @@ -0,0 +1,10 @@ +using GameCore.ECS; +using GameCore.Events.Interfaces; + +namespace GameCore.Events; + +public readonly struct InstantItemUsedEvent(Entity picker, string itemId) : IEvent +{ + public readonly Entity Picker = picker; + public readonly string ItemId = itemId; +} \ No newline at end of file diff --git a/GameCore/Events/InventoryItemChangedEvent.cs b/GameCore/Events/InventoryItemChangedEvent.cs new file mode 100644 index 0000000..3a96417 --- /dev/null +++ b/GameCore/Events/InventoryItemChangedEvent.cs @@ -0,0 +1,11 @@ +using GameCore.ECS; +using GameCore.Events.Interfaces; + +namespace GameCore.Events; + +public readonly struct InventoryItemChangedEvent(Entity owner, string itemId, int newQuantity) : IEvent +{ + public readonly Entity Owner = owner; + public readonly string ItemId = itemId; + public readonly int NewQuantity = newQuantity; +} \ No newline at end of file diff --git a/GameCore/Events/ProjectileImpactEvent.cs b/GameCore/Events/ProjectileImpactEvent.cs new file mode 100644 index 0000000..c1b325e --- /dev/null +++ b/GameCore/Events/ProjectileImpactEvent.cs @@ -0,0 +1,10 @@ +using GameCore.ECS; +using GameCore.Events.Interfaces; + +namespace GameCore.Events; + +public readonly struct ProjectileImpactEvent(Entity projectile, HitResult hit) : IEvent +{ + public readonly Entity ProjectileEntity = projectile; + public readonly HitResult Hit = hit; +} \ No newline at end of file diff --git a/GameCore/Events/WeaponEquippedEvent.cs b/GameCore/Events/WeaponEquippedEvent.cs new file mode 100644 index 0000000..c0688eb --- /dev/null +++ b/GameCore/Events/WeaponEquippedEvent.cs @@ -0,0 +1,10 @@ +using GameCore.ECS; +using GameCore.Events.Interfaces; + +namespace GameCore.Events; + +public readonly struct WeaponEquippedEvent(Entity owner, string newWeaponItemId) : IEvent +{ + public readonly Entity Owner = owner; + public readonly string NewWeaponItemId = newWeaponItemId; +} \ No newline at end of file diff --git a/GameCore/Inventory/InventorySystem.cs b/GameCore/Inventory/InventorySystem.cs index 20acf6e..a37ccb3 100644 --- a/GameCore/Inventory/InventorySystem.cs +++ b/GameCore/Inventory/InventorySystem.cs @@ -21,6 +21,10 @@ public class InventorySystem : ISystem private void OnAddItem(AddItemToInventoryEvent e) { var inventory = _world.GetComponent(e.Target); - inventory?.AddItem(e.Item); + if (inventory == null) return; + inventory.AddItem(e.Item); + + var newQuantity = inventory.GetItemCount(e.Item.ItemId); + _world.PublishEvent(new InventoryItemChangedEvent(e.Target, e.Item.ItemId, newQuantity)); } } \ No newline at end of file diff --git a/GameCore/Inventory/ItemAcquisitionSystem.cs b/GameCore/Inventory/ItemAcquisitionSystem.cs index 0c3d08e..ecd4389 100644 --- a/GameCore/Inventory/ItemAcquisitionSystem.cs +++ b/GameCore/Inventory/ItemAcquisitionSystem.cs @@ -27,6 +27,7 @@ public class ItemAcquisitionSystem : ISystem if (pickupComponent.IsInstantUse) { + _world.PublishEvent(new InstantItemUsedEvent(e.Picker, e.ItemId)); var context = new EffectContext { World = _world, diff --git a/GameCore/Player/EquipmentSystem.cs b/GameCore/Player/EquipmentSystem.cs index 564be28..09cd8b6 100644 --- a/GameCore/Player/EquipmentSystem.cs +++ b/GameCore/Player/EquipmentSystem.cs @@ -38,5 +38,7 @@ public class EquipmentSystem : ISystem weaponComponent.OnFireEffects = newData.OnFireEffects; weaponComponent.OnHitEffects = newData.OnHitEffects; weaponComponent.CooldownTimer = 0f; + + _world.PublishEvent(new WeaponEquippedEvent(e.Owner, e.NewWeaponItemId)); } } \ No newline at end of file