diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackageManager.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackageManager.cs index 03f2214d8..dba9f064b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackageManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackageManager.cs @@ -9,6 +9,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Xml.Linq; using Barotrauma.IO; +using Barotrauma.LuaCs.Events; using Barotrauma.Steam; using Microsoft.Xna.Framework; using OneOf.Types; diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs index a6a9ecb07..3ebfdd402 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs @@ -30,21 +30,10 @@ namespace Barotrauma // == startup _servicesProvider = SetupServicesProvider(); _runStateMachine = SetupStateMachine(); - _servicesProvider.GetService(); + + _servicesProvider.GetService(); + SubscribeToLuaCsEvents(); - PatchEventMethods(); - } - - private void PatchEventMethods() - { - if (_servicesProvider.TryGetService(out var svc)) - { - svc.GenerateMethodHooks(); - Logger.LogDebug($"Patched methods."); - return; - } - - Logger.LogError($"Failed to find {nameof(EventPatchingService)}"); } private void SubscribeToLuaCsEvents() @@ -196,7 +185,7 @@ namespace Barotrauma servicesProvider.RegisterServiceType(ServiceLifetime.Singleton); servicesProvider.RegisterServiceType(ServiceLifetime.Singleton); servicesProvider.RegisterServiceType(ServiceLifetime.Transient); - servicesProvider.RegisterServiceType(ServiceLifetime.Singleton); + servicesProvider.RegisterServiceType(ServiceLifetime.Singleton); // Extension/Sub Services servicesProvider.RegisterServiceType(ServiceLifetime.Transient); diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/EventPatchingService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/EventPatchingService.cs deleted file mode 100644 index e8bd20593..000000000 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/EventPatchingService.cs +++ /dev/null @@ -1,191 +0,0 @@ -using Barotrauma.LuaCs; -using Barotrauma.LuaCs.Events; -using Barotrauma.Networking; -using HarmonyLib; -using Microsoft.Xna.Framework; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Reflection; -using MonoMod.RuntimeDetour; -using static Barotrauma.ContentPackageManager; - -namespace Barotrauma.LuaCs; - - -internal class EventPatchingService : IService -{ - public bool IsDisposed { get; private set; } - private static EventPatchingService _instance; - private IEventService _eventService; - private ILoggerService _loggerService; - /// - /// Key: Original Method, Value: Active Hook. - /// - private readonly ConcurrentDictionary _runtimeHooks = new(); - - #region METHODINFO - - private static readonly MethodInfo Screen_Select_Orig = - typeof(Screen).GetMethod(nameof(Screen.Select), BindingFlags.Instance | BindingFlags.Public); - - private static readonly MethodInfo EnabledPackages_SetCore_Orig = - typeof(ContentPackageManager.EnabledPackages).GetMethod(nameof(ContentPackageManager.EnabledPackages.SetCore), - BindingFlags.Static | BindingFlags.Public); - - private static readonly MethodInfo EnabledPackages_SetRegular_Orig = - typeof(ContentPackageManager.EnabledPackages).GetMethod(nameof(ContentPackageManager.EnabledPackages.SetRegular), - BindingFlags.Static | BindingFlags.Public); - - private static readonly MethodInfo Character_Create_Orig = - AccessTools.DeclaredMethod(typeof(Character), - nameof(Character.Create), new [] - { - typeof(CharacterPrefab), - typeof(Vector2), - typeof(string), - typeof(CharacterInfo), - typeof(ushort), - typeof(bool), - typeof(bool), - typeof(bool), - typeof(RagdollParams), - typeof(bool) - }); - - - #endregion - - public EventPatchingService(IEventService eventService, ILoggerService loggerService) - { - _eventService = eventService; - _loggerService = loggerService; - _instance = this; - } - - public void GenerateMethodHooks() - { - IService.CheckDisposed(this); - - if (!_runtimeHooks.IsEmpty) - { - _loggerService.LogError($"{nameof(GenerateMethodHooks)}: Hooks are already active!"); - return; - } - - _runtimeHooks.TryAdd(Screen_Select_Orig, new Hook( - Screen_Select_Orig, - this.Screen_Select_Post - )); - - _runtimeHooks.TryAdd(EnabledPackages_SetCore_Orig, new Hook( - EnabledPackages_SetCore_Orig, - typeof(EventPatchingService).GetMethod(nameof(EnabledPackages_SetCore_Post)) - )); - - _runtimeHooks.TryAdd(EnabledPackages_SetRegular_Orig, new Hook( - EnabledPackages_SetRegular_Orig, - typeof(EventPatchingService).GetMethod(nameof(EnabledPackages_SetRegular_Post)) - )); - - _runtimeHooks.TryAdd(Character_Create_Orig, new Hook( - Character_Create_Orig, - this.Character_Create_Post - )); - } - - public void CoroutineManager_Update_Post() - { - _eventService.PublishEvent(x => x.OnUpdate(Timing.TotalTime)); - _loggerService.ProcessLogs(); - } - - public void Screen_Select_Post(Action orig, Screen src) - { - orig(src); - _eventService.PublishEvent(x => x.OnScreenSelected(Screen.Selected)); - } - - public void PackageSource_Refresh_Post() - { - _eventService.PublishEvent(x => x.OnAllPackageListChanged(ContentPackageManager.CorePackages, ContentPackageManager.RegularPackages)); - } - - public void ContentPackageManager_Init_Post() - { - _eventService.PublishEvent(x => x.OnAllPackageListChanged(ContentPackageManager.CorePackages, ContentPackageManager.RegularPackages)); - _eventService.PublishEvent(sub => sub.OnEnabledPackageListChanged(EnabledPackages.Core, EnabledPackages.Regular)); - } - - public static void EnabledPackages_SetCore_Post(Action orig, CorePackage newCore) - { - orig(newCore); - _instance?._eventService.PublishEvent(sub => sub.OnEnabledPackageListChanged(EnabledPackages.Core, EnabledPackages.Regular)); - } - - public static void EnabledPackages_SetRegular_Post(Action> orig, IReadOnlyList newRegular) - { - orig(newRegular); - _instance?._eventService.PublishEvent(sub => sub.OnEnabledPackageListChanged(EnabledPackages.Core, EnabledPackages.Regular)); - } - -#if CLIENT - public void GameClient_ReadDataMessage_Pre(IReadMessage inc) - { - ServerPacketHeader header = (ServerPacketHeader)inc.ReadByte(); - _eventService.PublishEvent(x => x.OnReceivedServerNetMessage(inc, header)); - inc.BitPosition -= 8; // rewind so the game can read the message - } - - public void SubEditorScreen_Selected_Post(Screen __instance) - { - _eventService.PublishEvent(x => x.OnScreenSelected(__instance)); - } - - public void PlayerInput_Update_Pre(double deltaTime) - { - _eventService.PublishEvent(x => x.OnKeyUpdate(deltaTime)); - } -#elif SERVER - public void GameServer_ReadDataMessage_Pre(NetworkConnection sender, IReadMessage inc) - { - ClientPacketHeader header = (ClientPacketHeader)inc.ReadByte(); - _eventService.PublishEvent(x => x.OnReceivedClientNetMessage(inc, header, sender)); - inc.BitPosition -= 8; // rewind so the game can read the message - } -#endif - - // Character.Create(), Line 1411. - public Character Character_Create_Post(Func orig, - CharacterPrefab prefab, Vector2 position, string seed, - CharacterInfo characterInfo = null, ushort id = Entity.NullEntityID, - bool isRemotePlayer = false, bool hasAi = true, bool createNetworkEvent = true, - RagdollParams ragdoll = null, bool spawnInitialItems = true) - { - Character result = orig(prefab, position, seed, characterInfo, id, isRemotePlayer, hasAi, createNetworkEvent, - ragdoll, spawnInitialItems); - _eventService.PublishEvent(x => x.OnCharacterCreated(result)); - return result; - } - - public void Character_GiveJobItems_Post(Character __instance, WayPoint spawnPoint, bool isPvPMode) - { - _eventService.PublishEvent(x => x.OnGiveCharacterJobItems(__instance, spawnPoint, isPvPMode)); - } - - public void Affliction_Update_Post(Affliction __instance, CharacterHealth characterHealth, Limb targetLimb, float deltaTime) - { - _eventService.PublishEvent(x => x.OnAfflictionUpdate(__instance, characterHealth, targetLimb, deltaTime)); - } - - public void Dispose() - { - IsDisposed = true; - foreach (var runtimeHook in _runtimeHooks) - { - runtimeHook.Value.Dispose(); - } - _runtimeHooks.Clear(); - } -} diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/HarmonyEventPatchesService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/HarmonyEventPatchesService.cs new file mode 100644 index 000000000..22186a47e --- /dev/null +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/HarmonyEventPatchesService.cs @@ -0,0 +1,132 @@ +using Barotrauma.LuaCs; +using Barotrauma.LuaCs.Events; +using Barotrauma.Networking; +using HarmonyLib; +using Microsoft.Xna.Framework; +using System; +using static Barotrauma.ContentPackageManager; + +namespace Barotrauma.LuaCs; + +[HarmonyPatch] +internal class HarmonyEventPatchesService : IService +{ + public bool IsDisposed { get; private set; } + + private static IEventService _eventService; + private static ILoggerService _loggerService; + private readonly Harmony Harmony; + + public HarmonyEventPatchesService(IEventService eventService, ILoggerService loggerService) + { + _eventService = eventService; + _loggerService = loggerService; + Harmony = new Harmony("LuaCsForBarotrauma.Events"); + Harmony.PatchAll(typeof(HarmonyEventPatchesService)); + } + + [HarmonyPatch(typeof(CoroutineManager), nameof(CoroutineManager.Update)), HarmonyPostfix] + public static void CoroutineManager_Update_Post() + { + _eventService.PublishEvent(x => x.OnUpdate(Timing.TotalTime)); + _loggerService.ProcessLogs(); + } + + [HarmonyPatch(typeof(Screen), nameof(Screen.Select)), HarmonyPostfix] + public static void Screen_Selected_Post(Screen __instance) + { + _eventService.PublishEvent(x => x.OnScreenSelected(__instance)); + } + + [HarmonyPatch(typeof(ContentPackageManager.PackageSource), nameof(ContentPackageManager.PackageSource.Refresh)), HarmonyPostfix] + public static void PackageSource_Refresh_Post() + { + _eventService.PublishEvent(x => x.OnAllPackageListChanged(ContentPackageManager.CorePackages, ContentPackageManager.RegularPackages)); + } + + [HarmonyPatch(typeof(ContentPackageManager), nameof(ContentPackageManager.Init)), HarmonyPostfix] + public static void ContentPackageManager_Init_Post() + { + _eventService.PublishEvent(x => x.OnAllPackageListChanged(ContentPackageManager.CorePackages, ContentPackageManager.RegularPackages)); + _eventService.PublishEvent(sub => sub.OnEnabledPackageListChanged(EnabledPackages.Core, EnabledPackages.Regular)); + } + + [HarmonyPatch(typeof(ContentPackageManager.EnabledPackages), nameof(ContentPackageManager.EnabledPackages.SetCore)), HarmonyPostfix] + public static void EnabledPackages_SetCore_Post() + { + _eventService.PublishEvent(sub => sub.OnEnabledPackageListChanged(EnabledPackages.Core, EnabledPackages.Regular)); + } + + [HarmonyPatch(typeof(ContentPackageManager.EnabledPackages), nameof(ContentPackageManager.EnabledPackages.SetRegular)), HarmonyPostfix] + public static void EnabledPackages_SetRegular_Post() + { + _eventService.PublishEvent(sub => sub.OnEnabledPackageListChanged(EnabledPackages.Core, EnabledPackages.Regular)); + } + + + +#if CLIENT + [HarmonyPatch(typeof(GameClient), "ReadDataMessage"), HarmonyPrefix] + public static void GameClient_ReadDataMessage_Pre(IReadMessage inc) + { + ServerPacketHeader header = (ServerPacketHeader)inc.ReadByte(); + _eventService.PublishEvent(x => x.OnReceivedServerNetMessage(inc, header)); + inc.BitPosition -= 8; // rewind so the game can read the message + } + + [HarmonyPatch(typeof(SubEditorScreen), nameof(SubEditorScreen.Select), new Type[] { }), HarmonyPostfix] + public static void SubEditorScreen_Selected_Post(Screen __instance) + { + _eventService.PublishEvent(x => x.OnScreenSelected(__instance)); + } + + [HarmonyPatch(typeof(PlayerInput), nameof(PlayerInput.Update)), HarmonyPrefix] + public static void PlayerInput_Update_Pre(double deltaTime) + { + _eventService.PublishEvent(x => x.OnKeyUpdate(deltaTime)); + } +#elif SERVER + [HarmonyPatch(typeof(GameServer), "ReadDataMessage"), HarmonyPrefix] + public static void GameServer_ReadDataMessage_Pre(NetworkConnection sender, IReadMessage inc) + { + ClientPacketHeader header = (ClientPacketHeader)inc.ReadByte(); + _eventService.PublishEvent(x => x.OnReceivedClientNetMessage(inc, header, sender)); + inc.BitPosition -= 8; // rewind so the game can read the message + } +#endif + + [HarmonyPatch(typeof(Character), nameof(Character.Create), new[] { + typeof(CharacterPrefab), + typeof(Vector2), + typeof(string), + typeof(CharacterInfo), + typeof(ushort), + typeof(bool), + typeof(bool), + typeof(bool), + typeof(RagdollParams), + typeof(bool) + }), HarmonyPostfix] + public static void Character_Create_Post(Character __result) + { + _eventService.PublishEvent(x => x.OnCharacterCreated(__result)); + } + + [HarmonyPatch(typeof(Character), nameof(Character.GiveJobItems)), HarmonyPostfix] + public static void Character_GiveJobItems_Post(Character __instance, WayPoint spawnPoint, bool isPvPMode) + { + _eventService.PublishEvent(x => x.OnGiveCharacterJobItems(__instance, spawnPoint, isPvPMode)); + } + + [HarmonyPatch(typeof(Affliction), nameof(Affliction.Update)), HarmonyPostfix] + public static void Affliction_Update_Post(Affliction __instance, CharacterHealth characterHealth, Limb targetLimb, float deltaTime) + { + _eventService.PublishEvent(x => x.OnAfflictionUpdate(__instance, characterHealth, targetLimb, deltaTime)); + } + + public void Dispose() + { + Harmony.UnpatchSelf(); + IsDisposed = true; + } +}