7rQ+AOtGMq$dC2*eS_At!e$MR
zjBw@OfWV3SqPLo-XBnh6I~Qa)gX-<&w5irbOs;L8p`b00@vcGv(bnz(A&;a7M21s1
zOGu|SO9K7BNJ0`J55LFXI}%GD%`4x&{Uqc0{E_Hh29smy+xR)su=lVIU=GOKv>;9^
zi#_(s&vA!*kH0pj$p`d4O^Ap87rCph#Zpq7)DXS}V?ri>(LhgcZfz|PDt`m4gbKiT
z%aPy~P_nX;c@ngX3DN!9f8~K74!_-u9MKWdCK<<#p9%bGuqTJ0-$dU-K>0dPvB|W&
z`?I>3sv!vnq6{IU-97u!DHR#XN!`=a1G_yyr)MNlzk9bRF;QDnlW1)dN-AxDUm4g&
z(1BU^v-gZobGfg&r+!ZHPVH$mq6w9NS$^zr){F
ziG0xNpO{VLJ+(L-dE||O1l~I+bue^LXF(?-u*`ePO($T21X24y`M0~cL8qTBR`KLu
zl2xXEGmXYq&Ah9%mu{~EdKtL-U)tNrPF7Y|AA$Cmf+B0sEqpiZ)j!E^0atVB;u
zSunlTwy+R0oBC{9rLeKGa`64^v=Ekuy*(ZhQePhg`zh?~e&}t?&DjjHx0_o;;%EAgB?BI}FCTQ6s#6H}8H9t_O2c*Z&U0zjPOvwC?Am@9y|0|m6|;}L
zo63&c*j~Mv2a5TPjlm;t?m)9B(3m
z=YIWae>)_5dXb1I>~_h!clQ7uU0x<97?+Y{s_)de ExistingTypes = new();
+
+ internal Dictionary> ReferenceTables = new();
+
+ internal Dictionary nameTableReferenceIndices = new();
+
+ internal ConcurrentDictionary> typeTable = new();
+
+ internal PmdBuilder(PolyMovieData Pmd)
+ {
+ this.Pmd = Pmd;
+ }
+
+ // I sincerely apologize for the absolute hell that is the writing code
+ //I dont know what the fuck I was smoking but I know if I touch it, the whole thing will explode
+ internal async Task CreatePmd(string path)
+ {
+
+ MemoryStream pmdFile = new MemoryStream();
+ using var writer = new BinaryWriter(pmdFile);
+
+ //await using DisposableDictionaryAsync dataTypes = new();
+ Dictionary dataTypes = new();
+ // Type, offset
+ foreach (PmdDataType pmdData in Pmd.PmdDataTypes)
+ {
+ if(pmdData is IReferenceType reference)
+ {
+ reference.SetReferences(this);
+ }
+ }
+ writer.FSeek(0x20 + 0x10 * Pmd.PmdDataTypes.Count + 0x40);
+ foreach (var referenceType in ReferenceTables)
+ {
+ var dataType = new PmdData_RawData();
+ dataType.Type = referenceType.Key;
+ dataType.Data = referenceType.Value;
+ var start = writer.FTell();
+ dataType.SaveData(this, writer);
+ dataTypes.Add(dataType, start);
+ //writer.Write(dataTypes[dataType].Item1.ToArray());
+ }
+
+ List> writeDataTasks = new();
+ foreach (PmdDataType pmdData in Pmd.PmdDataTypes)
+ {
+ var start = writer.FTell();
+ pmdData.SaveData(this, writer);
+ dataTypes.Add(pmdData, start);
+ //writer.Write(dataTypes[pmdData].Item1.ToArray());
+ }
+
+
+ /*
+ // I know this is incredibly cursed and I have no idea why this was neccessary
+ var reversed = dataStreams.ToDictionary(x => x.Value, x => x.Key);
+ //reversed.Reverse();
+
+ // Gives us plenty of space to write
+ pmdFile.Seek(0x20 + 0x10 * Pmd.PmdDataTypes.Count + 0x40, SeekOrigin.Begin);
+ List writeFileTasks = new();
+ foreach (var bucket in Async.Interleaved(writeDataTasks))
+ { // Process tasks as they finish ie. write to file as soon as memory buffer is done
+ var t = await bucket;
+ var result = await t;
+ long offset = pmdFile.Position;
+ offsets.Add(reversed[result], offset);
+ writeFileTasks.Add(pmdFile.WriteAsync(result.GetBuffer()).AsTask());
+ }
+
+ await Task.WhenAll(writeFileTasks);
+ */
+ // Write Header
+
+
+ writer.Seek(0, SeekOrigin.Begin);
+ writer.Write((int)0); // Filetype/format/userid
+ writer.Write((int)pmdFile.Length);
+ writer.Write(Pmd.MagicCode.ToCharArray());
+ writer.Write((int)0); // Expand Size
+ writer.Write(dataTypes.Count);
+ writer.Write(Pmd.Version);
+ writer.Write((int)0); //Reserve
+ writer.Write((int)0);
+
+
+ // Create Type table
+ writer.FSeek(0x20);
+ // Write the type table in the correct order
+ //IEnumerable> dataTypes = offsets.Reverse();
+ foreach (KeyValuePair dataType in dataTypes)
+ {
+ writer.Write((int)dataType.Key.Type);
+ writer.Write((int)dataType.Key.GetSize());// Size
+ writer.Write((int)dataType.Key.GetCount());
+ writer.Write((int)dataType.Value); // Offset
+ }
+
+
+ return pmdFile;
+ }
+
+
+ ///
+ /// Creates another datatype and returns it's index
+ ///
+ ///
+ ///
+ ///
+ internal int AddReference(PmdTypeID id, byte[] data)
+ {
+ if (ReferenceTables.ContainsKey(id))
+ {
+ ReferenceTables[id].Add(data);
+ return ReferenceTables.Count-1;
+ }
+ ReferenceTables.Add(id, new List());
+ ReferenceTables[id].Add(data);
+ return ReferenceTables.Count - 1;
+ }
+
+ }
+}
diff --git a/Libellus Library/Event/PmdReader.cs b/Libellus Library/Event/PmdReader.cs
new file mode 100644
index 0000000..b2f8ad0
--- /dev/null
+++ b/Libellus Library/Event/PmdReader.cs
@@ -0,0 +1,115 @@
+using LibellusLibrary.Event.Types;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+using LibellusLibrary.JSON;
+
+
+namespace LibellusLibrary.Event
+{
+ public class PmdReader
+ {
+
+ public async Task ReadPmd(BinaryReader reader)
+ {
+ PolyMovieData _data = new();
+
+ uint typeTblCnt = _data.ReadHeader(reader);
+
+ reader.BaseStream.Position = 0x20;
+ PmdTypeFactory factory = new();
+ _data.PmdDataTypes = factory.ReadDataTypes(reader, typeTblCnt, _data.Version);
+ return _data;
+ }
+
+ public async Task ReadPmd(Stream stream, bool leaveOpen = false)
+ {
+ using (BinaryReader reader = new BinaryReader(stream, Encoding.Default, leaveOpen))
+ {
+ return await ReadPmd(reader);
+ }
+ }
+ public async Task ReadPmd(string path)
+ {
+ if (!File.Exists(path))
+ {
+ throw new ArgumentException("Error while opening file.\nFile does not exist!\nFile: " + path);
+ }
+ using (MemoryStream stream = new MemoryStream(await File.ReadAllBytesAsync(path)))
+ {
+ return await ReadPmd(stream, false);
+ }
+ }
+
+
+ }
+
+ public class PmdJsonReader : JsonConverter
+ {
+ public override PolyMovieData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+
+ var pmd = new PolyMovieData();
+ // var data = reader.ReadJSONTokens();
+
+ reader.Read(); // startobject
+ reader.Read(); // MagicCode:
+ pmd.MagicCode = reader.GetString();
+ reader.Read(); // ""
+ reader.Read(); // Version
+ pmd.Version = reader.GetUInt32();
+ reader.Read(); //
+ reader.Read(); // Data Table
+
+ pmd.PmdDataTypes = new();
+
+ reader.Read();
+ List abstractTypes = new();
+
+ var abstractReader = reader;
+
+ while (abstractReader.TokenType != JsonTokenType.EndArray)
+ {
+ var abstractType = JsonSerializer.Deserialize(ref abstractReader, options);
+ abstractTypes.Add(abstractType);
+ abstractReader.Read();
+
+ }
+
+ foreach (PmdDataType abstractType in abstractTypes)
+ {
+ Type trueDataType = PmdTypeFactory.GetTypeCreator(abstractType.Type).CreateType(pmd.Version).GetType();
+
+
+
+ pmd.PmdDataTypes.Add((PmdDataType)JsonSerializer.Deserialize(ref reader, trueDataType, options));
+ reader.Read();
+ }
+ reader.Read();
+
+ return pmd;
+ }
+
+ public override void Write(Utf8JsonWriter writer, PolyMovieData value, JsonSerializerOptions options)
+ {
+ writer.WriteStartObject();
+ writer.WritePropertyName("Magic Code");
+ writer.WriteStringValue(value.MagicCode);
+ writer.WritePropertyName("Version");
+ writer.WriteNumberValue(value.Version);
+
+ writer.WritePropertyName("Data Table");
+ writer.WriteStartArray();
+ foreach (PmdDataType data in value.PmdDataTypes)
+ {
+ writer.WriteRawValue(JsonSerializer.Serialize