I hate animations
This commit is contained in:
@@ -193,7 +193,7 @@ public sealed class FileCacheManager : IHostedService
|
|||||||
|
|
||||||
foreach (var entry in cleanedPaths)
|
foreach (var entry in cleanedPaths)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Checking {path}", entry.Value);
|
//_logger.LogDebug("Checking {path}", entry.Value);
|
||||||
|
|
||||||
if (dict.TryGetValue(entry.Value, out var entity))
|
if (dict.TryGetValue(entry.Value, out var entity))
|
||||||
{
|
{
|
||||||
@@ -321,7 +321,7 @@ public sealed class FileCacheManager : IHostedService
|
|||||||
|
|
||||||
if (!entries.Exists(u => string.Equals(u.PrefixedFilePath, fileCache.PrefixedFilePath, StringComparison.OrdinalIgnoreCase)))
|
if (!entries.Exists(u => string.Equals(u.PrefixedFilePath, fileCache.PrefixedFilePath, StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Adding to DB: {hash} => {path}", fileCache.Hash, fileCache.PrefixedFilePath);
|
//_logger.LogTrace("Adding to DB: {hash} => {path}", fileCache.Hash, fileCache.PrefixedFilePath);
|
||||||
entries.Add(fileCache);
|
entries.Add(fileCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,7 +344,7 @@ public sealed class FileCacheManager : IHostedService
|
|||||||
private FileCacheEntity? GetValidatedFileCache(FileCacheEntity fileCache)
|
private FileCacheEntity? GetValidatedFileCache(FileCacheEntity fileCache)
|
||||||
{
|
{
|
||||||
var resultingFileCache = ReplacePathPrefixes(fileCache);
|
var resultingFileCache = ReplacePathPrefixes(fileCache);
|
||||||
_logger.LogTrace("Validating {path}", fileCache.PrefixedFilePath);
|
//_logger.LogTrace("Validating {path}", fileCache.PrefixedFilePath);
|
||||||
resultingFileCache = Validate(resultingFileCache);
|
resultingFileCache = Validate(resultingFileCache);
|
||||||
return resultingFileCache;
|
return resultingFileCache;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ internal sealed class DalamudLogger : ILogger
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
sb.AppendLine($"{unsupported}[{_name}]{{{(int)logLevel}}} {state}{(_hasModifiedGameFiles ? "." : string.Empty)}: {exception?.Message}");
|
sb.AppendLine($"{unsupported}[{_name}]{{{(int)logLevel}}} {state}{(_hasModifiedGameFiles ? "." : string.Empty)} {exception?.Message}");
|
||||||
sb.AppendLine(exception?.StackTrace);
|
sb.AppendLine(exception?.StackTrace);
|
||||||
var innerException = exception?.InnerException;
|
var innerException = exception?.InnerException;
|
||||||
while (innerException != null)
|
while (innerException != null)
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ namespace MareSynchronos.MareConfiguration.Configurations;
|
|||||||
public class XivDataStorageConfig : IMareConfiguration
|
public class XivDataStorageConfig : IMareConfiguration
|
||||||
{
|
{
|
||||||
public ConcurrentDictionary<string, long> TriangleDictionary { get; set; } = new(StringComparer.OrdinalIgnoreCase);
|
public ConcurrentDictionary<string, long> TriangleDictionary { get; set; } = new(StringComparer.OrdinalIgnoreCase);
|
||||||
public ConcurrentDictionary<string, List<List<ushort>>> BoneDictionary { get; set; } = new(StringComparer.OrdinalIgnoreCase);
|
public ConcurrentDictionary<string, Dictionary<string, List<ushort>>> BonesDictionary { get; set; } = new(StringComparer.OrdinalIgnoreCase);
|
||||||
public int Version { get; set; } = 0;
|
public int Version { get; set; } = 0;
|
||||||
}
|
}
|
||||||
@@ -249,28 +249,37 @@ public class PlayerDataFactory
|
|||||||
var boneIndices = _modelAnalyzer.GetSkeletonBoneIndices(charaPointer);
|
var boneIndices = _modelAnalyzer.GetSkeletonBoneIndices(charaPointer);
|
||||||
if (boneIndices != null)
|
if (boneIndices != null)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Found {idx} bone indices on player: {bones}", boneIndices.Count, string.Join(',', boneIndices));
|
foreach (var kvp in boneIndices)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Found {skellyname} ({idx} bone indices) on player: {bones}", kvp.Key, kvp.Value.Max(), string.Join(',', kvp.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boneIndices.All(u => u.Value.Count == 0)) return;
|
||||||
|
|
||||||
int noValidationFailed = 0;
|
int noValidationFailed = 0;
|
||||||
foreach (var file in previousData.FileReplacements[objectKind].Where(f => !f.IsFileSwap && f.GamePaths.First().EndsWith("pap", StringComparison.OrdinalIgnoreCase)).ToList())
|
foreach (var file in previousData.FileReplacements[objectKind].Where(f => !f.IsFileSwap && f.GamePaths.First().EndsWith("pap", StringComparison.OrdinalIgnoreCase)).ToList())
|
||||||
{
|
{
|
||||||
var animationIndices = await _dalamudUtil.RunOnFrameworkThread(() => _modelAnalyzer.GetBoneIndicesFromPap(file.Hash)).ConfigureAwait(false);
|
var skeletonIndices = await _dalamudUtil.RunOnFrameworkThread(() => _modelAnalyzer.GetBoneIndicesFromPap(file.Hash)).ConfigureAwait(false);
|
||||||
bool validationFailed = false;
|
bool validationFailed = false;
|
||||||
if (animationIndices != null)
|
if (skeletonIndices != null)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Verifying bone indices for {path}, found {x} animations", file.ResolvedPath, animationIndices.Count);
|
// 105 is the maximum vanilla skellington spoopy bone index
|
||||||
for (int i = 0; i < animationIndices.Count; i++)
|
if (skeletonIndices.All(k => k.Value.Max() <= 105))
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Verifying animation set {i}, found {idx} bone indeces", i, animationIndices[i].Count);
|
_logger.LogTrace("All indices of {path} are <= 105, ignoring", file.ResolvedPath);
|
||||||
if (animationIndices[i].Count > boneIndices.Count)
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogDebug("Verifying bone indices for {path}, found {x} skeletons", file.ResolvedPath, skeletonIndices.Count);
|
||||||
|
|
||||||
|
foreach (var boneCount in skeletonIndices.Select(k => k).ToList())
|
||||||
|
{
|
||||||
|
if (boneCount.Value.Max() > boneIndices.SelectMany(b => b.Value).Max())
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Found more bone indeces on the animation {path} ({idx}) than on player skeleton ({idx2})", file.ResolvedPath, animationIndices[i].Count, boneIndices.Count);
|
_logger.LogWarning("Found more bone indices on the animation {path} skeleton {skl} (max indice {idx}) than on any player related skeleton (max indice {idx2})",
|
||||||
validationFailed = true;
|
file.ResolvedPath, boneCount.Key, boneCount.Value.Max(), boneIndices.SelectMany(b => b.Value).Max());
|
||||||
}
|
|
||||||
else if (animationIndices[i].Exists(idx => !boneIndices.Contains(idx)))
|
|
||||||
{
|
|
||||||
_logger.LogWarning("Found bone indices referred on animation {path} that are not on the player skeleton", file.ResolvedPath);
|
|
||||||
validationFailed = true;
|
validationFailed = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,6 +296,7 @@ public class PlayerDataFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noValidationFailed > 0)
|
if (noValidationFailed > 0)
|
||||||
{
|
{
|
||||||
_mareMediator.Publish(new NotificationMessage("Invalid Skeleton Setup",
|
_mareMediator.Publish(new NotificationMessage("Invalid Skeleton Setup",
|
||||||
|
|||||||
@@ -27,38 +27,35 @@ public sealed class XivDataAnalyzer
|
|||||||
_luminaGameData = new GameData(gameData.GameData.DataPath.FullName);
|
_luminaGameData = new GameData(gameData.GameData.DataPath.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe List<ushort>? GetSkeletonBoneIndices(nint charaPtr)
|
public unsafe Dictionary<string, List<ushort>>? GetSkeletonBoneIndices(nint charaPtr)
|
||||||
{
|
{
|
||||||
if (charaPtr == nint.Zero) return null;
|
if (charaPtr == nint.Zero) return null;
|
||||||
var chara = (CharacterBase*)(((Character*)charaPtr)->GameObject.DrawObject);
|
var chara = (CharacterBase*)(((Character*)charaPtr)->GameObject.DrawObject);
|
||||||
|
if (chara->GetModelType() != CharacterBase.ModelType.Human) return null;
|
||||||
var resHandles = chara->Skeleton->SkeletonResourceHandles;
|
var resHandles = chara->Skeleton->SkeletonResourceHandles;
|
||||||
int i = -1;
|
int i = 0;
|
||||||
uint maxBones = 0;
|
Dictionary<string, List<ushort>> outputIndices = new();
|
||||||
List<ushort> outputIndices = new();
|
while (*(resHandles + i) != null)
|
||||||
while (*(resHandles + ++i) != null)
|
|
||||||
{
|
{
|
||||||
var handle = *(resHandles + i);
|
var handle = *(resHandles + i);
|
||||||
var curBones = handle->BoneCount;
|
var curBones = handle->BoneCount;
|
||||||
List<ushort> indices = new();
|
var skeletonName = handle->ResourceHandle.FileName.ToString();
|
||||||
|
outputIndices[skeletonName] = new();
|
||||||
for (ushort boneIdx = 0; boneIdx < curBones; boneIdx++)
|
for (ushort boneIdx = 0; boneIdx < curBones; boneIdx++)
|
||||||
{
|
{
|
||||||
var boneName = handle->HavokSkeleton->Bones[boneIdx].Name.String;
|
var boneName = handle->HavokSkeleton->Bones[boneIdx].Name.String;
|
||||||
if (boneName == null) continue;
|
if (boneName == null) continue;
|
||||||
indices.Add(boneIdx);
|
outputIndices[skeletonName].Add(boneIdx);
|
||||||
}
|
|
||||||
if (curBones > maxBones)
|
|
||||||
{
|
|
||||||
maxBones = curBones;
|
|
||||||
outputIndices = indices;
|
|
||||||
}
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return outputIndices;
|
return outputIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe List<List<ushort>>? GetBoneIndicesFromPap(string hash)
|
public unsafe Dictionary<string, List<ushort>>? GetBoneIndicesFromPap(string hash)
|
||||||
{
|
{
|
||||||
if (_configService.Current.BoneDictionary.TryGetValue(hash, out var bones)) return bones;
|
if (_configService.Current.BonesDictionary.TryGetValue(hash, out var bones)) return bones;
|
||||||
|
|
||||||
var cacheEntity = _fileCacheManager.GetFileCacheByHash(hash);
|
var cacheEntity = _fileCacheManager.GetFileCacheByHash(hash);
|
||||||
if (cacheEntity == null) return null;
|
if (cacheEntity == null) return null;
|
||||||
@@ -82,7 +79,7 @@ public sealed class XivDataAnalyzer
|
|||||||
var havokData = reader.ReadBytes(havokDataSize);
|
var havokData = reader.ReadBytes(havokDataSize);
|
||||||
if (havokData.Length <= 8) return null; // no havok data
|
if (havokData.Length <= 8) return null; // no havok data
|
||||||
|
|
||||||
var output = new List<List<ushort>>();
|
var output = new Dictionary<string, List<ushort>>(StringComparer.OrdinalIgnoreCase);
|
||||||
var tempHavokDataPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()) + ".hkx";
|
var tempHavokDataPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()) + ".hkx";
|
||||||
var tempHavokDataPathAnsi = Marshal.StringToHGlobalAnsi(tempHavokDataPath);
|
var tempHavokDataPathAnsi = Marshal.StringToHGlobalAnsi(tempHavokDataPath);
|
||||||
|
|
||||||
@@ -114,14 +111,15 @@ public sealed class XivDataAnalyzer
|
|||||||
var animContainer = (hkaAnimationContainer*)container->findObjectByName(n2, null);
|
var animContainer = (hkaAnimationContainer*)container->findObjectByName(n2, null);
|
||||||
for (int i = 0; i < animContainer->Bindings.Length; i++)
|
for (int i = 0; i < animContainer->Bindings.Length; i++)
|
||||||
{
|
{
|
||||||
var boneTransform = animContainer->Bindings[i].ptr->TransformTrackToBoneIndices;
|
var binding = animContainer->Bindings[i].ptr;
|
||||||
List<ushort> boneIndices = [];
|
var boneTransform = binding->TransformTrackToBoneIndices;
|
||||||
|
string name = binding->OriginalSkeletonName.String! + "_" + i;
|
||||||
|
output[name] = [];
|
||||||
for (int boneIdx = 0; boneIdx < boneTransform.Length; boneIdx++)
|
for (int boneIdx = 0; boneIdx < boneTransform.Length; boneIdx++)
|
||||||
{
|
{
|
||||||
boneIndices.Add((ushort)boneTransform[boneIdx]);
|
output[name].Add((ushort)boneTransform[boneIdx]);
|
||||||
}
|
}
|
||||||
|
output[name].Sort();
|
||||||
output.Add(boneIndices);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -137,7 +135,7 @@ public sealed class XivDataAnalyzer
|
|||||||
File.Delete(tempHavokDataPath);
|
File.Delete(tempHavokDataPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
_configService.Current.BoneDictionary[hash] = output;
|
_configService.Current.BonesDictionary[hash] = output;
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user