From a3c02ae179066af2afa3581bed6aa4269c88689f Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Thu, 20 Jul 2023 14:58:57 +0200 Subject: [PATCH] Improve handling of meta flags. --- Glamourer/Interop/MetaService.cs | 16 +++++++++++- Glamourer/State/StateListener.cs | 45 ++++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/Glamourer/Interop/MetaService.cs b/Glamourer/Interop/MetaService.cs index 93dd585..142fe75 100644 --- a/Glamourer/Interop/MetaService.cs +++ b/Glamourer/Interop/MetaService.cs @@ -10,27 +10,33 @@ public unsafe class MetaService : IDisposable { private readonly HeadGearVisibilityChanged _headGearEvent; private readonly WeaponVisibilityChanged _weaponEvent; + private readonly VisorStateChanged _visorEvent; private delegate void HideHatGearDelegate(DrawDataContainer* drawData, uint id, byte value); private delegate void HideWeaponsDelegate(DrawDataContainer* drawData, bool value); private readonly Hook _hideHatGearHook; private readonly Hook _hideWeaponsHook; + private readonly Hook _toggleVisorHook; - public MetaService(WeaponVisibilityChanged weaponEvent, HeadGearVisibilityChanged headGearEvent) + public MetaService(WeaponVisibilityChanged weaponEvent, HeadGearVisibilityChanged headGearEvent, VisorStateChanged visorEvent) { _weaponEvent = weaponEvent; _headGearEvent = headGearEvent; + _visorEvent = visorEvent; _hideHatGearHook = Hook.FromAddress((nint)DrawDataContainer.MemberFunctionPointers.HideHeadgear, HideHatDetour); _hideWeaponsHook = Hook.FromAddress((nint)DrawDataContainer.MemberFunctionPointers.HideWeapons, HideWeaponsDetour); + _toggleVisorHook = Hook.FromAddress((nint)DrawDataContainer.MemberFunctionPointers.SetVisor, ToggleVisorDetour); _hideHatGearHook.Enable(); _hideWeaponsHook.Enable(); + _toggleVisorHook.Enable(); } public void Dispose() { _hideHatGearHook.Dispose(); _hideWeaponsHook.Dispose(); + _toggleVisorHook.Dispose(); } public void SetHatState(Actor actor, bool value) @@ -73,4 +79,12 @@ public unsafe class MetaService : IDisposable Glamourer.Log.Verbose($"[MetaService] Hide Weapon triggered with 0x{(nint)drawData:X} {value} for {actor.Utf8Name}."); _hideWeaponsHook.Original(drawData, value); } + + private void ToggleVisorDetour(DrawDataContainer* drawData, bool value) + { + Actor actor = drawData->Parent; + _visorEvent.Invoke(actor.Model, ref value); + Glamourer.Log.Verbose($"[MetaService] Toggle Visor triggered with 0x{(nint)drawData:X} {value} for {actor.Utf8Name}."); + _toggleVisorHook.Original(drawData, value); + } } diff --git a/Glamourer/State/StateListener.cs b/Glamourer/State/StateListener.cs index 0a6e859..0e45427 100644 --- a/Glamourer/State/StateListener.cs +++ b/Glamourer/State/StateListener.cs @@ -23,6 +23,7 @@ public class StateListener : IDisposable private readonly Configuration _config; private readonly ActorService _actors; private readonly StateManager _manager; + private readonly StateApplier _applier; private readonly ItemManager _items; private readonly PenumbraService _penumbra; private readonly SlotUpdating _slotUpdating; @@ -35,6 +36,9 @@ public class StateListener : IDisposable private readonly FunModule _funModule; private readonly HumanModelList _humans; + private ActorIdentifier _creatingIdentifier = ActorIdentifier.Invalid; + private ActorState? _creatingState = null; + public bool Enabled { get => _config.Enabled; @@ -44,7 +48,7 @@ public class StateListener : IDisposable public StateListener(StateManager manager, ItemManager items, PenumbraService penumbra, ActorService actors, Configuration config, SlotUpdating slotUpdating, WeaponLoading weaponLoading, VisorStateChanged visorState, WeaponVisibilityChanged weaponVisibility, HeadGearVisibilityChanged headGearVisibility, AutoDesignApplier autoDesignApplier, FunModule funModule, HumanModelList humans, - EquipmentLoading equipmentLoading) + EquipmentLoading equipmentLoading, StateApplier applier) { _manager = manager; _items = items; @@ -60,6 +64,7 @@ public class StateListener : IDisposable _funModule = funModule; _humans = humans; _equipmentLoading = equipmentLoading; + _applier = applier; if (Enabled) Subscribe(); @@ -106,37 +111,37 @@ public class StateListener : IDisposable /// private unsafe void OnCreatingCharacterBase(nint actorPtr, string _, nint modelPtr, nint customizePtr, nint equipDataPtr) { - var actor = (Actor)actorPtr; - var identifier = actor.GetIdentifier(_actors.AwaitedService); + var actor = (Actor)actorPtr; + _creatingIdentifier = actor.GetIdentifier(_actors.AwaitedService); ref var modelId = ref *(uint*)modelPtr; ref var customize = ref *(Customize*)customizePtr; - if (_autoDesignApplier.Reduce(actor, identifier, out var state)) + if (_autoDesignApplier.Reduce(actor, _creatingIdentifier, out _creatingState)) { - switch (UpdateBaseData(actor, state, modelId, customizePtr, equipDataPtr)) + switch (UpdateBaseData(actor, _creatingState, modelId, customizePtr, equipDataPtr)) { // TODO handle right case UpdateState.Change: break; case UpdateState.Transformed: break; case UpdateState.NoChange: - modelId = state.ModelData.ModelId; - switch (UpdateBaseData(actor, state, customize)) + modelId = _creatingState.ModelData.ModelId; + switch (UpdateBaseData(actor, _creatingState, customize)) { case UpdateState.Transformed: break; case UpdateState.Change: break; case UpdateState.NoChange: - customize = state.ModelData.Customize; + customize = _creatingState.ModelData.Customize; break; } foreach (var slot in EquipSlotExtensions.EqdpSlots) - HandleEquipSlot(actor, state, slot, ref ((CharacterArmor*)equipDataPtr)[slot.ToIndex()]); + HandleEquipSlot(actor, _creatingState, slot, ref ((CharacterArmor*)equipDataPtr)[slot.ToIndex()]); break; } - state.TempUnlock(); + _creatingState.TempUnlock(); } _funModule.ApplyFun(actor, new Span((void*)equipDataPtr, 10), ref customize); @@ -173,7 +178,8 @@ public class StateListener : IDisposable return; if (!actor.Identifier(_actors.AwaitedService, out var identifier) - || !_manager.TryGetValue(identifier, out var state) || !state.BaseData.IsHuman) + || !_manager.TryGetValue(identifier, out var state) + || !state.BaseData.IsHuman) return; if (state.ModelData.Armor(slot) == armor) @@ -183,10 +189,10 @@ public class StateListener : IDisposable var setStain = state[slot, true] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc; switch (setItem, setStain) { - case (true, true): + case (true, true): _manager.ChangeEquip(state, slot, state.BaseData.Item(slot), state.BaseData.Stain(slot), StateChanged.Source.Manual); state[slot, false] = StateChanged.Source.Game; - state[slot, true] = StateChanged.Source.Game; + state[slot, true] = StateChanged.Source.Game; break; case (true, false): _manager.ChangeItem(state, slot, state.BaseData.Item(slot), StateChanged.Source.Manual); @@ -194,7 +200,7 @@ public class StateListener : IDisposable break; case (false, true): _manager.ChangeStain(state, slot, state.BaseData.Stain(slot), StateChanged.Source.Manual); - state[slot, true] = StateChanged.Source.Game; + state[slot, true] = StateChanged.Source.Game; break; } } @@ -483,6 +489,7 @@ public class StateListener : IDisposable private void Subscribe() { _penumbra.CreatingCharacterBase += OnCreatingCharacterBase; + _penumbra.CreatedCharacterBase += OnCreatedCharacterBase; _slotUpdating.Subscribe(OnSlotUpdating, SlotUpdating.Priority.StateListener); _equipmentLoading.Subscribe(OnEquipmentLoading, EquipmentLoading.Priority.StateListener); _weaponLoading.Subscribe(OnWeaponLoading, WeaponLoading.Priority.StateListener); @@ -494,6 +501,7 @@ public class StateListener : IDisposable private void Unsubscribe() { _penumbra.CreatingCharacterBase -= OnCreatingCharacterBase; + _penumbra.CreatedCharacterBase -= OnCreatedCharacterBase; _slotUpdating.Unsubscribe(OnSlotUpdating); _equipmentLoading.Unsubscribe(OnEquipmentLoading); _weaponLoading.Unsubscribe(OnWeaponLoading); @@ -501,4 +509,13 @@ public class StateListener : IDisposable _headGearVisibility.Unsubscribe(OnHeadGearVisibilityChange); _weaponVisibility.Unsubscribe(OnWeaponVisibilityChange); } + + private void OnCreatedCharacterBase(nint gameObject, string _, nint drawObject) + { + if (_creatingState == null) + return; + + _applier.ChangeHatState(new ActorData(gameObject, _creatingIdentifier.ToName()), _creatingState.ModelData.IsHatVisible()); + _applier.ChangeWeaponState(new ActorData(gameObject, _creatingIdentifier.ToName()), _creatingState.ModelData.IsWeaponVisible()); + } }