#if UNITY_EDITOR using System; using System.Diagnostics; using System.IO; using System.Net; using AOT.Boot; using UnityEditor; using UnityEngine; namespace AIGame.EditorTools { /// 仅在 Boot 配置为本机 AIServer 时,进入 Play Mode 前启动已有服务。 [InitializeOnLoad] public static class LocalServerAutoStart { [Serializable] class Health { public bool ok; public string service; } static LocalServerAutoStart() { EditorApplication.playModeStateChanged += state => { if (state != PlayModeStateChange.ExitingEditMode) return; var boot = UnityEngine.Object.FindObjectOfType(); if (boot == null) return; var settings = new SerializedObject(boot).FindProperty("settings"); if (settings.FindPropertyRelative("HttpBase").stringValue.TrimEnd('/') != "http://127.0.0.1:8080") return; try { UnityEngine.Debug.Log("[LocalAIServer] " + StartLocal()); } catch (Exception e) { UnityEngine.Debug.LogWarning("[LocalAIServer] " + e.Message); } }; } static bool IsHealthy() { try { var request = (HttpWebRequest)WebRequest.Create("http://127.0.0.1:8080/health"); request.Timeout = 250; request.ReadWriteTimeout = 250; request.Proxy = null; using (var response = request.GetResponse()) using (var reader = new StreamReader(response.GetResponseStream())) { var health = JsonUtility.FromJson(reader.ReadToEnd()); return health != null && health.ok && health.service == "aiserver"; } } catch { return false; } } [MenuItem("AIGame/Boot/Server/Start Local AIServer")] public static string StartLocal() { if (IsHealthy()) return "already healthy at 127.0.0.1:8080"; string repo = Directory.GetParent(Application.dataPath).Parent.FullName; string exe = Path.Combine(repo, "AIServer/build/Release/aiserver.exe"); if (!File.Exists(exe)) throw new FileNotFoundException("Build AIServer first: cmake --build AIServer/build --config Release", exe); var info = new ProcessStartInfo(exe) { Arguments = "--host 127.0.0.1 --port 8080 --daemon --db \"" + Path.Combine(repo, "AIServer/data/aiserver.db") + "\"", WorkingDirectory = Path.Combine(repo, "AIServer"), UseShellExecute = false, CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden }; using (var process = Process.Start(info)) { for (int i = 0; i < 15; i++) { System.Threading.Thread.Sleep(100); if (IsHealthy()) return "started at 127.0.0.1:8080"; if (process.HasExited) throw new Exception("Local AIServer exited; check port 8080 and the database path."); } } throw new Exception("Local AIServer did not become healthy; theme preview remains available without login."); } } } #endif