From 9f62067eae20096cda6b9a7f398f868857f3b9dd Mon Sep 17 00:00:00 2001 From: Tupelov <64274155+Tupelov@users.noreply.github.com> Date: Wed, 28 Sep 2022 20:06:58 -0400 Subject: [PATCH] Complete Rewrite --- .gitignore | 50 +++- Libellus Event Editing Tool.sln | 31 +++ .../Libellus Event Tool.csproj | 34 +++ Libellus Event Tool/Program.cs | 47 ++++ .../Properties/launchSettings.json | 7 + Libellus Event Tool/Resources/App.config | 3 + .../Resources}/heeho.ico | Bin Libellus Event Tool/heeho.ico | Bin 0 -> 103953 bytes Libellus Library/Event/PmdBuilder.cs | 139 +++++++++++ Libellus Library/Event/PmdReader.cs | 115 +++++++++ Libellus Library/Event/PolyMovieData.cs | 101 ++++++++ Libellus Library/Event/Types/IExternalFile.cs | 14 ++ .../Event/Types/IReferenceType.cs | 13 + Libellus Library/Event/Types/ITypeCreator.cs | 16 ++ Libellus Library/Event/Types/IVersionable.cs | 13 + Libellus Library/Event/Types/PmdDataType.cs | 93 +++++++ .../Event/Types/PmdData_Cutinfo.cs | 96 ++++++++ .../Event/Types/PmdData_Message.cs | 88 +++++++ Libellus Library/Event/Types/PmdData_Unit.cs | 148 ++++++++++++ .../Event/Types/PmdTypeFactory.cs | 86 +++++++ Libellus Library/Event/Types/UnkType.cs | 100 ++++++++ Libellus Library/JSON/ByteArrayToHexArray.cs | 81 +++++++ Libellus Library/JSON/Utilities.cs | 55 +++++ Libellus Library/Libellus Library.csproj | 10 + Libellus Library/Utils/Async.cs | 68 ++++++ .../Utils/DisposableCollections.cs | 66 +++++ .../Utils}/IO/IOUtils.cs | 92 +++---- .../Utils/Text.cs | 50 ++-- .../LibellusEventEditingTool.csproj | 32 --- Source/Libellus Event Editing Tool/Program.cs | 43 ---- .../Properties/launchSettings.json | 8 - Source/Libellus Event Tools.sln | 37 --- .../Converters/ByteArrayJsonConverter.cs | 74 ------ .../Converters/ByteArrayToHexArray.cs | 41 ---- .../Converters/CharArrayToStringConverter.cs | 33 --- .../DontDeserializeJsonConverter.cs | 28 --- .../Converters/HexStringJsonConverter.cs | 30 --- .../Converters/IntHexDumpConverter.cs | 51 ---- Source/LibellusLibrary/IO/FileBase.cs | 87 ------- Source/LibellusLibrary/LibellusLibrary.csproj | 22 -- .../LibellusLibrary/PMD/Frames/FrameInfo.cs | 23 -- .../PMD/Frames/FrameInfoFactory.cs | 99 -------- .../PMD/Frames/Nocturne/Unknown.cs | 30 --- .../PMD/Frames/NocturneFrameFactory.cs | 36 --- .../PMD/Frames/Persona3_4/Message.cs | 87 ------- .../PMD/Frames/Persona3_4/Unknown.cs | 30 --- .../PMD/Frames/Persona3_4FrameFactory.cs | 37 --- Source/LibellusLibrary/PMD/PMDFile.cs | 226 ------------------ Source/LibellusLibrary/PMD/Types/CutInfo.cs | 145 ----------- Source/LibellusLibrary/PMD/Types/DataType.cs | 13 - Source/LibellusLibrary/PMD/Types/Frame.cs | 94 -------- .../PMD/Types/IExternalFile.cs | 12 - .../PMD/Types/IVariableSize.cs | 4 - Source/LibellusLibrary/PMD/Types/Message.cs | 45 ---- Source/LibellusLibrary/PMD/Types/Name.cs | 53 ---- .../LibellusLibrary/PMD/Types/TypeFactory.cs | 91 ------- Source/LibellusLibrary/PMD/Types/TypeTable.cs | 111 --------- Source/LibellusLibrary/PMD/Types/Unknown.cs | 38 --- Source/LibellusLibrary/PMD/Versioning.cs | 27 --- Source/LibellusLibrary/PMD/old/Common.cs | 97 -------- .../PMD/old/DataTypes/Frame/PmdFrameObject.cs | 102 -------- .../PMD/old/DataTypes/Frame/PmdFrameUnit.cs | 14 -- .../PMD/old/DataTypes/PmdDataType.cs | 186 -------------- Source/LibellusLibrary/Utils/Reflection.cs | 34 --- .../LibellusLibraryTest.csproj | 13 - Source/LibellusLibraryTest/Program.cs | 86 ------- 66 files changed, 1533 insertions(+), 2302 deletions(-) create mode 100644 Libellus Event Editing Tool.sln create mode 100644 Libellus Event Tool/Libellus Event Tool.csproj create mode 100644 Libellus Event Tool/Program.cs create mode 100644 Libellus Event Tool/Properties/launchSettings.json create mode 100644 Libellus Event Tool/Resources/App.config rename {Source/Libellus Event Editing Tool => Libellus Event Tool/Resources}/heeho.ico (100%) create mode 100644 Libellus Event Tool/heeho.ico create mode 100644 Libellus Library/Event/PmdBuilder.cs create mode 100644 Libellus Library/Event/PmdReader.cs create mode 100644 Libellus Library/Event/PolyMovieData.cs create mode 100644 Libellus Library/Event/Types/IExternalFile.cs create mode 100644 Libellus Library/Event/Types/IReferenceType.cs create mode 100644 Libellus Library/Event/Types/ITypeCreator.cs create mode 100644 Libellus Library/Event/Types/IVersionable.cs create mode 100644 Libellus Library/Event/Types/PmdDataType.cs create mode 100644 Libellus Library/Event/Types/PmdData_Cutinfo.cs create mode 100644 Libellus Library/Event/Types/PmdData_Message.cs create mode 100644 Libellus Library/Event/Types/PmdData_Unit.cs create mode 100644 Libellus Library/Event/Types/PmdTypeFactory.cs create mode 100644 Libellus Library/Event/Types/UnkType.cs create mode 100644 Libellus Library/JSON/ByteArrayToHexArray.cs create mode 100644 Libellus Library/JSON/Utilities.cs create mode 100644 Libellus Library/Libellus Library.csproj create mode 100644 Libellus Library/Utils/Async.cs create mode 100644 Libellus Library/Utils/DisposableCollections.cs rename {Source/LibellusLibrary => Libellus Library/Utils}/IO/IOUtils.cs (93%) rename {Source/LibellusLibrary => Libellus Library}/Utils/Text.cs (92%) delete mode 100644 Source/Libellus Event Editing Tool/LibellusEventEditingTool.csproj delete mode 100644 Source/Libellus Event Editing Tool/Program.cs delete mode 100644 Source/Libellus Event Editing Tool/Properties/launchSettings.json delete mode 100644 Source/Libellus Event Tools.sln delete mode 100644 Source/LibellusLibrary/Converters/ByteArrayJsonConverter.cs delete mode 100644 Source/LibellusLibrary/Converters/ByteArrayToHexArray.cs delete mode 100644 Source/LibellusLibrary/Converters/CharArrayToStringConverter.cs delete mode 100644 Source/LibellusLibrary/Converters/DontDeserializeJsonConverter.cs delete mode 100644 Source/LibellusLibrary/Converters/HexStringJsonConverter.cs delete mode 100644 Source/LibellusLibrary/Converters/IntHexDumpConverter.cs delete mode 100644 Source/LibellusLibrary/IO/FileBase.cs delete mode 100644 Source/LibellusLibrary/LibellusLibrary.csproj delete mode 100644 Source/LibellusLibrary/PMD/Frames/FrameInfo.cs delete mode 100644 Source/LibellusLibrary/PMD/Frames/FrameInfoFactory.cs delete mode 100644 Source/LibellusLibrary/PMD/Frames/Nocturne/Unknown.cs delete mode 100644 Source/LibellusLibrary/PMD/Frames/NocturneFrameFactory.cs delete mode 100644 Source/LibellusLibrary/PMD/Frames/Persona3_4/Message.cs delete mode 100644 Source/LibellusLibrary/PMD/Frames/Persona3_4/Unknown.cs delete mode 100644 Source/LibellusLibrary/PMD/Frames/Persona3_4FrameFactory.cs delete mode 100644 Source/LibellusLibrary/PMD/PMDFile.cs delete mode 100644 Source/LibellusLibrary/PMD/Types/CutInfo.cs delete mode 100644 Source/LibellusLibrary/PMD/Types/DataType.cs delete mode 100644 Source/LibellusLibrary/PMD/Types/Frame.cs delete mode 100644 Source/LibellusLibrary/PMD/Types/IExternalFile.cs delete mode 100644 Source/LibellusLibrary/PMD/Types/IVariableSize.cs delete mode 100644 Source/LibellusLibrary/PMD/Types/Message.cs delete mode 100644 Source/LibellusLibrary/PMD/Types/Name.cs delete mode 100644 Source/LibellusLibrary/PMD/Types/TypeFactory.cs delete mode 100644 Source/LibellusLibrary/PMD/Types/TypeTable.cs delete mode 100644 Source/LibellusLibrary/PMD/Types/Unknown.cs delete mode 100644 Source/LibellusLibrary/PMD/Versioning.cs delete mode 100644 Source/LibellusLibrary/PMD/old/Common.cs delete mode 100644 Source/LibellusLibrary/PMD/old/DataTypes/Frame/PmdFrameObject.cs delete mode 100644 Source/LibellusLibrary/PMD/old/DataTypes/Frame/PmdFrameUnit.cs delete mode 100644 Source/LibellusLibrary/PMD/old/DataTypes/PmdDataType.cs delete mode 100644 Source/LibellusLibrary/Utils/Reflection.cs delete mode 100644 Source/LibellusLibraryTest/LibellusLibraryTest.csproj delete mode 100644 Source/LibellusLibraryTest/Program.cs diff --git a/.gitignore b/.gitignore index d2ab86a..8a30d25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,7 @@ -# Libellus files - -# Event files -*.pm1 -*.pm2 -*.pm3 - - - - ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore # User-specific files *.rsuser @@ -100,6 +90,7 @@ StyleCopReport.xml *.tmp_proj *_wpftmp.csproj *.log +*.tlog *.vspscc *.vssscc .builds @@ -303,6 +294,17 @@ node_modules/ # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts @@ -359,6 +361,9 @@ ASALocalRun/ # Local History for Visual Studio .localhistory/ +# Visual Studio History (VSHistory) files +.vshistory/ + # BeatPulse healthcheck temp database healthchecksdb @@ -369,4 +374,25 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml diff --git a/Libellus Event Editing Tool.sln b/Libellus Event Editing Tool.sln new file mode 100644 index 0000000..238a3fc --- /dev/null +++ b/Libellus Event Editing Tool.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31919.166 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Libellus Library", "Libellus Library\Libellus Library.csproj", "{8C8535E3-BA4F-42BD-81E4-D957E5D909DD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Libellus Event Tool", "Libellus Event Tool\Libellus Event Tool.csproj", "{ECF2C9F6-3F35-4AE8-B4F6-8E9B82DB3517}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8C8535E3-BA4F-42BD-81E4-D957E5D909DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C8535E3-BA4F-42BD-81E4-D957E5D909DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C8535E3-BA4F-42BD-81E4-D957E5D909DD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C8535E3-BA4F-42BD-81E4-D957E5D909DD}.Release|Any CPU.Build.0 = Release|Any CPU + {ECF2C9F6-3F35-4AE8-B4F6-8E9B82DB3517}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECF2C9F6-3F35-4AE8-B4F6-8E9B82DB3517}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECF2C9F6-3F35-4AE8-B4F6-8E9B82DB3517}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECF2C9F6-3F35-4AE8-B4F6-8E9B82DB3517}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1CE93346-778F-40E8-8E0A-705D29BD9440} + EndGlobalSection +EndGlobal diff --git a/Libellus Event Tool/Libellus Event Tool.csproj b/Libellus Event Tool/Libellus Event Tool.csproj new file mode 100644 index 0000000..8df596e --- /dev/null +++ b/Libellus Event Tool/Libellus Event Tool.csproj @@ -0,0 +1,34 @@ + + + + Exe + Libellus_Event_Tool + enable + enable + Libellus Event Editing Tool + heeho.ico + 2.0.0 + 2.0.0 + False + + net6.0 + + + + + portable + + + + portable + + + + + + + + + + + diff --git a/Libellus Event Tool/Program.cs b/Libellus Event Tool/Program.cs new file mode 100644 index 0000000..4f623fa --- /dev/null +++ b/Libellus Event Tool/Program.cs @@ -0,0 +1,47 @@ +using LibellusLibrary.Event; + + +namespace LibellusEventTool +{ + class Program + { + static async Task Main(string[] args) + { + + System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); + System.Diagnostics.FileVersionInfo fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location); + string version = fvi.FileVersion; + Console.WriteLine("Welcome to LEET!\nLibellus Event Editing Tool: v" + version + " \nNow with better syntax!\n"); + + if (args.Length < 1) + { + Console.WriteLine("Not Enough args!"); + Console.WriteLine("Press Any Button To Exit."); + Console.ReadKey(); + return; + } + foreach (string file in args) + { + string ext = Path.GetExtension(file).ToLower(); + if (ext == ".pm1" || ext == ".pm2" || ext == ".pm3") + { + Console.WriteLine("Coverting to Json: ", file);; + PmdReader reader = new PmdReader(); + PolyMovieData pmd = await reader.ReadPmd(file); + pmd.ExtractPmd(file, Path.GetFileNameWithoutExtension(file)); + continue; + } + + if (ext == ".json") + { + Console.WriteLine("Coverting to PMD: ", file); + PolyMovieData pmd = await PolyMovieData.LoadPmd(Path.Combine(file)); + string pmdext = "PM" + pmd.MagicCode[3]; + pmd.SavePmd(file + "." + pmdext); + } + } + Console.WriteLine("Press Any Button To Exit."); + Console.ReadKey(); + } + } +} \ No newline at end of file diff --git a/Libellus Event Tool/Properties/launchSettings.json b/Libellus Event Tool/Properties/launchSettings.json new file mode 100644 index 0000000..8d91fbd --- /dev/null +++ b/Libellus Event Tool/Properties/launchSettings.json @@ -0,0 +1,7 @@ +{ + "profiles": { + "Libellus Event Tool": { + "commandName": "Project" + } + } +} \ No newline at end of file diff --git a/Libellus Event Tool/Resources/App.config b/Libellus Event Tool/Resources/App.config new file mode 100644 index 0000000..49cc43e --- /dev/null +++ b/Libellus Event Tool/Resources/App.config @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Source/Libellus Event Editing Tool/heeho.ico b/Libellus Event Tool/Resources/heeho.ico similarity index 100% rename from Source/Libellus Event Editing Tool/heeho.ico rename to Libellus Event Tool/Resources/heeho.ico diff --git a/Libellus Event Tool/heeho.ico b/Libellus Event Tool/heeho.ico new file mode 100644 index 0000000000000000000000000000000000000000..5d3b12fc115bee6c321fb4de4161afc6be3624ff GIT binary patch literal 103953 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 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(data, options)); + } + writer.WriteEndArray(); + writer.WriteEndObject(); + } + } +} diff --git a/Libellus Library/Event/PolyMovieData.cs b/Libellus Library/Event/PolyMovieData.cs new file mode 100644 index 0000000..37510ac --- /dev/null +++ b/Libellus Library/Event/PolyMovieData.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Text.Json; +using System.Text.Json.Serialization; +using LibellusLibrary.Event.Types; + +namespace LibellusLibrary.Event +{ + [JsonConverter(typeof(PmdJsonReader))] + public class PolyMovieData + { + public string MagicCode { get; set; } + public uint Version { get; set; } + + + public List PmdDataTypes { get; set; } + + //internal Dictionary> + + + //Returns TypeTable Count + public uint ReadHeader(BinaryReader reader) + { + reader.BaseStream.Position = 8; + MagicCode = new(reader.ReadChars(4)); + + reader.BaseStream.Position = 0x10; + uint TypeTableCount = reader.ReadUInt32(); + + reader.BaseStream.Position = 0x14; + Version = reader.ReadUInt32(); + + return TypeTableCount; + } + + + + /// + /// Read a JSON file and turn it into a PMD + /// + /// + /// + /// + public async Task ExtractPmd(string directoryToExtract, string filename) + { + JsonSerializerOptions options = new(); + options.WriteIndented = true; + var json = JsonSerializer.Serialize(this, options); + json = JSON.Utilities.BeautifyJson(json); + Directory.CreateDirectory(directoryToExtract); + var tasks = new List(); + tasks.Add(Task.Run(() => File.WriteAllTextAsync(Path.Combine(directoryToExtract, filename + ".json"), json))); + foreach (var dataType in PmdDataTypes) + { + if (dataType is Types.IExternalFile fileType) + { + tasks.Add(fileType.SaveExternalFile(directoryToExtract)); + } + } + + await Task.WhenAll(tasks); + } + + public static async Task LoadPmd(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))) + { + var pmd = JsonSerializer.Deserialize(stream); + List tasks = new(); + // This the final step, the last battle! + foreach (PmdDataType data in pmd.PmdDataTypes) + { + if (data is IExternalFile externalData) + { + tasks.Add(externalData.LoadExternalFile(Directory.GetParent(path).FullName)); + } + } + await Task.WhenAll(tasks); + return pmd; + } + } + + public async void SavePmd(string path) + { + + PmdBuilder builder = new(this); + //File.Create(path); + var stream = await builder.CreatePmd(path); + File.WriteAllBytes(path,stream.ToArray()); + stream.Close(); + + } + } +} diff --git a/Libellus Library/Event/Types/IExternalFile.cs b/Libellus Library/Event/Types/IExternalFile.cs new file mode 100644 index 0000000..3f1db36 --- /dev/null +++ b/Libellus Library/Event/Types/IExternalFile.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibellusLibrary.Event.Types +{ + internal interface IExternalFile + { + public Task SaveExternalFile(string directory); + public Task LoadExternalFile(string directory); + } +} diff --git a/Libellus Library/Event/Types/IReferenceType.cs b/Libellus Library/Event/Types/IReferenceType.cs new file mode 100644 index 0000000..fb977b7 --- /dev/null +++ b/Libellus Library/Event/Types/IReferenceType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibellusLibrary.Event.Types +{ + internal interface IReferenceType + { + public void SetReferences(PmdBuilder pmdBuilder); + } +} diff --git a/Libellus Library/Event/Types/ITypeCreator.cs b/Libellus Library/Event/Types/ITypeCreator.cs new file mode 100644 index 0000000..8707651 --- /dev/null +++ b/Libellus Library/Event/Types/ITypeCreator.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibellusLibrary.Event.Types +{ + public interface ITypeCreator + { + public PmdDataType? CreateType(uint version); + public PmdDataType? ReadType(BinaryReader reader, uint version, List typeIDs,PmdTypeFactory typeFactory); + + } + +} diff --git a/Libellus Library/Event/Types/IVersionable.cs b/Libellus Library/Event/Types/IVersionable.cs new file mode 100644 index 0000000..6ef5aec --- /dev/null +++ b/Libellus Library/Event/Types/IVersionable.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibellusLibrary.Event.Types +{ + internal interface IVersionable + { + public PmdDataType CreateFromVersion(uint version, BinaryReader reader); + } +} diff --git a/Libellus Library/Event/Types/PmdDataType.cs b/Libellus Library/Event/Types/PmdDataType.cs new file mode 100644 index 0000000..4e5c75b --- /dev/null +++ b/Libellus Library/Event/Types/PmdDataType.cs @@ -0,0 +1,93 @@ +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; + +namespace LibellusLibrary.Event.Types +{ + public class PmdDataType + { + [JsonPropertyOrder(-1)] + [JsonConverter(typeof(JsonStringEnumConverter))] + public PmdTypeID Type { get; set; } + + internal virtual void SaveData(PmdBuilder builder, BinaryWriter writer)=> throw new NotImplementedException(this.Type.ToString()); + internal virtual int GetCount() => throw new NotImplementedException(this.Type.ToString()); + internal virtual int GetSize() => 0; // Data size doesnt matter for certain types + } + + public class PmdDataTypeConverter : JsonConverter + { + public override PmdDataType? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + // obj = base.Read(ref reader, typeToConvert, options); + //var conv = new ; + //var type = reader.TokenType; + //reader.Read(); + //type = reader.TokenType; + /* + reader.Read(); + reader.Read(); + var typeID = (PmdTypeID)reader.GetInt32(); + var creator = PmdTypeFactory.GetTypeCreator(typeID); + read + var dataType = creator.CreateType() + + var conv = new JsonStringEnumConverter().CreateConverter(typeof(PmdTypeID), options); + + JsonSerializer.Deserialize(ref reader, options); + */ + + //var str = reader.GetString(); + //var converters = options. + //var pmdData = new PmdDataType(); + //var obj = JsonSerializer.Deserialize(ref reader, typeof(PmdDataType),options, pmdData); + //type = reader.TokenType; + //var typeID = reader.GetInt32(); + + var deser = JsonSerializer.Deserialize(ref reader, options); + throw new NotImplementedException(); + } + + public override void Write(Utf8JsonWriter writer, PmdDataType value, JsonSerializerOptions options) + { + writer.WriteRawValue(JsonSerializer.Serialize(value,options)); + } + } + + public enum PmdTypeID + { + CutInfo = 0, + Name = 1, + Stage = 2, + Unit = 3, + Frame = 4, + Camera = 5, + Message = 6, + Effect = 7, + EffectData = 8, + UnitData = 9, + F1 = 10, + F2 = 11, + FTB = 12, + SLight = 13, + SFog = 14, + Blur2 = 15, + MultBlur = 16, + DistBlur = 17, + Filter = 18, + MultFilter = 19, + RipBlur = 20, + + ObjectTable = 21, + + RainData = 25, + BezierTable = 26, + RefTable = 27, + MAX = 28 + } + +} diff --git a/Libellus Library/Event/Types/PmdData_Cutinfo.cs b/Libellus Library/Event/Types/PmdData_Cutinfo.cs new file mode 100644 index 0000000..4c1e6c8 --- /dev/null +++ b/Libellus Library/Event/Types/PmdData_Cutinfo.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibellusLibrary.Event.Types +{ + internal class PmdData_Cutinfo : PmdDataType, ITypeCreator, IVersionable + { + + public PmdDataType CreateFromVersion(uint version, BinaryReader reader) + { + return version switch { + 12=> new PmdData_P3Cutinfo(reader), + _ => throw new NotImplementedException(), + }; + + + } + + public PmdDataType? CreateType(uint version) + { + return version switch + { + 12 => new PmdData_P3Cutinfo(), + _ => throw new NotImplementedException(), + }; + } + + public PmdDataType? ReadType(BinaryReader reader, uint version, List typeIDs, PmdTypeFactory typeFactory) + { + var OriginalPos = reader.BaseStream.Position; + + reader.BaseStream.Position = OriginalPos + 0xC; + reader.BaseStream.Position = (long)reader.ReadUInt32(); + + var cut = CreateFromVersion(version, reader); + reader.BaseStream.Position = OriginalPos; + return cut; + } + } + + public class PmdData_P3Cutinfo : PmdDataType + { + public int FirstFrame { get; set; } + public int LastFrame { get; set; } + public int TotalFrame { get; set; } + + // Normally Id remove this but im not sure if its actually not used + public int Reserve1 { get; set; } + + public int FieldMajorID { get; set; } + public int FieldMinorID { get; set; } + + public short Unknown1 { get; set; } + + public short FieldFBN { get; set; } + public int FieldENV { get; set; } + + public int Flags { get; set; } + + public PmdData_P3Cutinfo() + { + return; + } + public PmdData_P3Cutinfo(BinaryReader reader) + { + FirstFrame = reader.ReadInt32(); + LastFrame = reader.ReadInt32(); + TotalFrame = reader.ReadInt32(); + Reserve1 = reader.ReadInt32(); + FieldMajorID = reader.ReadInt32(); + FieldMinorID = reader.ReadInt32(); + Unknown1 = reader.ReadInt16(); + FieldFBN = reader.ReadInt16(); + FieldENV = reader.ReadInt32(); + Flags = reader.ReadInt32(); + } + + internal override void SaveData(PmdBuilder builder, BinaryWriter writer) + { + writer.Write(FirstFrame); + writer.Write(LastFrame); + writer.Write(TotalFrame); + writer.Write(Reserve1); + writer.Write(FieldMajorID); + writer.Write(FieldMinorID); + writer.Write(Unknown1); + writer.Write(FieldFBN); + writer.Write(FieldENV); + writer.Write(Flags); + } + internal override int GetCount() => 1; + } +} diff --git a/Libellus Library/Event/Types/PmdData_Message.cs b/Libellus Library/Event/Types/PmdData_Message.cs new file mode 100644 index 0000000..a5efe78 --- /dev/null +++ b/Libellus Library/Event/Types/PmdData_Message.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Text.Json; +using System.Text.Json.Serialization; +using LibellusLibrary.JSON; +using LibellusLibrary.Utils; + +namespace LibellusLibrary.Event.Types +{ + internal class PmdData_Message : PmdDataType, ITypeCreator, IExternalFile, IReferenceType + { + public string FileName { get; set; } + + + public byte[] MessageData; + + public PmdDataType? CreateType(uint version) + { + return new PmdData_Message(); + } + + public PmdDataType? ReadType(BinaryReader reader, uint version, List typeIDs, PmdTypeFactory typeFactory) + { + var OriginalPos = reader.BaseStream.Position; + + reader.BaseStream.Position = OriginalPos + 0x4; + var size = reader.ReadUInt32(); + + reader.BaseStream.Position = OriginalPos + 0x4; + var count = reader.ReadUInt32(); + + reader.BaseStream.Position = OriginalPos + 0xC; + reader.BaseStream.Position = (long)reader.ReadUInt32(); + + + MessageData = reader.ReadBytes((int)size); + FileName = ""; + foreach (string name in typeFactory.GetNameTable(reader)) + { + if (name.EndsWith(".msg")) + { + FileName = name.Substring(0, name.LastIndexOf('.')) + ".bmd"; + break; + } + else if (name.EndsWith(".bmd")) + { + FileName = name; + break; + } + } + if (FileName == "") + { + FileName = "Message.bmd"; + } + + reader.BaseStream.Position = (long)OriginalPos; + return this; + } + + public async Task SaveExternalFile(string directory) + { + await File.WriteAllBytesAsync(Path.Combine(directory, FileName), MessageData); + } + + public async Task LoadExternalFile(string directory) + { + MessageData = await File.ReadAllBytesAsync(directory + "\\" + FileName); + } + + internal override void SaveData(PmdBuilder builder, BinaryWriter writer) + { + writer.Write(MessageData); + return; + } + internal override int GetSize() => MessageData.Length; + internal override int GetCount() => 1; + + public void SetReferences(PmdBuilder pmdBuilder) + { + byte[] temp = Text.StringtoASCII8(FileName); + System.Array.Resize(ref temp, 32); + pmdBuilder.AddReference(PmdTypeID.Name, temp); + } + } +} diff --git a/Libellus Library/Event/Types/PmdData_Unit.cs b/Libellus Library/Event/Types/PmdData_Unit.cs new file mode 100644 index 0000000..6ff7ec2 --- /dev/null +++ b/Libellus Library/Event/Types/PmdData_Unit.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using LibellusLibrary.Utils; +using LibellusLibrary.Utils.IO; + +namespace LibellusLibrary.Event.Types +{ + internal class PmdData_Unit : PmdDataType, ITypeCreator, IExternalFile, IReferenceType + { + [JsonInclude] + public List Units {get; set;} + + public PmdDataType? CreateType(uint version) + { + return new PmdData_Unit(); + } + + public async Task LoadExternalFile(string directory) + { + foreach(var unit in Units) + { + unit.UnitData = await File.ReadAllBytesAsync(directory + "\\" + unit.FileName); + } + + } + + public async Task SaveExternalFile(string directory) + { + foreach (var unit in Units) + { + await File.WriteAllBytesAsync(Path.Combine(directory, unit.FileName), unit.UnitData); + } + } + + public PmdDataType? ReadType(BinaryReader reader, uint version, List typeIDs, PmdTypeFactory typeFactory) + { + if (Units == null) + Units = new(); + var OriginalPos = reader.BaseStream.Position; + + reader.BaseStream.Position = OriginalPos + 0x4; + var size = reader.ReadUInt32(); + + reader.BaseStream.Position = OriginalPos + 0x8; + var count = reader.ReadUInt32(); + + reader.BaseStream.Position = OriginalPos + 0xC; + reader.BaseStream.Position = (long)reader.ReadUInt32(); + var unitStart = reader.FTell(); + for(int i = 0; i < count; i++) + { + reader.FSeek(unitStart + i * 0x20); + var unit = new Pmd_UnitDef(); + unit.ReadUnit(reader, typeFactory); + Units.Add(unit); + } + + reader.BaseStream.Position = (long)OriginalPos; + return this; + + } + + internal override void SaveData(PmdBuilder builder,BinaryWriter writer) + { + var start = writer.FTell(); + var dataOffset = writer.FTell()+0x20*Units.Count; + + for(int i=0; i < Units.Count;i++) + { + writer.FSeek(start + i * 0x20); + Units[i].WriteUnit(writer, dataOffset); + dataOffset += Units[i].UnitData.Length; + } + + } + + public void SetReferences(PmdBuilder pmdBuilder) + { + foreach(Pmd_UnitDef unit in Units) + { + unit.SetReferences(pmdBuilder); + } + } + + internal override int GetCount() => Units.Count; + } + internal class Pmd_UnitDef: IReferenceType + { + public string FileName { get; set; } + public byte[] UnitData; + + public int MajorID { get; set; } + public int MinorID { get; set; } + [JsonConverter(typeof(JsonStringEnumConverter))] + public ObjectType ModelType { get; set; } + + public int NameIndex; + + public void ReadUnit(BinaryReader reader, PmdTypeFactory typeFactory) + { + FileName = typeFactory.GetNameTable(reader)[reader.ReadInt32()]; + reader.ReadInt32(); // FileIndex, should be the same as above + MajorID = reader.ReadInt32(); + MinorID = reader.ReadInt32(); + var offset = reader.ReadInt32(); + var size = reader.ReadInt32(); + ModelType = (ObjectType)reader.ReadInt32(); + reader.ReadInt32();// reserve + + var originalpos = reader.BaseStream.Position; + reader.FSeek(offset); + UnitData = reader.ReadBytes(size); + reader.BaseStream.Position = originalpos; + } + public void WriteUnit(BinaryWriter writer,long unitDataOffset) + { + writer.Write(NameIndex); + writer.Write(NameIndex); + + writer.Write(MajorID); + writer.Write(MinorID); + writer.Write((int)unitDataOffset); + writer.Write(((int)UnitData.Length)); + writer.Write((int)ModelType); + writer.Write((int)0); // Reserve + + writer.FSeek(unitDataOffset); + writer.Write(UnitData); + } + + public void SetReferences(PmdBuilder pmdBuilder) + { + byte[] temp = Text.StringtoASCII8(FileName); + System.Array.Resize(ref temp, 32); + NameIndex = pmdBuilder.AddReference(PmdTypeID.Name, temp); + } + + public enum ObjectType + { + Attachment = 1, + Field_Object = 2 + } + } +} diff --git a/Libellus Library/Event/Types/PmdTypeFactory.cs b/Libellus Library/Event/Types/PmdTypeFactory.cs new file mode 100644 index 0000000..b3a3047 --- /dev/null +++ b/Libellus Library/Event/Types/PmdTypeFactory.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibellusLibrary.Event.Types +{ + public class PmdTypeFactory + { + private List _types = new(); + public List typeIDs = new(); + + public List ReadDataTypes(BinaryReader reader, uint typeTableCount, uint version) + { + + _types = new List(); + typeIDs = ReadTypes(reader, typeTableCount); + foreach(var type in typeIDs) + { + ITypeCreator typecreator = GetTypeCreator(type); + + PmdDataType? dataType = typecreator.ReadType(reader, version, typeIDs,this); + if(dataType != null) { + dataType.Type = type; + _types.Add(dataType); + } + reader.BaseStream.Position += 0x10; + } + + return _types; + } + + public static ITypeCreator GetTypeCreator(PmdTypeID Type)=> Type switch + { + PmdTypeID.Message => new PmdData_Message(), + PmdTypeID.CutInfo => new PmdData_Cutinfo(), + PmdTypeID.Unit => new PmdData_Unit(), + _ => new UnkType() + }; + + public static bool IsSerialized(PmdTypeID type) => type switch + { + PmdTypeID.UnitData => false, + PmdTypeID.Name => false, + _=>true + }; + + private List ReadTypes(BinaryReader reader, uint typeTableCount) + { + long originalpos = reader.BaseStream.Position; + List types = new List(); + + for(int i = 0; i < typeTableCount; i++) + { + types.Add((PmdTypeID)reader.ReadUInt32()); + reader.BaseStream.Position += 0x0c; + } + reader.BaseStream.Position = originalpos; + return types; + } + public List GetNameTable(BinaryReader reader) + { + var originalpos = reader.BaseStream.Position; + var names = new List(); + for(int i =0;i< typeIDs.Count; i++) + { + if(typeIDs[i] == PmdTypeID.Name) + { + reader.BaseStream.Position = 0x20 + (0x10 * i) +0x8; + var nameCount = reader.ReadUInt32(); + reader.BaseStream.Position = reader.ReadUInt32(); + + for(int j = 0;j < nameCount; j++) + { + string data = new(reader.ReadChars(32)); + names.Add(data.Replace("\0", string.Empty)); + } + + } + } + reader.BaseStream.Position = originalpos; + return names; + } + } +} diff --git a/Libellus Library/Event/Types/UnkType.cs b/Libellus Library/Event/Types/UnkType.cs new file mode 100644 index 0000000..aa05d42 --- /dev/null +++ b/Libellus Library/Event/Types/UnkType.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace LibellusLibrary.Event.Types +{ + internal class UnkType : ITypeCreator + { + public PmdDataType? CreateType(uint version) + { + return new PmdData_RawData(); + } + + public PmdDataType? ReadType(BinaryReader reader, uint version, List typeIDs, PmdTypeFactory typeFactory) + { + var OriginalPos = reader.BaseStream.Position; + + reader.BaseStream.Position += 0x8; + var cnt = reader.ReadUInt32(); + if (cnt== 0) + { + reader.BaseStream.Position = OriginalPos; + var empty = new PmdData_RawData(); + empty.Data = new(); + return empty; + } + reader.BaseStream.Position = OriginalPos; + + if (!PmdTypeFactory.IsSerialized((PmdTypeID)reader.ReadUInt32())) + { + reader.BaseStream.Position = OriginalPos; + return null; + } + + var type = new PmdData_RawData(); + reader.BaseStream.Position = OriginalPos + 0x4; + var size = reader.ReadUInt32(); + + reader.BaseStream.Position = OriginalPos + 0xC; + reader.BaseStream.Position = (long)reader.ReadUInt32(); + for(int i = 0; i < cnt; i++) + { + type.Data.Add(reader.ReadBytes((int)size)); + } + + + reader.BaseStream.Position = OriginalPos; + return type; + } + } + + internal class PmdData_RawData : PmdDataType + { + [JsonConverter(typeof(JSON.ListByteArrayToHexArray))] + public List Data { get; set; } + + public PmdData_RawData() + { + Data = new List(); + } + + // This is dumb, mem streams are synchronus + internal override void SaveData(PmdBuilder builder, BinaryWriter writer) + { + foreach (var data in Data) + { + writer.Write(data); + } + + + return; + } + internal override int GetCount() + { + return Data.Count; + } + internal override int GetSize() + { + if(Data.Count == 0) + { + return 0; + } + // Here we assume that all the data has the same length + return Data[0].Length; + } + } + // Workaround for json to not die + internal class PmdRawData + { + [JsonConverter(typeof(JSON.ByteArrayToHexArray))] + public byte[] RawData { get; set; } + public PmdRawData(byte[] data) + { + RawData = data; + } + } +} diff --git a/Libellus Library/JSON/ByteArrayToHexArray.cs b/Libellus Library/JSON/ByteArrayToHexArray.cs new file mode 100644 index 0000000..ac934fb --- /dev/null +++ b/Libellus Library/JSON/ByteArrayToHexArray.cs @@ -0,0 +1,81 @@ +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; + +namespace LibellusLibrary.JSON +{ + class ByteArrayToHexArray : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(byte[]); + } + + public override byte[]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + var hex = reader.GetString(); + if (!string.IsNullOrEmpty(hex)) + { + hex = hex.Replace(" ", string.Empty); + return Enumerable.Range(0, hex.Length) + .Where(x => x % 2 == 0) + .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) + .ToArray(); + } + } + return Enumerable.Empty().ToArray(); + } + + public override void Write(Utf8JsonWriter writer, byte[] value, JsonSerializerOptions options) + { + var bytes = value as byte[]; + var @string = BitConverter.ToString(bytes).Replace("-", " "); + writer.WriteStringValue(@string); + + } + } + class ListByteArrayToHexArray : JsonConverter> + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(List); + } + + public override List? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + List result = new List(); + reader.Read(); + while (reader.TokenType != JsonTokenType.EndArray) + { + var hex = reader.GetString(); + if (!string.IsNullOrEmpty(hex)) + { + hex = hex.Replace(" ", string.Empty); + result.Add(Enumerable.Range(0, hex.Length) + .Where(x => x % 2 == 0) + .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) + .ToArray()); + } + reader.Read(); + + } + return result; + } + public override void Write(Utf8JsonWriter writer, List value, JsonSerializerOptions options) + { + writer.WriteStartArray(); + var converter = new ByteArrayToHexArray(); + foreach (var item in value) + { + converter.Write(writer, item, options); + } + writer.WriteEndArray(); + } + } +} \ No newline at end of file diff --git a/Libellus Library/JSON/Utilities.cs b/Libellus Library/JSON/Utilities.cs new file mode 100644 index 0000000..ab08fe7 --- /dev/null +++ b/Libellus Library/JSON/Utilities.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace LibellusLibrary.JSON +{ + public static class Utilities + { + public static string BeautifyJson(string json) + { + using JsonDocument document = JsonDocument.Parse(json); + using var stream = new MemoryStream(); + using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions() { Indented = true }); + document.WriteTo(writer); + writer.Flush(); + return Encoding.UTF8.GetString(stream.ToArray()); + } + + // Assumes that we are right after start object + public static Dictionary ReadJSONTokens(this Utf8JsonReader reader) + { + var tokens = new Dictionary(); + if (reader.TokenType == JsonTokenType.StartObject) + reader.Read(); + + while (reader.TokenType!=JsonTokenType.EndObject) + { + var tokenName = reader.GetString(); + reader.Read(); + object value = null; + switch (reader.TokenType) + { + case JsonTokenType.String: + value = reader.GetString(); + + break; + + case JsonTokenType.Number: + value = reader.GetInt64(); + tokens.Add(tokenName, value); + reader.Read(); + break; + //case JsonTokenType. + }; + tokens.Add(tokenName, value); + reader.Read(); + } + + return tokens; + } + } +} diff --git a/Libellus Library/Libellus Library.csproj b/Libellus Library/Libellus Library.csproj new file mode 100644 index 0000000..2664cb8 --- /dev/null +++ b/Libellus Library/Libellus Library.csproj @@ -0,0 +1,10 @@ + + + + net6.0 + LibellusLibrary + enable + enable + + + diff --git a/Libellus Library/Utils/Async.cs b/Libellus Library/Utils/Async.cs new file mode 100644 index 0000000..4d11045 --- /dev/null +++ b/Libellus Library/Utils/Async.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibellusLibrary.Utils +{ + public static class Async + { + + /// + /// Allows you to await tasks as they complete + /// + /// + /// + /// + public static Task>[] Interleaved(IEnumerable> tasks) + { // No clue how this works just copied it from microsoft lol + var inputTasks = tasks.ToList(); + + var buckets = new TaskCompletionSource>[inputTasks.Count]; + var results = new Task>[buckets.Length]; + for (int i = 0; i < buckets.Length; i++) + { + buckets[i] = new TaskCompletionSource>(); + results[i] = buckets[i].Task; + } + + int nextTaskIndex = -1; + Action> continuation = completed => + { + var bucket = buckets[Interlocked.Increment(ref nextTaskIndex)]; + bucket.TrySetResult(completed); + }; + + foreach (var inputTask in inputTasks) + inputTask.ContinueWith(continuation, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + + return results; + } + // For when a task doesnt return anything + public static Task[] Interleaved(IEnumerable tasks) + { // No clue how this works just copied it from microsoft lol + var inputTasks = tasks.ToList(); + + var buckets = new TaskCompletionSource[inputTasks.Count]; + var results = new Task[buckets.Length]; + for (int i = 0; i < buckets.Length; i++) + { + buckets[i] = new TaskCompletionSource(); + results[i] = buckets[i].Task; + } + + int nextTaskIndex = -1; + Action continuation = completed => + { + var bucket = buckets[Interlocked.Increment(ref nextTaskIndex)]; + bucket.TrySetResult(completed); + }; + + foreach (var inputTask in inputTasks) + inputTask.ContinueWith(continuation, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + + return results; + } + } +} diff --git a/Libellus Library/Utils/DisposableCollections.cs b/Libellus Library/Utils/DisposableCollections.cs new file mode 100644 index 0000000..c2a22a6 --- /dev/null +++ b/Libellus Library/Utils/DisposableCollections.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibellusLibrary.Utils +{ + public sealed class DisposableCollection : Collection, IDisposable + where T : IDisposable + { + public DisposableCollection() + : base() + { + + } + + public DisposableCollection(IList items) + : base(items) + { + } + + public void Dispose() + { + foreach (var item in this) + { + try + { + item.Dispose(); + } + catch + { + // swallow + } + } + } + } + + public sealed class DisposableDictionaryAsync : Dictionary, IAsyncDisposable + where TValue : IAsyncDisposable + { + public DisposableDictionaryAsync() + : base() + { + } + + public DisposableDictionaryAsync(IDictionary items) + : base(items) + { + } + + + public async ValueTask DisposeAsync() + { + List tasks= new(); + foreach (var item in this) + { + tasks.Add( item.Value.DisposeAsync().AsTask()); + } + await Task.WhenAll(tasks); + return; + + } + } +} diff --git a/Source/LibellusLibrary/IO/IOUtils.cs b/Libellus Library/Utils/IO/IOUtils.cs similarity index 93% rename from Source/LibellusLibrary/IO/IOUtils.cs rename to Libellus Library/Utils/IO/IOUtils.cs index a7fad83..48c3850 100644 --- a/Source/LibellusLibrary/IO/IOUtils.cs +++ b/Libellus Library/Utils/IO/IOUtils.cs @@ -1,46 +1,46 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.IO; - -namespace LibellusLibrary.IO -{ - public static class IOUtils - { - /// - /// Makes reader seek to position. - /// - /// This reader. - /// Position to seek to. - public static void FSeek(this BinaryReader reader, long position) - { - reader.BaseStream.Position = position; - } - - public static void FSeek(this BinaryWriter writer, long position) - { - writer.BaseStream.Position = position; - } - - public static long FTell(this BinaryReader reader) - { - return reader.BaseStream.Position; - } - - public static long FTell(this BinaryWriter writer) - { - return writer.BaseStream.Position; - } - public static void FSkip(this BinaryReader reader, long position) - { - reader.BaseStream.Position += position; - } - public static void FSkip(this BinaryWriter writer, long position) - { - writer.BaseStream.Position += position; - } - - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; + +namespace LibellusLibrary.Utils.IO +{ + public static class IOUtils + { + /// + /// Makes reader seek to position. + /// + /// This reader. + /// Position to seek to. + public static void FSeek(this BinaryReader reader, long position) + { + reader.BaseStream.Position = position; + } + + public static void FSeek(this BinaryWriter writer, long position) + { + writer.BaseStream.Position = position; + } + + public static long FTell(this BinaryReader reader) + { + return reader.BaseStream.Position; + } + + public static long FTell(this BinaryWriter writer) + { + return writer.BaseStream.Position; + } + public static void FSkip(this BinaryReader reader, long position) + { + reader.BaseStream.Position += position; + } + public static void FSkip(this BinaryWriter writer, long position) + { + writer.BaseStream.Position += position; + } + + } +} diff --git a/Source/LibellusLibrary/Utils/Text.cs b/Libellus Library/Utils/Text.cs similarity index 92% rename from Source/LibellusLibrary/Utils/Text.cs rename to Libellus Library/Utils/Text.cs index acaf5d6..40fe253 100644 --- a/Source/LibellusLibrary/Utils/Text.cs +++ b/Libellus Library/Utils/Text.cs @@ -1,25 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LibellusLibrary.Utils -{ - internal class Text - { - public static string ASCII8ToString(byte[] ASCIIData) - { - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - var e = Encoding.GetEncoding("437"); - return e.GetString(ASCIIData); - } - - public static byte[] StringtoASCII8(string text) - { - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - var e = Encoding.GetEncoding("437"); - return e.GetBytes(text); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibellusLibrary.Utils +{ + public static class Text + { + public static string ASCII8ToString(byte[] ASCIIData) + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + var e = Encoding.GetEncoding("437"); + return e.GetString(ASCIIData); + } + + public static byte[] StringtoASCII8(string text) + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + var e = Encoding.GetEncoding("437"); + return e.GetBytes(text); + } + } +} diff --git a/Source/Libellus Event Editing Tool/LibellusEventEditingTool.csproj b/Source/Libellus Event Editing Tool/LibellusEventEditingTool.csproj deleted file mode 100644 index 3ad775b..0000000 --- a/Source/Libellus Event Editing Tool/LibellusEventEditingTool.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - - Exe - net5.0 - LibellusEventEditingTool - LEET - heeho.ico - Tupelov - - - LICENSE - - https://github.com/Tupelov/Libellus-Event-Tools - - - - 4 - - - - - - - - - True - - - - - diff --git a/Source/Libellus Event Editing Tool/Program.cs b/Source/Libellus Event Editing Tool/Program.cs deleted file mode 100644 index f804c2a..0000000 --- a/Source/Libellus Event Editing Tool/Program.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.IO; -using LibellusLibrary.PMD; - - -namespace LibellusEventEditingTool -{ - class Program - { - static void Main(string[] args) - { - Console.WriteLine("Welcome to LEET!\nLibellus Event Editing Tool"); - if (args.Length < 1) - { - Console.WriteLine("Not Enough args!"); - return; - } - foreach (string file in args) - { - string ext = Path.GetExtension(file).ToLower(); - if (ext == ".pm1" || ext == ".pm2" || ext == ".pm3") - { - Console.WriteLine("Coverting to Json: ", file); - PmdFile pmdFile = new(file); - pmdFile.ExtractPmd(new FileInfo(file).Directory.FullName + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(file)); - continue; - } - - if (ext == ".json") - { - Console.WriteLine("Coverting to PMD: ", file); - PmdFile pmdFile = PmdFile.FromJson(file); - string pmdext = "PM" + pmdFile.MagicCode[3]; - pmdFile.Save(file + "." + pmdext); - //pmdFile2.Save("./output/" + name + ".lib.json" + Path.GetExtension(filePath)); - } - } - Console.WriteLine("Press Any Button To Exit."); - Console.ReadKey(); - return; - } - } -} diff --git a/Source/Libellus Event Editing Tool/Properties/launchSettings.json b/Source/Libellus Event Editing Tool/Properties/launchSettings.json deleted file mode 100644 index 3488a6b..0000000 --- a/Source/Libellus Event Editing Tool/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "LibellusEventEditingTool": { - "commandName": "Project", - "commandLineArgs": "\"F:\\Modding\\Persona Modding\\Persona 3\\Files\\data\\EVENT\\test\\E340_001.PM2\" \"F:\\Modding\\Persona Modding\\Persona 3\\Files\\data\\EVENT\\test\\E340_001\\E340_001.PM2.json\"" - } - } -} \ No newline at end of file diff --git a/Source/Libellus Event Tools.sln b/Source/Libellus Event Tools.sln deleted file mode 100644 index d26f12b..0000000 --- a/Source/Libellus Event Tools.sln +++ /dev/null @@ -1,37 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31205.134 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibellusLibrary", "LibellusLibrary\LibellusLibrary.csproj", "{D5AEB525-5C8A-47CD-BD83-F4F781D161EB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibellusLibraryTest", "LibellusLibraryTest\LibellusLibraryTest.csproj", "{CC21E436-E01C-4AC4-BAF4-69C5ED6E0AB6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibellusEventEditingTool", "Libellus Event Editing Tool\LibellusEventEditingTool.csproj", "{90638B41-BE6B-4133-B8E3-6C5451794FD8}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D5AEB525-5C8A-47CD-BD83-F4F781D161EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D5AEB525-5C8A-47CD-BD83-F4F781D161EB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D5AEB525-5C8A-47CD-BD83-F4F781D161EB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D5AEB525-5C8A-47CD-BD83-F4F781D161EB}.Release|Any CPU.Build.0 = Release|Any CPU - {CC21E436-E01C-4AC4-BAF4-69C5ED6E0AB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CC21E436-E01C-4AC4-BAF4-69C5ED6E0AB6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CC21E436-E01C-4AC4-BAF4-69C5ED6E0AB6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CC21E436-E01C-4AC4-BAF4-69C5ED6E0AB6}.Release|Any CPU.Build.0 = Release|Any CPU - {90638B41-BE6B-4133-B8E3-6C5451794FD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {90638B41-BE6B-4133-B8E3-6C5451794FD8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {90638B41-BE6B-4133-B8E3-6C5451794FD8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {90638B41-BE6B-4133-B8E3-6C5451794FD8}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {69D789A5-4393-493F-890A-F1C31FD52068} - EndGlobalSection -EndGlobal diff --git a/Source/LibellusLibrary/Converters/ByteArrayJsonConverter.cs b/Source/LibellusLibrary/Converters/ByteArrayJsonConverter.cs deleted file mode 100644 index 4ec6870..0000000 --- a/Source/LibellusLibrary/Converters/ByteArrayJsonConverter.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Copied(with permission) from TGE's EvtTool -using System; -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace LibellusLibrary.Converters -{ - public sealed class ByteArrayJsonConverter : JsonConverter - { - public override void WriteJson( JsonWriter writer, byte[] value, JsonSerializer serializer ) - { - if ( value == null ) - { - writer.WriteNull(); - return; - } - - byte[] data = ( byte[] )value; - - writer.Formatting = Formatting.None; - - // Compose an array. - writer.WriteRaw( " " ); - writer.WriteStartArray(); - - for ( var i = 0; i < data.Length; i++ ) - { - writer.WriteRaw( " " ); - writer.WriteRaw( data[i].ToString() ); - if ( i != data.Length - 1 ) - writer.WriteRaw( "," ); - } - - writer.WriteRaw( " " ); - writer.WriteEndArray(); - - writer.Formatting = Formatting.Indented; - } - - public override byte[] ReadJson( JsonReader reader, Type objectType, byte[] existingValue, bool hasExistingValue, JsonSerializer serializer ) - { - if ( reader.TokenType == JsonToken.StartArray ) - { - var byteList = new List(); - - while ( reader.Read() ) - { - switch ( reader.TokenType ) - { - case JsonToken.Integer: - byteList.Add( Convert.ToByte( reader.Value ) ); - break; - case JsonToken.EndArray: - return byteList.ToArray(); - case JsonToken.Comment: - // skip - break; - default: - throw new JsonSerializationException( - $"Unexpected token when reading bytes: {reader.TokenType}" ); - } - } - - throw new JsonSerializationException( "Unexpected end when reading bytes." ); - } - else - { - throw new JsonSerializationException( - "Unexpected token parsing binary. " + $"Expected StartArray, got {reader.TokenType}." ); - } - } - } - -} \ No newline at end of file diff --git a/Source/LibellusLibrary/Converters/ByteArrayToHexArray.cs b/Source/LibellusLibrary/Converters/ByteArrayToHexArray.cs deleted file mode 100644 index 61786d4..0000000 --- a/Source/LibellusLibrary/Converters/ByteArrayToHexArray.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LibellusLibrary.Converters -{ - class ByteArrayToHexArray: JsonConverter - { - public override bool CanConvert(Type objectType) - { - return objectType == typeof(byte[]); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - if (reader.TokenType == JsonToken.String) - { - var hex = serializer.Deserialize(reader); - if (!string.IsNullOrEmpty(hex)) - { - hex = hex.Replace(" ", string.Empty); - return Enumerable.Range(0, hex.Length) - .Where(x => x % 2 == 0) - .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) - .ToArray(); - } - } - return Enumerable.Empty().ToArray(); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var bytes = value as byte[]; - var @string = BitConverter.ToString(bytes).Replace("-", " "); - serializer.Serialize(writer, @string); - } - } -} diff --git a/Source/LibellusLibrary/Converters/CharArrayToStringConverter.cs b/Source/LibellusLibrary/Converters/CharArrayToStringConverter.cs deleted file mode 100644 index 2c58683..0000000 --- a/Source/LibellusLibrary/Converters/CharArrayToStringConverter.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LibellusLibrary.Converters -{ - internal class CharArrayToStringConverter: JsonConverter - { - - public override bool CanConvert(Type objectType) - { - return objectType == typeof(char[]); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - if (reader.TokenType == JsonToken.String) - { - var hex = serializer.Deserialize(reader); - return hex.ToCharArray(); - } - return Enumerable.Empty().ToArray(); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - serializer.Serialize(writer, new string((char[])value)); - } - } -} diff --git a/Source/LibellusLibrary/Converters/DontDeserializeJsonConverter.cs b/Source/LibellusLibrary/Converters/DontDeserializeJsonConverter.cs deleted file mode 100644 index 1ad2277..0000000 --- a/Source/LibellusLibrary/Converters/DontDeserializeJsonConverter.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace LibellusLibrary.Json.Converters -{ - public sealed class DontDeserializeJsonConverter : JsonConverter - { - public override bool CanConvert( Type objectType ) - { - return true; - } - - public override bool CanWrite => false; - - public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ) - { - // Skip JObject - JObject.ReadFrom( reader ); - return null; - } - - public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/Source/LibellusLibrary/Converters/HexStringJsonConverter.cs b/Source/LibellusLibrary/Converters/HexStringJsonConverter.cs deleted file mode 100644 index ff8f3e0..0000000 --- a/Source/LibellusLibrary/Converters/HexStringJsonConverter.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LibellusLibrary.Converters -{ - public sealed class HexStringJsonConverter : JsonConverter - { - public override bool CanConvert(Type objectType) - { - return typeof(uint).Equals(objectType); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - writer.WriteValue($"0x{value:x}"); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var str = reader.ReadAsString(); - if (str == null || !str.StartsWith("0x")) - throw new JsonSerializationException(); - return Convert.ToUInt32(str); - } - } -} diff --git a/Source/LibellusLibrary/Converters/IntHexDumpConverter.cs b/Source/LibellusLibrary/Converters/IntHexDumpConverter.cs deleted file mode 100644 index fa6c902..0000000 --- a/Source/LibellusLibrary/Converters/IntHexDumpConverter.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Text; -using Newtonsoft.Json; - -namespace LibellusLibrary.Converters -{ - public sealed class IntHexDumpJsonConverter : JsonConverter - { - public override byte[] ReadJson(JsonReader reader, Type objectType, byte[] existingValue, bool hasExistingValue, JsonSerializer serializer) - { - var str = ((string)reader.Value).Replace(" ", ""); - var bytes = new byte[str.Length / 2]; - var byteIndex = 0; - for (int i = 0; i < str.Length; i += 2) - { - bytes[byteIndex++] = byte.Parse(str[i].ToString() + str[i + 1].ToString(), System.Globalization.NumberStyles.HexNumber); - } - - return bytes; - } - - public override void WriteJson(JsonWriter writer, byte[] value, JsonSerializer serializer) - { - var builder = new StringBuilder(); - var first = true; - for (int i = 0; i < value.Length; i++) - { - if (!first) - { - builder.Append(" "); - } - else - { - first = false; - } - - if (i + 3 < value.Length) - { - builder.Append($"{(value[i] << 24 | value[i + 1] << 16 | value[i + 2] << 8 | value[i + 3]):X8}"); - i += 3; - } - else - { - builder.Append($"{value[i]:X2}"); - } - } - - writer.WriteValue(builder.ToString()); - } - } -} \ No newline at end of file diff --git a/Source/LibellusLibrary/IO/FileBase.cs b/Source/LibellusLibrary/IO/FileBase.cs deleted file mode 100644 index 6ad514b..0000000 --- a/Source/LibellusLibrary/IO/FileBase.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.IO; - -namespace LibellusLibrary.IO -{ - public abstract class FileBase - { - - internal abstract void Read(BinaryReader reader); - internal abstract void Write(BinaryWriter writer); - - public void Save(string path) - { - using (BinaryWriter writer = new BinaryWriter(File.Create(path))) - { - Write(writer); - } - } - - public void Save(Stream stream, bool leaveOpen = false) - { - using (BinaryWriter writer = new BinaryWriter(stream, Encoding.Default, leaveOpen)) - { - Write(writer); - } - } - - public void Save(BinaryWriter writer) - { - Write(writer); - - } - - public void Open(string path) - { - if (!File.Exists(path)) - { - throw new ArgumentException("Error while opening file.\nFile does not exist!\nFile: "+path); - } - //Use a memory stream instead of using a file stream - using (MemoryStream stream = new MemoryStream(File.ReadAllBytes(path))) - { - Open(stream, false); - } - } - - public void Open(Stream stream, bool leaveOpen = false) - { - using (BinaryReader reader = new BinaryReader(stream, Encoding.Default, leaveOpen)) - { - Open(reader); - } - } - - public void Open(BinaryReader reader) - { - Read(reader); - } - - } - - //All FileTypes should atleast have this. - #region - /* - public class SomeFile: FileBase - { - public SomeFile(string path) { Open(path); } - public SomeFile(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public SomeFile(BinaryReader reader) { Open(reader); } - - internal override void Read(BinaryReader reader) - { - return; - } - - internal override void Write(BinaryWriter writer) - { - return; - } - } - */ - #endregion -} diff --git a/Source/LibellusLibrary/LibellusLibrary.csproj b/Source/LibellusLibrary/LibellusLibrary.csproj deleted file mode 100644 index 40768d4..0000000 --- a/Source/LibellusLibrary/LibellusLibrary.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - net5.0 - Tupelov - A library for editing the PMD event format from atlus games. - LICENSE - - - - - - - - - - True - - - - - diff --git a/Source/LibellusLibrary/PMD/Frames/FrameInfo.cs b/Source/LibellusLibrary/PMD/Frames/FrameInfo.cs deleted file mode 100644 index 5eb07d3..0000000 --- a/Source/LibellusLibrary/PMD/Frames/FrameInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using LibellusLibrary.IO; - -namespace LibellusLibrary.PMD.Frames -{ - public abstract class FrameInfo : FileBase - { - - public FrameInfo() { } - public FrameInfo(string path) { Open(path); } - public FrameInfo(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public FrameInfo(BinaryReader reader) { Open(reader); } - - - } - -} diff --git a/Source/LibellusLibrary/PMD/Frames/FrameInfoFactory.cs b/Source/LibellusLibrary/PMD/Frames/FrameInfoFactory.cs deleted file mode 100644 index c94cff7..0000000 --- a/Source/LibellusLibrary/PMD/Frames/FrameInfoFactory.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace LibellusLibrary.PMD.Frames -{ - - public static class FrameInfoFactory - { - public static Type GetVersionFrameInfoFactory(FormatVersion version) - { - Type versionFrameInfoFactory = version switch - { - FormatVersion.v4_Nocturne => typeof(NocturneFrameFactory), - FormatVersion.v12_Persona3_4 => typeof(Persona3_4FrameFactory), - FormatVersion.v13_Persona3_4 => typeof(Persona3_4FrameFactory), - _ => throw new NotImplementedException(), - }; - return versionFrameInfoFactory; - } - - public static FrameInfo CreateFrameInfo(FrameInfoType infoType, FormatVersion version, BinaryReader reader = null) - { - Type factoryType = GetVersionFrameInfoFactory(version); - - MethodInfo method = factoryType.GetMethod("CreateInfo", BindingFlags.Static | BindingFlags.Public); - object[] args = new object[] { infoType, reader }; - return (FrameInfo)method.Invoke(null, args); - } - - } - - public enum FrameInfoType : short - { - STAGE = 0, - UNIT = 1, - CAMERA = 2, - EFFECT = 3, - Message = 4, - SE = 5, - FADE = 6, - QUAKE = 7, - BLUR = 8, - LIGHT = 9, - SLIGHT = 10, - SFOG = 11, - SKY = 12, - BLUR2 = 13, - MBLUR = 14, - DBLUR = 15, - FILTER = 16, - MFILTER = 17, - BED = 18, - BGM = 19, - MG1 = 20, - MG2 = 21, - FB = 22, - RBLUR = 23, - - TMX = 24, - - EPL = 26, - HBLUR = 27, - PADACT = 28, - MOVIE = 29, - TIMEI = 30, - RENDERTEX = 31, - BISTA = 32, - CTLCAM = 33, - WAIT = 34, - B_UP = 35, - CUTIN = 36, - EVENT_EFFECT = 37, - JUMP = 38, - KEYFREE = 39, - RANDOMJUMP = 40, - CUSTOMEVENT = 41, - CONDJUMP = 42, - COND_ON = 43, - COMULVJUMP = 44, - COUNTJUMP = 45, - HOLYJUMP = 46, - FIELDOBJ = 47, - PACKMODEL = 48, - FIELDEFF = 49, - SPUSE = 50, - SCRIPT = 51, - BLURFILTER = 52, - FOG = 53, - ENV = 54, - FLDSKY = 55, - FLDNOISE = 56, - CAMERA_STATE = 57 - } -} diff --git a/Source/LibellusLibrary/PMD/Frames/Nocturne/Unknown.cs b/Source/LibellusLibrary/PMD/Frames/Nocturne/Unknown.cs deleted file mode 100644 index 736b137..0000000 --- a/Source/LibellusLibrary/PMD/Frames/Nocturne/Unknown.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.IO; -using LibellusLibrary.Converters; -using Newtonsoft.Json; - -namespace LibellusLibrary.PMD.Frames.Nocturne -{ - public class Unknown : FrameInfo - { - [JsonConverter(typeof(ByteArrayToHexArray))] - public byte[] Data; - - - public Unknown() { } - public Unknown(string path) { Open(path); } - public Unknown(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public Unknown(BinaryReader reader) { Open(reader); } - - - internal override void Read(BinaryReader reader) - { - Data = reader.ReadBytes(8); - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(Data); - } - } -} diff --git a/Source/LibellusLibrary/PMD/Frames/NocturneFrameFactory.cs b/Source/LibellusLibrary/PMD/Frames/NocturneFrameFactory.cs deleted file mode 100644 index 896be81..0000000 --- a/Source/LibellusLibrary/PMD/Frames/NocturneFrameFactory.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LibellusLibrary.PMD.Frames -{ - class NocturneFrameFactory - { - public static Type GetFrameInfoFromType(FrameInfoType infoType) - { - Type frameInfoType = infoType switch - { - _ => typeof(Nocturne.Unknown) - }; - - return frameInfoType; - } - public static FrameInfo CreateInfo(FrameInfoType infoType, BinaryReader reader=null) - { - Type frameInfoType = GetFrameInfoFromType(infoType); - - - if (reader != null) - { - return (FrameInfo)Activator.CreateInstance(frameInfoType, reader); - } - else - { - return (FrameInfo)Activator.CreateInstance(frameInfoType); - } - } - } -} diff --git a/Source/LibellusLibrary/PMD/Frames/Persona3_4/Message.cs b/Source/LibellusLibrary/PMD/Frames/Persona3_4/Message.cs deleted file mode 100644 index a1ee65f..0000000 --- a/Source/LibellusLibrary/PMD/Frames/Persona3_4/Message.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System.IO; -using LibellusLibrary.Converters; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; - -namespace LibellusLibrary.PMD.Frames.Persona3_4 -{ - internal class Message: FrameInfo - { - - [JsonConverter(typeof(ByteArrayToHexArray))] - public byte[] Flags; - public byte MessageIndex; - public byte Field0D; - public byte Field0E; - public byte Field0F; - [JsonConverter(typeof(StringEnumConverter))] - public MessageMode Mode; - public int Field14; - public int Field18; - public int Field1C; - public int Field20; - public int Field24; - public int Field28; - public int Field2C; - public int Field30; - - public Message() { } - public Message(string path) { Open(path); } - public Message(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public Message(BinaryReader reader) { Open(reader); } - - - internal override void Read(BinaryReader reader) - { - Flags = reader.ReadBytes(12); - MessageIndex = reader.ReadByte(); - Field0D = reader.ReadByte(); - Field0E = reader.ReadByte(); - Field0F = reader.ReadByte(); - Mode = (MessageMode)reader.ReadInt32(); - Field14 = reader.ReadInt32(); - Field18 = reader.ReadInt32(); - Field1C = reader.ReadInt32(); - Field20 = reader.ReadInt32(); - Field24 = reader.ReadInt32(); - Field28 = reader.ReadInt32(); - Field2C = reader.ReadInt32(); - Field30 = reader.ReadInt32(); - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(Flags); - writer.Write(MessageIndex); - writer.Write(Field0D); - writer.Write(Field0E); - writer.Write(Field0F); - writer.Write((int)Mode); - writer.Write(Field14); - writer.Write(Field18); - writer.Write(Field1C); - writer.Write(Field20); - writer.Write(Field24); - writer.Write(Field28); - writer.Write(Field2C); - writer.Write(Field30); - } - - public enum MessageMode : int - { - Stop = 0, - NoStop = 1 - } - } - - /* - * -typedef struct { - pmdDataInfo_t Data1[3]; - int MessageIndex; - MESSAGE_MODE messageMode; - pmdDataInfo_t Data2[8]; -}pmdMessageObject_t; - - */ -} diff --git a/Source/LibellusLibrary/PMD/Frames/Persona3_4/Unknown.cs b/Source/LibellusLibrary/PMD/Frames/Persona3_4/Unknown.cs deleted file mode 100644 index b97bffb..0000000 --- a/Source/LibellusLibrary/PMD/Frames/Persona3_4/Unknown.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.IO; -using LibellusLibrary.Converters; -using Newtonsoft.Json; - -namespace LibellusLibrary.PMD.Frames.Persona3_4 -{ - public class Unknown : FrameInfo - { - [JsonConverter(typeof(ByteArrayToHexArray))] - public byte[] Data; - - - public Unknown() { } - public Unknown(string path) { Open(path); } - public Unknown(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public Unknown(BinaryReader reader) { Open(reader); } - - - internal override void Read(BinaryReader reader) - { - Data = reader.ReadBytes(52); - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(Data); - } - } -} diff --git a/Source/LibellusLibrary/PMD/Frames/Persona3_4FrameFactory.cs b/Source/LibellusLibrary/PMD/Frames/Persona3_4FrameFactory.cs deleted file mode 100644 index a540d55..0000000 --- a/Source/LibellusLibrary/PMD/Frames/Persona3_4FrameFactory.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using LibellusLibrary.PMD.Frames.Persona3_4; -namespace LibellusLibrary.PMD.Frames -{ - public class Persona3_4FrameFactory - { - public static Type GetFrameInfoFromType(FrameInfoType infoType) - { - Type frameInfoType = infoType switch - { - FrameInfoType.Message=> typeof(Message), - _ => typeof(Unknown) - }; - - return frameInfoType; - } - public static FrameInfo CreateInfo(FrameInfoType infoType, BinaryReader reader = null) - { - Type frameInfoType = GetFrameInfoFromType(infoType); - - - if (reader != null) - { - return (FrameInfo)Activator.CreateInstance(frameInfoType, reader); - } - else - { - return (FrameInfo)Activator.CreateInstance(frameInfoType); - } - } - } -} diff --git a/Source/LibellusLibrary/PMD/PMDFile.cs b/Source/LibellusLibrary/PMD/PMDFile.cs deleted file mode 100644 index fe19dc7..0000000 --- a/Source/LibellusLibrary/PMD/PMDFile.cs +++ /dev/null @@ -1,226 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using Newtonsoft.Json; -using LibellusLibrary.IO; -using System.Linq; -using System; -using Newtonsoft.Json.Converters; -using LibellusLibrary.Json.Converters; -using System.Collections; -using Newtonsoft.Json.Linq; -using LibellusLibrary.Converters; - -namespace LibellusLibrary.PMD -{ - [JsonConverter(typeof(PmdFileJsonConverter))] - public class PmdFile : FileBase - { - //Header - [JsonIgnore] public byte FileType; - [JsonIgnore] public byte FileFormat; - [JsonIgnore] public short UserID; - [JsonIgnore] public int FileSize => getFileSize(); - [JsonConverter(typeof(CharArrayToStringConverter))] - public char[] MagicCode;//PMD1/PMD2/PMD3 - [JsonIgnore] public int ExpandSize; - [JsonIgnore] public int TypeTableCount => TypeTable.Count;//Expands to get{return TypeTable.Count} - [JsonConverter(typeof(StringEnumConverter))] - public FormatVersion Version; - [JsonIgnore] public int Reserve2; - [JsonIgnore] public int Reserve3; - - [JsonConverter(typeof(DontDeserializeJsonConverter))] - public List TypeTable; - - public PmdFile() { } - public PmdFile(string path) { Open(path); } - public PmdFile(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public PmdFile(BinaryReader reader) { Open(reader); } - - internal int getFileSize() - { - int fileSize = 0x20;//Header Size - fileSize = fileSize + (0x10 * TypeTable.Count);//TypeTableSize - - foreach (Types.TypeTable typeTableEntry in TypeTable) - { - fileSize += typeTableEntry.ItemSize * typeTableEntry.ItemCount; - } - return fileSize; - } - - internal override void Read(BinaryReader reader) - { - FileType = reader.ReadByte(); - FileFormat = reader.ReadByte(); - UserID = reader.ReadInt16(); - //FileSize = reader.ReadInt32(); - reader.FSkip(4);//FileSize is set using a setter - MagicCode = reader.ReadChars(4); - //Console.WriteLine(MagicCode); - ExpandSize = reader.ReadInt32(); - int typeTablecnt = reader.ReadInt32();//= TypeTableCount - Version = (FormatVersion)reader.ReadInt32(); - - //Console.WriteLine("PMD File Ver.{0}", Version); - - Reserve2 = reader.ReadInt32(); - Reserve3 = reader.ReadInt32(); - TypeTable = new List(); - - for (int i = 0; i < typeTablecnt; i++) - { - Types.TypeTable typeTable= new(reader, Version); - typeTable.Version = Version; - TypeTable.Add(typeTable); - } - - return; - - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(FileType); - writer.Write(FileFormat); - writer.Write(UserID); - writer.Write(FileSize); - writer.Write(MagicCode); - writer.Write(ExpandSize); - writer.Write(TypeTable.Count); - writer.Write((int)Version); - writer.Write(Reserve2); - writer.Write(Reserve3); - - //First we write while adjusting the data offsets - long dataStart = writer.FTell() + (0x10 * TypeTable.Count); - long dataCurrent = dataStart; - foreach (Types.TypeTable typeTableEntry in TypeTable) - { - typeTableEntry.ItemAddress = (int)dataCurrent; - typeTableEntry.Write(writer); - dataCurrent += typeTableEntry.ItemSize * typeTableEntry.ItemCount; - } - writer.FSeek(dataStart); - //Now we write the data - foreach (Types.TypeTable typeTableEntry in TypeTable) - { - foreach (Types.DataType dataTypeEntry in typeTableEntry.DataTable) - { - dataTypeEntry.Write(writer); - } - } - } - - public string ToJson() - { - return Newtonsoft.Json.JsonConvert.SerializeObject(this, Newtonsoft.Json.Formatting.Indented, new Newtonsoft.Json.JsonSerializerSettings - { - //TypeNameHandling = TypeNameHandling.Auto - - }); - } - - public static PmdFile FromJson(string jsonpath) - { - string json = File.ReadAllText(jsonpath); - - PmdFile pmdFile = Newtonsoft.Json.JsonConvert.DeserializeObject(json, new JsonSerializerSettings - - { - TypeNameHandling = TypeNameHandling.Auto - - }); - - // Save External Files - if (pmdFile.TypeTable.Find(x => x.Type == Types.DataTypeID.Name) != null) - { - List names = pmdFile.TypeTable.Find(x => x.Type == Types.DataTypeID.Name).DataTable.Cast().ToList(); - List externalListTypeTable = pmdFile.TypeTable.Where(x => Types.TypeFactory.GetDataType(x.Type, pmdFile.Version).GetInterfaces().Contains(typeof(Types.IExternalFile))).ToList(); - foreach (var type in externalListTypeTable) - { - List externalFiles = type.DataTable.Cast().ToList(); - foreach (Types.IExternalFile external in externalFiles) - { - external.LoadFile(new FileInfo(jsonpath).Directory.FullName, names[external.NameIndex].String); - } - } - } - - return pmdFile; - } - - public void ExtractPmd(string path) - { - DirectoryInfo info = Directory.CreateDirectory(path); - - // Extract External Files - if (TypeTable.Find(x => x.Type == Types.DataTypeID.Name) != null) - { - List names = TypeTable.Find(x => x.Type == Types.DataTypeID.Name).DataTable.Cast().ToList(); - List externalListTypeTable = TypeTable.Where(x => Types.TypeFactory.GetDataType(x.Type, Version).GetInterfaces().Contains(typeof(Types.IExternalFile))).ToList(); - foreach (var type in externalListTypeTable) - { - List externalFiles = type.DataTable.Cast().ToList(); - foreach (Types.IExternalFile external in externalFiles) - { - if (external.GetType() == typeof(Types.Message)) - {// Messages dont have a name index so we have to find them manually - bool nameExists = false; - foreach (var nameData in names) - { - if (nameData.String.Contains(".msg")) - { - external.SaveFile(path, nameData.String); - nameExists = true; - break; - } - - } - if (!nameExists) - { - Console.WriteLine("WARNING: Couldnt find the name for the message! Adding a new name: message.msg"); - var name = new Types.Name(); - name.String = "message.msg"; - names.Add(name); - external.SaveFile(path, name.String); - } - - } - external.SaveFile(path, names[external.NameIndex].String); - } - } - } - - string json = ToJson(); - File.WriteAllText(path + Path.DirectorySeparatorChar + info.Name + ".PM" + MagicCode[3] + ".json", json); - } - - } - - public sealed class PmdFileJsonConverter : JsonConverter - { - public override void WriteJson(JsonWriter writer, PmdFile value, JsonSerializer serializer) { } - public override bool CanWrite => false; - - public override PmdFile ReadJson(JsonReader reader, Type objectType, PmdFile existingValue, bool hasExistingValue, JsonSerializer serializer) - { - var jsonObject = JObject.Load(reader); - var pmdFile = new PmdFile(); - serializer.Populate(jsonObject.CreateReader(), pmdFile); - pmdFile.TypeTable = new(); - JArray typeTable = (JArray)jsonObject["TypeTable"]; - - for (int i = 0; i < typeTable.Count; i++) - { - pmdFile.TypeTable.Add(new Types.TypeTable(pmdFile.Version)); - // This is kinda a hacky fix but it works, we're pretty much handling the JsonConverter - // ourselves so that we can pass a typeTable that already has Version set. - pmdFile.TypeTable[i].ReadJson(typeTable[i].CreateReader(), serializer, pmdFile.Version); - - - } - return pmdFile; - } - } -} diff --git a/Source/LibellusLibrary/PMD/Types/CutInfo.cs b/Source/LibellusLibrary/PMD/Types/CutInfo.cs deleted file mode 100644 index 9f66297..0000000 --- a/Source/LibellusLibrary/PMD/Types/CutInfo.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Text.Json.Serialization; - -namespace LibellusLibrary.PMD.Types -{ - public abstract class CutInfo : DataType, IVersioningHandler - { - - public override DataTypeID TypeID => DataTypeID.CutInfo; - - [JsonIgnore] public FormatVersion Version; - - public static Type GetTypeFromVersion(FormatVersion version) - { - if (CutinfoPersona3_4.GetSupportedVersions().Contains(version)) - { - return typeof(CutinfoPersona3_4); - } - else if (CutinfoNocturne.GetSupportedVersions().Contains(version)) - { - return typeof(CutinfoNocturne); - } - throw new System.NotImplementedException(); - } - - Type IVersioningHandler.GetTypeFromVersion(FormatVersion version) - { - return GetTypeFromVersion(version); - } - - - } - public class CutinfoNocturne : CutInfo, IVersioning - { - - public int FirstFrame; - public int LastFrame; - public int TotalFrame; - public int Reserve1; - - public CutinfoNocturne() { } - public CutinfoNocturne(string path, FormatVersion version) { Version = version; Open(path); } - public CutinfoNocturne(Stream stream, FormatVersion version, bool leaveOpen = false) { Version = version; Open(stream, leaveOpen); } - public CutinfoNocturne(BinaryReader reader, FormatVersion version) { Version = version; Open(reader); } - - internal override void Read(BinaryReader reader) - { - FirstFrame = reader.ReadInt32(); - LastFrame = reader.ReadInt32(); - TotalFrame = reader.ReadInt32(); - Reserve1 = reader.ReadInt32(); - return; - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(FirstFrame); - writer.Write(LastFrame); - writer.Write(TotalFrame); - writer.Write(Reserve1); - return; - } - - FormatVersion[] IVersioning.GetSupportedVersions() - { - return GetSupportedVersions(); - } - - - public static FormatVersion[] GetSupportedVersions() - { - return new FormatVersion[] { - FormatVersion.v3_Nocturne, - FormatVersion.v4_Nocturne - }; - } - - } - public class CutinfoPersona3_4 : CutInfo, IVersioning - { - - FormatVersion[] IVersioning.GetSupportedVersions() - { - return GetSupportedVersions(); - } - - - public static FormatVersion[] GetSupportedVersions() - { - return new FormatVersion[] { - FormatVersion.v12_Persona3_4, - FormatVersion.v13_Persona3_4 - }; - } - - - public int FirstFrame; - public int LastFrame; - public int TotalFrame; - public int Reserve1; - public int FieldMajorNo; - public int FieldMinorNo; - public short Field18; - public short FieldFBN; - public int FieldENV; - public int Field20; - - public CutinfoPersona3_4() { } - public CutinfoPersona3_4(string path, FormatVersion version) { Version = version; Open(path); } - public CutinfoPersona3_4(Stream stream, FormatVersion version, bool leaveOpen = false) { Version = version; Open(stream, leaveOpen); } - public CutinfoPersona3_4(BinaryReader reader,FormatVersion version) { Version = version; Open(reader); } - - internal override void Read(BinaryReader reader) - { - FirstFrame = reader.ReadInt32(); - LastFrame = reader.ReadInt32(); - TotalFrame = reader.ReadInt32(); - Reserve1 = reader.ReadInt32(); - FieldMajorNo = reader.ReadInt32(); - FieldMinorNo = reader.ReadInt32(); - Field18 = reader.ReadInt16(); - FieldFBN = reader.ReadInt16(); - FieldENV = reader.ReadInt32(); - Field20 = reader.ReadInt32(); - return; - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(FirstFrame); - writer.Write(LastFrame); - writer.Write(TotalFrame); - writer.Write(Reserve1); - writer.Write(FieldMajorNo); - writer.Write(FieldMinorNo); - writer.Write(Field18); - writer.Write(FieldFBN); - writer.Write(FieldENV); - writer.Write(Field20); - return; - } - } -} diff --git a/Source/LibellusLibrary/PMD/Types/DataType.cs b/Source/LibellusLibrary/PMD/Types/DataType.cs deleted file mode 100644 index 9021cec..0000000 --- a/Source/LibellusLibrary/PMD/Types/DataType.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Newtonsoft.Json; -using LibellusLibrary.IO; - -namespace LibellusLibrary.PMD.Types -{ - - public abstract class DataType : FileBase - { - [JsonIgnore] public abstract DataTypeID TypeID { get; } - } - - -} diff --git a/Source/LibellusLibrary/PMD/Types/Frame.cs b/Source/LibellusLibrary/PMD/Types/Frame.cs deleted file mode 100644 index 7420be5..0000000 --- a/Source/LibellusLibrary/PMD/Types/Frame.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using LibellusLibrary.Converters; -using LibellusLibrary.Json.Converters; -using LibellusLibrary.PMD.Frames; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using System.Reflection; -using Newtonsoft.Json.Linq; - -namespace LibellusLibrary.PMD.Types -{ - - //[JsonConverter(typeof(FrameInfo))] - public class Frame : DataType, IVersioningHandler, IVersioning - { - [JsonIgnore] public override DataTypeID TypeID => DataTypeID.Frame; - - [JsonIgnore] public FormatVersion Version; - - Type IVersioningHandler.GetTypeFromVersion(FormatVersion version) { return GetTypeFromVersion(version); } - public static Type GetTypeFromVersion(FormatVersion version) - { - if (GetSupportedVersions().Contains(version)) - { - return typeof(Frame); - } - - throw new System.NotImplementedException(); - } - - FormatVersion[] IVersioning.GetSupportedVersions() { return GetSupportedVersions(); } - public static FormatVersion[] GetSupportedVersions() - { - return new FormatVersion[] { - FormatVersion.v4_Nocturne, - FormatVersion.v12_Persona3_4, - FormatVersion.v13_Persona3_4 - }; - } - - - - - [JsonConverter(typeof(StringEnumConverter))] - public FrameInfoType InfoType; - public ushort FrameStart; - public ushort Length; - public short NameIndex; - [JsonConverter(typeof(DontDeserializeJsonConverter))] - public FrameInfo FrameInfo; - - public Frame(FormatVersion version) { Version = version; } - public Frame(string path, FormatVersion version) { Version = version; Open(path); } - public Frame(Stream stream, FormatVersion version, bool leaveOpen = false) { Version = version; Open(stream, leaveOpen); } - public Frame(BinaryReader reader, FormatVersion version) { Version = version; Open(reader); } - - internal override void Read(BinaryReader reader) - { - InfoType = (FrameInfoType)reader.ReadInt16(); - FrameStart = reader.ReadUInt16(); - Length = reader.ReadUInt16(); - NameIndex = reader.ReadInt16(); - FrameInfo = FrameInfoFactory.CreateFrameInfo(InfoType, Version, reader); - return; - } - - internal override void Write(BinaryWriter writer) - { - writer.Write((short)InfoType); - writer.Write(FrameStart); - writer.Write(Length); - writer.Write(NameIndex); - FrameInfo.Write(writer); - return; - } - - public static Frame ReadJson(JsonReader reader, JsonSerializer serializer, FormatVersion version) - { - var jsonObject = JObject.Load(reader); - var frame = new Frame(version); - serializer.Populate(jsonObject.CreateReader(), frame); - //serializer.Populate(jsonObject["DataTable"].CreateReader(), data); - - Type infoType = (Type)Frames.FrameInfoFactory.GetVersionFrameInfoFactory(version).GetMethod("GetFrameInfoFromType", BindingFlags.Static | BindingFlags.Public).Invoke(null,new object[] { frame.InfoType}); - frame.FrameInfo = (FrameInfo)Activator.CreateInstance(infoType); - serializer.Populate(jsonObject["FrameInfo"].CreateReader(), frame.FrameInfo); - return frame; - - } - } - -} diff --git a/Source/LibellusLibrary/PMD/Types/IExternalFile.cs b/Source/LibellusLibrary/PMD/Types/IExternalFile.cs deleted file mode 100644 index f640fa5..0000000 --- a/Source/LibellusLibrary/PMD/Types/IExternalFile.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace LibellusLibrary.PMD.Types -{ - interface IExternalFile - { - public int NameIndex { get; set; } - public byte[] Data { get; set; } - public int DataSize { get; set; } // Only used during reading - - public void SaveFile(string dir, string file); - public void LoadFile(string dir, string file); - } -} diff --git a/Source/LibellusLibrary/PMD/Types/IVariableSize.cs b/Source/LibellusLibrary/PMD/Types/IVariableSize.cs deleted file mode 100644 index cf52eaf..0000000 --- a/Source/LibellusLibrary/PMD/Types/IVariableSize.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace LibellusLibrary.PMD.Types -{ - interface IVariableSize {} -} diff --git a/Source/LibellusLibrary/PMD/Types/Message.cs b/Source/LibellusLibrary/PMD/Types/Message.cs deleted file mode 100644 index ede2b98..0000000 --- a/Source/LibellusLibrary/PMD/Types/Message.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Diagnostics; -using System.IO; - -using Newtonsoft.Json; - -namespace LibellusLibrary.PMD.Types -{ - - public class Message : DataType, IVariableSize, IExternalFile - { - public override DataTypeID TypeID => DataTypeID.Name; - - [JsonIgnore] public byte[] Data { get; set; } - [JsonIgnore] public int DataSize { get; set; } - public int NameIndex { get => 0; set { } } - - public Message() { } - public Message(string path) { Open(path); } - public Message(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public Message(BinaryReader reader, int size) { DataSize = size; Open(reader); } - - internal override void Read(BinaryReader reader) - { - Data = reader.ReadBytes(DataSize); - return; - } - internal override void Write(BinaryWriter writer) - { - writer.Write(Data); - } - - // No decompiling support yet so this will have to do - public void LoadFile(string dir, string file) - { - file = file.Replace("msg", "bmd"); - Data = File.ReadAllBytes(dir + Path.DirectorySeparatorChar + file); - } - - public void SaveFile(string dir, string file) - { - file = file.Replace("msg", "bmd"); - File.WriteAllBytes(dir + Path.DirectorySeparatorChar + file, Data); - } - } -} diff --git a/Source/LibellusLibrary/PMD/Types/Name.cs b/Source/LibellusLibrary/PMD/Types/Name.cs deleted file mode 100644 index 16f6b2a..0000000 --- a/Source/LibellusLibrary/PMD/Types/Name.cs +++ /dev/null @@ -1,53 +0,0 @@ -using LibellusLibrary.Converters; -using Newtonsoft.Json; -using System.Diagnostics; -using System.IO; -using System.Linq; -using LibellusLibrary.Utils; - -namespace LibellusLibrary.PMD.Types -{ - [DebuggerDisplay("Name: {String}")] - public class Name : DataType - { - public override DataTypeID TypeID => DataTypeID.Name; - - public string String - { - get { return _string.Replace("\0", string.Empty); } - set - { - if (value.Length > 32) - { - throw new System.Exception("Name can only be 32 characters!\nInputed String: " + value); - } - _string = value; - } - } - - private string _string; - - // [JsonConverter(typeof(CharArrayToStringConverter))] - // public char[] Chars; - - public Name() { } - public Name(string path) { Open(path); } - public Name(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public Name(BinaryReader reader) { Open(reader); } - - internal override void Read(BinaryReader reader) - { - byte[] temp = reader.ReadBytes(32); - //Chars = temp; - // - String = Text.ASCII8ToString(temp); - return; - } - internal override void Write(BinaryWriter writer) - { - byte[] temp = Text.StringtoASCII8(String); - System.Array.Resize(ref temp, 32); - writer.Write(temp); - } - } -} diff --git a/Source/LibellusLibrary/PMD/Types/TypeFactory.cs b/Source/LibellusLibrary/PMD/Types/TypeFactory.cs deleted file mode 100644 index 68282a7..0000000 --- a/Source/LibellusLibrary/PMD/Types/TypeFactory.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Reflection; - -using LibellusLibrary.Utils; - -namespace LibellusLibrary.PMD.Types -{ - public static class TypeFactory - { - public static DataType CreateDataType(DataTypeID type, FormatVersion version) - { - Type dataType = GetDataType(type, version); - return (DataType)Activator.CreateInstance(dataType); - } - - public static DataType CreateDataType(DataTypeID type, BinaryReader reader, FormatVersion version, int size = 0) - { - Type dataType = GetDataType(type, version); - if(dataType.HasInterface(typeof(IVariableSize))) - { - if (dataType == typeof(Unknown)) - { - return (DataType)Activator.CreateInstance(dataType, reader, size, type); - } - return (DataType)Activator.CreateInstance(dataType, reader, size); - }else if (dataType.HasInterface(typeof(IVersioning))) - { - return (DataType)Activator.CreateInstance(dataType, reader, version); - } - else - { - return (DataType)Activator.CreateInstance(dataType, reader); - } - - } - - public static Type GetDataType(DataTypeID type, FormatVersion version) - { - Type dataType = type switch - { - DataTypeID.CutInfo => typeof(CutInfo), - DataTypeID.Name => typeof(Name), - DataTypeID.Frame => typeof(Frame), - DataTypeID.Message => typeof(Message), - _ => typeof(Unknown) - }; - if (dataType.HasInterface(typeof(IVersioningHandler))) - { - MethodInfo method = dataType.GetMethod("GetTypeFromVersion", BindingFlags.Static | BindingFlags.Public); - object[] args = { version }; - dataType = (Type)method.Invoke(null, args); - } - return dataType; - } - } - - - public enum DataTypeID : int - { - CutInfo = 0, - Name = 1, - Stage = 2, - Unit = 3, - Frame = 4, - Camera = 5, - Message = 6, - Effect = 7, - EffectData = 8, - UnitData = 9, - F1 = 10, - F2 = 11, - FTB = 12, - SLight = 13, - SFog = 14, - Blur2 = 15, - MultBlur = 16, - DistBlur = 17, - Filter = 18, - MultFilter = 19, - RipBlur = 20, - - ObjectTable = 21, - - RainData = 25, - BezierTable = 26, - RefTable = 27, - MAX = 28 - } -} diff --git a/Source/LibellusLibrary/PMD/Types/TypeTable.cs b/Source/LibellusLibrary/PMD/Types/TypeTable.cs deleted file mode 100644 index 948a27d..0000000 --- a/Source/LibellusLibrary/PMD/Types/TypeTable.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.IO; -using Newtonsoft.Json; -using LibellusLibrary.IO; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Linq; -using LibellusLibrary.Json.Converters; -using System.Collections; -using LibellusLibrary.Utils; - -namespace LibellusLibrary.PMD.Types -{ - //[JsonConverter(typeof(TypeTableJsonConverter))] - public class TypeTable : FileBase - { - [JsonIgnore] public FormatVersion Version { get; set; } - - [JsonConverter(typeof(StringEnumConverter))] - public DataTypeID Type; - public int ItemSize; - [JsonIgnore] public int ItemCount => DataTable.Count; - [JsonIgnore] public int ItemAddress; - - [JsonConverter(typeof(DontDeserializeJsonConverter))] - public List DataTable; - - - public TypeTable(FormatVersion version) { Version = version; } - public TypeTable(string path, FormatVersion version) { Version = version; Open(path); } - public TypeTable(Stream stream, FormatVersion version, bool leaveOpen = false) { Version = version; Open(stream, leaveOpen); } - public TypeTable(BinaryReader reader, FormatVersion version) { Version = version; Open(reader); } - - public TypeTable(DataTypeID type, int itemSize, List dataTable, Version version) - { - Type = type; - ItemSize = itemSize; - ItemAddress = 0; - DataTable = dataTable; - return; - } - - - internal override void Read(BinaryReader reader) - { - Type = (DataTypeID)reader.ReadInt32(); - ItemSize = reader.ReadInt32(); - int dataCount = reader.ReadInt32(); - ItemAddress = reader.ReadInt32(); - DataTable = new List(); - - long currentPos = reader.FTell(); - reader.FSeek(ItemAddress); - for (int i = 0; i < dataCount; i++) - { - DataType Entry = TypeFactory.CreateDataType(Type, reader, Version, ItemSize); - DataTable.Add(Entry); - } - reader.FSeek(currentPos); - } - - internal override void Write(BinaryWriter writer) - { - writer.Write((int)Type); - writer.Write(ItemSize); - writer.Write(ItemCount); - writer.Write(ItemAddress); - return; - } - public void ReadJson(JsonReader reader, JsonSerializer serializer, FormatVersion version) - { - var jsonObject = JObject.Load(reader); - serializer.Populate(jsonObject.CreateReader(), this); - - Type type = TypeFactory.GetDataType(Type, Version); - - var data = Reflection.CreateListFromType(type); - if(type == typeof(Frame)) - { // Special handling for frames - for(int i = 0; i < jsonObject["DataTable"].Count(); i++) - { - data.Add(Frame.ReadJson(jsonObject["DataTable"][i].CreateReader(), serializer, version)); - } - DataTable = data.Cast().ToList(); - return; - } - try - { - serializer.Populate(jsonObject["DataTable"].CreateReader(), data); - } - catch (Newtonsoft.Json.JsonSerializationException e) - { - Console.WriteLine("An exception occured! We'll try to roll with it anyways."); - Console.WriteLine(e); - } - if (data.GetType() == typeof(List)) - { - foreach (Unknown unkData in data) - { - unkData.SetType(Type); - } - } - DataTable = data.Cast().ToList(); - - } - - } - - -} diff --git a/Source/LibellusLibrary/PMD/Types/Unknown.cs b/Source/LibellusLibrary/PMD/Types/Unknown.cs deleted file mode 100644 index 20b59bf..0000000 --- a/Source/LibellusLibrary/PMD/Types/Unknown.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.IO; -using Newtonsoft.Json; -using LibellusLibrary.Converters; - -namespace LibellusLibrary.PMD.Types -{ - public class Unknown : DataType, IVariableSize - { - public override DataTypeID TypeID => _typeID; - private DataTypeID _typeID; - - [JsonConverter(typeof(ByteArrayToHexArray))] - public byte[] Data; - [JsonIgnore] public int DataSize; - - public Unknown() { } - public Unknown(DataTypeID type) { _typeID = type; } - public Unknown(string path, int size, DataTypeID type) { DataSize = size; Open(path); _typeID = type; } - public Unknown(Stream stream, int size, DataTypeID type, bool leaveOpen = false) { DataSize = size; Open(stream, leaveOpen); _typeID = type; } - public Unknown(BinaryReader reader, int size, DataTypeID type) { DataSize = size; Open(reader); _typeID = type; } - - internal override void Read(BinaryReader reader) - { - Data = reader.ReadBytes(DataSize); - return; - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(Data); - } - - public void SetType(DataTypeID type) - { - _typeID = type; - } - } -} diff --git a/Source/LibellusLibrary/PMD/Versioning.cs b/Source/LibellusLibrary/PMD/Versioning.cs deleted file mode 100644 index 59f2a2f..0000000 --- a/Source/LibellusLibrary/PMD/Versioning.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LibellusLibrary.PMD -{ - - public enum FormatVersion : int - { - v3_Nocturne = 3, - v4_Nocturne = 4, - v12_Persona3_4=12, - v13_Persona3_4 = 13, - } - // Classes that implement this will have FormatVersion at the end of all of their constructors - interface IVersioning - { - public FormatVersion[] GetSupportedVersions(); - } - - interface IVersioningHandler - { - public Type GetTypeFromVersion(FormatVersion version); - } -} diff --git a/Source/LibellusLibrary/PMD/old/Common.cs b/Source/LibellusLibrary/PMD/old/Common.cs deleted file mode 100644 index e93b891..0000000 --- a/Source/LibellusLibrary/PMD/old/Common.cs +++ /dev/null @@ -1,97 +0,0 @@ -/* -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using LibellusLibrary.PmdFile.DataTypes; - -namespace LibellusLibrary.PmdFile.Common -{ - #region Enums - - - - public enum FrameObjectType: short - { - STAGE = 0, - UNIT = 1, - CAMERA = 2, - EFFECT = 3, - MESSAGE = 4, - SE = 5, - FADE = 6, - QUAKE = 7, - BLUR = 8, - LIGHT = 9, - SLIGHT = 10, - SFOG = 11, - SKY = 12, - BLUR2 = 13, - MBLUR = 14, - DBLUR = 15, - FILTER = 16, - MFILTER = 17, - BED = 18, - BGM = 19, - MG1 = 20, - MG2 = 21, - FB = 22, - RBLUR = 23, - - TMX = 24, - - EPL = 26, - HBLUR = 27, - PADACT = 28, - MOVIE = 29, - TIMEI = 30, - RENDERTEX = 31, - BISTA = 32, - CTLCAM = 33, - WAIT = 34, - B_UP = 35, - CUTIN = 36, - EVENT_EFFECT = 37, - JUMP = 38, - KEYFREE = 39, - RANDOMJUMP = 40, - CUSTOMEVENT = 41, - CONDJUMP = 42, - COND_ON = 43, - COMULVJUMP = 44, - COUNTJUMP = 45, - HOLYJUMP = 46, - FIELDOBJ = 47, - PACKMODEL = 48, - FIELDEFF = 49, - SPUSE = 50, - SCRIPT = 51, - BLURFILTER = 52, - FOG = 53, - ENV = 54, - FLDSKY = 55, - FLDNOISE = 56, - CAMERA_STATE = 57 - } - - public enum FrameFlagType : short - { - Disable = 0, - Local = 1, - Global = 2, - } - - public enum GlobalFlagType : short - { - Event = 0, - Commu = 1, - Sys = 2, - } - #endregion Enums - - -} -*/ \ No newline at end of file diff --git a/Source/LibellusLibrary/PMD/old/DataTypes/Frame/PmdFrameObject.cs b/Source/LibellusLibrary/PMD/old/DataTypes/Frame/PmdFrameObject.cs deleted file mode 100644 index a1c4b9c..0000000 --- a/Source/LibellusLibrary/PMD/old/DataTypes/Frame/PmdFrameObject.cs +++ /dev/null @@ -1,102 +0,0 @@ -/* -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using System.IO; -using LibellusLibrary.PmdFile.Common; -using LibellusLibrary.IO; - -namespace LibellusLibrary.PmdFile.DataTypes.Frame -{ - - public abstract class PmdFrameObject : FileBase - { - - public static PmdFrameObject CreateFrameObject(FrameObjectType type, BinaryReader reader) - { - PmdFrameObject Entry = type switch - { - //DataTypeID.CutInfo => new PmdDataCutInfo(reader), - //DataTypeID.Name => new PmdDataName(reader), - _ => new PmdFrameUnknown(reader) - }; - return Entry; - - } - - } - - public class PmdFrameUnknown : PmdFrameObject - { - - public byte[] Data; - - public PmdFrameUnknown() { Data=new byte[52]; } - public PmdFrameUnknown(string path) { Open(path); } - public PmdFrameUnknown(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public PmdFrameUnknown(BinaryReader reader) { Open(reader); } - - - internal override void Read(BinaryReader reader) - { - Data = reader.ReadBytes(52); - return; - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(Data); - return; - } - - } - public class PmdFrameFlag : FileBase - { - - FrameFlagType Type; - short FlagNo; - short CmpValue; - GlobalFlagType GFlagType; - - - public PmdFrameFlag(string path) { Open(path); } - public PmdFrameFlag(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public PmdFrameFlag(BinaryReader reader) { Open(reader); } - - - internal override void Read(BinaryReader reader) - { - Type = (FrameFlagType)reader.ReadInt16(); - FlagNo = reader.ReadInt16(); - CmpValue = reader.ReadInt16(); - if (Type == FrameFlagType.Global) - { - GFlagType = (GlobalFlagType)reader.ReadInt16(); - } - - return; - } - - internal override void Write(BinaryWriter writer) - { - writer.Write((short)Type); - writer.Write(FlagNo); - writer.Write(CmpValue); - if (Type == FrameFlagType.Global) - { - writer.Write((short)GFlagType); - } - else - { - writer.Write((short)0); - } - return; - } - - } - -} -*/ \ No newline at end of file diff --git a/Source/LibellusLibrary/PMD/old/DataTypes/Frame/PmdFrameUnit.cs b/Source/LibellusLibrary/PMD/old/DataTypes/Frame/PmdFrameUnit.cs deleted file mode 100644 index 702488a..0000000 --- a/Source/LibellusLibrary/PMD/old/DataTypes/Frame/PmdFrameUnit.cs +++ /dev/null @@ -1,14 +0,0 @@ -/* -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LibellusLibrary.PmdFile.DataTypes.Frame -{ - class PmdFrameUnit - { - } -} -*/ \ No newline at end of file diff --git a/Source/LibellusLibrary/PMD/old/DataTypes/PmdDataType.cs b/Source/LibellusLibrary/PMD/old/DataTypes/PmdDataType.cs deleted file mode 100644 index 39d277d..0000000 --- a/Source/LibellusLibrary/PMD/old/DataTypes/PmdDataType.cs +++ /dev/null @@ -1,186 +0,0 @@ -/* -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using System.IO; -using LibellusLibrary.IO; -using System.Diagnostics; - - -namespace LibellusLibrary.PmdFile.DataTypes -{ - - public abstract class PmdDataType : FileBase - { - - - - } - - public class PmdDataUnknown : PmdDataType - { - public byte[] Data; - public int DataSize; - - public PmdDataUnknown() { } - public PmdDataUnknown(string path, int size) { DataSize = size; Open(path); } - public PmdDataUnknown(Stream stream, int size, bool leaveOpen = false) { DataSize = size; Open(stream, leaveOpen); } - public PmdDataUnknown(BinaryReader reader, int size) { DataSize = size; Open(reader); } - - internal override void Read(BinaryReader reader) - { - Data = reader.ReadBytes(DataSize); - return; - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(Data); - } - } - - public class PmdDataCutInfo : PmdDataType - { - - public int FirstFrame; - public int LastFrame; - public int TotalFrame; - public int Reserve1; - public int FieldMajorNo; - public int FieldMinorNo; - public short Field18; - public short FieldFBN; - public int FieldENV; - public int Field20; - - public PmdDataCutInfo() { } - public PmdDataCutInfo(string path) { Open(path); } - public PmdDataCutInfo(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public PmdDataCutInfo(BinaryReader reader) { Open(reader); } - - internal override void Read(BinaryReader reader) - { - FirstFrame = reader.ReadInt32(); - LastFrame = reader.ReadInt32(); - TotalFrame = reader.ReadInt32(); - Reserve1 = reader.ReadInt32(); - FieldMajorNo = reader.ReadInt32(); - FieldMinorNo = reader.ReadInt32(); - Field18 = reader.ReadInt16(); - FieldFBN = reader.ReadInt16(); - FieldENV = reader.ReadInt32(); - Field20 = reader.ReadInt32(); - return; - } - - internal override void Write(BinaryWriter writer) - { - writer.Write(FirstFrame); - writer.Write(LastFrame); - writer.Write(TotalFrame); - writer.Write(Reserve1); - writer.Write(FieldMajorNo); - writer.Write(FieldMinorNo); - writer.Write(Field18); - writer.Write(FieldFBN); - writer.Write(FieldENV); - writer.Write(Field20); - return; - } - } - - [DebuggerDisplay("Name: {DebuggerDisplay}")] - public class PmdDataName : PmdDataType - { - - private string DebuggerDisplay { get { return new string(Name); } } - - - public char[] Name; - - public PmdDataName(string path) { Open(path); } - public PmdDataName(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public PmdDataName(BinaryReader reader) { Open(reader); } - - internal override void Read(BinaryReader reader) - { - Name = reader.ReadChars(32); - return; - } - internal override void Write(BinaryWriter writer) - { - writer.Write(Name); - } - } - - public class PmdDataUnitTable : FileBase - { - public int NameIndex; - public int FileIndex; - public int MajorNum; - public int MinorNum; - public int DataSize; - public int Unknown1; - public int Reserve1; - - - public PmdDataUnitTable(string path) { Open(path); } - public PmdDataUnitTable(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public PmdDataUnitTable(BinaryReader reader) { Open(reader); } - - internal override void Read(BinaryReader reader) - { - NameIndex = reader.ReadInt32(); - FileIndex = reader.ReadInt32(); - MajorNum = reader.ReadInt32(); - - return; - } - - internal override void Write(BinaryWriter writer) - { - return; - } - } - - [DebuggerDisplay("Type: {ObjectType}")] - public class PmdDataFrame : PmdDataType - { - public FrameObjectType ObjectType; - public ushort Frame; - public ushort Length; - public short NameIndex; - public PmdFrameObject Object; - - public PmdDataFrame() { } - public PmdDataFrame(string path) { Open(path); } - public PmdDataFrame(Stream stream, bool leaveOpen = false) { Open(stream, leaveOpen); } - public PmdDataFrame(BinaryReader reader) { Open(reader); } - - internal override void Read(BinaryReader reader) - { - ObjectType = (FrameObjectType)reader.ReadInt16(); - Frame = reader.ReadUInt16(); - Length = reader.ReadUInt16(); - NameIndex = reader.ReadInt16(); - Object = PmdFrameObject.CreateFrameObject(ObjectType, reader); - return; - } - - internal override void Write(BinaryWriter writer) - { - writer.Write((short)ObjectType); - writer.Write(Frame); - writer.Write(Length); - writer.Write(NameIndex); - Object.Write(writer); - return; - } - - } - -} -*/ \ No newline at end of file diff --git a/Source/LibellusLibrary/Utils/Reflection.cs b/Source/LibellusLibrary/Utils/Reflection.cs deleted file mode 100644 index 698c17f..0000000 --- a/Source/LibellusLibrary/Utils/Reflection.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LibellusLibrary.Utils -{ - public static class Reflection - { - /// - /// Checks if type has interface - /// - /// The Type of interface to be checked - /// Whether or not type has interface - public static bool HasInterface(this Type obj, Type interfaceType) - { - return obj.GetInterfaces().Contains(interfaceType); - } - - /// - /// Creates a < - /// - /// The type of list to create - /// - public static IList CreateListFromType(Type type) - { - var genericListType = typeof(List<>).MakeGenericType(new[] { type }); - return (IList)Activator.CreateInstance(genericListType); - } - - } -} diff --git a/Source/LibellusLibraryTest/LibellusLibraryTest.csproj b/Source/LibellusLibraryTest/LibellusLibraryTest.csproj deleted file mode 100644 index 07ba5c7..0000000 --- a/Source/LibellusLibraryTest/LibellusLibraryTest.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - Exe - net5.0 - LibellusLibraryTest.Program - - - - - - - diff --git a/Source/LibellusLibraryTest/Program.cs b/Source/LibellusLibraryTest/Program.cs deleted file mode 100644 index fccbdfa..0000000 --- a/Source/LibellusLibraryTest/Program.cs +++ /dev/null @@ -1,86 +0,0 @@ -#define P3 - -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; -using LibellusLibrary.PMD; -using LibellusLibrary.PMD.Types; - -namespace LibellusLibraryTest -{ - class Program - { - static void Main(string[] args) - { - - Console.WriteLine("Starting Test!"); - - if (Directory.Exists("./output")) - { - Directory.Delete("./output",true); - } - Directory.CreateDirectory("./output"); - - - //Yes I know I hardcoded it to my computer. -#if P3 - //string eventFolder = "F:/Modding/Persona Modding/Persona 3/Files/data/EVENT"; -#elif P4G - string eventFolder = "F:/Modding/Persona Modding/Persona 4 Golden/Files/Data-cpk-p4g/data.cpk_unpacked/event"; -#endif - //string[] files = Directory.GetFiles(eventFolder, "*.pm*", SearchOption.AllDirectories); - //searchForObject(files); - - string testFilePath = "F:/Modding/Persona Modding/Persona 3/Files/data/EVENT/E400/E401_004.PM2"; - TestConversion(testFilePath); - - Console.WriteLine("Finished tests, exiting."); - - } - - static void TestConversion(string filePath) - { - Console.WriteLine("Testing: {0}", filePath); - PmdFile pmdFile = new(filePath); - string name = Path.GetFileName(filePath); - File.Copy(filePath, "./output/" + name); - - pmdFile.Save("./output/" + name + ".lib" + Path.GetExtension(filePath)); - string json = pmdFile.ToJson(); - using (BinaryWriter writer = new BinaryWriter(File.Create("./output/" + name + Path.GetExtension(filePath)+".json"))) - { - writer.Write(json); - } - PmdFile pmdFile2 = PmdFile.FromJson(json); - pmdFile2.Save("./output/" + name + ".lib.json" + Path.GetExtension(filePath)); - } - - static void searchForObject(string[] files) - { - using StreamWriter log = new(File.OpenWrite("output.txt")); - - foreach (string pmd in files) - { - PmdFile pmdFile = new(pmd); - - List typeTable = pmdFile.TypeTable; - - foreach (var type in typeTable.Where(x => x.Type == DataTypeID.CutInfo)) - { - /*foreach (PmdDataCutInfo cutInfo in type.DataTable) - { - if (cutInfo.FieldMajorNo==32 && cutInfo.FieldMinorNo==8) - { - Console.WriteLine("Found use of field 32 08!\ninside file: {0}", pmd); - log.WriteLine("Found use of field 32 08!\ninside file: {0}", pmd); - } - }*/ - } - } - - log.Close(); - } - - } -}