diff --git a/README.md b/README.md index 1614ef7e..61150281 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ `Parsec` is a simple .NET parsing library for `Shaiya` file formats which provides easy to use APIs for serialization and deserialization of the game's file formats, including JSON and CSV support. -Parsec works on any .NET Standard 2.0 compliant platform, including .NET 7.0, .NET Framework 4.6.1+, .NET Core 2.0+, -Unity's Mono and Godot. +Parsec works on any .NET Standard 2.0 compliant platform, including .NET 5+, .NET Framework 4.6.1+, .NET Core 2.0+, +Unity and Godot. ## Supported file formats @@ -26,6 +26,7 @@ Unity's Mono and Godot. - `NpcSkill.SData` - `svmap` - `WLD` +- `dg` - `ANI` - `3DC` - `3DO` @@ -72,7 +73,7 @@ might not work with them. ### Prerequisites -- `.NET 7 SDK (recommended)` or any `.NET Standard 2.0` compliant platform +- `.NET 8 SDK (recommended)` or any `.NET Standard 2.0` compliant platform ## Documentation diff --git a/samples/Data/Sample.Data.csproj b/samples/Data/Sample.Data.csproj index 1717dd1b..20c36da8 100644 --- a/samples/Data/Sample.Data.csproj +++ b/samples/Data/Sample.Data.csproj @@ -2,8 +2,7 @@ Exe - net7.0 - 10 + net8.0 diff --git a/samples/Files/Program.cs b/samples/Files/Program.cs index 46fee6d6..1507e80c 100644 --- a/samples/Files/Program.cs +++ b/samples/Files/Program.cs @@ -1,6 +1,6 @@ -using Parsec; -using Parsec.Shaiya.SData; -using Parsec.Shaiya.Skill; +using System; +using Parsec; +using Parsec.Shaiya.Svmap; namespace Sample.Files; @@ -8,12 +8,27 @@ internal static class Program { private static void Main(string[] args) { - SData.DecryptFile("/home/matias/Desktop/DBSkillData.SData", "/home/matias/Desktop/DBSkillData.dec.SData"); + // This sample shows how you can convert a shaiya file format (in this case svmap) into json to be able to + // edit its properties as plain text, and then, convert it back to its original format - var skillData = ParsecReader.FromFile("/home/matias/Desktop/DBSkillData.dec.SData"); + // Step 1: Read a svmap from a file + var svmap = ParsecReader.FromFile("2.svmap"); - skillData.Write("/home/matias/Desktop/DBSkillData.dec.new.SData"); + // You can go through and modify its properties here too + foreach (var npc in svmap.Npcs) + { + Console.WriteLine($"NpcId: {npc.NpcId}, Type: {npc.NpcType}"); + } - var newSkillData = ParsecReader.FromFile("/home/matias/Desktop/DBSkillData.dec.new.SData"); + // Step 2: Export svmap as JSON + svmap.WriteJson("2.svmap.json"); + + // Step 3: Modify the json file in any text editor + + // Step 4: Read svmap from the modified JSON file + var svmapFromJson = ParsecReader.FromJsonFile("2.svmap.json"); + + // Step 5: Write the edited instance as .svmap + svmapFromJson.Write("2.edited.svmap"); } } diff --git a/samples/Files/Sample.Files.csproj b/samples/Files/Sample.Files.csproj index 70c68f19..8be3be82 100644 --- a/samples/Files/Sample.Files.csproj +++ b/samples/Files/Sample.Files.csproj @@ -2,8 +2,7 @@ Exe - net7.0 - 10 + net8.0 Sample.Files diff --git a/samples/Godot/Mob_Elk_01.3DC b/samples/Godot/Mob_Elk_01.3DC deleted file mode 100644 index 631b383c..00000000 Binary files a/samples/Godot/Mob_Elk_01.3DC and /dev/null differ diff --git a/samples/Godot/Mob_Elk_01.dds b/samples/Godot/Mob_Elk_01.dds deleted file mode 100644 index 16663859..00000000 Binary files a/samples/Godot/Mob_Elk_01.dds and /dev/null differ diff --git a/samples/Godot/README.md b/samples/Godot/README.md deleted file mode 100644 index 153d4e38..00000000 --- a/samples/Godot/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Parsec Godot Sample -This sample illustrates how Parsec can be used to load Shaiya assets into a `Godot` project. - -## Prerequisites -- `Godot 3 (Mono Version)` - -## Usage -Camera movement is done via the [Simple Free-Look Camera](https://godotengine.org/asset-library/asset/701) asset. - -Use **W** and **S** to move forward and backward. - -Use **A** and **D** to move left and right. - -Use **Q** and **E** to move up and down. - -Roll the **scroll wheel** to increase and decrease movement speed. - -Hold down the **right mouse button** to rotate the camera. \ No newline at end of file diff --git a/samples/Godot/Scene.tscn b/samples/Godot/Scene.tscn deleted file mode 100644 index a1ed3982..00000000 --- a/samples/Godot/Scene.tscn +++ /dev/null @@ -1,27 +0,0 @@ -[gd_scene load_steps=5 format=2] - -[ext_resource path="res://ShaiyaMeshInstance.cs" type="Script" id=1] -[ext_resource path="res://camera.gd" type="Script" id=2] -[ext_resource path="res://default_env.tres" type="Environment" id=5] - -[sub_resource type="ArrayMesh" id=1] - -[node name="Spatial" type="Spatial"] - -[node name="WorldEnvironment" type="WorldEnvironment" parent="."] -environment = ExtResource( 5 ) - -[node name="DirectionalLight" type="DirectionalLight" parent="WorldEnvironment"] -transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -0.65182, 2.90436, -3.64679 ) -shadow_enabled = true -shadow_bias = 0.0 -directional_shadow_mode = 0 -directional_shadow_max_distance = 40.0 - -[node name="MeshInstance" type="MeshInstance" parent="."] -mesh = SubResource( 1 ) -script = ExtResource( 1 ) - -[node name="Camera" type="Camera" parent="."] -transform = Transform( -0.00188498, 0, 0.999998, 0, 1, 0, -0.999998, 0, -0.00188498, 2.94621, 0.445381, -0.262532 ) -script = ExtResource( 2 ) diff --git a/samples/Godot/Shaiya.png b/samples/Godot/Shaiya.png deleted file mode 100644 index 8c7f272d..00000000 Binary files a/samples/Godot/Shaiya.png and /dev/null differ diff --git a/samples/Godot/ShaiyaGodotProject.csproj b/samples/Godot/ShaiyaGodotProject.csproj deleted file mode 100644 index 12e11cd2..00000000 --- a/samples/Godot/ShaiyaGodotProject.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - net472 - ShaiyaGodotProject - - - - - - - PreserveNewest - - - PreserveNewest - - - diff --git a/samples/Godot/ShaiyaGodotProject.sln b/samples/Godot/ShaiyaGodotProject.sln deleted file mode 100644 index 12d2f0be..00000000 --- a/samples/Godot/ShaiyaGodotProject.sln +++ /dev/null @@ -1,27 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShaiyaGodotProject", "ShaiyaGodotProject.csproj", "{6D73B1F4-0EE8-49B1-BFB3-E221D28FB500}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parsec", "..\..\src\Parsec\Parsec.csproj", "{290EBC41-B130-4B73-9FA8-EC71A3190280}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - ExportDebug|Any CPU = ExportDebug|Any CPU - ExportRelease|Any CPU = ExportRelease|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6D73B1F4-0EE8-49B1-BFB3-E221D28FB500}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6D73B1F4-0EE8-49B1-BFB3-E221D28FB500}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6D73B1F4-0EE8-49B1-BFB3-E221D28FB500}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU - {6D73B1F4-0EE8-49B1-BFB3-E221D28FB500}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU - {6D73B1F4-0EE8-49B1-BFB3-E221D28FB500}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU - {6D73B1F4-0EE8-49B1-BFB3-E221D28FB500}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU - {290EBC41-B130-4B73-9FA8-EC71A3190280}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {290EBC41-B130-4B73-9FA8-EC71A3190280}.Debug|Any CPU.Build.0 = Debug|Any CPU - {290EBC41-B130-4B73-9FA8-EC71A3190280}.ExportDebug|Any CPU.ActiveCfg = Debug|Any CPU - {290EBC41-B130-4B73-9FA8-EC71A3190280}.ExportDebug|Any CPU.Build.0 = Debug|Any CPU - {290EBC41-B130-4B73-9FA8-EC71A3190280}.ExportRelease|Any CPU.ActiveCfg = Debug|Any CPU - {290EBC41-B130-4B73-9FA8-EC71A3190280}.ExportRelease|Any CPU.Build.0 = Debug|Any CPU - EndGlobalSection -EndGlobal diff --git a/samples/Godot/ShaiyaMeshInstance.cs b/samples/Godot/ShaiyaMeshInstance.cs deleted file mode 100644 index ec2264ab..00000000 --- a/samples/Godot/ShaiyaMeshInstance.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Linq; -using Godot; -using Godot.Collections; -using Parsec; -using Parsec.Shaiya._3DC; - -namespace ShaiyaGodotProject -{ - public class ShaiyaMeshInstance : MeshInstance - { - private string _3dcPath = "Mob_Elk_01.3DC"; - private string _ddsPath = "Mob_Elk_01.dds"; - - public override void _Ready() - { - var obj = Reader.ReadFromFile<_3DC>(_3dcPath); - - var surfaceArray = new Array(); - surfaceArray.Resize((int)ArrayMesh.ArrayType.Max); - - var vertices = new Array(); - var uvs = new Array(); - var normals = new Array(); - var indices = new Array(); - - foreach (var vertex in obj.Vertices) - { - vertices.Add(new Vector3(vertex.Coordinates.X, vertex.Coordinates.Y, vertex.Coordinates.Z)); - normals.Add(new Vector3(vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z)); - uvs.Add(new Vector2(vertex.UV.X, vertex.UV.Y)); - } - - foreach (var face in obj.Faces) - { - indices.Add(face.VertexIndex1); - indices.Add(face.VertexIndex3); - indices.Add(face.VertexIndex2); - } - - surfaceArray[(int)Mesh.ArrayType.Vertex] = vertices.ToArray(); - surfaceArray[(int)Mesh.ArrayType.TexUv] = uvs.ToArray(); - surfaceArray[(int)Mesh.ArrayType.Normal] = normals.ToArray(); - surfaceArray[(int)Mesh.ArrayType.Index] = indices.ToArray(); - - var arrayMesh = new ArrayMesh(); - arrayMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, surfaceArray); - Mesh = arrayMesh; - - var texture = GD.Load(_ddsPath); - var material = new SpatialMaterial - { - AlbedoTexture = texture - }; - - MaterialOverride = material; - } - } -} diff --git a/samples/Godot/camera.gd b/samples/Godot/camera.gd deleted file mode 100644 index 9adf3482..00000000 --- a/samples/Godot/camera.gd +++ /dev/null @@ -1,106 +0,0 @@ -extends Camera - -export(float, 0.0, 1.0) var sensitivity = 0.25 - -# Mouse state -var _mouse_position = Vector2(0.0, 0.0) -var _total_pitch = 0.0 - -# Movement state -var _direction = Vector3(0.0, 0.0, 0.0) -var _velocity = Vector3(0.0, 0.0, 0.0) -var _acceleration = 30 -var _deceleration = -10 -var _vel_multiplier = 4 - -# Keyboard state -var _w = false -var _s = false -var _a = false -var _d = false -var _q = false -var _e = false - - -func _input(event): - # Receives mouse motion - if event is InputEventMouseMotion: - _mouse_position = event.relative - - # Receives mouse button input - if event is InputEventMouseButton: - match event.button_index: - BUTTON_RIGHT: # Only allows rotation if right click down - Input.set_mouse_mode( - Input.MOUSE_MODE_CAPTURED if event.pressed else Input.MOUSE_MODE_VISIBLE - ) - BUTTON_WHEEL_UP: # Increases max velocity - _vel_multiplier = clamp(_vel_multiplier * 1.1, 0.2, 20) - BUTTON_WHEEL_DOWN: # Decereases max velocity - _vel_multiplier = clamp(_vel_multiplier / 1.1, 0.2, 20) - - # Receives key input - if event is InputEventKey: - match event.scancode: - KEY_W: - _w = event.pressed - KEY_S: - _s = event.pressed - KEY_A: - _a = event.pressed - KEY_D: - _d = event.pressed - KEY_Q: - _q = event.pressed - KEY_E: - _e = event.pressed - - -# Updates mouselook and movement every frame -func _process(delta): - _update_mouselook() - _update_movement(delta) - - -# Updates camera movement -func _update_movement(delta): - # Computes desired direction from key states - _direction = Vector3( - _d as float - _a as float, _e as float - _q as float, _s as float - _w as float - ) - - # Computes the change in velocity due to desired direction and "drag" - # The "drag" is a constant acceleration on the camera to bring it's velocity to 0 - var offset = ( - _direction.normalized() * _acceleration * _vel_multiplier * delta - + _velocity.normalized() * _deceleration * _vel_multiplier * delta - ) - - # Checks if we should bother translating the camera - if _direction == Vector3.ZERO and offset.length_squared() > _velocity.length_squared(): - # Sets the velocity to 0 to prevent jittering due to imperfect deceleration - _velocity = Vector3.ZERO - else: - # Clamps speed to stay within maximum value (_vel_multiplier) - _velocity.x = clamp(_velocity.x + offset.x, -_vel_multiplier, _vel_multiplier) - _velocity.y = clamp(_velocity.y + offset.y, -_vel_multiplier, _vel_multiplier) - _velocity.z = clamp(_velocity.z + offset.z, -_vel_multiplier, _vel_multiplier) - - translate(_velocity * delta) - - -# Updates mouse look -func _update_mouselook(): - # Only rotates mouse if the mouse is captured - if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: - _mouse_position *= sensitivity - var yaw = _mouse_position.x - var pitch = _mouse_position.y - _mouse_position = Vector2(0, 0) - - # Prevents looking up/down too far - pitch = clamp(pitch, -90 - _total_pitch, 90 - _total_pitch) - _total_pitch += pitch - - rotate_y(deg2rad(-yaw)) - rotate_object_local(Vector3(1, 0, 0), deg2rad(-pitch)) diff --git a/samples/Godot/default_env.tres b/samples/Godot/default_env.tres deleted file mode 100644 index 94d8fe64..00000000 --- a/samples/Godot/default_env.tres +++ /dev/null @@ -1,11 +0,0 @@ -[gd_resource type="Environment" load_steps=2 format=2] - -[sub_resource type="ProceduralSky" id=1] - -[resource] -background_mode = 3 -background_sky = SubResource( 1 ) -background_color = Color( 0.866667, 0.866667, 0.866667, 1 ) -background_energy = 1.5 -tonemap_mode = 2 -tonemap_white = 6.0 diff --git a/samples/Godot/project.godot b/samples/Godot/project.godot deleted file mode 100644 index 496c5492..00000000 --- a/samples/Godot/project.godot +++ /dev/null @@ -1,32 +0,0 @@ -; Engine configuration file. -; It's best edited using the editor UI and not directly, -; since the parameters that go here are not all obvious. -; -; Format: -; [section] ; section goes between [] -; param=value ; assign values to parameters - -config_version=4 - -[application] - -config/name="ShaiyaGodotProject" -run/main_scene="res://Scene.tscn" -boot_splash/bg_color=Color( 0.141176, 0.141176, 0.141176, 1 ) -config/icon="res://Shaiya.png" - -[gui] - -common/drop_mouse_on_gui_input_disabled=true - -[mono] - -project/assembly_name="ShaiyaGodotProject" - -[physics] - -common/enable_pause_aware_picking=true - -[rendering] - -environment/default_environment="res://default_env.tres" diff --git a/samples/SData/Sample.SData.csproj b/samples/SData/Sample.SData.csproj index e336a48a..2672bebd 100644 --- a/samples/SData/Sample.SData.csproj +++ b/samples/SData/Sample.SData.csproj @@ -2,8 +2,7 @@ Exe - net7.0 - 10 + net8.0 diff --git a/src/Parsec/Common/Episode.cs b/src/Parsec/Common/Episode.cs index 38741b3c..e9e1c0fb 100644 --- a/src/Parsec/Common/Episode.cs +++ b/src/Parsec/Common/Episode.cs @@ -2,10 +2,17 @@ public enum Episode { - Unknown, - EP4, - EP5, - EP6, - EP7, - EP8 + Unknown = 0, + + EP4 = 40, + + EP5 = 50, + + EP6 = 60, + + EP6_4 = 64, + + EP7 = 70, + + EP8 = 80 } diff --git a/src/Parsec/Parsec.csproj b/src/Parsec/Parsec.csproj index 6573c81e..7d7b749f 100644 --- a/src/Parsec/Parsec.csproj +++ b/src/Parsec/Parsec.csproj @@ -4,24 +4,24 @@ 10 AnyCPU;x86 true - 1.0.1 + 1.1.1 Matias Ramirez - Matias Ramirez 2022 + Matias Ramirez 2021 https://github.com/matigramirez/Parsec https://github.com/matigramirez/Parsec csharp, shaiya, file, parser, dotnet Parsec is a simple file parsing library for Shaiya file formats built with C# and .NET Standard 2.0. Its goal is to make reading and manipulating the game's file formats with ease. false - netstandard2.0;net6.0;net7.0 + netstandard2.0;net6.0;net7.0;net8.0 true enable - + - + diff --git a/src/Parsec/Serialization/SBinaryReader.cs b/src/Parsec/Serialization/SBinaryReader.cs index a19799f5..68f7449b 100644 --- a/src/Parsec/Serialization/SBinaryReader.cs +++ b/src/Parsec/Serialization/SBinaryReader.cs @@ -46,6 +46,11 @@ public void ResetBuffer(byte[] buffer) _binaryReader = new BinaryReader(memoryStream); } + /// + /// Current position in the stream + /// + public long Position => _binaryReader.BaseStream.Position; + /// /// Length of the stream /// diff --git a/src/Parsec/Shaiya/Cash/CashProduct.cs b/src/Parsec/Shaiya/Cash/CashProduct.cs index 7ab9a7d4..b7ea702b 100644 --- a/src/Parsec/Shaiya/Cash/CashProduct.cs +++ b/src/Parsec/Shaiya/Cash/CashProduct.cs @@ -10,7 +10,7 @@ public sealed class CashProduct : ISerializable public uint Bag { get; set; } - public uint Unknown { get; set; } + public uint Icon { get; set; } public uint Cost { get; set; } @@ -26,7 +26,7 @@ public void Read(SBinaryReader binaryReader) { Index = binaryReader.ReadUInt32(); Bag = binaryReader.ReadUInt32(); - Unknown = binaryReader.ReadUInt32(); + Icon = binaryReader.ReadUInt32(); Cost = binaryReader.ReadUInt32(); Items = binaryReader.ReadList(24).ToList(); ProductName = binaryReader.ReadString(); @@ -43,7 +43,7 @@ public void Write(SBinaryWriter binaryWriter) { binaryWriter.Write(Index); binaryWriter.Write(Bag); - binaryWriter.Write(Unknown); + binaryWriter.Write(Icon); binaryWriter.Write(Cost); binaryWriter.Write(Items.Take(24).ToSerializable(), lengthPrefixed: false); diff --git a/src/Parsec/Shaiya/Common/BoundingBox.cs b/src/Parsec/Shaiya/Common/BoundingBox.cs index cea198f0..ef400363 100644 --- a/src/Parsec/Shaiya/Common/BoundingBox.cs +++ b/src/Parsec/Shaiya/Common/BoundingBox.cs @@ -1,4 +1,5 @@ -using Parsec.Serialization; +using Newtonsoft.Json; +using Parsec.Serialization; using Parsec.Shaiya.Core; namespace Parsec.Shaiya.Common; @@ -19,6 +20,7 @@ public struct BoundingBox : ISerializable /// public Vector3 UpperLimit { get; set; } + [JsonIgnore] public double Radius { get diff --git a/src/Parsec/Shaiya/Common/String256.cs b/src/Parsec/Shaiya/Common/String256.cs index 1ac276d0..d92e7353 100644 --- a/src/Parsec/Shaiya/Common/String256.cs +++ b/src/Parsec/Shaiya/Common/String256.cs @@ -1,4 +1,5 @@ using System.Text; +using Newtonsoft.Json; using Parsec.Serialization; using Parsec.Shaiya.Core; @@ -8,6 +9,7 @@ public sealed class String256 : ISerializable { public string Value { get; set; } = string.Empty; + [JsonIgnore] public char PaddingChar { get; set; } = '\0'; public void Read(SBinaryReader binaryReader) diff --git a/src/Parsec/Shaiya/Common/Vector2.cs b/src/Parsec/Shaiya/Common/Vector2.cs index 8cd94336..52249ca2 100644 --- a/src/Parsec/Shaiya/Common/Vector2.cs +++ b/src/Parsec/Shaiya/Common/Vector2.cs @@ -38,6 +38,7 @@ public void Write(SBinaryWriter binaryWriter) binaryWriter.Write(Y); } + [JsonIgnore] public double Length => Math.Sqrt(X * X + Y * Y); public static Vector2 operator +(Vector2 vec1, Vector2 vec2) => new(vec1.X + vec2.X, vec1.Y + vec2.Y); diff --git a/src/Parsec/Shaiya/Common/Vector3.cs b/src/Parsec/Shaiya/Common/Vector3.cs index 949a3a1f..4ca79865 100644 --- a/src/Parsec/Shaiya/Common/Vector3.cs +++ b/src/Parsec/Shaiya/Common/Vector3.cs @@ -46,6 +46,7 @@ public void Write(SBinaryWriter binaryWriter) binaryWriter.Write(Z); } + [JsonIgnore] public double Length => Math.Sqrt(X * X + Y * Y + Z * Z); public static Vector3 operator +(Vector3 vec1, Vector3 vec2) => new(vec1.X + vec2.X, vec1.Y + vec2.Y, vec1.Z + vec2.Z); diff --git a/src/Parsec/Shaiya/Dg/Dg.cs b/src/Parsec/Shaiya/Dg/Dg.cs new file mode 100644 index 00000000..8c16e6c9 --- /dev/null +++ b/src/Parsec/Shaiya/Dg/Dg.cs @@ -0,0 +1,66 @@ +using Parsec.Extensions; +using Parsec.Serialization; +using Parsec.Shaiya.Common; +using Parsec.Shaiya.Core; + +namespace Parsec.Shaiya.Dg; + +public class Dg : FileBase +{ + public BoundingBox BoundingBox { get; set; } + + public List TextureNames { get; set; } = new(); + + public int UnknownInt32 { get; set; } + + public List Nodes { get; set; } = new(); + + public override string Extension => "dg"; + + protected override void Read(SBinaryReader binaryReader) + { + BoundingBox = binaryReader.Read(); + TextureNames = binaryReader.ReadList().ToList(); + UnknownInt32 = binaryReader.ReadInt32(); + + while (true) + { + if (binaryReader.Position == binaryReader.StreamLength) + { + break; + } + + // When value is 1, node data follows, otherwise node reading must be skipped + var value = binaryReader.ReadInt32(); + + if (value > 0) + { + var node = binaryReader.Read(); + Nodes.Add(node); + } + else + { + Nodes.Add(null); + } + } + } + + protected override void Write(SBinaryWriter binaryWriter) + { + binaryWriter.Write(BoundingBox); + binaryWriter.Write(TextureNames.ToSerializable()); + binaryWriter.Write(UnknownInt32); + + foreach (var node in Nodes) + { + if (node == null) + { + binaryWriter.Write(0); + continue; + } + + binaryWriter.Write(1); + binaryWriter.Write(node); + } + } +} diff --git a/src/Parsec/Shaiya/Dg/DgCollisionMesh.cs b/src/Parsec/Shaiya/Dg/DgCollisionMesh.cs new file mode 100644 index 00000000..05e7b0c5 --- /dev/null +++ b/src/Parsec/Shaiya/Dg/DgCollisionMesh.cs @@ -0,0 +1,31 @@ +using Parsec.Extensions; +using Parsec.Serialization; +using Parsec.Shaiya.Common; +using Parsec.Shaiya.Core; + +namespace Parsec.Shaiya.Dg; + +public class DgCollisionMesh : ISerializable +{ + /// + /// Vertices of the 3d object. + /// + public List Vertices { get; set; } = new(); + + /// + /// Triangular faces (polygons) of the 3d object. + /// + public List Faces { get; set; } = new(); + + public void Read(SBinaryReader binaryReader) + { + Vertices = binaryReader.ReadList().ToList(); + Faces = binaryReader.ReadList().ToList(); + } + + public void Write(SBinaryWriter binaryWriter) + { + binaryWriter.Write(Vertices.ToSerializable()); + binaryWriter.Write(Faces.ToSerializable()); + } +} diff --git a/src/Parsec/Shaiya/Dg/DgCollisionMeshVertex.cs b/src/Parsec/Shaiya/Dg/DgCollisionMeshVertex.cs new file mode 100644 index 00000000..47046f0c --- /dev/null +++ b/src/Parsec/Shaiya/Dg/DgCollisionMeshVertex.cs @@ -0,0 +1,26 @@ +using Parsec.Serialization; +using Parsec.Shaiya.Common; +using Parsec.Shaiya.Core; + +namespace Parsec.Shaiya.Dg; + +/// +/// Represents a vertex used in DG collision objects +/// +public sealed class DgCollisionMeshVertex : ISerializable +{ + /// + /// Coordinates of the vertex in the 3D space. + /// + public Vector3 Coordinates { get; set; } + + public void Read(SBinaryReader binaryReader) + { + Coordinates = binaryReader.Read(); + } + + public void Write(SBinaryWriter binaryWriter) + { + binaryWriter.Write(Coordinates); + } +} diff --git a/src/Parsec/Shaiya/Dg/DgMesh.cs b/src/Parsec/Shaiya/Dg/DgMesh.cs new file mode 100644 index 00000000..c5bde923 --- /dev/null +++ b/src/Parsec/Shaiya/Dg/DgMesh.cs @@ -0,0 +1,29 @@ +using Parsec.Extensions; +using Parsec.Serialization; +using Parsec.Shaiya.Common; +using Parsec.Shaiya.Core; + +namespace Parsec.Shaiya.Dg; + +public class DgMesh : ISerializable +{ + public AlphaBlendingMode AlphaBlendingMode { get; set; } + + public List Vertices { get; set; } = new(); + + public List Faces { get; set; } = new(); + + public void Read(SBinaryReader binaryReader) + { + AlphaBlendingMode = (AlphaBlendingMode)binaryReader.ReadInt32(); + Vertices = binaryReader.ReadList().ToList(); + Faces = binaryReader.ReadList().ToList(); + } + + public void Write(SBinaryWriter binaryWriter) + { + binaryWriter.Write((int)AlphaBlendingMode); + binaryWriter.Write(Vertices.ToSerializable()); + binaryWriter.Write(Faces.ToSerializable()); + } +} diff --git a/src/Parsec/Shaiya/Dg/DgMeshCollisionType.cs b/src/Parsec/Shaiya/Dg/DgMeshCollisionType.cs new file mode 100644 index 00000000..875d9b66 --- /dev/null +++ b/src/Parsec/Shaiya/Dg/DgMeshCollisionType.cs @@ -0,0 +1,7 @@ +namespace Parsec.Shaiya.Dg; + +public enum DgMeshCollisionType +{ + Transparent = 0, + Collision = 1 +} diff --git a/src/Parsec/Shaiya/Dg/DgMeshVertex.cs b/src/Parsec/Shaiya/Dg/DgMeshVertex.cs new file mode 100644 index 00000000..cc2d82bd --- /dev/null +++ b/src/Parsec/Shaiya/Dg/DgMeshVertex.cs @@ -0,0 +1,51 @@ +using Parsec.Serialization; +using Parsec.Shaiya.Common; +using Parsec.Shaiya.Core; + +namespace Parsec.Shaiya.Dg; + +public class DgMeshVertex : ISerializable +{ + /// + /// Vertex coordinates in the 3D space + /// + public Vector3 Coordinates { get; set; } + + /// + /// Vertex normal used for lighting + /// + public Vector3 Normal { get; set; } + + /// + /// SMODs don't have bones, that's why this value is always -1. + /// + public int BoneId { get; set; } = -1; + + /// + /// Texture mapping + /// + public Vector2 TextureUV { get; set; } + + /// + /// Lightmap mapping + /// + public Vector2 LightmapUV { get; set; } + + public void Read(SBinaryReader binaryReader) + { + Coordinates = binaryReader.Read(); + Normal = binaryReader.Read(); + BoneId = binaryReader.ReadInt32(); + TextureUV = binaryReader.Read(); + LightmapUV = binaryReader.Read(); + } + + public void Write(SBinaryWriter binaryWriter) + { + binaryWriter.Write(Coordinates); + binaryWriter.Write(Normal); + binaryWriter.Write(BoneId); + binaryWriter.Write(TextureUV); + binaryWriter.Write(LightmapUV); + } +} diff --git a/src/Parsec/Shaiya/Dg/DgNode.cs b/src/Parsec/Shaiya/Dg/DgNode.cs new file mode 100644 index 00000000..92b1293c --- /dev/null +++ b/src/Parsec/Shaiya/Dg/DgNode.cs @@ -0,0 +1,55 @@ +using Parsec.Extensions; +using Parsec.Serialization; +using Parsec.Shaiya.Common; +using Parsec.Shaiya.Core; + +namespace Parsec.Shaiya.Dg; + +public class DgNode : ISerializable +{ + // TODO: Check + public Vector3 Center { get; set; } + + // TODO: Check + public BoundingBox ViewBox { get; set; } + + // TODO: Check + public BoundingBox CollisionBox { get; set; } + + public List Objects { get; set; } = new(); + + public DgMeshCollisionType CollisionType { get; set; } + + public DgCollisionMesh CollisionMesh { get; set; } = new(); + + public void Read(SBinaryReader binaryReader) + { + Center = binaryReader.Read(); + ViewBox = binaryReader.Read(); + CollisionBox = binaryReader.Read(); + + Objects = binaryReader.ReadList().ToList(); + + CollisionType = (DgMeshCollisionType)binaryReader.ReadInt32(); + + if (CollisionType == DgMeshCollisionType.Collision) + { + // Read extra node info + CollisionMesh = binaryReader.Read(); + } + } + + public void Write(SBinaryWriter binaryWriter) + { + binaryWriter.Write(Center); + binaryWriter.Write(ViewBox); + binaryWriter.Write(CollisionBox); + binaryWriter.Write(Objects.ToSerializable()); + binaryWriter.Write((int)CollisionType); + + if (CollisionType == DgMeshCollisionType.Collision) + { + binaryWriter.Write(CollisionMesh); + } + } +} diff --git a/src/Parsec/Shaiya/Dg/DgObject.cs b/src/Parsec/Shaiya/Dg/DgObject.cs new file mode 100644 index 00000000..354f9198 --- /dev/null +++ b/src/Parsec/Shaiya/Dg/DgObject.cs @@ -0,0 +1,24 @@ +using Parsec.Extensions; +using Parsec.Serialization; +using Parsec.Shaiya.Core; + +namespace Parsec.Shaiya.Dg; + +public class DgObject : ISerializable +{ + public int TextureIndex { get; set; } + + public List Meshes { get; set; } = new(); + + public void Read(SBinaryReader binaryReader) + { + TextureIndex = binaryReader.ReadInt32(); + Meshes = binaryReader.ReadList().ToList(); + } + + public void Write(SBinaryWriter binaryWriter) + { + binaryWriter.Write(TextureIndex); + binaryWriter.Write(Meshes.ToSerializable()); + } +} diff --git a/src/Parsec/Shaiya/DualLayerClothes/DualLayerClothes.cs b/src/Parsec/Shaiya/DualLayerClothes/DualLayerClothes.cs index 22c5b8a8..f5117680 100644 --- a/src/Parsec/Shaiya/DualLayerClothes/DualLayerClothes.cs +++ b/src/Parsec/Shaiya/DualLayerClothes/DualLayerClothes.cs @@ -1,9 +1,13 @@ -using Parsec.Extensions; +using System.Globalization; +using System.Text; +using CsvHelper; +using Parsec.Common; +using Parsec.Extensions; using Parsec.Serialization; namespace Parsec.Shaiya.DualLayerClothes; -public sealed class DualLayerClothes : SData.SData +public sealed class DualLayerClothes : SData.SData, ICsv { public List Records { get; set; } = new(); @@ -16,4 +20,28 @@ protected override void Write(SBinaryWriter binaryWriter) { binaryWriter.Write(Records.ToSerializable()); } + + public static DualLayerClothes FromCsv(string csvPath, Encoding? encoding = null) + { + encoding ??= Encoding.ASCII; + + using var reader = new StreamReader(csvPath, encoding); + using var csvReader = new CsvReader(reader, CultureInfo.InvariantCulture); + var records = csvReader.GetRecords().ToList(); + + var dualLayerClothes = new DualLayerClothes + { + Records = records + }; + + return dualLayerClothes; + } + + public void WriteCsv(string outputPath, Encoding? encoding = null) + { + encoding ??= Encoding; + using var writer = new StreamWriter(outputPath, false, encoding); + using var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture); + csvWriter.WriteRecords(Records); + } } diff --git a/src/Parsec/Shaiya/Item/Item.cs b/src/Parsec/Shaiya/Item/Item.cs index a4e4b5f2..a4fe7eef 100644 --- a/src/Parsec/Shaiya/Item/Item.cs +++ b/src/Parsec/Shaiya/Item/Item.cs @@ -30,6 +30,11 @@ protected override void Write(SBinaryWriter binaryWriter) /// instance public static Item FromCsv(string csvPath, Episode episode, Encoding? encoding = null) { + if (episode >= Episode.EP8) + { + throw new Exception("Item format is not supported for EP8 and above, use ItemData instead."); + } + encoding ??= Encoding.ASCII; // Read item definitions from csv @@ -60,7 +65,7 @@ public static Item FromCsv(string csvPath, Episode episode, Encoding? encoding = public void WriteCsv(string outputPath, Encoding? encoding = null) { - encoding = Encoding; + encoding ??= Encoding; using var writer = new StreamWriter(outputPath, false, encoding); using var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture); diff --git a/src/Parsec/Shaiya/Item/ItemDefinition.cs b/src/Parsec/Shaiya/Item/ItemDefinition.cs index 9858d8e3..ce591f26 100644 --- a/src/Parsec/Shaiya/Item/ItemDefinition.cs +++ b/src/Parsec/Shaiya/Item/ItemDefinition.cs @@ -55,12 +55,10 @@ public sealed class ItemDefinition : ISerializable public ushort ReqWis { get; set; } - public ushort ReqLuc { get; set; } + public uint ReqLuc { get; set; } public ushort ReqVg { get; set; } - public ushort Unknown { get; set; } - public byte ReqOg { get; set; } public byte ReqIg { get; set; } @@ -185,18 +183,20 @@ public void Read(SBinaryReader binaryReader) ReqRec = binaryReader.ReadUInt16(); ReqInt = binaryReader.ReadUInt16(); ReqWis = binaryReader.ReadUInt16(); - ReqLuc = binaryReader.ReadUInt16(); - ReqVg = binaryReader.ReadUInt16(); - if (episode >= Episode.EP6) + if (episode >= Episode.EP6_4) + { + ReqLuc = binaryReader.ReadUInt32(); + } + else { - Unknown = binaryReader.ReadUInt16(); + ReqLuc = binaryReader.ReadUInt16(); } + ReqVg = binaryReader.ReadUInt16(); ReqOg = binaryReader.ReadByte(); ReqIg = binaryReader.ReadByte(); - if (episode <= Episode.EP5) { Range = binaryReader.ReadByte(); @@ -286,20 +286,23 @@ public void Write(SBinaryWriter binaryWriter) binaryWriter.Write(ReqRec); binaryWriter.Write(ReqInt); binaryWriter.Write(ReqWis); - binaryWriter.Write(ReqLuc); - binaryWriter.Write(ReqVg); - if (episode >= Episode.EP6) + if (episode >= Episode.EP6_4) { - binaryWriter.Write(Unknown); + binaryWriter.Write(ReqLuc); + } + else + { + binaryWriter.Write((ushort)ReqLuc); } + binaryWriter.Write(ReqVg); binaryWriter.Write(ReqOg); binaryWriter.Write(ReqIg); if (episode <= Episode.EP5) { - binaryWriter.Write(Range); + binaryWriter.Write((byte)Range); } else { diff --git a/src/Parsec/Shaiya/KillStatus/KillStatusFaction.cs b/src/Parsec/Shaiya/KillStatus/KillStatusFaction.cs index faaa8372..351b039f 100644 --- a/src/Parsec/Shaiya/KillStatus/KillStatusFaction.cs +++ b/src/Parsec/Shaiya/KillStatus/KillStatusFaction.cs @@ -3,6 +3,5 @@ namespace Parsec.Shaiya.KillStatus; public enum KillStatusFaction : byte { Light, - Fury, - Any + Fury } diff --git a/src/Parsec/Shaiya/Monster/DBMonsterDataRecord.cs b/src/Parsec/Shaiya/Monster/DBMonsterDataRecord.cs index b53f0552..cefbe1cf 100644 --- a/src/Parsec/Shaiya/Monster/DBMonsterDataRecord.cs +++ b/src/Parsec/Shaiya/Monster/DBMonsterDataRecord.cs @@ -251,6 +251,44 @@ public void Read(SBinaryReader binaryReader) Skill2 = binaryReader.ReadInt64(); Skill3 = binaryReader.ReadInt64(); Skill4 = binaryReader.ReadInt64(); + Skill5 = binaryReader.ReadInt64(); + Skill6 = binaryReader.ReadInt64(); + NormalTime = binaryReader.ReadInt64(); + NormalStep = binaryReader.ReadInt64(); + ChaseTime = binaryReader.ReadInt64(); + ChaseStep = binaryReader.ReadInt64(); + ChaseRange = binaryReader.ReadInt64(); + AttackAni1 = binaryReader.ReadInt64(); + AttackType1 = binaryReader.ReadInt64(); + AttackTime1 = binaryReader.ReadInt64(); + AttackRange1 = binaryReader.ReadInt64(); + Attack1 = binaryReader.ReadInt64(); + AttackPlus1 = binaryReader.ReadInt64(); + AttackAttrib1 = binaryReader.ReadInt64(); + AttackSpecial1 = binaryReader.ReadInt64(); + AttackOk1 = binaryReader.ReadInt64(); + AttackAni2 = binaryReader.ReadInt64(); + AttackType2 = binaryReader.ReadInt64(); + AttackTime2 = binaryReader.ReadInt64(); + AttackRange2 = binaryReader.ReadInt64(); + Attack2 = binaryReader.ReadInt64(); + AttackPlus2 = binaryReader.ReadInt64(); + AttackAttrib2 = binaryReader.ReadInt64(); + AttackSpecial2 = binaryReader.ReadInt64(); + AttackOk2 = binaryReader.ReadInt64(); + AttackAni3 = binaryReader.ReadInt64(); + AttackType3 = binaryReader.ReadInt64(); + AttackTime3 = binaryReader.ReadInt64(); + AttackRange3 = binaryReader.ReadInt64(); + Attack3 = binaryReader.ReadInt64(); + AttackPlus3 = binaryReader.ReadInt64(); + AttackAttrib3 = binaryReader.ReadInt64(); + AttackSpecial3 = binaryReader.ReadInt64(); + AttackOk3 = binaryReader.ReadInt64(); + ColorType = binaryReader.ReadInt64(); + ColorHue = binaryReader.ReadInt64(); + ColorSaturation = binaryReader.ReadInt64(); + ColorLight = binaryReader.ReadInt64(); } public void Write(SBinaryWriter binaryWriter) @@ -311,5 +349,43 @@ public void Write(SBinaryWriter binaryWriter) binaryWriter.Write(Skill2); binaryWriter.Write(Skill3); binaryWriter.Write(Skill4); + binaryWriter.Write(Skill5); + binaryWriter.Write(Skill6); + binaryWriter.Write(NormalTime); + binaryWriter.Write(NormalStep); + binaryWriter.Write(ChaseTime); + binaryWriter.Write(ChaseStep); + binaryWriter.Write(ChaseRange); + binaryWriter.Write(AttackAni1); + binaryWriter.Write(AttackType1); + binaryWriter.Write(AttackTime1); + binaryWriter.Write(AttackRange1); + binaryWriter.Write(Attack1); + binaryWriter.Write(AttackPlus1); + binaryWriter.Write(AttackAttrib1); + binaryWriter.Write(AttackSpecial1); + binaryWriter.Write(AttackOk1); + binaryWriter.Write(AttackAni2); + binaryWriter.Write(AttackType2); + binaryWriter.Write(AttackTime2); + binaryWriter.Write(AttackRange2); + binaryWriter.Write(Attack2); + binaryWriter.Write(AttackPlus2); + binaryWriter.Write(AttackAttrib2); + binaryWriter.Write(AttackSpecial2); + binaryWriter.Write(AttackOk2); + binaryWriter.Write(AttackAni3); + binaryWriter.Write(AttackType3); + binaryWriter.Write(AttackTime3); + binaryWriter.Write(AttackRange3); + binaryWriter.Write(Attack3); + binaryWriter.Write(AttackPlus3); + binaryWriter.Write(AttackAttrib3); + binaryWriter.Write(AttackSpecial3); + binaryWriter.Write(AttackOk3); + binaryWriter.Write(ColorType); + binaryWriter.Write(ColorHue); + binaryWriter.Write(ColorSaturation); + binaryWriter.Write(ColorLight); } } diff --git a/src/Parsec/Shaiya/Monster/MonsterRecord.cs b/src/Parsec/Shaiya/Monster/MonsterRecord.cs index 6972a444..3a130f30 100644 --- a/src/Parsec/Shaiya/Monster/MonsterRecord.cs +++ b/src/Parsec/Shaiya/Monster/MonsterRecord.cs @@ -11,9 +11,9 @@ public sealed class MonsterRecord : ISerializable public short Level { get; set; } - public byte AI { get; set; } + public byte Ai { get; set; } - public int HP { get; set; } + public int Hp { get; set; } public byte Day { get; set; } @@ -31,17 +31,17 @@ public sealed class MonsterRecord : ISerializable public byte AttackType1 { get; set; } - public byte AttackElement1 { get; set; } + public byte AttackAni1 { get; set; } public byte AttackType2 { get; set; } - public byte AttackRange2 { get; set; } + public byte AttackAni2 { get; set; } public byte AttackType3 { get; set; } - public byte Unknown1 { get; set; } + public byte AttackAni3 { get; set; } - public byte Unknown2 { get; set; } + public byte AttackPlus3 { get; set; } public short QuestItemId { get; set; } @@ -50,8 +50,8 @@ public void Read(SBinaryReader binaryReader) MobName = binaryReader.ReadString(); ModelId = binaryReader.ReadInt16(); Level = binaryReader.ReadInt16(); - AI = binaryReader.ReadByte(); - HP = binaryReader.ReadInt32(); + Ai = binaryReader.ReadByte(); + Hp = binaryReader.ReadInt32(); Day = binaryReader.ReadByte(); Size = binaryReader.ReadByte(); Element = binaryReader.ReadByte(); @@ -60,12 +60,12 @@ public void Read(SBinaryReader binaryReader) ChaseTime = binaryReader.ReadInt32(); ChaseStep = binaryReader.ReadByte(); AttackType1 = binaryReader.ReadByte(); - AttackElement1 = binaryReader.ReadByte(); + AttackAni1 = binaryReader.ReadByte(); AttackType2 = binaryReader.ReadByte(); - AttackRange2 = binaryReader.ReadByte(); + AttackAni2 = binaryReader.ReadByte(); AttackType3 = binaryReader.ReadByte(); - Unknown1 = binaryReader.ReadByte(); - Unknown2 = binaryReader.ReadByte(); + AttackAni3 = binaryReader.ReadByte(); + AttackPlus3 = binaryReader.ReadByte(); QuestItemId = binaryReader.ReadInt16(); } @@ -74,8 +74,8 @@ public void Write(SBinaryWriter binaryWriter) binaryWriter.Write(MobName); binaryWriter.Write(ModelId); binaryWriter.Write(Level); - binaryWriter.Write(AI); - binaryWriter.Write(HP); + binaryWriter.Write(Ai); + binaryWriter.Write(Hp); binaryWriter.Write(Day); binaryWriter.Write(Size); binaryWriter.Write(Element); @@ -84,12 +84,12 @@ public void Write(SBinaryWriter binaryWriter) binaryWriter.Write(ChaseTime); binaryWriter.Write(ChaseStep); binaryWriter.Write(AttackType1); - binaryWriter.Write(AttackElement1); + binaryWriter.Write(AttackAni1); binaryWriter.Write(AttackType2); - binaryWriter.Write(AttackRange2); + binaryWriter.Write(AttackAni2); binaryWriter.Write(AttackType3); - binaryWriter.Write(Unknown1); - binaryWriter.Write(Unknown2); + binaryWriter.Write(AttackAni3); + binaryWriter.Write(AttackPlus3); binaryWriter.Write(QuestItemId); } } diff --git a/src/Parsec/Shaiya/SData/BinarySData.cs b/src/Parsec/Shaiya/SData/BinarySData.cs index 9edfeefa..2b7b7cdc 100644 --- a/src/Parsec/Shaiya/SData/BinarySData.cs +++ b/src/Parsec/Shaiya/SData/BinarySData.cs @@ -62,7 +62,7 @@ protected override void Write(SBinaryWriter binaryWriter) public void WriteCsv(string outputPath, Encoding? encoding = null) { - encoding ??= Encoding.ASCII; + encoding ??= Encoding; using var writer = new StreamWriter(outputPath, false, encoding); using var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture); csvWriter.WriteRecords(Records); diff --git a/src/Parsec/Shaiya/Wld/WldMusicZone.cs b/src/Parsec/Shaiya/Wld/WldMusicZone.cs index 20a2efb2..5dd7a599 100644 --- a/src/Parsec/Shaiya/Wld/WldMusicZone.cs +++ b/src/Parsec/Shaiya/Wld/WldMusicZone.cs @@ -30,11 +30,6 @@ public sealed class WldMusicZone : ISerializable /// public int Unknown { get; set; } - [JsonConstructor] - public WldMusicZone() - { - } - public void Read(SBinaryReader binaryReader) { BoundingBox = binaryReader.Read(); diff --git a/tests/Parsec.Tests/Parsec.Tests.csproj b/tests/Parsec.Tests/Parsec.Tests.csproj index 3c014cc5..00b61646 100644 --- a/tests/Parsec.Tests/Parsec.Tests.csproj +++ b/tests/Parsec.Tests/Parsec.Tests.csproj @@ -1,21 +1,19 @@ - + net8.0 false - - net7.0 - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -710,7 +708,7 @@ PreserveNewest - + PreserveNewest @@ -794,5 +792,32 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + diff --git a/tests/Parsec.Tests/Shaiya/Dg/DgTests.cs b/tests/Parsec.Tests/Shaiya/Dg/DgTests.cs new file mode 100644 index 00000000..7ceb267a --- /dev/null +++ b/tests/Parsec.Tests/Shaiya/Dg/DgTests.cs @@ -0,0 +1,30 @@ +namespace Parsec.Tests.Shaiya.Dg; + +public class DgTests +{ + [Theory] + [InlineData("R1_Dun1_2F.dg")] + [InlineData("r1_dun3.dg")] + [InlineData("r1_dun3_01.dg")] + [InlineData("r1_dun3_02.dg")] + [InlineData("r1_dun3_boss.dg")] + [InlineData("R1_Trade.dg")] + [InlineData("R2_Dun1.dg")] + public void DgMultipleReadWriteTest(string fileName) + { + var filePath = $"Shaiya/Dg/{fileName}"; + var outputPath = $"Shaiya/Dg/output_{fileName}"; + var jsonPath = $"Shaiya/Dg/{fileName}.json"; + + var dg = ParsecReader.FromFile(filePath); + dg.Write(outputPath); + dg.WriteJson(jsonPath); + + var outputDg = ParsecReader.FromFile(outputPath); + var dgFromJson = ParsecReader.FromJsonFile(jsonPath); + + // Check bytes + Assert.Equal(dg.GetBytes(), outputDg.GetBytes()); + Assert.Equal(dg.GetBytes(), dgFromJson.GetBytes()); + } +} diff --git a/tests/Parsec.Tests/Shaiya/Dg/R1_Dun1_2F.dg b/tests/Parsec.Tests/Shaiya/Dg/R1_Dun1_2F.dg new file mode 100644 index 00000000..133c5de7 Binary files /dev/null and b/tests/Parsec.Tests/Shaiya/Dg/R1_Dun1_2F.dg differ diff --git a/tests/Parsec.Tests/Shaiya/Dg/R1_Trade.dg b/tests/Parsec.Tests/Shaiya/Dg/R1_Trade.dg new file mode 100644 index 00000000..0e55262c Binary files /dev/null and b/tests/Parsec.Tests/Shaiya/Dg/R1_Trade.dg differ diff --git a/tests/Parsec.Tests/Shaiya/Dg/R2_Dun1.dg b/tests/Parsec.Tests/Shaiya/Dg/R2_Dun1.dg new file mode 100644 index 00000000..699916c5 Binary files /dev/null and b/tests/Parsec.Tests/Shaiya/Dg/R2_Dun1.dg differ diff --git a/tests/Parsec.Tests/Shaiya/Dg/r1_dun3.dg b/tests/Parsec.Tests/Shaiya/Dg/r1_dun3.dg new file mode 100644 index 00000000..9b66af91 Binary files /dev/null and b/tests/Parsec.Tests/Shaiya/Dg/r1_dun3.dg differ diff --git a/tests/Parsec.Tests/Shaiya/Dg/r1_dun3_01.dg b/tests/Parsec.Tests/Shaiya/Dg/r1_dun3_01.dg new file mode 100644 index 00000000..4a51b97e Binary files /dev/null and b/tests/Parsec.Tests/Shaiya/Dg/r1_dun3_01.dg differ diff --git a/tests/Parsec.Tests/Shaiya/Dg/r1_dun3_02.dg b/tests/Parsec.Tests/Shaiya/Dg/r1_dun3_02.dg new file mode 100644 index 00000000..fc09a1ee Binary files /dev/null and b/tests/Parsec.Tests/Shaiya/Dg/r1_dun3_02.dg differ diff --git a/tests/Parsec.Tests/Shaiya/Dg/r1_dun3_boss.dg b/tests/Parsec.Tests/Shaiya/Dg/r1_dun3_boss.dg new file mode 100644 index 00000000..422db1fc Binary files /dev/null and b/tests/Parsec.Tests/Shaiya/Dg/r1_dun3_boss.dg differ diff --git a/tests/Parsec.Tests/Shaiya/Item/ItemEp6_1251.SData b/tests/Parsec.Tests/Shaiya/Item/ItemEp64_1251.SData similarity index 100% rename from tests/Parsec.Tests/Shaiya/Item/ItemEp6_1251.SData rename to tests/Parsec.Tests/Shaiya/Item/ItemEp64_1251.SData diff --git a/tests/Parsec.Tests/Shaiya/Item/ItemTests.cs b/tests/Parsec.Tests/Shaiya/Item/ItemTests.cs index 38337efb..a9179199 100644 --- a/tests/Parsec.Tests/Shaiya/Item/ItemTests.cs +++ b/tests/Parsec.Tests/Shaiya/Item/ItemTests.cs @@ -20,28 +20,40 @@ public void ItemEp5CsvTest() } [Fact] - public void ItemEp6CsvTest() + public void ItemEp5ReadWriteTest() { - const string filePath = "Shaiya/Item/ItemEp6.SData"; - const string csvPath = "Shaiya/Item/ItemEp6.SData.csv"; + const string filePath = "Shaiya/Item/ItemEp5.SData"; + const string outputPath = "Shaiya/Item/ItemEp5.written.SData"; + + var item = ParsecReader.FromFile(filePath, Episode.EP5, TestEncodings.Encoding1252); + item.WriteEncrypted(outputPath); + + Assert.Equal(FileHash.Checksum(filePath), FileHash.Checksum(outputPath)); + } + + [Fact] + public void ItemEp64CsvTest() + { + const string filePath = "Shaiya/Item/Item_ES_ps0224.SData"; + const string csvPath = "Shaiya/Item/Item_ES_ps0224.SData.csv"; - var item = ParsecReader.FromFile(filePath, Episode.EP6); + var item = ParsecReader.FromFile(filePath, Episode.EP6_4, TestEncodings.Encoding1252); item.WriteCsv(csvPath); - var itemFromCsv = Parsec.Shaiya.Item.Item.FromCsv(csvPath, Episode.EP6); - Assert.Equal(item.GetBytes(Episode.EP6), itemFromCsv.GetBytes(Episode.EP6)); + var itemFromCsv = Parsec.Shaiya.Item.Item.FromCsv(csvPath, Episode.EP6_4, TestEncodings.Encoding1252); + Assert.Equal(item.GetBytes(Episode.EP6_4, TestEncodings.Encoding1252), itemFromCsv.GetBytes(Episode.EP6_4, TestEncodings.Encoding1252)); } [Fact] - public void ItemEp6Csv_EncodingTest() + public void ItemEp64Csv_EncodingTest() { - const string filePath = "Shaiya/Item/ItemEp6_1251.SData"; - const string csvPath = "Shaiya/Item/ItemEp6_1252.SData.csv"; + const string filePath = "Shaiya/Item/ItemEp64_1251.SData"; + const string csvPath = "Shaiya/Item/ItemEp64_1251.SData.csv"; var encoding = TestEncodings.Encoding1251; - var item = ParsecReader.FromFile(filePath, Episode.EP6, encoding); + var item = ParsecReader.FromFile(filePath, Episode.EP6_4, encoding); item.WriteCsv(csvPath, encoding); - var itemFromCsv = Parsec.Shaiya.Item.Item.FromCsv(csvPath, Episode.EP6, encoding); - Assert.Equal(item.GetBytes(Episode.EP6), itemFromCsv.GetBytes(Episode.EP6)); + var itemFromCsv = Parsec.Shaiya.Item.Item.FromCsv(csvPath, Episode.EP6_4, encoding); + Assert.Equal(item.GetBytes(Episode.EP6_4), itemFromCsv.GetBytes(Episode.EP6_4)); } [Fact] diff --git a/tests/Parsec.Tests/Shaiya/Item/Item_ES_ps0224.SData b/tests/Parsec.Tests/Shaiya/Item/Item_ES_ps0224.SData new file mode 100644 index 00000000..80e7d25c Binary files /dev/null and b/tests/Parsec.Tests/Shaiya/Item/Item_ES_ps0224.SData differ diff --git a/tests/Parsec.Tests/Shaiya/Item/Item_US_ps0216.SData b/tests/Parsec.Tests/Shaiya/Item/Item_US_ps0216.SData new file mode 100644 index 00000000..66cfe7f2 Binary files /dev/null and b/tests/Parsec.Tests/Shaiya/Item/Item_US_ps0216.SData differ diff --git a/tests/Parsec.Tests/Shaiya/SData/SDataTests.cs b/tests/Parsec.Tests/Shaiya/SData/SDataTests.cs index e2cdf544..f6257eec 100644 --- a/tests/Parsec.Tests/Shaiya/SData/SDataTests.cs +++ b/tests/Parsec.Tests/Shaiya/SData/SDataTests.cs @@ -60,7 +60,7 @@ public void SDataDecryptionTest() const string encryptedOutputPath = "Shaiya/SData/ItemEp6.encrypted.SData"; const string decryptedOutputPath = "Shaiya/SData/ItemEp6.decrypted.SData"; - var item = ParsecReader.FromFile(EncryptedSDataFilePath, Episode.EP6); + var item = ParsecReader.FromFile(EncryptedSDataFilePath, Episode.EP6_4); item.WriteEncrypted(encryptedOutputPath); item.WriteDecrypted(decryptedOutputPath);