diff --git a/Data.meta b/Data.meta new file mode 100644 index 0000000..04215d2 --- /dev/null +++ b/Data.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d7e9b1c3e60e2ff48be3cd61902ba6f1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Data/SPLASHLICENSE.DAT b/Data/SPLASHLICENSE.DAT new file mode 100644 index 0000000..e480cc9 Binary files /dev/null and b/Data/SPLASHLICENSE.DAT differ diff --git a/Data/SPLASHLICENSE.DAT.meta b/Data/SPLASHLICENSE.DAT.meta new file mode 100644 index 0000000..5701751 --- /dev/null +++ b/Data/SPLASHLICENSE.DAT.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 244f6913a02805e4aa3cebdd1240cab7 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Core/SplashBuildPaths.cs b/Editor/Core/SplashBuildPaths.cs index bf3bc15..4f034ff 100644 --- a/Editor/Core/SplashBuildPaths.cs +++ b/Editor/Core/SplashBuildPaths.cs @@ -109,6 +109,13 @@ namespace SplashEdit.EditorCode return Path.Combine(BuildOutputDir, $"scene_{sceneIndex}.splashpack"); } + /// + /// Default license file path (SPLASHLICENSE.DAT) shipped in the package Data folder. + /// Resolved relative to the Unity project so it works on any machine. + /// + public static string DefaultLicenseFilePath => + Path.GetFullPath(Path.Combine("Packages", "net.psxsplash.splashedit", "Data", "SPLASHLICENSE.DAT")); + /// /// Gets the loader pack (loading screen) output path for a scene by index. /// Uses a deterministic naming scheme: scene_0.loading, scene_1.loading, etc. diff --git a/Editor/Core/SplashSettings.cs b/Editor/Core/SplashSettings.cs index 821d6d9..14928a7 100644 --- a/Editor/Core/SplashSettings.cs +++ b/Editor/Core/SplashSettings.cs @@ -151,7 +151,7 @@ namespace SplashEdit.EditorCode /// public static string LicenseFilePath { - get => EditorPrefs.GetString(Prefix + "LicenseFilePath", ""); + get => EditorPrefs.GetString(Prefix + "LicenseFilePath", SplashBuildPaths.DefaultLicenseFilePath); set => EditorPrefs.SetString(Prefix + "LicenseFilePath", value); } diff --git a/Editor/Inspectors/PSXComponentEditors.cs b/Editor/Inspectors/PSXComponentEditors.cs index 573245d..1fad0aa 100644 --- a/Editor/Inspectors/PSXComponentEditors.cs +++ b/Editor/Inspectors/PSXComponentEditors.cs @@ -12,21 +12,21 @@ namespace SplashEdit.EditorCode { private bool _interactionFoldout = true; private bool _advancedFoldout = false; - + private SerializedProperty _interactionRadius; private SerializedProperty _interactButton; private SerializedProperty _isRepeatable; private SerializedProperty _cooldownFrames; private SerializedProperty _showPrompt; + private SerializedProperty _promptCanvasName; private SerializedProperty _requireLineOfSight; - private SerializedProperty _interactionOffset; - - private static readonly string[] ButtonNames = + + private static readonly string[] ButtonNames = { "Select", "L3", "R3", "Start", "Up", "Right", "Down", "Left", "L2", "R2", "L1", "R1", "Triangle", "Circle", "Cross", "Square" }; - + private void OnEnable() { _interactionRadius = serializedObject.FindProperty("interactionRadius"); @@ -34,10 +34,10 @@ namespace SplashEdit.EditorCode _isRepeatable = serializedObject.FindProperty("isRepeatable"); _cooldownFrames = serializedObject.FindProperty("cooldownFrames"); _showPrompt = serializedObject.FindProperty("showPrompt"); + _promptCanvasName = serializedObject.FindProperty("promptCanvasName"); _requireLineOfSight = serializedObject.FindProperty("requireLineOfSight"); - _interactionOffset = serializedObject.FindProperty("interactionOffset"); } - + public override void OnInspectorGUI() { serializedObject.Update(); @@ -76,15 +76,35 @@ namespace SplashEdit.EditorCode EditorGUI.indentLevel--; } - EditorGUILayout.PropertyField(_showPrompt); + EditorGUILayout.Space(4); + + EditorGUILayout.PropertyField(_showPrompt, new GUIContent("Show Prompt Canvas")); + + if (_showPrompt.boolValue) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_promptCanvasName, new GUIContent("Canvas Name")); + if (string.IsNullOrEmpty(_promptCanvasName.stringValue)) + { + EditorGUILayout.HelpBox( + "Enter the name of a PSXCanvas that will be shown when the player is in range and hidden when they leave.", + MessageType.Info); + } + if (_promptCanvasName.stringValue != null && _promptCanvasName.stringValue.Length > 15) + { + EditorGUILayout.HelpBox("Canvas name is limited to 15 characters.", MessageType.Warning); + } + EditorGUI.indentLevel--; + } }); EditorGUILayout.Space(2); _advancedFoldout = PSXEditorStyles.DrawFoldoutCard("Advanced", _advancedFoldout, () => { - EditorGUILayout.PropertyField(_requireLineOfSight); - EditorGUILayout.PropertyField(_interactionOffset); + EditorGUILayout.PropertyField(_requireLineOfSight, + new GUIContent("Require Facing", + "Player must be facing the object to interact. Uses a forward-direction check.")); }); EditorGUILayout.Space(4); diff --git a/Editor/Inspectors/PSXComponentEditors2.cs b/Editor/Inspectors/PSXComponentEditors2.cs index 2c7dda6..36cc9fa 100644 --- a/Editor/Inspectors/PSXComponentEditors2.cs +++ b/Editor/Inspectors/PSXComponentEditors2.cs @@ -1,3 +1,6 @@ +// I raged that my scrollwheel was broken while writing this and that's why it's 2 files. + + using UnityEngine; using UnityEditor; using SplashEdit.RuntimeCode; diff --git a/Editor/PSXObjectExporterEditor.cs b/Editor/PSXObjectExporterEditor.cs index 40224e9..1e3b61b 100644 --- a/Editor/PSXObjectExporterEditor.cs +++ b/Editor/PSXObjectExporterEditor.cs @@ -158,7 +158,7 @@ namespace SplashEdit.EditorCode if (collType == PSXCollisionType.Static) { EditorGUILayout.LabelField( - "Baked into world collision mesh. No runtime cost.", + "Only bakes holes in the navregions", PSXEditorStyles.RichLabel); } else if (collType == PSXCollisionType.Dynamic) diff --git a/Runtime/PSXAudioClip.cs b/Runtime/PSXAudioClip.cs index a52ba5f..61206e7 100644 --- a/Runtime/PSXAudioClip.cs +++ b/Runtime/PSXAudioClip.cs @@ -18,7 +18,7 @@ namespace SplashEdit.RuntimeCode /// At export time, the AudioClip is converted to SPU ADPCM and packed /// into the splashpack for runtime loading. /// - [AddComponentMenu("PSX/Audio Clip")] + [AddComponentMenu("PSX/PSX Audio Clip")] [Icon("Packages/net.psxsplash.splashedit/Icons/PSXAudioClip.png")] public class PSXAudioClip : MonoBehaviour { diff --git a/Runtime/PSXInteractable.cs b/Runtime/PSXInteractable.cs index 00b8401..92b76f0 100644 --- a/Runtime/PSXInteractable.cs +++ b/Runtime/PSXInteractable.cs @@ -14,25 +14,25 @@ namespace SplashEdit.RuntimeCode [Header("Interaction Settings")] [Tooltip("Distance within which the player can interact with this object")] [SerializeField] private float interactionRadius = 2.0f; - + [Tooltip("Button that triggers interaction (0-15, matches PS1 button mapping)")] - [SerializeField] private int interactButton = 5; // Default to Cross button - + [SerializeField] private int interactButton = 14; // Default to Cross button + [Tooltip("Can this object be interacted with multiple times?")] [SerializeField] private bool isRepeatable = true; - + [Tooltip("Cooldown between interactions (in frames, 60 = 1 second at NTSC)")] [SerializeField] private ushort cooldownFrames = 30; - - [Tooltip("Show interaction prompt when in range (requires UI system)")] - [SerializeField] private bool showPrompt = true; - + + [Tooltip("Show a UI canvas when the player is in range")] + [SerializeField] private bool showPrompt = false; + + [Tooltip("Name of the PSXCanvas to show when the player is in range")] + [SerializeField] private string promptCanvasName = ""; + [Header("Advanced")] - [Tooltip("Require line-of-sight to player for interaction")] + [Tooltip("Require the player to be facing this object to interact")] [SerializeField] private bool requireLineOfSight = false; - - [Tooltip("Custom interaction point offset from object center")] - [SerializeField] private Vector3 interactionOffset = Vector3.zero; // Public accessors for export public float InteractionRadius => interactionRadius; @@ -40,23 +40,19 @@ namespace SplashEdit.RuntimeCode public bool IsRepeatable => isRepeatable; public ushort CooldownFrames => cooldownFrames; public bool ShowPrompt => showPrompt; + public string PromptCanvasName => promptCanvasName; public bool RequireLineOfSight => requireLineOfSight; - public Vector3 InteractionOffset => interactionOffset; private void OnDrawGizmosSelected() { // Draw interaction radius Gizmos.color = new Color(1f, 1f, 0f, 0.3f); // Yellow, semi-transparent - Vector3 center = transform.position + interactionOffset; + Vector3 center = transform.position; Gizmos.DrawWireSphere(center, interactionRadius); - + // Draw filled sphere with lower alpha Gizmos.color = new Color(1f, 1f, 0f, 0.1f); Gizmos.DrawSphere(center, interactionRadius); - - // Draw interaction point - Gizmos.color = Color.yellow; - Gizmos.DrawSphere(center, 0.1f); } } } diff --git a/Runtime/PSXSceneExporter.cs b/Runtime/PSXSceneExporter.cs index 0b7f8e8..6151e0b 100644 --- a/Runtime/PSXSceneExporter.cs +++ b/Runtime/PSXSceneExporter.cs @@ -311,7 +311,6 @@ namespace SplashEdit.RuntimeCode atlases = _atlases, interactables = _interactables, audioClips = audioExports, - collisionExporter = _collisionExporter, navRegionBuilder = _navRegionBuilder, roomBuilder = _roomBuilder, bvh = _bvh, diff --git a/Runtime/PSXSceneWriter.cs b/Runtime/PSXSceneWriter.cs index 09e9145..4355184 100644 --- a/Runtime/PSXSceneWriter.cs +++ b/Runtime/PSXSceneWriter.cs @@ -22,7 +22,6 @@ namespace SplashEdit.RuntimeCode public TextureAtlas[] atlases; public PSXInteractable[] interactables; public AudioClipExport[] audioClips; - public PSXCollisionExporter collisionExporter; public PSXNavRegionBuilder navRegionBuilder; public PSXRoomBuilder roomBuilder; public BVH bvh; @@ -169,8 +168,8 @@ namespace SplashEdit.RuntimeCode writer.Write((ushort)scene.sceneType); writer.Write((ushort)triggerBoxCount); // was pad0 - writer.Write((ushort)scene.collisionExporter.MeshCount); - writer.Write((ushort)scene.collisionExporter.TriangleCount); + writer.Write((ushort)0); // collisionMeshCount (removed, kept for binary compat) + writer.Write((ushort)0); // collisionTriCount (removed, kept for binary compat) writer.Write((ushort)scene.navRegionBuilder.RegionCount); writer.Write((ushort)scene.navRegionBuilder.PortalCount); @@ -342,7 +341,7 @@ namespace SplashEdit.RuntimeCode scene.bvh.WriteToBinary(writer, gte); // ────────────────────────────────────────────────────── - // Interactable components (24 bytes each) + // Interactable components (28 bytes each) // ────────────────────────────────────────────────────── AlignToFourBytes(writer); foreach (PSXInteractable interactable in scene.interactables) @@ -353,11 +352,6 @@ namespace SplashEdit.RuntimeCode float radiusSq = interactable.InteractionRadius * interactable.InteractionRadius; writer.Write(PSXTrig.ConvertWorldToFixed12(radiusSq / (gte * gte))); - Vector3 offset = interactable.InteractionOffset; - writer.Write(PSXTrig.ConvertWorldToFixed12(offset.x / gte)); - writer.Write(PSXTrig.ConvertWorldToFixed12(-offset.y / gte)); - writer.Write(PSXTrig.ConvertWorldToFixed12(offset.z / gte)); - writer.Write((byte)interactable.InteractButton); byte flags = 0; if (interactable.IsRepeatable) flags |= 0x01; @@ -368,15 +362,14 @@ namespace SplashEdit.RuntimeCode writer.Write((ushort)0); // currentCooldown (runtime) writer.Write((ushort)goIndex); - } - // ────────────────────────────────────────────────────── - // World collision soup (version 7+) - // ────────────────────────────────────────────────────── - if (scene.collisionExporter.MeshCount > 0) - { - AlignToFourBytes(writer); - scene.collisionExporter.WriteToBinary(writer, gte); + // Prompt canvas name (16 bytes, null-terminated, zero-padded) + string canvasName = interactable.PromptCanvasName ?? ""; + byte[] nameBytes = new byte[16]; + int len = System.Math.Min(canvasName.Length, 15); + for (int ci = 0; ci < len; ci++) + nameBytes[ci] = (byte)canvasName[ci]; + writer.Write(nameBytes); } // ────────────────────────────────────────────────────── diff --git a/Runtime/SceneMemoryAnalyzer.cs b/Runtime/SceneMemoryAnalyzer.cs index 5a86fb8..5fd579e 100644 --- a/Runtime/SceneMemoryAnalyzer.cs +++ b/Runtime/SceneMemoryAnalyzer.cs @@ -114,9 +114,6 @@ namespace SplashEdit.RuntimeCode // ---- Interactable section ---- report.interactableBytes = (long)scene.interactables.Length * BytesPerInteractable; - // ---- Collision soup ---- - report.collisionBytes = EstimateCollisionSize(scene.collisionExporter); - // ---- Nav region data ---- report.navRegionBytes = EstimateNavRegionSize(scene.navRegionBuilder);