Do a bunch of refactoring regarding available application options.

This commit is contained in:
Ottermandias 2023-11-16 17:32:55 +01:00
parent f55d25b088
commit 68327d3563
12 changed files with 168 additions and 150 deletions

View file

@ -31,7 +31,7 @@ public class AutoDesign
public string Name(bool incognito) public string Name(bool incognito)
=> Revert ? RevertName : incognito ? Design!.Incognito : Design!.Name.Text; => Revert ? RevertName : incognito ? Design!.Incognito : Design!.Name.Text;
public ref DesignData GetDesignData(ActorState state) public ref readonly DesignData GetDesignData(ActorState state)
=> ref Design == null ? ref state.BaseData : ref Design.DesignData; => ref Design == null ? ref state.BaseData : ref Design.DesignData;
public bool Revert public bool Revert

View file

@ -89,7 +89,8 @@ public class AutoDesignApplier : IDisposable
{ {
if (_jobChangeMainhand.TryGetValue(current.Type, out var data)) if (_jobChangeMainhand.TryGetValue(current.Type, out var data))
{ {
Glamourer.Log.Verbose($"Changing Mainhand from {_jobChangeState.ModelData.Weapon(EquipSlot.MainHand)} | {_jobChangeState.BaseData.Weapon(EquipSlot.MainHand)} to {data.Item1} for 0x{actor.Address:X}."); Glamourer.Log.Verbose(
$"Changing Mainhand from {_jobChangeState.ModelData.Weapon(EquipSlot.MainHand)} | {_jobChangeState.BaseData.Weapon(EquipSlot.MainHand)} to {data.Item1} for 0x{actor.Address:X}.");
_state.ChangeItem(_jobChangeState, EquipSlot.MainHand, data.Item1, data.Item2); _state.ChangeItem(_jobChangeState, EquipSlot.MainHand, data.Item1, data.Item2);
weapon.Value = _jobChangeState.ModelData.Weapon(EquipSlot.MainHand); weapon.Value = _jobChangeState.ModelData.Weapon(EquipSlot.MainHand);
} }
@ -98,7 +99,8 @@ public class AutoDesignApplier : IDisposable
{ {
if (_jobChangeOffhand.TryGetValue(current.Type, out var data)) if (_jobChangeOffhand.TryGetValue(current.Type, out var data))
{ {
Glamourer.Log.Verbose($"Changing Offhand from {_jobChangeState.ModelData.Weapon(EquipSlot.OffHand)} | {_jobChangeState.BaseData.Weapon(EquipSlot.OffHand)} to {data.Item1} for 0x{actor.Address:X}."); Glamourer.Log.Verbose(
$"Changing Offhand from {_jobChangeState.ModelData.Weapon(EquipSlot.OffHand)} | {_jobChangeState.BaseData.Weapon(EquipSlot.OffHand)} to {data.Item1} for 0x{actor.Address:X}.");
_state.ChangeItem(_jobChangeState, EquipSlot.OffHand, data.Item1, data.Item2); _state.ChangeItem(_jobChangeState, EquipSlot.OffHand, data.Item1, data.Item2);
weapon.Value = _jobChangeState.ModelData.Weapon(EquipSlot.OffHand); weapon.Value = _jobChangeState.ModelData.Weapon(EquipSlot.OffHand);
} }
@ -277,8 +279,8 @@ public class AutoDesignApplier : IDisposable
if (design.ApplicationType is 0) if (design.ApplicationType is 0)
continue; continue;
ref var data = ref design.GetDesignData(state); ref readonly var data = ref design.GetDesignData(state);
var source = design.Revert ? StateChanged.Source.Game : StateChanged.Source.Fixed; var source = design.Revert ? StateChanged.Source.Game : StateChanged.Source.Fixed;
if (!data.IsHuman) if (!data.IsHuman)
continue; continue;

View file

@ -15,7 +15,7 @@ public sealed class Design : DesignBase, ISavable
{ {
#region Data #region Data
internal Design(CustomizationService customize, ItemManager items) internal Design(CustomizationService customize, ItemManager items)
: base(items) : base(customize, items)
{ } { }
internal Design(DesignBase other) internal Design(DesignBase other)

View file

@ -16,20 +16,37 @@ public class DesignBase
{ {
public const int FileVersion = 1; public const int FileVersion = 1;
internal DesignBase(ItemManager items) private DesignData _designData = new();
/// <summary> For read-only information about the actual design. </summary>
public ref readonly DesignData DesignData
=> ref _designData;
/// <summary> To make it clear that something is edited here. </summary>
public ref DesignData GetDesignDataRef()
=> ref _designData;
internal DesignBase(CustomizationService customize, ItemManager items)
{ {
DesignData.SetDefaultEquipment(items); _designData.SetDefaultEquipment(items);
CustomizationSet = SetCustomizationSet(customize);
} }
internal DesignBase(DesignBase clone) internal DesignBase(DesignBase clone)
{ {
DesignData = clone.DesignData; _designData = clone._designData;
ApplyCustomize = clone.ApplyCustomize & CustomizeFlagExtensions.AllRelevant; CustomizationSet = clone.CustomizationSet;
ApplyEquip = clone.ApplyEquip & EquipFlagExtensions.All; ApplyCustomize = clone.ApplyCustomizeRaw;
_designFlags = clone._designFlags & (DesignFlags)0x0F; ApplyEquip = clone.ApplyEquip & EquipFlagExtensions.All;
_designFlags = clone._designFlags & (DesignFlags)0x0F;
} }
internal DesignData DesignData = new(); /// <summary> Ensure that the customization set is updated when the design data changes. </summary>
internal void SetDesignData(CustomizationService customize, in DesignData other)
{
_designData = other;
CustomizationSet = SetCustomizationSet(customize);
}
#region Application Data #region Application Data
@ -43,9 +60,30 @@ public class DesignBase
WriteProtected = 0x10, WriteProtected = 0x10,
} }
internal CustomizeFlag ApplyCustomize = CustomizeFlagExtensions.AllRelevant; private CustomizeFlag _applyCustomize = CustomizeFlagExtensions.AllRelevant;
internal EquipFlag ApplyEquip = EquipFlagExtensions.All; public CustomizationSet CustomizationSet { get; private set; }
private DesignFlags _designFlags = DesignFlags.ApplyHatVisible | DesignFlags.ApplyVisorState | DesignFlags.ApplyWeaponVisible;
internal CustomizeFlag ApplyCustomize
{
get => _applyCustomize.FixApplication(CustomizationSet);
set => _applyCustomize = value & CustomizeFlagExtensions.AllRelevant;
}
internal CustomizeFlag ApplyCustomizeRaw
=> _applyCustomize;
internal EquipFlag ApplyEquip = EquipFlagExtensions.All;
private DesignFlags _designFlags = DesignFlags.ApplyHatVisible | DesignFlags.ApplyVisorState | DesignFlags.ApplyWeaponVisible;
public bool SetCustomize(CustomizationService customizationService, Customize customize)
{
if (customize.Equals(_designData.Customize))
return false;
_designData.Customize.Load(customize);
CustomizationSet = customizationService.AwaitedService.GetList(customize.Clan, customize.Gender);
return true;
}
public bool DoApplyHatVisible() public bool DoApplyHatVisible()
=> _designFlags.HasFlag(DesignFlags.ApplyHatVisible); => _designFlags.HasFlag(DesignFlags.ApplyHatVisible);
@ -119,7 +157,7 @@ public class DesignBase
=> ApplyEquip.HasFlag(slot.ToStainFlag()); => ApplyEquip.HasFlag(slot.ToStainFlag());
public bool DoApplyCustomize(CustomizeIndex idx) public bool DoApplyCustomize(CustomizeIndex idx)
=> idx is not CustomizeIndex.Race and not CustomizeIndex.BodyType && ApplyCustomize.HasFlag(idx.ToFlag()); => ApplyCustomize.HasFlag(idx.ToFlag());
internal bool SetApplyEquip(EquipSlot slot, bool value) internal bool SetApplyEquip(EquipSlot slot, bool value)
{ {
@ -143,20 +181,14 @@ public class DesignBase
internal bool SetApplyCustomize(CustomizeIndex idx, bool value) internal bool SetApplyCustomize(CustomizeIndex idx, bool value)
{ {
var newValue = value ? ApplyCustomize | idx.ToFlag() : ApplyCustomize & ~idx.ToFlag(); var newValue = value ? _applyCustomize | idx.ToFlag() : _applyCustomize & ~idx.ToFlag();
if (newValue == ApplyCustomize) if (newValue == _applyCustomize)
return false; return false;
ApplyCustomize = newValue; _applyCustomize = newValue;
return true; return true;
} }
public void FixCustomizeApplication(CustomizationService service, CustomizeFlag flags)
=> FixCustomizeApplication(service.AwaitedService.GetList(DesignData.Customize.Clan, DesignData.Customize.Gender), flags);
public void FixCustomizeApplication(CustomizationSet set, CustomizeFlag flags)
=> ApplyCustomize = flags.FixApplication(set);
internal FlagRestrictionResetter TemporarilyRestrictApplication(EquipFlag equipFlags, CustomizeFlag customizeFlags) internal FlagRestrictionResetter TemporarilyRestrictApplication(EquipFlag equipFlags, CustomizeFlag customizeFlags)
=> new(this, equipFlags, customizeFlags); => new(this, equipFlags, customizeFlags);
@ -170,7 +202,7 @@ public class DesignBase
{ {
_design = d; _design = d;
_oldEquipFlags = d.ApplyEquip; _oldEquipFlags = d.ApplyEquip;
_oldCustomizeFlags = d.ApplyCustomize; _oldCustomizeFlags = d.ApplyCustomizeRaw;
d.ApplyEquip &= equipFlags; d.ApplyEquip &= equipFlags;
d.ApplyCustomize &= customizeFlags; d.ApplyCustomize &= customizeFlags;
} }
@ -182,6 +214,11 @@ public class DesignBase
} }
} }
private CustomizationSet SetCustomizationSet(CustomizationService customize)
=> !_designData.IsHuman
? customize.AwaitedService.GetList(SubRace.Midlander, Gender.Male)
: customize.AwaitedService.GetList(_designData.Customize.Clan, _designData.Customize.Gender);
#endregion #endregion
#region Serialization #region Serialization
@ -209,22 +246,22 @@ public class DesignBase
}; };
var ret = new JObject(); var ret = new JObject();
if (DesignData.IsHuman) if (_designData.IsHuman)
{ {
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand)) foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
{ {
var item = DesignData.Item(slot); var item = _designData.Item(slot);
var stain = DesignData.Stain(slot); var stain = _designData.Stain(slot);
ret[slot.ToString()] = Serialize(item.Id, stain, DoApplyEquip(slot), DoApplyStain(slot)); ret[slot.ToString()] = Serialize(item.Id, stain, DoApplyEquip(slot), DoApplyStain(slot));
} }
ret["Hat"] = new QuadBool(DesignData.IsHatVisible(), DoApplyHatVisible()).ToJObject("Show", "Apply"); ret["Hat"] = new QuadBool(_designData.IsHatVisible(), DoApplyHatVisible()).ToJObject("Show", "Apply");
ret["Visor"] = new QuadBool(DesignData.IsVisorToggled(), DoApplyVisorToggle()).ToJObject("IsToggled", "Apply"); ret["Visor"] = new QuadBool(_designData.IsVisorToggled(), DoApplyVisorToggle()).ToJObject("IsToggled", "Apply");
ret["Weapon"] = new QuadBool(DesignData.IsWeaponVisible(), DoApplyWeaponVisible()).ToJObject("Show", "Apply"); ret["Weapon"] = new QuadBool(_designData.IsWeaponVisible(), DoApplyWeaponVisible()).ToJObject("Show", "Apply");
} }
else else
{ {
ret["Array"] = DesignData.WriteEquipmentBytesBase64(); ret["Array"] = _designData.WriteEquipmentBytesBase64();
} }
return ret; return ret;
@ -234,17 +271,17 @@ public class DesignBase
{ {
var ret = new JObject() var ret = new JObject()
{ {
["ModelId"] = DesignData.ModelId, ["ModelId"] = _designData.ModelId,
}; };
var customize = DesignData.Customize; var customize = _designData.Customize;
if (DesignData.IsHuman) if (_designData.IsHuman)
foreach (var idx in Enum.GetValues<CustomizeIndex>()) foreach (var idx in Enum.GetValues<CustomizeIndex>())
{ {
ret[idx.ToString()] = new JObject() ret[idx.ToString()] = new JObject()
{ {
["Value"] = customize[idx].Value, ["Value"] = customize[idx].Value,
["Apply"] = DoApplyCustomize(idx), ["Apply"] = ApplyCustomizeRaw.HasFlag(idx.ToFlag()),
}; };
} }
else else
@ -252,7 +289,7 @@ public class DesignBase
ret["Wetness"] = new JObject() ret["Wetness"] = new JObject()
{ {
["Value"] = DesignData.IsWet(), ["Value"] = _designData.IsWet(),
["Apply"] = DoApplyWetness(), ["Apply"] = DoApplyWetness(),
}; };
@ -275,7 +312,7 @@ public class DesignBase
private static DesignBase LoadDesignV1Base(CustomizationService customizations, ItemManager items, JObject json) private static DesignBase LoadDesignV1Base(CustomizationService customizations, ItemManager items, JObject json)
{ {
var ret = new DesignBase(items); var ret = new DesignBase(customizations, items);
LoadCustomize(customizations, json["Customize"], ret, "Temporary Design", false, true); LoadCustomize(customizations, json["Customize"], ret, "Temporary Design", false, true);
LoadEquip(items, json["Equipment"], ret, "Temporary Design", true); LoadEquip(items, json["Equipment"], ret, "Temporary Design", true);
return ret; return ret;
@ -285,16 +322,16 @@ public class DesignBase
{ {
if (equip == null) if (equip == null)
{ {
design.DesignData.SetDefaultEquipment(items); design._designData.SetDefaultEquipment(items);
Glamourer.Messager.NotificationMessage("The loaded design does not contain any equipment data, reset to default.", Glamourer.Messager.NotificationMessage("The loaded design does not contain any equipment data, reset to default.",
NotificationType.Warning); NotificationType.Warning);
return; return;
} }
if (!design.DesignData.IsHuman) if (!design._designData.IsHuman)
{ {
var textArray = equip["Array"]?.ToObject<string>() ?? string.Empty; var textArray = equip["Array"]?.ToObject<string>() ?? string.Empty;
design.DesignData.SetEquipmentBytesFromBase64(textArray); design._designData.SetEquipmentBytesFromBase64(textArray);
return; return;
} }
@ -319,8 +356,8 @@ public class DesignBase
PrintWarning(items.ValidateItem(slot, id, out var item, allowUnknown)); PrintWarning(items.ValidateItem(slot, id, out var item, allowUnknown));
PrintWarning(items.ValidateStain(stain, out stain, allowUnknown)); PrintWarning(items.ValidateStain(stain, out stain, allowUnknown));
design.DesignData.SetItem(slot, item); design._designData.SetItem(slot, item);
design.DesignData.SetStain(slot, stain); design._designData.SetStain(slot, stain);
design.SetApplyEquip(slot, apply); design.SetApplyEquip(slot, apply);
design.SetApplyStain(slot, applyStain); design.SetApplyStain(slot, applyStain);
} }
@ -336,10 +373,10 @@ public class DesignBase
PrintWarning(items.ValidateWeapons(id, idOff, out var main, out var off, allowUnknown)); PrintWarning(items.ValidateWeapons(id, idOff, out var main, out var off, allowUnknown));
PrintWarning(items.ValidateStain(stain, out stain, allowUnknown)); PrintWarning(items.ValidateStain(stain, out stain, allowUnknown));
PrintWarning(items.ValidateStain(stainOff, out stainOff, allowUnknown)); PrintWarning(items.ValidateStain(stainOff, out stainOff, allowUnknown));
design.DesignData.SetItem(EquipSlot.MainHand, main); design._designData.SetItem(EquipSlot.MainHand, main);
design.DesignData.SetItem(EquipSlot.OffHand, off); design._designData.SetItem(EquipSlot.OffHand, off);
design.DesignData.SetStain(EquipSlot.MainHand, stain); design._designData.SetStain(EquipSlot.MainHand, stain);
design.DesignData.SetStain(EquipSlot.OffHand, stainOff); design._designData.SetStain(EquipSlot.OffHand, stainOff);
design.SetApplyEquip(EquipSlot.MainHand, apply); design.SetApplyEquip(EquipSlot.MainHand, apply);
design.SetApplyEquip(EquipSlot.OffHand, applyOff); design.SetApplyEquip(EquipSlot.OffHand, applyOff);
design.SetApplyStain(EquipSlot.MainHand, applyStain); design.SetApplyStain(EquipSlot.MainHand, applyStain);
@ -347,15 +384,15 @@ public class DesignBase
} }
var metaValue = QuadBool.FromJObject(equip["Hat"], "Show", "Apply", QuadBool.NullFalse); var metaValue = QuadBool.FromJObject(equip["Hat"], "Show", "Apply", QuadBool.NullFalse);
design.SetApplyHatVisible(metaValue.Enabled); design.SetApplyHatVisible(metaValue.Enabled);
design.DesignData.SetHatVisible(metaValue.ForcedValue); design._designData.SetHatVisible(metaValue.ForcedValue);
metaValue = QuadBool.FromJObject(equip["Weapon"], "Show", "Apply", QuadBool.NullFalse); metaValue = QuadBool.FromJObject(equip["Weapon"], "Show", "Apply", QuadBool.NullFalse);
design.SetApplyWeaponVisible(metaValue.Enabled); design.SetApplyWeaponVisible(metaValue.Enabled);
design.DesignData.SetWeaponVisible(metaValue.ForcedValue); design._designData.SetWeaponVisible(metaValue.ForcedValue);
metaValue = QuadBool.FromJObject(equip["Visor"], "IsToggled", "Apply", QuadBool.NullFalse); metaValue = QuadBool.FromJObject(equip["Visor"], "IsToggled", "Apply", QuadBool.NullFalse);
design.SetApplyVisorToggle(metaValue.Enabled); design.SetApplyVisorToggle(metaValue.Enabled);
design.DesignData.SetVisor(metaValue.ForcedValue); design._designData.SetVisor(metaValue.ForcedValue);
} }
protected static void LoadCustomize(CustomizationService customizations, JToken? json, DesignBase design, string name, bool forbidNonHuman, protected static void LoadCustomize(CustomizationService customizations, JToken? json, DesignBase design, string name, bool forbidNonHuman,
@ -363,9 +400,9 @@ public class DesignBase
{ {
if (json == null) if (json == null)
{ {
design.DesignData.ModelId = 0; design._designData.ModelId = 0;
design.DesignData.IsHuman = true; design._designData.IsHuman = true;
design.DesignData.Customize = Customize.Default; design.SetCustomize(customizations, Customize.Default);
Glamourer.Messager.NotificationMessage("The loaded design does not contain any customization data, reset to default.", Glamourer.Messager.NotificationMessage("The loaded design does not contain any customization data, reset to default.",
NotificationType.Warning); NotificationType.Warning);
return; return;
@ -380,21 +417,22 @@ public class DesignBase
} }
var wetness = QuadBool.FromJObject(json["Wetness"], "Value", "Apply", QuadBool.NullFalse); var wetness = QuadBool.FromJObject(json["Wetness"], "Value", "Apply", QuadBool.NullFalse);
design.DesignData.SetIsWet(wetness.ForcedValue); design._designData.SetIsWet(wetness.ForcedValue);
design.SetApplyWetness(wetness.Enabled); design.SetApplyWetness(wetness.Enabled);
design.DesignData.ModelId = json["ModelId"]?.ToObject<uint>() ?? 0; design._designData.ModelId = json["ModelId"]?.ToObject<uint>() ?? 0;
PrintWarning(customizations.ValidateModelId(design.DesignData.ModelId, out design.DesignData.ModelId, out design.DesignData.IsHuman)); PrintWarning(customizations.ValidateModelId(design._designData.ModelId, out design._designData.ModelId, out design._designData.IsHuman));
if (design.DesignData.ModelId != 0 && forbidNonHuman) if (design._designData.ModelId != 0 && forbidNonHuman)
{ {
PrintWarning("Model IDs different from 0 are not currently allowed, reset model id to 0."); PrintWarning("Model IDs different from 0 are not currently allowed, reset model id to 0.");
design.DesignData.ModelId = 0; design._designData.ModelId = 0;
design.DesignData.IsHuman = true; design._designData.IsHuman = true;
} }
else if (!design.DesignData.IsHuman) else if (!design._designData.IsHuman)
{ {
var arrayText = json["Array"]?.ToObject<string>() ?? string.Empty; var arrayText = json["Array"]?.ToObject<string>() ?? string.Empty;
design.DesignData.Customize.LoadBase64(arrayText); design._designData.Customize.LoadBase64(arrayText);
design.CustomizationSet = design.SetCustomizationSet(customizations);
return; return;
} }
@ -403,42 +441,32 @@ public class DesignBase
PrintWarning(customizations.ValidateClan(clan, race, out race, out clan)); PrintWarning(customizations.ValidateClan(clan, race, out race, out clan));
var gender = (Gender)((json[CustomizeIndex.Gender.ToString()]?["Value"]?.ToObject<byte>() ?? 0) + 1); var gender = (Gender)((json[CustomizeIndex.Gender.ToString()]?["Value"]?.ToObject<byte>() ?? 0) + 1);
PrintWarning(customizations.ValidateGender(race, gender, out gender)); PrintWarning(customizations.ValidateGender(race, gender, out gender));
design.DesignData.Customize.Race = race; design._designData.Customize.Race = race;
design.DesignData.Customize.Clan = clan; design._designData.Customize.Clan = clan;
design.DesignData.Customize.Gender = gender; design._designData.Customize.Gender = gender;
design.CustomizationSet = design.SetCustomizationSet(customizations);
design.SetApplyCustomize(CustomizeIndex.Race, json[CustomizeIndex.Race.ToString()]?["Apply"]?.ToObject<bool>() ?? false); design.SetApplyCustomize(CustomizeIndex.Race, json[CustomizeIndex.Race.ToString()]?["Apply"]?.ToObject<bool>() ?? false);
design.SetApplyCustomize(CustomizeIndex.Clan, json[CustomizeIndex.Clan.ToString()]?["Apply"]?.ToObject<bool>() ?? false); design.SetApplyCustomize(CustomizeIndex.Clan, json[CustomizeIndex.Clan.ToString()]?["Apply"]?.ToObject<bool>() ?? false);
design.SetApplyCustomize(CustomizeIndex.Gender, json[CustomizeIndex.Gender.ToString()]?["Apply"]?.ToObject<bool>() ?? false); design.SetApplyCustomize(CustomizeIndex.Gender, json[CustomizeIndex.Gender.ToString()]?["Apply"]?.ToObject<bool>() ?? false);
var set = design.CustomizationSet;
var set = customizations.AwaitedService.GetList(clan, gender);
foreach (var idx in CustomizationExtensions.AllBasic) foreach (var idx in CustomizationExtensions.AllBasic)
{ {
if (set.IsAvailable(idx)) var tok = json[idx.ToString()];
{ var data = (CustomizeValue)(tok?["Value"]?.ToObject<byte>() ?? 0);
var tok = json[idx.ToString()]; PrintWarning(CustomizationService.ValidateCustomizeValue(set, design._designData.Customize.Face, idx, data, out data,
var data = (CustomizeValue)(tok?["Value"]?.ToObject<byte>() ?? 0); allowUnknown));
PrintWarning(CustomizationService.ValidateCustomizeValue(set, design.DesignData.Customize.Face, idx, data, out data, var apply = tok?["Apply"]?.ToObject<bool>() ?? false;
allowUnknown)); design._designData.Customize[idx] = data;
var apply = tok?["Apply"]?.ToObject<bool>() ?? false; design.SetApplyCustomize(idx, apply);
design.DesignData.Customize[idx] = data;
design.SetApplyCustomize(idx, apply);
}
else
{
design.DesignData.Customize[idx] = CustomizeValue.Zero;
design.SetApplyCustomize(idx, false);
}
} }
design.FixCustomizeApplication(set, design.ApplyCustomize);
} }
public void MigrateBase64(ItemManager items, HumanModelList humans, string base64) public void MigrateBase64(CustomizationService customize, ItemManager items, HumanModelList humans, string base64)
{ {
try try
{ {
DesignData = DesignBase64Migration.MigrateBase64(items, humans, base64, out var equipFlags, out var customizeFlags, _designData = DesignBase64Migration.MigrateBase64(items, humans, base64, out var equipFlags, out var customizeFlags,
out var writeProtected, out var writeProtected,
out var applyHat, out var applyVisor, out var applyWeapon); out var applyHat, out var applyVisor, out var applyWeapon);
ApplyEquip = equipFlags; ApplyEquip = equipFlags;
@ -448,6 +476,7 @@ public class DesignBase
SetApplyVisorToggle(applyVisor); SetApplyVisorToggle(applyVisor);
SetApplyWeaponVisible(applyWeapon); SetApplyWeaponVisible(applyWeapon);
SetApplyWetness(true); SetApplyWetness(true);
CustomizationSet = SetCustomizationSet(customize);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -455,15 +484,5 @@ public class DesignBase
} }
} }
public void RemoveInvalidCustomize(CustomizationService customizations)
{
var set = customizations.AwaitedService.GetList(DesignData.Customize.Clan, DesignData.Customize.Gender);
foreach (var idx in CustomizationExtensions.AllBasic.Where(i => !set.IsAvailable(i)))
{
DesignData.Customize[idx] = CustomizeValue.Zero;
SetApplyCustomize(idx, false);
}
}
#endregion #endregion
} }

View file

@ -60,13 +60,13 @@ public class DesignConverter
public DesignBase Convert(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags) public DesignBase Convert(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags)
{ {
var design = _designs.CreateTemporary(); var design = _designs.CreateTemporary();
design.ApplyEquip = equipFlags & EquipFlagExtensions.All; design.ApplyEquip = equipFlags & EquipFlagExtensions.All;
design.ApplyCustomize = customizeFlags;
design.SetApplyHatVisible(design.DoApplyEquip(EquipSlot.Head)); design.SetApplyHatVisible(design.DoApplyEquip(EquipSlot.Head));
design.SetApplyVisorToggle(design.DoApplyEquip(EquipSlot.Head)); design.SetApplyVisorToggle(design.DoApplyEquip(EquipSlot.Head));
design.SetApplyWeaponVisible(design.DoApplyEquip(EquipSlot.MainHand) || design.DoApplyEquip(EquipSlot.OffHand)); design.SetApplyWeaponVisible(design.DoApplyEquip(EquipSlot.MainHand) || design.DoApplyEquip(EquipSlot.OffHand));
design.SetApplyWetness(true); design.SetApplyWetness(true);
design.DesignData = state.ModelData; design.SetDesignData(_customize, state.ModelData);
design.FixCustomizeApplication(_customize, customizeFlags);
return design; return design;
} }
@ -90,7 +90,7 @@ public class DesignConverter
case 2: case 2:
case 4: case 4:
ret = _designs.CreateTemporary(); ret = _designs.CreateTemporary();
ret.MigrateBase64(_items, _humans, base64); ret.MigrateBase64(_customize, _items, _humans, base64);
break; break;
case 3: case 3:
{ {
@ -122,15 +122,8 @@ public class DesignConverter
return null; return null;
} }
if (!customize) ret.SetApplyWetness(customize);
{ ret.ApplyCustomize = customize ? CustomizeFlagExtensions.AllRelevant : 0;
ret.ApplyCustomize = 0;
ret.SetApplyWetness(false);
}
else
{
ret.FixCustomizeApplication(_customize, ret.ApplyCustomize);
}
if (!equip) if (!equip)
{ {
@ -152,7 +145,7 @@ public class DesignConverter
private static string ShareBackwardCompatible(JObject jObject, DesignBase design) private static string ShareBackwardCompatible(JObject jObject, DesignBase design)
{ {
var oldBase64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.ApplyEquip, design.ApplyCustomize, var oldBase64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.ApplyEquip, design.ApplyCustomizeRaw,
design.DoApplyHatVisible(), design.DoApplyVisorToggle(), design.DoApplyWeaponVisible(), design.WriteProtected(), 1f); design.DoApplyHatVisible(), design.DoApplyVisorToggle(), design.DoApplyWeaponVisible(), design.WriteProtected(), 1f);
var oldBytes = System.Convert.FromBase64String(oldBase64); var oldBytes = System.Convert.FromBase64String(oldBase64);
var json = jObject.ToString(Formatting.None); var json = jObject.ToString(Formatting.None);

View file

@ -90,7 +90,7 @@ public class DesignManager
/// <summary> Create a new temporary design without adding it to the manager. </summary> /// <summary> Create a new temporary design without adding it to the manager. </summary>
public DesignBase CreateTemporary() public DesignBase CreateTemporary()
=> new(_items); => new(_customizations, _items);
/// <summary> Create a new design of a given name. </summary> /// <summary> Create a new design of a given name. </summary>
public Design CreateEmpty(string name, bool handlePath) public Design CreateEmpty(string name, bool handlePath)
@ -275,6 +275,7 @@ public class DesignManager
public void ChangeCustomize(Design design, CustomizeIndex idx, CustomizeValue value) public void ChangeCustomize(Design design, CustomizeIndex idx, CustomizeValue value)
{ {
var oldValue = design.DesignData.Customize[idx]; var oldValue = design.DesignData.Customize[idx];
switch (idx) switch (idx)
{ {
case CustomizeIndex.Race: case CustomizeIndex.Race:
@ -282,21 +283,29 @@ public class DesignManager
Glamourer.Log.Error("Somehow race or body type was changed in a design. This should not happen."); Glamourer.Log.Error("Somehow race or body type was changed in a design. This should not happen.");
return; return;
case CustomizeIndex.Clan: case CustomizeIndex.Clan:
if (_customizations.ChangeClan(ref design.DesignData.Customize, (SubRace)value.Value) == 0) {
var customize = new Customize(design.DesignData.Customize.Data.Clone());
if (_customizations.ChangeClan(ref customize, (SubRace)value.Value) == 0)
return;
if (!design.SetCustomize(_customizations, customize))
return; return;
design.RemoveInvalidCustomize(_customizations);
break; break;
}
case CustomizeIndex.Gender: case CustomizeIndex.Gender:
if (_customizations.ChangeGender(ref design.DesignData.Customize, (Gender)(value.Value + 1)) == 0) {
var customize = new Customize(design.DesignData.Customize.Data.Clone());
if (_customizations.ChangeGender(ref customize, (Gender)(value.Value + 1)) == 0)
return;
if (!design.SetCustomize(_customizations, customize))
return; return;
design.RemoveInvalidCustomize(_customizations);
break; break;
}
default: default:
if (!_customizations.IsCustomizationValid(design.DesignData.Customize.Clan, design.DesignData.Customize.Gender, if (!_customizations.IsCustomizationValid(design.DesignData.Customize.Clan, design.DesignData.Customize.Gender,
design.DesignData.Customize.Face, idx, value) design.DesignData.Customize.Face, idx, value)
|| !design.DesignData.Customize.Set(idx, value)) || !design.GetDesignDataRef().Customize.Set(idx, value))
return; return;
break; break;
@ -311,8 +320,6 @@ public class DesignManager
/// <summary> Change whether to apply a specific customize value. </summary> /// <summary> Change whether to apply a specific customize value. </summary>
public void ChangeApplyCustomize(Design design, CustomizeIndex idx, bool value) public void ChangeApplyCustomize(Design design, CustomizeIndex idx, bool value)
{ {
var set = _customizations.AwaitedService.GetList(design.DesignData.Customize.Clan, design.DesignData.Customize.Gender);
value &= set.IsAvailable(idx) || idx is CustomizeIndex.Clan or CustomizeIndex.Gender;
if (!design.SetApplyCustomize(idx, value)) if (!design.SetApplyCustomize(idx, value))
return; return;
@ -329,7 +336,7 @@ public class DesignManager
return; return;
var old = design.DesignData.Item(slot); var old = design.DesignData.Item(slot);
if (!design.DesignData.SetItem(slot, item)) if (!design.GetDesignDataRef().SetItem(slot, item))
return; return;
design.LastEdit = DateTimeOffset.UtcNow; design.LastEdit = DateTimeOffset.UtcNow;
@ -358,7 +365,8 @@ public class DesignManager
return; return;
} }
if (!(design.DesignData.SetItem(EquipSlot.MainHand, item) | design.DesignData.SetItem(EquipSlot.OffHand, newOff))) if (!(design.GetDesignDataRef().SetItem(EquipSlot.MainHand, item)
| design.GetDesignDataRef().SetItem(EquipSlot.OffHand, newOff)))
return; return;
design.LastEdit = DateTimeOffset.UtcNow; design.LastEdit = DateTimeOffset.UtcNow;
@ -372,7 +380,7 @@ public class DesignManager
if (!_items.IsOffhandValid(currentOff.Type, item.ItemId, out item)) if (!_items.IsOffhandValid(currentOff.Type, item.ItemId, out item))
return; return;
if (!design.DesignData.SetItem(EquipSlot.OffHand, item)) if (!design.GetDesignDataRef().SetItem(EquipSlot.OffHand, item))
return; return;
design.LastEdit = DateTimeOffset.UtcNow; design.LastEdit = DateTimeOffset.UtcNow;
@ -404,7 +412,7 @@ public class DesignManager
return; return;
var oldStain = design.DesignData.Stain(slot); var oldStain = design.DesignData.Stain(slot);
if (!design.DesignData.SetStain(slot, stain)) if (!design.GetDesignDataRef().SetStain(slot, stain))
return; return;
design.LastEdit = DateTimeOffset.UtcNow; design.LastEdit = DateTimeOffset.UtcNow;
@ -430,10 +438,10 @@ public class DesignManager
{ {
var change = metaIndex switch var change = metaIndex switch
{ {
ActorState.MetaIndex.Wetness => design.DesignData.SetIsWet(value), ActorState.MetaIndex.Wetness => design.GetDesignDataRef().SetIsWet(value),
ActorState.MetaIndex.HatState => design.DesignData.SetHatVisible(value), ActorState.MetaIndex.HatState => design.GetDesignDataRef().SetHatVisible(value),
ActorState.MetaIndex.VisorState => design.DesignData.SetVisor(value), ActorState.MetaIndex.VisorState => design.GetDesignDataRef().SetVisor(value),
ActorState.MetaIndex.WeaponState => design.DesignData.SetWeaponVisible(value), ActorState.MetaIndex.WeaponState => design.GetDesignDataRef().SetWeaponVisible(value),
_ => throw new ArgumentOutOfRangeException(nameof(metaIndex), metaIndex, null), _ => throw new ArgumentOutOfRangeException(nameof(metaIndex), metaIndex, null),
}; };
if (!change) if (!change)
@ -470,13 +478,13 @@ public class DesignManager
{ {
_undoStore[design.Identifier] = design.DesignData; _undoStore[design.Identifier] = design.DesignData;
if (other.DoApplyWetness()) if (other.DoApplyWetness())
design.DesignData.SetIsWet(other.DesignData.IsWet()); design.GetDesignDataRef().SetIsWet(other.DesignData.IsWet());
if (other.DoApplyHatVisible()) if (other.DoApplyHatVisible())
design.DesignData.SetHatVisible(other.DesignData.IsHatVisible()); design.GetDesignDataRef().SetHatVisible(other.DesignData.IsHatVisible());
if (other.DoApplyVisorToggle()) if (other.DoApplyVisorToggle())
design.DesignData.SetVisor(other.DesignData.IsVisorToggled()); design.GetDesignDataRef().SetVisor(other.DesignData.IsVisorToggled());
if (other.DoApplyWeaponVisible()) if (other.DoApplyWeaponVisible())
design.DesignData.SetWeaponVisible(other.DesignData.IsWeaponVisible()); design.GetDesignDataRef().SetWeaponVisible(other.DesignData.IsWeaponVisible());
if (design.DesignData.IsHuman) if (design.DesignData.IsHuman)
{ {
@ -515,7 +523,7 @@ public class DesignManager
return; return;
var other = CreateTemporary(); var other = CreateTemporary();
other.DesignData = otherData; other.SetDesignData(_customizations, otherData);
ApplyDesign(design, other); ApplyDesign(design, other);
} }
@ -545,7 +553,7 @@ public class DesignManager
Identifier = CreateNewGuid(), Identifier = CreateNewGuid(),
Name = actualName, Name = actualName,
}; };
design.MigrateBase64(_items, _humans, base64); design.MigrateBase64(_customizations, _items, _humans, base64);
if (!oldDesigns.Any(d => d.Name == design.Name && d.CreationDate == design.CreationDate)) if (!oldDesigns.Any(d => d.Name == design.Name && d.CreationDate == design.CreationDate))
{ {
Add(design, $"Migrated old design to {design.Identifier}."); Add(design, $"Migrated old design to {design.Identifier}.");

View file

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Specialized;
using System.Linq; using System.Linq;
using Dalamud.Interface; using Dalamud.Interface;
using Glamourer.Customization; using Glamourer.Customization;

View file

@ -962,7 +962,7 @@ public unsafe class DebugTab : ITab
continue; continue;
DrawDesign(design); DrawDesign(design);
var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.ApplyEquip, design.ApplyCustomize, var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.ApplyEquip, design.ApplyCustomizeRaw,
design.DoApplyHatVisible(), design.DoApplyHatVisible(),
design.DoApplyVisorToggle(), design.DoApplyWeaponVisible(), design.WriteProtected()); design.DoApplyVisorToggle(), design.DoApplyWeaponVisible(), design.WriteProtected());
using var font = ImRaii.PushFont(UiBuilder.MonoFont); using var font = ImRaii.PushFont(UiBuilder.MonoFont);

View file

@ -4,7 +4,6 @@ using System.Numerics;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.Internal.Notifications;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Glamourer.Customization;
using Glamourer.Designs; using Glamourer.Designs;
using Glamourer.Events; using Glamourer.Events;
using Glamourer.Services; using Glamourer.Services;
@ -119,6 +118,9 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
case DesignChanged.Type.Deleted: case DesignChanged.Type.Deleted:
case DesignChanged.Type.ApplyCustomize: case DesignChanged.Type.ApplyCustomize:
case DesignChanged.Type.ApplyEquip: case DesignChanged.Type.ApplyEquip:
case DesignChanged.Type.Customize:
case DesignChanged.Type.Equip:
case DesignChanged.Type.Weapon:
SetFilterDirty(); SetFilterDirty();
break; break;
} }
@ -274,9 +276,8 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
/// <summary> Combined wrapper for handling all filters and setting state. </summary> /// <summary> Combined wrapper for handling all filters and setting state. </summary>
private bool ApplyFiltersAndState(DesignFileSystem.Leaf leaf, out DesignState state) private bool ApplyFiltersAndState(DesignFileSystem.Leaf leaf, out DesignState state)
{ {
var applyEquip = leaf.Value.ApplyEquip != 0; var applyEquip = leaf.Value.ApplyEquip != 0;
var list = _customizationService.AwaitedService.GetList(leaf.Value.DesignData.Customize.Clan, leaf.Value.DesignData.Customize.Gender); var applyCustomize = leaf.Value.ApplyCustomize != 0;
var applyCustomize = leaf.Value.ApplyCustomize.FixApplication(list) != 0;
state.Color = (applyEquip, applyCustomize) switch state.Color = (applyEquip, applyCustomize) switch
{ {

View file

@ -193,7 +193,7 @@ public class DesignPanel
if (!ImGui.CollapsingHeader(header)) if (!ImGui.CollapsingHeader(header))
return; return;
if (_customizationDrawer.Draw(_selector.Selected!.DesignData.Customize, _selector.Selected.ApplyCustomize, if (_customizationDrawer.Draw(_selector.Selected!.DesignData.Customize, _selector.Selected.ApplyCustomizeRaw,
_selector.Selected!.WriteProtected(), false)) _selector.Selected!.WriteProtected(), false))
foreach (var idx in Enum.GetValues<CustomizeIndex>()) foreach (var idx in Enum.GetValues<CustomizeIndex>())
{ {
@ -217,18 +217,15 @@ public class DesignPanel
using (var group1 = ImRaii.Group()) using (var group1 = ImRaii.Group())
{ {
var set = _customizationService.AwaitedService.GetList(_selector.Selected!.DesignData.Customize.Clan, var set = _selector.Selected!.CustomizationSet;
_selector.Selected!.DesignData.Customize.Gender); var available = set.SettingAvailable | CustomizeFlag.Clan | CustomizeFlag.Gender;
var all = CustomizationExtensions.All.Where(set.IsAvailable).Select(c => c.ToFlag()).Aggregate((a, b) => a | b) var flags = _selector.Selected!.ApplyCustomize == 0 ? 0 : (_selector.Selected!.ApplyCustomize & available) == available ? 3 : 1;
| CustomizeFlag.Clan
| CustomizeFlag.Gender;
var flags = (_selector.Selected!.ApplyCustomize & all) == 0 ? 0 : (_selector.Selected!.ApplyCustomize & all) == all ? 3 : 1;
if (ImGui.CheckboxFlags("Apply All Customizations", ref flags, 3)) if (ImGui.CheckboxFlags("Apply All Customizations", ref flags, 3))
{ {
var newFlags = flags == 3; var newFlags = flags == 3;
_manager.ChangeApplyCustomize(_selector.Selected!, CustomizeIndex.Clan, newFlags); _manager.ChangeApplyCustomize(_selector.Selected!, CustomizeIndex.Clan, newFlags);
_manager.ChangeApplyCustomize(_selector.Selected!, CustomizeIndex.Gender, newFlags); _manager.ChangeApplyCustomize(_selector.Selected!, CustomizeIndex.Gender, newFlags);
foreach (var index in CustomizationExtensions.AllBasic.Where(set.IsAvailable)) foreach (var index in CustomizationExtensions.AllBasic)
_manager.ChangeApplyCustomize(_selector.Selected!, index, newFlags); _manager.ChangeApplyCustomize(_selector.Selected!, index, newFlags);
} }

View file

@ -249,8 +249,7 @@ public unsafe class FunModule : IDisposable
try try
{ {
var tmp = _designManager.CreateTemporary(); var tmp = _designManager.CreateTemporary();
tmp.DesignData = _stateManager.FromActor(actor, true, true); tmp.SetDesignData(_customizations, _stateManager.FromActor(actor, true, true));
tmp.FixCustomizeApplication(_customizations, CustomizeFlagExtensions.AllRelevant);
var data = _designConverter.ShareBase64(tmp); var data = _designConverter.ShareBase64(tmp);
ImGui.SetClipboardText(data); ImGui.SetClipboardText(data);
Glamourer.Messager.NotificationMessage($"Copied current actual design of {actor.Utf8Name} to clipboard.", NotificationType.Info, Glamourer.Messager.NotificationMessage($"Copied current actual design of {actor.Utf8Name} to clipboard.", NotificationType.Info,

View file

@ -368,7 +368,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
}; };
} }
if (!_editor.ChangeModelId(state, design.DesignData.ModelId, design.DesignData.Customize, design.DesignData.GetEquipmentPtr(), source, if (!_editor.ChangeModelId(state, design.DesignData.ModelId, design.DesignData.Customize, design.GetDesignDataRef().GetEquipmentPtr(), source,
out var oldModelId, key)) out var oldModelId, key))
return; return;