【工具】增加协议模拟工具
parent
7f19b4a4d6
commit
3e3a44b66b
|
|
@ -0,0 +1,706 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Gameplay.Net;
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.Reflection;
|
||||
using NLDMID;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public class NetDebugWindow : EditorWindow
|
||||
{
|
||||
[MenuItem("Tools/网络协议调试")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
var window = GetWindow<NetDebugWindow>("网络协议调试");
|
||||
window.minSize = new Vector2(400f, 500f);
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private List<MSGID> _clientMsgIds;
|
||||
private List<string> _clientMsgNames;
|
||||
private List<string> _filteredNames;
|
||||
private List<MSGID> _filteredIds;
|
||||
private int _selectedIndex = 0;
|
||||
private string _searchText = "";
|
||||
private Vector2 _fieldScrollPos;
|
||||
private Vector2 _logScrollPos;
|
||||
private List<string> _logEntries = new List<string>();
|
||||
private Dictionary<string, bool> _foldoutStates = new Dictionary<string, bool>();
|
||||
private Dictionary<Type, PropertyInfo> _mPBPropertyCache = new Dictionary<Type, PropertyInfo>();
|
||||
private Dictionary<Type, FieldInfo> _mPBBackingFieldCache = new Dictionary<Type, FieldInfo>();
|
||||
private MSGID _lastSelectedId = MSGID.None;
|
||||
private bool _initialized;
|
||||
|
||||
private void _Init()
|
||||
{
|
||||
if (_initialized) return;
|
||||
_initialized = true;
|
||||
|
||||
_clientMsgIds = new List<MSGID>();
|
||||
_clientMsgNames = new List<string>();
|
||||
|
||||
foreach (MSGID id in Enum.GetValues(typeof(MSGID)))
|
||||
{
|
||||
string name = id.ToString();
|
||||
if (name.StartsWith("Clt"))
|
||||
{
|
||||
_clientMsgIds.Add(id);
|
||||
_clientMsgNames.Add($"{name} ({(int)id})");
|
||||
}
|
||||
}
|
||||
|
||||
_filteredIds = new List<MSGID>(_clientMsgIds);
|
||||
_filteredNames = new List<string>(_clientMsgNames);
|
||||
}
|
||||
|
||||
private PropertyInfo _GetmPBProperty(Type msgType)
|
||||
{
|
||||
if (!_mPBPropertyCache.TryGetValue(msgType, out PropertyInfo prop))
|
||||
{
|
||||
prop = msgType.GetProperty("mPB", BindingFlags.Public | BindingFlags.Instance);
|
||||
_mPBPropertyCache[msgType] = prop;
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
private FieldInfo _GetmPBBackingField(Type msgType)
|
||||
{
|
||||
if (!_mPBBackingFieldCache.TryGetValue(msgType, out FieldInfo field))
|
||||
{
|
||||
field = msgType.GetField("m_PB", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
_mPBBackingFieldCache[msgType] = field;
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
_Init();
|
||||
|
||||
bool isPlaying = EditorApplication.isPlaying;
|
||||
bool netReady = isPlaying && NetManager.Instance != null && NetManager.Instance.mClient != null;
|
||||
|
||||
EditorGUILayout.HelpBox(
|
||||
netReady ? "连接正常,可以发送协议" : "请先进入 Play 模式并确保网络连接正常",
|
||||
netReady ? MessageType.Info : MessageType.Warning
|
||||
);
|
||||
|
||||
EditorGUI.BeginDisabledGroup(!netReady);
|
||||
try
|
||||
{
|
||||
EditorGUILayout.Space(4);
|
||||
EditorGUILayout.LabelField("搜索协议", EditorStyles.boldLabel);
|
||||
string newSearch = EditorGUILayout.TextField(_searchText);
|
||||
if (newSearch != _searchText)
|
||||
{
|
||||
_searchText = newSearch;
|
||||
_FilterMsgIds();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(4);
|
||||
EditorGUILayout.LabelField("选择协议ID", EditorStyles.boldLabel);
|
||||
if (_filteredNames != null && _filteredNames.Count > 0)
|
||||
{
|
||||
_selectedIndex = EditorGUILayout.Popup("协议", _selectedIndex, _filteredNames.ToArray());
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(4);
|
||||
EditorGUILayout.LabelField("协议字段", EditorStyles.boldLabel);
|
||||
|
||||
Gameplay.Net.IMessage currentMsg = null;
|
||||
object pbObj = null;
|
||||
|
||||
if (netReady && _filteredIds != null && _filteredIds.Count > 0 && _selectedIndex >= 0 && _selectedIndex < _filteredIds.Count)
|
||||
{
|
||||
try
|
||||
{
|
||||
MSGID selectedId = _filteredIds[_selectedIndex];
|
||||
if (selectedId != _lastSelectedId)
|
||||
{
|
||||
_foldoutStates.Clear();
|
||||
_lastSelectedId = selectedId;
|
||||
}
|
||||
currentMsg = NetManager.Instance.GetMessage(selectedId);
|
||||
if (currentMsg != null)
|
||||
{
|
||||
PropertyInfo mPBProp = _GetmPBProperty(currentMsg.GetType());
|
||||
if (mPBProp != null)
|
||||
{
|
||||
pbObj = mPBProp.GetValue(currentMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
EditorGUILayout.HelpBox($"获取协议消息失败: {e.Message}", MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (pbObj != null)
|
||||
{
|
||||
_fieldScrollPos = EditorGUILayout.BeginScrollView(_fieldScrollPos, GUILayout.ExpandHeight(true));
|
||||
try
|
||||
{
|
||||
_DrawProtobufMessage(pbObj, "");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
EditorGUILayout.HelpBox($"绘制协议字段失败: {e.Message}", MessageType.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
}
|
||||
else if (netReady)
|
||||
{
|
||||
EditorGUILayout.HelpBox("无法获取协议消息内容", MessageType.Warning);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(4);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
try
|
||||
{
|
||||
if (GUILayout.Button("发送协议", GUILayout.Height(30)))
|
||||
{
|
||||
_Send(currentMsg);
|
||||
}
|
||||
if (GUILayout.Button("重置字段", GUILayout.Height(30)))
|
||||
{
|
||||
_Reset(currentMsg);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(4);
|
||||
EditorGUILayout.LabelField("发送日志", EditorStyles.boldLabel);
|
||||
if (GUILayout.Button("清空日志"))
|
||||
{
|
||||
_logEntries.Clear();
|
||||
}
|
||||
_logScrollPos = EditorGUILayout.BeginScrollView(_logScrollPos, GUILayout.Height(120));
|
||||
for (int i = _logEntries.Count - 1; i >= 0; i--)
|
||||
{
|
||||
EditorGUILayout.TextArea(_logEntries[i], GUILayout.ExpandWidth(true));
|
||||
}
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private void _FilterMsgIds()
|
||||
{
|
||||
_filteredIds = new List<MSGID>();
|
||||
_filteredNames = new List<string>();
|
||||
for (int i = 0; i < _clientMsgIds.Count; i++)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_searchText) || _clientMsgNames[i].IndexOf(_searchText, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
_filteredIds.Add(_clientMsgIds[i]);
|
||||
_filteredNames.Add(_clientMsgNames[i]);
|
||||
}
|
||||
}
|
||||
_selectedIndex = 0;
|
||||
}
|
||||
|
||||
private void _Send(Gameplay.Net.IMessage msg)
|
||||
{
|
||||
if (msg == null)
|
||||
{
|
||||
Debug.LogWarning("[NetDebug] 消息为空,无法发送");
|
||||
return;
|
||||
}
|
||||
if (NetManager.Instance?.mClient == null)
|
||||
{
|
||||
Debug.LogWarning("[NetDebug] NetClient 不可用");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
NetManager.Instance.mClient.SendMessage(msg);
|
||||
string logEntry = $"[{DateTime.Now:HH:mm:ss}] 发送 {msg.ID}";
|
||||
_logEntries.Add(logEntry);
|
||||
Debug.Log($"[NetDebug] {logEntry}\n{msg}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[NetDebug] 发送失败: {e.Message}\n{e.StackTrace}");
|
||||
_logEntries.Add($"[{DateTime.Now:HH:mm:ss}] 发送失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void _Reset(Gameplay.Net.IMessage msg)
|
||||
{
|
||||
if (msg == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
FieldInfo backField = _GetmPBBackingField(msg.GetType());
|
||||
if (backField != null)
|
||||
{
|
||||
backField.SetValue(msg, null);
|
||||
}
|
||||
_foldoutStates.Clear();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[NetDebug] 重置失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void _DrawProtobufMessage(object pbObj, string pathPrefix)
|
||||
{
|
||||
if (pbObj == null) return;
|
||||
|
||||
Google.Protobuf.IMessage iMsg = pbObj as Google.Protobuf.IMessage;
|
||||
if (iMsg == null) return;
|
||||
|
||||
MessageDescriptor descriptor = iMsg.Descriptor;
|
||||
if (descriptor == null) return;
|
||||
|
||||
Type pbType = pbObj.GetType();
|
||||
|
||||
foreach (var field in descriptor.Fields.InFieldNumberOrder())
|
||||
{
|
||||
string csharpName = _ProtoNameToCSharpName(field.Name);
|
||||
string fieldPath = string.IsNullOrEmpty(pathPrefix) ? csharpName : $"{pathPrefix}.{csharpName}";
|
||||
PropertyInfo propInfo = pbType.GetProperty(csharpName, BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (field.IsRepeated)
|
||||
{
|
||||
_DrawRepeatedField(field, propInfo, pbObj, fieldPath);
|
||||
}
|
||||
else if (_IsMessageField(field))
|
||||
{
|
||||
_DrawNestedMessage(field, propInfo, pbObj, fieldPath);
|
||||
}
|
||||
else if (field.FieldType == FieldType.Enum)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (field.EnumType != null && field.EnumType.Values.Count > 0)
|
||||
{
|
||||
_DrawEnumField(field, propInfo, pbObj, fieldPath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
EditorGUILayout.HelpBox("无效的字段:" + field.Name, MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_DrawScalarField(field, propInfo, pbObj, fieldPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _DrawRepeatedField(FieldDescriptor field, PropertyInfo propInfo, object pbObj, string fieldPath)
|
||||
{
|
||||
if (propInfo == null)
|
||||
{
|
||||
EditorGUILayout.LabelField(field.Name, "(无法访问属性)");
|
||||
return;
|
||||
}
|
||||
|
||||
IList list = propInfo.GetValue(pbObj) as IList;
|
||||
if (list == null)
|
||||
{
|
||||
EditorGUILayout.LabelField(field.Name, "(列表为 null)");
|
||||
return;
|
||||
}
|
||||
|
||||
string csharpName = _ProtoNameToCSharpName(field.Name);
|
||||
string listLabel = $"{csharpName} [{list.Count}]";
|
||||
bool foldout = _GetFoldoutState(fieldPath, true);
|
||||
foldout = EditorGUILayout.Foldout(foldout, listLabel);
|
||||
_SetFoldoutState(fieldPath, foldout);
|
||||
|
||||
if (!foldout) return;
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
bool isElementMsg = _IsMessageField(field);
|
||||
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (isElementMsg && list[i] != null)
|
||||
{
|
||||
bool itemFoldout = _GetFoldoutState($"{fieldPath}[{i}]", false);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
itemFoldout = EditorGUILayout.Foldout(itemFoldout, $"[{i}]");
|
||||
_SetFoldoutState($"{fieldPath}[{i}]", itemFoldout);
|
||||
if (GUILayout.Button("×", GUILayout.Width(20)))
|
||||
{
|
||||
list.RemoveAt(i);
|
||||
i--;
|
||||
EditorGUILayout.EndHorizontal();
|
||||
continue;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
if (itemFoldout)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
_DrawProtobufMessage(list[i], $"{fieldPath}[{i}]");
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField($"[{i}]", GUILayout.Width(40));
|
||||
object val = list[i];
|
||||
object newVal = _DrawValueField(val, field, "");
|
||||
if (newVal != null && !newVal.Equals(val))
|
||||
{
|
||||
try { list[i] = newVal; } catch { }
|
||||
}
|
||||
if (GUILayout.Button("×", GUILayout.Width(20)))
|
||||
{
|
||||
list.RemoveAt(i);
|
||||
i--;
|
||||
EditorGUILayout.EndHorizontal();
|
||||
continue;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button("+ 添加元素", GUILayout.Height(20)))
|
||||
{
|
||||
if (isElementMsg)
|
||||
{
|
||||
Type elementType = field.MessageType.ClrType;
|
||||
if (elementType != null)
|
||||
{
|
||||
object newElem = Activator.CreateInstance(elementType);
|
||||
list.Add(newElem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
object defaultVal = _GetDefaultForRepeatedElement(field);
|
||||
if (defaultVal != null)
|
||||
{
|
||||
list.Add(defaultVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
private void _DrawNestedMessage(FieldDescriptor field, PropertyInfo propInfo, object pbObj, string fieldPath)
|
||||
{
|
||||
string label = _ProtoNameToCSharpName(field.Name);
|
||||
|
||||
object subMsg = null;
|
||||
if (propInfo != null)
|
||||
{
|
||||
subMsg = propInfo.GetValue(pbObj);
|
||||
}
|
||||
|
||||
if (subMsg == null)
|
||||
{
|
||||
if (propInfo != null && _IsMessageField(field) && field.MessageType.ClrType != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
subMsg = Activator.CreateInstance(field.MessageType.ClrType);
|
||||
propInfo.SetValue(pbObj, subMsg);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
EditorGUILayout.LabelField(label, $"(创建失败: {e.Message})");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField(label, "(无法创建子消息)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool foldout = _GetFoldoutState(fieldPath, false);
|
||||
foldout = EditorGUILayout.Foldout(foldout, label);
|
||||
_SetFoldoutState(fieldPath, foldout);
|
||||
|
||||
if (foldout)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
_DrawProtobufMessage(subMsg, fieldPath);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
private void _DrawEnumField(FieldDescriptor field, PropertyInfo propInfo, object pbObj, string fieldPath)
|
||||
{
|
||||
if (propInfo == null)
|
||||
{
|
||||
EditorGUILayout.LabelField(field.Name, "(无法访问属性)");
|
||||
return;
|
||||
}
|
||||
|
||||
string label = _ProtoNameToCSharpName(field.Name);
|
||||
object currentVal = propInfo.GetValue(pbObj);
|
||||
|
||||
int currentInt = Convert.ToInt32(currentVal);
|
||||
|
||||
string[] displayOptions = new string[field.EnumType.Values.Count];
|
||||
int[] values = new int[field.EnumType.Values.Count];
|
||||
int selectedIdx = 0;
|
||||
for (int i = 0; i < field.EnumType.Values.Count; i++)
|
||||
{
|
||||
displayOptions[i] = $"{field.EnumType.Values[i].Name} = {field.EnumType.Values[i].Number}";
|
||||
values[i] = field.EnumType.Values[i].Number;
|
||||
if (values[i] == currentInt) selectedIdx = i;
|
||||
}
|
||||
|
||||
int newIdx = EditorGUILayout.Popup(label, selectedIdx, displayOptions);
|
||||
if (newIdx >= 0 && newIdx < values.Length && values[newIdx] != currentInt)
|
||||
{
|
||||
try
|
||||
{
|
||||
_SetPropertyValue(propInfo, pbObj, values[newIdx]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[NetDebug] 设置枚举字段 {label} 失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _DrawScalarField(FieldDescriptor field, PropertyInfo propInfo, object pbObj, string fieldPath)
|
||||
{
|
||||
if (propInfo == null)
|
||||
{
|
||||
EditorGUILayout.LabelField(field.Name, "(无法访问属性)");
|
||||
return;
|
||||
}
|
||||
|
||||
string label = _ProtoNameToCSharpName(field.Name);
|
||||
object currentVal = propInfo.GetValue(pbObj);
|
||||
if (currentVal == null) currentVal = _GetDefaultValue(field);
|
||||
|
||||
object newVal = _DrawValueField(currentVal, field, label);
|
||||
if (newVal != null && !newVal.Equals(currentVal))
|
||||
{
|
||||
try
|
||||
{
|
||||
_SetPropertyValue(propInfo, pbObj, newVal);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[NetDebug] 设置字段 {label} 失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object _DrawValueField(object currentVal, FieldDescriptor field, string labelOverride)
|
||||
{
|
||||
string label = string.IsNullOrEmpty(labelOverride) ? _ProtoNameToCSharpName(field.Name) : labelOverride;
|
||||
|
||||
switch (field.FieldType)
|
||||
{
|
||||
case FieldType.UInt32:
|
||||
case FieldType.Fixed32:
|
||||
{
|
||||
long val = Convert.ToInt64(currentVal);
|
||||
long newVal = EditorGUILayout.LongField(label, val);
|
||||
return (uint)Math.Max(0, newVal);
|
||||
}
|
||||
case FieldType.Int32:
|
||||
case FieldType.SInt32:
|
||||
case FieldType.SFixed32:
|
||||
{
|
||||
int val = Convert.ToInt32(currentVal);
|
||||
return EditorGUILayout.IntField(label, val);
|
||||
}
|
||||
case FieldType.UInt64:
|
||||
case FieldType.Fixed64:
|
||||
{
|
||||
long val = Convert.ToInt64(currentVal);
|
||||
long newVal = EditorGUILayout.LongField(label, val);
|
||||
return (ulong)newVal;
|
||||
}
|
||||
case FieldType.Int64:
|
||||
case FieldType.SInt64:
|
||||
case FieldType.SFixed64:
|
||||
{
|
||||
long val = Convert.ToInt64(currentVal);
|
||||
return EditorGUILayout.LongField(label, val);
|
||||
}
|
||||
case FieldType.Float:
|
||||
{
|
||||
float val = Convert.ToSingle(currentVal);
|
||||
return EditorGUILayout.FloatField(label, val);
|
||||
}
|
||||
case FieldType.Double:
|
||||
{
|
||||
double val = Convert.ToDouble(currentVal);
|
||||
return EditorGUILayout.DoubleField(label, val);
|
||||
}
|
||||
case FieldType.Bool:
|
||||
{
|
||||
bool val = Convert.ToBoolean(currentVal);
|
||||
return EditorGUILayout.Toggle(label, val);
|
||||
}
|
||||
case FieldType.String:
|
||||
{
|
||||
string val = currentVal as string ?? "";
|
||||
return EditorGUILayout.TextField(label, val);
|
||||
}
|
||||
case FieldType.Bytes:
|
||||
{
|
||||
string val = currentVal is ByteString bs ? BitConverter.ToString(bs.ToByteArray()) : "";
|
||||
EditorGUILayout.LabelField(label, "(bytes) " + val);
|
||||
return null;
|
||||
}
|
||||
case FieldType.Enum:
|
||||
{
|
||||
int val = Convert.ToInt32(currentVal);
|
||||
string[] displayOptions = new string[field.EnumType.Values.Count];
|
||||
int[] values = new int[field.EnumType.Values.Count];
|
||||
int selectedIdx = 0;
|
||||
for (int i = 0; i < field.EnumType.Values.Count; i++)
|
||||
{
|
||||
displayOptions[i] = $"{field.EnumType.Values[i].Name} = {field.EnumType.Values[i].Number}";
|
||||
values[i] = field.EnumType.Values[i].Number;
|
||||
if (values[i] == val) selectedIdx = i;
|
||||
}
|
||||
int newIdx = EditorGUILayout.Popup(label, selectedIdx, displayOptions);
|
||||
if (newIdx >= 0 && newIdx < values.Length) return values[newIdx];
|
||||
return val;
|
||||
}
|
||||
default:
|
||||
EditorGUILayout.LabelField(label, $"(不支持 {field.FieldType})");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private object _GetDefaultValue(FieldDescriptor field)
|
||||
{
|
||||
switch (field.FieldType)
|
||||
{
|
||||
case FieldType.UInt32:
|
||||
case FieldType.Fixed32: return (uint)0;
|
||||
case FieldType.Int32:
|
||||
case FieldType.SInt32:
|
||||
case FieldType.SFixed32: return 0;
|
||||
case FieldType.UInt64:
|
||||
case FieldType.Fixed64: return (ulong)0;
|
||||
case FieldType.Int64:
|
||||
case FieldType.SInt64:
|
||||
case FieldType.SFixed64: return (long)0;
|
||||
case FieldType.Float: return 0f;
|
||||
case FieldType.Double: return 0.0;
|
||||
case FieldType.Bool: return false;
|
||||
case FieldType.String: return "";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
private object _GetDefaultForRepeatedElement(FieldDescriptor field)
|
||||
{
|
||||
switch (field.FieldType)
|
||||
{
|
||||
case FieldType.Int32:
|
||||
case FieldType.SInt32:
|
||||
case FieldType.SFixed32:
|
||||
return 0;
|
||||
case FieldType.UInt32:
|
||||
case FieldType.Fixed32:
|
||||
return (uint)0;
|
||||
case FieldType.Int64:
|
||||
case FieldType.SInt64:
|
||||
case FieldType.SFixed64:
|
||||
return (long)0;
|
||||
case FieldType.UInt64:
|
||||
case FieldType.Fixed64:
|
||||
return (ulong)0;
|
||||
case FieldType.Float:
|
||||
return 0f;
|
||||
case FieldType.Double:
|
||||
return 0.0;
|
||||
case FieldType.Bool:
|
||||
return false;
|
||||
case FieldType.String:
|
||||
return "";
|
||||
case FieldType.Enum:
|
||||
if (field.EnumType != null && field.EnumType.Values.Count > 0)
|
||||
return field.EnumType.Values[0].Number;
|
||||
return 0;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void _SetPropertyValue(PropertyInfo propInfo, object target, object value)
|
||||
{
|
||||
Type propType = propInfo.PropertyType;
|
||||
if (propType.IsEnum && value != null)
|
||||
{
|
||||
value = Enum.ToObject(propType, Convert.ToInt32(value));
|
||||
}
|
||||
else if (value != null && !propType.IsAssignableFrom(value.GetType()))
|
||||
{
|
||||
try
|
||||
{
|
||||
value = Convert.ChangeType(value, propType);
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
// Conversion not possible, keep original value
|
||||
return;
|
||||
}
|
||||
}
|
||||
propInfo.SetValue(target, value);
|
||||
}
|
||||
|
||||
private bool _IsMessageField(FieldDescriptor field)
|
||||
{
|
||||
return field.FieldType == FieldType.Message || field.FieldType == FieldType.Group;
|
||||
}
|
||||
|
||||
private string _ProtoNameToCSharpName(string protoName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(protoName)) return protoName;
|
||||
string[] parts = protoName.Split('_');
|
||||
for (int i = 0; i < parts.Length; i++)
|
||||
{
|
||||
if (parts[i].Length > 0)
|
||||
{
|
||||
parts[i] = char.ToUpper(parts[i][0]) + parts[i].Substring(1);
|
||||
}
|
||||
}
|
||||
return string.Join("", parts);
|
||||
}
|
||||
|
||||
private bool _GetFoldoutState(string key, bool defaultValue)
|
||||
{
|
||||
if (_foldoutStates.TryGetValue(key, out bool val))
|
||||
return val;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private void _SetFoldoutState(string key, bool value)
|
||||
{
|
||||
_foldoutStates[key] = value;
|
||||
}
|
||||
|
||||
private void OnInspectorUpdate()
|
||||
{
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7d36088dc69f41448a1dbb40a70e336e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue