mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-13 12:14:18 +01:00
Update other things.
This commit is contained in:
parent
81059411e5
commit
9529963aa2
31 changed files with 575 additions and 294 deletions
|
|
@ -106,6 +106,7 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
||||||
["Tags"] = JArray.FromObject(Tags),
|
["Tags"] = JArray.FromObject(Tags),
|
||||||
["WriteProtected"] = WriteProtected(),
|
["WriteProtected"] = WriteProtected(),
|
||||||
["Equipment"] = SerializeEquipment(),
|
["Equipment"] = SerializeEquipment(),
|
||||||
|
["Bonus"] = SerializeBonusItems(),
|
||||||
["Customize"] = SerializeCustomize(),
|
["Customize"] = SerializeCustomize(),
|
||||||
["Parameters"] = SerializeParameters(),
|
["Parameters"] = SerializeParameters(),
|
||||||
["Materials"] = SerializeMaterials(),
|
["Materials"] = SerializeMaterials(),
|
||||||
|
|
@ -171,6 +172,7 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
||||||
design.SetWriteProtected(json["WriteProtected"]?.ToObject<bool>() ?? false);
|
design.SetWriteProtected(json["WriteProtected"]?.ToObject<bool>() ?? false);
|
||||||
LoadCustomize(customizations, json["Customize"], design, design.Name, true, false);
|
LoadCustomize(customizations, json["Customize"], design, design.Name, true, false);
|
||||||
LoadEquip(items, json["Equipment"], design, design.Name, true);
|
LoadEquip(items, json["Equipment"], design, design.Name, true);
|
||||||
|
LoadBonus(items, design, json["Bonus"]);
|
||||||
LoadMods(json["Mods"], design);
|
LoadMods(json["Mods"], design);
|
||||||
LoadParameters(json["Parameters"], design, design.Name);
|
LoadParameters(json["Parameters"], design, design.Name);
|
||||||
LoadMaterials(json["Materials"], design, design.Name);
|
LoadMaterials(json["Materials"], design, design.Name);
|
||||||
|
|
|
||||||
|
|
@ -228,6 +228,7 @@ public class DesignBase
|
||||||
{
|
{
|
||||||
["FileVersion"] = FileVersion,
|
["FileVersion"] = FileVersion,
|
||||||
["Equipment"] = SerializeEquipment(),
|
["Equipment"] = SerializeEquipment(),
|
||||||
|
["Bonus"] = SerializeBonusItems(),
|
||||||
["Customize"] = SerializeCustomize(),
|
["Customize"] = SerializeCustomize(),
|
||||||
["Parameters"] = SerializeParameters(),
|
["Parameters"] = SerializeParameters(),
|
||||||
["Materials"] = SerializeMaterials(),
|
["Materials"] = SerializeMaterials(),
|
||||||
|
|
@ -279,7 +280,7 @@ public class DesignBase
|
||||||
var item = _designData.BonusItem(slot);
|
var item = _designData.BonusItem(slot);
|
||||||
ret[slot.ToString()] = new JObject()
|
ret[slot.ToString()] = new JObject()
|
||||||
{
|
{
|
||||||
["BonusId"] = item.ModelId.Id,
|
["BonusId"] = item.Id.Id,
|
||||||
["Apply"] = DoApplyBonusItem(slot),
|
["Apply"] = DoApplyBonusItem(slot),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -424,9 +425,35 @@ public class DesignBase
|
||||||
LoadEquip(items, json["Equipment"], ret, "Temporary Design", true);
|
LoadEquip(items, json["Equipment"], ret, "Temporary Design", true);
|
||||||
LoadParameters(json["Parameters"], ret, "Temporary Design");
|
LoadParameters(json["Parameters"], ret, "Temporary Design");
|
||||||
LoadMaterials(json["Materials"], ret, "Temporary Design");
|
LoadMaterials(json["Materials"], ret, "Temporary Design");
|
||||||
|
LoadBonus(items, ret, json["Bonus"]);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static void LoadBonus(ItemManager items, DesignBase design, JToken? json)
|
||||||
|
{
|
||||||
|
if (json is not JObject obj)
|
||||||
|
{
|
||||||
|
design.Application.BonusItem = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
var itemJson = json[slot.ToString()] as JObject;
|
||||||
|
if (itemJson == null)
|
||||||
|
{
|
||||||
|
design.Application.BonusItem &= ~slot;
|
||||||
|
design.GetDesignDataRef().SetBonusItem(slot, BonusItem.Empty(slot));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
design.SetApplyBonusItem(slot, itemJson["Apply"]?.ToObject<bool>() ?? false);
|
||||||
|
var id = itemJson["BonusId"]?.ToObject<ushort>() ?? 0;
|
||||||
|
var item = items.Resolve(slot, id);
|
||||||
|
design.GetDesignDataRef().SetBonusItem(slot, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected static void LoadParameters(JToken? parameters, DesignBase design, string name)
|
protected static void LoadParameters(JToken? parameters, DesignBase design, string name)
|
||||||
{
|
{
|
||||||
if (parameters == null)
|
if (parameters == null)
|
||||||
|
|
@ -436,7 +463,6 @@ public class DesignBase
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach (var flag in CustomizeParameterExtensions.ValueFlags)
|
foreach (var flag in CustomizeParameterExtensions.ValueFlags)
|
||||||
{
|
{
|
||||||
if (!TryGetToken(flag, out var token))
|
if (!TryGetToken(flag, out var token))
|
||||||
|
|
@ -523,32 +549,15 @@ public class DesignBase
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static (CustomItemId, StainIds, bool, bool, bool, bool) ParseItem(EquipSlot slot, JToken? item)
|
|
||||||
{
|
|
||||||
var id = item?["ItemId"]?.ToObject<ulong>() ?? ItemManager.NothingId(slot).Id;
|
|
||||||
var stain = (StainId)(item?["Stain"]?.ToObject<byte>() ?? 0);
|
|
||||||
var crest = item?["Crest"]?.ToObject<bool>() ?? false;
|
|
||||||
var apply = item?["Apply"]?.ToObject<bool>() ?? false;
|
|
||||||
var applyStain = item?["ApplyStain"]?.ToObject<bool>() ?? false;
|
|
||||||
var applyCrest = item?["ApplyCrest"]?.ToObject<bool>() ?? false;
|
|
||||||
return (id, stain, crest, apply, applyStain, applyCrest);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintWarning(string msg)
|
|
||||||
{
|
|
||||||
if (msg.Length > 0 && name != "Temporary Design")
|
|
||||||
Glamourer.Messager.NotificationMessage($"{msg} ({name})", NotificationType.Warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||||
{
|
{
|
||||||
var (id, stain, crest, apply, applyStain, applyCrest) = ParseItem(slot, equip[slot.ToString()]);
|
var (id, stains, crest, apply, applyStain, applyCrest) = ParseItem(slot, equip[slot.ToString()]);
|
||||||
|
|
||||||
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(stains, out stains, allowUnknown));
|
||||||
var crestSlot = slot.ToCrestFlag();
|
var crestSlot = slot.ToCrestFlag();
|
||||||
design._designData.SetItem(slot, item);
|
design._designData.SetItem(slot, item);
|
||||||
design._designData.SetStain(slot, stain);
|
design._designData.SetStain(slot, stains);
|
||||||
design._designData.SetCrest(crestSlot, crest);
|
design._designData.SetCrest(crestSlot, crest);
|
||||||
design.SetApplyEquip(slot, apply);
|
design.SetApplyEquip(slot, apply);
|
||||||
design.SetApplyStain(slot, applyStain);
|
design.SetApplyStain(slot, applyStain);
|
||||||
|
|
@ -556,21 +565,21 @@ public class DesignBase
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var (id, stain, crest, apply, applyStain, applyCrest) = ParseItem(EquipSlot.MainHand, equip[EquipSlot.MainHand.ToString()]);
|
var (id, stains, crest, apply, applyStain, applyCrest) = ParseItem(EquipSlot.MainHand, equip[EquipSlot.MainHand.ToString()]);
|
||||||
if (id == ItemManager.NothingId(EquipSlot.MainHand))
|
if (id == ItemManager.NothingId(EquipSlot.MainHand))
|
||||||
id = items.DefaultSword.ItemId;
|
id = items.DefaultSword.ItemId;
|
||||||
var (idOff, stainOff, crestOff, applyOff, applyStainOff, applyCrestOff) =
|
var (idOff, stainsOff, crestOff, applyOff, applyStainOff, applyCrestOff) =
|
||||||
ParseItem(EquipSlot.OffHand, equip[EquipSlot.OffHand.ToString()]);
|
ParseItem(EquipSlot.OffHand, equip[EquipSlot.OffHand.ToString()]);
|
||||||
if (id == ItemManager.NothingId(EquipSlot.OffHand))
|
if (id == ItemManager.NothingId(EquipSlot.OffHand))
|
||||||
id = ItemManager.NothingId(FullEquipType.Shield);
|
id = ItemManager.NothingId(FullEquipType.Shield);
|
||||||
|
|
||||||
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(stains, out stains, allowUnknown));
|
||||||
PrintWarning(items.ValidateStain(stainOff, out stainOff, allowUnknown));
|
PrintWarning(items.ValidateStain(stainsOff, out stainsOff, 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, stains);
|
||||||
design._designData.SetStain(EquipSlot.OffHand, stainOff);
|
design._designData.SetStain(EquipSlot.OffHand, stainsOff);
|
||||||
design._designData.SetCrest(CrestFlag.MainHand, crest);
|
design._designData.SetCrest(CrestFlag.MainHand, crest);
|
||||||
design._designData.SetCrest(CrestFlag.OffHand, crestOff);
|
design._designData.SetCrest(CrestFlag.OffHand, crestOff);
|
||||||
design.SetApplyEquip(EquipSlot.MainHand, apply);
|
design.SetApplyEquip(EquipSlot.MainHand, apply);
|
||||||
|
|
@ -591,6 +600,24 @@ public class DesignBase
|
||||||
metaValue = QuadBool.FromJObject(equip["Visor"], "IsToggled", "Apply", QuadBool.NullFalse);
|
metaValue = QuadBool.FromJObject(equip["Visor"], "IsToggled", "Apply", QuadBool.NullFalse);
|
||||||
design.SetApplyMeta(MetaIndex.VisorState, metaValue.Enabled);
|
design.SetApplyMeta(MetaIndex.VisorState, metaValue.Enabled);
|
||||||
design._designData.SetVisor(metaValue.ForcedValue);
|
design._designData.SetVisor(metaValue.ForcedValue);
|
||||||
|
return;
|
||||||
|
|
||||||
|
void PrintWarning(string msg)
|
||||||
|
{
|
||||||
|
if (msg.Length > 0 && name != "Temporary Design")
|
||||||
|
Glamourer.Messager.NotificationMessage($"{msg} ({name})", NotificationType.Warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
static (CustomItemId, StainIds, bool, bool, bool, bool) ParseItem(EquipSlot slot, JToken? item)
|
||||||
|
{
|
||||||
|
var id = item?["ItemId"]?.ToObject<ulong>() ?? ItemManager.NothingId(slot).Id;
|
||||||
|
var stains = StainIds.ParseFromObject(item as JObject);
|
||||||
|
var crest = item?["Crest"]?.ToObject<bool>() ?? false;
|
||||||
|
var apply = item?["Apply"]?.ToObject<bool>() ?? false;
|
||||||
|
var applyStain = item?["ApplyStain"]?.ToObject<bool>() ?? false;
|
||||||
|
var applyCrest = item?["ApplyCrest"]?.ToObject<bool>() ?? false;
|
||||||
|
return (id, stains, crest, apply, applyStain, applyCrest);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void LoadCustomize(CustomizeService customizations, JToken? json, DesignBase design, string name, bool forbidNonHuman,
|
protected static void LoadCustomize(CustomizeService customizations, JToken? json, DesignBase design, string name, bool forbidNonHuman,
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ public class DesignConverter(
|
||||||
foreach (var (key, value) in materials.Values)
|
foreach (var (key, value) in materials.Values)
|
||||||
{
|
{
|
||||||
var idx = MaterialValueIndex.FromKey(key);
|
var idx = MaterialValueIndex.FromKey(key);
|
||||||
if (idx.RowIndex >= LegacyColorTable.NumUsedRows)
|
if (idx.RowIndex >= ColorTable.NumUsedRows)
|
||||||
continue;
|
continue;
|
||||||
if (idx.MaterialIndex >= MaterialService.MaterialsPerModel)
|
if (idx.MaterialIndex >= MaterialService.MaterialsPerModel)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ public unsafe struct DesignData
|
||||||
8 => EquipItem.FromIds(_itemIds[ 8], _iconIds[ 8], ((CharacterArmor*)ptr)[8].Set, 0, ((CharacterArmor*)ptr)[8].Variant, FullEquipType.Finger, name: _nameRFinger ),
|
8 => EquipItem.FromIds(_itemIds[ 8], _iconIds[ 8], ((CharacterArmor*)ptr)[8].Set, 0, ((CharacterArmor*)ptr)[8].Variant, FullEquipType.Finger, name: _nameRFinger ),
|
||||||
9 => EquipItem.FromIds(_itemIds[ 9], _iconIds[ 9], ((CharacterArmor*)ptr)[9].Set, 0, ((CharacterArmor*)ptr)[9].Variant, FullEquipType.Finger, name: _nameLFinger ),
|
9 => EquipItem.FromIds(_itemIds[ 9], _iconIds[ 9], ((CharacterArmor*)ptr)[9].Set, 0, ((CharacterArmor*)ptr)[9].Variant, FullEquipType.Finger, name: _nameLFinger ),
|
||||||
10 => EquipItem.FromIds(_itemIds[10], _iconIds[10], *(PrimaryId*)(ptr + EquipmentByteSize + 0), *(SecondaryId*)(ptr + EquipmentByteSize + 2), *(Variant*)(ptr + EquipmentByteSize + 4), _typeMainhand, name: _nameMainhand),
|
10 => EquipItem.FromIds(_itemIds[10], _iconIds[10], *(PrimaryId*)(ptr + EquipmentByteSize + 0), *(SecondaryId*)(ptr + EquipmentByteSize + 2), *(Variant*)(ptr + EquipmentByteSize + 4), _typeMainhand, name: _nameMainhand),
|
||||||
11 => EquipItem.FromIds(_itemIds[11], _iconIds[11], *(PrimaryId*)(ptr + EquipmentByteSize + 4), *(SecondaryId*)(ptr + EquipmentByteSize + 2), *(Variant*)(ptr + EquipmentByteSize + 4), _typeOffhand, name: _nameOffhand ),
|
11 => EquipItem.FromIds(_itemIds[11], _iconIds[11], *(PrimaryId*)(ptr + EquipmentByteSize + 8), *(SecondaryId*)(ptr + EquipmentByteSize + 10), *(Variant*)(ptr + EquipmentByteSize + 12), _typeOffhand, name: _nameOffhand ),
|
||||||
_ => new EquipItem(),
|
_ => new EquipItem(),
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
};
|
};
|
||||||
|
|
@ -176,12 +176,14 @@ public unsafe struct DesignData
|
||||||
_nameMainhand = item.Name;
|
_nameMainhand = item.Name;
|
||||||
_equipmentBytes[EquipmentByteSize + 2] = (byte)item.SecondaryId.Id;
|
_equipmentBytes[EquipmentByteSize + 2] = (byte)item.SecondaryId.Id;
|
||||||
_equipmentBytes[EquipmentByteSize + 3] = (byte)(item.SecondaryId.Id >> 8);
|
_equipmentBytes[EquipmentByteSize + 3] = (byte)(item.SecondaryId.Id >> 8);
|
||||||
|
_equipmentBytes[EquipmentByteSize + 4] = item.Variant.Id;
|
||||||
_typeMainhand = item.Type;
|
_typeMainhand = item.Type;
|
||||||
return true;
|
return true;
|
||||||
case 11:
|
case 11:
|
||||||
_nameOffhand = item.Name;
|
_nameOffhand = item.Name;
|
||||||
_equipmentBytes[EquipmentByteSize + 2] = (byte)item.SecondaryId.Id;
|
_equipmentBytes[EquipmentByteSize + 10] = (byte)item.SecondaryId.Id;
|
||||||
_equipmentBytes[EquipmentByteSize + 3] = (byte)(item.SecondaryId.Id >> 8);
|
_equipmentBytes[EquipmentByteSize + 11] = (byte)(item.SecondaryId.Id >> 8);
|
||||||
|
_equipmentBytes[EquipmentByteSize + 12] = item.Variant.Id;
|
||||||
_typeOffhand = item.Type;
|
_typeOffhand = item.Type;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -212,18 +214,18 @@ public unsafe struct DesignData
|
||||||
=> slot.ToIndex() switch
|
=> slot.ToIndex() switch
|
||||||
{
|
{
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
0 => SetIfDifferent(ref _equipmentBytes[0 * CharacterArmor.Size + 3], stains.Stain1.Id) || SetIfDifferent(ref _equipmentBytes[0 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
0 => SetIfDifferent(ref _equipmentBytes[0 * CharacterArmor.Size + 3], stains.Stain1.Id) | SetIfDifferent(ref _equipmentBytes[0 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
||||||
1 => SetIfDifferent(ref _equipmentBytes[1 * CharacterArmor.Size + 3], stains.Stain1.Id) || SetIfDifferent(ref _equipmentBytes[1 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
1 => SetIfDifferent(ref _equipmentBytes[1 * CharacterArmor.Size + 3], stains.Stain1.Id) | SetIfDifferent(ref _equipmentBytes[1 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
||||||
2 => SetIfDifferent(ref _equipmentBytes[2 * CharacterArmor.Size + 3], stains.Stain1.Id) || SetIfDifferent(ref _equipmentBytes[2 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
2 => SetIfDifferent(ref _equipmentBytes[2 * CharacterArmor.Size + 3], stains.Stain1.Id) | SetIfDifferent(ref _equipmentBytes[2 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
||||||
3 => SetIfDifferent(ref _equipmentBytes[3 * CharacterArmor.Size + 3], stains.Stain1.Id) || SetIfDifferent(ref _equipmentBytes[3 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
3 => SetIfDifferent(ref _equipmentBytes[3 * CharacterArmor.Size + 3], stains.Stain1.Id) | SetIfDifferent(ref _equipmentBytes[3 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
||||||
4 => SetIfDifferent(ref _equipmentBytes[4 * CharacterArmor.Size + 3], stains.Stain1.Id) || SetIfDifferent(ref _equipmentBytes[4 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
4 => SetIfDifferent(ref _equipmentBytes[4 * CharacterArmor.Size + 3], stains.Stain1.Id) | SetIfDifferent(ref _equipmentBytes[4 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
||||||
5 => SetIfDifferent(ref _equipmentBytes[5 * CharacterArmor.Size + 3], stains.Stain1.Id) || SetIfDifferent(ref _equipmentBytes[5 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
5 => SetIfDifferent(ref _equipmentBytes[5 * CharacterArmor.Size + 3], stains.Stain1.Id) | SetIfDifferent(ref _equipmentBytes[5 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
||||||
6 => SetIfDifferent(ref _equipmentBytes[6 * CharacterArmor.Size + 3], stains.Stain1.Id) || SetIfDifferent(ref _equipmentBytes[6 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
6 => SetIfDifferent(ref _equipmentBytes[6 * CharacterArmor.Size + 3], stains.Stain1.Id) | SetIfDifferent(ref _equipmentBytes[6 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
||||||
7 => SetIfDifferent(ref _equipmentBytes[7 * CharacterArmor.Size + 3], stains.Stain1.Id) || SetIfDifferent(ref _equipmentBytes[7 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
7 => SetIfDifferent(ref _equipmentBytes[7 * CharacterArmor.Size + 3], stains.Stain1.Id) | SetIfDifferent(ref _equipmentBytes[7 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
||||||
8 => SetIfDifferent(ref _equipmentBytes[8 * CharacterArmor.Size + 3], stains.Stain1.Id) || SetIfDifferent(ref _equipmentBytes[8 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
8 => SetIfDifferent(ref _equipmentBytes[8 * CharacterArmor.Size + 3], stains.Stain1.Id) | SetIfDifferent(ref _equipmentBytes[8 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
||||||
9 => SetIfDifferent(ref _equipmentBytes[9 * CharacterArmor.Size + 3], stains.Stain1.Id) || SetIfDifferent(ref _equipmentBytes[9 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
9 => SetIfDifferent(ref _equipmentBytes[9 * CharacterArmor.Size + 3], stains.Stain1.Id) | SetIfDifferent(ref _equipmentBytes[9 * CharacterArmor.Size + 4], stains.Stain2.Id),
|
||||||
10 => SetIfDifferent(ref _equipmentBytes[EquipmentByteSize + 6], stains.Stain1.Id) || SetIfDifferent(ref _equipmentBytes[EquipmentByteSize + 7], stains.Stain2.Id),
|
10 => SetIfDifferent(ref _equipmentBytes[EquipmentByteSize + 6], stains.Stain1.Id) | SetIfDifferent(ref _equipmentBytes[EquipmentByteSize + 7], stains.Stain2.Id),
|
||||||
11 => SetIfDifferent(ref _equipmentBytes[EquipmentByteSize + 14], stains.Stain1.Id) || SetIfDifferent(ref _equipmentBytes[EquipmentByteSize + 15], stains.Stain2.Id),
|
11 => SetIfDifferent(ref _equipmentBytes[EquipmentByteSize + 14], stains.Stain1.Id) | SetIfDifferent(ref _equipmentBytes[EquipmentByteSize + 15], stains.Stain2.Id),
|
||||||
_ => false,
|
_ => false,
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
};
|
};
|
||||||
|
|
@ -322,6 +324,13 @@ public unsafe struct DesignData
|
||||||
SetItem(EquipSlot.OffHand, ItemManager.NothingItem(FullEquipType.Shield));
|
SetItem(EquipSlot.OffHand, ItemManager.NothingItem(FullEquipType.Shield));
|
||||||
SetStain(EquipSlot.OffHand, StainIds.None);
|
SetStain(EquipSlot.OffHand, StainIds.None);
|
||||||
SetCrest(CrestFlag.OffHand, false);
|
SetCrest(CrestFlag.OffHand, false);
|
||||||
|
SetDefaultBonusItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetDefaultBonusItems()
|
||||||
|
{
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
|
SetBonusItem(slot, Penumbra.GameData.Structs.BonusItem.Empty(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,9 +165,21 @@ public class DesignEditor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public void ChangeBonusItem(object data, BonusItemFlag slot, BonusItem item, ApplySettings settings = default)
|
public void ChangeBonusItem(object data, BonusItemFlag slot, BonusItem item, ApplySettings settings = default)
|
||||||
{
|
{
|
||||||
|
var design = (Design)data;
|
||||||
|
if (!Items.IsBonusItemValid(slot, item.Id, out item))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var oldItem = design.DesignData.BonusItem(slot);
|
||||||
|
if (!design.GetDesignDataRef().SetBonusItem(slot, item))
|
||||||
|
return;
|
||||||
|
|
||||||
|
design.LastEdit = DateTimeOffset.UtcNow;
|
||||||
|
SaveService.QueueSave(design);
|
||||||
|
Glamourer.Log.Debug($"Set {slot} bonus item to {item}.");
|
||||||
|
DesignChanged.Invoke(DesignChanged.Type.BonusItem, design, (oldItem, item, slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|
|
||||||
|
|
@ -356,7 +356,7 @@ public sealed class DesignManager : DesignEditor
|
||||||
design.LastEdit = DateTimeOffset.UtcNow;
|
design.LastEdit = DateTimeOffset.UtcNow;
|
||||||
SaveService.QueueSave(design);
|
SaveService.QueueSave(design);
|
||||||
Glamourer.Log.Debug($"Set applying of {slot} bonus item to {value}.");
|
Glamourer.Log.Debug($"Set applying of {slot} bonus item to {value}.");
|
||||||
DesignChanged.Invoke(DesignChanged.Type.ApplyBonus, design, slot);
|
DesignChanged.Invoke(DesignChanged.Type.ApplyBonusItem, design, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Change whether to apply a specific stain. </summary>
|
/// <summary> Change whether to apply a specific stain. </summary>
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,9 @@ public sealed class DesignChanged()
|
||||||
/// <summary> An existing design had an equipment piece changed. Data is the old value, the new value and the slot [(EquipItem, EquipItem, EquipSlot)]. </summary>
|
/// <summary> An existing design had an equipment piece changed. Data is the old value, the new value and the slot [(EquipItem, EquipItem, EquipSlot)]. </summary>
|
||||||
Equip,
|
Equip,
|
||||||
|
|
||||||
|
/// <summary> An existing design had a bonus item changed. Data is the old value, the new value and the slot [(BonusItem, BonusItem, BonusItemFlag)]. </summary>
|
||||||
|
BonusItem,
|
||||||
|
|
||||||
/// <summary> An existing design had its weapons changed. Data is the old mainhand, the old offhand, the new mainhand, the new offhand (if any) and the new gauntlets (if any). [(EquipItem, EquipItem, EquipItem, EquipItem?, EquipItem?)]. </summary>
|
/// <summary> An existing design had its weapons changed. Data is the old mainhand, the old offhand, the new mainhand, the new offhand (if any) and the new gauntlets (if any). [(EquipItem, EquipItem, EquipItem, EquipItem?, EquipItem?)]. </summary>
|
||||||
Weapon,
|
Weapon,
|
||||||
|
|
||||||
|
|
@ -90,7 +93,7 @@ public sealed class DesignChanged()
|
||||||
ApplyEquip,
|
ApplyEquip,
|
||||||
|
|
||||||
/// <summary> An existing design changed whether a specific bonus item is applied. Data is the slot of the item [BonusItemFlag]. </summary>
|
/// <summary> An existing design changed whether a specific bonus item is applied. Data is the slot of the item [BonusItemFlag]. </summary>
|
||||||
ApplyBonus,
|
ApplyBonusItem,
|
||||||
|
|
||||||
/// <summary> An existing design changed whether a specific stain is applied. Data is the slot of the equipment [EquipSlot]. </summary>
|
/// <summary> An existing design changed whether a specific stain is applied. Data is the slot of the equipment [EquipSlot]. </summary>
|
||||||
ApplyStain,
|
ApplyStain,
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@ public struct CustomizeParameterData
|
||||||
public Vector3 HairSpecular;
|
public Vector3 HairSpecular;
|
||||||
public Vector3 HairHighlight;
|
public Vector3 HairHighlight;
|
||||||
public Vector3 LeftEye;
|
public Vector3 LeftEye;
|
||||||
|
public float LeftScleraIntensity;
|
||||||
public Vector3 RightEye;
|
public Vector3 RightEye;
|
||||||
|
public float RightScleraIntensity;
|
||||||
public Vector3 FeatureColor;
|
public Vector3 FeatureColor;
|
||||||
public float FacePaintUvMultiplier;
|
public float FacePaintUvMultiplier;
|
||||||
public float FacePaintUvOffset;
|
public float FacePaintUvOffset;
|
||||||
|
|
@ -33,7 +35,9 @@ public struct CustomizeParameterData
|
||||||
CustomizeParameterFlag.HairSpecular => new CustomizeParameterValue(HairSpecular),
|
CustomizeParameterFlag.HairSpecular => new CustomizeParameterValue(HairSpecular),
|
||||||
CustomizeParameterFlag.HairHighlight => new CustomizeParameterValue(HairHighlight),
|
CustomizeParameterFlag.HairHighlight => new CustomizeParameterValue(HairHighlight),
|
||||||
CustomizeParameterFlag.LeftEye => new CustomizeParameterValue(LeftEye),
|
CustomizeParameterFlag.LeftEye => new CustomizeParameterValue(LeftEye),
|
||||||
|
CustomizeParameterFlag.LeftScleraIntensity => new CustomizeParameterValue(LeftScleraIntensity),
|
||||||
CustomizeParameterFlag.RightEye => new CustomizeParameterValue(RightEye),
|
CustomizeParameterFlag.RightEye => new CustomizeParameterValue(RightEye),
|
||||||
|
CustomizeParameterFlag.RightScleraIntensity => new CustomizeParameterValue(RightScleraIntensity),
|
||||||
CustomizeParameterFlag.FeatureColor => new CustomizeParameterValue(FeatureColor),
|
CustomizeParameterFlag.FeatureColor => new CustomizeParameterValue(FeatureColor),
|
||||||
CustomizeParameterFlag.DecalColor => new CustomizeParameterValue(DecalColor),
|
CustomizeParameterFlag.DecalColor => new CustomizeParameterValue(DecalColor),
|
||||||
CustomizeParameterFlag.FacePaintUvMultiplier => new CustomizeParameterValue(FacePaintUvMultiplier),
|
CustomizeParameterFlag.FacePaintUvMultiplier => new CustomizeParameterValue(FacePaintUvMultiplier),
|
||||||
|
|
@ -57,7 +61,9 @@ public struct CustomizeParameterData
|
||||||
CustomizeParameterFlag.HairSpecular => SetIfDifferent(ref HairSpecular, value.InternalTriple),
|
CustomizeParameterFlag.HairSpecular => SetIfDifferent(ref HairSpecular, value.InternalTriple),
|
||||||
CustomizeParameterFlag.HairHighlight => SetIfDifferent(ref HairHighlight, value.InternalTriple),
|
CustomizeParameterFlag.HairHighlight => SetIfDifferent(ref HairHighlight, value.InternalTriple),
|
||||||
CustomizeParameterFlag.LeftEye => SetIfDifferent(ref LeftEye, value.InternalTriple),
|
CustomizeParameterFlag.LeftEye => SetIfDifferent(ref LeftEye, value.InternalTriple),
|
||||||
|
CustomizeParameterFlag.LeftScleraIntensity => SetIfDifferent(ref LeftScleraIntensity, value.Single),
|
||||||
CustomizeParameterFlag.RightEye => SetIfDifferent(ref RightEye, value.InternalTriple),
|
CustomizeParameterFlag.RightEye => SetIfDifferent(ref RightEye, value.InternalTriple),
|
||||||
|
CustomizeParameterFlag.RightScleraIntensity => SetIfDifferent(ref RightScleraIntensity, value.Single),
|
||||||
CustomizeParameterFlag.FeatureColor => SetIfDifferent(ref FeatureColor, value.InternalTriple),
|
CustomizeParameterFlag.FeatureColor => SetIfDifferent(ref FeatureColor, value.InternalTriple),
|
||||||
CustomizeParameterFlag.DecalColor => SetIfDifferent(ref DecalColor, value.InternalQuadruple),
|
CustomizeParameterFlag.DecalColor => SetIfDifferent(ref DecalColor, value.InternalQuadruple),
|
||||||
CustomizeParameterFlag.FacePaintUvMultiplier => SetIfDifferent(ref FacePaintUvMultiplier, value.Single),
|
CustomizeParameterFlag.FacePaintUvMultiplier => SetIfDifferent(ref FacePaintUvMultiplier, value.Single),
|
||||||
|
|
@ -67,7 +73,7 @@ public struct CustomizeParameterData
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
public readonly void Apply(ref CustomizeParameter parameters, CustomizeParameterFlag flags = CustomizeParameterExtensions.All)
|
public readonly unsafe void Apply(ref CustomizeParameter parameters, CustomizeParameterFlag flags = CustomizeParameterExtensions.All)
|
||||||
{
|
{
|
||||||
parameters.SkinColor = (flags & (CustomizeParameterFlag.SkinDiffuse | CustomizeParameterFlag.MuscleTone)) switch
|
parameters.SkinColor = (flags & (CustomizeParameterFlag.SkinDiffuse | CustomizeParameterFlag.MuscleTone)) switch
|
||||||
{
|
{
|
||||||
|
|
@ -77,20 +83,20 @@ public struct CustomizeParameterData
|
||||||
_ => new CustomizeParameterValue(SkinDiffuse, MuscleTone).XivQuadruple,
|
_ => new CustomizeParameterValue(SkinDiffuse, MuscleTone).XivQuadruple,
|
||||||
};
|
};
|
||||||
|
|
||||||
parameters.LeftColor = (flags & (CustomizeParameterFlag.LeftEye | CustomizeParameterFlag.FacePaintUvMultiplier)) switch
|
parameters.LeftColor = (flags & (CustomizeParameterFlag.LeftEye | CustomizeParameterFlag.LeftScleraIntensity)) switch
|
||||||
{
|
{
|
||||||
0 => parameters.LeftColor,
|
0 => parameters.LeftColor,
|
||||||
CustomizeParameterFlag.LeftEye => new CustomizeParameterValue(LeftEye, parameters.LeftColor.W).XivQuadruple,
|
CustomizeParameterFlag.LeftEye => new CustomizeParameterValue(LeftEye, parameters.LeftColor.W).XivQuadruple,
|
||||||
CustomizeParameterFlag.FacePaintUvMultiplier => parameters.LeftColor with { W = FacePaintUvMultiplier },
|
CustomizeParameterFlag.LeftScleraIntensity => parameters.LeftColor with { W = LeftScleraIntensity },
|
||||||
_ => new CustomizeParameterValue(LeftEye, FacePaintUvMultiplier).XivQuadruple,
|
_ => new CustomizeParameterValue(LeftEye, LeftScleraIntensity).XivQuadruple,
|
||||||
};
|
};
|
||||||
|
|
||||||
parameters.RightColor = (flags & (CustomizeParameterFlag.RightEye | CustomizeParameterFlag.FacePaintUvOffset)) switch
|
parameters.RightColor = (flags & (CustomizeParameterFlag.RightEye | CustomizeParameterFlag.RightScleraIntensity)) switch
|
||||||
{
|
{
|
||||||
0 => parameters.RightColor,
|
0 => parameters.RightColor,
|
||||||
CustomizeParameterFlag.RightEye => new CustomizeParameterValue(RightEye, parameters.RightColor.W).XivQuadruple,
|
CustomizeParameterFlag.RightEye => new CustomizeParameterValue(RightEye, parameters.RightColor.W).XivQuadruple,
|
||||||
CustomizeParameterFlag.FacePaintUvOffset => parameters.RightColor with { W = FacePaintUvOffset },
|
CustomizeParameterFlag.RightScleraIntensity => parameters.RightColor with { W = RightScleraIntensity },
|
||||||
_ => new CustomizeParameterValue(RightEye, FacePaintUvOffset).XivQuadruple,
|
_ => new CustomizeParameterValue(RightEye, RightScleraIntensity).XivQuadruple,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (flags.HasFlag(CustomizeParameterFlag.SkinSpecular))
|
if (flags.HasFlag(CustomizeParameterFlag.SkinSpecular))
|
||||||
|
|
@ -101,6 +107,10 @@ public struct CustomizeParameterData
|
||||||
parameters.HairFresnelValue0 = new CustomizeParameterValue(HairSpecular).XivTriple;
|
parameters.HairFresnelValue0 = new CustomizeParameterValue(HairSpecular).XivTriple;
|
||||||
if (flags.HasFlag(CustomizeParameterFlag.HairHighlight))
|
if (flags.HasFlag(CustomizeParameterFlag.HairHighlight))
|
||||||
parameters.MeshColor = new CustomizeParameterValue(HairHighlight).XivTriple;
|
parameters.MeshColor = new CustomizeParameterValue(HairHighlight).XivTriple;
|
||||||
|
if (flags.HasFlag(CustomizeParameterFlag.FacePaintUvMultiplier))
|
||||||
|
GetUvMultiplierWrite(ref parameters) = FacePaintUvMultiplier;
|
||||||
|
if (flags.HasFlag(CustomizeParameterFlag.FacePaintUvOffset))
|
||||||
|
GetUvOffsetWrite(ref parameters) = FacePaintUvOffset;
|
||||||
if (flags.HasFlag(CustomizeParameterFlag.LipDiffuse))
|
if (flags.HasFlag(CustomizeParameterFlag.LipDiffuse))
|
||||||
parameters.LipColor = new CustomizeParameterValue(LipDiffuse).XivQuadruple;
|
parameters.LipColor = new CustomizeParameterValue(LipDiffuse).XivQuadruple;
|
||||||
if (flags.HasFlag(CustomizeParameterFlag.FeatureColor))
|
if (flags.HasFlag(CustomizeParameterFlag.FeatureColor))
|
||||||
|
|
@ -115,7 +125,7 @@ public struct CustomizeParameterData
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
public readonly void ApplySingle(ref CustomizeParameter parameters, CustomizeParameterFlag flag)
|
public readonly unsafe void ApplySingle(ref CustomizeParameter parameters, CustomizeParameterFlag flag)
|
||||||
{
|
{
|
||||||
switch (flag)
|
switch (flag)
|
||||||
{
|
{
|
||||||
|
|
@ -150,19 +160,25 @@ public struct CustomizeParameterData
|
||||||
parameters.OptionColor = new CustomizeParameterValue(FeatureColor).XivTriple;
|
parameters.OptionColor = new CustomizeParameterValue(FeatureColor).XivTriple;
|
||||||
break;
|
break;
|
||||||
case CustomizeParameterFlag.FacePaintUvMultiplier:
|
case CustomizeParameterFlag.FacePaintUvMultiplier:
|
||||||
parameters.LeftColor.W = FacePaintUvMultiplier;
|
GetUvMultiplierWrite(ref parameters) = FacePaintUvMultiplier;
|
||||||
break;
|
break;
|
||||||
case CustomizeParameterFlag.FacePaintUvOffset:
|
case CustomizeParameterFlag.FacePaintUvOffset:
|
||||||
parameters.RightColor.W = FacePaintUvOffset;
|
GetUvOffsetWrite(ref parameters) = FacePaintUvOffset;
|
||||||
|
break;
|
||||||
|
case CustomizeParameterFlag.LeftScleraIntensity:
|
||||||
|
parameters.LeftColor.W = LeftScleraIntensity;
|
||||||
|
break;
|
||||||
|
case CustomizeParameterFlag.RightScleraIntensity:
|
||||||
|
parameters.RightColor.W = RightScleraIntensity;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CustomizeParameterData FromParameters(in CustomizeParameter parameter, in DecalParameters decal)
|
public static unsafe CustomizeParameterData FromParameters(in CustomizeParameter parameter, in DecalParameters decal)
|
||||||
=> new()
|
=> new()
|
||||||
{
|
{
|
||||||
FacePaintUvOffset = parameter.RightColor.W,
|
FacePaintUvOffset = GetUvOffset(parameter),
|
||||||
FacePaintUvMultiplier = parameter.LeftColor.W,
|
FacePaintUvMultiplier = GetUvMultiplier(parameter),
|
||||||
MuscleTone = parameter.SkinColor.W,
|
MuscleTone = parameter.SkinColor.W,
|
||||||
SkinDiffuse = new CustomizeParameterValue(parameter.SkinColor).InternalTriple,
|
SkinDiffuse = new CustomizeParameterValue(parameter.SkinColor).InternalTriple,
|
||||||
SkinSpecular = new CustomizeParameterValue(parameter.SkinFresnelValue0).InternalTriple,
|
SkinSpecular = new CustomizeParameterValue(parameter.SkinFresnelValue0).InternalTriple,
|
||||||
|
|
@ -171,12 +187,14 @@ public struct CustomizeParameterData
|
||||||
HairSpecular = new CustomizeParameterValue(parameter.HairFresnelValue0).InternalTriple,
|
HairSpecular = new CustomizeParameterValue(parameter.HairFresnelValue0).InternalTriple,
|
||||||
HairHighlight = new CustomizeParameterValue(parameter.MeshColor).InternalTriple,
|
HairHighlight = new CustomizeParameterValue(parameter.MeshColor).InternalTriple,
|
||||||
LeftEye = new CustomizeParameterValue(parameter.LeftColor).InternalTriple,
|
LeftEye = new CustomizeParameterValue(parameter.LeftColor).InternalTriple,
|
||||||
|
LeftScleraIntensity = new CustomizeParameterValue(parameter.LeftColor.W).Single,
|
||||||
RightEye = new CustomizeParameterValue(parameter.RightColor).InternalTriple,
|
RightEye = new CustomizeParameterValue(parameter.RightColor).InternalTriple,
|
||||||
|
RightScleraIntensity = new CustomizeParameterValue(parameter.RightColor.W).Single,
|
||||||
FeatureColor = new CustomizeParameterValue(parameter.OptionColor).InternalTriple,
|
FeatureColor = new CustomizeParameterValue(parameter.OptionColor).InternalTriple,
|
||||||
DecalColor = FromParameter(decal),
|
DecalColor = FromParameter(decal),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static CustomizeParameterValue FromParameter(in CustomizeParameter parameter, CustomizeParameterFlag flag)
|
public static unsafe CustomizeParameterValue FromParameter(in CustomizeParameter parameter, CustomizeParameterFlag flag)
|
||||||
=> flag switch
|
=> flag switch
|
||||||
{
|
{
|
||||||
CustomizeParameterFlag.SkinDiffuse => new CustomizeParameterValue(parameter.SkinColor),
|
CustomizeParameterFlag.SkinDiffuse => new CustomizeParameterValue(parameter.SkinColor),
|
||||||
|
|
@ -189,8 +207,8 @@ public struct CustomizeParameterData
|
||||||
CustomizeParameterFlag.LeftEye => new CustomizeParameterValue(parameter.LeftColor),
|
CustomizeParameterFlag.LeftEye => new CustomizeParameterValue(parameter.LeftColor),
|
||||||
CustomizeParameterFlag.RightEye => new CustomizeParameterValue(parameter.RightColor),
|
CustomizeParameterFlag.RightEye => new CustomizeParameterValue(parameter.RightColor),
|
||||||
CustomizeParameterFlag.FeatureColor => new CustomizeParameterValue(parameter.OptionColor),
|
CustomizeParameterFlag.FeatureColor => new CustomizeParameterValue(parameter.OptionColor),
|
||||||
CustomizeParameterFlag.FacePaintUvMultiplier => new CustomizeParameterValue(parameter.LeftColor.W),
|
CustomizeParameterFlag.FacePaintUvMultiplier => new CustomizeParameterValue(GetUvMultiplier(parameter)),
|
||||||
CustomizeParameterFlag.FacePaintUvOffset => new CustomizeParameterValue(parameter.RightColor.W),
|
CustomizeParameterFlag.FacePaintUvOffset => new CustomizeParameterValue(GetUvOffset(parameter)),
|
||||||
_ => CustomizeParameterValue.Zero,
|
_ => CustomizeParameterValue.Zero,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -223,4 +241,41 @@ public struct CustomizeParameterData
|
||||||
val = @new;
|
val = @new;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static unsafe float GetUvOffset(in CustomizeParameter parameter)
|
||||||
|
{
|
||||||
|
// TODO CS Update
|
||||||
|
fixed (CustomizeParameter* ptr = ¶meter)
|
||||||
|
{
|
||||||
|
return ((float*)ptr)[23];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static unsafe ref float GetUvOffsetWrite(ref CustomizeParameter parameter)
|
||||||
|
{
|
||||||
|
// TODO CS Update
|
||||||
|
fixed (CustomizeParameter* ptr = ¶meter)
|
||||||
|
{
|
||||||
|
return ref ((float*)ptr)[23];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static unsafe float GetUvMultiplier(in CustomizeParameter parameter)
|
||||||
|
{
|
||||||
|
// TODO CS Update
|
||||||
|
fixed (CustomizeParameter* ptr = ¶meter)
|
||||||
|
{
|
||||||
|
return ((float*)ptr)[15];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static unsafe ref float GetUvMultiplierWrite(ref CustomizeParameter parameter)
|
||||||
|
{
|
||||||
|
// TODO CS Update
|
||||||
|
fixed (CustomizeParameter* ptr = ¶meter)
|
||||||
|
{
|
||||||
|
return ref ((float*)ptr)[15];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,17 +16,24 @@ public enum CustomizeParameterFlag : ushort
|
||||||
FacePaintUvMultiplier = 0x0400,
|
FacePaintUvMultiplier = 0x0400,
|
||||||
FacePaintUvOffset = 0x0800,
|
FacePaintUvOffset = 0x0800,
|
||||||
DecalColor = 0x1000,
|
DecalColor = 0x1000,
|
||||||
|
LeftScleraIntensity = 0x2000,
|
||||||
|
RightScleraIntensity = 0x4000,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CustomizeParameterExtensions
|
public static class CustomizeParameterExtensions
|
||||||
{
|
{
|
||||||
public const CustomizeParameterFlag All = (CustomizeParameterFlag)0x1FFF;
|
// Speculars are not available anymore.
|
||||||
|
public const CustomizeParameterFlag All = (CustomizeParameterFlag)0x1FDB;
|
||||||
|
|
||||||
public const CustomizeParameterFlag RgbTriples = All
|
public const CustomizeParameterFlag RgbTriples = All
|
||||||
& ~(RgbaQuadruples | Percentages | Values);
|
& ~(RgbaQuadruples | Percentages | Values);
|
||||||
|
|
||||||
public const CustomizeParameterFlag RgbaQuadruples = CustomizeParameterFlag.DecalColor | CustomizeParameterFlag.LipDiffuse;
|
public const CustomizeParameterFlag RgbaQuadruples = CustomizeParameterFlag.DecalColor | CustomizeParameterFlag.LipDiffuse;
|
||||||
public const CustomizeParameterFlag Percentages = CustomizeParameterFlag.MuscleTone;
|
|
||||||
|
public const CustomizeParameterFlag Percentages = CustomizeParameterFlag.MuscleTone
|
||||||
|
| CustomizeParameterFlag.LeftScleraIntensity
|
||||||
|
| CustomizeParameterFlag.RightScleraIntensity;
|
||||||
|
|
||||||
public const CustomizeParameterFlag Values = CustomizeParameterFlag.FacePaintUvOffset | CustomizeParameterFlag.FacePaintUvMultiplier;
|
public const CustomizeParameterFlag Values = CustomizeParameterFlag.FacePaintUvOffset | CustomizeParameterFlag.FacePaintUvMultiplier;
|
||||||
|
|
||||||
public static readonly IReadOnlyList<CustomizeParameterFlag> AllFlags = [.. Enum.GetValues<CustomizeParameterFlag>()];
|
public static readonly IReadOnlyList<CustomizeParameterFlag> AllFlags = [.. Enum.GetValues<CustomizeParameterFlag>()];
|
||||||
|
|
@ -60,6 +67,8 @@ public static class CustomizeParameterExtensions
|
||||||
CustomizeParameterFlag.FacePaintUvMultiplier => "Multiplier for Face Paint",
|
CustomizeParameterFlag.FacePaintUvMultiplier => "Multiplier for Face Paint",
|
||||||
CustomizeParameterFlag.FacePaintUvOffset => "Offset of Face Paint",
|
CustomizeParameterFlag.FacePaintUvOffset => "Offset of Face Paint",
|
||||||
CustomizeParameterFlag.DecalColor => "Face Paint Color",
|
CustomizeParameterFlag.DecalColor => "Face Paint Color",
|
||||||
|
CustomizeParameterFlag.LeftScleraIntensity => "Left Sclera Intensity",
|
||||||
|
CustomizeParameterFlag.RightScleraIntensity => "Right Sclera Intensity",
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -158,22 +158,22 @@ public class EquipmentDrawer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DrawAllStain(out StainId ret, bool locked)
|
public bool DrawAllStain(out StainIds ret, bool locked)
|
||||||
{
|
{
|
||||||
using var disabled = ImRaii.Disabled(locked);
|
using var disabled = ImRaii.Disabled(locked);
|
||||||
var change = _stainCombo.Draw("Dye All Slots", Stain.None.RgbaColor, string.Empty, false, false, MouseWheelType.None);
|
var change = _stainCombo.Draw("Dye All Slots", Stain.None.RgbaColor, string.Empty, false, false, MouseWheelType.None);
|
||||||
ret = Stain.None.RowIndex;
|
ret = StainIds.None;
|
||||||
if (change)
|
if (change)
|
||||||
if (_stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out var stain))
|
if (_stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out var stain))
|
||||||
ret = stain.RowIndex;
|
ret = StainIds.All(stain.RowIndex);
|
||||||
else if (_stainCombo.CurrentSelection.Key == Stain.None.RowIndex)
|
else if (_stainCombo.CurrentSelection.Key == Stain.None.RowIndex)
|
||||||
ret = Stain.None.RowIndex;
|
ret = StainIds.None;
|
||||||
|
|
||||||
if (!locked)
|
if (!locked)
|
||||||
{
|
{
|
||||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right) && _config.DeleteDesignModifier.IsActive())
|
if (ImGui.IsItemClicked(ImGuiMouseButton.Right) && _config.DeleteDesignModifier.IsActive())
|
||||||
{
|
{
|
||||||
ret = Stain.None.RowIndex;
|
ret = StainIds.None;
|
||||||
change = true;
|
change = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -420,7 +420,7 @@ public class EquipmentDrawer
|
||||||
|
|
||||||
private void DrawBonusItemNormal(in BonusDrawData bonusDrawData)
|
private void DrawBonusItemNormal(in BonusDrawData bonusDrawData)
|
||||||
{
|
{
|
||||||
ImGui.Dummy(_iconSize with { Y = ImUtf8.FrameHeight });
|
bonusDrawData.CurrentItem.DrawIcon(_textures, _iconSize, bonusDrawData.Slot);
|
||||||
var right = ImGui.IsItemClicked(ImGuiMouseButton.Right);
|
var right = ImGui.IsItemClicked(ImGuiMouseButton.Right);
|
||||||
var left = ImGui.IsItemClicked(ImGuiMouseButton.Left);
|
var left = ImGui.IsItemClicked(ImGuiMouseButton.Left);
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@ public sealed unsafe class AdvancedDyePopup(
|
||||||
|
|
||||||
private void DrawButton(MaterialValueIndex index)
|
private void DrawButton(MaterialValueIndex index)
|
||||||
{
|
{
|
||||||
|
// TODO fix when working
|
||||||
|
return;
|
||||||
if (!config.UseAdvancedDyes)
|
if (!config.UseAdvancedDyes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -193,11 +195,11 @@ public sealed unsafe class AdvancedDyePopup(
|
||||||
DrawWindow(textures);
|
DrawWindow(textures);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawTable(MaterialValueIndex materialIndex, in LegacyColorTable table)
|
private void DrawTable(MaterialValueIndex materialIndex, in ColorTable table)
|
||||||
{
|
{
|
||||||
using var disabled = ImRaii.Disabled(_state.IsLocked);
|
using var disabled = ImRaii.Disabled(_state.IsLocked);
|
||||||
_anyChanged = false;
|
_anyChanged = false;
|
||||||
for (byte i = 0; i < LegacyColorTable.NumUsedRows; ++i)
|
for (byte i = 0; i < ColorTable.NumUsedRows; ++i)
|
||||||
{
|
{
|
||||||
var index = materialIndex with { RowIndex = i };
|
var index = materialIndex with { RowIndex = i };
|
||||||
ref var row = ref table[i];
|
ref var row = ref table[i];
|
||||||
|
|
@ -208,7 +210,7 @@ public sealed unsafe class AdvancedDyePopup(
|
||||||
DrawAllRow(materialIndex, table);
|
DrawAllRow(materialIndex, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawAllRow(MaterialValueIndex materialIndex, in LegacyColorTable table)
|
private void DrawAllRow(MaterialValueIndex materialIndex, in ColorTable table)
|
||||||
{
|
{
|
||||||
using var id = ImRaii.PushId(100);
|
using var id = ImRaii.PushId(100);
|
||||||
var buttonSize = new Vector2(ImGui.GetFrameHeight());
|
var buttonSize = new Vector2(ImGui.GetFrameHeight());
|
||||||
|
|
@ -245,11 +247,11 @@ public sealed unsafe class AdvancedDyePopup(
|
||||||
ImGui.SameLine(0, spacing);
|
ImGui.SameLine(0, spacing);
|
||||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.UndoAlt.ToIconString(), buttonSize, "Reset this table to game state.", !_anyChanged,
|
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.UndoAlt.ToIconString(), buttonSize, "Reset this table to game state.", !_anyChanged,
|
||||||
true))
|
true))
|
||||||
for (byte i = 0; i < LegacyColorTable.NumUsedRows; ++i)
|
for (byte i = 0; i < ColorTable.NumUsedRows; ++i)
|
||||||
stateManager.ResetMaterialValue(_state, materialIndex with { RowIndex = i }, ApplySettings.Game);
|
stateManager.ResetMaterialValue(_state, materialIndex with { RowIndex = i }, ApplySettings.Game);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawRow(ref LegacyColorTable.Row row, MaterialValueIndex index, in LegacyColorTable table)
|
private void DrawRow(ref ColorTable.Row row, MaterialValueIndex index, in ColorTable table)
|
||||||
{
|
{
|
||||||
using var id = ImRaii.PushId(index.RowIndex);
|
using var id = ImRaii.PushId(index.RowIndex);
|
||||||
var changed = _state.Materials.TryGetValue(index, out var value);
|
var changed = _state.Materials.TryGetValue(index, out var value);
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,13 @@ namespace Glamourer.Gui.Materials;
|
||||||
public static class ColorRowClipboard
|
public static class ColorRowClipboard
|
||||||
{
|
{
|
||||||
private static ColorRow _row;
|
private static ColorRow _row;
|
||||||
private static LegacyColorTable _table;
|
private static ColorTable _table;
|
||||||
|
|
||||||
public static bool IsSet { get; private set; }
|
public static bool IsSet { get; private set; }
|
||||||
|
|
||||||
public static bool IsTableSet { get; private set; }
|
public static bool IsTableSet { get; private set; }
|
||||||
|
|
||||||
public static LegacyColorTable Table
|
public static ColorTable Table
|
||||||
{
|
{
|
||||||
get => _table;
|
get => _table;
|
||||||
set
|
set
|
||||||
|
|
|
||||||
|
|
@ -175,9 +175,9 @@ public class MaterialDrawer(DesignManager _designManager, Configuration _config)
|
||||||
{
|
{
|
||||||
_newRowIdx += 1;
|
_newRowIdx += 1;
|
||||||
ImGui.SetNextItemWidth(ImGui.CalcTextSize("Row #0000").X);
|
ImGui.SetNextItemWidth(ImGui.CalcTextSize("Row #0000").X);
|
||||||
if (ImGui.DragInt("##Row", ref _newRowIdx, 0.01f, 1, LegacyColorTable.NumUsedRows, "Row #%i"))
|
if (ImGui.DragInt("##Row", ref _newRowIdx, 0.01f, 1, ColorTable.NumUsedRows, "Row #%i"))
|
||||||
{
|
{
|
||||||
_newRowIdx = Math.Clamp(_newRowIdx, 1, LegacyColorTable.NumUsedRows);
|
_newRowIdx = Math.Clamp(_newRowIdx, 1, ColorTable.NumUsedRows);
|
||||||
_newKey = _newKey with { RowIndex = (byte)(_newRowIdx - 1) };
|
_newKey = _newKey with { RowIndex = (byte)(_newRowIdx - 1) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ using OtterGui;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Gui.Debug;
|
using Penumbra.GameData.Gui.Debug;
|
||||||
|
using FFXIVClientStructs.FFXIV.Shader;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||||
|
|
||||||
|
|
@ -94,7 +95,8 @@ public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectM
|
||||||
|
|
||||||
foreach (var type in Enum.GetValues<CustomizeIndex>())
|
foreach (var type in Enum.GetValues<CustomizeIndex>())
|
||||||
{
|
{
|
||||||
PrintRow(type.ToDefaultName(), state.BaseData.Customize[type].Value, state.ModelData.Customize[type].Value, state.Sources[type]);
|
PrintRow(type.ToDefaultName(), state.BaseData.Customize[type].Value, state.ModelData.Customize[type].Value,
|
||||||
|
state.Sources[type]);
|
||||||
ImGui.TableNextRow();
|
ImGui.TableNextRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
135
Glamourer/Gui/Tabs/DebugTab/AdvancedCustomizationDrawer.cs
Normal file
135
Glamourer/Gui/Tabs/DebugTab/AdvancedCustomizationDrawer.cs
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||||
|
using Glamourer.Interop;
|
||||||
|
using ImGuiNET;
|
||||||
|
using OtterGui.Raii;
|
||||||
|
using OtterGui.Text;
|
||||||
|
using Penumbra.GameData.Gui.Debug;
|
||||||
|
|
||||||
|
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||||
|
|
||||||
|
public unsafe class AdvancedCustomizationDrawer(ObjectManager objects) : IGameDataDrawer
|
||||||
|
{
|
||||||
|
public string Label
|
||||||
|
=> "Advanced Customizations";
|
||||||
|
|
||||||
|
public bool Disabled
|
||||||
|
=> false;
|
||||||
|
|
||||||
|
public void Draw()
|
||||||
|
{
|
||||||
|
var (player, data) = objects.PlayerData;
|
||||||
|
if (!data.Valid)
|
||||||
|
{
|
||||||
|
ImUtf8.Text("Invalid player."u8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var model = data.Objects[0].Model;
|
||||||
|
if (!model.IsHuman)
|
||||||
|
{
|
||||||
|
ImUtf8.Text("Invalid model."u8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawCBuffer("Customize"u8, model.AsHuman->CustomizeParameterCBuffer, 0);
|
||||||
|
DrawCBuffer("Decal"u8, model.AsHuman->DecalColorCBuffer, 1);
|
||||||
|
DrawCBuffer("Unk1"u8, *(ConstantBuffer**)((byte*)model.AsHuman + 0xBA0), 2);
|
||||||
|
DrawCBuffer("Unk2"u8, *(ConstantBuffer**)((byte*)model.AsHuman + 0xBA8), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void DrawCBuffer(ReadOnlySpan<byte> label, ConstantBuffer* cBuffer, int type)
|
||||||
|
{
|
||||||
|
using var tree = ImUtf8.TreeNode(label);
|
||||||
|
if (!tree)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (cBuffer == null)
|
||||||
|
{
|
||||||
|
ImUtf8.Text("Invalid CBuffer."u8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImUtf8.Text($"{cBuffer->ByteSize / 4}");
|
||||||
|
ImUtf8.Text($"{cBuffer->Flags}");
|
||||||
|
ImUtf8.Text($"0x{(ulong)cBuffer:X}");
|
||||||
|
var parameters = (float*)cBuffer->UnsafeSourcePointer;
|
||||||
|
if (parameters == null)
|
||||||
|
{
|
||||||
|
ImUtf8.Text("No Parameters."u8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var start = parameters;
|
||||||
|
using (ImUtf8.Group())
|
||||||
|
{
|
||||||
|
for (var end = start + cBuffer->ByteSize / 4; parameters < end; parameters += 2)
|
||||||
|
DrawParameters(parameters, type, (int)(parameters - start));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine(0, 50 * ImUtf8.GlobalScale);
|
||||||
|
parameters = start + 1;
|
||||||
|
using (ImUtf8.Group())
|
||||||
|
{
|
||||||
|
for (var end = start + cBuffer->ByteSize / 4; parameters < end; parameters += 2)
|
||||||
|
DrawParameters(parameters, type, (int)(parameters - start));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DrawParameters(float* param, int type, int idx)
|
||||||
|
{
|
||||||
|
using var id = ImUtf8.PushId((nint)param);
|
||||||
|
ImUtf8.TextFrameAligned($"{idx:D2}: ");
|
||||||
|
ImUtf8.SameLineInner();
|
||||||
|
ImGui.SetNextItemWidth(200 * ImUtf8.GlobalScale);
|
||||||
|
if (TryGetKnown(type, idx, out var known))
|
||||||
|
{
|
||||||
|
ImUtf8.DragScalar(known, ref *param, float.MinValue, float.MaxValue, 0.01f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled));
|
||||||
|
ImUtf8.DragScalar($"+0x{idx * 4:X2}", ref *param, float.MinValue, float.MaxValue, 0.01f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetKnown(int type, int idx, out ReadOnlySpan<byte> text)
|
||||||
|
{
|
||||||
|
if (type == 0)
|
||||||
|
text = idx switch
|
||||||
|
{
|
||||||
|
0 => "Diffuse.R"u8,
|
||||||
|
1 => "Diffuse.G"u8,
|
||||||
|
2 => "Diffuse.B"u8,
|
||||||
|
3 => "Muscle Tone"u8,
|
||||||
|
8 => "Lipstick.R"u8,
|
||||||
|
9 => "Lipstick.G"u8,
|
||||||
|
10 => "Lipstick.B"u8,
|
||||||
|
11 => "Lipstick.Opacity"u8,
|
||||||
|
12 => "Hair.R"u8,
|
||||||
|
13 => "Hair.G"u8,
|
||||||
|
14 => "Hair.B"u8,
|
||||||
|
15 => "Facepaint.Offset"u8,
|
||||||
|
20 => "Highlight.R"u8,
|
||||||
|
21 => "Highlight.G"u8,
|
||||||
|
22 => "Highlight.B"u8,
|
||||||
|
23 => "Facepaint.Multiplier"u8,
|
||||||
|
24 => "LeftEye.R"u8,
|
||||||
|
25 => "LeftEye.G"u8,
|
||||||
|
26 => "LeftEye.B"u8,
|
||||||
|
27 => "LeftSclera"u8,
|
||||||
|
28 => "RightEye.R"u8,
|
||||||
|
29 => "RightEye.G"u8,
|
||||||
|
30 => "RightEye.B"u8,
|
||||||
|
31 => "RightSclera"u8,
|
||||||
|
32 => "Feature.R"u8,
|
||||||
|
33 => "Feature.G"u8,
|
||||||
|
34 => "Feature.B"u8,
|
||||||
|
_ => [],
|
||||||
|
};
|
||||||
|
else
|
||||||
|
text = [];
|
||||||
|
|
||||||
|
return text.Length > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -38,7 +38,8 @@ public class DebugTabHeader(string label, params IGameDataDrawer[] subTrees)
|
||||||
provider.GetRequiredService<PenumbraPanel>(),
|
provider.GetRequiredService<PenumbraPanel>(),
|
||||||
provider.GetRequiredService<IpcTesterPanel>(),
|
provider.GetRequiredService<IpcTesterPanel>(),
|
||||||
provider.GetRequiredService<DatFilePanel>(),
|
provider.GetRequiredService<DatFilePanel>(),
|
||||||
provider.GetRequiredService<GlamourPlatePanel>()
|
provider.GetRequiredService<GlamourPlatePanel>(),
|
||||||
|
provider.GetRequiredService<AdvancedCustomizationDrawer>()
|
||||||
);
|
);
|
||||||
|
|
||||||
public static DebugTabHeader CreateGameData(IServiceProvider provider)
|
public static DebugTabHeader CreateGameData(IServiceProvider provider)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
|
using Glamourer.Designs;
|
||||||
using Glamourer.GameData;
|
using Glamourer.GameData;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
|
|
@ -12,23 +13,23 @@ using ImGuiClip = OtterGui.ImGuiClip;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.UnlocksTab;
|
namespace Glamourer.Gui.Tabs.UnlocksTab;
|
||||||
|
|
||||||
public class UnlockOverview
|
public class UnlockOverview(
|
||||||
|
ItemManager items,
|
||||||
|
CustomizeService customizations,
|
||||||
|
ItemUnlockManager itemUnlocks,
|
||||||
|
CustomizeUnlockManager customizeUnlocks,
|
||||||
|
PenumbraChangedItemTooltip tooltip,
|
||||||
|
TextureService textures,
|
||||||
|
CodeService codes,
|
||||||
|
JobService jobs,
|
||||||
|
FavoriteManager favorites)
|
||||||
{
|
{
|
||||||
private readonly ItemManager _items;
|
|
||||||
private readonly ItemUnlockManager _itemUnlocks;
|
|
||||||
private readonly CustomizeService _customizations;
|
|
||||||
private readonly CustomizeUnlockManager _customizeUnlocks;
|
|
||||||
private readonly PenumbraChangedItemTooltip _tooltip;
|
|
||||||
private readonly TextureService _textures;
|
|
||||||
private readonly CodeService _codes;
|
|
||||||
private readonly JobService _jobs;
|
|
||||||
private readonly FavoriteManager _favorites;
|
|
||||||
|
|
||||||
private static readonly Vector4 UnavailableTint = new(0.3f, 0.3f, 0.3f, 1.0f);
|
private static readonly Vector4 UnavailableTint = new(0.3f, 0.3f, 0.3f, 1.0f);
|
||||||
|
|
||||||
private FullEquipType _selected1 = FullEquipType.Unknown;
|
private FullEquipType _selected1 = FullEquipType.Unknown;
|
||||||
private SubRace _selected2 = SubRace.Unknown;
|
private SubRace _selected2 = SubRace.Unknown;
|
||||||
private Gender _selected3 = Gender.Unknown;
|
private Gender _selected3 = Gender.Unknown;
|
||||||
|
private BonusItemFlag _selected4 = BonusItemFlag.Unknown;
|
||||||
|
|
||||||
private void DrawSelector()
|
private void DrawSelector()
|
||||||
{
|
{
|
||||||
|
|
@ -38,7 +39,7 @@ public class UnlockOverview
|
||||||
|
|
||||||
foreach (var type in Enum.GetValues<FullEquipType>())
|
foreach (var type in Enum.GetValues<FullEquipType>())
|
||||||
{
|
{
|
||||||
if (type.IsOffhandType() || !_items.ItemData.ByType.TryGetValue(type, out var items) || items.Count == 0)
|
if (type.IsOffhandType() || !items.ItemData.ByType.TryGetValue(type, out var value) || value.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ImGui.Selectable(type.ToName(), _selected1 == type))
|
if (ImGui.Selectable(type.ToName(), _selected1 == type))
|
||||||
|
|
@ -46,12 +47,21 @@ public class UnlockOverview
|
||||||
_selected1 = type;
|
_selected1 = type;
|
||||||
_selected2 = SubRace.Unknown;
|
_selected2 = SubRace.Unknown;
|
||||||
_selected3 = Gender.Unknown;
|
_selected3 = Gender.Unknown;
|
||||||
|
_selected4 = BonusItemFlag.Unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGui.Selectable("Bonus Items", _selected4 == BonusItemFlag.Glasses))
|
||||||
|
{
|
||||||
|
_selected1 = FullEquipType.Unknown;
|
||||||
|
_selected2 = SubRace.Unknown;
|
||||||
|
_selected3 = Gender.Unknown;
|
||||||
|
_selected4 = BonusItemFlag.Glasses;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var (clan, gender) in CustomizeManager.AllSets())
|
foreach (var (clan, gender) in CustomizeManager.AllSets())
|
||||||
{
|
{
|
||||||
if (_customizations.Manager.GetSet(clan, gender).HairStyles.Count == 0)
|
if (customizations.Manager.GetSet(clan, gender).HairStyles.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ImGui.Selectable($"{(gender is Gender.Male ? '♂' : '♀')} {clan.ToShortName()} Hair & Paint",
|
if (ImGui.Selectable($"{(gender is Gender.Male ? '♂' : '♀')} {clan.ToShortName()} Hair & Paint",
|
||||||
|
|
@ -60,25 +70,11 @@ public class UnlockOverview
|
||||||
_selected1 = FullEquipType.Unknown;
|
_selected1 = FullEquipType.Unknown;
|
||||||
_selected2 = clan;
|
_selected2 = clan;
|
||||||
_selected3 = gender;
|
_selected3 = gender;
|
||||||
|
_selected4 = BonusItemFlag.Unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnlockOverview(ItemManager items, CustomizeService customizations, ItemUnlockManager itemUnlocks,
|
|
||||||
CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip, TextureService textures, CodeService codes,
|
|
||||||
JobService jobs, FavoriteManager favorites)
|
|
||||||
{
|
|
||||||
_items = items;
|
|
||||||
_customizations = customizations;
|
|
||||||
_itemUnlocks = itemUnlocks;
|
|
||||||
_customizeUnlocks = customizeUnlocks;
|
|
||||||
_tooltip = tooltip;
|
|
||||||
_textures = textures;
|
|
||||||
_codes = codes;
|
|
||||||
_jobs = jobs;
|
|
||||||
_favorites = favorites;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Draw()
|
public void Draw()
|
||||||
{
|
{
|
||||||
using var color = ImRaii.PushColor(ImGuiCol.Border, ImGui.GetColorU32(ImGuiCol.TableBorderStrong));
|
using var color = ImRaii.PushColor(ImGuiCol.Border, ImGui.GetColorU32(ImGuiCol.TableBorderStrong));
|
||||||
|
|
@ -97,11 +93,13 @@ public class UnlockOverview
|
||||||
DrawItems();
|
DrawItems();
|
||||||
else if (_selected2 is not SubRace.Unknown && _selected3 is not Gender.Unknown)
|
else if (_selected2 is not SubRace.Unknown && _selected3 is not Gender.Unknown)
|
||||||
DrawCustomizations();
|
DrawCustomizations();
|
||||||
|
else if (_selected4 is not BonusItemFlag.Unknown)
|
||||||
|
DrawBonusItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCustomizations()
|
private void DrawCustomizations()
|
||||||
{
|
{
|
||||||
var set = _customizations.Manager.GetSet(_selected2, _selected3);
|
var set = customizations.Manager.GetSet(_selected2, _selected3);
|
||||||
|
|
||||||
var spacing = IconSpacing;
|
var spacing = IconSpacing;
|
||||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
|
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
|
||||||
|
|
@ -111,16 +109,16 @@ public class UnlockOverview
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
foreach (var customize in set.HairStyles.Concat(set.FacePaints))
|
foreach (var customize in set.HairStyles.Concat(set.FacePaints))
|
||||||
{
|
{
|
||||||
if (!_customizeUnlocks.Unlockable.TryGetValue(customize, out var unlockData))
|
if (!customizeUnlocks.Unlockable.TryGetValue(customize, out var unlockData))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var unlocked = _customizeUnlocks.IsUnlocked(customize, out var time);
|
var unlocked = customizeUnlocks.IsUnlocked(customize, out var time);
|
||||||
var icon = _customizations.Manager.GetIcon(customize.IconId);
|
var icon = customizations.Manager.GetIcon(customize.IconId);
|
||||||
var hasIcon = icon.TryGetWrap(out var wrap, out _);
|
var hasIcon = icon.TryGetWrap(out var wrap, out _);
|
||||||
ImGui.Image(wrap?.ImGuiHandle ?? icon.GetWrapOrEmpty().ImGuiHandle, iconSize, Vector2.Zero, Vector2.One,
|
ImGui.Image(wrap?.ImGuiHandle ?? icon.GetWrapOrEmpty().ImGuiHandle, iconSize, Vector2.Zero, Vector2.One,
|
||||||
unlocked || _codes.Enabled(CodeService.CodeFlag.Shirts) ? Vector4.One : UnavailableTint);
|
unlocked || codes.Enabled(CodeService.CodeFlag.Shirts) ? Vector4.One : UnavailableTint);
|
||||||
|
|
||||||
if (_favorites.Contains(_selected3, _selected2, customize.Index, customize.Value))
|
if (favorites.Contains(_selected3, _selected2, customize.Index, customize.Value))
|
||||||
ImGui.GetWindowDrawList().AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), ColorId.FavoriteStarOn.Value(),
|
ImGui.GetWindowDrawList().AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), ColorId.FavoriteStarOn.Value(),
|
||||||
12 * ImGuiHelpers.GlobalScale, ImDrawFlags.RoundCornersAll, 6 * ImGuiHelpers.GlobalScale);
|
12 * ImGuiHelpers.GlobalScale, ImDrawFlags.RoundCornersAll, 6 * ImGuiHelpers.GlobalScale);
|
||||||
|
|
||||||
|
|
@ -147,24 +145,90 @@ public class UnlockOverview
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawBonusItems()
|
||||||
|
{
|
||||||
|
var spacing = IconSpacing;
|
||||||
|
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
|
||||||
|
var iconSize = ImGuiHelpers.ScaledVector2(64);
|
||||||
|
var iconsPerRow = IconsPerRow(iconSize.X, spacing.X);
|
||||||
|
var numRows = (items.DictBonusItems.Count + iconsPerRow - 1) / iconsPerRow;
|
||||||
|
var numVisibleRows = (int)(Math.Ceiling(ImGui.GetContentRegionAvail().Y / (iconSize.Y + spacing.Y)) + 0.5f) + 1;
|
||||||
|
|
||||||
|
var skips = ImGuiClip.GetNecessarySkips(iconSize.Y + spacing.Y);
|
||||||
|
var start = skips * iconsPerRow;
|
||||||
|
var end = Math.Min(numVisibleRows * iconsPerRow + skips * iconsPerRow, items.DictBonusItems.Count);
|
||||||
|
var counter = 0;
|
||||||
|
|
||||||
|
foreach (var item in items.DictBonusItems.Values.Skip(start).Take(end - start))
|
||||||
|
{
|
||||||
|
DrawItem(item);
|
||||||
|
if (counter != iconsPerRow - 1)
|
||||||
|
{
|
||||||
|
ImGui.SameLine();
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
counter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.GetCursorPosX() != 0)
|
||||||
|
ImGui.NewLine();
|
||||||
|
var remainder = numRows - numVisibleRows - skips;
|
||||||
|
if (remainder > 0)
|
||||||
|
ImGuiClip.DrawEndDummy(remainder, iconSize.Y + spacing.Y);
|
||||||
|
|
||||||
|
void DrawItem(BonusItem item)
|
||||||
|
{
|
||||||
|
// TODO check unlocks
|
||||||
|
var unlocked = true;
|
||||||
|
if (!textures.TryLoadIcon(item.Icon.Id, out var iconHandle))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var (icon, size) = (iconHandle.ImGuiHandle, new Vector2(iconHandle.Width, iconHandle.Height));
|
||||||
|
|
||||||
|
ImGui.Image(icon, iconSize, Vector2.Zero, Vector2.One,
|
||||||
|
unlocked || codes.Enabled(CodeService.CodeFlag.Shirts) ? Vector4.One : UnavailableTint);
|
||||||
|
if (favorites.Contains(item))
|
||||||
|
ImGui.GetWindowDrawList().AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), ColorId.FavoriteStarOn.Value(),
|
||||||
|
2 * ImGuiHelpers.GlobalScale, ImDrawFlags.RoundCornersAll, 4 * ImGuiHelpers.GlobalScale);
|
||||||
|
|
||||||
|
// TODO handle clicking
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
{
|
||||||
|
using var tt = ImRaii.Tooltip();
|
||||||
|
if (size.X >= iconSize.X && size.Y >= iconSize.Y)
|
||||||
|
ImGui.Image(icon, size);
|
||||||
|
ImGui.TextUnformatted(item.Name);
|
||||||
|
ImGui.TextUnformatted($"{item.Slot.ToName()}");
|
||||||
|
ImGui.TextUnformatted($"{item.ModelId.Id}-{item.Variant.Id}");
|
||||||
|
// TODO
|
||||||
|
ImGui.TextUnformatted("Always Unlocked"); // : $"Unlocked on {time:g}" : "Not Unlocked.");
|
||||||
|
// TODO
|
||||||
|
//tooltip.CreateTooltip(item, string.Empty, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawItems()
|
private void DrawItems()
|
||||||
{
|
{
|
||||||
if (!_items.ItemData.ByType.TryGetValue(_selected1, out var items))
|
if (!items.ItemData.ByType.TryGetValue(_selected1, out var value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var spacing = IconSpacing;
|
var spacing = IconSpacing;
|
||||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
|
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
|
||||||
var iconSize = ImGuiHelpers.ScaledVector2(64);
|
var iconSize = ImGuiHelpers.ScaledVector2(64);
|
||||||
var iconsPerRow = IconsPerRow(iconSize.X, spacing.X);
|
var iconsPerRow = IconsPerRow(iconSize.X, spacing.X);
|
||||||
var numRows = (items.Count + iconsPerRow - 1) / iconsPerRow;
|
var numRows = (value.Count + iconsPerRow - 1) / iconsPerRow;
|
||||||
var numVisibleRows = (int)(Math.Ceiling(ImGui.GetContentRegionAvail().Y / (iconSize.Y + spacing.Y)) + 0.5f) + 1;
|
var numVisibleRows = (int)(Math.Ceiling(ImGui.GetContentRegionAvail().Y / (iconSize.Y + spacing.Y)) + 0.5f) + 1;
|
||||||
|
|
||||||
var skips = ImGuiClip.GetNecessarySkips(iconSize.Y + spacing.Y);
|
var skips = ImGuiClip.GetNecessarySkips(iconSize.Y + spacing.Y);
|
||||||
var end = Math.Min(numVisibleRows * iconsPerRow + skips * iconsPerRow, items.Count);
|
var end = Math.Min(numVisibleRows * iconsPerRow + skips * iconsPerRow, value.Count);
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
for (var idx = skips * iconsPerRow; idx < end; ++idx)
|
for (var idx = skips * iconsPerRow; idx < end; ++idx)
|
||||||
{
|
{
|
||||||
DrawItem(items[idx]);
|
DrawItem(value[idx]);
|
||||||
if (counter != iconsPerRow - 1)
|
if (counter != iconsPerRow - 1)
|
||||||
{
|
{
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
|
@ -185,23 +249,23 @@ public class UnlockOverview
|
||||||
|
|
||||||
void DrawItem(EquipItem item)
|
void DrawItem(EquipItem item)
|
||||||
{
|
{
|
||||||
var unlocked = _itemUnlocks.IsUnlocked(item.Id, out var time);
|
var unlocked = itemUnlocks.IsUnlocked(item.Id, out var time);
|
||||||
if (!_textures.TryLoadIcon(item.IconId.Id, out var iconHandle))
|
if (!textures.TryLoadIcon(item.IconId.Id, out var iconHandle))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var (icon, size) = (iconHandle.ImGuiHandle, new Vector2(iconHandle.Width, iconHandle.Height));
|
var (icon, size) = (iconHandle.ImGuiHandle, new Vector2(iconHandle.Width, iconHandle.Height));
|
||||||
|
|
||||||
ImGui.Image(icon, iconSize, Vector2.Zero, Vector2.One,
|
ImGui.Image(icon, iconSize, Vector2.Zero, Vector2.One,
|
||||||
unlocked || _codes.Enabled(CodeService.CodeFlag.Shirts) ? Vector4.One : UnavailableTint);
|
unlocked || codes.Enabled(CodeService.CodeFlag.Shirts) ? Vector4.One : UnavailableTint);
|
||||||
if (_favorites.Contains(item))
|
if (favorites.Contains(item))
|
||||||
ImGui.GetWindowDrawList().AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), ColorId.FavoriteStarOn.Value(),
|
ImGui.GetWindowDrawList().AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), ColorId.FavoriteStarOn.Value(),
|
||||||
2 * ImGuiHelpers.GlobalScale, ImDrawFlags.RoundCornersAll, 4 * ImGuiHelpers.GlobalScale);
|
2 * ImGuiHelpers.GlobalScale, ImDrawFlags.RoundCornersAll, 4 * ImGuiHelpers.GlobalScale);
|
||||||
|
|
||||||
if (ImGui.IsItemClicked())
|
if (ImGui.IsItemClicked())
|
||||||
Glamourer.Messager.Chat.Print(new SeStringBuilder().AddItemLink(item.ItemId.Id, false).BuiltString);
|
Glamourer.Messager.Chat.Print(new SeStringBuilder().AddItemLink(item.ItemId.Id, false).BuiltString);
|
||||||
|
|
||||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right) && _tooltip.Player(out var state))
|
if (ImGui.IsItemClicked(ImGuiMouseButton.Right) && tooltip.Player(out var state))
|
||||||
_tooltip.ApplyItem(state, item);
|
tooltip.ApplyItem(state, item);
|
||||||
|
|
||||||
if (ImGui.IsItemHovered())
|
if (ImGui.IsItemHovered())
|
||||||
{
|
{
|
||||||
|
|
@ -213,7 +277,7 @@ public class UnlockOverview
|
||||||
ImGui.TextUnformatted($"{item.Type.ToName()} ({slot.ToName()})");
|
ImGui.TextUnformatted($"{item.Type.ToName()} ({slot.ToName()})");
|
||||||
if (item.Type.ValidOffhand().IsOffhandType())
|
if (item.Type.ValidOffhand().IsOffhandType())
|
||||||
ImGui.TextUnformatted(
|
ImGui.TextUnformatted(
|
||||||
$"{item.Weapon()}{(_items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand) ? $" | {offhand.Weapon()}" : string.Empty)}");
|
$"{item.Weapon()}{(items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand) ? $" | {offhand.Weapon()}" : string.Empty)}");
|
||||||
else
|
else
|
||||||
ImGui.TextUnformatted(slot is EquipSlot.MainHand ? $"{item.Weapon()}" : $"{item.Armor()}");
|
ImGui.TextUnformatted(slot is EquipSlot.MainHand ? $"{item.Weapon()}" : $"{item.Armor()}");
|
||||||
ImGui.TextUnformatted(
|
ImGui.TextUnformatted(
|
||||||
|
|
@ -221,17 +285,17 @@ public class UnlockOverview
|
||||||
|
|
||||||
if (item.Level.Value <= 1)
|
if (item.Level.Value <= 1)
|
||||||
{
|
{
|
||||||
if (item.JobRestrictions.Id <= 1 || item.JobRestrictions.Id >= _jobs.AllJobGroups.Count)
|
if (item.JobRestrictions.Id <= 1 || item.JobRestrictions.Id >= jobs.AllJobGroups.Count)
|
||||||
ImGui.TextUnformatted("For Everyone");
|
ImGui.TextUnformatted("For Everyone");
|
||||||
else
|
else
|
||||||
ImGui.TextUnformatted($"For all {_jobs.AllJobGroups[item.JobRestrictions.Id].Name}");
|
ImGui.TextUnformatted($"For all {jobs.AllJobGroups[item.JobRestrictions.Id].Name}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (item.JobRestrictions.Id <= 1 || item.JobRestrictions.Id >= _jobs.AllJobGroups.Count)
|
if (item.JobRestrictions.Id <= 1 || item.JobRestrictions.Id >= jobs.AllJobGroups.Count)
|
||||||
ImGui.TextUnformatted($"For Everyone of at least Level {item.Level}");
|
ImGui.TextUnformatted($"For Everyone of at least Level {item.Level}");
|
||||||
else
|
else
|
||||||
ImGui.TextUnformatted($"For all {_jobs.AllJobGroups[item.JobRestrictions.Id].Name} of at least Level {item.Level}");
|
ImGui.TextUnformatted($"For all {jobs.AllJobGroups[item.JobRestrictions.Id].Name} of at least Level {item.Level}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.Flags.HasFlag(ItemFlags.IsDyable1))
|
if (item.Flags.HasFlag(ItemFlags.IsDyable1))
|
||||||
|
|
@ -240,7 +304,7 @@ public class UnlockOverview
|
||||||
ImGui.TextUnformatted("Tradable");
|
ImGui.TextUnformatted("Tradable");
|
||||||
if (item.Flags.HasFlag(ItemFlags.IsCrestWorthy))
|
if (item.Flags.HasFlag(ItemFlags.IsCrestWorthy))
|
||||||
ImGui.TextUnformatted("Can apply Crest");
|
ImGui.TextUnformatted("Can apply Crest");
|
||||||
_tooltip.CreateTooltip(item, string.Empty, false);
|
tooltip.CreateTooltip(item, string.Empty, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,30 @@ public static class UiHelpers
|
||||||
if (empty)
|
if (empty)
|
||||||
{
|
{
|
||||||
var (bgColor, tint) = isEmpty
|
var (bgColor, tint) = isEmpty
|
||||||
? (ImGui.GetColorU32(ImGuiCol.FrameBg), new Vector4(0.1f, 0.1f, 0.1f, 0.5f))
|
? (ImGui.GetColorU32(ImGuiCol.FrameBg), Vector4.One)
|
||||||
: (ImGui.GetColorU32(ImGuiCol.FrameBgActive), new Vector4(0.3f, 0.3f, 0.3f, 0.8f));
|
: (ImGui.GetColorU32(ImGuiCol.FrameBgActive), new Vector4(0.3f, 0.3f, 0.3f, 1f));
|
||||||
|
var pos = ImGui.GetCursorScreenPos();
|
||||||
|
ImGui.GetWindowDrawList().AddRectFilled(pos, pos + size, bgColor, 5 * ImGuiHelpers.GlobalScale);
|
||||||
|
if (ptr != nint.Zero)
|
||||||
|
ImGui.Image(ptr, size, Vector2.Zero, Vector2.One, tint);
|
||||||
|
else
|
||||||
|
ImGui.Dummy(size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGuiUtil.HoverIcon(ptr, textureSize, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawIcon(this BonusItem item, TextureService textures, Vector2 size, BonusItemFlag slot)
|
||||||
|
{
|
||||||
|
var isEmpty = item.ModelId.Id == 0;
|
||||||
|
var (ptr, textureSize, empty) = textures.GetIcon(item, slot);
|
||||||
|
if (empty)
|
||||||
|
{
|
||||||
|
var (bgColor, tint) = isEmpty
|
||||||
|
? (ImGui.GetColorU32(ImGuiCol.FrameBg), Vector4.One)
|
||||||
|
: (ImGui.GetColorU32(ImGuiCol.FrameBgActive), new Vector4(0.3f, 0.3f, 0.3f, 1f));
|
||||||
var pos = ImGui.GetCursorScreenPos();
|
var pos = ImGui.GetCursorScreenPos();
|
||||||
ImGui.GetWindowDrawList().AddRectFilled(pos, pos + size, bgColor, 5 * ImGuiHelpers.GlobalScale);
|
ImGui.GetWindowDrawList().AddRectFilled(pos, pos + size, bgColor, 5 * ImGuiHelpers.GlobalScale);
|
||||||
if (ptr != nint.Zero)
|
if (ptr != nint.Zero)
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,13 @@ namespace Glamourer.Interop.Material;
|
||||||
public unsafe class DirectXService(IFramework framework) : IService
|
public unsafe class DirectXService(IFramework framework) : IService
|
||||||
{
|
{
|
||||||
private readonly object _lock = new();
|
private readonly object _lock = new();
|
||||||
private readonly ConcurrentDictionary<nint, (DateTime Update, LegacyColorTable Table)> _textures = [];
|
private readonly ConcurrentDictionary<nint, (DateTime Update, ColorTable Table)> _textures = [];
|
||||||
|
|
||||||
/// <summary> Generate a color table the way the game does inside the original texture, and release the original. </summary>
|
/// <summary> Generate a color table the way the game does inside the original texture, and release the original. </summary>
|
||||||
/// <param name="original"> The original texture that will be replaced with a new one. </param>
|
/// <param name="original"> The original texture that will be replaced with a new one. </param>
|
||||||
/// <param name="colorTable"> The input color table. </param>
|
/// <param name="colorTable"> The input color table. </param>
|
||||||
/// <returns> Success or failure. </returns>
|
/// <returns> Success or failure. </returns>
|
||||||
public bool ReplaceColorTable(Texture** original, in LegacyColorTable colorTable)
|
public bool ReplaceColorTable(Texture** original, in ColorTable colorTable)
|
||||||
{
|
{
|
||||||
if (original == null)
|
if (original == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -38,7 +38,7 @@ public unsafe class DirectXService(IFramework framework) : IService
|
||||||
if (texture.IsInvalid)
|
if (texture.IsInvalid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fixed (LegacyColorTable* ptr = &colorTable)
|
fixed (ColorTable* ptr = &colorTable)
|
||||||
{
|
{
|
||||||
if (!texture.Texture->InitializeContents(ptr))
|
if (!texture.Texture->InitializeContents(ptr))
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -51,7 +51,7 @@ public unsafe class DirectXService(IFramework framework) : IService
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetColorTable(Texture* texture, out LegacyColorTable table)
|
public bool TryGetColorTable(Texture* texture, out ColorTable table)
|
||||||
{
|
{
|
||||||
if (_textures.TryGetValue((nint)texture, out var p) && framework.LastUpdateUTC == p.Update)
|
if (_textures.TryGetValue((nint)texture, out var p) && framework.LastUpdateUTC == p.Update)
|
||||||
{
|
{
|
||||||
|
|
@ -73,7 +73,7 @@ public unsafe class DirectXService(IFramework framework) : IService
|
||||||
/// <param name="texture"> A pointer to the internal texture struct containing the GPU handle. </param>
|
/// <param name="texture"> A pointer to the internal texture struct containing the GPU handle. </param>
|
||||||
/// <param name="table"> The returned color table. </param>
|
/// <param name="table"> The returned color table. </param>
|
||||||
/// <returns> Whether the table could be fetched. </returns>
|
/// <returns> Whether the table could be fetched. </returns>
|
||||||
private static bool TextureColorTable(Texture* texture, out LegacyColorTable table)
|
private static bool TextureColorTable(Texture* texture, out ColorTable table)
|
||||||
{
|
{
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
{
|
{
|
||||||
|
|
@ -114,7 +114,7 @@ public unsafe class DirectXService(IFramework framework) : IService
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Turn a mapped texture into a color table. </summary>
|
/// <summary> Turn a mapped texture into a color table. </summary>
|
||||||
private static LegacyColorTable GetTextureData(ID3D11Texture2D1 resource, MappedSubresource map)
|
private static ColorTable GetTextureData(ID3D11Texture2D1 resource, MappedSubresource map)
|
||||||
{
|
{
|
||||||
var desc = resource.Description1;
|
var desc = resource.Description1;
|
||||||
|
|
||||||
|
|
@ -133,14 +133,14 @@ public unsafe class DirectXService(IFramework framework) : IService
|
||||||
/// <param name="height"> The height of the texture. (Needs to be 16).</param>
|
/// <param name="height"> The height of the texture. (Needs to be 16).</param>
|
||||||
/// <param name="pitch"> The stride in the texture data. </param>
|
/// <param name="pitch"> The stride in the texture data. </param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private static LegacyColorTable ReadTexture(nint data, int length, int height, int pitch)
|
private static ColorTable ReadTexture(nint data, int length, int height, int pitch)
|
||||||
{
|
{
|
||||||
// Check that the data has sufficient dimension and size.
|
// Check that the data has sufficient dimension and size.
|
||||||
var expectedSize = sizeof(Half) * MaterialService.TextureWidth * height * 4;
|
var expectedSize = sizeof(Half) * MaterialService.TextureWidth * height * 4;
|
||||||
if (length < expectedSize || sizeof(LegacyColorTable) != expectedSize || height != MaterialService.TextureHeight)
|
if (length < expectedSize || sizeof(ColorTable) != expectedSize || height != MaterialService.TextureHeight)
|
||||||
return default;
|
return default;
|
||||||
|
|
||||||
var ret = new LegacyColorTable();
|
var ret = new ColorTable();
|
||||||
var target = (byte*)&ret;
|
var target = (byte*)&ret;
|
||||||
// If the stride is the same as in the table, just copy.
|
// If the stride is the same as in the table, just copy.
|
||||||
if (pitch == MaterialService.TextureWidth)
|
if (pitch == MaterialService.TextureWidth)
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,11 @@ public sealed unsafe class LiveColorTablePreviewer : IService, IDisposable
|
||||||
private readonly DirectXService _directXService;
|
private readonly DirectXService _directXService;
|
||||||
|
|
||||||
public MaterialValueIndex LastValueIndex { get; private set; } = MaterialValueIndex.Invalid;
|
public MaterialValueIndex LastValueIndex { get; private set; } = MaterialValueIndex.Invalid;
|
||||||
public LegacyColorTable LastOriginalColorTable { get; private set; }
|
public ColorTable LastOriginalColorTable { get; private set; }
|
||||||
private MaterialValueIndex _valueIndex = MaterialValueIndex.Invalid;
|
private MaterialValueIndex _valueIndex = MaterialValueIndex.Invalid;
|
||||||
private ObjectIndex _lastObjectIndex = ObjectIndex.AnyIndex;
|
private ObjectIndex _lastObjectIndex = ObjectIndex.AnyIndex;
|
||||||
private ObjectIndex _objectIndex = ObjectIndex.AnyIndex;
|
private ObjectIndex _objectIndex = ObjectIndex.AnyIndex;
|
||||||
private LegacyColorTable _originalColorTable;
|
private ColorTable _originalColorTable;
|
||||||
|
|
||||||
public LiveColorTablePreviewer(global::Penumbra.GameData.Interop.ObjectManager objects, IFramework framework, DirectXService directXService)
|
public LiveColorTablePreviewer(global::Penumbra.GameData.Interop.ObjectManager objects, IFramework framework, DirectXService directXService)
|
||||||
{
|
{
|
||||||
|
|
@ -78,7 +78,7 @@ public sealed unsafe class LiveColorTablePreviewer : IService, IDisposable
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (var i = 0; i < LegacyColorTable.NumUsedRows; ++i)
|
for (var i = 0; i < ColorTable.NumUsedRows; ++i)
|
||||||
{
|
{
|
||||||
table[i].Diffuse = diffuse;
|
table[i].Diffuse = diffuse;
|
||||||
table[i].Emissive = emissive;
|
table[i].Emissive = emissive;
|
||||||
|
|
@ -92,7 +92,7 @@ public sealed unsafe class LiveColorTablePreviewer : IService, IDisposable
|
||||||
_objectIndex = ObjectIndex.AnyIndex;
|
_objectIndex = ObjectIndex.AnyIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnHover(MaterialValueIndex index, ObjectIndex objectIndex, LegacyColorTable table)
|
public void OnHover(MaterialValueIndex index, ObjectIndex objectIndex, ColorTable table)
|
||||||
{
|
{
|
||||||
if (_valueIndex.DrawObject is not MaterialValueIndex.DrawObjectType.Invalid)
|
if (_valueIndex.DrawObject is not MaterialValueIndex.DrawObjectType.Invalid)
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ public sealed unsafe class MaterialManager : IRequiredService, IDisposable
|
||||||
|
|
||||||
private void OnPrepareColorSet(CharacterBase* characterBase, MaterialResourceHandle* material, ref StainId stain, ref nint ret)
|
private void OnPrepareColorSet(CharacterBase* characterBase, MaterialResourceHandle* material, ref StainId stain, ref nint ret)
|
||||||
{
|
{
|
||||||
|
// TODO fix when working
|
||||||
|
return;
|
||||||
if (!_config.UseAdvancedDyes)
|
if (!_config.UseAdvancedDyes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -76,7 +78,7 @@ public sealed unsafe class MaterialManager : IRequiredService, IDisposable
|
||||||
|
|
||||||
/// <summary> Update and apply the glamourer state of an actor according to the application sources when updated by the game. </summary>
|
/// <summary> Update and apply the glamourer state of an actor according to the application sources when updated by the game. </summary>
|
||||||
private void UpdateMaterialValues(ActorState state, ReadOnlySpan<(uint Key, MaterialValueState Value)> values, CharacterWeapon drawData,
|
private void UpdateMaterialValues(ActorState state, ReadOnlySpan<(uint Key, MaterialValueState Value)> values, CharacterWeapon drawData,
|
||||||
ref LegacyColorTable colorTable)
|
ref ColorTable colorTable)
|
||||||
{
|
{
|
||||||
var deleteList = _deleteList.Value!;
|
var deleteList = _deleteList.Value!;
|
||||||
deleteList.Clear();
|
deleteList.Clear();
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ namespace Glamourer.Interop.Material;
|
||||||
|
|
||||||
public static unsafe class MaterialService
|
public static unsafe class MaterialService
|
||||||
{
|
{
|
||||||
public const int TextureWidth = 4;
|
public const int TextureWidth = 8;
|
||||||
public const int TextureHeight = LegacyColorTable.NumUsedRows;
|
public const int TextureHeight = ColorTable.NumUsedRows;
|
||||||
public const int MaterialsPerModel = 4;
|
public const int MaterialsPerModel = 10;
|
||||||
|
|
||||||
public static bool GenerateNewColorTable(in LegacyColorTable colorTable, out Texture* texture)
|
public static bool GenerateNewColorTable(in ColorTable colorTable, out Texture* texture)
|
||||||
{
|
{
|
||||||
var textureSize = stackalloc int[2];
|
var textureSize = stackalloc int[2];
|
||||||
textureSize[0] = TextureWidth;
|
textureSize[0] = TextureWidth;
|
||||||
|
|
@ -24,7 +24,7 @@ public static unsafe class MaterialService
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fixed (LegacyColorTable* ptr = &colorTable)
|
fixed (ColorTable* ptr = &colorTable)
|
||||||
{
|
{
|
||||||
return texture->InitializeContents(ptr);
|
return texture->InitializeContents(ptr);
|
||||||
}
|
}
|
||||||
|
|
@ -53,7 +53,7 @@ public static unsafe class MaterialService
|
||||||
/// <param name="modelSlot"> The model slot. </param>
|
/// <param name="modelSlot"> The model slot. </param>
|
||||||
/// <param name="materialSlot"> The material slot in the model. </param>
|
/// <param name="materialSlot"> The material slot in the model. </param>
|
||||||
/// <returns> A pointer to the color table or null. </returns>
|
/// <returns> A pointer to the color table or null. </returns>
|
||||||
public static LegacyColorTable* GetMaterialColorTable(Model model, int modelSlot, byte materialSlot)
|
public static ColorTable* GetMaterialColorTable(Model model, int modelSlot, byte materialSlot)
|
||||||
{
|
{
|
||||||
if (!model.IsCharacterBase)
|
if (!model.IsCharacterBase)
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -66,6 +66,6 @@ public static unsafe class MaterialService
|
||||||
if (material == null || material->ColorTable == null)
|
if (material == null || material->ColorTable == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return (LegacyColorTable*)material->ColorTable;
|
return (ColorTable*)material->ColorTable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ public readonly record struct MaterialValueIndex(
|
||||||
=> materialIndex < MaterialService.MaterialsPerModel;
|
=> materialIndex < MaterialService.MaterialsPerModel;
|
||||||
|
|
||||||
public static bool ValidateRow(byte rowIndex)
|
public static bool ValidateRow(byte rowIndex)
|
||||||
=> rowIndex < LegacyColorTable.NumUsedRows;
|
=> rowIndex < ColorTable.NumUsedRows;
|
||||||
|
|
||||||
private static uint ToKey(DrawObjectType type, byte slotIndex, byte materialIndex, byte rowIndex)
|
private static uint ToKey(DrawObjectType type, byte slotIndex, byte materialIndex, byte rowIndex)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ public struct ColorRow(Vector3 diffuse, Vector3 specular, Vector3 emissive, floa
|
||||||
public float SpecularStrength = specularStrength;
|
public float SpecularStrength = specularStrength;
|
||||||
public float GlossStrength = glossStrength;
|
public float GlossStrength = glossStrength;
|
||||||
|
|
||||||
public ColorRow(in LegacyColorTable.Row row)
|
public ColorRow(in ColorTable.Row row)
|
||||||
: this(Root(row.Diffuse), Root(row.Specular), Root(row.Emissive), row.SpecularStrength, row.GlossStrength)
|
: this(Root(row.Diffuse), Root(row.Specular), Root(row.Emissive), row.SpecularStrength, row.GlossStrength)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ public struct ColorRow(Vector3 diffuse, Vector3 specular, Vector3 emissive, floa
|
||||||
private static float Root(float value)
|
private static float Root(float value)
|
||||||
=> value < 0 ? MathF.Sqrt(-value) : MathF.Sqrt(value);
|
=> value < 0 ? MathF.Sqrt(-value) : MathF.Sqrt(value);
|
||||||
|
|
||||||
public readonly bool Apply(ref LegacyColorTable.Row row)
|
public readonly bool Apply(ref ColorTable.Row row)
|
||||||
{
|
{
|
||||||
var ret = false;
|
var ret = false;
|
||||||
var d = Square(Diffuse);
|
var d = Square(Diffuse);
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ public sealed unsafe class PrepareColorSet
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryGetColorTable(CharacterBase* characterBase, MaterialResourceHandle* material, StainIds stainIds,
|
public static bool TryGetColorTable(CharacterBase* characterBase, MaterialResourceHandle* material, StainIds stainIds,
|
||||||
out LegacyColorTable table)
|
out ColorTable table)
|
||||||
{
|
{
|
||||||
if (material->ColorTable == null)
|
if (material->ColorTable == null)
|
||||||
{
|
{
|
||||||
|
|
@ -64,7 +64,7 @@ public sealed unsafe class PrepareColorSet
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var newTable = *(LegacyColorTable*)material->ColorTable;
|
var newTable = *(ColorTable*)material->ColorTable;
|
||||||
// TODO
|
// TODO
|
||||||
//if (stainIds.Stain1.Id != 0 || stainIds.Stain2.Id != 0)
|
//if (stainIds.Stain1.Id != 0 || stainIds.Stain2.Id != 0)
|
||||||
// characterBase->ReadStainingTemplate(material, stainId.Id, (Half*)(&newTable));
|
// characterBase->ReadStainingTemplate(material, stainId.Id, (Half*)(&newTable));
|
||||||
|
|
@ -73,7 +73,7 @@ public sealed unsafe class PrepareColorSet
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Assumes the actor is valid. </summary>
|
/// <summary> Assumes the actor is valid. </summary>
|
||||||
public static bool TryGetColorTable(Actor actor, MaterialValueIndex index, out LegacyColorTable table)
|
public static bool TryGetColorTable(Actor actor, MaterialValueIndex index, out ColorTable table)
|
||||||
{
|
{
|
||||||
var idx = index.SlotIndex * MaterialService.MaterialsPerModel + index.MaterialIndex;
|
var idx = index.SlotIndex * MaterialService.MaterialsPerModel + index.MaterialIndex;
|
||||||
if (!index.TryGetModel(actor, out var model))
|
if (!index.TryGetModel(actor, out var model))
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ public unsafe class WeaponService : IDisposable
|
||||||
private readonly WeaponLoading _event;
|
private readonly WeaponLoading _event;
|
||||||
private readonly ThreadLocal<bool> _inUpdate = new(() => false);
|
private readonly ThreadLocal<bool> _inUpdate = new(() => false);
|
||||||
|
|
||||||
|
|
||||||
private readonly delegate* unmanaged[Stdcall]<DrawDataContainer*, uint, ulong, byte, byte, byte, byte, void>
|
private readonly delegate* unmanaged[Stdcall]<DrawDataContainer*, uint, ulong, byte, byte, byte, byte, void>
|
||||||
_original;
|
_original;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,21 @@ public sealed class TextureService(IUiBuilder uiBuilder, IDataManager dataManage
|
||||||
: (nint.Zero, Vector2.Zero, true);
|
: (nint.Zero, Vector2.Zero, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public (nint, Vector2, bool) GetIcon(BonusItem item, BonusItemFlag slot)
|
||||||
|
{
|
||||||
|
if (item.Icon.Id != 0 && TryLoadIcon(item.Icon.Id, out var ret))
|
||||||
|
return (ret.ImGuiHandle, new Vector2(ret.Width, ret.Height), false);
|
||||||
|
|
||||||
|
var idx = slot.ToIndex();
|
||||||
|
if (idx == uint.MaxValue)
|
||||||
|
return (nint.Zero, Vector2.Zero, true);
|
||||||
|
|
||||||
|
idx += 12;
|
||||||
|
return idx < 13 && _slotIcons[idx] != null
|
||||||
|
? (_slotIcons[idx]!.ImGuiHandle, new Vector2(_slotIcons[idx]!.Width, _slotIcons[idx]!.Height), true)
|
||||||
|
: (nint.Zero, Vector2.Zero, true);
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
for (var i = 0; i < _slotIcons.Length; ++i)
|
for (var i = 0; i < _slotIcons.Length; ++i)
|
||||||
|
|
@ -34,9 +49,9 @@ public sealed class TextureService(IUiBuilder uiBuilder, IDataManager dataManage
|
||||||
|
|
||||||
private static IDalamudTextureWrap?[] CreateSlotIcons(IUiBuilder uiBuilder)
|
private static IDalamudTextureWrap?[] CreateSlotIcons(IUiBuilder uiBuilder)
|
||||||
{
|
{
|
||||||
var ret = new IDalamudTextureWrap?[12];
|
var ret = new IDalamudTextureWrap?[13];
|
||||||
|
|
||||||
using var uldWrapper = uiBuilder.LoadUld("ui/uld/ArmouryBoard.uld");
|
using var uldWrapper = uiBuilder.LoadUld("ui/uld/Character.uld");
|
||||||
|
|
||||||
if (!uldWrapper.Valid)
|
if (!uldWrapper.Valid)
|
||||||
{
|
{
|
||||||
|
|
@ -44,33 +59,37 @@ public sealed class TextureService(IUiBuilder uiBuilder, IDataManager dataManage
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetIcon(EquipSlot.Head, 1);
|
SetIcon(EquipSlot.Head, 19);
|
||||||
SetIcon(EquipSlot.Body, 2);
|
SetIcon(EquipSlot.Body, 20);
|
||||||
SetIcon(EquipSlot.Hands, 3);
|
SetIcon(EquipSlot.Hands, 21);
|
||||||
SetIcon(EquipSlot.Legs, 5);
|
SetIcon(EquipSlot.Legs, 23);
|
||||||
SetIcon(EquipSlot.Feet, 6);
|
SetIcon(EquipSlot.Feet, 24);
|
||||||
SetIcon(EquipSlot.Ears, 8);
|
SetIcon(EquipSlot.Ears, 25);
|
||||||
SetIcon(EquipSlot.Neck, 9);
|
SetIcon(EquipSlot.Neck, 26);
|
||||||
SetIcon(EquipSlot.Wrists, 10);
|
SetIcon(EquipSlot.Wrists, 27);
|
||||||
SetIcon(EquipSlot.RFinger, 11);
|
SetIcon(EquipSlot.RFinger, 28);
|
||||||
SetIcon(EquipSlot.MainHand, 0);
|
SetIcon(EquipSlot.MainHand, 17);
|
||||||
SetIcon(EquipSlot.OffHand, 7);
|
SetIcon(EquipSlot.OffHand, 18);
|
||||||
|
Set(BonusItemFlag.Glasses.ToName(), (int) BonusItemFlag.Glasses.ToIndex() + 12, 55);
|
||||||
ret[EquipSlot.LFinger.ToIndex()] = ret[EquipSlot.RFinger.ToIndex()];
|
ret[EquipSlot.LFinger.ToIndex()] = ret[EquipSlot.RFinger.ToIndex()];
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
void SetIcon(EquipSlot slot, int index)
|
void Set(string name, int slot, int index)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ret[slot.ToIndex()] = uldWrapper.LoadTexturePart("ui/uld/ArmouryBoard_hr1.tex", index)!;
|
ret[slot] = uldWrapper.LoadTexturePart("ui/uld/Character_hr1.tex", index)!;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Glamourer.Log.Error($"Could not get empty slot texture for {slot.ToName()}, icon will be left empty. "
|
Glamourer.Log.Error($"Could not get empty slot texture for {name}, icon will be left empty. "
|
||||||
+ $"This may be because of incompatible mods affecting your character screen interface:\n{ex}");
|
+ $"This may be because of incompatible mods affecting your character screen interface:\n{ex}");
|
||||||
ret[slot.ToIndex()] = null;
|
ret[slot] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetIcon(EquipSlot slot, int index)
|
||||||
|
=> Set(slot.ToName(), (int)slot.ToIndex(), index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -306,6 +306,8 @@ public class StateApplier(
|
||||||
|
|
||||||
public unsafe void ChangeMaterialValue(ActorData data, MaterialValueIndex index, ColorRow? value, bool force)
|
public unsafe void ChangeMaterialValue(ActorData data, MaterialValueIndex index, ColorRow? value, bool force)
|
||||||
{
|
{
|
||||||
|
// TODO fix when working
|
||||||
|
return;
|
||||||
if (!force && !_config.UseAdvancedDyes)
|
if (!force && !_config.UseAdvancedDyes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -338,6 +340,8 @@ public class StateApplier(
|
||||||
|
|
||||||
public unsafe void ChangeMaterialValues(ActorData data, in StateMaterialManager materials, bool force)
|
public unsafe void ChangeMaterialValues(ActorData data, in StateMaterialManager materials, bool force)
|
||||||
{
|
{
|
||||||
|
// TODO: fix when working
|
||||||
|
return;
|
||||||
if (!force && !_config.UseAdvancedDyes)
|
if (!force && !_config.UseAdvancedDyes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -383,6 +387,11 @@ public class StateApplier(
|
||||||
ChangeCustomize(actors, state.ModelData.Customize);
|
ChangeCustomize(actors, state.ModelData.Customize);
|
||||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||||
ChangeArmor(actors, slot, state.ModelData.Armor(slot), !state.Sources[slot, false].IsIpc(), state.ModelData.IsHatVisible());
|
ChangeArmor(actors, slot, state.ModelData.Armor(slot), !state.Sources[slot, false].IsIpc(), state.ModelData.IsHatVisible());
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
var item = state.ModelData.BonusItem(slot);
|
||||||
|
ChangeBonusItem(actors, slot, item.ModelId, item.Variant);
|
||||||
|
}
|
||||||
|
|
||||||
var mainhandActors = state.ModelData.MainhandType != state.BaseData.MainhandType ? actors.OnlyGPose() : actors;
|
var mainhandActors = state.ModelData.MainhandType != state.BaseData.MainhandType ? actors.OnlyGPose() : actors;
|
||||||
ChangeMainhand(mainhandActors, state.ModelData.Item(EquipSlot.MainHand), state.ModelData.Stain(EquipSlot.MainHand));
|
ChangeMainhand(mainhandActors, state.ModelData.Item(EquipSlot.MainHand), state.ModelData.Stain(EquipSlot.MainHand));
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ public class StateEditor(
|
||||||
var @new = state.ModelData.Parameters[flag];
|
var @new = state.ModelData.Parameters[flag];
|
||||||
var actors = Applier.ChangeParameters(state, flag, settings.Source.RequiresChange());
|
var actors = Applier.ChangeParameters(state, flag, settings.Source.RequiresChange());
|
||||||
Glamourer.Log.Verbose(
|
Glamourer.Log.Verbose(
|
||||||
$"Set {flag} crest in state {state.Identifier.Incognito(null)} from {old} to {@new}. [Affecting {actors.ToLazyString("nothing")}.]");
|
$"Set {flag} in state {state.Identifier.Incognito(null)} from {old} to {@new}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||||
StateChanged.Invoke(StateChangeType.Parameter, settings.Source, state, actors, (old, @new, flag));
|
StateChanged.Invoke(StateChangeType.Parameter, settings.Source, state, actors, (old, @new, flag));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,9 @@ public readonly record struct StateIndex(int Value) : IEqualityOperators<StateIn
|
||||||
CustomizeParameterFlag.HairSpecular => new StateIndex(ParamHairSpecular),
|
CustomizeParameterFlag.HairSpecular => new StateIndex(ParamHairSpecular),
|
||||||
CustomizeParameterFlag.HairHighlight => new StateIndex(ParamHairHighlight),
|
CustomizeParameterFlag.HairHighlight => new StateIndex(ParamHairHighlight),
|
||||||
CustomizeParameterFlag.LeftEye => new StateIndex(ParamLeftEye),
|
CustomizeParameterFlag.LeftEye => new StateIndex(ParamLeftEye),
|
||||||
|
CustomizeParameterFlag.LeftScleraIntensity => new StateIndex(ParamLeftScleraIntensity),
|
||||||
CustomizeParameterFlag.RightEye => new StateIndex(ParamRightEye),
|
CustomizeParameterFlag.RightEye => new StateIndex(ParamRightEye),
|
||||||
|
CustomizeParameterFlag.RightScleraIntensity => new StateIndex(ParamRightScleraIntensity),
|
||||||
CustomizeParameterFlag.FeatureColor => new StateIndex(ParamFeatureColor),
|
CustomizeParameterFlag.FeatureColor => new StateIndex(ParamFeatureColor),
|
||||||
CustomizeParameterFlag.FacePaintUvMultiplier => new StateIndex(ParamFacePaintUvMultiplier),
|
CustomizeParameterFlag.FacePaintUvMultiplier => new StateIndex(ParamFacePaintUvMultiplier),
|
||||||
CustomizeParameterFlag.FacePaintUvOffset => new StateIndex(ParamFacePaintUvOffset),
|
CustomizeParameterFlag.FacePaintUvOffset => new StateIndex(ParamFacePaintUvOffset),
|
||||||
|
|
@ -199,8 +201,10 @@ public readonly record struct StateIndex(int Value) : IEqualityOperators<StateIn
|
||||||
public const int ParamHairSpecular = ParamHairDiffuse + 1;
|
public const int ParamHairSpecular = ParamHairDiffuse + 1;
|
||||||
public const int ParamHairHighlight = ParamHairSpecular + 1;
|
public const int ParamHairHighlight = ParamHairSpecular + 1;
|
||||||
public const int ParamLeftEye = ParamHairHighlight + 1;
|
public const int ParamLeftEye = ParamHairHighlight + 1;
|
||||||
public const int ParamRightEye = ParamLeftEye + 1;
|
public const int ParamLeftScleraIntensity = ParamLeftEye + 1;
|
||||||
public const int ParamFeatureColor = ParamRightEye + 1;
|
public const int ParamRightEye = ParamLeftScleraIntensity + 1;
|
||||||
|
public const int ParamRightScleraIntensity = ParamRightEye + 1;
|
||||||
|
public const int ParamFeatureColor = ParamRightScleraIntensity + 1;
|
||||||
public const int ParamFacePaintUvMultiplier = ParamFeatureColor + 1;
|
public const int ParamFacePaintUvMultiplier = ParamFeatureColor + 1;
|
||||||
public const int ParamFacePaintUvOffset = ParamFacePaintUvMultiplier + 1;
|
public const int ParamFacePaintUvOffset = ParamFacePaintUvMultiplier + 1;
|
||||||
public const int ParamDecalColor = ParamFacePaintUvOffset + 1;
|
public const int ParamDecalColor = ParamFacePaintUvOffset + 1;
|
||||||
|
|
@ -309,7 +313,9 @@ public readonly record struct StateIndex(int Value) : IEqualityOperators<StateIn
|
||||||
ParamHairSpecular => CustomizeParameterFlag.HairSpecular,
|
ParamHairSpecular => CustomizeParameterFlag.HairSpecular,
|
||||||
ParamHairHighlight => CustomizeParameterFlag.HairHighlight,
|
ParamHairHighlight => CustomizeParameterFlag.HairHighlight,
|
||||||
ParamLeftEye => CustomizeParameterFlag.LeftEye,
|
ParamLeftEye => CustomizeParameterFlag.LeftEye,
|
||||||
|
ParamLeftScleraIntensity => CustomizeParameterFlag.LeftScleraIntensity,
|
||||||
ParamRightEye => CustomizeParameterFlag.RightEye,
|
ParamRightEye => CustomizeParameterFlag.RightEye,
|
||||||
|
ParamRightScleraIntensity => CustomizeParameterFlag.RightScleraIntensity,
|
||||||
ParamFeatureColor => CustomizeParameterFlag.FeatureColor,
|
ParamFeatureColor => CustomizeParameterFlag.FeatureColor,
|
||||||
ParamFacePaintUvMultiplier => CustomizeParameterFlag.FacePaintUvMultiplier,
|
ParamFacePaintUvMultiplier => CustomizeParameterFlag.FacePaintUvMultiplier,
|
||||||
ParamFacePaintUvOffset => CustomizeParameterFlag.FacePaintUvOffset,
|
ParamFacePaintUvOffset => CustomizeParameterFlag.FacePaintUvOffset,
|
||||||
|
|
@ -320,103 +326,6 @@ public readonly record struct StateIndex(int Value) : IEqualityOperators<StateIn
|
||||||
_ => -1,
|
_ => -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
public object? GetValue(in DesignData data)
|
|
||||||
{
|
|
||||||
return Value switch
|
|
||||||
{
|
|
||||||
EquipHead => data.Item(EquipSlot.Head),
|
|
||||||
EquipBody => data.Item(EquipSlot.Body),
|
|
||||||
EquipHands => data.Item(EquipSlot.Hands),
|
|
||||||
EquipLegs => data.Item(EquipSlot.Legs),
|
|
||||||
EquipFeet => data.Item(EquipSlot.Feet),
|
|
||||||
EquipEars => data.Item(EquipSlot.Ears),
|
|
||||||
EquipNeck => data.Item(EquipSlot.Neck),
|
|
||||||
EquipWrist => data.Item(EquipSlot.Wrists),
|
|
||||||
EquipRFinger => data.Item(EquipSlot.RFinger),
|
|
||||||
EquipLFinger => data.Item(EquipSlot.LFinger),
|
|
||||||
EquipMainhand => data.Item(EquipSlot.MainHand),
|
|
||||||
EquipOffhand => data.Item(EquipSlot.OffHand),
|
|
||||||
|
|
||||||
StainHead => data.Stain(EquipSlot.Head),
|
|
||||||
StainBody => data.Stain(EquipSlot.Body),
|
|
||||||
StainHands => data.Stain(EquipSlot.Hands),
|
|
||||||
StainLegs => data.Stain(EquipSlot.Legs),
|
|
||||||
StainFeet => data.Stain(EquipSlot.Feet),
|
|
||||||
StainEars => data.Stain(EquipSlot.Ears),
|
|
||||||
StainNeck => data.Stain(EquipSlot.Neck),
|
|
||||||
StainWrist => data.Stain(EquipSlot.Wrists),
|
|
||||||
StainRFinger => data.Stain(EquipSlot.RFinger),
|
|
||||||
StainLFinger => data.Stain(EquipSlot.LFinger),
|
|
||||||
StainMainhand => data.Stain(EquipSlot.MainHand),
|
|
||||||
StainOffhand => data.Stain(EquipSlot.OffHand),
|
|
||||||
|
|
||||||
CustomizeRace => data.Customize[CustomizeIndex.Race],
|
|
||||||
CustomizeGender => data.Customize[CustomizeIndex.Gender],
|
|
||||||
CustomizeBodyType => data.Customize[CustomizeIndex.BodyType],
|
|
||||||
CustomizeHeight => data.Customize[CustomizeIndex.Height],
|
|
||||||
CustomizeClan => data.Customize[CustomizeIndex.Clan],
|
|
||||||
CustomizeFace => data.Customize[CustomizeIndex.Face],
|
|
||||||
CustomizeHairstyle => data.Customize[CustomizeIndex.Hairstyle],
|
|
||||||
CustomizeHighlights => data.Customize[CustomizeIndex.Highlights],
|
|
||||||
CustomizeSkinColor => data.Customize[CustomizeIndex.SkinColor],
|
|
||||||
CustomizeEyeColorRight => data.Customize[CustomizeIndex.EyeColorRight],
|
|
||||||
CustomizeHairColor => data.Customize[CustomizeIndex.HairColor],
|
|
||||||
CustomizeHighlightsColor => data.Customize[CustomizeIndex.HighlightsColor],
|
|
||||||
CustomizeFacialFeature1 => data.Customize[CustomizeIndex.FacialFeature1],
|
|
||||||
CustomizeFacialFeature2 => data.Customize[CustomizeIndex.FacialFeature2],
|
|
||||||
CustomizeFacialFeature3 => data.Customize[CustomizeIndex.FacialFeature3],
|
|
||||||
CustomizeFacialFeature4 => data.Customize[CustomizeIndex.FacialFeature4],
|
|
||||||
CustomizeFacialFeature5 => data.Customize[CustomizeIndex.FacialFeature5],
|
|
||||||
CustomizeFacialFeature6 => data.Customize[CustomizeIndex.FacialFeature6],
|
|
||||||
CustomizeFacialFeature7 => data.Customize[CustomizeIndex.FacialFeature7],
|
|
||||||
CustomizeLegacyTattoo => data.Customize[CustomizeIndex.LegacyTattoo],
|
|
||||||
CustomizeTattooColor => data.Customize[CustomizeIndex.TattooColor],
|
|
||||||
CustomizeEyebrows => data.Customize[CustomizeIndex.Eyebrows],
|
|
||||||
CustomizeEyeColorLeft => data.Customize[CustomizeIndex.EyeColorLeft],
|
|
||||||
CustomizeEyeShape => data.Customize[CustomizeIndex.EyeShape],
|
|
||||||
CustomizeSmallIris => data.Customize[CustomizeIndex.SmallIris],
|
|
||||||
CustomizeNose => data.Customize[CustomizeIndex.Nose],
|
|
||||||
CustomizeJaw => data.Customize[CustomizeIndex.Jaw],
|
|
||||||
CustomizeMouth => data.Customize[CustomizeIndex.Mouth],
|
|
||||||
CustomizeLipstick => data.Customize[CustomizeIndex.Lipstick],
|
|
||||||
CustomizeLipColor => data.Customize[CustomizeIndex.LipColor],
|
|
||||||
CustomizeMuscleMass => data.Customize[CustomizeIndex.MuscleMass],
|
|
||||||
CustomizeTailShape => data.Customize[CustomizeIndex.TailShape],
|
|
||||||
CustomizeBustSize => data.Customize[CustomizeIndex.BustSize],
|
|
||||||
CustomizeFacePaint => data.Customize[CustomizeIndex.FacePaint],
|
|
||||||
CustomizeFacePaintReversed => data.Customize[CustomizeIndex.FacePaintReversed],
|
|
||||||
CustomizeFacePaintColor => data.Customize[CustomizeIndex.FacePaintColor],
|
|
||||||
|
|
||||||
MetaWetness => data.GetMeta(MetaIndex.Wetness),
|
|
||||||
MetaHatState => data.GetMeta(MetaIndex.HatState),
|
|
||||||
MetaVisorState => data.GetMeta(MetaIndex.VisorState),
|
|
||||||
MetaWeaponState => data.GetMeta(MetaIndex.WeaponState),
|
|
||||||
MetaModelId => data.ModelId,
|
|
||||||
|
|
||||||
CrestHead => data.Crest(CrestFlag.Head),
|
|
||||||
CrestBody => data.Crest(CrestFlag.Body),
|
|
||||||
CrestOffhand => data.Crest(CrestFlag.OffHand),
|
|
||||||
|
|
||||||
ParamSkinDiffuse => data.Parameters[CustomizeParameterFlag.SkinDiffuse],
|
|
||||||
ParamMuscleTone => data.Parameters[CustomizeParameterFlag.MuscleTone],
|
|
||||||
ParamSkinSpecular => data.Parameters[CustomizeParameterFlag.SkinSpecular],
|
|
||||||
ParamLipDiffuse => data.Parameters[CustomizeParameterFlag.LipDiffuse],
|
|
||||||
ParamHairDiffuse => data.Parameters[CustomizeParameterFlag.HairDiffuse],
|
|
||||||
ParamHairSpecular => data.Parameters[CustomizeParameterFlag.HairSpecular],
|
|
||||||
ParamHairHighlight => data.Parameters[CustomizeParameterFlag.HairHighlight],
|
|
||||||
ParamLeftEye => data.Parameters[CustomizeParameterFlag.LeftEye],
|
|
||||||
ParamRightEye => data.Parameters[CustomizeParameterFlag.RightEye],
|
|
||||||
ParamFeatureColor => data.Parameters[CustomizeParameterFlag.FeatureColor],
|
|
||||||
ParamFacePaintUvMultiplier => data.Parameters[CustomizeParameterFlag.FacePaintUvMultiplier],
|
|
||||||
ParamFacePaintUvOffset => data.Parameters[CustomizeParameterFlag.FacePaintUvOffset],
|
|
||||||
ParamDecalColor => data.Parameters[CustomizeParameterFlag.DecalColor],
|
|
||||||
|
|
||||||
BonusItemGlasses => data.BonusItem(BonusItemFlag.Glasses),
|
|
||||||
|
|
||||||
_ => null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetName(EquipFlag flag)
|
private static string GetName(EquipFlag flag)
|
||||||
{
|
{
|
||||||
var slot = flag.ToSlot(out var stain);
|
var slot = flag.ToSlot(out var stain);
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 8928015f38f951810a9a6fbb44fb4a0cb9a712dd
|
Subproject commit 491b61916951b7192bb2354d725363340ea153b5
|
||||||
Loading…
Add table
Add a link
Reference in a new issue