From 9904e9208243126f93078599fcfa7ac54cf05def Mon Sep 17 00:00:00 2001 From: dexy Date: Sun, 8 May 2022 20:54:21 +1000 Subject: [PATCH] Improved conversion of struct arrays to/from byte arrays --- .../GameFiles/MetaTypes/MetaTypes.cs | 55 ++++++++++++------- .../GameFiles/MetaTypes/PsoTypes.cs | 16 ++++-- .../GameFiles/Resources/ResourceData.cs | 35 ++++++++---- 3 files changed, 71 insertions(+), 35 deletions(-) diff --git a/CodeWalker.Core/GameFiles/MetaTypes/MetaTypes.cs b/CodeWalker.Core/GameFiles/MetaTypes/MetaTypes.cs index 168ec24..7e122cd 100644 --- a/CodeWalker.Core/GameFiles/MetaTypes/MetaTypes.cs +++ b/CodeWalker.Core/GameFiles/MetaTypes/MetaTypes.cs @@ -1449,21 +1449,31 @@ namespace CodeWalker.GameFiles public static byte[] ConvertArrayToBytes(params T[] items) where T : struct { if (items == null) return null; - int size = Marshal.SizeOf(typeof(T)); - int sizetot = size * items.Length; - byte[] arrout = new byte[sizetot]; - int offset = 0; - for (int i = 0; i < items.Length; i++) - { - byte[] arr = new byte[size]; - IntPtr ptr = Marshal.AllocHGlobal(size); - Marshal.StructureToPtr(items[i], ptr, true); - Marshal.Copy(ptr, arr, 0, size); - Marshal.FreeHGlobal(ptr); - Buffer.BlockCopy(arr, 0, arrout, offset, size); - offset += size; - } - return arrout; + + var size = Marshal.SizeOf(typeof(T)) * items.Length; + var b = new byte[size]; + GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned); + var h = handle.AddrOfPinnedObject(); + Marshal.Copy(h, b, 0, size); + handle.Free(); + return b; + + + //int size = Marshal.SizeOf(typeof(T)); + //int sizetot = size * items.Length; + //byte[] arrout = new byte[sizetot]; + //int offset = 0; + //for (int i = 0; i < items.Length; i++) + //{ + // byte[] arr = new byte[size]; + // IntPtr ptr = Marshal.AllocHGlobal(size); + // Marshal.StructureToPtr(items[i], ptr, true); + // Marshal.Copy(ptr, arr, 0, size); + // Marshal.FreeHGlobal(ptr); + // Buffer.BlockCopy(arr, 0, arrout, offset, size); + // offset += size; + //} + //return arrout; } @@ -1487,11 +1497,16 @@ namespace CodeWalker.GameFiles { T[] items = new T[count]; int itemsize = Marshal.SizeOf(typeof(T)); - for (int i = 0; i < count; i++) - { - int off = offset + i * itemsize; - items[i] = ConvertData(data, off); - } + //for (int i = 0; i < count; i++) + //{ + // int off = offset + i * itemsize; + // items[i] = ConvertData(data, off); + //} + GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned); + var h = handle.AddrOfPinnedObject(); + Marshal.Copy(data, offset, h, itemsize * count); + handle.Free(); + return items; } public static T[] ConvertDataArray(Meta meta, MetaName name, Array_StructurePointer array) where T : struct diff --git a/CodeWalker.Core/GameFiles/MetaTypes/PsoTypes.cs b/CodeWalker.Core/GameFiles/MetaTypes/PsoTypes.cs index 11907f3..c49dbb2 100644 --- a/CodeWalker.Core/GameFiles/MetaTypes/PsoTypes.cs +++ b/CodeWalker.Core/GameFiles/MetaTypes/PsoTypes.cs @@ -15848,11 +15848,17 @@ namespace CodeWalker.GameFiles { T[] items = new T[count]; int itemsize = Marshal.SizeOf(typeof(T)); - for (int i = 0; i < count; i++) - { - int off = offset + i * itemsize; - items[i] = ConvertDataRaw(data, off); - } + //for (int i = 0; i < count; i++) + //{ + // int off = offset + i * itemsize; + // items[i] = ConvertDataRaw(data, off); + //} + + GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned); + var h = handle.AddrOfPinnedObject(); + Marshal.Copy(data, offset, h, itemsize * count); + handle.Free(); + return items; } diff --git a/CodeWalker.Core/GameFiles/Resources/ResourceData.cs b/CodeWalker.Core/GameFiles/Resources/ResourceData.cs index 4449427..3093d74 100644 --- a/CodeWalker.Core/GameFiles/Resources/ResourceData.cs +++ b/CodeWalker.Core/GameFiles/Resources/ResourceData.cs @@ -369,15 +369,22 @@ namespace CodeWalker.GameFiles //var result2 = new T[count]; //Buffer.BlockCopy(data, 0, result2, 0, (int)length); //error: "object must be an array of primitives" :( + //var result = new T[count]; + //GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); + //var h = handle.AddrOfPinnedObject(); + //for (uint i = 0; i < count; i++) + //{ + // result[i] = Marshal.PtrToStructure(h + (int)(i * structsize)); + //} + //handle.Free(); + var result = new T[count]; - GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); + GCHandle handle = GCHandle.Alloc(result, GCHandleType.Pinned); var h = handle.AddrOfPinnedObject(); - for (uint i = 0; i < count; i++) - { - result[i] = Marshal.PtrToStructure(h + (int)(i * structsize)); - } + Marshal.Copy(data, 0, h, (int)length); handle.Free(); + if (cache) arrayPool[(long)position] = result; return result; @@ -388,13 +395,21 @@ namespace CodeWalker.GameFiles var result = new T[count]; var length = count * structsize; byte[] data = ReadBytes((int)length); - GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); + + //GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); + //var h = handle.AddrOfPinnedObject(); + //for (uint i = 0; i < count; i++) + //{ + // result[i] = Marshal.PtrToStructure(h + (int)(i * structsize)); + //} + //handle.Free(); + + GCHandle handle = GCHandle.Alloc(result, GCHandleType.Pinned); var h = handle.AddrOfPinnedObject(); - for (uint i = 0; i < count; i++) - { - result[i] = Marshal.PtrToStructure(h + (int)(i * structsize)); - } + Marshal.Copy(data, 0, h, (int)length); handle.Free(); + + return result; }