{"TotalCount":3,"Files":[{"Ident":"coomzy.reconnecter","Path":"Editor/ReconnecterEditorTool.cs","FileName":"ReconnecterEditorTool.cs","PackageType":"library","CodeKind":"Editor","AssetVersionId":73637,"IsPrivate":false,"Code":"using Sandbox;\r\nusing Editor;\r\n\r\npublic class ReconnecterBar : ToolbarGroup\r\n{\r\n\t[Event(\u0022tools.headerbar.build\u0022, Priority = 150)]\r\n\tpublic static void OnBuildHeaderToolbar(HeadBarEvent e)\r\n\t{\r\n\t\te.RightCenter.Add(new ReconnecterBar(null));\r\n\t\te.RightCenter.AddSpacingCell(8);\r\n\t}\r\n\r\n\tpublic ReconnecterBar(Widget parent) : base(parent, \u0022Reconnecter\u0022, null)\r\n\t{\r\n\t\tToolTip = \u0022Auto Reconnect Clients\u0022;\r\n\t}\r\n\r\n\tpublic override void Build()\r\n\t{\r\n\t\tAddToggleButton(\u0022Auto Reconnect Clients\u0022, \u0022autorenew\u0022, () =\u003E ReconnecterEditor.autoReconnectEnabled, SetAutoReconnect);\r\n\t\tAddToggleButton(\u0022Allow Instance Launching\u0022, \u0022person_add\u0022, () =\u003E ReconnecterEditor.allowLaunchInstance, SetAllowLaunchInstance);\r\n\t\tAddButton(\u0022Force Reconnect Clients\u0022, \u0022group\u0022, ForceAutoReconnect);\r\n\t}\r\n\r\n\tpublic void SetAutoReconnect(bool enabled)\r\n\t{\r\n\t\tReconnecterEditor.autoReconnectEnabled = enabled;\r\n\t}\r\n\r\n\tpublic void SetAllowLaunchInstance(bool enabled)\r\n\t{\r\n\t\tReconnecterEditor.allowLaunchInstance = enabled;\r\n\t}\r\n\r\n\tpublic void ForceAutoReconnect()\r\n\t{\r\n\t\tReconnecterEditor.CreateSessionText(true);\r\n\t}\r\n}"},{"Ident":"coomzy.reconnecter","Path":"Editor/ReconnecterEditor.cs","FileName":"ReconnecterEditor.cs","PackageType":"library","CodeKind":"Editor","AssetVersionId":73637,"IsPrivate":false,"Code":"using Sandbox;\r\nusing Sandbox.Internal;\r\nusing System.Diagnostics;\r\nusing System.IO;\r\n\r\npublic static class ReconnecterEditor\r\n{\r\n\tpublic static string packageFolders =\u003E $\u0022{Project.Current.Package.Org.Ident}/{Project.Current.Package.Ident}\u0022;\r\n\tpublic static string dataFolder =\u003E Editor.FileSystem.Root.GetFullPath($\u0022/data/{packageFolders}\u0022);\r\n\r\n\tpublic static bool autoReconnectEnabled\r\n\t{\r\n\t\tget\r\n\t\t{\r\n\t\t\treturn GlobalToolsNamespace.EditorCookie.Get\u003Cbool\u003E(\u0022reconnecter_enabled\u0022, true);\r\n\t\t}\r\n\t\tset\r\n\t\t{\r\n\t\t\tGlobalToolsNamespace.EditorCookie.Set\u003Cbool\u003E(\u0022reconnecter_enabled\u0022, value);\r\n\t\t}\r\n\t}\r\n\tpublic static bool allowLaunchInstance\r\n\t{\r\n\t\tget\r\n\t\t{\r\n\t\t\treturn GlobalToolsNamespace.EditorCookie.Get\u003Cbool\u003E(\u0022reconnecter_allowLaunchInstance\u0022, true);\r\n\t\t}\r\n\t\tset\r\n\t\t{\r\n\t\t\tGlobalToolsNamespace.EditorCookie.Set\u003Cbool\u003E(\u0022reconnecter_allowLaunchInstance\u0022, value);\r\n\t\t}\r\n\t}\r\n\r\n\tstatic ReconnecterEditor()\r\n\t{\r\n\t\tReconnecterSystem.RegisterOnRequestWriteSession(CreateSessionText);\r\n\t}\r\n\r\n\tpublic static void CreateSessionText(bool force = false)\r\n\t{\r\n\t\tif (!autoReconnectEnabled \u0026\u0026 !force)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tstring filePath = $\u0022{dataFolder}/{ReconnecterSystem.SESSION_FILE_PATH}\u0022;\r\n\r\n\t\tstring destinationDirectory = Path.GetDirectoryName(filePath);\r\n\t\tif (!Directory.Exists(destinationDirectory))\r\n\t\t{\r\n\t\t\tDirectory.CreateDirectory(destinationDirectory);\r\n\t\t}\r\n\r\n\t\tFile.WriteAllText(filePath, System.DateTime.UtcNow.ToString());\r\n\t\t//Log.Info($\u0022CreateSessionText() filePath: {filePath}\u0022);\r\n\t}\r\n\r\n\t[Event(\u0022scene.play\u0022, Priority = int.MinValue)]\r\n\tpublic static void ScenePlay()\r\n\t{\t\t\r\n\t\tReconnecterSystem.OnPlayInEditor();\r\n\r\n\t\tif (!autoReconnectEnabled || !allowLaunchInstance)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tProcess[] processes = Process.GetProcessesByName(\u0022sbox\u0022);\r\n\t\tbool isProcessRunning = processes.Length \u003E 0;\r\n\r\n\t\tif (isProcessRunning)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tSpawnProcess();\r\n\t}\r\n\r\n\tpublic static void SpawnProcess()\r\n\t{\r\n\t\tvar p = new Process();\r\n\t\tp.StartInfo.FileName = \u0022sbox.exe\u0022;\r\n\t\tp.StartInfo.WorkingDirectory = System.Environment.CurrentDirectory;\r\n\t\tp.StartInfo.CreateNoWindow = true;\r\n\t\tp.StartInfo.RedirectStandardOutput = true;\r\n\t\tp.StartInfo.RedirectStandardError = true;\r\n\t\tp.StartInfo.UseShellExecute = false;\r\n\r\n\t\tp.StartInfo.ArgumentList.Add(\u0022-joinlocal\u0022);\r\n\r\n\t\t// This doesn\u0027t seem to work because it doesn\u0027t use Steam\u0027s Launch Options?\r\n\t\tp.StartInfo.ArgumentList.Add(\u0022-sw\u0022);\r\n\r\n\t\tp.Start();\r\n\t}\r\n}"},{"Ident":"coomzy.reconnecter","Path":"Code/ReconnecterSystem.cs","FileName":"ReconnecterSystem.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":73637,"IsPrivate":false,"Code":"using System;\r\nusing Sandbox;\r\nusing System.Linq;\r\nusing Sandbox.Network;\r\n\r\npublic class ReconnecterSystem : GameObjectSystem\r\n{\r\n\tpublic static ReconnecterComponent instance { get; set; }\r\n\tpublic static DateTime? startTime { get; set; }\r\n\r\n\tpublic const string SESSION_FILE_PATH = \u0022reconnecter_session.txt\u0022;\r\n\r\n\tpublic ReconnecterSystem(Scene scene) : base(scene)\r\n\t{\r\n\t\tif (!Application.IsDebug)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (startTime == null)\r\n\t\t{\r\n\t\t\tstartTime = DateTime.UtcNow;\r\n\t\t}\r\n\r\n\t\tif (Game.IsEditor)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tListen(Stage.FinishUpdate, 0, FinishUpdate, \u0022ReconnecterSystem.FinishUpdate\u0022);\r\n\t}\r\n\r\n\t// Called from ReconnecterEditor, don\u0027t know a better way\r\n\t// It\u0027s called after ReconnecterSystem()\r\n\tpublic static void OnPlayInEditor()\r\n\t{\r\n\t\tif (instance != null)\r\n\t\t{\r\n\t\t\tinstance.Destroy();\r\n\t\t\tinstance = null;\r\n\t\t}\r\n\r\n\t\tif (instance == null)\r\n\t\t{\r\n\t\t\tvar newGO = new GameObject(true);\r\n\t\t\tinstance = newGO.Components.Create\u003CReconnecterComponent\u003E();\r\n\t\t\tnewGO.Flags = GameObjectFlags.DontDestroyOnLoad;\r\n\t\t}\r\n\r\n\t\tstartTime = null;\r\n\t}\r\n\r\n\tpublic static void OnStartedHosting()\r\n\t{\r\n\t\tif (!Game.IsEditor)\r\n        {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tTryRequestWriteSession();\r\n\t}\r\n\r\n\tvoid FinishUpdate()\r\n\t{\r\n\t\tif (!FileSystem.Data.FileExists(SESSION_FILE_PATH))\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar sessionText = FileSystem.Data.ReadAllText(SESSION_FILE_PATH);\r\n\t\tif (!DateTime.TryParse(sessionText, out var lastSessionStart))\r\n\t\t{\r\n\t\t\tLog.Info($\u0022Reconnecter failed to parse session text: {sessionText}\u0022);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (lastSessionStart \u003C= startTime.Value)\r\n\t\t{\r\n\t\t\t//Log.Info($\u0022You\u0027re in the most active session\u0022);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tNetworking.Disconnect();\r\n\t\tNetworking.Connect(\u0022local\u0022);\r\n\t}\r\n\r\n\tpublic static event Action\u003Cbool\u003E OnRequestWriteSession;\r\n\tpublic static void RegisterOnRequestWriteSession(Action\u003Cbool\u003E handler)\r\n\t{\r\n\t\tif (OnRequestWriteSession != null \u0026\u0026 OnRequestWriteSession.GetInvocationList().Contains(handler))\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tOnRequestWriteSession \u002B= handler;\r\n\t}\r\n\r\n\tpublic static void TryRequestWriteSession()\r\n\t{\r\n\t\tOnRequestWriteSession?.Invoke(false);\r\n\t}\r\n\r\n\t[ConCmd(\u0022reconnect_clients\u0022)]\r\n\tpublic static void RequestWriteSession()\r\n\t{\r\n\t\tOnRequestWriteSession?.Invoke(true);\r\n\t}\r\n}\r\n\r\npublic class ReconnecterComponent : Component, Component.INetworkListener\r\n{\r\n\tpublic void OnActive(Connection channel)\r\n\t{\r\n\t\tif (channel == null || !channel.IsHost)\r\n\t\t{\r\n\t\t\treturn;\t\r\n\t\t}\r\n\r\n\t\tReconnecterSystem.OnStartedHosting();\r\n\t}\r\n}"}]}