Broken RUntime
This commit is contained in:
@@ -4,6 +4,7 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
@@ -46,6 +47,7 @@ namespace SplashEdit.EditorCode
|
||||
private bool _hasRedux;
|
||||
private bool _hasNativeProject;
|
||||
private bool _hasPsxavenc;
|
||||
private bool _hasMkpsxiso;
|
||||
private string _reduxVersion = "";
|
||||
|
||||
// ───── Native project installer ─────
|
||||
@@ -486,6 +488,22 @@ namespace SplashEdit.EditorCode
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
// mkpsxiso (ISO builder)
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
DrawStatusIcon(_hasMkpsxiso);
|
||||
GUILayout.Label("mkpsxiso (ISO)", GUILayout.Width(160));
|
||||
GUILayout.FlexibleSpace();
|
||||
if (!_hasMkpsxiso)
|
||||
{
|
||||
if (GUILayout.Button("Download", GUILayout.Width(80)))
|
||||
DownloadMkpsxiso();
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("Installed", EditorStyles.miniLabel);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
// Refresh button
|
||||
EditorGUILayout.Space(2);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
@@ -653,14 +671,11 @@ namespace SplashEdit.EditorCode
|
||||
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
// GTE Scaling
|
||||
EditorGUILayout.LabelField("Export Settings", EditorStyles.boldLabel);
|
||||
SplashSettings.DefaultGTEScaling = EditorGUILayout.FloatField("Default GTE Scaling", SplashSettings.DefaultGTEScaling);
|
||||
SplashSettings.AutoValidateOnExport = EditorGUILayout.Toggle("Auto-Validate on Export", SplashSettings.AutoValidateOnExport);
|
||||
|
||||
EditorGUILayout.Space(6);
|
||||
|
||||
// Open dedicated VRAM windows
|
||||
EditorGUILayout.LabelField("Advanced Tools", EditorStyles.boldLabel);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Open VRAM Editor", GUILayout.Height(24)))
|
||||
@@ -673,11 +688,6 @@ namespace SplashEdit.EditorCode
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button("Open Scene Validator", EditorStyles.miniButton))
|
||||
{
|
||||
PSXSceneValidatorWindow.ShowWindow();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
@@ -711,6 +721,34 @@ namespace SplashEdit.EditorCode
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
// ISO settings (only for ISO build target)
|
||||
if (SplashSettings.Target == BuildTarget.ISO)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Volume Label:", GUILayout.Width(80));
|
||||
SplashSettings.ISOVolumeLabel = EditorGUILayout.TextField(SplashSettings.ISOVolumeLabel);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.Label("License File:", GUILayout.Width(80));
|
||||
string licensePath = SplashSettings.LicenseFilePath;
|
||||
string displayPath = string.IsNullOrEmpty(licensePath) ? "(none — homebrew)" : Path.GetFileName(licensePath);
|
||||
GUILayout.Label(displayPath, EditorStyles.miniLabel, GUILayout.ExpandWidth(true));
|
||||
if (GUILayout.Button("Browse", EditorStyles.miniButton, GUILayout.Width(60)))
|
||||
{
|
||||
string path = EditorUtility.OpenFilePanel(
|
||||
"Select Sony License File", "", "dat");
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
SplashSettings.LicenseFilePath = path;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(licensePath) &&
|
||||
GUILayout.Button("Clear", EditorStyles.miniButton, GUILayout.Width(40)))
|
||||
{
|
||||
SplashSettings.LicenseFilePath = "";
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
|
||||
// Big Build & Run button
|
||||
@@ -759,7 +797,7 @@ namespace SplashEdit.EditorCode
|
||||
}
|
||||
if (GUILayout.Button("Compile Only", EditorStyles.miniButton, GUILayout.Width(100)))
|
||||
{
|
||||
CompileNative();
|
||||
CompileOnly();
|
||||
}
|
||||
GUILayout.FlexibleSpace();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
@@ -774,12 +812,11 @@ namespace SplashEdit.EditorCode
|
||||
/// <summary>
|
||||
/// The main pipeline: Validate → Export all scenes → Compile → Launch.
|
||||
/// </summary>
|
||||
public void BuildAndRun()
|
||||
public async void BuildAndRun()
|
||||
{
|
||||
if (_isBuilding) return;
|
||||
_isBuilding = true;
|
||||
|
||||
// Open the PSX Console so build output is visible immediately
|
||||
var console = EditorWindow.GetWindow<PSXConsoleWindow>();
|
||||
console.titleContent = new GUIContent("PSX Console", EditorGUIUtility.IconContent("d_UnityEditor.ConsoleWindow").image);
|
||||
console.minSize = new Vector2(400, 200);
|
||||
@@ -787,7 +824,6 @@ namespace SplashEdit.EditorCode
|
||||
|
||||
try
|
||||
{
|
||||
// Step 1: Validate
|
||||
Log("Validating toolchain...", LogType.Log);
|
||||
if (!ValidateToolchain())
|
||||
{
|
||||
@@ -796,7 +832,6 @@ namespace SplashEdit.EditorCode
|
||||
}
|
||||
Log("Toolchain OK.", LogType.Log);
|
||||
|
||||
// Step 2: Export all scenes
|
||||
Log("Exporting scenes...", LogType.Log);
|
||||
if (!ExportAllScenes())
|
||||
{
|
||||
@@ -805,16 +840,15 @@ namespace SplashEdit.EditorCode
|
||||
}
|
||||
Log($"Exported {_sceneList.Count} scene(s).", LogType.Log);
|
||||
|
||||
// Step 3: Compile native
|
||||
Log("Compiling native code...", LogType.Log);
|
||||
if (!CompileNative())
|
||||
EditorUtility.DisplayProgressBar("SplashEdit", "Compiling native code...", 0.6f);
|
||||
if (!await CompileNativeAsync())
|
||||
{
|
||||
Log("Compilation failed. Check build log.", LogType.Error);
|
||||
return;
|
||||
}
|
||||
Log("Compile succeeded.", LogType.Log);
|
||||
|
||||
// Step 4: Launch
|
||||
Log("Launching...", LogType.Log);
|
||||
Launch();
|
||||
}
|
||||
@@ -852,6 +886,11 @@ namespace SplashEdit.EditorCode
|
||||
Log("PCSX-Redux not found. Click Download in the Toolchain section.", LogType.Error);
|
||||
return false;
|
||||
}
|
||||
if (SplashSettings.Target == BuildTarget.ISO && !_hasMkpsxiso)
|
||||
{
|
||||
Log("mkpsxiso not found. Click Download in the Toolchain section.", LogType.Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
string nativeDir = SplashBuildPaths.NativeSourceDir;
|
||||
if (string.IsNullOrEmpty(nativeDir) || !Directory.Exists(nativeDir))
|
||||
@@ -902,7 +941,7 @@ namespace SplashEdit.EditorCode
|
||||
EditorSceneManager.OpenScene(scene.path, OpenSceneMode.Single);
|
||||
|
||||
// Find the exporter
|
||||
var exporter = UnityEngine.Object.FindObjectOfType<PSXSceneExporter>();
|
||||
var exporter = UnityEngine.Object.FindFirstObjectByType<PSXSceneExporter>();
|
||||
if (exporter == null)
|
||||
{
|
||||
Log($"Scene '{scene.name}' has no PSXSceneExporter. Skipping.", LogType.Warning);
|
||||
@@ -1051,10 +1090,29 @@ namespace SplashEdit.EditorCode
|
||||
|
||||
// ───── Step 3: Compile ─────
|
||||
|
||||
/// <summary>
|
||||
/// Runs make in the native project directory.
|
||||
/// </summary>
|
||||
public bool CompileNative()
|
||||
private async void CompileOnly()
|
||||
{
|
||||
if (_isBuilding) return;
|
||||
_isBuilding = true;
|
||||
Repaint();
|
||||
try
|
||||
{
|
||||
Log("Compiling native code...", LogType.Log);
|
||||
EditorUtility.DisplayProgressBar("SplashEdit", "Compiling native code...", 0.5f);
|
||||
if (await CompileNativeAsync())
|
||||
Log("Compile succeeded.", LogType.Log);
|
||||
else
|
||||
Log("Compilation failed. Check build log.", LogType.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isBuilding = false;
|
||||
EditorUtility.ClearProgressBar();
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> CompileNativeAsync()
|
||||
{
|
||||
string nativeDir = SplashBuildPaths.NativeSourceDir;
|
||||
if (string.IsNullOrEmpty(nativeDir))
|
||||
@@ -1064,9 +1122,11 @@ namespace SplashEdit.EditorCode
|
||||
}
|
||||
|
||||
string buildArg = SplashSettings.Mode == BuildMode.Debug ? "BUILD=Debug" : "";
|
||||
// Run clean first, THEN build — "make clean all -jN" races clean vs build in sub-makes
|
||||
string makeCmd = $"make clean && make all -j{SystemInfo.processorCount} {buildArg}".Trim();
|
||||
|
||||
if (SplashSettings.Target == BuildTarget.ISO)
|
||||
buildArg += " LOADER=cdrom";
|
||||
|
||||
string makeCmd = $"make clean && make all -j{SystemInfo.processorCount} {buildArg}".Trim();
|
||||
Log($"Running: {makeCmd}", LogType.Log);
|
||||
|
||||
var psi = new ProcessStartInfo
|
||||
@@ -1084,45 +1144,57 @@ namespace SplashEdit.EditorCode
|
||||
|
||||
try
|
||||
{
|
||||
var process = Process.Start(psi);
|
||||
string stdout = process.StandardOutput.ReadToEnd();
|
||||
string stderr = process.StandardError.ReadToEnd();
|
||||
process.WaitForExit();
|
||||
var process = new Process { StartInfo = psi, EnableRaisingEvents = true };
|
||||
var stdoutBuf = new System.Text.StringBuilder();
|
||||
var stderrBuf = new System.Text.StringBuilder();
|
||||
|
||||
// Log output to panel only (no Unity console spam)
|
||||
if (!string.IsNullOrEmpty(stdout))
|
||||
process.OutputDataReceived += (s, e) =>
|
||||
{
|
||||
foreach (string line in stdout.Split('\n'))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(line))
|
||||
LogToPanel(line.Trim(), LogType.Log);
|
||||
}
|
||||
if (e.Data != null) stdoutBuf.AppendLine(e.Data);
|
||||
};
|
||||
process.ErrorDataReceived += (s, e) =>
|
||||
{
|
||||
if (e.Data != null) stderrBuf.AppendLine(e.Data);
|
||||
};
|
||||
|
||||
var tcs = new TaskCompletionSource<int>();
|
||||
process.Exited += (s, e) => tcs.TrySetResult(process.ExitCode);
|
||||
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
int exitCode = await tcs.Task;
|
||||
process.Dispose();
|
||||
|
||||
string stdout = stdoutBuf.ToString();
|
||||
string stderr = stderrBuf.ToString();
|
||||
|
||||
foreach (string line in stdout.Split('\n'))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(line))
|
||||
LogToPanel(line.Trim(), LogType.Log);
|
||||
}
|
||||
|
||||
if (process.ExitCode != 0)
|
||||
if (exitCode != 0)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(stderr))
|
||||
foreach (string line in stderr.Split('\n'))
|
||||
{
|
||||
foreach (string line in stderr.Split('\n'))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(line))
|
||||
LogToPanel(line.Trim(), LogType.Error);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(line))
|
||||
LogToPanel(line.Trim(), LogType.Error);
|
||||
}
|
||||
Log($"Make exited with code {process.ExitCode}", LogType.Error);
|
||||
Log($"Make exited with code {exitCode}", LogType.Error);
|
||||
|
||||
// Write build log file
|
||||
File.WriteAllText(SplashBuildPaths.BuildLogPath,
|
||||
$"=== STDOUT ===\n{stdout}\n=== STDERR ===\n{stderr}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy the compiled exe to PSXBuild/
|
||||
string exeSource = FindCompiledExe(nativeDir);
|
||||
if (!string.IsNullOrEmpty(exeSource))
|
||||
{
|
||||
File.Copy(exeSource, SplashBuildPaths.CompiledExePath, true);
|
||||
Log($"Copied .ps-exe to PSXBuild/", LogType.Log);
|
||||
Log("Copied .ps-exe to PSXBuild/", LogType.Log);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1172,7 +1244,7 @@ namespace SplashEdit.EditorCode
|
||||
LaunchToHardware();
|
||||
break;
|
||||
case BuildTarget.ISO:
|
||||
Log("ISO build not yet implemented.", LogType.Warning);
|
||||
BuildAndLaunchISO();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1274,6 +1346,235 @@ namespace SplashEdit.EditorCode
|
||||
}
|
||||
}
|
||||
|
||||
// ───── ISO Build ─────
|
||||
|
||||
private void BuildAndLaunchISO()
|
||||
{
|
||||
if (!_hasMkpsxiso)
|
||||
{
|
||||
Log("mkpsxiso not installed. Click Download in the Toolchain section.", LogType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string exePath = SplashBuildPaths.CompiledExePath;
|
||||
if (!File.Exists(exePath))
|
||||
{
|
||||
Log("Compiled .ps-exe not found in PSXBuild/.", LogType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ask user for output location
|
||||
string defaultDir = SplashBuildPaths.BuildOutputDir;
|
||||
string savePath = EditorUtility.SaveFilePanel(
|
||||
"Save ISO Image", defaultDir, "psxsplash", "bin");
|
||||
if (string.IsNullOrEmpty(savePath))
|
||||
{
|
||||
Log("ISO build cancelled.", LogType.Log);
|
||||
return;
|
||||
}
|
||||
|
||||
string outputBin = savePath;
|
||||
string outputCue = Path.ChangeExtension(savePath, ".cue");
|
||||
|
||||
// Step 1: Generate SYSTEM.CNF
|
||||
Log("Generating SYSTEM.CNF...", LogType.Log);
|
||||
if (!GenerateSystemCnf())
|
||||
{
|
||||
Log("Failed to generate SYSTEM.CNF.", LogType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: Generate XML catalog for mkpsxiso
|
||||
Log("Generating ISO catalog...", LogType.Log);
|
||||
string xmlPath = GenerateISOCatalog(outputBin, outputCue);
|
||||
if (string.IsNullOrEmpty(xmlPath))
|
||||
{
|
||||
Log("Failed to generate ISO catalog.", LogType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 3: Delete existing .bin/.cue — mkpsxiso won't overwrite them
|
||||
try
|
||||
{
|
||||
if (File.Exists(outputBin)) File.Delete(outputBin);
|
||||
if (File.Exists(outputCue)) File.Delete(outputCue);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"Could not remove old ISO files: {ex.Message}", LogType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 4: Run mkpsxiso
|
||||
Log("Building ISO image...", LogType.Log);
|
||||
bool success = MkpsxisoDownloader.BuildISO(xmlPath, outputBin, outputCue,
|
||||
msg => Log(msg, LogType.Log));
|
||||
|
||||
if (success)
|
||||
{
|
||||
long fileSize = new FileInfo(outputBin).Length;
|
||||
Log($"ISO image written: {outputBin} ({fileSize:N0} bytes)", LogType.Log);
|
||||
Log($"CUE sheet written: {outputCue}", LogType.Log);
|
||||
|
||||
// Offer to reveal in explorer
|
||||
EditorUtility.RevealInFinder(outputBin);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("ISO build failed.", LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Derive the executable name on disc from the volume label.
|
||||
/// Uppercase, no extension, trimmed to 12 characters (ISO9660 limit).
|
||||
/// </summary>
|
||||
private static string GetISOExeName()
|
||||
{
|
||||
string label = SplashSettings.ISOVolumeLabel;
|
||||
if (string.IsNullOrEmpty(label)) label = "PSXSPLASH";
|
||||
|
||||
// Uppercase, strip anything not A-Z / 0-9 / underscore
|
||||
label = label.ToUpperInvariant();
|
||||
var sb = new System.Text.StringBuilder(label.Length);
|
||||
foreach (char c in label)
|
||||
{
|
||||
if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')
|
||||
sb.Append(c);
|
||||
}
|
||||
string name = sb.ToString();
|
||||
if (name.Length == 0) name = "PSXSPLASH";
|
||||
if (name.Length > 12) name = name.Substring(0, 12);
|
||||
return name;
|
||||
}
|
||||
|
||||
private bool GenerateSystemCnf()
|
||||
{
|
||||
try
|
||||
{
|
||||
string cnfPath = SplashBuildPaths.SystemCnfPath;
|
||||
|
||||
// The executable name on disc — no extension, max 12 chars
|
||||
string exeName = GetISOExeName();
|
||||
|
||||
// SYSTEM.CNF content — the BIOS reads this to launch the executable.
|
||||
// BOOT: path to the executable on disc (cdrom:\path;1)
|
||||
// TCB: number of thread control blocks (4 is standard)
|
||||
// EVENT: number of event control blocks (10 is standard)
|
||||
// STACK: initial stack pointer address (top of RAM minus a small margin)
|
||||
string content =
|
||||
$"BOOT = cdrom:\\{exeName};1\r\n" +
|
||||
"TCB = 4\r\n" +
|
||||
"EVENT = 10\r\n" +
|
||||
"STACK = 801FFF00\r\n";
|
||||
|
||||
File.WriteAllText(cnfPath, content, new System.Text.UTF8Encoding(false));
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"SYSTEM.CNF generation error: {ex.Message}", LogType.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the mkpsxiso XML catalog describing the ISO filesystem layout.
|
||||
/// Includes SYSTEM.CNF, the executable, all splashpacks, loading packs, and manifest.
|
||||
/// </summary>
|
||||
private string GenerateISOCatalog(string outputBin, string outputCue)
|
||||
{
|
||||
try
|
||||
{
|
||||
string xmlPath = SplashBuildPaths.ISOCatalogPath;
|
||||
string buildDir = SplashBuildPaths.BuildOutputDir;
|
||||
string volumeLabel = SplashSettings.ISOVolumeLabel;
|
||||
if (string.IsNullOrEmpty(volumeLabel)) volumeLabel = "PSXSPLASH";
|
||||
|
||||
// Sanitize volume label (ISO9660: uppercase, max 31 chars)
|
||||
volumeLabel = volumeLabel.ToUpperInvariant();
|
||||
if (volumeLabel.Length > 31) volumeLabel = volumeLabel.Substring(0, 31);
|
||||
|
||||
var xml = new System.Text.StringBuilder();
|
||||
xml.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
xml.AppendLine("<iso_project image_name=\"psxsplash.bin\" cue_sheet=\"psxsplash.cue\">");
|
||||
xml.AppendLine(" <track type=\"data\">");
|
||||
xml.AppendLine(" <identifiers");
|
||||
xml.AppendLine(" system=\"PLAYSTATION\"");
|
||||
xml.AppendLine(" application=\"PLAYSTATION\"");
|
||||
xml.AppendLine($" volume=\"{EscapeXml(volumeLabel)}\"");
|
||||
xml.AppendLine($" volume_set=\"{EscapeXml(volumeLabel)}\"");
|
||||
xml.AppendLine(" publisher=\"SPLASHEDIT\"");
|
||||
xml.AppendLine(" data_preparer=\"MKPSXISO\"");
|
||||
xml.AppendLine(" />");
|
||||
|
||||
// License file (optional)
|
||||
string licensePath = SplashSettings.LicenseFilePath;
|
||||
if (!string.IsNullOrEmpty(licensePath) && File.Exists(licensePath))
|
||||
{
|
||||
xml.AppendLine($" <license file=\"{EscapeXml(licensePath)}\"/>");
|
||||
}
|
||||
|
||||
xml.AppendLine(" <directory_tree>");
|
||||
|
||||
// SYSTEM.CNF — must be first for BIOS to find it
|
||||
string cnfPath = SplashBuildPaths.SystemCnfPath;
|
||||
xml.AppendLine($" <file name=\"SYSTEM.CNF\" source=\"{EscapeXml(cnfPath)}\"/>");
|
||||
|
||||
// The executable — renamed to match what SYSTEM.CNF points to
|
||||
string exePath = SplashBuildPaths.CompiledExePath;
|
||||
string isoExeName = GetISOExeName();
|
||||
xml.AppendLine($" <file name=\"{isoExeName}\" source=\"{EscapeXml(exePath)}\"/>");
|
||||
|
||||
// Manifest
|
||||
string manifestPath = SplashBuildPaths.ManifestPath;
|
||||
if (File.Exists(manifestPath))
|
||||
{
|
||||
xml.AppendLine($" <file name=\"MANIFEST.BIN\" source=\"{EscapeXml(manifestPath)}\"/>");
|
||||
}
|
||||
|
||||
// Scene splashpacks and loading packs
|
||||
for (int i = 0; i < _sceneList.Count; i++)
|
||||
{
|
||||
string splashpack = SplashBuildPaths.GetSceneSplashpackPath(i, _sceneList[i].name);
|
||||
if (File.Exists(splashpack))
|
||||
{
|
||||
string isoName = $"SCENE_{i}.SPK";
|
||||
xml.AppendLine($" <file name=\"{isoName}\" source=\"{EscapeXml(splashpack)}\"/>");
|
||||
}
|
||||
|
||||
string loadingPack = SplashBuildPaths.GetSceneLoaderPackPath(i, _sceneList[i].name);
|
||||
if (File.Exists(loadingPack))
|
||||
{
|
||||
string isoName = $"SCENE_{i}.LDG";
|
||||
xml.AppendLine($" <file name=\"{isoName}\" source=\"{EscapeXml(loadingPack)}\"/>");
|
||||
}
|
||||
}
|
||||
|
||||
// Trailing dummy sectors to prevent drive runaway
|
||||
xml.AppendLine(" <dummy sectors=\"128\"/>");
|
||||
xml.AppendLine(" </directory_tree>");
|
||||
xml.AppendLine(" </track>");
|
||||
xml.AppendLine("</iso_project>");
|
||||
|
||||
File.WriteAllText(xmlPath, xml.ToString(), new System.Text.UTF8Encoding(false));
|
||||
Log($"ISO catalog written: {xmlPath}", LogType.Log);
|
||||
return xmlPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"ISO catalog generation error: {ex.Message}", LogType.Error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static string EscapeXml(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s)) return "";
|
||||
return s.Replace("&", "&").Replace("<", "<")
|
||||
.Replace(">", ">").Replace("\"", """);
|
||||
}
|
||||
|
||||
private void StopPCdrvHost()
|
||||
{
|
||||
if (_pcdrvHost != null)
|
||||
@@ -1339,6 +1640,8 @@ namespace SplashEdit.EditorCode
|
||||
|
||||
_hasPsxavenc = PSXAudioConverter.IsInstalled();
|
||||
|
||||
_hasMkpsxiso = MkpsxisoDownloader.IsInstalled();
|
||||
|
||||
string nativeDir = SplashBuildPaths.NativeSourceDir;
|
||||
_hasNativeProject = !string.IsNullOrEmpty(nativeDir) && Directory.Exists(nativeDir);
|
||||
}
|
||||
@@ -1418,6 +1721,22 @@ namespace SplashEdit.EditorCode
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private async void DownloadMkpsxiso()
|
||||
{
|
||||
Log("Downloading mkpsxiso ISO builder...", LogType.Log);
|
||||
bool success = await MkpsxisoDownloader.DownloadAndInstall(msg => Log(msg, LogType.Log));
|
||||
if (success)
|
||||
{
|
||||
RefreshToolchainStatus();
|
||||
Log("mkpsxiso ready!", LogType.Log);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("mkpsxiso download failed. ISO builds will not work.", LogType.Error);
|
||||
}
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void ScanSerialPorts()
|
||||
{
|
||||
try
|
||||
|
||||
Reference in New Issue
Block a user