This commit is contained in:
mob-sakai
2023-08-17 09:43:02 +09:00
parent 35325c8899
commit 3df190382a
33 changed files with 1596 additions and 1752 deletions

View File

@@ -1,10 +1,11 @@
using System;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Serialization;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditorInternal;
#endif
namespace Coffee.NanoMonitor
@@ -13,24 +14,29 @@ namespace Coffee.NanoMonitor
[CustomEditor(typeof(NanoMonitor))]
internal class NanoMonitorEditor : Editor
{
private UnityEditorInternal.ReorderableList m_MonitorItemList;
private ReorderableList _monitorItemList;
private void OnEnable()
{
var items = serializedObject.FindProperty("m_CustomMonitorItems");
m_MonitorItemList = new UnityEditorInternal.ReorderableList(serializedObject, items)
_monitorItemList = new ReorderableList(serializedObject, items)
{
draggable = false,
drawHeaderCallback = r => { EditorGUI.LabelField(r, new GUIContent("Custom Monitor Items")); },
drawHeaderCallback = r =>
{
EditorGUI.LabelField(r, new GUIContent("Custom Monitor Items"));
},
drawElementCallback = (r, i, _, __) =>
{
EditorGUI.LabelField(new Rect(r.x, r.y, r.width, r.height - 2), GUIContent.none, EditorStyles.textArea);
EditorGUI.LabelField(new Rect(r.x, r.y, r.width, r.height - 2), GUIContent.none,
EditorStyles.textArea);
var labelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 80;
EditorGUI.PropertyField(new Rect(r.x + 2, r.y + 3, r.width - 4, r.height - 4), items.GetArrayElementAtIndex(i), true);
EditorGUI.PropertyField(new Rect(r.x + 2, r.y + 3, r.width - 4, r.height - 4),
items.GetArrayElementAtIndex(i), true);
EditorGUIUtility.labelWidth = labelWidth;
},
elementHeightCallback = i => EditorGUI.GetPropertyHeight(items.GetArrayElementAtIndex(i)) + 6,
elementHeightCallback = i => EditorGUI.GetPropertyHeight(items.GetArrayElementAtIndex(i)) + 6
};
}
@@ -38,7 +44,7 @@ namespace Coffee.NanoMonitor
{
base.OnInspectorGUI();
m_MonitorItemList.DoLayoutList();
_monitorItemList.DoLayoutList();
serializedObject.ApplyModifiedProperties();
}
}
@@ -52,38 +58,50 @@ namespace Coffee.NanoMonitor
// Serialize Members.
//################################
// Settings
[Header("Settings")] [SerializeField] [Range(0.01f, 2f)]
[Header("Settings")]
[SerializeField]
[Range(0.01f, 2f)]
private float m_Interval = 1f;
[SerializeField] [Range(0, 3)] private int m_Precision = 2;
[SerializeField] private Font m_Font;
[SerializeField]
[Range(0, 3)]
private int m_Precision = 2;
[SerializeField]
private Font m_Font;
// Foldout
[Header("Foldout")] [SerializeField] private bool m_Opened = false;
[Header("Foldout")]
[SerializeField]
private bool m_Opened;
[FormerlySerializedAs("m_Collapse")] [SerializeField]
private GameObject m_FoldoutObject = null;
[FormerlySerializedAs("m_Collapse")]
[SerializeField]
private GameObject m_FoldoutObject;
[SerializeField] private Button m_OpenButton = null;
[SerializeField] private Button m_CloseButton = null;
[SerializeField]
private Button m_OpenButton;
[SerializeField]
private Button m_CloseButton;
// View
[Header("View")] [SerializeField] private MonitorUI m_Fps = null;
[SerializeField] private MonitorUI m_Gc = null;
[SerializeField] private MonitorUI m_MonoUsage = null;
[SerializeField] private MonitorUI m_UnityUsage = null;
[Header("View")]
[SerializeField]
private MonitorUI m_Fps;
[HideInInspector] [SerializeField] private CustomMonitorItem[] m_CustomMonitorItems = new CustomMonitorItem[0];
[SerializeField]
private MonitorUI m_Gc;
[SerializeField]
private MonitorUI m_MonoUsage;
//################################
// Public Members.
//################################
public void Clean()
{
Resources.UnloadUnusedAssets();
GC.Collect();
}
[SerializeField]
private MonitorUI m_UnityUsage;
[HideInInspector]
[SerializeField]
private CustomMonitorItem[] m_CustomMonitorItems = new CustomMonitorItem[0];
//################################
@@ -93,44 +111,75 @@ namespace Coffee.NanoMonitor
private double _fpsElapsed;
private int _frames;
private void Open()
private void Update()
{
_frames++;
_elapsed += Time.unscaledDeltaTime;
_fpsElapsed += Time.unscaledDeltaTime;
if (_elapsed < m_Interval) return;
if (m_Fps)
{
m_Fps.SetText("FPS: {0}", (int)(_frames / _fpsElapsed));
}
if (m_Gc)
{
m_Gc.SetText("GC: {0}", GC.CollectionCount(0));
}
if (m_MonoUsage)
{
var monoUsed = (Profiler.GetMonoUsedSizeLong() >> 10) / 1024f;
var monoTotal = (Profiler.GetMonoHeapSizeLong() >> 10) / 1024f;
if (m_Precision == 3)
{
m_MonoUsage.SetText("Mono: {0:N3}/{1:N3}MB", monoUsed, monoTotal);
}
else if (m_Precision == 2)
{
m_MonoUsage.SetText("Mono: {0:N2}/{1:N2}MB", monoUsed, monoTotal);
}
else if (m_Precision == 1)
{
m_MonoUsage.SetText("Mono: {0:N1}/{1:N1}MB", monoUsed, monoTotal);
}
else
{
m_MonoUsage.SetText("Mono: {0:N0}/{1:N0}MB", monoUsed, monoTotal);
}
}
if (m_UnityUsage)
{
var unityUsed = (Profiler.GetTotalAllocatedMemoryLong() >> 10) / 1024f;
var unityTotal = (Profiler.GetTotalReservedMemoryLong() >> 10) / 1024f;
if (m_Precision == 3)
{
m_UnityUsage.SetText("Unity: {0:N3}/{1:N3}MB", unityUsed, unityTotal);
}
else if (m_Precision == 2)
{
m_UnityUsage.SetText("Unity: {0:N2}/{1:N2}MB", unityUsed, unityTotal);
}
else if (m_Precision == 1)
{
m_UnityUsage.SetText("Unity: {0:N1}/{1:N1}MB", unityUsed, unityTotal);
}
else
{
m_UnityUsage.SetText("Unity: {0:N0}/{1:N0}MB", unityUsed, unityTotal);
}
}
foreach (var item in m_CustomMonitorItems)
{
item.UpdateText();
}
_frames = 0;
_elapsed = m_Interval;
_elapsed %= m_Interval;
_fpsElapsed = 0;
if (m_FoldoutObject)
{
m_FoldoutObject.SetActive(true);
}
if (m_CloseButton)
{
m_CloseButton.gameObject.SetActive(true);
}
if (m_OpenButton)
{
m_OpenButton.gameObject.SetActive(false);
}
}
private void Close()
{
if (m_FoldoutObject)
{
m_FoldoutObject.SetActive(false);
}
if (m_CloseButton)
{
m_CloseButton.gameObject.SetActive(false);
}
if (m_OpenButton)
{
m_OpenButton.gameObject.SetActive(true);
}
}
@@ -172,77 +221,6 @@ namespace Coffee.NanoMonitor
}
}
private void Update()
{
_frames++;
_elapsed += Time.unscaledDeltaTime;
_fpsElapsed += Time.unscaledDeltaTime;
if (_elapsed < m_Interval) return;
if (m_Fps)
{
m_Fps.SetText("FPS: {0}", (int) (_frames / _fpsElapsed));
}
if (m_Gc)
{
m_Gc.SetText("GC: {0}", GC.CollectionCount(0));
}
if (m_MonoUsage)
{
var monoUsed = (UnityEngine.Profiling.Profiler.GetMonoUsedSizeLong() >> 10) / 1024f;
var monoTotal = (UnityEngine.Profiling.Profiler.GetMonoHeapSizeLong() >> 10) / 1024f;
if (m_Precision == 3)
{
m_MonoUsage.SetText("Mono: {0:N3}/{1:N3}MB", monoUsed, monoTotal);
}
else if (m_Precision == 2)
{
m_MonoUsage.SetText("Mono: {0:N2}/{1:N2}MB", monoUsed, monoTotal);
}
else if (m_Precision == 1)
{
m_MonoUsage.SetText("Mono: {0:N1}/{1:N1}MB", monoUsed, monoTotal);
}
else
{
m_MonoUsage.SetText("Mono: {0:N0}/{1:N0}MB", monoUsed, monoTotal);
}
}
if (m_UnityUsage)
{
var unityUsed = (UnityEngine.Profiling.Profiler.GetTotalAllocatedMemoryLong() >> 10) / 1024f;
var unityTotal = (UnityEngine.Profiling.Profiler.GetTotalReservedMemoryLong() >> 10) / 1024f;
if (m_Precision == 3)
{
m_UnityUsage.SetText("Unity: {0:N3}/{1:N3}MB", unityUsed, unityTotal);
}
else if (m_Precision == 2)
{
m_UnityUsage.SetText("Unity: {0:N2}/{1:N2}MB", unityUsed, unityTotal);
}
else if (m_Precision == 1)
{
m_UnityUsage.SetText("Unity: {0:N1}/{1:N1}MB", unityUsed, unityTotal);
}
else
{
m_UnityUsage.SetText("Unity: {0:N0}/{1:N0}MB", unityUsed, unityTotal);
}
}
foreach (var item in m_CustomMonitorItems)
{
item.UpdateText();
}
_frames = 0;
_elapsed %= m_Interval;
_fpsElapsed = 0;
}
#if UNITY_EDITOR
private void OnValidate()
{
@@ -264,5 +242,55 @@ namespace Coffee.NanoMonitor
}
}
#endif
//################################
// Public Members.
//################################
public void Clean()
{
Resources.UnloadUnusedAssets();
GC.Collect();
}
private void Open()
{
_frames = 0;
_elapsed = m_Interval;
_fpsElapsed = 0;
if (m_FoldoutObject)
{
m_FoldoutObject.SetActive(true);
}
if (m_CloseButton)
{
m_CloseButton.gameObject.SetActive(true);
}
if (m_OpenButton)
{
m_OpenButton.gameObject.SetActive(false);
}
}
private void Close()
{
if (m_FoldoutObject)
{
m_FoldoutObject.SetActive(false);
}
if (m_CloseButton)
{
m_CloseButton.gameObject.SetActive(false);
}
if (m_OpenButton)
{
m_OpenButton.gameObject.SetActive(true);
}
}
}
}

View File

@@ -2,14 +2,17 @@
using UnityEngine;
using UnityEngine.UI;
namespace Coffee.NanoMonitor{
namespace Coffee.NanoMonitor
{
public class FixedFont
{
private readonly UIVertex[] _tmpVerts = new UIVertex[4];
private static readonly Dictionary<Font, FixedFont> _fonts = new Dictionary<Font, FixedFont>();
private static readonly TextGenerator _textGenerator = new TextGenerator(100);
private const string k_Characters =
"_!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
private static TextGenerationSettings _settings = new TextGenerationSettings
private static readonly Dictionary<Font, FixedFont> s_Fonts = new Dictionary<Font, FixedFont>();
private static readonly TextGenerator s_TextGenerator = new TextGenerator(100);
private static TextGenerationSettings s_Settings = new TextGenerationSettings
{
scaleFactor = 1,
horizontalOverflow = HorizontalWrapMode.Overflow,
@@ -19,25 +22,33 @@ namespace Coffee.NanoMonitor{
color = Color.white
};
private int _resolution = 0;
private readonly Font _font;
private UIVertex[] _verts;
private readonly UIVertex[] _tmpVerts = new UIVertex[4];
private UICharInfo[] _charInfos;
private int _resolution;
private UIVertex[] _verts;
private FixedFont(Font font)
{
_font = font;
}
public int fontSize => _font.dynamic ? 32 : _font.fontSize;
public int fontSize
{
get
{
return _font.dynamic ? 32 : _font.fontSize;
}
}
public static FixedFont GetOrCreate(Font font)
{
if (font == null) return null;
if (_fonts.TryGetValue(font, out var data)) return data;
if (s_Fonts.TryGetValue(font, out var data)) return data;
data = new FixedFont(font);
_fonts.Add(font, data);
s_Fonts.Add(font, data);
return data;
}
@@ -61,18 +72,20 @@ namespace Coffee.NanoMonitor{
if (_resolution == currentResolution) return;
_resolution = currentResolution;
_settings.font = _font;
_textGenerator.Invalidate();
_textGenerator.Populate("_!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", _settings);
s_Settings.font = _font;
s_TextGenerator.Invalidate();
s_TextGenerator.Populate(k_Characters, s_Settings);
_verts = _textGenerator.GetVerticesArray();
_charInfos = _textGenerator.GetCharactersArray();
_verts = s_TextGenerator.GetVerticesArray();
_charInfos = s_TextGenerator.GetCharactersArray();
float offsetX = 0;
for (var i = 0; i < _verts.Length; i++)
{
if ((i & 3) == 0)
{
offsetX = _verts[i].position.x;
}
var v = _verts[i];
v.position -= new Vector3(offsetX, 0);
@@ -118,18 +131,27 @@ namespace Coffee.NanoMonitor{
for (var i = 0; i < 4; i++)
{
_tmpVerts[i] = new UIVertex();
_tmpVerts[i].uv0 = uv;
_tmpVerts[i].color = color;
_tmpVerts[i] = new UIVertex
{
uv0 = uv,
color = color
};
if (i == 0)
_tmpVerts[i].position = new Vector2(-size.x, -size.y) + offset;
else if (i == 1)
_tmpVerts[i].position = new Vector2(-size.x, size.y) + offset;
else if (i == 2)
_tmpVerts[i].position = new Vector2(size.x, size.y) + offset;
else
_tmpVerts[i].position = new Vector2(size.x, -size.y) + offset;
switch (i)
{
case 0:
_tmpVerts[i].position = new Vector2(-size.x, -size.y) + offset;
break;
case 1:
_tmpVerts[i].position = new Vector2(-size.x, size.y) + offset;
break;
case 2:
_tmpVerts[i].position = new Vector2(size.x, size.y) + offset;
break;
case 3:
_tmpVerts[i].position = new Vector2(size.x, -size.y) + offset;
break;
}
}
toFill.AddUIVertexQuad(_tmpVerts);

View File

@@ -1,50 +1,46 @@
using System.Text;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
namespace Coffee.NanoMonitor{
namespace Coffee.NanoMonitor
{
#if UNITY_EDITOR
using UnityEditor;
[CustomEditor(typeof(MonitorUI))]
public class MonitorTextEditor : Editor
{
private SerializedProperty m_Mode;
private SerializedProperty m_TextAnchor;
private SerializedProperty m_FontSize;
private SerializedProperty m_Font;
private SerializedProperty m_Text;
private SerializedProperty m_Color;
private SerializedProperty _color;
private SerializedProperty _font;
private SerializedProperty _fontSize;
private SerializedProperty _mode;
private SerializedProperty _text;
private SerializedProperty _textAnchor;
private void OnEnable()
{
m_Mode = serializedObject.FindProperty("m_Mode");
m_Text = serializedObject.FindProperty("m_Text");
m_Color = serializedObject.FindProperty("m_Color");
_mode = serializedObject.FindProperty("m_Mode");
_text = serializedObject.FindProperty("m_Text");
_color = serializedObject.FindProperty("m_Color");
var fontData = serializedObject.FindProperty("m_FontData");
m_FontSize = fontData.FindPropertyRelative("m_FontSize");
m_Font = fontData.FindPropertyRelative("m_Font");
m_TextAnchor = serializedObject.FindProperty("m_TextAnchor");
_fontSize = fontData.FindPropertyRelative("m_FontSize");
_font = fontData.FindPropertyRelative("m_Font");
_textAnchor = serializedObject.FindProperty("m_TextAnchor");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(m_Mode);
if ((MonitorUI.Mode) m_Mode.intValue == MonitorUI.Mode.Text)
EditorGUILayout.PropertyField(_mode);
if ((MonitorUI.Mode)_mode.intValue == MonitorUI.Mode.Text)
{
EditorGUILayout.PropertyField(m_Text);
EditorGUILayout.PropertyField(m_FontSize);
EditorGUILayout.PropertyField(m_TextAnchor);
//EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.PropertyField(m_Font);
//EditorGUI.EndDisabledGroup();
EditorGUILayout.PropertyField(_text);
EditorGUILayout.PropertyField(_fontSize);
EditorGUILayout.PropertyField(_textAnchor);
EditorGUILayout.PropertyField(_font);
}
EditorGUILayout.PropertyField(m_Color);
EditorGUILayout.PropertyField(_color);
serializedObject.ApplyModifiedProperties();
}
@@ -56,7 +52,7 @@ namespace Coffee.NanoMonitor{
public enum Mode
{
Text,
Fill,
Fill
}
public enum TextAnchor
@@ -74,26 +70,38 @@ namespace Coffee.NanoMonitor{
[SerializeField] private TextAnchor m_TextAnchor;
//################################
// Private Members.
//################################
private readonly StringBuilder _sb = new StringBuilder(64);
//################################
// Public Members.
//################################
public override string text
{
get => m_StringBuilder.ToString();
get
{
return _sb.ToString();
}
set
{
m_Text = value;
if (m_StringBuilder.IsEqual(m_Text)) return;
if (_sb.IsEqual(m_Text)) return;
m_StringBuilder.Length = 0;
m_StringBuilder.Append(m_Text);
_sb.Length = 0;
_sb.Append(m_Text);
SetVerticesDirty();
}
}
public TextAnchor textAnchor
{
get => m_TextAnchor;
get
{
return m_TextAnchor;
}
set
{
if (m_TextAnchor == value) return;
@@ -105,44 +113,11 @@ namespace Coffee.NanoMonitor{
public override bool raycastTarget
{
get => m_Mode == Mode.Fill;
set { }
}
public void SetText(string format, double arg0 = 0, double arg1 = 0, double arg2 = 0, double arg3 = 0)
{
m_StringBuilder.Length = 0;
m_StringBuilder.AppendFormatNoAlloc(format, arg0, arg1, arg2, arg3);
SetVerticesDirty();
}
public void SetText(StringBuilder builder)
{
m_StringBuilder.Length = 0;
m_StringBuilder.Append(builder);
SetVerticesDirty();
}
//################################
// Private Members.
//################################
private readonly StringBuilder m_StringBuilder = new StringBuilder(64);
private void UpdateFont()
{
//var globalFont = NNanoMonitorttings.Instance.font;
//if (globalFont)
//{
// font = globalFont;
//}
var fontData = FixedFont.GetOrCreate(font);
if (fontData != null)
get
{
fontData.Invalidate();
fontData.UpdateFont();
return m_Mode == Mode.Fill;
}
set { }
}
@@ -151,19 +126,17 @@ namespace Coffee.NanoMonitor{
//################################
protected override void OnEnable()
{
//NaNanoMonitortings.Instance.onFontChanged += UpdateFont;
RegisterDirtyMaterialCallback(UpdateFont);
base.OnEnable();
raycastTarget = false;
maskable = false;
m_StringBuilder.Length = 0;
m_StringBuilder.Append(m_Text);
_sb.Length = 0;
_sb.Append(m_Text);
}
protected override void OnDisable()
{
//NanNanoMonitorings.Instance.onFontChanged -= UpdateFont;
UnregisterDirtyMaterialCallback(UpdateFont);
base.OnDisable();
@@ -174,14 +147,38 @@ namespace Coffee.NanoMonitor{
{
base.OnValidate();
if (!m_StringBuilder.IsEqual(m_Text))
if (!_sb.IsEqual(m_Text))
{
m_StringBuilder.Length = 0;
m_StringBuilder.Append(m_Text);
_sb.Length = 0;
_sb.Append(m_Text);
}
}
#endif
public void SetText(string format, double arg0 = 0, double arg1 = 0, double arg2 = 0, double arg3 = 0)
{
_sb.Length = 0;
_sb.AppendFormatNoAlloc(format, arg0, arg1, arg2, arg3);
SetVerticesDirty();
}
public void SetText(StringBuilder builder)
{
_sb.Length = 0;
_sb.Append(builder);
SetVerticesDirty();
}
private void UpdateFont()
{
var fontData = FixedFont.GetOrCreate(font);
if (fontData != null)
{
fontData.Invalidate();
fontData.UpdateFont();
}
}
protected override void OnPopulateMesh(VertexHelper toFill)
{
toFill.Clear();
@@ -197,7 +194,7 @@ namespace Coffee.NanoMonitor{
return;
}
var scale = (float) fontSize / fontData.fontSize;
var scale = (float)fontSize / fontData.fontSize;
float offset = 0;
switch (textAnchor)
{
@@ -205,20 +202,26 @@ namespace Coffee.NanoMonitor{
offset = rectTransform.rect.xMin;
break;
case TextAnchor.Center:
for (var i = 0; i < m_StringBuilder.Length; i++)
offset = fontData.Layout(m_StringBuilder[i], offset, scale);
for (var i = 0; i < _sb.Length; i++)
{
offset = fontData.Layout(_sb[i], offset, scale);
}
offset = -offset / 2;
break;
case TextAnchor.Right:
for (var i = 0; i < m_StringBuilder.Length; i++)
offset = fontData.Layout(m_StringBuilder[i], offset, scale);
for (var i = 0; i < _sb.Length; i++)
{
offset = fontData.Layout(_sb[i], offset, scale);
}
offset = rectTransform.rect.xMax - offset;
break;
}
for (var i = 0; i < m_StringBuilder.Length; i++)
for (var i = 0; i < _sb.Length; i++)
{
offset = fontData.Append(toFill, m_StringBuilder[i], offset, scale, color);
offset = fontData.Append(toFill, _sb[i], offset, scale, color);
}
}

View File

@@ -1,55 +0,0 @@
using System;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Coffee.MiniProfiler
{
internal class MiniProfilerSettings : ScriptableSettings<MiniProfilerSettings>
{
[Header("UI")]
[SerializeField] private Font m_Font = null;
[Header("Instantiate On Boot")]
[SerializeField] private GameObject miniProfilerPrefab = null;
[SerializeField] private string[] m_SceneNames = new string[0];
public Font font => m_Font;
public event Action onFontChanged;
protected override void OnBoot()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneLoaded += OnSceneLoaded;
}
public void OnSceneLoaded(Scene scene, LoadSceneMode __)
{
SceneManager.sceneLoaded -= OnSceneLoaded;
if (!miniProfilerPrefab || !m_SceneNames.Contains(scene.name)) return;
var go = Instantiate(miniProfilerPrefab);
if (Application.isPlaying)
DontDestroyOnLoad(go);
}
protected override bool bootOnPlayMode => true;
protected override bool bootOnEditorMode => false;
#if UNITY_EDITOR
protected override void OnValidate()
{
onFontChanged?.Invoke();
base.OnValidate();
}
private void Reset()
{
m_Font = UnityEngine.Resources.GetBuiltinResource<Font>("Arial.ttf");
}
[UnityEditor.SettingsProvider]
private static UnityEditor.SettingsProvider CreateSettingsProvider() => new ScriptableSettingsProvider<MiniProfilerSettings>();
#endif
}
}

View File

@@ -1,13 +0,0 @@
fileFormatVersion: 2
guid: 647dad4f8226a49b9874b68b79413d64
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- miniProfilerPrefab: {fileID: 7211429669315726685, guid: 784696794bc6345bc80bf49623581c2e,
type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,280 +0,0 @@
using UnityEngine;
using System;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Coffee.MiniProfiler
{
internal abstract class ScriptableSettings : ScriptableObject
{
#if UNITY_EDITOR
public virtual string GetSettingPath()
{
return GetSettingPath(GetType());
}
internal static string GetSettingPath(Type type)
{
return $"Project/{ObjectNames.NicifyVariableName(type.Name.Replace("ProjectSettings", ""))}";
}
#endif
public virtual string GetDefaultAssetPath()
{
return $"Assets/ProjectSettings/{GetType().Name}.asset";
}
}
internal abstract class ScriptableSettings<T> : ScriptableSettings
where T : ScriptableSettings<T>
{
//################################
// Public Members.
//################################
public static T Instance => _instance ? _instance : _instance = GetOrCreate();
private static T _instance;
protected virtual bool bootOnEditorMode => true;
protected virtual bool bootOnPlayMode => true;
protected abstract void OnBoot();
#if UNITY_EDITOR
//################################
// Private Members.
//################################
private bool enabled;
private static T GetOrCreate()
{
return PlayerSettings.GetPreloadedAssets()
.OfType<T>()
.FirstOrDefault() ?? CreateInstance<T>();
}
private void OnPlayModeStateChanged(PlayModeStateChange state)
{
switch (state)
{
case PlayModeStateChange.EnteredEditMode:
enabled = true;
Boot();
break;
case PlayModeStateChange.ExitingEditMode:
case PlayModeStateChange.ExitingPlayMode:
enabled = false;
break;
}
}
private void Boot()
{
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
var assets = preloadedAssets.OfType<T>().ToArray();
var first = assets.FirstOrDefault() ?? this as T;
// If there are no preloaded assets, registry the first asset.
// If there are multiple preloaded assets, unregisters all but the first one.
if (assets.Length != 1)
{
// The first asset is not saved.
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(first)))
{
if (!AssetDatabase.IsValidFolder("Assets/ProjectSettings"))
AssetDatabase.CreateFolder("Assets", "ProjectSettings");
var assetName = ObjectNames.NicifyVariableName(first.GetType().Name.Replace("ProjectSettings", ""));
var assetPath = AssetDatabase.GenerateUniqueAssetPath($"Assets/ProjectSettings/{assetName}.asset");
AssetDatabase.CreateAsset(first, assetPath);
}
PlayerSettings.SetPreloadedAssets(preloadedAssets
.Where(x => x)
.Except(assets)
.Concat(new[] {first})
.ToArray());
}
// Another asset is registered as a preload asset.
if (first != this)
{
UnityEngine.Debug.LogError($"Another asset '{first}' is registered as a preload '{typeof(T).Name}' asset." +
$"\nThis instance ('{this}') will be ignored. Check 'Project Settings > Player > Preload Assets'", this);
return;
}
_instance = first;
// Do nothing on editor mode.
if (!bootOnEditorMode && !EditorApplication.isPlayingOrWillChangePlaymode)
{
return;
}
// Do nothing on play mode.
if (!bootOnPlayMode && EditorApplication.isPlayingOrWillChangePlaymode)
{
return;
}
OnBoot();
}
//################################
// Unity Callbacks.
//################################
private void OnEnable()
{
enabled = true;
Boot();
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
}
private void OnDisable()
{
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
}
protected virtual void OnValidate()
{
if (enabled)
Boot();
}
#else
private static T GetOrCreate()
{
return CreateInstance<T>();
}
private void OnEnable()
{
if (!bootOnPlayMode) return;
_instance = this as T;
OnBoot();
}
#endif
}
[CustomEditor(typeof(ScriptablePreferenceSettings<>), true)]
internal class ScriptablePreferenceSettingsEditor : Editor
{
private static readonly GUIContent _button = new GUIContent("Open Project Settings");
public override void OnInspectorGUI()
{
if (GUILayout.Button(_button))
{
SettingsService.OpenProjectSettings(((ScriptableSettings) target).GetSettingPath());
}
}
}
internal abstract class ScriptablePreferenceSettings<T> : ScriptableSingleton<T>
where T : ScriptablePreferenceSettings<T>
{
}
#if UNITY_EDITOR
[CustomEditor(typeof(ScriptableSettings), true)]
internal class ScriptableSettingsEditor : Editor
{
private static readonly GUIContent _button = new GUIContent("Open Project Settings");
public override void OnInspectorGUI()
{
if (GUILayout.Button(_button))
{
SettingsService.OpenProjectSettings(((ScriptableSettings) target).GetSettingPath());
}
}
}
internal class ScriptableSettingsProvider<T> : SettingsProvider where T : ScriptableSettings<T>
{
public ScriptableSettingsProvider(string path) : base(path)
{
}
public ScriptableSettingsProvider() : base(ScriptableSettings.GetSettingPath(typeof(T)))
{
}
protected SerializedObject serializedObject { get; private set; }
protected ScriptableSettings<T> target { get; private set; }
public sealed override void OnGUI(string searchContext)
{
if (!target)
{
target = ScriptableSettings<T>.Instance;
serializedObject = new SerializedObject(target);
}
OnGUI();
}
protected virtual void OnGUI()
{
serializedObject.UpdateIfRequiredOrScript();
var iterator = serializedObject.GetIterator();
var enterChildren = true;
while (iterator.NextVisible(enterChildren))
{
if (iterator.propertyPath != "m_Script")
EditorGUILayout.PropertyField(iterator, true);
enterChildren = false;
}
serializedObject.ApplyModifiedProperties();
}
}
internal class ScriptablePreferenceSettingsProvider<T> : SettingsProvider where T : ScriptableSettings<T>
{
public ScriptablePreferenceSettingsProvider(string path) : base(path, SettingsScope.User)
{
}
public ScriptablePreferenceSettingsProvider() : base(ScriptableSettings.GetSettingPath(typeof(T)), SettingsScope.User)
{
}
protected SerializedObject serializedObject { get; private set; }
protected ScriptableSettings<T> target { get; private set; }
public sealed override void OnGUI(string searchContext)
{
if (!target)
{
target = ScriptableSettings<T>.Instance;
serializedObject = new SerializedObject(target);
}
OnGUI();
}
protected virtual void OnGUI()
{
serializedObject.UpdateIfRequiredOrScript();
var iterator = serializedObject.GetIterator();
var enterChildren = true;
while (iterator.NextVisible(enterChildren))
{
if (iterator.propertyPath != "m_Script")
EditorGUILayout.PropertyField(iterator, true);
enterChildren = false;
}
serializedObject.ApplyModifiedProperties();
}
}
#endif
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 6ea9606f69cee413e9f96f52de99fa5e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,4 +1,5 @@
using UnityEngine;
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
@@ -11,12 +12,17 @@ namespace Coffee.NanoMonitor
{
public override void OnGUI(Rect p, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 0, p.width, 16), property.FindPropertyRelative("m_Text"));
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 1, p.width, 16), property.FindPropertyRelative("m_Format"));
var pos = new Rect(p.x, p.y + 18 * 0, p.width, 16);
EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Text"));
pos.y += 18;
EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Format"));
pos.y += 18;
EditorGUI.indentLevel++;
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 2, p.width, 16), property.FindPropertyRelative("m_Arg0"));
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 3, p.width, 16), property.FindPropertyRelative("m_Arg1"));
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 4, p.width, 16), property.FindPropertyRelative("m_Arg2"));
EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Arg0"));
pos.y += 18;
EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Arg1"));
pos.y += 18;
EditorGUI.PropertyField(pos, property.FindPropertyRelative("m_Arg2"));
EditorGUI.indentLevel--;
property.serializedObject.ApplyModifiedProperties();
@@ -29,19 +35,21 @@ namespace Coffee.NanoMonitor
}
#endif
[System.Serializable]
[Serializable]
public class CustomMonitorItem
{
[SerializeField] private MonitorUI m_Text = null;
[SerializeField] private MonitorUI m_Text;
[SerializeField] private string m_Format = "";
[SerializeField] private NumericProperty m_Arg0 = null;
[SerializeField] private NumericProperty m_Arg1 = null;
[SerializeField] private NumericProperty m_Arg2 = null;
[SerializeField] private NumericProperty m_Arg0;
[SerializeField] private NumericProperty m_Arg1;
[SerializeField] private NumericProperty m_Arg2;
public void UpdateText()
{
if (m_Text)
{
m_Text.SetText(m_Format, m_Arg0.Get(), m_Arg1.Get(), m_Arg2.Get());
}
}
}
}

View File

@@ -2,12 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.Serialization;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
namespace Coffee.NanoMonitor
{
@@ -20,39 +16,45 @@ namespace Coffee.NanoMonitor
private static readonly Dictionary<Type, string> s_SupportedTypes = new Dictionary<Type, string>
{
{typeof(bool), "bool"},
{typeof(sbyte), "sbyte"},
{typeof(short), "short"},
{typeof(int), "int"},
{typeof(long), "long"},
{typeof(byte), "byte"},
{typeof(ushort), "ushort"},
{typeof(uint), "uint"},
{typeof(ulong), "ulong"},
{typeof(float), "float"},
{typeof(double), "double"},
{typeof(decimal), "decimal"},
{ typeof(bool), "bool" },
{ typeof(sbyte), "sbyte" },
{ typeof(short), "short" },
{ typeof(int), "int" },
{ typeof(long), "long" },
{ typeof(byte), "byte" },
{ typeof(ushort), "ushort" },
{ typeof(uint), "uint" },
{ typeof(ulong), "ulong" },
{ typeof(float), "float" },
{ typeof(double), "double" },
{ typeof(decimal), "decimal" }
};
private static void Init()
{
if (s_PropertyMenu != null) return;
const BindingFlags bindingFlags = BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Static
| BindingFlags.GetProperty;
var properties = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes())
.SelectMany(type => type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetProperty))
.SelectMany(type => type.GetProperties(bindingFlags))
.Where(pi => pi.GetMethod != null && s_SupportedTypes.ContainsKey(pi.PropertyType))
.OrderBy(pi => ConvertToMenuItem(pi, false))
.ToArray();
s_PropertyMenu = new GenericMenu();
s_PropertyMenu.AddItem(new GUIContent("No Property"), false, arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), null);
s_PropertyMenu.AddItem(new GUIContent("(Non Public Properties)/"), false, ()=>{});
s_PropertyMenu.AddItem(new GUIContent("No Property"), false,
arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), null);
s_PropertyMenu.AddItem(new GUIContent("(Non Public Properties)/"), false, () => { });
s_PropertyMenu.AddSeparator("");
foreach (var pi in properties)
{
s_PropertyMenu.AddItem(new GUIContent(ConvertToMenuItem(pi, true)), false, arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), pi);
s_PropertyMenu.AddItem(new GUIContent(ConvertToMenuItem(pi, true)), false,
arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), pi);
}
}
@@ -60,11 +62,17 @@ namespace Coffee.NanoMonitor
{
var type = p.DeclaringType;
if (type == null) return "";
var category = p.GetMethod.IsPublic && type.IsPublic ? "" : "(Non Public Properties)/";
var category = p.GetMethod.IsPublic && type.IsPublic
? ""
: "(Non Public Properties)/";
var typeName = type.FullName;
var asmName = type.Assembly.GetName().Name;
if (asmName == "UnityEngine.CoreModule")
{
asmName = "UnityEngine";
}
return propertyType
? $"{category}{asmName}/{typeName}/{s_SupportedTypes[p.PropertyType]} {p.Name}"
: $"{category}{asmName}/{typeName}/{p.Name}";
@@ -84,7 +92,9 @@ namespace Coffee.NanoMonitor
{
s_OnMenuSelected = p =>
{
path.stringValue = p == null ? "" : $"{p.DeclaringType?.FullName}, {p.DeclaringType?.Assembly.GetName().Name};{p.Name}";
path.stringValue = p == null
? ""
: $"{p.DeclaringType?.FullName}, {p.DeclaringType?.Assembly.GetName().Name};{p.Name}";
property.serializedObject.ApplyModifiedProperties();
};
s_PropertyMenu.DropDown(position);
@@ -104,6 +114,22 @@ namespace Coffee.NanoMonitor
[SerializeField] private string m_Path = "";
//################################
// Private Members.
//################################
private Func<double> _get;
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
var pInfo = GetPropertyInfo(m_Path);
_get = CreateFunc(pInfo?.GetMethod);
}
//################################
// Public Members.
//################################
@@ -112,12 +138,6 @@ namespace Coffee.NanoMonitor
return _get?.Invoke() ?? -1;
}
//################################
// Private Members.
//################################
private Func<double> _get = null;
private static PropertyInfo GetPropertyInfo(string path)
{
var p = path.Split(';');
@@ -126,14 +146,14 @@ namespace Coffee.NanoMonitor
var type = Type.GetType(p[0]);
if (type == null)
{
UnityEngine.Debug.LogException(new Exception($"Type '{p[0]}' is not found"));
Debug.LogException(new Exception($"Type '{p[0]}' is not found"));
return null;
}
var pInfo = type.GetProperty(p[1], BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static);
if (pInfo == null)
{
UnityEngine.Debug.LogException(new Exception($"Member '{p[1]}' is not found in type '{type}'"));
Debug.LogException(new Exception($"Member '{p[1]}' is not found in type '{type}'"));
}
return pInfo;
@@ -145,55 +165,72 @@ namespace Coffee.NanoMonitor
switch (Type.GetTypeCode(mInfo.ReturnType))
{
case TypeCode.Boolean:
var f_bool = (Func<bool>) mInfo.CreateDelegate(typeof(Func<bool>));
return () => f_bool() ? 1 : 0;
{
var func = (Func<bool>)mInfo.CreateDelegate(typeof(Func<bool>));
return () => func() ? 1 : 0;
}
case TypeCode.Byte:
var f_byte = (Func<byte>) mInfo.CreateDelegate(typeof(Func<byte>));
return () => f_byte();
{
var func = (Func<byte>)mInfo.CreateDelegate(typeof(Func<byte>));
return () => func();
}
case TypeCode.SByte:
var f_sbyte = (Func<sbyte>) mInfo.CreateDelegate(typeof(Func<sbyte>));
return () => f_sbyte();
{
var func = (Func<sbyte>)mInfo.CreateDelegate(typeof(Func<sbyte>));
return () => func();
}
case TypeCode.UInt16:
var f_ushort = (Func<ushort>) mInfo.CreateDelegate(typeof(Func<ushort>));
return () => f_ushort();
{
var func = (Func<ushort>)mInfo.CreateDelegate(typeof(Func<ushort>));
return () => func();
}
case TypeCode.UInt32:
var f_uint = (Func<uint>) mInfo.CreateDelegate(typeof(Func<uint>));
return () => f_uint();
{
var func = (Func<uint>)mInfo.CreateDelegate(typeof(Func<uint>));
return () => func();
}
case TypeCode.UInt64:
var f_ulong = (Func<ulong>) mInfo.CreateDelegate(typeof(Func<ulong>));
return () => f_ulong();
{
var func = (Func<ulong>)mInfo.CreateDelegate(typeof(Func<ulong>));
return () => func();
}
case TypeCode.Int16:
var f_short = (Func<short>) mInfo.CreateDelegate(typeof(Func<short>));
return () => f_short();
{
var func = (Func<short>)mInfo.CreateDelegate(typeof(Func<short>));
return () => func();
}
case TypeCode.Int32:
var f_int = (Func<int>) mInfo.CreateDelegate(typeof(Func<int>));
return () => f_int();
{
var f = (Func<int>)mInfo.CreateDelegate(typeof(Func<int>));
return () => f();
}
case TypeCode.Int64:
var f_long = (Func<long>) mInfo.CreateDelegate(typeof(Func<long>));
return () => f_long();
{
var f = (Func<long>)mInfo.CreateDelegate(typeof(Func<long>));
return () => f();
}
case TypeCode.Decimal:
var f_decimal = (Func<decimal>) mInfo.CreateDelegate(typeof(Func<decimal>));
return () => (double) f_decimal();
{
var f = (Func<decimal>)mInfo.CreateDelegate(typeof(Func<decimal>));
return () => (double)f();
}
case TypeCode.Double:
var f_double = (Func<double>) mInfo.CreateDelegate(typeof(Func<double>));
return f_double;
{
var f = (Func<double>)mInfo.CreateDelegate(typeof(Func<double>));
return f;
}
case TypeCode.Single:
var f_float = (Func<float>) mInfo.CreateDelegate(typeof(Func<float>));
return () => f_float();
{
var f = (Func<float>)mInfo.CreateDelegate(typeof(Func<float>));
return () => f();
}
default:
UnityEngine.Debug.LogException(new Exception(string.Format("Method '{1}.{0}' is not supported.", mInfo.Name, mInfo.DeclaringType)));
{
var message = $"Method '{mInfo.DeclaringType}.{mInfo.Name} ({mInfo.ReturnType})' is not supported.";
Debug.LogException(new Exception(message));
return null;
}
}
}
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
var pInfo = GetPropertyInfo(m_Path);
_get = CreateFunc(pInfo?.GetMethod);
}
}
}

View File

@@ -21,7 +21,8 @@ namespace Coffee.NanoMonitor
return true;
}
public static void AppendFormatNoAlloc(this StringBuilder sb, string format, double arg0 = 0, double arg1 = 0, double arg2 = 0, double arg3 = 0)
public static void AppendFormatNoAlloc(this StringBuilder sb, string format, double arg0 = 0, double arg1 = 0,
double arg2 = 0, double arg3 = 0)
{
for (var i = 0; i < format.Length; i++)
{
@@ -56,7 +57,7 @@ namespace Coffee.NanoMonitor
}
}
internal static void AppendInteger(this StringBuilder sb, double number, int padding, int precision, int alignment)
private static void AppendInteger(this StringBuilder sb, double number, int padding, int alignment)
{
number = Math.Truncate(number);
var sign = number < 0;
@@ -68,8 +69,8 @@ namespace Coffee.NanoMonitor
var n = Math.Truncate(number % 10);
number /= 10;
sb.Append((char) (n + 48));
} while (1 <= number || (sb.Length - startIndex) < padding);
sb.Append((char)(n + 48));
} while (1 <= number || sb.Length - startIndex < padding);
if (sign)
{
@@ -82,11 +83,12 @@ namespace Coffee.NanoMonitor
sb.Alignment(alignment, startIndex, endIndex);
}
internal static void AppendDouble(this StringBuilder sb, double number, int padding, int precision, int alignment)
private static void AppendDouble(this StringBuilder sb, double number, int padding, int precision,
int alignment)
{
var integer = Math.Truncate(number);
var startIndex = sb.Length;
sb.AppendInteger(integer, padding, precision, 0);
sb.AppendInteger(integer, padding, 0);
if (0 < precision)
{
@@ -96,8 +98,8 @@ namespace Coffee.NanoMonitor
for (var p = 0; p < precision; p++)
{
number *= 10;
integer = (long) number;
sb.Append((char) (integer + 48));
integer = (long)number;
sb.Append((char)(integer + 48));
number -= integer;
number = Math.Round(number, precision);
}
@@ -106,20 +108,18 @@ namespace Coffee.NanoMonitor
sb.Alignment(alignment, startIndex, sb.Length - 1);
}
internal static void Reverse(this StringBuilder sb, int start, int end)
private static void Reverse(this StringBuilder sb, int start, int end)
{
while (start < end)
{
var c = sb[start];
sb[start] = sb[end];
sb[end] = c;
// swap
(sb[start], sb[end]) = (sb[end], sb[start]);
start++;
end--;
}
}
internal static void Alignment(this StringBuilder sb, int alignment, int start, int end)
private static void Alignment(this StringBuilder sb, int alignment, int start, int end)
{
if (alignment == 0) return;
@@ -129,9 +129,8 @@ namespace Coffee.NanoMonitor
sb.Append(' ', alignment - len);
for (var i = 0; i < len; i++)
{
var c = sb[end - i];
sb[end - i] = sb[start + alignment - i - 1];
sb[start + alignment - i - 1] = c;
// swap
(sb[end - i], sb[start + alignment - i - 1]) = (sb[start + alignment - i - 1], sb[end - i]);
}
}
else if (alignment < 0 && len < -alignment)
@@ -140,7 +139,8 @@ namespace Coffee.NanoMonitor
}
}
internal static int GetFormat(string format, int i, out int argIndex, out int padding, out int precision, out int alignment)
private static int GetFormat(string format, int i, out int argIndex, out int padding, out int precision,
out int alignment)
{
argIndex = -1;
padding = 0;