Allow multiple fixed designs for a single character to be active, and check jobs. Use the job-group with fewer entries if they are overlapping, and the first added if they have the same number of entries.

This commit is contained in:
Ottermandias 2021-10-09 13:47:24 +02:00
parent 9dafc65975
commit 6d5503b3bc
6 changed files with 201 additions and 35 deletions

View file

@ -11,6 +11,8 @@ namespace Glamourer
{
private static Dictionary<byte, Stain>? _stains;
private static Dictionary<EquipSlot, List<Item>>? _itemsBySlot;
private static Dictionary<byte, Job>? _jobs;
private static Dictionary<ushort, JobGroup>? _jobGroups;
private static SortedList<uint, ModelChara>? _models;
public static IReadOnlyDictionary<uint, ModelChara> Models(DataManager dataManager)
@ -84,5 +86,53 @@ namespace Glamourer
_itemsBySlot[EquipSlot.LFinger] = _itemsBySlot[EquipSlot.RFinger];
return _itemsBySlot;
}
public static IReadOnlyDictionary<byte, Job> Jobs(DataManager dataManager)
{
if (_jobs != null)
return _jobs;
var sheet = dataManager.GetExcelSheet<ClassJob>()!;
_jobs = sheet.ToDictionary(j => (byte)j.RowId, j => new Job(j));
return _jobs;
}
public static IReadOnlyDictionary<ushort, JobGroup> JobGroups(DataManager dataManager)
{
if (_jobGroups != null)
return _jobGroups;
var sheet = dataManager.GetExcelSheet<ClassJobCategory>()!;
var jobs = dataManager.GetExcelSheet<ClassJob>()!;
static bool ValidIndex(uint idx)
{
if (idx > 0 && idx < 36)
return true;
return idx switch
{
91 => true,
92 => true,
96 => true,
98 => true,
99 => true,
111 => true,
112 => true,
129 => true,
149 => true,
150 => true,
156 => true,
157 => true,
158 => true,
159 => true,
_ => false,
};
}
_jobGroups = sheet.Where(j => ValidIndex(j.RowId))
.ToDictionary(j => (ushort) j.RowId, j => new JobGroup(j, jobs));
return _jobGroups;
}
}
}

21
Glamourer.GameData/Job.cs Normal file
View file

@ -0,0 +1,21 @@
using Lumina.Excel.GeneratedSheets;
namespace Glamourer
{
public readonly struct Job
{
public readonly string Name;
public readonly string Abbreviation;
public readonly ClassJob Base;
public uint Id
=> Base.RowId;
public Job(ClassJob job)
{
Base = job;
Name = job.Name.ToString();
Abbreviation = job.Abbreviation.ToString();
}
}
}

View file

@ -0,0 +1,50 @@
using System;
using System.Diagnostics;
using System.Linq;
using Lumina.Excel;
using Lumina.Excel.GeneratedSheets;
namespace Glamourer
{
public readonly struct JobGroup
{
public readonly string Name;
private readonly ulong _flags;
public readonly int Count;
public readonly uint Id;
public JobGroup(ClassJobCategory group, ExcelSheet<ClassJob> jobs)
{
Count = 0;
_flags = 0ul;
Id = group.RowId;
Name = group.Name.ToString();
Debug.Assert(jobs.RowCount < 64);
foreach (var job in jobs)
{
var abbr = job.Abbreviation.ToString();
if (!abbr.Any())
continue;
var prop = group.GetType().GetProperty(abbr);
Debug.Assert(prop != null);
if (!(bool) prop.GetValue(group)!)
continue;
++Count;
_flags |= 1ul << (int) job.RowId;
}
}
public bool Fits(Job job)
=> Fits(job.Id);
public bool Fits(uint jobId)
{
var flag = 1ul << (int)jobId;
return (flag & _flags) != 0;
}
}
}

View file

@ -13,44 +13,50 @@ namespace Glamourer.Designs
{
public class FixedDesign
{
public string Name;
public Design Design;
public bool Enabled;
public string Name;
public JobGroup Jobs;
public Design Design;
public bool Enabled;
public GlamourerConfig.FixedDesign ToSave()
=> new()
{
Name = Name,
Path = Design.FullName(),
Enabled = Enabled,
Name = Name,
Path = Design.FullName(),
Enabled = Enabled,
JobGroups = Jobs.Id,
};
public FixedDesign(string name, Design design, bool enabled)
public FixedDesign(string name, Design design, bool enabled, JobGroup jobs)
{
Name = name;
Design = design;
Enabled = enabled;
Jobs = jobs;
}
}
public List<FixedDesign> Data;
public Dictionary<string, FixedDesign> EnabledDesigns;
public List<FixedDesign> Data;
public Dictionary<string, List<FixedDesign>> EnabledDesigns;
public readonly IReadOnlyDictionary<ushort, JobGroup> JobGroups;
public bool EnableDesign(FixedDesign design)
{
var changes = !design.Enabled;
if (EnabledDesigns.TryGetValue(design.Name, out var oldDesign))
{
oldDesign.Enabled = false;
changes = true;
}
else
if (!EnabledDesigns.TryGetValue(design.Name, out var designs))
{
EnabledDesigns[design.Name] = new List<FixedDesign> { design };
Glamourer.PlayerWatcher.AddPlayerToWatch(design.Name);
changes = true;
}
else if (!designs.Contains(design))
{
designs.Add(design);
changes = true;
}
EnabledDesigns[design.Name] = design;
design.Enabled = true;
design.Enabled = true;
if (Dalamud.Objects.FirstOrDefault(o => o.ObjectKind == ObjectKind.Player && o.Name.ToString() == design.Name)
is Character character)
OnPlayerChange(character);
@ -63,15 +69,25 @@ namespace Glamourer.Designs
return false;
design.Enabled = false;
EnabledDesigns.Remove(design.Name);
Glamourer.PlayerWatcher.RemovePlayerFromWatch(design.Name);
if (!EnabledDesigns.TryGetValue(design.Name, out var designs))
return false;
if (!designs.Remove(design))
return false;
if (designs.Count == 0)
{
EnabledDesigns.Remove(design.Name);
Glamourer.PlayerWatcher.RemovePlayerFromWatch(design.Name);
}
return true;
}
public FixedDesigns(DesignManager designs)
{
JobGroups = GameData.JobGroups(Dalamud.GameData);
Data = new List<FixedDesign>(Glamourer.Config.FixedDesigns.Count);
EnabledDesigns = new Dictionary<string, FixedDesign>(Glamourer.Config.FixedDesigns.Count);
EnabledDesigns = new Dictionary<string, List<FixedDesign>>(Glamourer.Config.FixedDesigns.Count);
Glamourer.PlayerWatcher.PlayerChanged += OnPlayerChange;
var changes = false;
for (var i = 0; i < Glamourer.Config.FixedDesigns.Count; ++i)
@ -79,7 +95,9 @@ namespace Glamourer.Designs
var save = Glamourer.Config.FixedDesigns[i];
if (designs.FileSystem.Find(save.Path, out var d) && d is Design design)
{
Data.Add(new FixedDesign(save.Name, design, save.Enabled));
if (!JobGroups.TryGetValue((ushort) save.JobGroups, out var jobGroup))
jobGroup = JobGroups[1];
Data.Add(new FixedDesign(save.Name, design, save.Enabled, jobGroup));
if (save.Enabled)
changes |= EnableDesign(Data.Last());
}
@ -98,18 +116,23 @@ namespace Glamourer.Designs
private void OnPlayerChange(Character character)
{
var name = character.Name.ToString();
if (EnabledDesigns.TryGetValue(name, out var design))
{
PluginLog.Debug("Redrawing {CharacterName} with {DesignName}.", name, design.Design.FullName());
design.Design.Data.Apply(character);
Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(character);
Glamourer.Penumbra.RedrawObject(character, RedrawType.WithSettings, false);
}
if (!EnabledDesigns.TryGetValue(name, out var designs))
return;
var design = designs.OrderBy(d => d.Jobs.Count).FirstOrDefault(d => d.Jobs.Fits(character.ClassJob.Id));
if (design == null)
return;
PluginLog.Debug("Redrawing {CharacterName} with {DesignName} for job {JobGroup}.", name, design.Design.FullName(),
design.Jobs.Name);
design.Design.Data.Apply(character);
Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(character);
Glamourer.Penumbra.RedrawObject(character, RedrawType.WithSettings, false);
}
public void Add(string name, Design design, bool enabled = false)
public void Add(string name, Design design, JobGroup group, bool enabled = false)
{
Data.Add(new FixedDesign(name, design, enabled));
Data.Add(new FixedDesign(name, design, enabled, group));
Glamourer.Config.FixedDesigns.Add(Data.Last().ToSave());
if (enabled)

View file

@ -9,6 +9,7 @@ namespace Glamourer
{
public string Name;
public string Path;
public uint JobGroups;
public bool Enabled;
}

View file

@ -16,6 +16,7 @@ namespace Glamourer.Gui
private List<string>? _fullPathCache;
private string _newFixCharacterName = string.Empty;
private string _newFixDesignPath = string.Empty;
private JobGroup? _newFixDesignGroup;
private Design? _newFixDesign;
private int _fixDragDropIdx = -1;
@ -24,24 +25,28 @@ namespace Glamourer.Gui
private void DrawFixedDesignsTab()
{
_newFixDesignGroup ??= _plugin.FixedDesigns.JobGroups[1];
using var raii = new ImGuiRaii();
if (!raii.Begin(() => ImGui.BeginTabItem("Fixed Designs"), ImGui.EndTabItem))
{
_fullPathCache = null;
_newFixDesign = null;
_newFixDesignPath = string.Empty;
_fullPathCache = null;
_newFixDesign = null;
_newFixDesignPath = string.Empty;
_newFixDesignGroup = _plugin.FixedDesigns.JobGroups[1];
return;
}
_fullPathCache ??= _plugin.FixedDesigns.Data.Select(d => d.Design.FullName()).ToList();
raii.Begin(() => ImGui.BeginTable("##FixedTable", 3), ImGui.EndTable);
raii.Begin(() => ImGui.BeginTable("##FixedTable", 4), ImGui.EndTable);
var buttonWidth = 23.5f * ImGuiHelpers.GlobalScale;
ImGui.TableSetupColumn("##DeleteColumn", ImGuiTableColumnFlags.WidthFixed, 2 * buttonWidth);
ImGui.TableSetupColumn("Character", ImGuiTableColumnFlags.WidthFixed, 200 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Jobs", ImGuiTableColumnFlags.WidthFixed, 175 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Design", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableHeadersRow();
var xPos = 0f;
@ -92,6 +97,8 @@ namespace Glamourer.Gui
ImGui.EndDragDropTarget();
}
ImGui.TableNextColumn();
ImGui.Text(_plugin.FixedDesigns.Data[i].Jobs.Name);
ImGui.TableNextColumn();
ImGui.Text(path);
}
@ -110,16 +117,30 @@ namespace Glamourer.Gui
else if (ImGui.Button($"{FontAwesomeIcon.Plus.ToIconChar()}##NewFix"))
{
_fullPathCache.Add(_newFixDesignPath);
_plugin.FixedDesigns.Add(_newFixCharacterName, _newFixDesign, false);
_plugin.FixedDesigns.Add(_newFixCharacterName, _newFixDesign, _newFixDesignGroup.Value, false);
_newFixCharacterName = string.Empty;
_newFixDesignPath = string.Empty;
_newFixDesign = null;
_newFixDesignGroup = _plugin.FixedDesigns.JobGroups[1];
}
raii.PopFonts();
ImGui.TableNextColumn();
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
ImGui.InputTextWithHint("##NewFix", "Enter new Character", ref _newFixCharacterName, 32);
ImGui.TableNextColumn();
ImGui.SetNextItemWidth(-1);
if (raii.Begin(() => ImGui.BeginCombo("##NewFixDesignGroup", _newFixDesignGroup.Value.Name), ImGui.EndCombo))
{
foreach (var (id, group) in _plugin.FixedDesigns.JobGroups)
{
ImGui.SetNextItemWidth(-1);
if (ImGui.Selectable($"{group.Name}##NewFixDesignGroup", group.Name == _newFixDesignGroup.Value.Name))
_newFixDesignGroup = group;
}
raii.End();
}
ImGui.TableNextColumn();
ImGui.SetNextItemWidth(-1);
if (!raii.Begin(() => ImGui.BeginCombo("##NewFixPath", _newFixDesignPath), ImGui.EndCombo))