mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-15 21:24:18 +01:00
Add experimental automation condition for gearsets.
This commit is contained in:
parent
c11bd629da
commit
dd42b7ab7f
7 changed files with 185 additions and 32 deletions
|
|
@ -27,6 +27,7 @@ public class AutoDesign
|
|||
public Design? Design;
|
||||
public JobGroup Jobs;
|
||||
public Type ApplicationType;
|
||||
public short GearsetIndex = -1;
|
||||
|
||||
public string Name(bool incognito)
|
||||
=> Revert ? RevertName : incognito ? Design!.Incognito : Design!.Name.Text;
|
||||
|
|
@ -43,10 +44,22 @@ public class AutoDesign
|
|||
Design = Design,
|
||||
ApplicationType = ApplicationType,
|
||||
Jobs = Jobs,
|
||||
GearsetIndex = GearsetIndex,
|
||||
};
|
||||
|
||||
public unsafe bool IsActive(Actor actor)
|
||||
=> actor.IsCharacter && Jobs.Fits(actor.AsCharacter->CharacterData.ClassJob);
|
||||
{
|
||||
if (!actor.IsCharacter)
|
||||
return false;
|
||||
|
||||
var ret = true;
|
||||
if (GearsetIndex < 0)
|
||||
ret &= Jobs.Fits(actor.AsCharacter->CharacterData.ClassJob);
|
||||
else
|
||||
ret &= AutoDesignApplier.CheckGearset(GearsetIndex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public JObject Serialize()
|
||||
=> new()
|
||||
|
|
@ -58,9 +71,12 @@ public class AutoDesign
|
|||
|
||||
private JObject CreateConditionObject()
|
||||
{
|
||||
var ret = new JObject();
|
||||
if (Jobs.Id != 0)
|
||||
ret["JobGroup"] = Jobs.Id;
|
||||
var ret = new JObject
|
||||
{
|
||||
["Gearset"] = GearsetIndex,
|
||||
["JobGroup"] = Jobs.Id,
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
|
|
@ -26,6 +27,7 @@ public class AutoDesignApplier : IDisposable
|
|||
private readonly AutoDesignManager _manager;
|
||||
private readonly StateManager _state;
|
||||
private readonly JobService _jobs;
|
||||
private readonly EquippedGearset _equippedGearset;
|
||||
private readonly ActorService _actors;
|
||||
private readonly CustomizationService _customizations;
|
||||
private readonly CustomizeUnlockManager _customizeUnlocks;
|
||||
|
|
@ -49,7 +51,8 @@ public class AutoDesignApplier : IDisposable
|
|||
|
||||
public AutoDesignApplier(Configuration config, AutoDesignManager manager, StateManager state, JobService jobs,
|
||||
CustomizationService customizations, ActorService actors, ItemUnlockManager itemUnlocks, CustomizeUnlockManager customizeUnlocks,
|
||||
AutomationChanged @event, ObjectManager objects, WeaponLoading weapons, HumanModelList humans, IClientState clientState)
|
||||
AutomationChanged @event, ObjectManager objects, WeaponLoading weapons, HumanModelList humans, IClientState clientState,
|
||||
EquippedGearset equippedGearset)
|
||||
{
|
||||
_config = config;
|
||||
_manager = manager;
|
||||
|
|
@ -64,15 +67,18 @@ public class AutoDesignApplier : IDisposable
|
|||
_weapons = weapons;
|
||||
_humans = humans;
|
||||
_clientState = clientState;
|
||||
_equippedGearset = equippedGearset;
|
||||
_jobs.JobChanged += OnJobChange;
|
||||
_event.Subscribe(OnAutomationChange, AutomationChanged.Priority.AutoDesignApplier);
|
||||
_weapons.Subscribe(OnWeaponLoading, WeaponLoading.Priority.AutoDesignApplier);
|
||||
_equippedGearset.Subscribe(OnEquippedGearset, EquippedGearset.Priority.AutoDesignApplier);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_weapons.Unsubscribe(OnWeaponLoading);
|
||||
_event.Unsubscribe(OnAutomationChange);
|
||||
_equippedGearset.Unsubscribe(OnEquippedGearset);
|
||||
_jobs.JobChanged -= OnJobChange;
|
||||
}
|
||||
|
||||
|
|
@ -496,4 +502,38 @@ public class AutoDesignApplier : IDisposable
|
|||
totalMetaFlags |= 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
internal static int NewGearsetId = -1;
|
||||
|
||||
private void OnEquippedGearset(string name, int id, int prior, byte _, byte job)
|
||||
{
|
||||
if (!_config.EnableAutoDesigns)
|
||||
return;
|
||||
|
||||
var (player, data) = _objects.PlayerData;
|
||||
if (!player.IsValid)
|
||||
return;
|
||||
|
||||
if (!GetPlayerSet(player, out var set) || !_state.TryGetValue(player, out var state))
|
||||
return;
|
||||
|
||||
var respectManual = prior == id;
|
||||
NewGearsetId = id;
|
||||
Reduce(data.Objects[0], state, set, respectManual, job != state.LastJob);
|
||||
NewGearsetId = -1;
|
||||
foreach (var actor in data.Objects)
|
||||
_state.ReapplyState(actor);
|
||||
}
|
||||
|
||||
public static unsafe bool CheckGearset(short check)
|
||||
{
|
||||
if (NewGearsetId != -1)
|
||||
return check == NewGearsetId;
|
||||
|
||||
var module = RaptureGearsetModule.Instance();
|
||||
if (module == null)
|
||||
return false;
|
||||
|
||||
return check == module->CurrentGearsetIndex;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,6 +306,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
|||
return;
|
||||
|
||||
var design = set.Designs[which];
|
||||
|
||||
if (design.Jobs.Id == jobs.Id)
|
||||
return;
|
||||
|
||||
|
|
@ -316,6 +317,22 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
|||
_event.Invoke(AutomationChanged.Type.ChangedConditions, set, (which, old, jobs));
|
||||
}
|
||||
|
||||
public void ChangeGearsetCondition(AutoDesignSet set, int which, short index)
|
||||
{
|
||||
if (which >= set.Designs.Count || which < 0)
|
||||
return;
|
||||
|
||||
var design = set.Designs[which];
|
||||
if (design.GearsetIndex == index)
|
||||
return;
|
||||
|
||||
var old = design.GearsetIndex;
|
||||
design.GearsetIndex = index;
|
||||
Save();
|
||||
Glamourer.Log.Debug($"Changed gearset condition from {old} to {index} for associated design {which + 1} in design set.");
|
||||
_event.Invoke(AutomationChanged.Type.ChangedConditions, set, (which, old, index));
|
||||
}
|
||||
|
||||
public void ChangeApplicationType(AutoDesignSet set, int which, AutoDesign.Type type)
|
||||
{
|
||||
if (which >= set.Designs.Count || which < 0)
|
||||
|
|
@ -338,10 +355,8 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
|||
|
||||
public void Save(StreamWriter writer)
|
||||
{
|
||||
using var j = new JsonTextWriter(writer)
|
||||
{
|
||||
Formatting = Formatting.Indented,
|
||||
};
|
||||
using var j = new JsonTextWriter(writer);
|
||||
j.Formatting = Formatting.Indented;
|
||||
Serialize().WriteTo(j);
|
||||
}
|
||||
|
||||
|
|
@ -456,13 +471,16 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
|||
{
|
||||
if (designIdentifier.Length == 0)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage($"Error parsing automatically applied design for set {setName}: No design specified.", NotificationType.Warning);
|
||||
Glamourer.Messager.NotificationMessage($"Error parsing automatically applied design for set {setName}: No design specified.",
|
||||
NotificationType.Warning);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Guid.TryParse(designIdentifier, out var guid))
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage($"Error parsing automatically applied design for set {setName}: {designIdentifier} is not a valid GUID.", NotificationType.Warning);
|
||||
Glamourer.Messager.NotificationMessage(
|
||||
$"Error parsing automatically applied design for set {setName}: {designIdentifier} is not a valid GUID.",
|
||||
NotificationType.Warning);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
@ -471,7 +489,8 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
|||
if (design == null)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(
|
||||
$"Error parsing automatically applied design for set {setName}: The specified design {guid} does not exist.", NotificationType.Warning);
|
||||
$"Error parsing automatically applied design for set {setName}: The specified design {guid} does not exist.",
|
||||
NotificationType.Warning);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -483,24 +502,31 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
|||
Design = design,
|
||||
ApplicationType = applicationType & AutoDesign.Type.All,
|
||||
};
|
||||
return ParseConditions(setName, jObj, ret) ? ret : null;
|
||||
}
|
||||
|
||||
private bool ParseConditions(string setName, JObject jObj, AutoDesign ret)
|
||||
{
|
||||
var conditions = jObj["Conditions"];
|
||||
if (conditions == null)
|
||||
return ret;
|
||||
return true;
|
||||
|
||||
var jobs = conditions["JobGroup"]?.ToObject<int>() ?? -1;
|
||||
if (jobs >= 0)
|
||||
{
|
||||
if (!_jobs.JobGroups.TryGetValue((ushort)jobs, out var jobGroup))
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage($"Error parsing automatically applied design for set {setName}: The job condition {jobs} does not exist.", NotificationType.Warning);
|
||||
return null;
|
||||
Glamourer.Messager.NotificationMessage(
|
||||
$"Error parsing automatically applied design for set {setName}: The job condition {jobs} does not exist.",
|
||||
NotificationType.Warning);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret.Jobs = jobGroup;
|
||||
}
|
||||
|
||||
return ret;
|
||||
ret.GearsetIndex = conditions["Gearset"]?.ToObject<short>() ?? -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Save()
|
||||
|
|
|
|||
30
Glamourer/Events/EquippedGearset.cs
Normal file
30
Glamourer/Events/EquippedGearset.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using OtterGui.Classes;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the player equips a gear set.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the name of the gear set. </item>
|
||||
/// <item>Parameter is the id of the gear set. </item>
|
||||
/// <item>Parameter is the id of the prior gear set. </item>
|
||||
/// <item>Parameter is the id of the associated glamour. </item>
|
||||
/// <item>Parameter is the job id of the associated job. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class EquippedGearset : EventWrapper<Action<string, int, int, byte, byte>, EquippedGearset.Priority>
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Automation.AutoDesignApplier.OnEquippedGearset"/>
|
||||
AutoDesignApplier = 0,
|
||||
}
|
||||
|
||||
public EquippedGearset()
|
||||
: base(nameof(EquippedGearset))
|
||||
{ }
|
||||
|
||||
public void Invoke(string name, int id, int lastId, byte glamour, byte jobId)
|
||||
=> Invoke(this, name, id, lastId, glamour, jobId);
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
|
@ -29,17 +30,18 @@ public class SetPanel
|
|||
private readonly CustomizeUnlockManager _customizeUnlocks;
|
||||
private readonly CustomizationService _customizations;
|
||||
|
||||
private readonly Configuration _config;
|
||||
private readonly RevertDesignCombo _designCombo;
|
||||
private readonly JobGroupCombo _jobGroupCombo;
|
||||
private readonly IdentifierDrawer _identifierDrawer;
|
||||
private readonly Configuration _config;
|
||||
private readonly RevertDesignCombo _designCombo;
|
||||
private readonly JobGroupCombo _jobGroupCombo;
|
||||
private readonly IdentifierDrawer _identifierDrawer;
|
||||
|
||||
private string? _tempName;
|
||||
private int _dragIndex = -1;
|
||||
|
||||
private Action? _endAction;
|
||||
|
||||
public SetPanel(SetSelector selector, AutoDesignManager manager, JobService jobs, ItemUnlockManager itemUnlocks, RevertDesignCombo designCombo,
|
||||
public SetPanel(SetSelector selector, AutoDesignManager manager, JobService jobs, ItemUnlockManager itemUnlocks,
|
||||
RevertDesignCombo designCombo,
|
||||
CustomizeUnlockManager customizeUnlocks, CustomizationService customizations, IdentifierDrawer identifierDrawer, Configuration config)
|
||||
{
|
||||
_selector = selector;
|
||||
|
|
@ -216,11 +218,11 @@ public class SetPanel
|
|||
ImGui.TableNextColumn();
|
||||
DrawApplicationTypeBoxes(Selection, design, idx, singleRow);
|
||||
ImGui.TableNextColumn();
|
||||
_jobGroupCombo.Draw(Selection, design, idx);
|
||||
DrawConditions(design, idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
_jobGroupCombo.Draw(Selection, design, idx);
|
||||
DrawConditions(design, idx);
|
||||
ImGui.TableNextColumn();
|
||||
DrawApplicationTypeBoxes(Selection, design, idx, singleRow);
|
||||
}
|
||||
|
|
@ -244,6 +246,38 @@ public class SetPanel
|
|||
_endAction = null;
|
||||
}
|
||||
|
||||
private int _tmpGearset = int.MaxValue;
|
||||
|
||||
private void DrawConditions(AutoDesign design, int idx)
|
||||
{
|
||||
var usingGearset = design.GearsetIndex >= 0;
|
||||
if (ImGui.Button($"{(usingGearset ? "Gearset:" : "Jobs:")}##usingGearset"))
|
||||
{
|
||||
usingGearset = !usingGearset;
|
||||
_manager.ChangeGearsetCondition(Selection, idx, (short)(usingGearset ? 0 : -1));
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip("Click to switch between Job and Gearset restrictions.");
|
||||
|
||||
ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X);
|
||||
if (usingGearset)
|
||||
{
|
||||
var set = 1 + (_tmpGearset == int.MaxValue ? design.GearsetIndex : _tmpGearset);
|
||||
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
|
||||
if (ImGui.InputInt("##whichGearset", ref set, 0, 0))
|
||||
_tmpGearset = Math.Clamp(set, 1, 100);
|
||||
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||
{
|
||||
_manager.ChangeGearsetCondition(Selection, idx, (short)(_tmpGearset - 1));
|
||||
_tmpGearset = int.MaxValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_jobGroupCombo.Draw(Selection, design, idx);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawWarnings(AutoDesign design, int idx)
|
||||
{
|
||||
if (design.Revert)
|
||||
|
|
|
|||
|
|
@ -7,17 +7,20 @@ using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
|||
using Glamourer.Events;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
||||
public unsafe class InventoryService : IDisposable
|
||||
{
|
||||
private readonly MovedEquipment _event;
|
||||
private readonly MovedEquipment _movedItemsEvent;
|
||||
private readonly EquippedGearset _gearsetEvent;
|
||||
private readonly List<(EquipSlot, uint, StainId)> _itemList = new(12);
|
||||
|
||||
public InventoryService(MovedEquipment @event, IGameInteropProvider interop)
|
||||
public InventoryService(MovedEquipment movedItemsEvent, IGameInteropProvider interop, EquippedGearset gearsetEvent)
|
||||
{
|
||||
_event = @event;
|
||||
_movedItemsEvent = movedItemsEvent;
|
||||
_gearsetEvent = gearsetEvent;
|
||||
|
||||
_moveItemHook = interop.HookFromAddress<MoveItemDelegate>((nint)InventoryManager.MemberFunctionPointers.MoveItemSlot, MoveItemDetour);
|
||||
_equipGearsetHook =
|
||||
|
|
@ -39,7 +42,10 @@ public unsafe class InventoryService : IDisposable
|
|||
|
||||
private int EquipGearSetDetour(RaptureGearsetModule* module, int gearsetId, byte glamourPlateId)
|
||||
{
|
||||
var ret = _equipGearsetHook.Original(module, gearsetId, glamourPlateId);
|
||||
var prior = module->CurrentGearsetIndex;
|
||||
var ret = _equipGearsetHook.Original(module, gearsetId, glamourPlateId);
|
||||
var set = module->GetGearset(gearsetId);
|
||||
_gearsetEvent.Invoke(new ByteString(set->Name).ToString(), gearsetId, prior, glamourPlateId, set->ClassJob);
|
||||
Glamourer.Log.Excessive($"[InventoryService] Applied gear set {gearsetId} with glamour plate {glamourPlateId} (Returned {ret})");
|
||||
if (ret == 0)
|
||||
{
|
||||
|
|
@ -107,7 +113,7 @@ public unsafe class InventoryService : IDisposable
|
|||
Add(EquipSlot.LFinger, ref entry->RingLeft);
|
||||
}
|
||||
|
||||
_event.Invoke(_itemList.ToArray());
|
||||
_movedItemsEvent.Invoke(_itemList.ToArray());
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -127,18 +133,18 @@ public unsafe class InventoryService : IDisposable
|
|||
{
|
||||
if (InvokeSource(sourceContainer, sourceSlot, out var source))
|
||||
if (InvokeTarget(manager, targetContainer, targetSlot, out var target))
|
||||
_event.Invoke(new[]
|
||||
_movedItemsEvent.Invoke(new[]
|
||||
{
|
||||
source,
|
||||
target,
|
||||
});
|
||||
else
|
||||
_event.Invoke(new[]
|
||||
_movedItemsEvent.Invoke(new[]
|
||||
{
|
||||
source,
|
||||
});
|
||||
else if (InvokeTarget(manager, targetContainer, targetSlot, out var target))
|
||||
_event.Invoke(new[]
|
||||
_movedItemsEvent.Invoke(new[]
|
||||
{
|
||||
target,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ public static class ServiceManager
|
|||
.AddSingleton<ObjectUnlocked>()
|
||||
.AddSingleton<TabSelected>()
|
||||
.AddSingleton<MovedEquipment>()
|
||||
.AddSingleton<EquippedGearset>()
|
||||
.AddSingleton<GPoseService>()
|
||||
.AddSingleton<PenumbraReloaded>();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue