From f70251fa3b34c494058a879a2a5f7e598d03aa03 Mon Sep 17 00:00:00 2001 From: Evil Factory <36804725+evilfactory@users.noreply.github.com> Date: Sun, 15 Feb 2026 17:58:25 -0300 Subject: [PATCH] Event pain --- .../AI/Objectives/AIObjectiveManager.cs | 4 - .../SharedSource/Characters/Character.cs | 6 - .../SharedSource/Items/Inventory.cs | 10 - .../SharedSource/Items/Item.cs | 15 -- .../SharedSource/LuaCs/IEvents.cs | 190 +++++++++++++++++- .../_Services/HarmonyEventPatchesService.cs | 99 +++++++++ .../_Services/LuaScriptManagementService.cs | 9 + 7 files changed, 294 insertions(+), 39 deletions(-) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveManager.cs index 83e475c37..23aea4234 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveManager.cs @@ -103,10 +103,6 @@ namespace Barotrauma public void AddObjective(T objective) where T : AIObjective { - var result = GameMain.LuaCs.Hook.Call("AI.addObjective", this, objective); - - if (result != null && result.Value) return; - if (objective == null) { #if DEBUG diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index 3436ec8a6..198ff8d93 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -4605,12 +4605,6 @@ namespace Barotrauma public AttackResult DamageLimb(Vector2 worldPosition, Limb hitLimb, IEnumerable afflictions, float stun, bool playSound, Vector2 attackImpulse, Character attacker = null, float damageMultiplier = 1, bool allowStacking = true, float penetration = 0f, bool shouldImplode = false, bool ignoreDamageOverlay = false, bool recalculateVitality = true) { if (Removed) { return new AttackResult(); } - - AttackResult? retAttackResult = GameMain.LuaCs.Hook.Call("character.damageLimb", this, worldPosition, hitLimb, afflictions, stun, playSound, attackImpulse, attacker, damageMultiplier, allowStacking, penetration, shouldImplode); - if (retAttackResult != null) - { - return retAttackResult.Value; - } SetStun(stun); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Inventory.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Inventory.cs index d1be5145e..ce4da3bda 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Inventory.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Inventory.cs @@ -651,11 +651,6 @@ namespace Barotrauma return; } - var should = GameMain.LuaCs.Hook.Call("inventoryPutItem", this, item, user, i, removeItem); - - if (should != null && should.Value) - return; - if (Owner == null) { return; } Inventory prevInventory = item.ParentInventory; @@ -765,11 +760,6 @@ namespace Barotrauma if (slots[index].Items.Any(it => !it.IsInteractable(user))) { return false; } if (!AllowSwappingContainedItems) { return false; } - var should = GameMain.LuaCs.Hook.Call("inventoryItemSwap", this, item, user, index, swapWholeStack); - - if (should != null) - return should.Value; - //swap to InvSlotType.Any if possible Inventory otherInventory = item.ParentInventory; bool otherIsEquipped = false; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs index e61097a03..f74a46541 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs @@ -1411,8 +1411,6 @@ namespace Barotrauma if (Components.Any(ic => ic is Wire) && Components.All(ic => ic is Wire || ic is Holdable)) { isWire = true; } if (HasTag(Barotrauma.Tags.LogicItem)) { isLogic = true; } - GameMain.LuaCs.Hook.Call("item.created", this); - ApplyStatusEffects(ActionType.OnSpawn, 1.0f); // Set max condition multipliers from campaign settings for RecalculateConditionValues() @@ -3364,10 +3362,6 @@ namespace Barotrauma } if (condition <= 0.0f) { return; } - - var should = GameMain.LuaCs.Hook.Call("item.use", new object[] { this, user, targetLimb, useTarget }); - - if (should != null && should.Value) { return; } bool remove = false; @@ -3400,11 +3394,6 @@ namespace Barotrauma { if (condition <= 0.0f) { return; } - var should = GameMain.LuaCs.Hook.Call("item.secondaryUse", this, character); - - if (should != null && should.Value) - return; - bool remove = false; foreach (ItemComponent ic in components) @@ -4621,8 +4610,6 @@ namespace Barotrauma body.Remove(); body = null; } - - GameMain.LuaCs.Hook.Call("item.removed", this); } public override void Remove() @@ -4707,8 +4694,6 @@ namespace Barotrauma } RemoveProjSpecific(); - - GameMain.LuaCs.Hook.Call("item.removed", this); } private void RemoveFromLists() diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/IEvents.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/IEvents.cs index 391ac742f..662d7742f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/IEvents.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/IEvents.cs @@ -1,9 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using Barotrauma.Items.Components; +using Barotrauma.Items.Components; using Barotrauma.LuaCs.Data; using Barotrauma.Networking; +using Microsoft.Xna.Framework; +using Steamworks.Ugc; +using System; +using System.Collections.Generic; +using System.Reflection; namespace Barotrauma.LuaCs.Events; @@ -351,6 +353,186 @@ interface IEventSignalReceived : IEvent } } +interface IEventItemCreated : IEvent +{ + void OnItemCreated(Item item); + + static IEventItemCreated IEvent.GetLuaRunner(IDictionary luaFunc) + => new LuaWrapper(luaFunc); + + public sealed class LuaWrapper : LuaWrapperBase, IEventItemCreated + { + public LuaWrapper(IDictionary luaFuncs) : base(luaFuncs) + { + } + + public void OnItemCreated(Item item) + { + LuaFuncs[nameof(OnItemCreated)](item); + } + } +} + +interface IEventItemRemoved : IEvent +{ + void OnItemRemoved(Item item); + + static IEventItemRemoved IEvent.GetLuaRunner(IDictionary luaFunc) + => new LuaWrapper(luaFunc); + + public sealed class LuaWrapper : LuaWrapperBase, IEventItemRemoved + { + public LuaWrapper(IDictionary luaFuncs) : base(luaFuncs) + { + } + + public void OnItemRemoved(Item item) + { + LuaFuncs[nameof(OnItemRemoved)](item); + } + } +} + +interface IEventItemUse : IEvent +{ + bool? OnItemUsed(Item item, Character user, Limb targetLimb, Entity useTarget); + + static IEventItemUse IEvent.GetLuaRunner(IDictionary luaFunc) + => new LuaWrapper(luaFunc); + + public sealed class LuaWrapper : LuaWrapperBase, IEventItemUse + { + public LuaWrapper(IDictionary luaFuncs) : base(luaFuncs) + { + } + + public bool? OnItemUsed(Item item, Character user, Limb targetLimb, Entity useTarget) + { + var result = LuaFuncs[nameof(OnItemUsed)](item, user, targetLimb, useTarget); + if (result is bool b) + { + return b; + } + else + { + return null; + } + } + } +} + +interface IEventItemSecondaryUse : IEvent +{ + bool? OnItemSecondaryUsed(Item item, Character user); + + static IEventItemSecondaryUse IEvent.GetLuaRunner(IDictionary luaFunc) + => new LuaWrapper(luaFunc); + + public sealed class LuaWrapper : LuaWrapperBase, IEventItemSecondaryUse + { + public LuaWrapper(IDictionary luaFuncs) : base(luaFuncs) + { + } + + public bool? OnItemSecondaryUsed(Item item, Character user) + { + var result = LuaFuncs[nameof(OnItemSecondaryUsed)](item, user); + if (result is bool b) + { + return b; + } + else + { + return null; + } + } + } +} + +interface IEventCharacterDamageLimb : IEvent +{ + AttackResult? OnCharacterDamageLimb(Character character, Vector2 worldPosition, Limb hitLimb, IEnumerable afflictions, float stun, bool playSound, Vector2 attackImpulse, Character attacker = null, float damageMultiplier = 1, bool allowStacking = true, float penetration = 0f, bool shouldImplode = false); + + static IEventCharacterDamageLimb IEvent.GetLuaRunner(IDictionary luaFunc) + => new LuaWrapper(luaFunc); + + public sealed class LuaWrapper : LuaWrapperBase, IEventCharacterDamageLimb + { + public LuaWrapper(IDictionary luaFuncs) : base(luaFuncs) + { + } + + public AttackResult? OnCharacterDamageLimb(Character character, Vector2 worldPosition, Limb hitLimb, IEnumerable afflictions, float stun, bool playSound, Vector2 attackImpulse, Character attacker = null, float damageMultiplier = 1, bool allowStacking = true, float penetration = 0f, bool shouldImplode = false) + { + var result = LuaFuncs[nameof(OnCharacterDamageLimb)](character, worldPosition, hitLimb, afflictions, stun, playSound, attackImpulse, attacker, damageMultiplier, allowStacking, penetration, shouldImplode); + if (result is AttackResult attackResult) + { + return attackResult; + } + else + { + return null; + } + } + } +} + +interface IEventInventoryPutItem : IEvent +{ + bool? OnInventoryPutItem(Inventory inventory, Item item, Character user, int i, bool removeItem); + + static IEventInventoryPutItem IEvent.GetLuaRunner(IDictionary luaFunc) + => new LuaWrapper(luaFunc); + + public sealed class LuaWrapper : LuaWrapperBase, IEventInventoryPutItem + { + public LuaWrapper(IDictionary luaFuncs) : base(luaFuncs) + { + } + + public bool? OnInventoryPutItem(Inventory inventory, Item item, Character user, int i, bool removeItem) + { + var result = LuaFuncs[nameof(OnInventoryPutItem)](inventory, item, user, i, removeItem); + if (result is bool b) + { + return b; + } + else + { + return null; + } + } + } +} + +interface IEventInventoryItemSwap : IEvent +{ + bool? OnInventoryItemSwap(Inventory inventory, Item item, Character user, int i, bool swapWholeStack); + + static IEventInventoryItemSwap IEvent.GetLuaRunner(IDictionary luaFunc) + => new LuaWrapper(luaFunc); + + public sealed class LuaWrapper : LuaWrapperBase, IEventInventoryItemSwap + { + public LuaWrapper(IDictionary luaFuncs) : base(luaFuncs) + { + } + + public bool? OnInventoryItemSwap(Inventory inventory, Item item, Character user, int i, bool swapWholeStack) + { + var result = LuaFuncs[nameof(OnInventoryItemSwap)](inventory, item, user, i, swapWholeStack); + if (result is bool b) + { + return b; + } + else + { + return null; + } + } + } +} + #endregion #region Networking diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/HarmonyEventPatchesService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/HarmonyEventPatchesService.cs index e3907ca72..75b6a4e04 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/HarmonyEventPatchesService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/HarmonyEventPatchesService.cs @@ -180,6 +180,20 @@ internal class HarmonyEventPatchesService : IService _eventService.PublishEvent(x => x.OnGiveCharacterJobItems(__instance, spawnPoint, isPvPMode)); } + [HarmonyPatch(typeof(Character), nameof(Character.DamageLimb)), HarmonyPrefix] + public static bool Character_DamageLimb_Pre(AttackResult __result, Character __instance, Vector2 worldPosition, Limb hitLimb, IEnumerable afflictions, float stun, bool playSound, Vector2 attackImpulse, Character attacker, float damageMultiplier, bool allowStacking, float penetration, bool shouldImplode, bool ignoreDamageOverlay, bool recalculateVitality) + { + AttackResult? result = null; + _eventService.PublishEvent(x => result = x.OnCharacterDamageLimb(__instance, worldPosition, hitLimb, afflictions, stun, playSound, attackImpulse, attacker, damageMultiplier, allowStacking, penetration, shouldImplode)); + if (result != null) + { + __result = (AttackResult)result; + return false; // skip + } + + return true; + } + [HarmonyPatch(typeof(Affliction), nameof(Affliction.Update)), HarmonyPostfix] public static void Affliction_Update_Post(Affliction __instance, CharacterHealth characterHealth, Limb targetLimb, float deltaTime) { @@ -206,6 +220,91 @@ internal class HarmonyEventPatchesService : IService } } + [HarmonyPatch(typeof(Item), MethodType.Constructor, new Type[] { typeof(Rectangle), typeof(ItemPrefab), typeof(Submarine), typeof(bool), typeof(ushort) }), HarmonyPostfix] + public static void Item_Ctor_Post(Item __instance) + { + _eventService.PublishEvent(x => x.OnItemCreated(__instance)); + } + + [HarmonyPatch(typeof(Item), nameof(Item.Remove)), HarmonyPostfix] + public static void Item_Remove_Post(Item __instance) + { + _eventService.PublishEvent(x => x.OnItemRemoved(__instance)); + } + + [HarmonyPatch(typeof(Item), nameof(Item.Remove)), HarmonyPostfix] + public static void Item_ShallowRemove_Post(Item __instance) + { + _eventService.PublishEvent(x => x.OnItemRemoved(__instance)); + } + + [HarmonyPatch(typeof(Item), nameof(Item.Use)), HarmonyPrefix] + public static bool Item_Use_Pre(Item __instance, Character user, Limb targetLimb, Entity useTarget) + { + if (__instance.RequireAimToUse && (user == null || !user.IsKeyDown(InputType.Aim))) + { + return true; + } + + if (__instance.Condition <= 0.0f) { return true; } + + bool? result = null; + _eventService.PublishEvent(x => result = x.OnItemUsed(__instance, user, targetLimb, useTarget)); + if (result == true) + { + return false; // skip + } + + return true; + } + + [HarmonyPatch(typeof(Item), nameof(Item.SecondaryUse)), HarmonyPrefix] + public static bool Item_SecondaryUse_Pre(Item __instance, Character character) + { + if (__instance.Condition <= 0.0f) { return true; } + + bool? result = null; + _eventService.PublishEvent(x => result = x.OnItemSecondaryUsed(__instance, character)); + if (result == true) + { + return false; // skip + } + + return true; + } + + [HarmonyPatch(typeof(Inventory), "PutItem"), HarmonyPrefix] + public static bool Inventory_PutItem_Prefix(Inventory __instance, Item item, int i, Character user, bool removeItem) + { + bool? result = null; + _eventService.PublishEvent(x => result = x.OnInventoryPutItem(__instance, item, user, i, removeItem)); + if (result == true) + { + return false; // skip + } + + return true; + } + + [HarmonyPatch(typeof(Inventory), "TrySwapping"), HarmonyPrefix] + public static bool Inventory_TrySwapping_Prefix(Inventory __instance, Item item, int index, Character user, bool swapWholeStack, ref bool __result) + { + // uncomment when we are plugin + // if (item?.ParentInventory == null || !__instance.slots[index].Any()) { return false; } + // if (__instance.slots[index].Items.Any(it => !it.IsInteractable(user))) { return false; } + if (!__instance.AllowSwappingContainedItems) { return false; } + + bool? result = null; + _eventService.PublishEvent(x => result = x.OnInventoryItemSwap(__instance, item, user, index, swapWholeStack)); + if (result != null) + { + __result = (bool)result; + return false; // skip + } + + return true; + } + public void Dispose() { IsDisposed = true; diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/LuaScriptManagementService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/LuaScriptManagementService.cs index 27ce50979..d0267f7d3 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/LuaScriptManagementService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/LuaScriptManagementService.cs @@ -177,6 +177,7 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService _eventService.RegisterLuaEventAlias("character.created", nameof(IEventCharacterCreated.OnCharacterCreated)); _eventService.RegisterLuaEventAlias("character.death", nameof(IEventCharacterDeath.OnCharacterDeath)); + _eventService.RegisterLuaEventAlias("character.damageLimb", nameof(IEventCharacterDamageLimb.OnCharacterDamageLimb)); _eventService.RegisterLuaEventAlias("character.giveJobItems", nameof(IEventGiveCharacterJobItems.OnGiveCharacterJobItems)); _eventService.RegisterLuaEventAlias("roundStart", nameof(IEventRoundStarted.OnRoundStart)); @@ -185,6 +186,14 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService _eventService.RegisterLuaEventAlias("signalReceived", nameof(IEventSignalReceived.OnSignalReceived)); + _eventService.RegisterLuaEventAlias("item.created", nameof(IEventItemCreated.OnItemCreated)); + _eventService.RegisterLuaEventAlias("item.removed", nameof(IEventItemRemoved.OnItemRemoved)); + _eventService.RegisterLuaEventAlias("item.use", nameof(IEventItemUse.OnItemUsed)); + _eventService.RegisterLuaEventAlias("item.secondaryUse", nameof(IEventItemSecondaryUse.OnItemSecondaryUsed)); + + _eventService.RegisterLuaEventAlias("inventoryPutItem", nameof(IEventInventoryPutItem.OnInventoryPutItem)); + _eventService.RegisterLuaEventAlias("inventoryItemSwap", nameof(IEventInventoryItemSwap.OnInventoryItemSwap)); + #if SERVER _eventService.RegisterLuaEventAlias("client.connected", nameof(IEventClientConnected.OnClientConnected)); _eventService.RegisterLuaEventAlias("client.disconnected", nameof(IEventClientDisconnected.OnClientDisconnected));