From b3da18843850dc01121d158df82f03c694370050 Mon Sep 17 00:00:00 2001 From: jracek Date: Wed, 9 Apr 2025 22:20:52 +0200 Subject: [PATCH] Added lua exporting --- Editor/LuaFileAssetEditor.cs | 15 ++++++ Editor/LuaFileAssetEditor.cs.meta | 2 + Editor/LuaImporter.cs | 17 +++++++ Editor/LuaImporter.cs.meta | 2 + Runtime/LuaFile.cs | 11 +++++ Runtime/LuaFile.cs.meta | 2 + Runtime/PSXObjectExporter.cs | 2 + Runtime/PSXSceneExporter.cs | 65 +++++++++++++++++++++++- doc/splashbundle.md | 79 +++++++++++++++++------------- tools/imhex.hexproj | Bin 19456 -> 19968 bytes 10 files changed, 161 insertions(+), 34 deletions(-) create mode 100644 Editor/LuaFileAssetEditor.cs create mode 100644 Editor/LuaFileAssetEditor.cs.meta create mode 100644 Editor/LuaImporter.cs create mode 100644 Editor/LuaImporter.cs.meta create mode 100644 Runtime/LuaFile.cs create mode 100644 Runtime/LuaFile.cs.meta diff --git a/Editor/LuaFileAssetEditor.cs b/Editor/LuaFileAssetEditor.cs new file mode 100644 index 0000000..04968a8 --- /dev/null +++ b/Editor/LuaFileAssetEditor.cs @@ -0,0 +1,15 @@ +using Splashedit.RuntimeCode; +using UnityEditor; +using UnityEngine; + +[CustomEditor(typeof(LuaFile))] +public class LuaScriptAssetEditor : Editor +{ + public override void OnInspectorGUI() + { + LuaFile luaScriptAsset = (LuaFile)target; + + // Allow user to drag-and-drop the Lua file + luaScriptAsset.luaScript = (TextAsset)EditorGUILayout.ObjectField("Lua Script", luaScriptAsset.luaScript, typeof(TextAsset), false); + } +} diff --git a/Editor/LuaFileAssetEditor.cs.meta b/Editor/LuaFileAssetEditor.cs.meta new file mode 100644 index 0000000..670ebc0 --- /dev/null +++ b/Editor/LuaFileAssetEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 32c0501d523345500be12e6e4214ec9d \ No newline at end of file diff --git a/Editor/LuaImporter.cs b/Editor/LuaImporter.cs new file mode 100644 index 0000000..97aa322 --- /dev/null +++ b/Editor/LuaImporter.cs @@ -0,0 +1,17 @@ +using UnityEngine; +using System.IO; +using UnityEditor.AssetImporters; + +namespace SplashEdit.EditorCode +{ + [ScriptedImporter(1, "lua")] + class LuaImporter : ScriptedImporter + { + public override void OnImportAsset(AssetImportContext ctx) + { + var asset = new TextAsset(File.ReadAllText(ctx.assetPath)); + ctx.AddObjectToAsset("Text", asset); + ctx.SetMainObject(asset); + } + } +} \ No newline at end of file diff --git a/Editor/LuaImporter.cs.meta b/Editor/LuaImporter.cs.meta new file mode 100644 index 0000000..dcc9288 --- /dev/null +++ b/Editor/LuaImporter.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d364a1392e3bccd77aca824ac471f89c \ No newline at end of file diff --git a/Runtime/LuaFile.cs b/Runtime/LuaFile.cs new file mode 100644 index 0000000..56a297d --- /dev/null +++ b/Runtime/LuaFile.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +namespace Splashedit.RuntimeCode +{ + + [CreateAssetMenu(fileName = "NewLuaScript", menuName = "Lua Script", order = 1)] + public class LuaFile : ScriptableObject + { + public TextAsset luaScript; + } +} diff --git a/Runtime/LuaFile.cs.meta b/Runtime/LuaFile.cs.meta new file mode 100644 index 0000000..25e5cc5 --- /dev/null +++ b/Runtime/LuaFile.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e3b07239f3beb7a87ad987c3fedae9c1 \ No newline at end of file diff --git a/Runtime/PSXObjectExporter.cs b/Runtime/PSXObjectExporter.cs index 8cd3fda..7062393 100644 --- a/Runtime/PSXObjectExporter.cs +++ b/Runtime/PSXObjectExporter.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Splashedit.RuntimeCode; using UnityEngine; namespace SplashEdit.RuntimeCode @@ -7,6 +8,7 @@ namespace SplashEdit.RuntimeCode public class PSXObjectExporter : MonoBehaviour { public PSXBPP BitDepth = PSXBPP.TEX_8BIT; // Defines the bit depth of the texture (e.g., 4BPP, 8BPP) + public LuaFile luaFile; public List Textures { get; set; } = new List(); // Stores the converted PlayStation-style texture public PSXMesh Mesh { get; set; } // Stores the converted PlayStation-style mesh diff --git a/Runtime/PSXSceneExporter.cs b/Runtime/PSXSceneExporter.cs index 688e23c..8d2d874 100644 --- a/Runtime/PSXSceneExporter.cs +++ b/Runtime/PSXSceneExporter.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using Splashedit.RuntimeCode; using UnityEditor; using UnityEngine; @@ -83,6 +84,10 @@ namespace SplashEdit.RuntimeCode string path = EditorUtility.SaveFilePanel("Select Output File", "", "output", "bin"); int totalFaces = 0; + // Lists for lua data offsets. + List luaOffsetPlaceholderPositions = new List(); + List luaDataOffsets = new List(); + // Lists for mesh data offsets. List meshOffsetPlaceholderPositions = new List(); List meshDataOffsets = new List(); @@ -100,6 +105,7 @@ namespace SplashEdit.RuntimeCode List navmeshDataOffsets = new List(); int clutCount = 0; + List luaFiles = new List(); // Cluts foreach (TextureAtlas atlas in _atlases) @@ -113,12 +119,26 @@ namespace SplashEdit.RuntimeCode } } + // Lua files + foreach (PSXObjectExporter exporter in _exporters) + { + if (exporter.luaFile != null) + { + //if not contains + if (!luaFiles.Contains(exporter.luaFile)) + { + luaFiles.Add(exporter.luaFile); + } + } + } + using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create))) { // Header writer.Write('S'); // 1 byte // 1 writer.Write('P'); // 1 byte // 2 writer.Write((ushort)1); // 2 bytes - version // 4 + writer.Write((ushort)luaFiles.Count); // 2 bytes - padding // 6 writer.Write((ushort)_exporters.Length); // 2 bytes // 6 writer.Write((ushort)_navmeshes.Length); // 8 writer.Write((ushort)_atlases.Length); // 2 bytes // 10 @@ -134,6 +154,16 @@ namespace SplashEdit.RuntimeCode writer.Write((ushort)PSXTrig.ConvertCoordinateToPSX(_playerHeight, GTEScaling)); // 26 writer.Write((ushort)0); + writer.Write((ushort)0); + + // Lua file section + foreach (LuaFile luaFile in luaFiles) + { + // Write placeholder for lua file data offset and record its position. + luaOffsetPlaceholderPositions.Add(writer.BaseStream.Position); + writer.Write((int)0); // 4-byte placeholder for mesh data offset. + writer.Write((uint)luaFile.luaScript.text.Length); + } // GameObject section (exporters) foreach (PSXObjectExporter exporter in _exporters) @@ -159,7 +189,15 @@ namespace SplashEdit.RuntimeCode writer.Write((int)rotationMatrix[2, 2]); writer.Write((ushort)exporter.Mesh.Triangles.Count); - writer.Write((ushort)0); + if (exporter.luaFile != null) + { + int index = luaFiles.IndexOf(exporter.luaFile); + writer.Write((short)index); + } + else + { + writer.Write((short)-1); + } } // Navmesh metadata section @@ -205,6 +243,17 @@ namespace SplashEdit.RuntimeCode // Start of data section + // Lua data section: Write lua file data for each exporter. + foreach (LuaFile luaFile in luaFiles) + { + AlignToFourBytes(writer); + // Record the current offset for this lua file's data. + long luaDataOffset = writer.BaseStream.Position; + luaDataOffsets.Add(luaDataOffset); + + writer.Write(luaFile.luaScript.bytes); + } + // Mesh data section: Write mesh data for each exporter. foreach (PSXObjectExporter exporter in _exporters) { @@ -337,6 +386,20 @@ namespace SplashEdit.RuntimeCode } + // Bacfill the lua data offsets into the metadata section. + if (luaOffsetPlaceholderPositions.Count == luaDataOffsets.Count) + { + for (int i = 0; i < luaOffsetPlaceholderPositions.Count; i++) + { + writer.Seek((int)luaOffsetPlaceholderPositions[i], SeekOrigin.Begin); + writer.Write((int)luaDataOffsets[i]); + } + } + else + { + Debug.LogError("Mismatch between metadata lua offset placeholders and lua data blocks!"); + } + // Backfill the mesh data offsets into the metadata section. if (meshOffsetPlaceholderPositions.Count == meshDataOffsets.Count) { diff --git a/doc/splashbundle.md b/doc/splashbundle.md index 46caf90..75e811e 100644 --- a/doc/splashbundle.md +++ b/doc/splashbundle.md @@ -10,24 +10,32 @@ All numeric values are stored in little‐endian format. All offsets are counted | ------ | ---- | ------ | ----------------------------------- | | 0x00 | 2 | char | `'SP'` – File magic | | 0x02 | 2 | uint16 | Version number | -| 0x04 | 2 | uint16 | Number of GameObjects | -| 0x06 | 2 | uint16 | Number of Navmeshes | -| 0x08 | 2 | uint16 | Number of Texture Atlases | -| 0x0A | 2 | uint16 | Number of CLUTs | -| 0x0C | 2 | uint16 | Player Start X | -| 0x0E | 2 | uint16 | Player Start Y | -| 0x10 | 2 | uint16 | Player Start Z | -| 0x12 | 2 | uint16 | Player Rotation X | -| 0x14 | 2 | uint16 | Player Rotation Y | -| 0x16 | 2 | uint16 | Player Rotation Z | -| 0x18 | 2 | uint16 | Player Height | -| 0x1A | 2 | uint16 | Reserved (always 0) | +| 0x04 | 2 | uint16 | Number of Lua Files | +| 0x06 | 2 | uint16 | Number of GameObjects | +| 0x08 | 2 | uint16 | Number of Navmeshes | +| 0x0A | 2 | uint16 | Number of Texture Atlases | +| 0x0C | 2 | uint16 | Number of CLUTs | +| 0x0E | 2 | uint16 | Player Start X (Fixed-point) | +| 0x10 | 2 | uint16 | Player Start Y (Fixed-point) | +| 0x12 | 2 | uint16 | Player Start Z (Fixed-point) | +| 0x14 | 2 | uint16 | Player Rotation X (Fixed-point) | +| 0x16 | 2 | uint16 | Player Rotation Y (Fixed-point) | +| 0x18 | 2 | uint16 | Player Rotation Z (Fixed-point) | +| 0x1A | 2 | uint16 | Player Height (Fixed-point) | +| 0x1C | 4 | uint32 | Reserved (always 0) | --- ## 2. Metadata Section -### 2.1 GameObject Descriptors (56 bytes each) +### 2.1 Lua File Descriptors (8 bytes each) + +| Offset (per entry) | Size | Type | Description | +| ------------------ | ---- | ------ | --------------------------------- | +| 0x00 | 4 | uint32 | Lua File Data Offset | +| 0x04 | 4 | uint32 | Lua File Size | + +### 2.2 GameObject Descriptors (56 bytes each) | Offset (per entry) | Size | Type | Description | | ------------------ | ---- | -------- | --------------------------------- | @@ -37,21 +45,17 @@ All numeric values are stored in little‐endian format. All offsets are counted | 0x0C | 4 | int32 | Z position (Fixed-point) | | 0x10 | 36 | int32[9] | 3×3 Rotation Matrix (Fixed-point) | | 0x34 | 2 | uint16 | Triangle count | -| 0x36 | 2 | int16 | Padding | +| 0x36 | 2 | int16 | Lua File Index (-1 if none) | -> Mesh data for each GameObject is located at `meshDataOffset`. - -### 2.2 Navmesh Descriptors (8 bytes each) +### 2.3 Navmesh Descriptors (8 bytes each) | Offset (per entry) | Size | Type | Description | | ------------------ | ---- | ------ | --------------------------------- | | 0x00 | 4 | uint32 | Navmesh Data Offset | -| 0x04 | 2 | int16 | Triangle count | -| 0x06 | 2 | int16 | Padding | +| 0x04 | 2 | uint16 | Triangle count | +| 0x06 | 2 | uint16 | Padding | -> Each triangle in a navmesh is defined by 3 `int16` vertices (6 bytes per vertex). - -### 2.3 Texture Atlas Descriptors (12 bytes each) +### 2.4 Texture Atlas Descriptors (12 bytes each) | Offset (per entry) | Size | Type | Description | | ------------------ | ---- | ------ | -------------------------------- | @@ -61,9 +65,7 @@ All numeric values are stored in little‐endian format. All offsets are counted | 0x08 | 2 | uint16 | Atlas Position X (VRAM origin) | | 0x0A | 2 | uint16 | Atlas Position Y (VRAM origin) | -> Pixel data is stored as `uint16[width * height]`. - -### 2.4 CLUT Descriptors (12 bytes each) +### 2.5 CLUT Descriptors (12 bytes each) | Offset (per entry) | Size | Type | Description | | ------------------ | ---- | ------ | ----------------------------------------------------- | @@ -73,20 +75,24 @@ All numeric values are stored in little‐endian format. All offsets are counted | 0x08 | 2 | uint16 | Palette entry count | | 0x0A | 2 | uint16 | Padding | -> CLUT pixel data is stored as `uint16[length]`. - --- ## 3. Data Section -### 3.1 Mesh Data Block (per GameObject) +### 3.1 Lua Data Block + +Each Lua file is stored as raw bytes. The size of each Lua file is specified in the Lua File Descriptor. + +--- + +### 3.2 Mesh Data Block (per GameObject) Each mesh is made of triangles: **Triangle Layout (52 bytes):** | Field | Size | Description | -| -------------------|------|-----------------------------------------------------| +| ------------------- |------|-----------------------------------------------------| | Vertex v0 | 6 | x, y, z (int16) | | Vertex v1 | 6 | x, y, z (int16) | | Vertex v2 | 6 | x, y, z (int16) | @@ -105,20 +111,27 @@ Each mesh is made of triangles: --- -### 3.2 Navmesh Data Block +### 3.3 Navmesh Data Block Each triangle is 3 vertices (`int16` x/y/z), total 18 bytes per triangle. --- -### 3.3 Texture Atlas Data Block +### 3.4 Texture Atlas Data Block Pixel data stored as `uint16[width * height]`. --- -### 3.4 CLUT Data Block +### 3.5 CLUT Data Block Pixel data stored as `uint16[length]`. ---- \ No newline at end of file +--- + +## Notes + +- All offsets are aligned to 4-byte boundaries. +- Fixed-point values are scaled by the `GTEScaling` factor. +- Lua file indices in GameObject descriptors are `-1` if no Lua file is associated with the object. +- Navmesh triangles are stored as raw vertex data without additional attributes. \ No newline at end of file diff --git a/tools/imhex.hexproj b/tools/imhex.hexproj index 1afaa9f7c8b8ffbf0879109fd6321abe8a457ff8..48f799811656f14f48745439a7d430f03856f60e 100644 GIT binary patch delta 267 zcmZpe!Pqc|aYKy=i;01;$>atRNfr|Z1%u6oT*-`+#3FcdN)z2Ob5fo2OY=%L`-!nI z)*HoIbJbdNaTS*ol_r-c_&^kRq$Z}M7AaJ7DF8vKv5^8)qkmdjacYS*y0A}bUV2Fe zL^wGku}C2~KP5F9ss|z&tKgtel95@ghicO1Q1MHQFlTw@rKDDD){<;t(nNI!R8Mhq g8qo0>V7I}{nfyRng##wPd6je+)5Z-vjEm&-07&v#9RL6T delta 64 zcmV-G0Kfl$oB@EC0kC`&1T!=>Fq42383Z)|ATYBr3S$A17Fd&R7Wx7)U9;vF(*cux W8VQq)8XvRj8D9dkq8w5Jq987eP88n&