mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-19 05:57:42 +01:00
Change mousewheel to ctrl, current material state.
This commit is contained in:
parent
42ac507b86
commit
b5b9289dc2
20 changed files with 537 additions and 296 deletions
|
|
@ -6,6 +6,8 @@ using Glamourer.Interop.Structs;
|
|||
using Glamourer.State;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Interop.Material;
|
||||
|
|
@ -19,6 +21,8 @@ public sealed unsafe class MaterialManager : IRequiredService, IDisposable
|
|||
|
||||
private int _lastSlot;
|
||||
|
||||
private readonly ThreadLocal<List<MaterialValueIndex>> _deleteList = new(() => []);
|
||||
|
||||
public MaterialManager(PrepareColorSet prepareColorSet, StateManager stateManager, ActorManager actors, PenumbraService penumbra)
|
||||
{
|
||||
_stateManager = stateManager;
|
||||
|
|
@ -39,7 +43,8 @@ public sealed unsafe class MaterialManager : IRequiredService, IDisposable
|
|||
var (slotId, materialId) = FindMaterial(characterBase, material);
|
||||
|
||||
if (!validType
|
||||
|| slotId == byte.MaxValue
|
||||
|| slotId > 9
|
||||
|| type is not MaterialValueIndex.DrawObjectType.Human && slotId > 0
|
||||
|| !actor.Identifier(_actors, out var identifier)
|
||||
|| !_stateManager.TryGetValue(identifier, out var state))
|
||||
return;
|
||||
|
|
@ -53,38 +58,60 @@ public sealed unsafe class MaterialManager : IRequiredService, IDisposable
|
|||
if (!PrepareColorSet.TryGetColorTable(characterBase, material, stain, out var baseColorSet))
|
||||
return;
|
||||
|
||||
for (var i = 0; i < values.Length; ++i)
|
||||
var drawData = type switch
|
||||
{
|
||||
var idx = MaterialValueIndex.FromKey(values[i].key);
|
||||
var (oldGame, model, source) = values[i].Value;
|
||||
ref var row = ref baseColorSet[idx.RowIndex];
|
||||
if (!idx.DataIndex.TryGetValue(row, out var newGame))
|
||||
continue;
|
||||
|
||||
if (newGame == oldGame)
|
||||
{
|
||||
idx.DataIndex.SetValue(ref row, model);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (source.Base())
|
||||
{
|
||||
case StateSource.Manual:
|
||||
_stateManager.ChangeMaterialValue(state, idx, Vector3.Zero, Vector3.Zero, ApplySettings.Game);
|
||||
--i;
|
||||
break;
|
||||
case StateSource.Fixed:
|
||||
idx.DataIndex.SetValue(ref row, model);
|
||||
state.Materials.UpdateValue(idx, new MaterialValueState(newGame, model, source), out _);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
MaterialValueIndex.DrawObjectType.Human => GetTempSlot((Human*)characterBase, slotId),
|
||||
_ => GetTempSlot((Weapon*)characterBase),
|
||||
};
|
||||
UpdateMaterialValues(state, values, drawData, ref baseColorSet);
|
||||
|
||||
if (MaterialService.GenerateNewColorTable(baseColorSet, out var texture))
|
||||
ret = (nint)texture;
|
||||
}
|
||||
|
||||
/// <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,
|
||||
ref MtrlFile.ColorTable colorTable)
|
||||
{
|
||||
var deleteList = _deleteList.Value!;
|
||||
deleteList.Clear();
|
||||
for (var i = 0; i < values.Length; ++i)
|
||||
{
|
||||
var idx = MaterialValueIndex.FromKey(values[i].Key);
|
||||
var materialValue = values[i].Value;
|
||||
ref var row = ref colorTable[idx.RowIndex];
|
||||
var newGame = new ColorRow(row);
|
||||
if (materialValue.EqualGame(newGame, drawData))
|
||||
materialValue.Model.Apply(ref row);
|
||||
else
|
||||
switch (materialValue.Source)
|
||||
{
|
||||
case StateSource.Pending:
|
||||
materialValue.Model.Apply(ref row);
|
||||
state.Materials.UpdateValue(idx, new MaterialValueState(newGame, materialValue.Model, drawData, StateSource.Manual),
|
||||
out _);
|
||||
break;
|
||||
case StateSource.IpcManual:
|
||||
case StateSource.Manual:
|
||||
deleteList.Add(idx);
|
||||
break;
|
||||
case StateSource.Fixed:
|
||||
case StateSource.IpcFixed:
|
||||
materialValue.Model.Apply(ref row);
|
||||
state.Materials.UpdateValue(idx, new MaterialValueState(newGame, materialValue.Model, drawData, materialValue.Source),
|
||||
out _);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var idx in deleteList)
|
||||
_stateManager.ChangeMaterialValue(state, idx, default, ApplySettings.Game);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the index of a material by searching through a draw objects pointers.
|
||||
/// Tries to take shortcuts for consecutive searches like when a character is newly created.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private (byte SlotId, byte MaterialId) FindMaterial(CharacterBase* characterBase, MaterialResourceHandle* material)
|
||||
{
|
||||
|
|
@ -119,6 +146,7 @@ public sealed unsafe class MaterialManager : IRequiredService, IDisposable
|
|||
return (byte.MaxValue, byte.MaxValue);
|
||||
}
|
||||
|
||||
/// <summary> Find the type of the given draw object by checking the actors pointers. </summary>
|
||||
private static bool FindType(CharacterBase* characterBase, Actor actor, out MaterialValueIndex.DrawObjectType type)
|
||||
{
|
||||
type = MaterialValueIndex.DrawObjectType.Human;
|
||||
|
|
@ -145,4 +173,26 @@ public sealed unsafe class MaterialManager : IRequiredService, IDisposable
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary> We need to get the temporary set, variant and stain that is currently being set if it is available. </summary>
|
||||
private CharacterWeapon GetTempSlot(Human* human, byte slotId)
|
||||
{
|
||||
if (human->ChangedEquipData == null)
|
||||
return ((Model)human).GetArmor(((uint)slotId).ToEquipSlot()).ToWeapon(0);
|
||||
|
||||
return ((CharacterArmor*)human->ChangedEquipData + slotId * 3)->ToWeapon(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We need to get the temporary set, variant and stain that is currently being set if it is available.
|
||||
/// Weapons do not change in skeleton id without being reconstructed, so this is not changeable data.
|
||||
/// </summary>
|
||||
private CharacterWeapon GetTempSlot(Weapon* weapon)
|
||||
{
|
||||
var changedData = *(void**)((byte*)weapon + 0x918);
|
||||
if (changedData == null)
|
||||
return new CharacterWeapon(weapon->ModelSetId, weapon->SecondaryId, (Variant)weapon->Variant, (StainId)weapon->ModelUnknown);
|
||||
|
||||
return new CharacterWeapon(weapon->ModelSetId, *(SecondaryId*)changedData, ((Variant*)changedData)[2], ((StainId*)changedData)[3]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue