From 376dc4afaa217ebe4a233f9bea1032b03fd97c7e Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Tue, 10 Sep 2024 06:25:03 -0700 Subject: [PATCH] chore: update ffi task interface --- Assets/Rivet/Editor/Native/cli.meta | 8 - .../Editor/Native/cli/rivet-aarch64-apple | 3 - .../Native/cli/rivet-aarch64-apple.meta | 7 - Assets/Rivet/Editor/Native/cli/rivet-linux | 3 - .../Rivet/Editor/Native/cli/rivet-linux.meta | 7 - .../Rivet/Editor/Native/cli/rivet-windows.exe | 3 - .../Editor/Native/cli/rivet-windows.exe.meta | 7 - .../Rivet/Editor/Native/cli/rivet-x86-apple | 3 - .../Editor/Native/cli/rivet-x86-apple.meta | 7 - .../Native/librivet_toolchain_ffi.dylib | 3 - .../Native/librivet_toolchain_ffi.dylib.meta | 27 -- .../librivet_toolchain_ffi_linux_x86_64.so | 3 - .../librivet_toolchain_ffi_macos_arm64.dylib | 4 +- .../librivet_toolchain_ffi_macos_x86_64.dylib | 3 - ...ivet_toolchain_ffi_macos_x86_64.dylib.meta | 63 ---- Assets/Rivet/Editor/RivetToolchain.cs | 50 ++- Assets/Rivet/Editor/Task.cs | 357 +++++------------- Assets/Rivet/Editor/TaskManager.cs | 2 +- .../Rivet/Editor/UI/Tabs/DevelopController.cs | 12 +- .../Editor/UI/Tabs/SettingsController.cs | 18 +- .../Editor/UI/TaskPopup/TaskPopupWindow.cs | 4 +- backend.json | 2 +- deno.lock | 219 +++++++++++ scripts/build_dev.ts | 56 +++ scripts/copy_native_dev.sh | 13 - scripts/run_dev.ts | 65 ++++ 26 files changed, 479 insertions(+), 470 deletions(-) delete mode 100644 Assets/Rivet/Editor/Native/cli.meta delete mode 100755 Assets/Rivet/Editor/Native/cli/rivet-aarch64-apple delete mode 100644 Assets/Rivet/Editor/Native/cli/rivet-aarch64-apple.meta delete mode 100755 Assets/Rivet/Editor/Native/cli/rivet-linux delete mode 100644 Assets/Rivet/Editor/Native/cli/rivet-linux.meta delete mode 100755 Assets/Rivet/Editor/Native/cli/rivet-windows.exe delete mode 100644 Assets/Rivet/Editor/Native/cli/rivet-windows.exe.meta delete mode 100755 Assets/Rivet/Editor/Native/cli/rivet-x86-apple delete mode 100644 Assets/Rivet/Editor/Native/cli/rivet-x86-apple.meta delete mode 100755 Assets/Rivet/Editor/Native/librivet_toolchain_ffi.dylib delete mode 100644 Assets/Rivet/Editor/Native/librivet_toolchain_ffi.dylib.meta delete mode 100755 Assets/Rivet/Editor/Native/librivet_toolchain_ffi_linux_x86_64.so delete mode 100755 Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_x86_64.dylib delete mode 100644 Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_x86_64.dylib.meta create mode 100755 scripts/build_dev.ts delete mode 100755 scripts/copy_native_dev.sh create mode 100755 scripts/run_dev.ts diff --git a/Assets/Rivet/Editor/Native/cli.meta b/Assets/Rivet/Editor/Native/cli.meta deleted file mode 100644 index 84cc968..0000000 --- a/Assets/Rivet/Editor/Native/cli.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: dc26f57ca54624f7c85b59ad2711ed7d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Rivet/Editor/Native/cli/rivet-aarch64-apple b/Assets/Rivet/Editor/Native/cli/rivet-aarch64-apple deleted file mode 100755 index c9bca70..0000000 --- a/Assets/Rivet/Editor/Native/cli/rivet-aarch64-apple +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6b875ac82c2313512f1079dd157259c7dfd3a403e8535db8e608a6c1f78e8e4b -size 9125587 diff --git a/Assets/Rivet/Editor/Native/cli/rivet-aarch64-apple.meta b/Assets/Rivet/Editor/Native/cli/rivet-aarch64-apple.meta deleted file mode 100644 index cdaa431..0000000 --- a/Assets/Rivet/Editor/Native/cli/rivet-aarch64-apple.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 45835e4887751469cb985633e8f1b4aa -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Rivet/Editor/Native/cli/rivet-linux b/Assets/Rivet/Editor/Native/cli/rivet-linux deleted file mode 100755 index 8d8c4fe..0000000 --- a/Assets/Rivet/Editor/Native/cli/rivet-linux +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ddb4ce6379580d298fe915a241a0219c8351404c3e5959bf643ce5afc08431be -size 15883728 diff --git a/Assets/Rivet/Editor/Native/cli/rivet-linux.meta b/Assets/Rivet/Editor/Native/cli/rivet-linux.meta deleted file mode 100644 index 6cbe4ad..0000000 --- a/Assets/Rivet/Editor/Native/cli/rivet-linux.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 5c95a1ee6c4534a5998b8a10a43c5bb3 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Rivet/Editor/Native/cli/rivet-windows.exe b/Assets/Rivet/Editor/Native/cli/rivet-windows.exe deleted file mode 100755 index ffc83be..0000000 --- a/Assets/Rivet/Editor/Native/cli/rivet-windows.exe +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:84399a751761c49884f274062da1d72380a5b7f66ac4f6397bee3f317133b715 -size 18604650 diff --git a/Assets/Rivet/Editor/Native/cli/rivet-windows.exe.meta b/Assets/Rivet/Editor/Native/cli/rivet-windows.exe.meta deleted file mode 100644 index 6cccf7b..0000000 --- a/Assets/Rivet/Editor/Native/cli/rivet-windows.exe.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 8361253527e2040ba973981af3d6f432 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Rivet/Editor/Native/cli/rivet-x86-apple b/Assets/Rivet/Editor/Native/cli/rivet-x86-apple deleted file mode 100755 index 91d1e2d..0000000 --- a/Assets/Rivet/Editor/Native/cli/rivet-x86-apple +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0dfd7c5d011fabe83f9a10ddc45fc071ffff67e056834aba1ea71701135aec44 -size 9713832 diff --git a/Assets/Rivet/Editor/Native/cli/rivet-x86-apple.meta b/Assets/Rivet/Editor/Native/cli/rivet-x86-apple.meta deleted file mode 100644 index a1febe5..0000000 --- a/Assets/Rivet/Editor/Native/cli/rivet-x86-apple.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: e3042bd0427e8485bbbd4079aeb70994 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Rivet/Editor/Native/librivet_toolchain_ffi.dylib b/Assets/Rivet/Editor/Native/librivet_toolchain_ffi.dylib deleted file mode 100755 index b393072..0000000 --- a/Assets/Rivet/Editor/Native/librivet_toolchain_ffi.dylib +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0789eb2e1f75dba3b212b5cee1e4632a520bb0ea3500fd5d73120063d1055f00 -size 24814704 diff --git a/Assets/Rivet/Editor/Native/librivet_toolchain_ffi.dylib.meta b/Assets/Rivet/Editor/Native/librivet_toolchain_ffi.dylib.meta deleted file mode 100644 index 0103483..0000000 --- a/Assets/Rivet/Editor/Native/librivet_toolchain_ffi.dylib.meta +++ /dev/null @@ -1,27 +0,0 @@ -fileFormatVersion: 2 -guid: eb6d30b377e914570944f966faf712b4 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 1 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_linux_x86_64.so b/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_linux_x86_64.so deleted file mode 100755 index 02c6508..0000000 --- a/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_linux_x86_64.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cc907e19944bf5c05c749c407b456d5c6342d2fdb676338b2b319320212c49ab -size 15191104 diff --git a/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_arm64.dylib b/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_arm64.dylib index 9d9889c..90035a2 100755 --- a/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_arm64.dylib +++ b/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_arm64.dylib @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7130f91527572984c3d1e7f83bb152539e0f189a3b10fd80088fc00f0fce32d7 -size 8358601 +oid sha256:d588e458af847b8e3763925eb27f76cce5dee520072a34c71560e9ec129827bd +size 120593104 diff --git a/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_x86_64.dylib b/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_x86_64.dylib deleted file mode 100755 index c95490b..0000000 --- a/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_x86_64.dylib +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:be9992964c83b2528c6824ede25352c1a126163c843dfff19af511e43af2a8a3 -size 8888568 diff --git a/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_x86_64.dylib.meta b/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_x86_64.dylib.meta deleted file mode 100644 index 0769c29..0000000 --- a/Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_x86_64.dylib.meta +++ /dev/null @@ -1,63 +0,0 @@ -fileFormatVersion: 2 -guid: 2addda22ef32f42cb9760067b9dedc63 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 1 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Editor: 0 - Exclude Linux64: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 1 - settings: - CPU: x86_64 - DefaultValueInitialized: true - OS: OSX - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: AnyCPU - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Rivet/Editor/RivetToolchain.cs b/Assets/Rivet/Editor/RivetToolchain.cs index e4a91a0..dcb065a 100644 --- a/Assets/Rivet/Editor/RivetToolchain.cs +++ b/Assets/Rivet/Editor/RivetToolchain.cs @@ -1,39 +1,51 @@ -// namespace Rivet.Editor -// { -// public static class RivetToolchain -// { -// public const string NativeLib = "rivet_toolchain"; - -// [DIlImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "run_task")] -// public static extern uint run_task(); -// } -// } - using System; +using System.Diagnostics; using System.Runtime.InteropServices; namespace Rivet.Editor { - public class RivetToolchain + public static class RivetToolchain { const string RustLibrary = "__Internal"; + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void EventCallback(ulong taskId, IntPtr eventJson); [DllImport(RustLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "run_task")] - private static extern IntPtr run_task( - [MarshalAs(UnmanagedType.LPStr)] string run_config, + private static extern ulong run_task( [MarshalAs(UnmanagedType.LPStr)] string name, - [MarshalAs(UnmanagedType.LPStr)] string input_json + [MarshalAs(UnmanagedType.LPStr)] string inputJson, + EventCallback callback ); + [DllImport(RustLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "abort_task")] + private static extern bool abort_task(ulong taskId); + + [DllImport(RustLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "shutdown")] + private static extern void shutdown(); + [DllImport(RustLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "free_rust_string")] private static extern void free_rust_string(IntPtr str); - public static string RunTaskRaw(string runConfig, string name, string inputJson) + public static ulong RunTask(string name, string inputJson, EventCallback callback) + { + return run_task(name, inputJson, callback); + } + + public static bool AbortTask(ulong taskId) + { + return abort_task(taskId); + } + + public static void Shutdown() + { + shutdown(); + } + + public static string PtrToString(IntPtr ptr) { - IntPtr resultPtr = run_task(runConfig, name, inputJson); - string result = Marshal.PtrToStringAnsi(resultPtr); - free_rust_string(resultPtr); + string result = Marshal.PtrToStringAnsi(ptr); + free_rust_string(ptr); return result; } } diff --git a/Assets/Rivet/Editor/Task.cs b/Assets/Rivet/Editor/Task.cs index dcc98b7..3451c7c 100644 --- a/Assets/Rivet/Editor/Task.cs +++ b/Assets/Rivet/Editor/Task.cs @@ -1,13 +1,8 @@ using UnityEngine; using System; -using System.IO; -using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using System.Collections.Generic; -using System.Diagnostics; -using Unity.VisualScripting; +using UnityEditor; namespace Rivet.Editor { @@ -15,335 +10,157 @@ public class RivetTask : IDisposable { public enum LogType { STDOUT, STDERR } - private const float POLL_LOGS_INTERVAL = 0.25f; + // Events + public event Action TaskLog; + public event Action TaskOk; + public event Action TaskError; + public event Action TaskOutput; // Config private string _name; private JObject _input; // State - public bool IsRunning { get; private set; } = false; - public bool IsFinished { get; private set; } = false; - private StateFiles _stateFiles; - private CancellationTokenSource _cts; - private FileStream _logFileStream; - private long _logLastPosition; - private bool _disposed = false; - - public delegate void LogHandler(string message, LogType type); - public event LogHandler OnLog; - - private class StateFiles - { - public string BasePath; - public string AbortPath; - public string OutputPath; - } + public bool IsRunning { get; private set; } = true; + public bool IsKilled { get; private set; } = false; + private JObject _logResult; + private ulong _taskId; public RivetTask(string name, JObject input) { if (string.IsNullOrEmpty(name) || input == null) { - throw new ArgumentException("RivetTask initiated without required args"); + RivetLogger.Error("RivetTask initiated without required args"); + return; } _name = name; _input = input; - _stateFiles = GenerateStateFilesDir(); - } - - public async Task> RunAsync(CancellationToken cancellationToken = default) - { - if (IsRunning) - { - throw new InvalidOperationException("Task is already running"); - } - - IsRunning = true; - _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - try - { - var runConfig = new JObject - { - ["abort_path"] = _stateFiles.AbortPath, - ["output_path"] = _stateFiles.OutputPath, - }; - - RivetLogger.Log($"Task {_name} Request: {_input.ToString(Formatting.None)}"); - - var logPollingTask = StartLogPolling(_cts.Token); - var result = await Task.Run(() => RunTask(_name, _input, runConfig), _cts.Token); - IsRunning = false; - IsFinished = true; + var inputJson = _input.ToString(Newtonsoft.Json.Formatting.None); - // Read end of logs immediately. Log polling task will cancel - // itself. - await Task.Run(() => ReadLogTail()); + RivetLogger.Log($"[{_name}] Request: {inputJson}"); + Task.Run(() => Run(name, inputJson)); + } - return result; - } - finally - { - IsRunning = false; - IsFinished = true; - FinishLogs(); - Dispose(); // Self-dispose after the task is complete - } + private void Run(string name, string inputJson) + { + _taskId = RivetToolchain.RunTask(name, inputJson, OnOutputEvent); + RivetLogger.Log($"task id {_taskId}"); } - private async Task StartLogPolling(CancellationToken cancellationToken) + private void OnOutputEvent(ulong taskId, IntPtr eventJsonPtr) { - while (!cancellationToken.IsCancellationRequested && IsRunning) - { - ReadLogTail(); - await Task.Delay(TimeSpan.FromSeconds(POLL_LOGS_INTERVAL), cancellationToken); - } + string eventJson = RivetToolchain.PtrToString(eventJsonPtr); + RivetLogger.Log($"received event {eventJson}"); + EditorApplication.delayCall += () => HandleOnOutputEvent(eventJson); } - private Result RunTask(string name, JObject input, JObject runConfig) + private void HandleOnOutputEvent(string eventJson) { - try + RivetLogger.Log($"output event {_taskId}"); + var eventObj = JObject.Parse(eventJson); + if (eventObj.ContainsKey("log")) { - var outputRaw = RivetToolchain.RunTaskRaw(runConfig.ToString(Formatting.None), name, input.ToString(Formatting.None)); - var output = JObject.Parse(outputRaw); - if (output.GetValue("Ok")?.Value() is { } okInner) - { - RivetLogger.Log($"Task {name} Success: {okInner.ToString(Formatting.None)}"); - return new ResultOk(okInner); - } - else if (output.GetValue("Err") is { } errInner) - { - RivetLogger.Log($"Task {name} Err: {errInner}"); - return new ResultErr(errInner.ToString(Formatting.None)); - } - else - { - throw new Exception("unreachable"); - } + OnLogEvent(eventObj); } - catch (Exception error) + else if (eventObj.ContainsKey("result")) { - UnityEngine.Debug.LogError($"Error running task: {error}"); - return new ResultErr(error.ToString()); + _logResult = eventObj["result"] as JObject; + OnFinish(); + } + else if (eventObj.ContainsKey("set_backend_port")) + { + var port = eventObj["set_backend_port"]["port"].Value(); + // TODO: + // Assuming you have a similar configuration saving mechanism + // RivetPluginBridge.Instance.LocalBackendPort = port; + // RivetPluginBridge.Instance.SaveConfiguration(); + RivetLogger.Log($"Set backend port {port}"); + } + else + { + RivetLogger.Warning($"Unknown event {eventJson}"); } } - // private Result RunTask(string name, JObject input, JObject runConfig) - // { - // var output = RunRivetCLI("task", "run", "--run-config", runConfig.ToString(Formatting.None), "--name", name, "--input", input.ToString(Formatting.None)); - // switch (output) - // { - // case ResultOk ok: - // if (ok.Data.GetValue("Ok")?.Value() is { } okInner) - // { - // RivetLogger.Log($"Task {name} Success: {okInner.ToString(Formatting.None)}"); - // return new ResultOk(okInner); - // } - // else if (ok.Data.GetValue("Err") is { } errInner) - // { - // RivetLogger.Log($"Task {name} Err: {errInner}"); - // return new ResultErr(errInner.ToString(Formatting.None)); - // } - // else - // { - // throw new Exception("unreachable"); - // } - // case ResultErr err: - // RivetLogger.Log($"Task {name} Command Err: {err.Message}"); - // return err; - // default: - // throw new Exception("unreachable"); - // } - // } + private void OnLogEvent(JObject eventObj) + { + TaskLog?.Invoke(eventObj["log"].ToString(), LogType.STDOUT); + } - // TODO: Remove this - public static string GetRivetCLIPath() + private void OnFinish() { - if (Application.platform == RuntimePlatform.WindowsEditor) + IsRunning = false; + + JObject outputResult = null; + if (IsKilled) { - return "Assets/Rivet/Editor/Native/cli/rivet-windows.exe"; + outputResult = new JObject { ["Err"] = "Task killed" }; } - else if (Application.platform == RuntimePlatform.OSXEditor) + else { - if (SystemInfo.processorType.Contains("Apple")) + if (_logResult == null) { - return "Assets/Rivet/Editor/Native/cli/rivet-aarch64-apple"; - } - else - { - return "Assets/Rivet/Editor/Native/cli/rivet-x86-apple"; + RivetLogger.Error("Received no output from task"); + TaskError?.Invoke("Received no output from task"); + return; } + + outputResult = _logResult; } - else if (Application.platform == RuntimePlatform.LinuxEditor) + + TaskOutput?.Invoke(outputResult); + if (outputResult.ContainsKey("Ok")) { - return "Assets/Rivet/Editor/Native/cli/rivet-linux"; + RivetLogger.Log($"[{_name}] Success: {outputResult["Ok"]}"); + TaskOk?.Invoke(outputResult["Ok"] as JObject); } else { - throw new Exception("Unsupported platform"); + RivetLogger.Error($"[{_name}] Error: {outputResult["Err"]}"); + TaskError?.Invoke(outputResult["Err"].ToString()); } } - // private static Result RunRivetCLI(params string[] args) - // { - // // TODO: Turn this on if debug is enabled - // RivetLogger.Log($"Running Rivet CLI: {GetRivetCLIPath()} {string.Join(" ", args)}"); - - // if (!File.Exists(GetRivetCLIPath())) - // { - // return new ResultErr("File does not exist: " + GetRivetCLIPath()); - // } - - // var startInfo = new ProcessStartInfo - // { - // FileName = GetRivetCLIPath(), - // RedirectStandardOutput = true, - // RedirectStandardError = true, - // UseShellExecute = false, - // CreateNoWindow = true, - // }; - // foreach (var arg in args) { - // startInfo.ArgumentList.Add(arg); - // } - - // try - // { - // using var process = Process.Start(startInfo); - // var stdout = process.StandardOutput.ReadToEnd(); - // var stderr = process.StandardError.ReadToEnd(); - // process.WaitForExit(); - - // RivetLogger.Log($"Process output:\n\n{stdout}\n\n{stderr}"); - - // if (process.ExitCode == 0) - // { - // return new ResultOk(JObject.Parse(stdout)); - // } - // else - // { - // return new ResultErr($"Process failed with exit code {process.ExitCode}\n\nstdout:\n{stdout}\n\nstderr:\n{stderr}"); - // } - // } - // catch (System.Exception ex) - // { - // return new ResultErr("Failed to start process: " + ex.Message); - // } - - // } - - public void Kill() + public async Task> RunAsync() { - if (!IsRunning) return; + var tcs = new TaskCompletionSource>(); - RivetLogger.Log("Aborting process"); - File.Create(_stateFiles.AbortPath).Dispose(); - _cts?.Cancel(); - } - - private StateFiles GenerateStateFilesDir() - { - var tempBaseDir = Path.Combine(Application.temporaryCachePath, "tmp"); - var uniqueId = DateTime.Now.Ticks; - var tempDirPath = Path.Combine(tempBaseDir, $"task_{_name}_{uniqueId}"); + TaskOk += (result) => tcs.TrySetResult(new ResultOk(result)); + TaskError += (error) => tcs.TrySetResult(new ResultErr(error)); try { - Directory.CreateDirectory(tempDirPath); - var tempAbortPath = Path.Combine(tempDirPath, "abort"); - var tempOutputPath = Path.Combine(tempDirPath, "output"); - File.Create(tempOutputPath).Dispose(); - - return new StateFiles - { - BasePath = tempDirPath, - AbortPath = tempAbortPath, - OutputPath = tempOutputPath - }; + return await tcs.Task; } - catch (Exception e) + finally { - RivetLogger.Error($"Failed to create temporary directory: {e.Message}"); - return null; + Dispose(); } } - private string StripAnsiCodes(string input) + public void Kill() { - return System.Text.RegularExpressions.Regex.Replace(input, @"\x1b\[[0-9;]*m", string.Empty); - } + if (!IsRunning || IsKilled) + return; - private void ReadLogTail() - { - if (_logFileStream == null) + IsKilled = true; + + if (_taskId != 0) { - _logFileStream = new FileStream(_stateFiles.OutputPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + RivetLogger.Log("Killing task"); + RivetToolchain.AbortTask(_taskId); } - - long currentPosition = _logFileStream.Length; - if (currentPosition > _logLastPosition) + else { - _logFileStream.Seek(_logLastPosition, SeekOrigin.Begin); - byte[] buffer = new byte[currentPosition - _logLastPosition]; - _logFileStream.Read(buffer, 0, buffer.Length); - _logLastPosition = currentPosition; - - string newContent = System.Text.Encoding.UTF8.GetString(buffer); - string[] lines = newContent.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); - - foreach (var line in lines) - { - try - { - var parsed = JsonConvert.DeserializeObject>(line); - if (parsed.ContainsKey("Stdout")) - { - OnLog?.Invoke(StripAnsiCodes(parsed["Stdout"]), LogType.STDOUT); - } - else if (parsed.ContainsKey("Stderr")) - { - OnLog?.Invoke(StripAnsiCodes(parsed["Stderr"]), LogType.STDERR); - } - } - catch (JsonException) - { - RivetLogger.Error($"Failed to parse: {line}"); - } - } + RivetLogger.Warning("No task handle"); } } - private void FinishLogs() - { - _logFileStream?.Dispose(); - _logFileStream = null; - } - public void Dispose() { - if (_disposed) return; - _cts?.Dispose(); - _logFileStream?.Dispose(); - CleanupTempFiles(); - _disposed = true; - } - - private void CleanupTempFiles() - { - if (_stateFiles == null) return; - try - { - if (File.Exists(_stateFiles.AbortPath)) - File.Delete(_stateFiles.AbortPath); - if (File.Exists(_stateFiles.OutputPath)) - File.Delete(_stateFiles.OutputPath); - if (Directory.Exists(_stateFiles.BasePath)) - Directory.Delete(_stateFiles.BasePath, true); - } - catch (IOException ex) - { - RivetLogger.Error($"Error cleaning up temporary files: {ex.Message}"); - } + Kill(); } } } diff --git a/Assets/Rivet/Editor/TaskManager.cs b/Assets/Rivet/Editor/TaskManager.cs index 019f8dd..38a3399 100644 --- a/Assets/Rivet/Editor/TaskManager.cs +++ b/Assets/Rivet/Editor/TaskManager.cs @@ -90,7 +90,7 @@ public async Task StartTask(bool restart = true) { _task = new RivetTask(config.Value.Name, config.Value.Input); _taskStopping = false; - _task.OnLog += OnTaskLog; + _task.TaskLog += OnTaskLog; OnStateChange(); } diff --git a/Assets/Rivet/Editor/UI/Tabs/DevelopController.cs b/Assets/Rivet/Editor/UI/Tabs/DevelopController.cs index 65fbc99..14d2e8f 100644 --- a/Assets/Rivet/Editor/UI/Tabs/DevelopController.cs +++ b/Assets/Rivet/Editor/UI/Tabs/DevelopController.cs @@ -155,12 +155,12 @@ private void OnLocalGameServerStart() // _ = _pluginWindow.LocalGameServerManager.StartTask(); - _ = new RivetTask("show_term", new JObject - { - ["command"] = _pluginWindow.LocalGameServerExecutablePath, - // ["args"] = new JArray { "-batchmode", "-nographics", "-logFile", logPath, "-server" }, - ["args"] = new JArray { "-batchmode", "-nographics", "-server" }, - }).RunAsync(); + // _ = new RivetTask("show_term", new JObject + // { + // ["command"] = _pluginWindow.LocalGameServerExecutablePath, + // // ["args"] = new JArray { "-batchmode", "-nographics", "-logFile", logPath, "-server" }, + // ["args"] = new JArray { "-batchmode", "-nographics", "-server" }, + // }).RunAsync(); } private void OnPlayerStart() diff --git a/Assets/Rivet/Editor/UI/Tabs/SettingsController.cs b/Assets/Rivet/Editor/UI/Tabs/SettingsController.cs index ae52685..e45d584 100644 --- a/Assets/Rivet/Editor/UI/Tabs/SettingsController.cs +++ b/Assets/Rivet/Editor/UI/Tabs/SettingsController.cs @@ -92,15 +92,15 @@ private async Task OnStartBackend() return; } - var input = new JObject { - ["port"] = port, - ["cwd"] = Builder.ProjectRoot() - }; - await new RivetTask("show_term", new JObject - { - ["command"] = RivetTask.GetRivetCLIPath(), - ["args"] = new JArray { "task", "run", "--run-config", "{}", "--name", "backend_dev", "--input", input.ToString(Formatting.None) }, - }).RunAsync(); + // var input = new JObject { + // ["port"] = port, + // ["cwd"] = Builder.ProjectRoot() + // }; + // await new RivetTask("show_term", new JObject + // { + // ["command"] = RivetTask.GetRivetCLIPath(), + // ["args"] = new JArray { "task", "run", "--run-config", "{}", "--name", "backend_dev", "--input", input.ToString(Formatting.None) }, + // }).RunAsync(); } private async Task OnUnlinkGame() diff --git a/Assets/Rivet/Editor/UI/TaskPopup/TaskPopupWindow.cs b/Assets/Rivet/Editor/UI/TaskPopup/TaskPopupWindow.cs index 126b3ab..de1513f 100644 --- a/Assets/Rivet/Editor/UI/TaskPopup/TaskPopupWindow.cs +++ b/Assets/Rivet/Editor/UI/TaskPopup/TaskPopupWindow.cs @@ -111,7 +111,7 @@ public void CreateGUI() private async void InitializeAndStartTask() { _task = new RivetTask(TaskName, TaskInput); - _task.OnLog += OnTaskLog; + _task.TaskLog += OnTaskLog; AddLogLine("Starting task...", LogType.META); EditorApplication.delayCall += () => UpdateUI(); @@ -130,7 +130,7 @@ private async void InitializeAndStartTask() private void UpdateUI() { - bool running = _task != null && !_task.IsFinished; + bool running = _task != null && _task.IsRunning; _doneButton.text = running ? "Cancel" : "Close"; } diff --git a/backend.json b/backend.json index cc78679..ca8f6fb 100644 --- a/backend.json +++ b/backend.json @@ -13,7 +13,7 @@ "config": { "lobbies": { "regions": [ - "atl" + "lax" ], "backend": { "server": { diff --git a/deno.lock b/deno.lock index f7b7571..26a9da9 100644 --- a/deno.lock +++ b/deno.lock @@ -2,12 +2,43 @@ "version": "3", "packages": { "specifiers": { + "jsr:@std/fs": "jsr:@std/fs@1.0.3", + "jsr:@std/path": "jsr:@std/path@1.0.4", + "jsr:@std/path@^1.0.4": "jsr:@std/path@1.0.4", "npm:@prisma/adapter-pg@^5.12.0": "npm:@prisma/adapter-pg@5.17.0_pg@8.12.0", + "npm:@types/node": "npm:@types/node@18.16.19", + "npm:glob": "npm:glob@11.0.0", "npm:pg@^8.11.3": "npm:pg@8.12.0", "npm:zod-validation-error@3.3.0": "npm:zod-validation-error@3.3.0_zod@3.23.8", "npm:zod@3.23.8": "npm:zod@3.23.8" }, + "jsr": { + "@std/fs@1.0.3": { + "integrity": "3cb839b1360b0a42d8b367c3093bfe4071798e6694fa44cf1963e04a8edba4fe", + "dependencies": [ + "jsr:@std/path@^1.0.4" + ] + }, + "@std/path@1.0.4": { + "integrity": "48dd5d8389bcfcd619338a01bdf862cb7799933390146a54ae59356a0acc7105" + } + }, "npm": { + "@isaacs/cliui@8.0.2": { + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "string-width@5.1.2", + "string-width-cjs": "string-width@4.2.3", + "strip-ansi": "strip-ansi@7.1.0", + "strip-ansi-cjs": "strip-ansi@6.0.1", + "wrap-ansi": "wrap-ansi@8.1.0", + "wrap-ansi-cjs": "wrap-ansi@7.0.0" + } + }, + "@pkgjs/parseargs@0.11.0": { + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dependencies": {} + }, "@prisma/adapter-pg@5.17.0_pg@8.12.0": { "integrity": "sha512-ZMHVGOxftEZEbIzQ8gEGQBnK5MxBwKuLcoLZ/hpYA//csVxQhsnBoi2iGYOMcSv6gD6y7k6FroAESk9KzRiMtw==", "dependencies": { @@ -26,6 +57,130 @@ "@prisma/debug": "@prisma/debug@5.17.0" } }, + "@types/node@18.16.19": { + "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==", + "dependencies": {} + }, + "ansi-regex@5.0.1": { + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dependencies": {} + }, + "ansi-regex@6.0.1": { + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dependencies": {} + }, + "ansi-styles@4.3.0": { + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "color-convert@2.0.1" + } + }, + "ansi-styles@6.2.1": { + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dependencies": {} + }, + "balanced-match@1.0.2": { + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dependencies": {} + }, + "brace-expansion@2.0.1": { + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "balanced-match@1.0.2" + } + }, + "color-convert@2.0.1": { + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "color-name@1.1.4" + } + }, + "color-name@1.1.4": { + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dependencies": {} + }, + "cross-spawn@7.0.3": { + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "path-key@3.1.1", + "shebang-command": "shebang-command@2.0.0", + "which": "which@2.0.2" + } + }, + "eastasianwidth@0.2.0": { + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dependencies": {} + }, + "emoji-regex@8.0.0": { + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dependencies": {} + }, + "emoji-regex@9.2.2": { + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dependencies": {} + }, + "foreground-child@3.3.0": { + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dependencies": { + "cross-spawn": "cross-spawn@7.0.3", + "signal-exit": "signal-exit@4.1.0" + } + }, + "glob@11.0.0": { + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", + "dependencies": { + "foreground-child": "foreground-child@3.3.0", + "jackspeak": "jackspeak@4.0.1", + "minimatch": "minimatch@10.0.1", + "minipass": "minipass@7.1.2", + "package-json-from-dist": "package-json-from-dist@1.0.0", + "path-scurry": "path-scurry@2.0.0" + } + }, + "is-fullwidth-code-point@3.0.0": { + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dependencies": {} + }, + "isexe@2.0.0": { + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dependencies": {} + }, + "jackspeak@4.0.1": { + "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", + "dependencies": { + "@isaacs/cliui": "@isaacs/cliui@8.0.2", + "@pkgjs/parseargs": "@pkgjs/parseargs@0.11.0" + } + }, + "lru-cache@11.0.0": { + "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==", + "dependencies": {} + }, + "minimatch@10.0.1": { + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dependencies": { + "brace-expansion": "brace-expansion@2.0.1" + } + }, + "minipass@7.1.2": { + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dependencies": {} + }, + "package-json-from-dist@1.0.0": { + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dependencies": {} + }, + "path-key@3.1.1": { + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dependencies": {} + }, + "path-scurry@2.0.0": { + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dependencies": { + "lru-cache": "lru-cache@11.0.0", + "minipass": "minipass@7.1.2" + } + }, "pg-cloudflare@1.1.1": { "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", "dependencies": {} @@ -97,10 +252,74 @@ "xtend": "xtend@4.0.2" } }, + "shebang-command@2.0.0": { + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "shebang-regex@3.0.0" + } + }, + "shebang-regex@3.0.0": { + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dependencies": {} + }, + "signal-exit@4.1.0": { + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dependencies": {} + }, "split2@4.2.0": { "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dependencies": {} }, + "string-width@4.2.3": { + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "emoji-regex@8.0.0", + "is-fullwidth-code-point": "is-fullwidth-code-point@3.0.0", + "strip-ansi": "strip-ansi@6.0.1" + } + }, + "string-width@5.1.2": { + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "eastasianwidth@0.2.0", + "emoji-regex": "emoji-regex@9.2.2", + "strip-ansi": "strip-ansi@7.1.0" + } + }, + "strip-ansi@6.0.1": { + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "ansi-regex@5.0.1" + } + }, + "strip-ansi@7.1.0": { + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "ansi-regex@6.0.1" + } + }, + "which@2.0.2": { + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "isexe@2.0.0" + } + }, + "wrap-ansi@7.0.0": { + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "ansi-styles@4.3.0", + "string-width": "string-width@4.2.3", + "strip-ansi": "strip-ansi@6.0.1" + } + }, + "wrap-ansi@8.1.0": { + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "ansi-styles@6.2.1", + "string-width": "string-width@5.1.2", + "strip-ansi": "strip-ansi@7.1.0" + } + }, "xtend@4.0.2": { "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dependencies": {} diff --git a/scripts/build_dev.ts b/scripts/build_dev.ts new file mode 100755 index 0000000..300c376 --- /dev/null +++ b/scripts/build_dev.ts @@ -0,0 +1,56 @@ +#!/usr/bin/env -S deno run --allow-read --allow-write --allow-run + +import { ensureDir } from "jsr:@std/fs"; +import { dirname, fromFileUrl, join } from "jsr:@std/path"; + +const __dirname = dirname(fromFileUrl(Deno.mainModule)); +const toolchainRepoPath = join(__dirname, "..", "..", "toolchain"); +const assetsPath = join(__dirname, "..", "Assets", "Rivet", "Editor", "Native"); + +const platform = Deno.build.os; +const arch = Deno.build.arch; + +const target = { + os: platform === "darwin" ? "macos" : platform, + arch: arch === "aarch64" ? "arm64" : arch, + ext: platform === "windows" ? "dll" : platform === "darwin" ? "dylib" : "so", + rustTarget: `${arch === "aarch64" ? "aarch64" : "x86_64"}-${ + platform === "windows" ? "pc-windows-gnu" : + platform === "darwin" ? "apple-darwin" : + "unknown-linux-gnu" + }`, +}; + +async function runCommand(cmd: string[], cwd?: string): Promise { + const command = new Deno.Command(cmd[0], { + args: cmd.slice(1), + cwd, + stdout: "inherit", + stderr: "inherit", + }); + const { code } = await command.output(); + if (code !== 0) throw new Error(`Command failed: ${cmd.join(" ")}`); +} + +async function copyFile(src: string, dest: string): Promise { + await ensureDir(dirname(dest)); + await Deno.copyFile(src, dest); +} + +// Build client +await runCommand(["cargo", "build", "--release"], toolchainRepoPath); + +// Copy FFI library +const ffiSrc = join( + toolchainRepoPath, + "target", + "release", + `librivet_toolchain_ffi.${target.ext}`, +); +const ffiDest = join( + assetsPath, + `librivet_toolchain_ffi_${target.os}_${target.arch}.${target.ext}`, +); +await copyFile(ffiSrc, ffiDest); + +console.log("Library copied successfully."); diff --git a/scripts/copy_native_dev.sh b/scripts/copy_native_dev.sh deleted file mode 100755 index 45bb1a7..0000000 --- a/scripts/copy_native_dev.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -set -euf - -echo "TODO: Currently only supports macOS ARM64" - -# Build client -(cd $CLI_REPO_PATH && cargo build) - -# macOS (ARM64) -rm -rf ./Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_arm64.dylib -cp -r $CLI_REPO_PATH/target/debug/librivet_toolchain_ffi.dylib ./Assets/Rivet/Editor/Native/librivet_toolchain_ffi_macos_arm64.dylib -rm -rf ./Assets/Rivet/Editor/Native/cli/rivet-aarch64-apple -cp -r $CLI_REPO_PATH/target/debug/rivet ./Assets/Rivet/Editor/Native/cli/rivet-aarch64-apple diff --git a/scripts/run_dev.ts b/scripts/run_dev.ts new file mode 100755 index 0000000..2028757 --- /dev/null +++ b/scripts/run_dev.ts @@ -0,0 +1,65 @@ +#!/usr/bin/env -S deno run --allow-net --allow-env --allow-read --allow-write --allow-run + +import "./build_dev.ts"; + +import { glob } from "npm:glob"; +import { dirname, fromFileUrl, join } from "jsr:@std/path"; + +const __dirname = dirname(fromFileUrl(import.meta.url)); +const projectDir = `${__dirname}/..`; + +// Determine the Unity executable path based on the platform +let unityPath: string; +switch (Deno.build.os) { + case "windows": + unityPath = + "C:\\Program Files\\Unity\\Hub\\Editor\\*\\Editor\\Unity.exe"; + break; + case "darwin": + unityPath = + "/Applications/Unity/Hub/Editor/*/Unity.app/Contents/MacOS/Unity"; + break; + case "linux": + unityPath = "/opt/unity/editor/*/Editor/Unity"; + break; + default: + throw new Error("Unsupported operating system"); +} + +// Find the latest Unity version installed +const unityVersions = await glob(unityPath); +if (unityVersions.length === 0) { + throw new Error("No Unity installation found"); +} +unityVersions.sort(); +const latestUnity = unityVersions[unityVersions.length - 1]; + +// Delete the multiple project file lock +const lockFilePath = join(projectDir, "Temp", "UnityLockfile"); +try { + await Deno.remove(lockFilePath); + console.log("Deleted Unity lock file"); +} catch (error) { + if (!(error instanceof Deno.errors.NotFound)) { + console.warn("Failed to delete Unity lock file:", error); + } +} + +// Construct the command to open Unity +const command = new Deno.Command(latestUnity, { + args: ["-projectPath", projectDir, "-logfile", "-"], + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", +}); + +// Run the command without detaching +const process = command.spawn(); + +// Wait for the process to exit +const status = await process.status; + +if (!status.success) { + console.error("Failed to open Unity project"); + Deno.exit(status.code); +}