first commit
This commit is contained in:
270
NitroxClient/Debuggers/BaseDebugger.cs
Normal file
270
NitroxClient/Debuggers/BaseDebugger.cs
Normal file
@@ -0,0 +1,270 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Helper;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Debuggers
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
public abstract class BaseDebugger
|
||||
{
|
||||
public readonly string DebuggerName;
|
||||
public readonly KeyCode Hotkey;
|
||||
public readonly bool HotkeyAltRequired;
|
||||
public readonly bool HotkeyControlRequired;
|
||||
public readonly bool HotkeyShiftRequired;
|
||||
public readonly string HotkeyString;
|
||||
public readonly GUISkinCreationOptions SkinCreationOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Currently active tab. This is the index used with <see cref="tabs"/>.
|
||||
/// </summary>
|
||||
public DebuggerTab ActiveTab;
|
||||
|
||||
public bool CanDragWindow = true;
|
||||
|
||||
public virtual bool Enabled { get; set; }
|
||||
|
||||
public Rect WindowRect;
|
||||
|
||||
/// <summary>
|
||||
/// Optional rendered tabs of the current debugger.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <see cref="ActiveTab"/> gives the index of the currently selected tab.
|
||||
/// </remarks>
|
||||
private readonly Dictionary<string, DebuggerTab> tabs = new Dictionary<string, DebuggerTab>();
|
||||
|
||||
private float maxHeight;
|
||||
|
||||
protected BaseDebugger(float desiredWidth, string debuggerName = null, KeyCode hotkey = KeyCode.None, bool control = false, bool shift = false, bool alt = false, GUISkinCreationOptions skinOptions = GUISkinCreationOptions.DEFAULT, float maxHeight = 1000f)
|
||||
{
|
||||
this.maxHeight = maxHeight;
|
||||
|
||||
if (desiredWidth < 200)
|
||||
{
|
||||
desiredWidth = 200;
|
||||
}
|
||||
|
||||
WindowRect = new Rect(Screen.width / 2 - (desiredWidth / 2), Screen.height * 0.1f, desiredWidth, Math.Min(Screen.height * 0.8f, maxHeight)); // Default position in center of screen.
|
||||
|
||||
Hotkey = hotkey;
|
||||
HotkeyAltRequired = alt;
|
||||
HotkeyShiftRequired = shift;
|
||||
HotkeyControlRequired = control;
|
||||
HotkeyString = Hotkey == KeyCode.None ? "None" : $"{(HotkeyControlRequired ? "CTRL+" : "")}{(HotkeyAltRequired ? "ALT+" : "")}{(HotkeyShiftRequired ? "SHIFT+" : "")}{Hotkey}";
|
||||
SkinCreationOptions = skinOptions;
|
||||
|
||||
if (string.IsNullOrEmpty(debuggerName))
|
||||
{
|
||||
string name = GetType().Name;
|
||||
DebuggerName = name.Substring(0, name.IndexOf("Debugger", StringComparison.Ordinal));
|
||||
}
|
||||
else
|
||||
{
|
||||
DebuggerName = debuggerName;
|
||||
}
|
||||
}
|
||||
|
||||
public enum GUISkinCreationOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses the NitroxDebug skin.
|
||||
/// </summary>
|
||||
DEFAULT,
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of the default Unity IMGUI skin and sets the copied skin as render skin.
|
||||
/// </summary>
|
||||
UNITYCOPY,
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy based on the NitroxDebug skin and sets the copied skin as render skin.
|
||||
/// </summary>
|
||||
DERIVEDCOPY
|
||||
}
|
||||
|
||||
protected DebuggerTab AddTab(string name, Action render)
|
||||
{
|
||||
DebuggerTab tab = new(name, render);
|
||||
tabs.Add(tab.Name, tab);
|
||||
return tab;
|
||||
}
|
||||
|
||||
protected Optional<DebuggerTab> GetTab(string name)
|
||||
{
|
||||
Validate.NotNull(name);
|
||||
|
||||
tabs.TryGetValue(name, out DebuggerTab tab);
|
||||
return Optional.OfNullable(tab);
|
||||
}
|
||||
|
||||
public virtual void Update()
|
||||
{
|
||||
// Defaults to a no-op but can be overriden
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call this inside a <see cref="MonoBehaviour.OnGUI"/> method.
|
||||
/// </summary>
|
||||
public virtual void OnGUI()
|
||||
{
|
||||
if (!Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GUISkin skin = GetSkin();
|
||||
GUISkinUtils.RenderWithSkin(skin, () =>
|
||||
{
|
||||
WindowRect = GUILayout.Window(GUIUtility.GetControlID(FocusType.Keyboard), WindowRect, RenderInternal, $"[DEBUGGER] {DebuggerName}", GUILayout.ExpandHeight(true), GUILayout.ExpandWidth(true));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optionally adjust the skin that is used during render.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Set <see cref="SkinCreationOptions"/> on <see cref="GUISkinCreationOptions.UNITYCOPY"/> or <see cref="GUISkinCreationOptions.DERIVEDCOPY"/> in constructor before using this method.
|
||||
/// </remarks>
|
||||
/// <param name="skin">Skin that is being used during <see cref="Render(int)"/>.</param>
|
||||
protected virtual void OnSetSkin(GUISkin skin)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optionally use a custom render solution for the debugger by overriding this method.
|
||||
/// </summary>
|
||||
protected virtual void Render()
|
||||
{
|
||||
ActiveTab?.Render();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (a copy of) a skin specified by <see cref="GUISkinCreationOptions"/>.
|
||||
/// </summary>
|
||||
/// <returns>A reference to an existing or copied skin.</returns>
|
||||
private GUISkin GetSkin()
|
||||
{
|
||||
GUISkin skin = GUI.skin;
|
||||
string skinName = GetSkinName();
|
||||
switch (SkinCreationOptions)
|
||||
{
|
||||
case GUISkinCreationOptions.DEFAULT:
|
||||
skin = GUISkinUtils.RegisterDerivedOnce("debuggers.default", s =>
|
||||
{
|
||||
SetBaseStyle(s);
|
||||
OnSetSkinImpl(s);
|
||||
});
|
||||
break;
|
||||
|
||||
case GUISkinCreationOptions.UNITYCOPY:
|
||||
skin = GUISkinUtils.RegisterDerivedOnce(skinName, OnSetSkinImpl);
|
||||
break;
|
||||
|
||||
case GUISkinCreationOptions.DERIVEDCOPY:
|
||||
GUISkin baseSkin = GUISkinUtils.RegisterDerivedOnce("debuggers.default", SetBaseStyle);
|
||||
skin = GUISkinUtils.RegisterDerivedOnce(skinName, OnSetSkinImpl, baseSkin);
|
||||
break;
|
||||
}
|
||||
|
||||
return skin;
|
||||
}
|
||||
|
||||
private string GetSkinName()
|
||||
{
|
||||
string name = GetType().Name;
|
||||
return $"debuggers.{name.Substring(0, name.IndexOf("Debugger")).ToLowerInvariant()}";
|
||||
}
|
||||
|
||||
private void OnSetSkinImpl(GUISkin skin)
|
||||
{
|
||||
if (SkinCreationOptions == GUISkinCreationOptions.DEFAULT)
|
||||
{
|
||||
Enabled = false;
|
||||
throw new NotSupportedException($"Cannot change {nameof(GUISkin)} for {GetType().FullName} when accessing the default skin. Change {nameof(SkinCreationOptions)} to something else than {nameof(GUISkinCreationOptions.DEFAULT)}.");
|
||||
}
|
||||
|
||||
OnSetSkin(skin);
|
||||
}
|
||||
|
||||
private void RenderInternal(int windowId)
|
||||
{
|
||||
using (new GUILayout.HorizontalScope("Box"))
|
||||
{
|
||||
if (tabs.Count == 1)
|
||||
{
|
||||
GUILayout.Label(tabs.First().Key, "tabActive");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (DebuggerTab tab in tabs.Values)
|
||||
{
|
||||
if (GUILayout.Button(tab.Name, ActiveTab == tab ? "tabActive" : "tab"))
|
||||
{
|
||||
ActiveTab = tab;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Render();
|
||||
if (CanDragWindow)
|
||||
{
|
||||
GUI.DragWindow();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetBaseStyle(GUISkin skin)
|
||||
{
|
||||
skin.label.alignment = TextAnchor.MiddleLeft;
|
||||
skin.label.margin = new RectOffset();
|
||||
skin.label.padding = new RectOffset();
|
||||
|
||||
skin.SetCustomStyle("header", skin.label, s =>
|
||||
{
|
||||
s.margin.top = 10;
|
||||
s.margin.bottom = 10;
|
||||
s.alignment = TextAnchor.MiddleCenter;
|
||||
s.fontSize = 16;
|
||||
s.fontStyle = FontStyle.Bold;
|
||||
});
|
||||
|
||||
skin.SetCustomStyle("tab", skin.button, s =>
|
||||
{
|
||||
s.fontSize = 16;
|
||||
s.margin = new RectOffset(5, 5, 5, 5);
|
||||
});
|
||||
|
||||
skin.SetCustomStyle("tabActive", skin.button, s =>
|
||||
{
|
||||
s.fontStyle = FontStyle.Bold;
|
||||
s.fontSize = 16;
|
||||
});
|
||||
}
|
||||
|
||||
public virtual void ResetWindowPosition()
|
||||
{
|
||||
WindowRect = new Rect(Screen.width / 2f - (WindowRect.width / 2), Screen.height / 2f - (WindowRect.height / 2), WindowRect.width, Math.Min(Screen.height * 0.8f, maxHeight)); //Reset position of debuggers because SN sometimes throws the windows from planet 4546B
|
||||
}
|
||||
|
||||
public class DebuggerTab
|
||||
{
|
||||
public DebuggerTab(string name, Action render)
|
||||
{
|
||||
Validate.NotNull(name, $"Expected a name for the {nameof(DebuggerTab)}");
|
||||
Validate.NotNull(render, $"Expected an action for the {nameof(DebuggerTab)}");
|
||||
|
||||
Name = name;
|
||||
Render = render;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public Action Render { get; }
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user