diff --git a/Misc/MonoProfilerToggle.cs b/Misc/MonoProfilerToggle.cs new file mode 100644 index 0000000..4bfdf38 --- /dev/null +++ b/Misc/MonoProfilerToggle.cs @@ -0,0 +1,161 @@ +using System; +using UnityEngine; + +using System.IO; +using System.Net.Sockets; +using System.Text.RegularExpressions; +using System.Text; + +[KSPAddon(KSPAddon.Startup.Instantly, false)] +public class MonoProfilerToggle : MonoBehaviour +{ + private static TcpClient link = null; + private static NetworkStream stream = null; + private static StreamReader reader = null; + private static StreamWriter writer = null; + + private static int port = -1; + private static bool profiling = true; + private static bool error = false; + + private Rect pos; + private GUIStyle style_r, style_g, style_b; + + private float last_command = -1; + + public MonoProfilerToggle() + { + if (link != null) + return; + + var profargs = System.Environment.GetEnvironmentVariable("MONO_PROFILE"); + if (profargs == null || profargs == "") + return; + + if (Connect(profargs)) + DontDestroyOnLoad(this); + } + + private bool Connect(string profargs) + { + Regex port_re = new Regex(@"command-port=(?\d+)"); + MatchCollection matches = port_re.Matches(profargs); + + foreach (Match match in matches) + { + if (match.Groups["port"].Success) + port = int.Parse(match.Groups["port"].Value); + } + + if (port < 0) + return false; + + if (profargs.Contains("start-disabled")) + profiling = false; + + try + { + link = new TcpClient("127.0.0.1", port); + link.ReceiveTimeout = 5000; + + stream = link.GetStream(); + reader = new StreamReader(stream, Encoding.ASCII); + writer = new StreamWriter(stream, Encoding.ASCII); + + return true; + } + catch (Exception e) + { + Debug.LogError("Cannot connect to profiler: "+e); + link = null; + error = true; + return false; + } + } + + private void SendEnable(bool on) + { + try + { + error = false; + + try + { + while (stream.DataAvailable) + Debug.Log("profiler: "+reader.ReadLine()); + } + catch (SocketException e) + { + Debug.LogError("profiler read: "+e); + } + + reader.DiscardBufferedData(); + + writer.WriteLine(on ? "enable" : "disable"); + writer.Flush(); + + var reply = reader.ReadLine(); + + if (reply.StartsWith("DONE")) + profiling = on; + else + { + Debug.LogError("Profiler reply: "+reply); + error = true; + } + } + catch (Exception e) + { + Debug.LogError("Profiler control: "+e); + error = true; + } + } + + public void Update() + { + if (link != null && link.Connected) + { + if (Input.GetKeyDown(KeyCode.F10) && Input.GetKey(KeyCode.RightAlt)) + { + // Don't send commands too often + if (Time.realtimeSinceStartup < last_command+1) + return; + + last_command = Time.realtimeSinceStartup; + SendEnable(!profiling); + } + } + } + + public void OnGUI() + { + if (link == null && !error) + return; + + if (style_r == null) + { + pos = new Rect(Screen.width - 60, Screen.height - 60, 50, 60); + + style_r = new GUIStyle(GUI.skin.label); + style_r.alignment = TextAnchor.LowerRight; + style_r.normal.textColor = new Color(1.0f, 0.0f, 0.0f, 0.7f); + + style_g = new GUIStyle(style_r); + style_g.normal.textColor = new Color(0.0f, 1.0f, 0.0f, 0.7f); + + style_b = new GUIStyle(style_r); + style_b.normal.textColor = new Color(0.0f, 0.0f, 1.0f, 0.7f); + } + + if (!error && !link.Connected) + error = true; + + if (error) + GUI.Label(pos, "ERR", style_r); + else if (profiling) + GUI.Label(pos, "On", style_g); + else + GUI.Label(pos, "Off", style_b); + } +} + diff --git a/README.rst b/README.rst index 7a6eac7..59c57e5 100644 --- a/README.rst +++ b/README.rst @@ -93,10 +93,18 @@ The script contains three sample sets of options: that after using the ``disable`` command, and waiting a bit, it is mostly safe to quit the game with Alt-F4. + The ``Misc`` subfolder includes a *MonoProfilerToggle* utility, which + implements an in-game way to send these commands. When loaded into the game + with this mode of profiling enabled, it automatically establishes the TCP + control connection, and then shows the estimated current state in the bottom + right corner of the screen, while allowing it to be toggled by pressing + *Right Alt + F10*. + **Note:** Shutting down the game and then quickly restarting it may cause a failure to listen on the port due to a reuse timeout. The only way you will know is that telnet won't be able to connect. - Also, you cannot reconnect if you close telnet by mistake. + Also, it does not support simultaneous connections, or reconnecting + if you close telnet by mistake. OS specifics diff --git a/package.sh b/package.sh index 1858fb7..cd37dcc 100755 --- a/package.sh +++ b/package.sh @@ -19,6 +19,7 @@ compile_ksp() { compile_ksp Misc/FPS.dll Misc/FPS.cs compile_ksp Misc/UnityObjectTree.dll Misc/UnityObjectTree.cs +compile_ksp Misc/MonoProfilerToggle.dll Misc/MonoProfilerToggle.cs MONODIR=mono/builds/embedruntimes/