feat: Ping/Traffic/FPS Graphs (#3897)

* wip shader

* line graph, abstract base + fps graph

* canvas scaler

* Network usage graph + line graph tweaks

* ping graph

* undo tank scene changes

* using cleanup

* unity 2019 prefabs

* code style

* naming & naming rule tweaks

* implicit private

* explicit type in new()

* No braces if not needed

* also for for-loops (and all other constructs)

* don't enforce blank lines, bit odd sometimes

* Naming/commenting/material diagnostic

* 2019 mats

* mirror icon on scripts
This commit is contained in:
Robin Rolf 2024-09-23 18:47:20 +01:00 committed by GitHub
parent 927bdccf6e
commit 682bba2509
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 7544 additions and 225 deletions

View File

@ -1,141 +1,181 @@
###############################
# Core EditorConfig Options #
###############################
root = true root = true
[*.{cs,csx,vb,vbx,md}] ###############################
indent_style = space # Core EditorConfig Options #
indent_size = 4 ###############################
insert_final_newline = true [*.{cs,csx,vb,vbx,md}]
indent_style = space
indent_size = 4
insert_final_newline = true
charset = utf-8 charset = utf-8
[*.md] [*.md]
trim_trailing_whitespace = false trim_trailing_whitespace = false
# Code files # Code files
[*.{cs,csx,vb,vbx}] [*.{cs,csx,vb,vbx}]
trim_trailing_whitespace = true trim_trailing_whitespace = true
############################### ###############################
# .NET Coding Conventions # # .NET Coding Conventions #
############################### ###############################
[*.{cs,vb}] [*.{cs,vb}]
# Organize usings # Organize usings
dotnet_sort_system_directives_first = true dotnet_sort_system_directives_first = true
# this. preferences # this. preferences
dotnet_style_qualification_for_field = false:silent dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:silent dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:silent dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:silent dotnet_style_qualification_for_event = false:suggestion
# Language keywords vs BCL types preferences # Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:silent dotnet_style_predefined_type_for_member_access = true:suggestion
# Parentheses preferences # Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
# Modifier preferences # Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
dotnet_style_readonly_field = true:suggestion dotnet_style_readonly_field = true:suggestion
# Code-block preferences # Code-block preferences
csharp_prefer_braces = when_multiline:suggestion csharp_prefer_braces = when_multiline:suggestion
csharp_prefer_simple_using_statement = false:suggestion csharp_prefer_simple_using_statement = false:suggestion
# Expression-level preferences # Expression-level preferences
dotnet_style_object_initializer = true:suggestion dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_prefer_inferred_tuple_names = true:suggestion dotnet_prefer_inferred_tuple_names = true:suggestion
dotnet_prefer_inferred_anonymous_type_member_names = true:suggestion dotnet_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:silent dotnet_style_prefer_auto_properties = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = true:silent dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
dotnet_style_prefer_conditional_expression_over_return = true:silent dotnet_style_prefer_conditional_expression_over_return = true:suggestion
############################### ###############################
# Naming Conventions # # Naming Conventions #
############################### ###############################
# Style Definitions # Style Definitions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# Use PascalCase for constant fields # Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field dotnet_naming_symbols.constant_fields.applicable_kinds = *
dotnet_naming_symbols.constant_fields.applicable_accessibilities = * dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const dotnet_naming_symbols.constant_fields.required_modifiers = const
# Methods are PascalCase
dotnet_naming_rule.method_should_be_pascal_case.severity = suggestion dotnet_naming_rule.method_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.method_should_be_pascal_case.symbols = method dotnet_naming_rule.method_should_be_pascal_case.symbols = method
dotnet_naming_rule.method_should_be_pascal_case.style = pascal_case_style dotnet_naming_rule.method_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.method.applicable_kinds = method dotnet_naming_symbols.method.applicable_kinds = method
dotnet_naming_symbols.method.applicable_accessibilities = * dotnet_naming_symbols.method.applicable_accessibilities = *
dotnet_naming_symbols.method.required_modifiers = dotnet_naming_symbols.method.required_modifiers =
###############################
# C# Coding Conventions # # Private instance fields are camelCase
############################### dotnet_naming_symbols.private_fields.applicable_kinds = field
[*.cs] dotnet_naming_symbols.private_fields.applicable_accessibilities = private
# var preferences dotnet_naming_symbols.private_fields.required_modifiers =
csharp_style_var_for_built_in_types = false:suggestion dotnet_naming_style.lower_case.capitalization = camel_case
csharp_style_var_when_type_is_apparent = false:suggestion dotnet_naming_style.lower_case.required_prefix =
csharp_style_var_elsewhere = false:suggestion dotnet_naming_style.lower_case.required_suffix =
# Expression-bodied members dotnet_naming_rule.private_fields_underscore_lower_case.symbols = private_fields
csharp_style_expression_bodied_methods = false:silent dotnet_naming_rule.private_fields_underscore_lower_case.style = lower_case
csharp_style_expression_bodied_constructors = false:silent dotnet_naming_rule.private_fields_underscore_lower_case.severity = warning
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent # Static fields are PascalCase
csharp_style_expression_bodied_indexers = true:silent dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion
csharp_style_expression_bodied_accessors = true:silent dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
# Pattern matching preferences dotnet_naming_rule.static_fields_should_be_camel_case.style = pascal_case_style
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion dotnet_naming_symbols.static_fields.applicable_kinds = field
# Null-checking preferences dotnet_naming_symbols.static_fields.required_modifiers = static
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion ###############################
# Modifier preferences # C# Coding Conventions #
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion ###############################
# Expression-level preferences [*.cs]
csharp_prefer_braces = true:silent # var preferences
csharp_style_deconstructed_variable_declaration = true:suggestion csharp_style_var_for_built_in_types = false:suggestion
csharp_prefer_simple_default_expression = true:suggestion csharp_style_var_when_type_is_apparent = false:suggestion
csharp_style_pattern_local_over_anonymous_function = true:suggestion csharp_style_var_elsewhere = false:suggestion
csharp_style_inlined_variable_declaration = true:suggestion # Expression-bodied members
############################### csharp_style_expression_bodied_methods = true:suggestion
# C# Formatting Rules # csharp_style_expression_bodied_constructors = false:suggestion
############################### csharp_style_expression_bodied_operators = false:suggestion
# New line preferences csharp_style_expression_bodied_properties = true:suggestion
csharp_new_line_before_open_brace = all csharp_style_expression_bodied_indexers = true:suggestion
csharp_new_line_before_else = true csharp_style_expression_bodied_accessors = true:suggestion
csharp_new_line_before_catch = true # Pattern matching preferences
csharp_new_line_before_finally = true csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_new_line_before_members_in_object_initializers = true csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_new_line_before_members_in_anonymous_types = true # Null-checking preferences
csharp_new_line_between_query_expression_clauses = true csharp_style_throw_expression = true:suggestion
# Indentation preferences csharp_style_conditional_delegate_call = true:suggestion
csharp_indent_case_contents = true # Modifier preferences
csharp_indent_switch_labels = true csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async:suggestion
csharp_indent_labels = flush_left # Expression-level preferences
# Space preferences csharp_prefer_braces = true:suggestion
csharp_space_after_cast = false csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_space_after_keywords_in_control_flow_statements = true csharp_prefer_simple_default_expression = true:suggestion
csharp_space_between_method_call_parameter_list_parentheses = false csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_style_inlined_variable_declaration = true:suggestion
csharp_space_between_parentheses = false ###############################
csharp_space_before_colon_in_inheritance_clause = true # C# Formatting Rules #
csharp_space_after_colon_in_inheritance_clause = true ###############################
csharp_space_around_binary_operators = before_and_after # New line preferences
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false csharp_new_line_before_open_brace = all
csharp_space_between_method_call_name_and_opening_parenthesis = false csharp_new_line_before_else = true
csharp_space_between_method_call_empty_parameter_list_parentheses = false csharp_new_line_before_catch = true
# Wrapping preferences csharp_new_line_before_finally = true
csharp_preserve_single_line_statements = true csharp_new_line_before_members_in_object_initializers = true
csharp_preserve_single_line_blocks = true csharp_new_line_before_members_in_anonymous_types = true
############################### csharp_new_line_between_query_expression_clauses = true
# VB Coding Conventions # # Indentation preferences
############################### csharp_indent_case_contents = true
[*.vb] csharp_indent_switch_labels = true
# Modifier preferences csharp_indent_labels = flush_left
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion # Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
# ReSharper properties
resharper_blank_lines_around_invocable = 1
resharper_blank_lines_around_type = 1
resharper_braces_for_for = not_required
resharper_braces_for_dowhile = not_required
resharper_braces_for_fixed = not_required
resharper_braces_for_lock = not_required
resharper_braces_for_using = not_required
resharper_braces_for_while = not_required
resharper_braces_for_foreach = not_required
resharper_braces_for_ifelse = not_required
resharper_braces_redundant = true
resharper_default_private_modifier = implicit
resharper_object_creation_when_type_evident = explicitly_typed
resharper_place_simple_initializer_on_single_line = true
resharper_remove_blank_lines_near_braces_in_code = true
resharper_remove_blank_lines_near_braces_in_declarations = true
###############################
# VB Coding Conventions #
###############################
[*.vb]
# Modifier preferences
visual_basic_preferred_modifier_order = Partial, Default, Private, Protected, Public, Friend, NotOverridable, Overridable, MustOverride, Overloads, Overrides, MustInherit, NotInheritable, Static, Shared, Shadows, ReadOnly, WriteOnly, Dim, Const, WithEvents, Widening, Narrowing, Custom, Async:suggestion
[*.yml] [*.yml]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4b799e47369048fcb1604e5b3e7d71cf
timeCreated: 1724245584

View File

@ -0,0 +1,217 @@
using System;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
namespace Mirror
{
public enum GraphAggregationMode
{
Sum,
Average,
PerSecond,
Min,
Max
}
public abstract class BaseUIGraph : MonoBehaviour
{
static readonly int MaxValue = Shader.PropertyToID("_MaxValue");
static readonly int GraphData = Shader.PropertyToID("_GraphData");
static readonly int CategoryCount = Shader.PropertyToID("_CategoryCount");
static readonly int Colors = Shader.PropertyToID("_CategoryColors");
static readonly int Width = Shader.PropertyToID("_Width");
static readonly int DataStart = Shader.PropertyToID("_DataStart");
public Material Material;
public Graphic Renderer;
[Range(1, 64)]
public int Points = 64;
public float SecondsPerPoint = 1;
public Color[] CategoryColors = new[] { Color.cyan };
public bool IsStacked;
public Text[] LegendTexts;
[Header("Diagnostics")]
[ReadOnly, SerializeField]
Material runtimeMaterial;
float[] graphData;
// graphData is a circular buffer, this is the offset to get the 0-index
int graphDataStartIndex;
// Is graphData dirty and needs to be set to the material
bool isGraphDataDirty;
// currently aggregating data to be added to the graph soon
float[] aggregatingData;
GraphAggregationMode[] aggregatingModes;
// Counts for avg aggregation mode
int[] aggregatingDataCounts;
// How much time has elapsed since the last aggregation finished
float aggregatingTime;
int DataLastIndex => (graphDataStartIndex - 1 + Points) % Points;
void Awake()
{
Renderer.material = runtimeMaterial = Instantiate(Material);
graphData = new float[Points * CategoryColors.Length];
aggregatingData = new float[CategoryColors.Length];
aggregatingDataCounts = new int[CategoryColors.Length];
aggregatingModes = new GraphAggregationMode[CategoryColors.Length];
isGraphDataDirty = true;
}
protected virtual void OnValidate()
{
if (Renderer == null)
Renderer = GetComponent<Graphic>();
}
protected virtual void Update()
{
for (int i = 0; i < CategoryColors.Length; i++)
{
CollectData(i, out float value, out GraphAggregationMode mode);
// we probably don't need negative values, so lets skip supporting it
if (value < 0)
{
Debug.LogWarning("Graphing negative values is not supported.");
value = 0;
}
if (mode != aggregatingModes[i])
{
aggregatingModes[i] = mode;
ResetCurrent(i);
}
switch (mode)
{
case GraphAggregationMode.Average:
case GraphAggregationMode.Sum:
case GraphAggregationMode.PerSecond:
aggregatingData[i] += value;
aggregatingDataCounts[i]++;
break;
case GraphAggregationMode.Min:
if (aggregatingData[i] > value)
aggregatingData[i] = value;
break;
case GraphAggregationMode.Max:
if (value > aggregatingData[i])
aggregatingData[i] = value;
break;
default:
throw new ArgumentOutOfRangeException();
}
}
aggregatingTime += Time.deltaTime;
if (aggregatingTime > SecondsPerPoint)
{
graphDataStartIndex = (graphDataStartIndex + 1) % Points;
ClearDataAt(DataLastIndex);
for (int i = 0; i < CategoryColors.Length; i++)
{
float value = aggregatingData[i];
switch (aggregatingModes[i])
{
case GraphAggregationMode.Sum:
case GraphAggregationMode.Min:
case GraphAggregationMode.Max:
// do nothing!
break;
case GraphAggregationMode.Average:
value /= aggregatingDataCounts[i];
break;
case GraphAggregationMode.PerSecond:
value /= aggregatingTime;
break;
default:
throw new ArgumentOutOfRangeException();
}
SetCurrentGraphData(i, value);
ResetCurrent(i);
}
aggregatingTime = 0;
}
}
void ResetCurrent(int i)
{
switch (aggregatingModes[i])
{
case GraphAggregationMode.Min:
aggregatingData[i] = float.MaxValue;
break;
default:
aggregatingData[i] = 0;
break;
}
aggregatingDataCounts[i] = 0;
}
protected virtual string FormatValue(float value) => $"{value:N1}";
protected abstract void CollectData(int category, out float value, out GraphAggregationMode mode);
void SetCurrentGraphData(int c, float value)
{
graphData[DataLastIndex * CategoryColors.Length + c] = value;
isGraphDataDirty = true;
}
void ClearDataAt(int i)
{
for (int c = 0; c < CategoryColors.Length; c++)
graphData[i * CategoryColors.Length + c] = 0;
isGraphDataDirty = true;
}
public void LateUpdate()
{
if (isGraphDataDirty)
{
runtimeMaterial.SetInt(Width, Points);
runtimeMaterial.SetInt(DataStart, graphDataStartIndex);
float max = 1;
if (IsStacked)
for (int x = 0; x < Points; x++)
{
float total = 0;
for (int c = 0; c < CategoryColors.Length; c++)
total += graphData[x * CategoryColors.Length + c];
if (total > max)
max = total;
}
else
for (int i = 0; i < graphData.Length; i++)
{
float v = graphData[i];
if (v > max)
max = v;
}
max = AdjustMaxValue(max);
for (int i = 0; i < LegendTexts.Length; i++)
{
Text legendText = LegendTexts[i];
float pct = (float)i / (LegendTexts.Length - 1);
legendText.text = FormatValue(max * pct);
}
runtimeMaterial.SetFloat(MaxValue, max);
runtimeMaterial.SetFloatArray(GraphData, graphData);
runtimeMaterial.SetInt(CategoryCount, CategoryColors.Length);
runtimeMaterial.SetColorArray(Colors, CategoryColors);
isGraphDataDirty = false;
}
}
protected virtual float AdjustMaxValue(float max) => Mathf.Ceil(max);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0f7dbe0fe96842f3b3ec76d05d2bb24a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,40 @@
using System;
using UnityEngine;
namespace Mirror
{
public class FpsMinMaxAvgGraph : BaseUIGraph
{
protected override void CollectData(int category, out float value, out GraphAggregationMode mode)
{
value = 1 / Time.deltaTime;
switch (category)
{
case 0:
mode = GraphAggregationMode.Average;
break;
case 1:
mode = GraphAggregationMode.Min;
break;
case 2:
mode = GraphAggregationMode.Max;
break;
default:
throw new ArgumentOutOfRangeException($"{category} is not valid.");
}
}
protected override void OnValidate()
{
base.OnValidate();
if (CategoryColors.Length != 3)
CategoryColors = new[]
{
Color.cyan, // avg
Color.red, // min
Color.green // max
};
IsStacked = false;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 73bc3b929ec94537a8dbd67eb9d0c2c6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,89 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: LineGraph
m_Shader: {fileID: 4800000, guid: e9fd6820072746bbaa3a83a449c31709, type: 3}
m_ShaderKeywords:
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
- _BumpScale: 1
- _CategoryCount: 0
- _ColorMask: 15
- _Cutoff: 0.5
- _DataStart: 0
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _LineWidth: 1
- _MaxValue: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _Stencil: 0
- _StencilComp: 8
- _StencilOp: 0
- _StencilReadMask: 255
- _StencilWriteMask: 255
- _UVSec: 0
- _UseUIAlphaClip: 0
- _Width: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5f77111e39fad6240bbf2a93d735b648
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,178 @@
Shader "Mirror/NetworkGraphLines"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
_Width ("Width", Int) = 0
_LineWidth ("Line Width", Float) = 0.005
_CategoryCount ("CategoryCount", Int) = 0
_MaxValue ("MaxValue", Float) = 1
_DataStart ("DataStart", Int) = 0
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
_StencilReadMask ("Stencil Read Mask", Float) = 255
_ColorMask ("Color Mask", Float) = 15
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Stencil
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
Cull Off
Lighting Off
ZWrite Off
ZTest [unity_GUIZTestMode]
Blend SrcAlpha OneMinusSrcAlpha
ColorMask [_ColorMask]
Pass
{
Name "Default"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#pragma multi_compile_local _ UNITY_UI_CLIP_RECT
#pragma multi_compile_local _ UNITY_UI_ALPHACLIP
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
sampler2D _MainTex; // we dont use this, but unitys ui library expects the shader to have a texture
fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
float4 _MainTex_ST;
uint _Width;
half _LineWidth;
uint _CategoryCount;
uint _MaxValue;
uint _DataStart;
half _GraphData[64 /* max. 128 points */ * 8 /* max 8 categories */];
half4 _CategoryColors[8 /* max 8 categories */];
v2f vert(appdata_t v)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
OUT.worldPosition = v.vertex;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
OUT.color = v.color * _Color;
return OUT;
}
// Helper function to calculate the shortest distance from a point (p) to a line segment (from a to b)
float distanceToLineSegment(float2 p, float2 a, float2 b)
{
float2 ab = b - a;
float2 ap = p - a;
float t = saturate(dot(ap, ab) / dot(ab, ab));
// Clamp t between 0 and 1 to ensure we stay within the segment
float2 closestPoint = a + t * ab; // Find the closest point on the line segment
return length(p - closestPoint); // Return the distance from p to the closest point on the line
}
fixed4 frag(v2f IN) : SV_Target
{
uint wCur = (uint)(IN.texcoord.x * _Width);
uint wMin = wCur == 0 ? 0 : wCur - 1;
uint wMax = wCur == _Width - 1 ? wCur : wCur + 1;
float2 screenSize = _ScreenParams.xy;
// this scaling only works if the object is flat and not rotated - but thats fine
float2 pixelScale = float2(1 / ddx(IN.texcoord.x), 1 / ddy(IN.texcoord.y));
float2 screenSpaceUV = IN.texcoord * pixelScale;
half4 color = half4(0, 0, 0, 0);
// Loop through the graph's points
bool colored = false;
for (uint wNonOffset = wMin; wNonOffset < wMax && !colored; wNonOffset++)
{
uint w = (wNonOffset + _DataStart) % _Width;
// previous entry, unless it's the start, then we clamp to start
uint nextW = (w + 1) % _Width;
float texPosCurrentX = float(wNonOffset) / _Width;
float texPosPrevX = texPosCurrentX + 1.0f / _Width;
for (uint c = 0; c < _CategoryCount; c++)
{
float categoryValueCurrent = _GraphData[w * _CategoryCount + c] / _MaxValue;
float categoryValueNext = _GraphData[nextW * _CategoryCount + c] / _MaxValue;
float2 pointCurrent = float2(texPosCurrentX, categoryValueCurrent);
float2 pointNext = float2(texPosPrevX, categoryValueNext);
float distance = distanceToLineSegment(screenSpaceUV, pointCurrent * pixelScale,
pointNext * pixelScale);
if (distance < _LineWidth)
{
color = _CategoryColors[c];
colored = true;
break;
}
}
}
color *= IN.color;
#ifdef UNITY_UI_CLIP_RECT
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#endif
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e9fd6820072746bbaa3a83a449c31709
timeCreated: 1725809505

View File

@ -0,0 +1,138 @@
Shader "Mirror/NetworkGraphStacked"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
_Width ("Width", Int) = 0
_CategoryCount ("CategoryCount", Int) = 0
_MaxValue ("MaxValue", Float) = 1
_DataStart ("DataStart", Int) = 0
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
_StencilReadMask ("Stencil Read Mask", Float) = 255
_ColorMask ("Color Mask", Float) = 15
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Stencil
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
Cull Off
Lighting Off
ZWrite Off
ZTest [unity_GUIZTestMode]
Blend SrcAlpha OneMinusSrcAlpha
ColorMask [_ColorMask]
Pass
{
Name "Default"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#pragma multi_compile_local _ UNITY_UI_CLIP_RECT
#pragma multi_compile_local _ UNITY_UI_ALPHACLIP
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
sampler2D _MainTex; // we dont use this, but unitys ui library expects the shader to have a texture
fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
float4 _MainTex_ST;
uint _Width;
uint _CategoryCount;
uint _MaxValue;
uint _DataStart;
half _GraphData[64 /* max. 64 points */ * 8 /* max 8 categories */];
half4 _CategoryColors[8 /* max 8 categories */];
v2f vert(appdata_t v)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
OUT.worldPosition = v.vertex;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
OUT.color = v.color * _Color;
return OUT;
}
fixed4 frag(v2f IN) : SV_Target
{
uint w = ((uint)(IN.texcoord.x * _Width) + _DataStart) % _Width;
half4 color = half4(0, 0, 0, 0);
float totalValue = 0;
for (uint c = 0; c < _CategoryCount; c++)
{
float categoryValue = _GraphData[w * _CategoryCount + c] / _MaxValue;
totalValue += categoryValue;
if (totalValue >= IN.texcoord.y)
{
color = _CategoryColors[c];
break;
}
}
color *= IN.color;
#ifdef UNITY_UI_CLIP_RECT
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#endif
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b5b24284f35f4992bcd4cc43919267d7
timeCreated: 1724246251

View File

@ -0,0 +1,34 @@
using System;
using UnityEngine;
namespace Mirror
{
public class NetworkPingGraph : BaseUIGraph
{
protected override void CollectData(int category, out float value, out GraphAggregationMode mode)
{
mode = GraphAggregationMode.Average;
switch (category)
{
case 0:
value = (float)NetworkTime.rtt * 1000f;
break;
case 1:
value = (float)NetworkTime.rttVariance * 1000f;
break;
default:
throw new ArgumentOutOfRangeException($"{category} is not valid.");
}
}
protected override string FormatValue(float value) => $"{value:N0}ms";
protected override void OnValidate()
{
base.OnValidate();
if (CategoryColors.Length != 2)
CategoryColors = new[] { Color.cyan, Color.yellow };
IsStacked = false;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 14a68afedbbf4568b0decc5c3fe6dfd9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -14,10 +14,15 @@ public class NetworkRuntimeProfiler : MonoBehaviour
public class Sorter : IComparer<Stat> public class Sorter : IComparer<Stat>
{ {
public SortBy Order; public SortBy Order;
public int Compare(Stat a, Stat b) public int Compare(Stat a, Stat b)
{ {
if (a == null) return 1; if (a == null)
if (b == null) return -1; return 1;
if (b == null)
return -1;
// Compare B to A for desc order // Compare B to A for desc order
switch (Order) switch (Order)
{ {
@ -40,7 +45,7 @@ public enum SortBy
RecentBytes, RecentBytes,
RecentCount, RecentCount,
TotalBytes, TotalBytes,
TotalCount, TotalCount
} }
public class Stat public class Stat
@ -60,21 +65,21 @@ public void ResetRecent()
public void Add(int count, int bytes) public void Add(int count, int bytes)
{ {
this.TotalBytes += bytes; TotalBytes += bytes;
this.TotalCount += count; TotalCount += count;
this.RecentBytes += bytes; RecentBytes += bytes;
this.RecentCount += count; RecentCount += count;
} }
} }
public class MessageStats class MessageStats
{ {
public Dictionary<Type, Stat> MessageByType = new Dictionary<Type, Stat>(); public readonly Dictionary<Type, Stat> MessageByType = new Dictionary<Type, Stat>();
public Dictionary<ushort, Stat> RpcByHash = new Dictionary<ushort, Stat>(); public readonly Dictionary<ushort, Stat> RpcByHash = new Dictionary<ushort, Stat>();
public void Record(NetworkDiagnostics.MessageInfo info) public void Record(NetworkDiagnostics.MessageInfo info)
{ {
Type type = info.message.GetType(); Type type = info.message.GetType();
if (!MessageByType.TryGetValue(type, out Stat stat)) if (!MessageByType.TryGetValue(type, out Stat stat))
{ {
@ -86,30 +91,27 @@ public void Record(NetworkDiagnostics.MessageInfo info)
RecentCount = 0, RecentCount = 0,
RecentBytes = 0 RecentBytes = 0
}; };
MessageByType[type] = stat; MessageByType[type] = stat;
} }
stat.Add(info.count, info.bytes * info.count); stat.Add(info.count, info.bytes * info.count);
if (info.message is CommandMessage cmd) if (info.message is CommandMessage cmd)
{
RecordRpc(cmd.functionHash, info); RecordRpc(cmd.functionHash, info);
}
else if (info.message is RpcMessage rpc) else if (info.message is RpcMessage rpc)
{
RecordRpc(rpc.functionHash, info); RecordRpc(rpc.functionHash, info);
}
} }
private void RecordRpc(ushort hash, NetworkDiagnostics.MessageInfo info) void RecordRpc(ushort hash, NetworkDiagnostics.MessageInfo info)
{ {
if (!RpcByHash.TryGetValue(hash, out Stat stat)) if (!RpcByHash.TryGetValue(hash, out Stat stat))
{ {
string name = "n/a"; string name = "n/a";
RemoteCallDelegate rpcDelegate = RemoteProcedureCalls.GetDelegate(hash); RemoteCallDelegate rpcDelegate = RemoteProcedureCalls.GetDelegate(hash);
if (rpcDelegate != null) if (rpcDelegate != null)
{
name = $"{rpcDelegate.Method.DeclaringType}.{rpcDelegate.GetMethodName().Replace(RemoteProcedureCalls.InvokeRpcPrefix, "")}"; name = $"{rpcDelegate.Method.DeclaringType}.{rpcDelegate.GetMethodName().Replace(RemoteProcedureCalls.InvokeRpcPrefix, "")}";
}
stat = new Stat stat = new Stat
{ {
Name = name, Name = name,
@ -118,108 +120,93 @@ private void RecordRpc(ushort hash, NetworkDiagnostics.MessageInfo info)
RecentCount = 0, RecentCount = 0,
RecentBytes = 0 RecentBytes = 0
}; };
RpcByHash[hash] = stat; RpcByHash[hash] = stat;
} }
stat.Add(info.count, info.bytes * info.count); stat.Add(info.count, info.bytes * info.count);
} }
public void ResetRecent() public void ResetRecent()
{ {
foreach (Stat stat in MessageByType.Values) foreach (Stat stat in MessageByType.Values)
{
stat.ResetRecent(); stat.ResetRecent();
}
foreach (Stat stat in RpcByHash.Values) foreach (Stat stat in RpcByHash.Values)
{
stat.ResetRecent(); stat.ResetRecent();
}
} }
} }
[Tooltip("How many seconds to accumulate 'recent' stats for, this is also the output interval")] [Tooltip("How many seconds to accumulate 'recent' stats for, this is also the output interval")]
public float RecentDuration = 5; public float RecentDuration = 5;
public Sorter Sort = new Sorter(); public Sorter Sort = new Sorter();
public enum OutputType public enum OutputType
{ {
UnityLog, UnityLog,
StdOut, StdOut,
File File
} }
public OutputType Output; public OutputType Output;
[Tooltip("If Output is set to 'File', where to the path of that file")] [Tooltip("If Output is set to 'File', where to the path of that file")]
public string OutputFilePath = "network-stats.log"; public string OutputFilePath = "network-stats.log";
private readonly MessageStats _in = new MessageStats(); readonly MessageStats inStats = new MessageStats();
private readonly MessageStats _out = new MessageStats(); readonly MessageStats outStats = new MessageStats();
private StringBuilder _print = new StringBuilder(); readonly StringBuilder printBuilder = new StringBuilder();
private float _elapsedSinceReset; float elapsedSinceReset;
private void Start() void Start()
{ {
// Ordering, Awake happens before NetworkDiagnostics reset
NetworkDiagnostics.InMessageEvent += HandleMessageIn; NetworkDiagnostics.InMessageEvent += HandleMessageIn;
NetworkDiagnostics.OutMessageEvent += HandleMessageOut; NetworkDiagnostics.OutMessageEvent += HandleMessageOut;
} }
private void OnDestroy()
void OnDestroy()
{ {
NetworkDiagnostics.InMessageEvent -= HandleMessageIn; NetworkDiagnostics.InMessageEvent -= HandleMessageIn;
NetworkDiagnostics.OutMessageEvent -= HandleMessageOut; NetworkDiagnostics.OutMessageEvent -= HandleMessageOut;
} }
private void HandleMessageOut(NetworkDiagnostics.MessageInfo info)
void HandleMessageOut(NetworkDiagnostics.MessageInfo info) => outStats.Record(info);
void HandleMessageIn(NetworkDiagnostics.MessageInfo info) => inStats.Record(info);
void LateUpdate()
{ {
_out.Record(info); elapsedSinceReset += Time.deltaTime;
} if (elapsedSinceReset > RecentDuration)
private void HandleMessageIn(NetworkDiagnostics.MessageInfo info)
{
_in.Record(info);
}
private void LateUpdate()
{
_elapsedSinceReset += Time.deltaTime;
if (_elapsedSinceReset > RecentDuration)
{ {
_elapsedSinceReset = 0; elapsedSinceReset = 0;
Print(); Print();
_in.ResetRecent(); inStats.ResetRecent();
_out.ResetRecent(); outStats.ResetRecent();
} }
} }
private void Print()
void Print()
{ {
_print.Clear(); printBuilder.Clear();
_print.AppendLine($"Stats for {DateTime.Now} ({RecentDuration:N1}s interval)"); printBuilder.AppendLine($"Stats for {DateTime.Now} ({RecentDuration:N1}s interval)");
int nameMaxLength = "OUT Message".Length; int nameMaxLength = "OUT Message".Length;
foreach (Stat stat in _in.MessageByType.Values) foreach (Stat stat in inStats.MessageByType.Values)
{
if (stat.Name.Length > nameMaxLength) if (stat.Name.Length > nameMaxLength)
{
nameMaxLength = stat.Name.Length; nameMaxLength = stat.Name.Length;
}
}
foreach (Stat stat in _out.MessageByType.Values) foreach (Stat stat in outStats.MessageByType.Values)
{
if (stat.Name.Length > nameMaxLength) if (stat.Name.Length > nameMaxLength)
{
nameMaxLength = stat.Name.Length; nameMaxLength = stat.Name.Length;
}
}
foreach (Stat stat in _in.RpcByHash.Values)
{
if (stat.Name.Length > nameMaxLength)
{
nameMaxLength = stat.Name.Length;
}
}
foreach (Stat stat in _out.RpcByHash.Values) foreach (Stat stat in inStats.RpcByHash.Values)
{ if (stat.Name.Length > nameMaxLength)
nameMaxLength = stat.Name.Length;
foreach (Stat stat in outStats.RpcByHash.Values)
if (stat.Name.Length > nameMaxLength) if (stat.Name.Length > nameMaxLength)
{
nameMaxLength = stat.Name.Length; nameMaxLength = stat.Name.Length;
}
}
string recentBytes = "Recent Bytes"; string recentBytes = "Recent Bytes";
string recentCount = "Recent Count"; string recentCount = "Recent Count";
@ -234,60 +221,54 @@ private void Print()
int totalCountPad = Mathf.Max(totalCount.Length, maxCountLength); int totalCountPad = Mathf.Max(totalCount.Length, maxCountLength);
string header = $"| {"IN Message".PadLeft(nameMaxLength)} | {recentBytes.PadLeft(recentBytesPad)} | {recentCount.PadLeft(recentCountPad)} | {totalBytes.PadLeft(totalBytesPad)} | {totalCount.PadLeft(totalCountPad)} |"; string header = $"| {"IN Message".PadLeft(nameMaxLength)} | {recentBytes.PadLeft(recentBytesPad)} | {recentCount.PadLeft(recentCountPad)} | {totalBytes.PadLeft(totalBytesPad)} | {totalCount.PadLeft(totalCountPad)} |";
string sep = "".PadLeft(header.Length, '-'); string sep = "".PadLeft(header.Length, '-');
_print.AppendLine(sep); printBuilder.AppendLine(sep);
_print.AppendLine(header); printBuilder.AppendLine(header);
_print.AppendLine(sep); printBuilder.AppendLine(sep);
foreach (Stat stat in inStats.MessageByType.Values.OrderBy(stat => stat, Sort))
printBuilder.AppendLine($"| {stat.Name.PadLeft(nameMaxLength)} | {FormatBytes(stat.RecentBytes).PadLeft(recentBytesPad)} | {FormatCount(stat.RecentCount).PadLeft(recentCountPad)} | {FormatBytes(stat.TotalBytes).PadLeft(totalBytesPad)} | {FormatCount(stat.TotalCount).PadLeft(totalCountPad)} |");
foreach (Stat stat in _in.MessageByType.Values.OrderBy(stat => stat, Sort))
{
_print.AppendLine($"| {stat.Name.PadLeft(nameMaxLength)} | {FormatBytes(stat.RecentBytes).PadLeft(recentBytesPad)} | {FormatCount(stat.RecentCount).PadLeft(recentCountPad)} | {FormatBytes(stat.TotalBytes).PadLeft(totalBytesPad)} | {FormatCount(stat.TotalCount).PadLeft(totalCountPad)} |");
}
header = $"| {"IN RPCs".PadLeft(nameMaxLength)} | {recentBytes.PadLeft(recentBytesPad)} | {recentCount.PadLeft(recentCountPad)} | {totalBytes.PadLeft(totalBytesPad)} | {totalCount.PadLeft(totalCountPad)} |"; header = $"| {"IN RPCs".PadLeft(nameMaxLength)} | {recentBytes.PadLeft(recentBytesPad)} | {recentCount.PadLeft(recentCountPad)} | {totalBytes.PadLeft(totalBytesPad)} | {totalCount.PadLeft(totalCountPad)} |";
_print.AppendLine(sep); printBuilder.AppendLine(sep);
_print.AppendLine(header); printBuilder.AppendLine(header);
_print.AppendLine(sep); printBuilder.AppendLine(sep);
foreach (Stat stat in _in.RpcByHash.Values.OrderBy(stat => stat, Sort)) foreach (Stat stat in inStats.RpcByHash.Values.OrderBy(stat => stat, Sort))
{ printBuilder.AppendLine($"| {stat.Name.PadLeft(nameMaxLength)} | {FormatBytes(stat.RecentBytes).PadLeft(recentBytesPad)} | {FormatCount(stat.RecentCount).PadLeft(recentCountPad)} | {FormatBytes(stat.TotalBytes).PadLeft(totalBytesPad)} | {FormatCount(stat.TotalCount).PadLeft(totalCountPad)} |");
_print.AppendLine($"| {stat.Name.PadLeft(nameMaxLength)} | {FormatBytes(stat.RecentBytes).PadLeft(recentBytesPad)} | {FormatCount(stat.RecentCount).PadLeft(recentCountPad)} | {FormatBytes(stat.TotalBytes).PadLeft(totalBytesPad)} | {FormatCount(stat.TotalCount).PadLeft(totalCountPad)} |");
}
header = $"| {"OUT Message".PadLeft(nameMaxLength)} | {recentBytes.PadLeft(recentBytesPad)} | {recentCount.PadLeft(recentCountPad)} | {totalBytes.PadLeft(totalBytesPad)} | {totalCount.PadLeft(totalCountPad)} |"; header = $"| {"OUT Message".PadLeft(nameMaxLength)} | {recentBytes.PadLeft(recentBytesPad)} | {recentCount.PadLeft(recentCountPad)} | {totalBytes.PadLeft(totalBytesPad)} | {totalCount.PadLeft(totalCountPad)} |";
_print.AppendLine(sep); printBuilder.AppendLine(sep);
_print.AppendLine(header); printBuilder.AppendLine(header);
_print.AppendLine(sep); printBuilder.AppendLine(sep);
foreach (Stat stat in _out.MessageByType.Values.OrderBy(stat => stat, Sort)) foreach (Stat stat in outStats.MessageByType.Values.OrderBy(stat => stat, Sort))
{ printBuilder.AppendLine($"| {stat.Name.PadLeft(nameMaxLength)} | {FormatBytes(stat.RecentBytes).PadLeft(recentBytesPad)} | {FormatCount(stat.RecentCount).PadLeft(recentCountPad)} | {FormatBytes(stat.TotalBytes).PadLeft(totalBytesPad)} | {FormatCount(stat.TotalCount).PadLeft(totalCountPad)} |");
_print.AppendLine($"| {stat.Name.PadLeft(nameMaxLength)} | {FormatBytes(stat.RecentBytes).PadLeft(recentBytesPad)} | {FormatCount(stat.RecentCount).PadLeft(recentCountPad)} | {FormatBytes(stat.TotalBytes).PadLeft(totalBytesPad)} | {FormatCount(stat.TotalCount).PadLeft(totalCountPad)} |");
}
header = $"| {"OUT RPCs".PadLeft(nameMaxLength)} | {recentBytes.PadLeft(recentBytesPad)} | {recentCount.PadLeft(recentCountPad)} | {totalBytes.PadLeft(totalBytesPad)} | {totalCount.PadLeft(totalCountPad)} |"; header = $"| {"OUT RPCs".PadLeft(nameMaxLength)} | {recentBytes.PadLeft(recentBytesPad)} | {recentCount.PadLeft(recentCountPad)} | {totalBytes.PadLeft(totalBytesPad)} | {totalCount.PadLeft(totalCountPad)} |";
_print.AppendLine(sep); printBuilder.AppendLine(sep);
_print.AppendLine(header); printBuilder.AppendLine(header);
_print.AppendLine(sep); printBuilder.AppendLine(sep);
foreach (Stat stat in _out.RpcByHash.Values.OrderBy(stat => stat, Sort)) foreach (Stat stat in outStats.RpcByHash.Values.OrderBy(stat => stat, Sort))
{ printBuilder.AppendLine($"| {stat.Name.PadLeft(nameMaxLength)} | {FormatBytes(stat.RecentBytes).PadLeft(recentBytesPad)} | {FormatCount(stat.RecentCount).PadLeft(recentCountPad)} | {FormatBytes(stat.TotalBytes).PadLeft(totalBytesPad)} | {FormatCount(stat.TotalCount).PadLeft(totalCountPad)} |");
_print.AppendLine($"| {stat.Name.PadLeft(nameMaxLength)} | {FormatBytes(stat.RecentBytes).PadLeft(recentBytesPad)} | {FormatCount(stat.RecentCount).PadLeft(recentCountPad)} | {FormatBytes(stat.TotalBytes).PadLeft(totalBytesPad)} | {FormatCount(stat.TotalCount).PadLeft(totalCountPad)} |");
} printBuilder.AppendLine(sep);
_print.AppendLine(sep);
switch (Output) switch (Output)
{ {
case OutputType.UnityLog: case OutputType.UnityLog:
Debug.Log(_print.ToString()); Debug.Log(printBuilder.ToString());
break; break;
case OutputType.StdOut: case OutputType.StdOut:
Console.Write(_print); Console.Write(printBuilder);
break; break;
case OutputType.File: case OutputType.File:
File.AppendAllText(OutputFilePath, _print.ToString()); File.AppendAllText(OutputFilePath, printBuilder.ToString());
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
} }
private string FormatBytes(long bytes) static string FormatBytes(long bytes)
{ {
const double KiB = 1024; const double KiB = 1024;
const double MiB = KiB * 1024; const double MiB = KiB * 1024;
@ -296,16 +277,20 @@ private string FormatBytes(long bytes)
if (bytes < KiB) if (bytes < KiB)
return $"{bytes:N0} B"; return $"{bytes:N0} B";
if (bytes < MiB) if (bytes < MiB)
return $"{bytes / KiB:N2} KiB"; return $"{bytes / KiB:N2} KiB";
if (bytes < GiB) if (bytes < GiB)
return $"{bytes / MiB:N2} MiB"; return $"{bytes / MiB:N2} MiB";
if (bytes < TiB) if (bytes < TiB)
return $"{bytes / GiB:N2} GiB"; return $"{bytes / GiB:N2} GiB";
return $"{bytes / TiB:N2} TiB"; return $"{bytes / TiB:N2} TiB";
} }
private string FormatCount(long count) string FormatCount(long count)
{ {
const double K = 1000; const double K = 1000;
const double M = K * 1000; const double M = K * 1000;
@ -314,12 +299,16 @@ private string FormatCount(long count)
if (count < K) if (count < K)
return $"{count:N0}"; return $"{count:N0}";
if (count < M) if (count < M)
return $"{count / K:N2} K"; return $"{count / K:N2} K";
if (count < G) if (count < G)
return $"{count / M:N2} M"; return $"{count / M:N2} M";
if (count < T) if (count < T)
return $"{count / G:N2} G"; return $"{count / G:N2} G";
return $"{count / T:N2} T"; return $"{count / T:N2} T";
} }
} }

View File

@ -0,0 +1,85 @@
using System;
using UnityEngine;
namespace Mirror
{
public class NetworkUsageGraph : BaseUIGraph
{
int dataIn;
int dataOut;
void Start()
{
// Ordering, Awake happens before NetworkDiagnostics reset
NetworkDiagnostics.InMessageEvent += OnReceive;
NetworkDiagnostics.OutMessageEvent += OnSend;
}
void OnEnable()
{
// If we've been inactive, clear counter
dataIn = 0;
dataOut = 0;
}
void OnDestroy()
{
NetworkDiagnostics.InMessageEvent -= OnReceive;
NetworkDiagnostics.OutMessageEvent -= OnSend;
}
void OnSend(NetworkDiagnostics.MessageInfo obj) => dataOut += obj.bytes;
void OnReceive(NetworkDiagnostics.MessageInfo obj) => dataIn += obj.bytes;
protected override void CollectData(int category, out float value, out GraphAggregationMode mode)
{
mode = GraphAggregationMode.PerSecond;
switch (category)
{
case 0:
value = dataIn;
dataIn = 0;
break;
case 1:
value = dataOut;
dataOut = 0;
break;
default:
throw new ArgumentOutOfRangeException($"{category} is not valid.");
}
}
static readonly string[] Units = new[] { "B/s", "KiB/s", "MiB/s" };
const float UnitScale = 1024;
protected override string FormatValue(float value)
{
string selectedUnit = null;
for (int i = 0; i < Units.Length; i++)
{
string unit = Units[i];
selectedUnit = unit;
if (i > 0)
value /= UnitScale;
if (value < UnitScale)
break;
}
return $"{value:N0} {selectedUnit}";
}
protected override void OnValidate()
{
base.OnValidate();
if (CategoryColors.Length != 2)
CategoryColors = new[]
{
Color.red, // min
Color.green // max
};
IsStacked = false;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e1ae19b97f0e4a5eb8cf5158d97506f5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 083c6613a11cad746bb252bc7748947f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9bdc42bca9b7109428d00fe33bdb5102
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,765 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &2777084101886578567
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3864348419064627986}
- component: {fileID: 4699359553083341963}
m_Layer: 5
m_Name: Graphs
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!224 &3864348419064627986
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2777084101886578567}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 4509006437822490170}
- {fileID: 522813179161291686}
- {fileID: 7802229218722708586}
m_Father: {fileID: 5551289487596275721}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &4699359553083341963
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2777084101886578567}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Padding:
m_Left: 10
m_Right: 0
m_Top: 10
m_Bottom: 0
m_ChildAlignment: 2
m_Spacing: 0
m_ChildForceExpandWidth: 0
m_ChildForceExpandHeight: 0
m_ChildControlWidth: 0
m_ChildControlHeight: 0
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
--- !u!1 &4512081604627528395
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5551289487596275721}
- component: {fileID: 5641452096830013034}
- component: {fileID: 4961392508020504993}
- component: {fileID: 1349218098020237989}
- component: {fileID: 8415974033864006777}
m_Layer: 5
m_Name: GraphCanvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &5551289487596275721
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4512081604627528395}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_Children:
- {fileID: 3864348419064627986}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!223 &5641452096830013034
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4512081604627528395}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 0
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_AdditionalShaderChannelsFlag: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!114 &4961392508020504993
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4512081604627528395}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 1
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
m_ReferenceResolution: {x: 1280, y: 720}
m_ScreenMatchMode: 0
m_MatchWidthOrHeight: 1
m_PhysicalUnit: 3
m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
--- !u!114 &1349218098020237989
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4512081604627528395}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreReversedGraphics: 1
m_BlockingObjects: 0
m_BlockingMask:
serializedVersion: 2
m_Bits: 4294967295
--- !u!114 &8415974033864006777
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4512081604627528395}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a27b133d890c41828d3b01ffa12fe440, type: 3}
m_Name:
m_EditorClassIdentifier:
Key: 291
ToToggle: {fileID: 2777084101886578567}
--- !u!1001 &4204022305993221602
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 3864348419064627986}
m_Modifications:
- target: {fileID: 343546205212282745, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 343546205212282745, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 343546205212282745, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_SizeDelta.x
value: 86.666664
objectReference: {fileID: 0}
- target: {fileID: 343546205212282745, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_SizeDelta.y
value: 20
objectReference: {fileID: 0}
- target: {fileID: 343546205212282745, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 43.333332
objectReference: {fileID: 0}
- target: {fileID: 343546205212282745, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -10
objectReference: {fileID: 0}
- target: {fileID: 343546205281663118, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 343546205281663118, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 343546205281663118, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_SizeDelta.x
value: 86.666664
objectReference: {fileID: 0}
- target: {fileID: 343546205281663118, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_SizeDelta.y
value: 20
objectReference: {fileID: 0}
- target: {fileID: 343546205281663118, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 130
objectReference: {fileID: 0}
- target: {fileID: 343546205281663118, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -10
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_SizeDelta.x
value: 300
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_SizeDelta.y
value: 150
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 1668.6208
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -85
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 343546206339761113, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_Name
value: FPSMinMaxAvg
objectReference: {fileID: 0}
- target: {fileID: 343546206506823101, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 343546206506823101, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 343546206506823101, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_SizeDelta.x
value: 86.666664
objectReference: {fileID: 0}
- target: {fileID: 343546206506823101, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_SizeDelta.y
value: 20
objectReference: {fileID: 0}
- target: {fileID: 343546206506823101, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 216.66666
objectReference: {fileID: 0}
- target: {fileID: 343546206506823101, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -10
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 9bdc42bca9b7109428d00fe33bdb5102, type: 3}
--- !u!224 &4509006437822490170 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102,
type: 3}
m_PrefabInstance: {fileID: 4204022305993221602}
m_PrefabAsset: {fileID: 0}
--- !u!1001 &7469102913200609509
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 3864348419064627986}
m_Modifications:
- target: {fileID: 942441613928011978, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 942441613928011978, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 942441613928011978, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_SizeDelta.x
value: 130
objectReference: {fileID: 0}
- target: {fileID: 942441613928011978, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_SizeDelta.y
value: 20
objectReference: {fileID: 0}
- target: {fileID: 942441613928011978, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 195
objectReference: {fileID: 0}
- target: {fileID: 942441613928011978, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -10
objectReference: {fileID: 0}
- target: {fileID: 2997867828362567431, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_Name
value: PingGraph
objectReference: {fileID: 0}
- target: {fileID: 6899184289734897349, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6899184289734897349, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6899184289734897349, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_SizeDelta.x
value: 130
objectReference: {fileID: 0}
- target: {fileID: 6899184289734897349, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_SizeDelta.y
value: 20
objectReference: {fileID: 0}
- target: {fileID: 6899184289734897349, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 65
objectReference: {fileID: 0}
- target: {fileID: 6899184289734897349, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -10
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_RootOrder
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_SizeDelta.x
value: 300
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_SizeDelta.y
value: 150
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 1968.6208
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -85
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: ed3b4e27086dcc64b8c6605011a321e2, type: 3}
--- !u!224 &522813179161291686 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2,
type: 3}
m_PrefabInstance: {fileID: 7469102913200609509}
m_PrefabAsset: {fileID: 0}
--- !u!1001 &8208221870570858035
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 3864348419064627986}
m_Modifications:
- target: {fileID: 1750250400045347475, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1750250400045347475, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1750250400045347475, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_SizeDelta.x
value: 130
objectReference: {fileID: 0}
- target: {fileID: 1750250400045347475, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_SizeDelta.y
value: 20
objectReference: {fileID: 0}
- target: {fileID: 1750250400045347475, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 65
objectReference: {fileID: 0}
- target: {fileID: 1750250400045347475, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -10
objectReference: {fileID: 0}
- target: {fileID: 1986485545668258777, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: Points
value: 32
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_RootOrder
value: 2
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_SizeDelta.x
value: 300
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_SizeDelta.y
value: 150
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 2268.6208
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -85
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3670180597793129839, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_Name
value: NetworkGraph
objectReference: {fileID: 0}
- target: {fileID: 8473536528693599174, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8473536528693599174, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8473536528693599174, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_SizeDelta.x
value: 130
objectReference: {fileID: 0}
- target: {fileID: 8473536528693599174, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_SizeDelta.y
value: 20
objectReference: {fileID: 0}
- target: {fileID: 8473536528693599174, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 195
objectReference: {fileID: 0}
- target: {fileID: 8473536528693599174, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -10
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 3c7a97355c25a2b4da731b53876f8a8b, type: 3}
--- !u!224 &7802229218722708586 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b,
type: 3}
m_PrefabInstance: {fileID: 8208221870570858035}
m_PrefabAsset: {fileID: 0}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e87e1847def3c1f41b19b7df4f0920b3
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3c7a97355c25a2b4da731b53876f8a8b
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ed3b4e27086dcc64b8c6605011a321e2
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,88 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: StackedGraph
m_Shader: {fileID: 4800000, guid: b5b24284f35f4992bcd4cc43919267d7, type: 3}
m_ShaderKeywords:
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
- _BumpScale: 1
- _CategoryCount: 0
- _ColorMask: 15
- _Cutoff: 0.5
- _DataStart: 0
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _MaxValue: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _Stencil: 0
- _StencilComp: 8
- _StencilOp: 0
- _StencilReadMask: 255
- _StencilWriteMask: 255
- _UVSec: 0
- _UseUIAlphaClip: 0
- _Width: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 14fba9d19cfe7f346bfb595965558722
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,15 @@
using UnityEngine;
namespace Mirror
{
public class ToggleHotkey : MonoBehaviour
{
public KeyCode Key = KeyCode.F10;
public GameObject ToToggle;
void Update()
{
if (Input.GetKeyDown(Key))
ToToggle.SetActive(!ToToggle.activeSelf);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a27b133d890c41828d3b01ffa12fe440
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3}
userData:
assetBundleName:
assetBundleVariant: