/// <summary> /// Creates a byte array to be read by the game from a <see cref="HintFile"/>. /// </summary> public byte[] ToArray() { // Make native entries. var entries = new Entry[Entries.Length]; for (int x = 0; x < entries.Length; x++) { entries[x] = new Entry(Entries[x]); } // Write strings from managed entries to a byte region. var stringData = new List <byte>(entries.Length * LongStringLength); byte[] bytes; for (int x = 0; x < entries.Length; x++) { entries[x].Offset = stringData.Count; bytes = _encoder.GetBytes(Entries[x].Text); stringData.AddRange(bytes); stringData.Add(0); } var nullEntry = Entry.Null; var nullEntryBytes = Struct.GetBytes(ref nullEntry); var stringDataBytes = stringData.ToArray(); var entryData = StructArray.GetBytes(entries); var allData = new byte[entryData.Length + nullEntryBytes.Length + stringData.Count]; Buffer.BlockCopy(entryData, 0, allData, 0, entryData.Length); Buffer.BlockCopy(nullEntryBytes, 0, allData, entryData.Length, nullEntryBytes.Length); Buffer.BlockCopy(stringDataBytes, 0, allData, entryData.Length + nullEntryBytes.Length, stringDataBytes.Length); return(allData); }
/* Construction/Destruction */ public RandomUInt64Generator(int megabytes) { int totalBytes = Mathematics.MegaBytesToBytes(megabytes); int structs = Mathematics.BytesToStructCount <UInt64>(totalBytes); Structs = new UInt64[structs]; for (int x = 0; x < structs; x++) { Structs[x] = (UInt64)NextRandom(UInt64.MinValue, UInt64.MaxValue); } Bytes = StructArray.GetBytes(Structs); }
/* Construction/Destruction */ public RandomDoubleGenerator(int megabytes) { int totalBytes = Mathematics.MegaBytesToBytes(megabytes); int structs = Mathematics.BytesToStructCount <Double>(totalBytes); Structs = new Double[structs]; for (int x = 0; x < structs; x++) { Structs[x] = (Double)NextRandom(Double.MinValue, Double.MaxValue); } Bytes = StructArray.GetBytes(Structs); }
/* Construction/Destruction */ public RandomInt32Generator(int megabytes) { int totalBytes = Mathematics.MegaBytesToBytes(megabytes); int structs = Mathematics.BytesToStructCount <Int32>(totalBytes); Structs = new Int32[structs]; for (int x = 0; x < structs; x++) { Structs[x] = (Int32)NextRandom(Int32.MinValue, Int32.MaxValue); } Bytes = StructArray.GetBytes(Structs); }
/* Construction/Destruction */ public RandomIntStructGenerator(int megabytes) { int totalBytes = Mathematics.MegaBytesToBytes(megabytes); int structs = Mathematics.BytesToStructCount <RandomIntStruct>(totalBytes); Structs = new RandomIntStruct[structs]; for (int x = 0; x < structs; x++) { Structs[x] = RandomIntStruct.BuildRandomStruct(); } Bytes = StructArray.GetBytes(Structs); File.WriteAllBytes(TestFileName, Bytes); }
/* Construction/Destruction */ public RandomIntegerGenerator(int megabytes) { int totalBytes = Mathematics.MegaBytesToBytes(megabytes); int structs = Mathematics.BytesToStructCount <int>(totalBytes); Structs = new int[structs]; for (int x = 0; x < structs; x++) { Structs[x] = _random.Next(); } Bytes = StructArray.GetBytes(Structs); File.WriteAllBytes(TestFileName, Bytes); }
/// <summary> /// Shows some functionality of the <see cref="Struct"/> and <see cref="StructArray"/> utility classes. /// </summary> /// <param name="memory">This object is used to perform memory read/write/free/allocate operations.</param> /// <param name="memoryLocation">Arbitrary location in memory where this tutorial will be held.</param> private static void StructUtilityExample(IMemory memory, IntPtr memoryLocation) { // Under the hood; the IMemory implementations may use a certain struct utility classes known as Struct // and StructArray which provide various methods for struct conversions and general work with structs. // Like earlier; let's load the adventure binary file. byte[] physicsData = File.ReadAllBytes($"phys.bin"); // But this time; do a direct conversion rather than reading from memory. // Note that you don't even need to specify item count this time arounnd. // This is auto-decided from array size, but can be manually overwritten. StructArray.FromArray(physicsData, out AdventurePhysics[] adventurePhysics); // Calculate total array size (in bytes). int arraySize = StructArray.GetSize <AdventurePhysics>(adventurePhysics.Length); // Get raw bytes for the struct. byte[] physicsDataBack = StructArray.GetBytes(adventurePhysics); // You can also read/write structures; as a shorthand to Memory class. StructArray.ToPtr(memoryLocation, adventurePhysics); StructArray.FromPtr(memoryLocation, out AdventurePhysics[] adventurePhysicsCopy, adventurePhysics.Length); // Beware of the double sided blade however. // A. Struct class allows you to change the source read/write source for FromPtr and ToPtr. // B. It affects both Struct and StructArray. // Note: There are also explicit overloads for FromPtr and ToPtr that let you use a source without modifying current source. Struct.Source = memory; // And of course the source is an implementation of IMemory. // Print details. if (physicsDataBack.SequenceEqual(physicsDataBack)) { Console.WriteLine($"Success: Original Physics Data and StructArray.GetBytes() are Equal"); } Console.WriteLine($"Struct Array Size: {arraySize}"); }
/// <summary> /// Appends an managed/marshalled structure onto the <see cref="MemoryStream"/> and advances the position. /// </summary> public void Append <T>(T[] structure, bool marshalStructure = true) => Append(StructArray.GetBytes(structure, marshalStructure));
/// <summary> /// Appends an unmanaged structure onto the <see cref="MemoryStream"/> and advances the position. /// </summary> public void Append <T>(T[] structure) where T : unmanaged => Append(StructArray.GetBytes(structure));
/// <summary> /// Converts a <see cref="MotionPackage"/> into a native .MTP file. /// </summary> public byte[] ToMtp() { var bytes = new List <byte>(1000000); var header = Header; header.SwapEndian(); bytes.AddRange(Struct.GetBytes(ref header)); // Write entries var dummyAnimationEntry = new AnimationEntry(); var dummyAnimationEntryBytes = Struct.GetBytes(ref dummyAnimationEntry); int[] entryOffsets = Entries.Select(x => AddRange(bytes, dummyAnimationEntryBytes)).ToArray(); // Write file names. int[] fileNameOffsets = Entries.Select(x => { int firstRef = AddRange(bytes, String.GetNullTerminatedBytes(String.Win1252Encoder, x.FileName)); // Must pad to next group of 4-bytes, otherwise game will fail to parse while (bytes.Count % 4 > 0) { bytes.Add(0x00); } return(firstRef); }).ToArray(); // Write file data. int[] fileDataOffsets = Entries.Select(x => AddRange(bytes, x.FileData)).ToArray(); // Write extra properties. int[] filePropertyOffsets = Entries.Select(x => { if (x.Tuples != null) { // Temporarily swap out the endian of all tuples before writing to array, then swap back. for (int i = 0; i < x.Tuples.Length; i++) { x.Tuples[i].SwapEndian(); } var result = AddRange(bytes, StructArray.GetBytes(x.Tuples)); for (int i = 0; i < x.Tuples.Length; i++) { x.Tuples[i].SwapEndian(); } return(result); } return(0); }).ToArray(); // Fix Offsets var byteArray = bytes.ToArray(); fixed(byte *byteArrayPtr = byteArray) { for (int x = 0; x < Entries.Length; x++) { ref var entry = ref Unsafe.AsRef <AnimationEntry>(byteArrayPtr + entryOffsets[x]); Endian.Reverse(ref fileNameOffsets[x]); Endian.Reverse(ref fileDataOffsets[x]); Endian.Reverse(ref filePropertyOffsets[x]); entry.FileNamePtr = fileNameOffsets[x]; entry.FileDataPtr = fileDataOffsets[x]; entry.PropertyTuplePtr = filePropertyOffsets[x]; } }
public void Write <T>(T[] structure, bool marshalStructure = true) => Write(StructArray.GetBytes(structure, marshalStructure));
public void Write <T>(T[] structure) where T : unmanaged => Write(StructArray.GetBytes(structure));