Penumbra/Penumbra/Mods/Manager/OptionEditor/ImcAttributeCache.cs
2024-08-01 17:14:46 +02:00

105 lines
3.5 KiB
C#

using OtterGui;
using Penumbra.GameData.Structs;
using Penumbra.Mods.Groups;
using Penumbra.Mods.SubMods;
namespace Penumbra.Mods.Manager.OptionEditor;
public unsafe ref struct ImcAttributeCache
{
private fixed bool _canChange[ImcEntry.NumAttributes];
private fixed byte _option[ImcEntry.NumAttributes];
/// <summary> Obtain the earliest unset flag, or 0 if none are unset. </summary>
public readonly ushort LowestUnsetMask;
public ImcAttributeCache(ImcModGroup group)
{
for (var i = 0; i < ImcEntry.NumAttributes; ++i)
{
_canChange[i] = true;
_option[i] = byte.MaxValue;
var flag = (ushort)(1 << i);
foreach (var (option, idx) in group.OptionData.WithIndex())
{
if ((option.AttributeMask & flag) == 0)
continue;
_canChange[i] = option.AttributeMask != flag;
_option[i] = (byte)idx;
break;
}
if (_option[i] == byte.MaxValue && LowestUnsetMask is 0)
LowestUnsetMask = flag;
}
}
/// <summary> Checks whether an attribute flag can be set by anything, i.e. if it might be the only flag for an option and thus could not be removed from that option. </summary>
public readonly bool CanChange(int idx)
=> _canChange[idx];
/// <summary> Set a default attribute flag to a value if possible, remove it from its prior option if necessary, and return if anything changed. </summary>
public readonly bool Set(ImcModGroup group, int idx, bool value)
{
var flag = 1 << idx;
var oldMask = group.DefaultEntry.AttributeMask;
if (!value)
{
var newMask = (ushort)(oldMask & ~flag);
if (oldMask == newMask)
return false;
group.DefaultEntry = group.DefaultEntry with { AttributeMask = newMask };
return true;
}
var mask = (ushort)(oldMask | flag);
if (oldMask == mask)
return false;
group.DefaultEntry = group.DefaultEntry with { AttributeMask = mask };
return true;
}
/// <summary> Set an attribute flag to a value if possible, remove it from its prior option or the default entry if necessary, and return if anything changed. </summary>
public readonly bool Set(ImcSubMod option, int idx, bool value, bool turnOffDefault = false)
{
if (!_canChange[idx])
return false;
var flag = 1 << idx;
var oldMask = option.AttributeMask;
if (!value)
{
var newMask = (ushort)(oldMask & ~flag);
if (oldMask == newMask)
return false;
option.AttributeMask = newMask;
return true;
}
var mask = (ushort)(oldMask | flag);
if (oldMask == mask)
return false;
option.AttributeMask = mask;
if (_option[idx] <= ImcEntry.NumAttributes)
{
var oldOption = option.Group.OptionData[_option[idx]];
oldOption.AttributeMask = (ushort)(oldOption.AttributeMask & ~flag);
}
else if (turnOffDefault && _option[idx] is byte.MaxValue - 1)
{
option.Group.DefaultEntry = option.Group.DefaultEntry with
{
AttributeMask = (ushort)(option.Group.DefaultEntry.AttributeMask & ~flag),
};
}
return true;
}
}