mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-26 02:19:21 +01:00
.
This commit is contained in:
parent
ee98d6b600
commit
20cc67275a
25 changed files with 324 additions and 173 deletions
|
|
@ -94,7 +94,7 @@ public class AutoDesignApplier : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private void OnJobChange(Actor actor, Job _)
|
||||
private void OnJobChange(Actor actor, Job oldJob, Job newJob)
|
||||
{
|
||||
if (!_config.EnableAutoDesigns || !actor.Identifier(_actors.AwaitedService, out var id))
|
||||
return;
|
||||
|
|
@ -102,16 +102,18 @@ public class AutoDesignApplier : IDisposable
|
|||
if (!GetPlayerSet(id, out var set))
|
||||
{
|
||||
if (_state.TryGetValue(id, out var s))
|
||||
s.LastJob = actor.Job;
|
||||
s.LastJob = (byte) newJob.Id;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_state.GetOrCreate(id, actor, out var state))
|
||||
return;
|
||||
|
||||
var sameJob = state.LastJob == actor.Job;
|
||||
if (oldJob.Id == newJob.Id && state.LastJob == newJob.Id)
|
||||
return;
|
||||
|
||||
state.LastJob = actor.Job;
|
||||
Reduce(actor, state, set, sameJob);
|
||||
Reduce(actor, state, set, state.LastJob == newJob.Id);
|
||||
_state.ReapplyState(actor);
|
||||
}
|
||||
|
||||
|
|
@ -185,7 +187,7 @@ public class AutoDesignApplier : IDisposable
|
|||
if (equipFlags.HasFlag(flag))
|
||||
{
|
||||
var item = design.Item(slot);
|
||||
if (_code.EnabledInventory || _itemUnlocks.IsUnlocked(item.Id, out _))
|
||||
if (_code.EnabledInventory || _itemUnlocks.IsUnlocked(item.ItemId, out _))
|
||||
{
|
||||
if (!respectManual || state[slot, false] is not StateChanged.Source.Manual)
|
||||
_state.ChangeItem(state, slot, item, StateChanged.Source.Fixed);
|
||||
|
|
@ -206,7 +208,7 @@ public class AutoDesignApplier : IDisposable
|
|||
{
|
||||
var item = design.Item(EquipSlot.MainHand);
|
||||
if (state.ModelData.Item(EquipSlot.MainHand).Type == item.Type
|
||||
&& (_code.EnabledInventory || _itemUnlocks.IsUnlocked(item.Id, out _)))
|
||||
&& (_code.EnabledInventory || _itemUnlocks.IsUnlocked(item.ItemId, out _)))
|
||||
{
|
||||
if (!respectManual || state[EquipSlot.MainHand, false] is not StateChanged.Source.Manual)
|
||||
_state.ChangeItem(state, EquipSlot.MainHand, item, StateChanged.Source.Fixed);
|
||||
|
|
@ -218,7 +220,7 @@ public class AutoDesignApplier : IDisposable
|
|||
{
|
||||
var item = design.Item(EquipSlot.OffHand);
|
||||
if (state.ModelData.Item(EquipSlot.OffHand).Type == item.Type
|
||||
&& (_code.EnabledInventory || _itemUnlocks.IsUnlocked(item.Id, out _)))
|
||||
&& (_code.EnabledInventory || _itemUnlocks.IsUnlocked(item.ItemId, out _)))
|
||||
{
|
||||
if (!respectManual || state[EquipSlot.OffHand, false] is not StateChanged.Source.Manual)
|
||||
_state.ChangeItem(state, EquipSlot.OffHand, item, StateChanged.Source.Fixed);
|
||||
|
|
|
|||
|
|
@ -130,8 +130,8 @@ public sealed class Design : DesignBase, ISavable
|
|||
if (design.LastEdit < creationDate)
|
||||
design.LastEdit = creationDate;
|
||||
|
||||
LoadCustomize(customizations, json["Customize"], design, design.Name);
|
||||
LoadEquip(items, json["Equipment"], design, design.Name);
|
||||
LoadCustomize(customizations, json["Customize"], design, design.Name, true, false);
|
||||
LoadEquip(items, json["Equipment"], design, design.Name, false);
|
||||
LoadMods(json["Mods"], design);
|
||||
return design;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,27 +167,33 @@ public class DesignBase
|
|||
|
||||
protected JObject SerializeEquipment()
|
||||
{
|
||||
static JObject Serialize(uint itemId, StainId stain, bool apply, bool applyStain)
|
||||
static JObject Serialize(ulong id, StainId stain, bool apply, bool applyStain)
|
||||
=> new()
|
||||
{
|
||||
["ItemId"] = itemId,
|
||||
["ItemId"] = id,
|
||||
["Stain"] = stain.Value,
|
||||
["Apply"] = apply,
|
||||
["ApplyStain"] = applyStain,
|
||||
};
|
||||
|
||||
var ret = new JObject();
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
|
||||
if (DesignData.IsHuman)
|
||||
{
|
||||
var item = DesignData.Item(slot);
|
||||
var stain = DesignData.Stain(slot);
|
||||
ret[slot.ToString()] = Serialize(item.Id, stain, DoApplyEquip(slot), DoApplyStain(slot));
|
||||
}
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
|
||||
{
|
||||
var item = DesignData.Item(slot);
|
||||
var stain = DesignData.Stain(slot);
|
||||
ret[slot.ToString()] = Serialize(item.Id, stain, DoApplyEquip(slot), DoApplyStain(slot));
|
||||
}
|
||||
|
||||
ret["Hat"] = new QuadBool(DesignData.IsHatVisible(), DoApplyHatVisible()).ToJObject("Show", "Apply");
|
||||
ret["Visor"] = new QuadBool(DesignData.IsVisorToggled(), DoApplyVisorToggle()).ToJObject("IsToggled", "Apply");
|
||||
ret["Weapon"] = new QuadBool(DesignData.IsWeaponVisible(), DoApplyWeaponVisible()).ToJObject("Show", "Apply");
|
||||
ret["Array"] = DesignData.WriteEquipmentBytesBase64();
|
||||
ret["Hat"] = new QuadBool(DesignData.IsHatVisible(), DoApplyHatVisible()).ToJObject("Show", "Apply");
|
||||
ret["Visor"] = new QuadBool(DesignData.IsVisorToggled(), DoApplyVisorToggle()).ToJObject("IsToggled", "Apply");
|
||||
ret["Weapon"] = new QuadBool(DesignData.IsWeaponVisible(), DoApplyWeaponVisible()).ToJObject("Show", "Apply");
|
||||
}
|
||||
else
|
||||
{
|
||||
ret["Array"] = DesignData.WriteEquipmentBytesBase64();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -198,22 +204,25 @@ public class DesignBase
|
|||
{
|
||||
["ModelId"] = DesignData.ModelId,
|
||||
};
|
||||
|
||||
var customize = DesignData.Customize;
|
||||
foreach (var idx in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
ret[idx.ToString()] = new JObject()
|
||||
if (DesignData.IsHuman)
|
||||
foreach (var idx in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
["Value"] = customize[idx].Value,
|
||||
["Apply"] = DoApplyCustomize(idx),
|
||||
};
|
||||
}
|
||||
ret[idx.ToString()] = new JObject()
|
||||
{
|
||||
["Value"] = customize[idx].Value,
|
||||
["Apply"] = DoApplyCustomize(idx),
|
||||
};
|
||||
}
|
||||
else
|
||||
ret["Array"] = customize.WriteBase64();
|
||||
|
||||
ret["Wetness"] = new JObject()
|
||||
{
|
||||
["Value"] = DesignData.IsWet(),
|
||||
["Apply"] = DoApplyWetness(),
|
||||
};
|
||||
ret["Array"] = DesignData.Customize.WriteBase64();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -235,12 +244,12 @@ public class DesignBase
|
|||
private static DesignBase LoadDesignV1Base(CustomizationService customizations, ItemManager items, JObject json)
|
||||
{
|
||||
var ret = new DesignBase(items);
|
||||
LoadCustomize(customizations, json["Customize"], ret, "Temporary Design");
|
||||
LoadEquip(items, json["Equipment"], ret, "Temporary Design");
|
||||
LoadCustomize(customizations, json["Customize"], ret, "Temporary Design", false, true);
|
||||
LoadEquip(items, json["Equipment"], ret, "Temporary Design", true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected static void LoadEquip(ItemManager items, JToken? equip, DesignBase design, string name)
|
||||
protected static void LoadEquip(ItemManager items, JToken? equip, DesignBase design, string name, bool allowUnknown)
|
||||
{
|
||||
if (equip == null)
|
||||
{
|
||||
|
|
@ -257,9 +266,9 @@ public class DesignBase
|
|||
return;
|
||||
}
|
||||
|
||||
static (uint, StainId, bool, bool) ParseItem(EquipSlot slot, JToken? item)
|
||||
static (ulong, StainId, bool, bool) ParseItem(EquipSlot slot, JToken? item)
|
||||
{
|
||||
var id = item?["ItemId"]?.ToObject<uint>() ?? ItemManager.NothingId(slot);
|
||||
var id = item?["ItemId"]?.ToObject<ulong>() ?? ItemManager.NothingId(slot);
|
||||
var stain = (StainId)(item?["Stain"]?.ToObject<byte>() ?? 0);
|
||||
var apply = item?["Apply"]?.ToObject<bool>() ?? false;
|
||||
var applyStain = item?["ApplyStain"]?.ToObject<bool>() ?? false;
|
||||
|
|
@ -276,8 +285,8 @@ public class DesignBase
|
|||
{
|
||||
var (id, stain, apply, applyStain) = ParseItem(slot, equip[slot.ToString()]);
|
||||
|
||||
PrintWarning(items.ValidateItem(slot, id, out var item));
|
||||
PrintWarning(items.ValidateStain(stain, out stain));
|
||||
PrintWarning(items.ValidateItem(slot, id, out var item, allowUnknown));
|
||||
PrintWarning(items.ValidateStain(stain, out stain, allowUnknown));
|
||||
design.DesignData.SetItem(slot, item);
|
||||
design.DesignData.SetStain(slot, stain);
|
||||
design.SetApplyEquip(slot, apply);
|
||||
|
|
@ -287,14 +296,14 @@ public class DesignBase
|
|||
{
|
||||
var (id, stain, apply, applyStain) = ParseItem(EquipSlot.MainHand, equip[EquipSlot.MainHand.ToString()]);
|
||||
if (id == ItemManager.NothingId(EquipSlot.MainHand))
|
||||
id = items.DefaultSword.Id;
|
||||
id = items.DefaultSword.ItemId;
|
||||
var (idOff, stainOff, applyOff, applyStainOff) = ParseItem(EquipSlot.OffHand, equip[EquipSlot.OffHand.ToString()]);
|
||||
if (id == ItemManager.NothingId(EquipSlot.OffHand))
|
||||
id = ItemManager.NothingId(FullEquipType.Shield);
|
||||
|
||||
PrintWarning(items.ValidateWeapons(id, idOff, out var main, out var off));
|
||||
PrintWarning(items.ValidateStain(stain, out stain));
|
||||
PrintWarning(items.ValidateStain(stainOff, out stainOff));
|
||||
PrintWarning(items.ValidateWeapons((uint)id, (uint)idOff, out var main, out var off));
|
||||
PrintWarning(items.ValidateStain(stain, out stain, allowUnknown));
|
||||
PrintWarning(items.ValidateStain(stainOff, out stainOff, allowUnknown));
|
||||
design.DesignData.SetItem(EquipSlot.MainHand, main);
|
||||
design.DesignData.SetItem(EquipSlot.OffHand, off);
|
||||
design.DesignData.SetStain(EquipSlot.MainHand, stain);
|
||||
|
|
@ -317,7 +326,8 @@ public class DesignBase
|
|||
design.DesignData.SetVisor(metaValue.ForcedValue);
|
||||
}
|
||||
|
||||
protected static void LoadCustomize(CustomizationService customizations, JToken? json, DesignBase design, string name)
|
||||
protected static void LoadCustomize(CustomizationService customizations, JToken? json, DesignBase design, string name, bool forbidNonHuman,
|
||||
bool allowUnknown)
|
||||
{
|
||||
if (json == null)
|
||||
{
|
||||
|
|
@ -341,7 +351,13 @@ public class DesignBase
|
|||
|
||||
design.DesignData.ModelId = json["ModelId"]?.ToObject<uint>() ?? 0;
|
||||
PrintWarning(customizations.ValidateModelId(design.DesignData.ModelId, out design.DesignData.ModelId, out design.DesignData.IsHuman));
|
||||
if (!design.DesignData.IsHuman)
|
||||
if (design.DesignData.ModelId != 0 && forbidNonHuman)
|
||||
{
|
||||
PrintWarning("Model IDs different from 0 are not currently allowed, reset model id to 0.");
|
||||
design.DesignData.ModelId = 0;
|
||||
design.DesignData.IsHuman = true;
|
||||
}
|
||||
else if (!design.DesignData.IsHuman)
|
||||
{
|
||||
var arrayText = json["Array"]?.ToObject<string>() ?? string.Empty;
|
||||
design.DesignData.Customize.LoadBase64(arrayText);
|
||||
|
|
@ -366,7 +382,7 @@ public class DesignBase
|
|||
{
|
||||
var tok = json[idx.ToString()];
|
||||
var data = (CustomizeValue)(tok?["Value"]?.ToObject<byte>() ?? 0);
|
||||
PrintWarning(CustomizationService.ValidateCustomizeValue(set, design.DesignData.Customize.Face, idx, data, out data));
|
||||
PrintWarning(CustomizationService.ValidateCustomizeValue(set, design.DesignData.Customize.Face, idx, data, out data, allowUnknown));
|
||||
var apply = tok?["Apply"]?.ToObject<bool>() ?? false;
|
||||
design.DesignData.Customize[idx] = data;
|
||||
design.SetApplyCustomize(idx, apply);
|
||||
|
|
|
|||
|
|
@ -45,22 +45,28 @@ public unsafe struct DesignData
|
|||
return index > 11 ? (StainId)0 : _equipmentBytes[4 * index + 3];
|
||||
}
|
||||
|
||||
public FullEquipType MainhandType
|
||||
=> _typeMainhand;
|
||||
|
||||
public FullEquipType OffhandType
|
||||
=> _typeOffhand;
|
||||
|
||||
public readonly EquipItem Item(EquipSlot slot)
|
||||
=> slot.ToIndex() switch
|
||||
{
|
||||
// @formatter:off
|
||||
0 => new EquipItem(_nameHead, _itemIds[ 0], _iconIds[ 0], (SetId)(_equipmentBytes[ 0] | (_equipmentBytes[ 1] << 8)), (WeaponType)0, _equipmentBytes[ 2], FullEquipType.Head ),
|
||||
1 => new EquipItem(_nameBody, _itemIds[ 1], _iconIds[ 1], (SetId)(_equipmentBytes[ 4] | (_equipmentBytes[ 5] << 8)), (WeaponType)0, _equipmentBytes[ 6], FullEquipType.Body ),
|
||||
2 => new EquipItem(_nameHands, _itemIds[ 2], _iconIds[ 2], (SetId)(_equipmentBytes[ 8] | (_equipmentBytes[ 9] << 8)), (WeaponType)0, _equipmentBytes[10], FullEquipType.Hands ),
|
||||
3 => new EquipItem(_nameLegs, _itemIds[ 3], _iconIds[ 3], (SetId)(_equipmentBytes[12] | (_equipmentBytes[13] << 8)), (WeaponType)0, _equipmentBytes[14], FullEquipType.Legs ),
|
||||
4 => new EquipItem(_nameFeet, _itemIds[ 4], _iconIds[ 4], (SetId)(_equipmentBytes[16] | (_equipmentBytes[17] << 8)), (WeaponType)0, _equipmentBytes[18], FullEquipType.Feet ),
|
||||
5 => new EquipItem(_nameEars, _itemIds[ 5], _iconIds[ 5], (SetId)(_equipmentBytes[20] | (_equipmentBytes[21] << 8)), (WeaponType)0, _equipmentBytes[22], FullEquipType.Ears ),
|
||||
6 => new EquipItem(_nameNeck, _itemIds[ 6], _iconIds[ 6], (SetId)(_equipmentBytes[24] | (_equipmentBytes[25] << 8)), (WeaponType)0, _equipmentBytes[26], FullEquipType.Neck ),
|
||||
7 => new EquipItem(_nameWrists, _itemIds[ 7], _iconIds[ 7], (SetId)(_equipmentBytes[28] | (_equipmentBytes[29] << 8)), (WeaponType)0, _equipmentBytes[30], FullEquipType.Wrists ),
|
||||
8 => new EquipItem(_nameRFinger, _itemIds[ 8], _iconIds[ 8], (SetId)(_equipmentBytes[32] | (_equipmentBytes[33] << 8)), (WeaponType)0, _equipmentBytes[34], FullEquipType.Finger ),
|
||||
9 => new EquipItem(_nameLFinger, _itemIds[ 9], _iconIds[ 9], (SetId)(_equipmentBytes[36] | (_equipmentBytes[37] << 8)), (WeaponType)0, _equipmentBytes[38], FullEquipType.Finger ),
|
||||
10 => new EquipItem(_nameMainhand, _itemIds[10], _iconIds[10], (SetId)(_equipmentBytes[40] | (_equipmentBytes[41] << 8)), _secondaryMainhand, _equipmentBytes[42], _typeMainhand ),
|
||||
11 => new EquipItem(_nameOffhand, _itemIds[11], _iconIds[11], (SetId)(_equipmentBytes[44] | (_equipmentBytes[45] << 8)), _secondaryOffhand, _equipmentBytes[46], _typeOffhand ),
|
||||
0 => EquipItem.FromIds(_itemIds[ 0], _iconIds[ 0], (SetId)(_equipmentBytes[ 0] | (_equipmentBytes[ 1] << 8)), (WeaponType)0, _equipmentBytes[ 2], FullEquipType.Head, _nameHead ),
|
||||
1 => EquipItem.FromIds(_itemIds[ 1], _iconIds[ 1], (SetId)(_equipmentBytes[ 4] | (_equipmentBytes[ 5] << 8)), (WeaponType)0, _equipmentBytes[ 6], FullEquipType.Body, _nameBody ),
|
||||
2 => EquipItem.FromIds(_itemIds[ 2], _iconIds[ 2], (SetId)(_equipmentBytes[ 8] | (_equipmentBytes[ 9] << 8)), (WeaponType)0, _equipmentBytes[10], FullEquipType.Hands, _nameHands ),
|
||||
3 => EquipItem.FromIds(_itemIds[ 3], _iconIds[ 3], (SetId)(_equipmentBytes[12] | (_equipmentBytes[13] << 8)), (WeaponType)0, _equipmentBytes[14], FullEquipType.Legs, _nameLegs ),
|
||||
4 => EquipItem.FromIds(_itemIds[ 4], _iconIds[ 4], (SetId)(_equipmentBytes[16] | (_equipmentBytes[17] << 8)), (WeaponType)0, _equipmentBytes[18], FullEquipType.Feet, _nameFeet ),
|
||||
5 => EquipItem.FromIds(_itemIds[ 5], _iconIds[ 5], (SetId)(_equipmentBytes[20] | (_equipmentBytes[21] << 8)), (WeaponType)0, _equipmentBytes[22], FullEquipType.Ears, _nameEars ),
|
||||
6 => EquipItem.FromIds(_itemIds[ 6], _iconIds[ 6], (SetId)(_equipmentBytes[24] | (_equipmentBytes[25] << 8)), (WeaponType)0, _equipmentBytes[26], FullEquipType.Neck, _nameNeck ),
|
||||
7 => EquipItem.FromIds(_itemIds[ 7], _iconIds[ 7], (SetId)(_equipmentBytes[28] | (_equipmentBytes[29] << 8)), (WeaponType)0, _equipmentBytes[30], FullEquipType.Wrists, _nameWrists ),
|
||||
8 => EquipItem.FromIds(_itemIds[ 8], _iconIds[ 8], (SetId)(_equipmentBytes[32] | (_equipmentBytes[33] << 8)), (WeaponType)0, _equipmentBytes[34], FullEquipType.Finger, _nameRFinger ),
|
||||
9 => EquipItem.FromIds(_itemIds[ 9], _iconIds[ 9], (SetId)(_equipmentBytes[36] | (_equipmentBytes[37] << 8)), (WeaponType)0, _equipmentBytes[38], FullEquipType.Finger, _nameLFinger ),
|
||||
10 => EquipItem.FromIds(_itemIds[10], _iconIds[10], (SetId)(_equipmentBytes[40] | (_equipmentBytes[41] << 8)), _secondaryMainhand, _equipmentBytes[42], _typeMainhand, _nameMainhand),
|
||||
11 => EquipItem.FromIds(_itemIds[11], _iconIds[11], (SetId)(_equipmentBytes[44] | (_equipmentBytes[45] << 8)), _secondaryOffhand, _equipmentBytes[46], _typeOffhand, _nameOffhand ),
|
||||
_ => new EquipItem(),
|
||||
// @formatter:on
|
||||
};
|
||||
|
|
@ -86,10 +92,10 @@ public unsafe struct DesignData
|
|||
public bool SetItem(EquipSlot slot, EquipItem item)
|
||||
{
|
||||
var index = slot.ToIndex();
|
||||
if (index > 11 || _itemIds[index] == item.Id)
|
||||
if (index > 11)
|
||||
return false;
|
||||
|
||||
_itemIds[index] = item.Id;
|
||||
_itemIds[index] = item.ItemId;
|
||||
_iconIds[index] = item.IconId;
|
||||
_equipmentBytes[4 * index + 0] = (byte)item.ModelId;
|
||||
_equipmentBytes[4 * index + 1] = (byte)(item.ModelId.Value >> 8);
|
||||
|
|
@ -212,7 +218,7 @@ public unsafe struct DesignData
|
|||
Customize.Load(customize);
|
||||
fixed (byte* ptr = _equipmentBytes)
|
||||
{
|
||||
MemoryUtility.MemCpyUnchecked(ptr, (byte*) equipData, 40);
|
||||
MemoryUtility.MemCpyUnchecked(ptr, (byte*)equipData, 40);
|
||||
}
|
||||
|
||||
SetHatVisible(true);
|
||||
|
|
@ -228,16 +234,16 @@ public unsafe struct DesignData
|
|||
MemoryUtility.MemSet(ptr, 0, 10 * 2);
|
||||
}
|
||||
|
||||
_nameHead = string.Empty;
|
||||
_nameBody = string.Empty;
|
||||
_nameHands = string.Empty;
|
||||
_nameLegs = string.Empty;
|
||||
_nameFeet = string.Empty;
|
||||
_nameEars = string.Empty;
|
||||
_nameNeck = string.Empty;
|
||||
_nameWrists = string.Empty;
|
||||
_nameRFinger = string.Empty;
|
||||
_nameLFinger = string.Empty;
|
||||
_nameHead = string.Empty;
|
||||
_nameBody = string.Empty;
|
||||
_nameHands = string.Empty;
|
||||
_nameLegs = string.Empty;
|
||||
_nameFeet = string.Empty;
|
||||
_nameEars = string.Empty;
|
||||
_nameNeck = string.Empty;
|
||||
_nameWrists = string.Empty;
|
||||
_nameRFinger = string.Empty;
|
||||
_nameLFinger = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ using Newtonsoft.Json.Linq;
|
|||
using OtterGui;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using static OtterGui.Raii.ImRaii;
|
||||
|
||||
namespace Glamourer.Designs;
|
||||
|
||||
|
|
@ -260,28 +259,6 @@ public class DesignManager
|
|||
_event.Invoke(DesignChanged.Type.WriteProtection, design, value);
|
||||
}
|
||||
|
||||
public void ChangeModelId(Design design, uint modelId, Customize customize, nint equipData, bool isHuman)
|
||||
{
|
||||
var oldValue = design.DesignData.ModelId;
|
||||
|
||||
if (!isHuman)
|
||||
{
|
||||
design.DesignData.LoadNonHuman(modelId, customize, equipData);
|
||||
}
|
||||
else if (!design.DesignData.IsHuman)
|
||||
{
|
||||
design.DesignData.IsHuman = true;
|
||||
design.DesignData.ModelId = modelId;
|
||||
design.DesignData.SetDefaultEquipment(_items);
|
||||
design.DesignData.Customize = Customize.Default;
|
||||
}
|
||||
|
||||
design.LastEdit = DateTimeOffset.UtcNow;
|
||||
Glamourer.Log.Debug($"Changed model id in design {design.Identifier} from {oldValue} to {modelId}.");
|
||||
_saveService.QueueSave(design);
|
||||
_event.Invoke(DesignChanged.Type.ModelId, design, (oldValue, modelId));
|
||||
}
|
||||
|
||||
/// <summary> Change a customization value. </summary>
|
||||
public void ChangeCustomize(Design design, CustomizeIndex idx, CustomizeValue value)
|
||||
{
|
||||
|
|
@ -332,7 +309,7 @@ public class DesignManager
|
|||
/// <summary> Change a non-weapon equipment piece. </summary>
|
||||
public void ChangeEquip(Design design, EquipSlot slot, EquipItem item)
|
||||
{
|
||||
if (!_items.IsItemValid(slot, item.Id, out item))
|
||||
if (!_items.IsItemValid(slot, item.ItemId, out item))
|
||||
return;
|
||||
|
||||
var old = design.DesignData.Item(slot);
|
||||
|
|
@ -341,7 +318,7 @@ public class DesignManager
|
|||
|
||||
design.LastEdit = DateTimeOffset.UtcNow;
|
||||
Glamourer.Log.Debug(
|
||||
$"Set {slot.ToName()} equipment piece in design {design.Identifier} from {old.Name} ({old.Id}) to {item.Name} ({item.Id}).");
|
||||
$"Set {slot.ToName()} equipment piece in design {design.Identifier} from {old.Name} ({old.ItemId}) to {item.Name} ({item.ItemId}).");
|
||||
_saveService.QueueSave(design);
|
||||
_event.Invoke(DesignChanged.Type.Equip, design, (old, item, slot));
|
||||
}
|
||||
|
|
@ -355,13 +332,13 @@ public class DesignManager
|
|||
{
|
||||
case EquipSlot.MainHand:
|
||||
var newOff = currentOff;
|
||||
if (!_items.IsItemValid(EquipSlot.MainHand, item.Id, out item))
|
||||
if (!_items.IsItemValid(EquipSlot.MainHand, item.ItemId, out item))
|
||||
return;
|
||||
|
||||
if (item.Type != currentMain.Type)
|
||||
{
|
||||
var newOffId = item.Type.Offhand().IsOffhandType()
|
||||
? item.Id
|
||||
? item.ItemId
|
||||
: ItemManager.NothingId(item.Type.Offhand());
|
||||
if (!_items.IsOffhandValid(item, newOffId, out newOff))
|
||||
return;
|
||||
|
|
@ -373,12 +350,12 @@ public class DesignManager
|
|||
design.LastEdit = DateTimeOffset.UtcNow;
|
||||
_saveService.QueueSave(design);
|
||||
Glamourer.Log.Debug(
|
||||
$"Set {EquipSlot.MainHand.ToName()} weapon in design {design.Identifier} from {currentMain.Name} ({currentMain.Id}) to {item.Name} ({item.Id}).");
|
||||
$"Set {EquipSlot.MainHand.ToName()} weapon in design {design.Identifier} from {currentMain.Name} ({currentMain.ItemId}) to {item.Name} ({item.ItemId}).");
|
||||
_event.Invoke(DesignChanged.Type.Weapon, design, (currentMain, currentOff, item, newOff));
|
||||
|
||||
return;
|
||||
case EquipSlot.OffHand:
|
||||
if (!_items.IsOffhandValid(currentOff.Type, item.Id, out item))
|
||||
if (!_items.IsOffhandValid(currentOff.Type, item.ItemId, out item))
|
||||
return;
|
||||
|
||||
if (!design.DesignData.SetItem(EquipSlot.OffHand, item))
|
||||
|
|
@ -387,7 +364,7 @@ public class DesignManager
|
|||
design.LastEdit = DateTimeOffset.UtcNow;
|
||||
_saveService.QueueSave(design);
|
||||
Glamourer.Log.Debug(
|
||||
$"Set {EquipSlot.OffHand.ToName()} weapon in design {design.Identifier} from {currentOff.Name} ({currentOff.Id}) to {item.Name} ({item.Id}).");
|
||||
$"Set {EquipSlot.OffHand.ToName()} weapon in design {design.Identifier} from {currentOff.Name} ({currentOff.ItemId}) to {item.Name} ({item.ItemId}).");
|
||||
_event.Invoke(DesignChanged.Type.Weapon, design, (currentMain, currentOff, currentMain, item));
|
||||
return;
|
||||
default: return;
|
||||
|
|
@ -409,7 +386,7 @@ public class DesignManager
|
|||
/// <summary> Change the stain for any equipment piece. </summary>
|
||||
public void ChangeStain(Design design, EquipSlot slot, StainId stain)
|
||||
{
|
||||
if (_items.ValidateStain(stain, out _).Length > 0)
|
||||
if (_items.ValidateStain(stain, out _, false).Length > 0)
|
||||
return;
|
||||
|
||||
var oldStain = design.DesignData.Stain(slot);
|
||||
|
|
@ -477,9 +454,6 @@ public class DesignManager
|
|||
/// <summary> Apply an entire design based on its appliance rules piece by piece. </summary>
|
||||
public void ApplyDesign(Design design, DesignBase other)
|
||||
{
|
||||
ChangeModelId(design, other.DesignData.ModelId, other.DesignData.Customize, other.DesignData.GetEquipmentPtr(),
|
||||
other.DesignData.IsHuman);
|
||||
|
||||
if (other.DoApplyWetness())
|
||||
design.DesignData.SetIsWet(other.DesignData.IsWet());
|
||||
if (other.DoApplyHatVisible())
|
||||
|
|
|
|||
|
|
@ -46,9 +46,6 @@ public sealed class DesignChanged : EventWrapper<Action<DesignChanged.Type, Desi
|
|||
/// <summary> An existing design had an existing associated mod removed. Data is the Mod and its Settings [(Mod, ModSettings)]. </summary>
|
||||
RemovedMod,
|
||||
|
||||
/// <summary> An existing design had its model id changed. This means everything else might also have changed. Data is the old value and the new value. [(uint, uint)]. </summary>
|
||||
ModelId,
|
||||
|
||||
/// <summary> An existing design had a customization changed. Data is the old value, the new value and the type [(CustomizeValue, CustomizeValue, CustomizeIndex)]. </summary>
|
||||
Customize,
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.Customization;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Raii;
|
||||
|
|
@ -14,19 +15,33 @@ public partial class CustomizationDrawer
|
|||
{
|
||||
using var _ = SetId(index);
|
||||
var (current, custom) = GetCurrentCustomization(index);
|
||||
var color = ImGui.ColorConvertU32ToFloat4(custom.Color);
|
||||
|
||||
// Print 1-based index instead of 0.
|
||||
if (ImGui.ColorButton($"{current + 1}##color", color, ImGuiColorEditFlags.None, _framedIconSize))
|
||||
ImGui.OpenPopup(ColorPickerPopupName);
|
||||
var color = ImGui.ColorConvertU32ToFloat4(current < 0 ? ImGui.GetColorU32(ImGuiCol.FrameBg) : custom.Color);
|
||||
|
||||
using (var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * ImGuiHelpers.GlobalScale, current < 0))
|
||||
{
|
||||
// Print 1-based index instead of 0.
|
||||
if (ImGui.ColorButton($"{current + 1}##color", color, ImGuiColorEditFlags.None, _framedIconSize))
|
||||
ImGui.OpenPopup(ColorPickerPopupName);
|
||||
}
|
||||
|
||||
if (current < 0)
|
||||
{
|
||||
using var font = ImRaii.PushFont(UiBuilder.IconFont);
|
||||
var size = ImGui.CalcTextSize(FontAwesomeIcon.Question.ToIconString());
|
||||
var pos = ImGui.GetItemRectMin() + (ImGui.GetItemRectSize() - size) / 2;
|
||||
ImGui.GetWindowDrawList().AddText(pos, ImGui.GetColorU32(ImGuiCol.Text), FontAwesomeIcon.Question.ToIconString());
|
||||
current = 0;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
using (var group = ImRaii.Group())
|
||||
{
|
||||
DataInputInt(current);
|
||||
ImGui.TextUnformatted(_currentOption);
|
||||
ImGui.TextUnformatted(custom.Color == 0 ? $"{_currentOption} (Custom #{custom.Value})" : _currentOption);
|
||||
}
|
||||
|
||||
DrawColorPickerPopup();
|
||||
}
|
||||
|
||||
|
|
@ -57,8 +72,8 @@ public partial class CustomizationDrawer
|
|||
{
|
||||
var current = _set.DataByValue(index, _customize[index], out var custom, _customize.Face);
|
||||
if (_set.IsAvailable(index) && current < 0)
|
||||
throw new Exception($"Read invalid customization value {_customize[index]} for {index}.");
|
||||
return (current, new CustomizeData(index, _customize[index], 0, 0));
|
||||
|
||||
return (current, custom!.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,21 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Plugin;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using CustomizeData = Penumbra.GameData.Structs.CustomizeData;
|
||||
|
||||
namespace Glamourer.Gui.Customization;
|
||||
|
||||
public partial class CustomizationDrawer : IDisposable
|
||||
{
|
||||
private readonly CodeService _codes;
|
||||
|
||||
private readonly Vector4 _redTint = new(0.6f, 0.3f, 0.3f, 1f);
|
||||
private readonly ImGuiScene.TextureWrap? _legacyTattoo;
|
||||
|
||||
|
|
@ -38,9 +42,10 @@ public partial class CustomizationDrawer : IDisposable
|
|||
|
||||
private readonly CustomizationService _service;
|
||||
|
||||
public CustomizationDrawer(DalamudPluginInterface pi, CustomizationService service)
|
||||
public CustomizationDrawer(DalamudPluginInterface pi, CustomizationService service, CodeService codes)
|
||||
{
|
||||
_service = service;
|
||||
_codes = codes;
|
||||
_legacyTattoo = GetLegacyTattooIcon(pi);
|
||||
_customize = Customize.Default;
|
||||
}
|
||||
|
|
@ -100,6 +105,9 @@ public partial class CustomizationDrawer : IDisposable
|
|||
|
||||
try
|
||||
{
|
||||
if (_codes.EnabledArtisan)
|
||||
return DrawArtisan();
|
||||
|
||||
DrawRaceGenderSelector();
|
||||
_set = _service.AwaitedService.GetList(_customize.Clan, _customize.Gender);
|
||||
|
||||
|
|
@ -129,6 +137,31 @@ public partial class CustomizationDrawer : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private unsafe bool DrawArtisan()
|
||||
{
|
||||
for (var i = 0; i < CustomizeData.Size; ++i)
|
||||
{
|
||||
using var id = ImRaii.PushId(i);
|
||||
int value = _customize.Data.Data[i];
|
||||
ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale);
|
||||
if (!ImGui.InputInt(string.Empty, ref value, 0, 0))
|
||||
continue;
|
||||
|
||||
var newValue = (byte)Math.Clamp(value, 0, byte.MaxValue);
|
||||
if (newValue != _customize.Data.Data[i])
|
||||
foreach (var flag in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
var (j, mask) = flag.ToByteAndMask();
|
||||
if (j == i)
|
||||
Changed |= flag.ToFlag();
|
||||
}
|
||||
|
||||
_customize.Data.Data[i] = newValue;
|
||||
}
|
||||
|
||||
return Changed != 0;
|
||||
}
|
||||
|
||||
private void UpdateSizes()
|
||||
{
|
||||
_iconSize = new Vector2(ImGui.GetTextLineHeightWithSpacing() * 2);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using Glamourer.Designs;
|
|||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
@ -22,10 +23,13 @@ public class EquipmentDrawer
|
|||
private readonly StainData _stainData;
|
||||
private readonly ItemCombo[] _itemCombo;
|
||||
private readonly Dictionary<FullEquipType, WeaponCombo> _weaponCombo;
|
||||
private readonly CodeService _codes;
|
||||
|
||||
public EquipmentDrawer(DataManager gameData, ItemManager items)
|
||||
|
||||
public EquipmentDrawer(DataManager gameData, ItemManager items, CodeService codes)
|
||||
{
|
||||
_items = items;
|
||||
_codes = codes;
|
||||
_stainData = items.Stains;
|
||||
_stainCombo = new FilterComboColors(140,
|
||||
_stainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))));
|
||||
|
|
@ -57,9 +61,12 @@ public class EquipmentDrawer
|
|||
public bool DrawArmor(EquipItem current, EquipSlot slot, out EquipItem armor, Gender gender = Gender.Unknown, Race race = Race.Unknown)
|
||||
{
|
||||
Debug.Assert(slot.IsEquipment() || slot.IsAccessory(), $"Called {nameof(DrawArmor)} on {slot}.");
|
||||
if (_codes.EnabledArtisan)
|
||||
return DrawArmorArtisan(current, slot, out armor, gender, race);
|
||||
|
||||
var combo = _itemCombo[slot.ToIndex()];
|
||||
armor = current;
|
||||
var change = combo.Draw(VerifyRestrictedGear(armor, slot, gender, race), armor.Id, 320 * ImGuiHelpers.GlobalScale);
|
||||
var change = combo.Draw(VerifyRestrictedGear(armor, slot, gender, race), armor.ItemId, 320 * ImGuiHelpers.GlobalScale);
|
||||
if (armor.ModelId.Value != 0)
|
||||
{
|
||||
ImGuiUtil.HoverTooltip("Right-click to clear.");
|
||||
|
|
@ -81,18 +88,82 @@ public class EquipmentDrawer
|
|||
return change;
|
||||
}
|
||||
|
||||
public bool DrawStain(StainId current, EquipSlot slot, out Stain stain)
|
||||
public bool DrawArmorArtisan(EquipItem current, EquipSlot slot, out EquipItem armor, Gender gender = Gender.Unknown,
|
||||
Race race = Race.Unknown)
|
||||
{
|
||||
var found = _stainData.TryGetValue(current, out stain);
|
||||
using var id = ImRaii.PushId((int)slot);
|
||||
int setId = current.ModelId.Value;
|
||||
int variant = current.Variant;
|
||||
var ret = false;
|
||||
armor = current;
|
||||
ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.InputInt("##setId", ref setId, 0, 0))
|
||||
{
|
||||
var newSetId = (SetId)Math.Clamp(setId, 0, ushort.MaxValue);
|
||||
if (newSetId.Value != current.ModelId.Value)
|
||||
{
|
||||
armor = _items.Identify(slot, newSetId, current.Variant);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.InputInt("##variant", ref variant, 0, 0))
|
||||
{
|
||||
var newVariant = (byte)Math.Clamp(variant, 0, byte.MaxValue);
|
||||
if (newVariant != current.Variant)
|
||||
{
|
||||
armor = _items.Identify(slot, current.ModelId, newVariant);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool DrawStain(StainId current, EquipSlot slot, out StainId ret)
|
||||
{
|
||||
if (_codes.EnabledArtisan)
|
||||
return DrawStainArtisan(current, slot, out ret);
|
||||
|
||||
var found = _stainData.TryGetValue(current, out var stain);
|
||||
var change = _stainCombo.Draw($"##stain{slot}", stain.RgbaColor, stain.Name, found);
|
||||
ImGuiUtil.HoverTooltip("Right-click to clear.");
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
stain = Stain.None;
|
||||
ret = stain.RowIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
return change && _stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out stain);
|
||||
if (change && _stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out stain))
|
||||
{
|
||||
ret = stain.RowIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
ret = current;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool DrawStainArtisan(StainId current, EquipSlot slot, out StainId stain)
|
||||
{
|
||||
using var id = ImRaii.PushId((int)slot);
|
||||
int stainId = current.Value;
|
||||
ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.InputInt("##stain", ref stainId, 0, 0))
|
||||
{
|
||||
var newStainId = (StainId)Math.Clamp(stainId, 0, byte.MaxValue);
|
||||
if (newStainId != current)
|
||||
{
|
||||
stain = newStainId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
stain = current;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool DrawMainhand(EquipItem current, bool drawAll, out EquipItem weapon)
|
||||
|
|
@ -101,7 +172,7 @@ public class EquipmentDrawer
|
|||
if (!_weaponCombo.TryGetValue(drawAll ? FullEquipType.Unknown : current.Type, out var combo))
|
||||
return false;
|
||||
|
||||
if (!combo.Draw(weapon.Name, weapon.Id, 320 * ImGuiHelpers.GlobalScale))
|
||||
if (!combo.Draw(weapon.Name, weapon.ItemId, 320 * ImGuiHelpers.GlobalScale))
|
||||
return false;
|
||||
|
||||
weapon = combo.CurrentSelection;
|
||||
|
|
@ -118,7 +189,7 @@ public class EquipmentDrawer
|
|||
if (!_weaponCombo.TryGetValue(offType, out var combo))
|
||||
return false;
|
||||
|
||||
var change = combo.Draw(weapon.Name, weapon.Id, 320 * ImGuiHelpers.GlobalScale);
|
||||
var change = combo.Draw(weapon.Name, weapon.ItemId, 320 * ImGuiHelpers.GlobalScale);
|
||||
if (!offType.IsOffhandType() && weapon.ModelId.Value != 0)
|
||||
{
|
||||
ImGuiUtil.HoverTooltip("Right-click to clear.");
|
||||
|
|
|
|||
|
|
@ -34,10 +34,10 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
|
|||
|
||||
protected override int UpdateCurrentSelected(int currentSelected)
|
||||
{
|
||||
if (CurrentSelection.Id == _currentItem)
|
||||
if (CurrentSelection.ItemId == _currentItem)
|
||||
return currentSelected;
|
||||
|
||||
CurrentSelectionIdx = Items.IndexOf(i => i.Id == _currentItem);
|
||||
CurrentSelectionIdx = Items.IndexOf(i => i.ItemId == _currentItem);
|
||||
CurrentSelection = CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : default;
|
||||
return base.UpdateCurrentSelected(CurrentSelectionIdx);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
|
|||
|
||||
protected override int UpdateCurrentSelected(int currentSelected)
|
||||
{
|
||||
if (CurrentSelection.Id == _currentItemId)
|
||||
if (CurrentSelection.ItemId == _currentItemId)
|
||||
return currentSelected;
|
||||
|
||||
CurrentSelectionIdx = Items.IndexOf(i => i.Id == _currentItemId);
|
||||
CurrentSelectionIdx = Items.IndexOf(i => i.ItemId == _currentItemId);
|
||||
CurrentSelection = CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : default;
|
||||
return base.UpdateCurrentSelected(CurrentSelectionIdx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ public class PenumbraChangedItemTooltip : IDisposable
|
|||
else
|
||||
{
|
||||
var oldItem = state.ModelData.Item(slot);
|
||||
if (oldItem.Id != item.Id)
|
||||
if (oldItem.ItemId != item.ItemId)
|
||||
_lastItems[slot.ToIndex()] = oldItem;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,33 +131,33 @@ public class ActorPanel
|
|||
{
|
||||
var stain = _state.ModelData.Stain(slot);
|
||||
if (_equipmentDrawer.DrawStain(stain, slot, out var newStain))
|
||||
_stateManager.ChangeStain(_state, slot, newStain.RowIndex, StateChanged.Source.Manual);
|
||||
_stateManager.ChangeStain(_state, slot, newStain, StateChanged.Source.Manual);
|
||||
|
||||
ImGui.SameLine();
|
||||
var armor = _state.ModelData.Item(slot);
|
||||
if (_equipmentDrawer.DrawArmor(armor, slot, out var newArmor, _state.ModelData.Customize.Gender, _state.ModelData.Customize.Race))
|
||||
_stateManager.ChangeEquip(_state, slot, newArmor, newStain.RowIndex, StateChanged.Source.Manual);
|
||||
_stateManager.ChangeEquip(_state, slot, newArmor, newStain, StateChanged.Source.Manual);
|
||||
}
|
||||
|
||||
var mhStain = _state.ModelData.Stain(EquipSlot.MainHand);
|
||||
if (_equipmentDrawer.DrawStain(mhStain, EquipSlot.MainHand, out var newMhStain))
|
||||
_stateManager.ChangeStain(_state, EquipSlot.MainHand, newMhStain.RowIndex, StateChanged.Source.Manual);
|
||||
_stateManager.ChangeStain(_state, EquipSlot.MainHand, newMhStain, StateChanged.Source.Manual);
|
||||
|
||||
ImGui.SameLine();
|
||||
var mh = _state.ModelData.Item(EquipSlot.MainHand);
|
||||
if (_equipmentDrawer.DrawMainhand(mh, false, out var newMh))
|
||||
_stateManager.ChangeEquip(_state, EquipSlot.MainHand, newMh, newMhStain.RowIndex, StateChanged.Source.Manual);
|
||||
_stateManager.ChangeEquip(_state, EquipSlot.MainHand, newMh, newMhStain, StateChanged.Source.Manual);
|
||||
|
||||
if (newMh.Type.Offhand() is not FullEquipType.Unknown)
|
||||
{
|
||||
var ohStain = _state.ModelData.Stain(EquipSlot.OffHand);
|
||||
if (_equipmentDrawer.DrawStain(ohStain, EquipSlot.OffHand, out var newOhStain))
|
||||
_stateManager.ChangeStain(_state, EquipSlot.OffHand, newOhStain.RowIndex, StateChanged.Source.Manual);
|
||||
_stateManager.ChangeStain(_state, EquipSlot.OffHand, newOhStain, StateChanged.Source.Manual);
|
||||
|
||||
ImGui.SameLine();
|
||||
var oh = _state.ModelData.Item(EquipSlot.OffHand);
|
||||
if (_equipmentDrawer.DrawMainhand(oh, false, out var newOh))
|
||||
_stateManager.ChangeEquip(_state, EquipSlot.OffHand, newOh, newOhStain.RowIndex, StateChanged.Source.Manual);
|
||||
_stateManager.ChangeEquip(_state, EquipSlot.OffHand, newOh, newOhStain, StateChanged.Source.Manual);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ public class SetPanel
|
|||
continue;
|
||||
|
||||
var item = design.Design.DesignData.Item(slot);
|
||||
if (!_itemUnlocks.IsUnlocked(item.Id, out _))
|
||||
if (!_itemUnlocks.IsUnlocked(item.ItemId, out _))
|
||||
sb.AppendLine($"{item.Name} in {slot.ToName()} slot is not unlocked but should be applied.");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -155,6 +155,15 @@ public unsafe class DebugTab : ITab
|
|||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable(model.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
if (actor.IsCharacter)
|
||||
{
|
||||
if (actor.AsCharacter->CharacterData.TransformationId != 0)
|
||||
ImGui.TextUnformatted($"Transformation Id: {actor.AsCharacter->CharacterData.TransformationId}");
|
||||
if (actor.AsCharacter->CharacterData.ModelCharaId_2 != -1)
|
||||
ImGui.TextUnformatted($"ModelChara2 {actor.AsCharacter->CharacterData.ModelCharaId_2}");
|
||||
if (actor.AsCharacter->CharacterData.StatusEffectVFXId != 0)
|
||||
ImGui.TextUnformatted($"Status Id: {actor.AsCharacter->CharacterData.StatusEffectVFXId}");
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Mainhand");
|
||||
ImGuiUtil.DrawTableColumn(actor.IsCharacter ? actor.GetMainhand().ToString() : "No Character");
|
||||
|
|
@ -712,7 +721,7 @@ public unsafe class DebugTab : ITab
|
|||
return;
|
||||
|
||||
disabled.Dispose();
|
||||
ImRaii.TreeNode($"Default Sword: {_items.DefaultSword.Name} ({_items.DefaultSword.Id}) ({_items.DefaultSword.Weapon()})",
|
||||
ImRaii.TreeNode($"Default Sword: {_items.DefaultSword.Name} ({_items.DefaultSword.ItemId}) ({_items.DefaultSword.Weapon()})",
|
||||
ImGuiTreeNodeFlags.Leaf).Dispose();
|
||||
DrawNameTable("All Items (Main)", ref _itemFilter,
|
||||
_items.ItemService.AwaitedService.AllItems(true).Select(p => (p.Item1,
|
||||
|
|
@ -726,7 +735,7 @@ public unsafe class DebugTab : ITab
|
|||
{
|
||||
DrawNameTable(type.ToName(), ref _itemFilter,
|
||||
_items.ItemService.AwaitedService[type]
|
||||
.Select(p => (p.Id, $"{p.Name} ({(p.WeaponType == 0 ? p.Armor().ToString() : p.Weapon().ToString())})")));
|
||||
.Select(p => (Id: p.ItemId, $"{p.Name} ({(p.WeaponType == 0 ? p.Armor().ToString() : p.Weapon().ToString())})")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1091,7 +1100,7 @@ public unsafe class DebugTab : ITab
|
|||
var stain = data.Stain(slot);
|
||||
ImGuiUtil.DrawTableColumn(slot.ToName());
|
||||
ImGuiUtil.DrawTableColumn(item.Name);
|
||||
ImGuiUtil.DrawTableColumn(item.Id.ToString());
|
||||
ImGuiUtil.DrawTableColumn(item.ItemId.ToString());
|
||||
ImGuiUtil.DrawTableColumn(stain.ToString());
|
||||
}
|
||||
|
||||
|
|
@ -1175,7 +1184,7 @@ public unsafe class DebugTab : ITab
|
|||
var applyStain = design.DoApplyStain(slot);
|
||||
ImGuiUtil.DrawTableColumn(slot.ToName());
|
||||
ImGuiUtil.DrawTableColumn(item.Name);
|
||||
ImGuiUtil.DrawTableColumn(item.Id.ToString());
|
||||
ImGuiUtil.DrawTableColumn(item.ItemId.ToString());
|
||||
ImGuiUtil.DrawTableColumn(apply ? "Apply" : "Keep");
|
||||
ImGuiUtil.DrawTableColumn(stain.ToString());
|
||||
ImGuiUtil.DrawTableColumn(applyStain ? "Apply" : "Keep");
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ public class DesignPanel
|
|||
{
|
||||
var stain = _selector.Selected!.DesignData.Stain(slot);
|
||||
if (_equipmentDrawer.DrawStain(stain, slot, out var newStain))
|
||||
_manager.ChangeStain(_selector.Selected!, slot, newStain.RowIndex);
|
||||
_manager.ChangeStain(_selector.Selected!, slot, newStain);
|
||||
|
||||
ImGui.SameLine();
|
||||
var armor = _selector.Selected!.DesignData.Item(slot);
|
||||
|
|
@ -142,7 +142,7 @@ public class DesignPanel
|
|||
|
||||
var mhStain = _selector.Selected!.DesignData.Stain(EquipSlot.MainHand);
|
||||
if (_equipmentDrawer.DrawStain(mhStain, EquipSlot.MainHand, out var newMhStain))
|
||||
_manager.ChangeStain(_selector.Selected!, EquipSlot.MainHand, newMhStain.RowIndex);
|
||||
_manager.ChangeStain(_selector.Selected!, EquipSlot.MainHand, newMhStain);
|
||||
|
||||
ImGui.SameLine();
|
||||
var mh = _selector.Selected!.DesignData.Item(EquipSlot.MainHand);
|
||||
|
|
@ -153,7 +153,7 @@ public class DesignPanel
|
|||
{
|
||||
var ohStain = _selector.Selected!.DesignData.Stain(EquipSlot.OffHand);
|
||||
if (_equipmentDrawer.DrawStain(ohStain, EquipSlot.OffHand, out var newOhStain))
|
||||
_manager.ChangeStain(_selector.Selected!, EquipSlot.OffHand, newOhStain.RowIndex);
|
||||
_manager.ChangeStain(_selector.Selected!, EquipSlot.OffHand, newOhStain);
|
||||
|
||||
ImGui.SameLine();
|
||||
var oh = _selector.Selected!.DesignData.Item(EquipSlot.OffHand);
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ public class UnlockOverview
|
|||
|
||||
void DrawItem(EquipItem item)
|
||||
{
|
||||
var unlocked = _itemUnlocks.IsUnlocked(item.Id, out var time);
|
||||
var unlocked = _itemUnlocks.IsUnlocked(item.ItemId, out var time);
|
||||
var iconHandle = _textureCache.LoadIcon(item.IconId);
|
||||
if (!iconHandle.HasValue)
|
||||
return;
|
||||
|
|
@ -179,7 +179,7 @@ public class UnlockOverview
|
|||
ImGui.TextUnformatted($"{item.Type.ToName()} ({slot.ToName()})");
|
||||
if (item.Type.Offhand().IsOffhandType())
|
||||
ImGui.TextUnformatted(
|
||||
$"{item.Weapon()}{(_items.ItemService.AwaitedService.TryGetValue(item.Id, false, out var offhand) ? $" | {offhand.Weapon()}" : string.Empty)}");
|
||||
$"{item.Weapon()}{(_items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand) ? $" | {offhand.Weapon()}" : string.Empty)}");
|
||||
else
|
||||
ImGui.TextUnformatted(slot is EquipSlot.MainHand ? $"{item.Weapon()}" : $"{item.Armor()}");
|
||||
ImGui.TextUnformatted(
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
|
||||
public override void DrawColumn(EquipItem item, int idx)
|
||||
{
|
||||
if (!_unlocks.IsUnlocked(item.Id, out var time))
|
||||
if (!_unlocks.IsUnlocked(item.ItemId, out var time))
|
||||
return;
|
||||
|
||||
ImGui.AlignTextToFramePadding();
|
||||
|
|
@ -202,8 +202,8 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
|
||||
public override int Compare(EquipItem lhs, EquipItem rhs)
|
||||
{
|
||||
var unlockedLhs = _unlocks.IsUnlocked(lhs.Id, out var timeLhs);
|
||||
var unlockedRhs = _unlocks.IsUnlocked(rhs.Id, out var timeRhs);
|
||||
var unlockedLhs = _unlocks.IsUnlocked(lhs.ItemId, out var timeLhs);
|
||||
var unlockedRhs = _unlocks.IsUnlocked(rhs.ItemId, out var timeRhs);
|
||||
var c1 = unlockedLhs.CompareTo(unlockedRhs);
|
||||
return c1 != 0 ? c1 : timeLhs.CompareTo(timeRhs);
|
||||
}
|
||||
|
|
@ -215,15 +215,15 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
=> 70 * ImGuiHelpers.GlobalScale;
|
||||
|
||||
public override int Compare(EquipItem lhs, EquipItem rhs)
|
||||
=> lhs.Id.CompareTo(rhs.Id);
|
||||
=> lhs.ItemId.CompareTo(rhs.ItemId);
|
||||
|
||||
public override string ToName(EquipItem item)
|
||||
=> item.Id.ToString();
|
||||
=> item.ItemId.ToString();
|
||||
|
||||
public override void DrawColumn(EquipItem item, int _)
|
||||
{
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGuiUtil.RightAlign(item.Id.ToString());
|
||||
ImGuiUtil.RightAlign(item.ItemId.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -243,7 +243,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
ImGuiUtil.RightAlign(item.ModelString);
|
||||
if (ImGui.IsItemHovered()
|
||||
&& item.Type.Offhand().IsOffhandType()
|
||||
&& _items.ItemService.AwaitedService.TryGetValue(item.Id, false, out var offhand))
|
||||
&& _items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand))
|
||||
{
|
||||
using var tt = ImRaii.Tooltip();
|
||||
ImGui.TextUnformatted("Offhand: " + offhand.ModelString);
|
||||
|
|
@ -261,7 +261,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
|
|||
if (FilterRegex?.IsMatch(item.ModelString) ?? item.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
|
||||
if (item.Type.Offhand().IsOffhandType() && _items.ItemService.AwaitedService.TryGetValue(item.Id, false, out var offhand))
|
||||
if (item.Type.Offhand().IsOffhandType() && _items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand))
|
||||
return FilterRegex?.IsMatch(offhand.ModelString)
|
||||
?? offhand.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public class JobService : IDisposable
|
|||
public readonly IReadOnlyDictionary<byte, Job> Jobs;
|
||||
public readonly IReadOnlyDictionary<ushort, JobGroup> JobGroups;
|
||||
|
||||
public event Action<Actor, Job>? JobChanged;
|
||||
public event Action<Actor, Job, Job>? JobChanged;
|
||||
|
||||
public JobService(DataManager gameData)
|
||||
{
|
||||
|
|
@ -40,10 +40,12 @@ public class JobService : IDisposable
|
|||
|
||||
private void ChangeJobDetour(nint data, uint jobIndex)
|
||||
{
|
||||
var old = ((Actor)(data - _characterDataOffset)).Job;
|
||||
_changeJobHook.Original(data, jobIndex);
|
||||
var actor = (Actor)(data - _characterDataOffset);
|
||||
var job = Jobs.TryGetValue((byte) jobIndex, out var j) ? j : Jobs[0];
|
||||
Glamourer.Log.Excessive($"{actor} changed job to {job}");
|
||||
JobChanged?.Invoke(actor, job);
|
||||
var actor = (Actor)(data - _characterDataOffset);
|
||||
var job = Jobs.TryGetValue((byte)jobIndex, out var j) ? j : Jobs[0];
|
||||
var oldJob = Jobs.TryGetValue(old, out var o) ? o : Jobs[0];
|
||||
Glamourer.Log.Excessive($"{actor} changed job from {oldJob} to {job}");
|
||||
JobChanged?.Invoke(actor, oldJob, job);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,9 +26,13 @@ public class CodeService
|
|||
public Race EnabledOops { get; private set; }
|
||||
public bool EnabledMesmer { get; private set; }
|
||||
public bool EnabledInventory { get; private set; }
|
||||
public bool EnabledArtisan { get; private set; }
|
||||
|
||||
public CodeService(Configuration config)
|
||||
=> _config = config;
|
||||
{
|
||||
_config = config;
|
||||
Load();
|
||||
}
|
||||
|
||||
private void Load()
|
||||
{
|
||||
|
|
@ -84,6 +88,7 @@ public class CodeService
|
|||
_ when CodeOops7.SequenceEqual(sha) => v => EnabledOops = v ? Race.Hrothgar : Race.Unknown,
|
||||
_ when CodeOops8.SequenceEqual(sha) => v => EnabledOops = v ? Race.Viera : Race.Unknown,
|
||||
_ when CodeInventory.SequenceEqual(sha) => v => EnabledInventory = v,
|
||||
_ when CodeArtisan.SequenceEqual(sha) => v => EnabledArtisan = v,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
|
@ -104,5 +109,6 @@ public class CodeService
|
|||
private static ReadOnlySpan<byte> CodeOops7 => new byte[] { 0x41, 0xEC, 0x65, 0x05, 0x8D, 0x20, 0x68, 0x5A, 0xB7, 0xEB, 0x92, 0x15, 0x43, 0xCF, 0x15, 0x05, 0x27, 0x51, 0xFE, 0x20, 0xC9, 0xB6, 0x2B, 0x84, 0xD9, 0x6A, 0x49, 0x5A, 0x5B, 0x7F, 0x2E, 0xE7 };
|
||||
private static ReadOnlySpan<byte> CodeOops8 => new byte[] { 0x16, 0xFF, 0x63, 0x85, 0x1C, 0xF5, 0x34, 0x33, 0x67, 0x8C, 0x46, 0x8E, 0x3E, 0xE3, 0xA6, 0x94, 0xF9, 0x74, 0x47, 0xAA, 0xC7, 0x29, 0x59, 0x1F, 0x6C, 0x6E, 0xF2, 0xF5, 0x87, 0x24, 0x9E, 0x2B };
|
||||
private static ReadOnlySpan<byte> CodeInventory => new byte[] { 0xD1, 0x35, 0xD7, 0x18, 0xBE, 0x45, 0x42, 0xBD, 0x88, 0x77, 0x7E, 0xC4, 0x41, 0x06, 0x34, 0x4D, 0x71, 0x3A, 0xC5, 0xCC, 0xA4, 0x1B, 0x7D, 0x3F, 0x3B, 0x86, 0x07, 0xCB, 0x63, 0xD7, 0xF9, 0xDB };
|
||||
private static ReadOnlySpan<byte> CodeArtisan => new byte[] { 0xDE, 0x01, 0x32, 0x1E, 0x7F, 0x22, 0x80, 0x3D, 0x76, 0xDF, 0x74, 0x0E, 0xEC, 0x33, 0xD3, 0xF4, 0x1A, 0x98, 0x9E, 0x9D, 0x22, 0x5C, 0xAC, 0x3B, 0xFE, 0x0B, 0xC2, 0x13, 0xB9, 0x91, 0x24, 0x61 };
|
||||
// @formatter:on
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
=> HumanModels = humanModels;
|
||||
|
||||
public (Customize NewValue, CustomizeFlag Applied, CustomizeFlag Changed) Combine(Customize oldValues, Customize newValues,
|
||||
CustomizeFlag applyWhich)
|
||||
CustomizeFlag applyWhich, bool allowUnknown)
|
||||
{
|
||||
CustomizeFlag applied = 0;
|
||||
CustomizeFlag changed = 0;
|
||||
|
|
@ -46,7 +46,7 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
continue;
|
||||
|
||||
var value = newValues[index];
|
||||
if (IsCustomizationValid(set, ret.Face, index, value))
|
||||
if (allowUnknown || IsCustomizationValid(set, ret.Face, index, value))
|
||||
{
|
||||
if (ret[index].Value != value.Value)
|
||||
changed |= flag;
|
||||
|
|
@ -194,7 +194,7 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
|
||||
/// <summary>
|
||||
/// Check that the given model id is valid.
|
||||
/// The returned model id is 0.
|
||||
/// The returned model id is 0 if it is not.
|
||||
/// The return value is an empty string if everything was correct and a warning otherwise.
|
||||
/// </summary>
|
||||
public string ValidateModelId(uint modelId, out uint actualModelId, out bool isHuman)
|
||||
|
|
@ -217,9 +217,9 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
/// The return value is an empty string or a warning message.
|
||||
/// </summary>
|
||||
public static string ValidateCustomizeValue(CustomizationSet set, CustomizeValue face, CustomizeIndex index, CustomizeValue value,
|
||||
out CustomizeValue actualValue)
|
||||
out CustomizeValue actualValue, bool allowUnknown)
|
||||
{
|
||||
if (IsCustomizationValid(set, face, index, value))
|
||||
if (allowUnknown || IsCustomizationValid(set, face, index, value))
|
||||
{
|
||||
actualValue = value;
|
||||
return string.Empty;
|
||||
|
|
@ -279,7 +279,7 @@ public sealed class CustomizationService : AsyncServiceWrapper<ICustomizationMan
|
|||
CustomizeFlag flags = 0;
|
||||
foreach (var idx in Enum.GetValues<CustomizeIndex>().Where(set.IsAvailable))
|
||||
{
|
||||
if (ValidateCustomizeValue(set, customize.Face, idx, customize[idx], out var fixedValue).Length > 0)
|
||||
if (ValidateCustomizeValue(set, customize.Face, idx, customize[idx], out var fixedValue, false).Length > 0)
|
||||
{
|
||||
customize[idx] = fixedValue;
|
||||
flags |= idx.ToFlag();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using Lumina.Excel;
|
|||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using static OtterGui.Raii.ImRaii;
|
||||
using Race = Penumbra.GameData.Enums.Race;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
|
@ -111,7 +112,7 @@ public class ItemManager : IDisposable
|
|||
var item = IdentifierService.AwaitedService.Identify(id, variant, slot).FirstOrDefault();
|
||||
return item.Valid
|
||||
? item
|
||||
: new EquipItem($"Unknown ({id.Value}-{variant})", 0, 0, id, 0, variant, 0);
|
||||
: new EquipItem($"Unknown ({id.Value}-{variant})", 0, 0, id, 0, variant, slot.ToEquipType());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +132,7 @@ public class ItemManager : IDisposable
|
|||
var item = IdentifierService.AwaitedService.Identify(id, type, variant, slot).FirstOrDefault();
|
||||
return item.Valid
|
||||
? item
|
||||
: new EquipItem($"Unknown ({id.Value}-{type.Value}-{variant})", 0, 0, id, type, variant, 0);
|
||||
: EquipItem.FromIds(0, 0, id, type, variant, slot.ToEquipType(), null);
|
||||
}
|
||||
|
||||
/// <summary> Returns whether an item id represents a valid item for a slot and gives the item. </summary>
|
||||
|
|
@ -147,12 +148,20 @@ public class ItemManager : IDisposable
|
|||
/// The returned item is either the resolved correct item, or the Nothing item for that slot.
|
||||
/// The return value is an empty string if there was no problem and a warning otherwise.
|
||||
/// </summary>
|
||||
public string ValidateItem(EquipSlot slot, uint itemId, out EquipItem item)
|
||||
public string ValidateItem(EquipSlot slot, ulong itemId, out EquipItem item, bool allowUnknown)
|
||||
{
|
||||
if (slot is EquipSlot.MainHand or EquipSlot.OffHand)
|
||||
throw new Exception("Internal Error: Used armor functionality for weapons.");
|
||||
|
||||
if (IsItemValid(slot, itemId, out item))
|
||||
if (itemId > uint.MaxValue)
|
||||
{
|
||||
var id = (SetId)(itemId & ushort.MaxValue);
|
||||
var variant = (byte)(itemId >> 32);
|
||||
item = new EquipItem($"Unknown ({id}-{variant})", 0, 0, id, 0, variant, slot.ToEquipType());
|
||||
return allowUnknown ? string.Empty : $"The item {itemId} yields an unknown item.";
|
||||
}
|
||||
|
||||
if (IsItemValid(slot, (uint) itemId, out item))
|
||||
return string.Empty;
|
||||
|
||||
item = NothingItem(slot);
|
||||
|
|
@ -169,9 +178,9 @@ public class ItemManager : IDisposable
|
|||
/// The returned stain id is either the input or 0.
|
||||
/// The return value is an empty string if there was no problem and a warning otherwise.
|
||||
/// </summary>
|
||||
public string ValidateStain(StainId stain, out StainId ret)
|
||||
public string ValidateStain(StainId stain, out StainId ret, bool allowUnknown)
|
||||
{
|
||||
if (IsStainValid(stain))
|
||||
if (allowUnknown || IsStainValid(stain))
|
||||
{
|
||||
ret = stain;
|
||||
return string.Empty;
|
||||
|
|
|
|||
|
|
@ -23,10 +23,16 @@ public class StateEditor
|
|||
}
|
||||
|
||||
/// <summary> Change the model id. If the actor is changed from a human to another human, customize and equipData are unused. </summary>
|
||||
/// <remarks> We currently only allow changing things to humans, not humans to monsters. </remarks>
|
||||
public bool ChangeModelId(ActorState state, uint modelId, in Customize customize, nint equipData, StateChanged.Source source,
|
||||
out uint oldModelId, uint key = 0)
|
||||
{
|
||||
oldModelId = state.ModelData.ModelId;
|
||||
|
||||
// TODO think about this.
|
||||
if (modelId != 0)
|
||||
return false;
|
||||
|
||||
if (!state.CanUnlock(key))
|
||||
return false;
|
||||
|
||||
|
|
@ -94,7 +100,7 @@ public class StateEditor
|
|||
if (!state.CanUnlock(key))
|
||||
return false;
|
||||
|
||||
(var customize, var applied, changed) = _customizations.Combine(state.ModelData.Customize, customizeInput, applyWhich);
|
||||
(var customize, var applied, changed) = _customizations.Combine(state.ModelData.Customize, customizeInput, applyWhich, true);
|
||||
if (changed == 0)
|
||||
return false;
|
||||
|
||||
|
|
@ -130,6 +136,11 @@ public class StateEditor
|
|||
if (!state.CanUnlock(key))
|
||||
return false;
|
||||
|
||||
// Can not change weapon type from expected type in state.
|
||||
if (slot is EquipSlot.MainHand && item.Type != state.BaseData.MainhandType
|
||||
|| slot is EquipSlot.OffHand && item.Type != state.BaseData.MainhandType.Offhand())
|
||||
return false;
|
||||
|
||||
state.ModelData.SetItem(slot, item);
|
||||
state.ModelData.SetStain(slot, stain);
|
||||
state[slot, false] = source;
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
? _applier.ChangeArmor(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc)
|
||||
: _applier.ChangeWeapon(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
|
||||
Glamourer.Log.Verbose(
|
||||
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.Id}) to {item.Name} ({item.Id}). [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item.Name} ({item.ItemId}). [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
_event.Invoke(type, source, state, actors, (old, item, slot));
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +260,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
|||
? _applier.ChangeArmor(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc)
|
||||
: _applier.ChangeWeapon(state, slot, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
|
||||
Glamourer.Log.Verbose(
|
||||
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.Id}) to {item.Name} ({item.Id}) and its stain from {oldStain.Value} to {stain.Value}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item.Name} ({item.ItemId}) and its stain from {oldStain.Value} to {stain.Value}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
_event.Invoke(type, source, state, actors, (old, item, slot));
|
||||
_event.Invoke(StateChanged.Type.Stain, source, state, actors, (oldStain, stain, slot));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,10 +125,10 @@ public class ItemUnlockManager : ISavable, IDisposable
|
|||
|
||||
bool AddItem(uint itemId)
|
||||
{
|
||||
if (!_items.ItemService.AwaitedService.TryGetValue(itemId, out var equip) || !_unlocked.TryAdd(equip.Id, time))
|
||||
if (!_items.ItemService.AwaitedService.TryGetValue(itemId, out var equip) || !_unlocked.TryAdd(equip.ItemId, time))
|
||||
return false;
|
||||
|
||||
_event.Invoke(ObjectUnlocked.Type.Item, equip.Id, DateTimeOffset.FromUnixTimeMilliseconds(time));
|
||||
_event.Invoke(ObjectUnlocked.Type.Item, equip.ItemId, DateTimeOffset.FromUnixTimeMilliseconds(time));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -274,7 +274,7 @@ public class ItemUnlockManager : ISavable, IDisposable
|
|||
foreach (var row in cabinet)
|
||||
{
|
||||
if (items.ItemService.AwaitedService.TryGetValue(row.Item.Row, out var item))
|
||||
ret.TryAdd(item.Id, new UnlockRequirements(row.RowId, 0, 0, 0, UnlockType.Cabinet));
|
||||
ret.TryAdd(item.ItemId, new UnlockRequirements(row.RowId, 0, 0, 0, UnlockType.Cabinet));
|
||||
}
|
||||
|
||||
var gilShop = gameData.GetExcelSheet<GilShopItem>()!;
|
||||
|
|
@ -290,7 +290,7 @@ public class ItemUnlockManager : ISavable, IDisposable
|
|||
var type = (quest1 != 0 ? UnlockType.Quest1 : 0)
|
||||
| (quest2 != 0 ? UnlockType.Quest2 : 0)
|
||||
| (achievement != 0 ? UnlockType.Achievement : 0);
|
||||
ret.TryAdd(item.Id, new UnlockRequirements(quest1, quest2, achievement, state, type));
|
||||
ret.TryAdd(item.ItemId, new UnlockRequirements(quest1, quest2, achievement, state, type));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue