diff --git a/LightlessSync/Services/XivDataAnalyzer.cs b/LightlessSync/Services/XivDataAnalyzer.cs index 6cd9cef..f3f7e9d 100644 --- a/LightlessSync/Services/XivDataAnalyzer.cs +++ b/LightlessSync/Services/XivDataAnalyzer.cs @@ -164,12 +164,25 @@ public sealed class XivDataAnalyzer var output = new Dictionary>(StringComparer.OrdinalIgnoreCase); - var tempHavokDataPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()) + ".hkx"; - var tempHavokDataPathAnsi = Marshal.StringToHGlobalAnsi(tempHavokDataPath); + // write to temp file + var tempHavokDataPath = Path.Combine(Path.GetTempPath(), $"lightless_{Guid.NewGuid():N}.hkx"); + var tempHavokDataPathAnsi = IntPtr.Zero; try { - File.WriteAllBytes(tempHavokDataPath, havokData); + using (var tempFs = new FileStream(tempHavokDataPath, FileMode.CreateNew, FileAccess.Write, FileShare.None, 4096, FileOptions.DeleteOnClose)) + { + tempFs.Write(havokData, 0, havokData.Length); + tempFs.Flush(true); + } + + if (!File.Exists(tempHavokDataPath)) + { + _logger.LogWarning("Temporary havok file was deleted before it could be loaded: {path}", tempHavokDataPath); + return null; + } + + tempHavokDataPathAnsi = Marshal.StringToHGlobalAnsi(tempHavokDataPath); var loadoptions = stackalloc hkSerializeUtil.LoadOptions[1]; loadoptions->TypeInfoRegistry = hkBuiltinTypeRegistry.Instance()->GetTypeInfoRegistry(); @@ -181,7 +194,10 @@ public sealed class XivDataAnalyzer var resource = hkSerializeUtil.LoadFromFile((byte*)tempHavokDataPathAnsi, null, loadoptions); if (resource == null) - throw new InvalidOperationException("Resource was null after loading"); + { + _logger.LogWarning("Havok resource was null after loading from {path}", tempHavokDataPath); + return null; + } var rootLevelName = @"hkRootLevelContainer"u8; fixed (byte* n1 = rootLevelName) @@ -229,8 +245,8 @@ public sealed class XivDataAnalyzer foreach (var key in output.Keys.ToList()) { output[key] = [.. output[key] - .Distinct() - .Order()]; + .Distinct() + .Order()]; } } catch (Exception ex) @@ -240,8 +256,18 @@ public sealed class XivDataAnalyzer } finally { - Marshal.FreeHGlobal(tempHavokDataPathAnsi); - try { File.Delete(tempHavokDataPath); } catch { /* ignore */ } + if (tempHavokDataPathAnsi != IntPtr.Zero) + Marshal.FreeHGlobal(tempHavokDataPathAnsi); + + try + { + if (File.Exists(tempHavokDataPath)) + File.Delete(tempHavokDataPath); + } + catch (Exception ex) + { + _logger.LogTrace(ex, "Could not delete temporary havok file: {path}", tempHavokDataPath); + } } _configService.Current.BonesDictionary[hash] = output;