HLAPI 2017.4 (from https://bitbucket.org/Unity-Technologies/networking/src 2017.3, which is the same for 2017.4)

This commit is contained in:
vis2k 2018-06-07 15:41:08 +02:00
parent 6b2e2f3afd
commit 1e77e191b3
86 changed files with 26406 additions and 0 deletions

View File

@ -0,0 +1,96 @@
#if ENABLE_UNET
using System;
using UnityEditor.Animations;
using UnityEngine;
using UnityEngine.Networking;
namespace UnityEditor
{
[CustomEditor(typeof(NetworkAnimator), true)]
[CanEditMultipleObjects]
public class NetworkAnimatorEditor : Editor
{
NetworkAnimator m_AnimSync;
[NonSerialized] bool m_Initialized;
SerializedProperty m_AnimatorProperty;
GUIContent m_AnimatorLabel;
void Init()
{
if (m_Initialized)
return;
m_Initialized = true;
m_AnimSync = target as NetworkAnimator;
m_AnimatorProperty = serializedObject.FindProperty("m_Animator");
m_AnimatorLabel = new GUIContent("Animator", "The Animator component to synchronize.");
}
public override void OnInspectorGUI()
{
Init();
serializedObject.Update();
DrawControls();
serializedObject.ApplyModifiedProperties();
}
void DrawControls()
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_AnimatorProperty, m_AnimatorLabel);
if (EditorGUI.EndChangeCheck())
{
m_AnimSync.ResetParameterOptions();
}
if (m_AnimSync.animator == null)
return;
var controller = m_AnimSync.animator.runtimeAnimatorController as AnimatorController;
if (controller != null)
{
var showWarning = false;
EditorGUI.indentLevel += 1;
int i = 0;
foreach (var p in controller.parameters)
{
if (i >= 32)
{
showWarning = true;
break;
}
bool oldSend = m_AnimSync.GetParameterAutoSend(i);
bool send = EditorGUILayout.Toggle(p.name, oldSend);
if (send != oldSend)
{
m_AnimSync.SetParameterAutoSend(i, send);
EditorUtility.SetDirty(target);
}
i += 1;
}
if (showWarning)
{
EditorGUILayout.HelpBox("NetworkAnimator can only select between the first 32 parameters in a mecanim controller", MessageType.Warning);
}
EditorGUI.indentLevel -= 1;
}
if (Application.isPlaying)
{
EditorGUILayout.Separator();
if (m_AnimSync.param0 != "") EditorGUILayout.LabelField("Param 0", m_AnimSync.param0);
if (m_AnimSync.param1 != "") EditorGUILayout.LabelField("Param 1", m_AnimSync.param1);
if (m_AnimSync.param2 != "") EditorGUILayout.LabelField("Param 2", m_AnimSync.param2);
if (m_AnimSync.param3 != "") EditorGUILayout.LabelField("Param 3", m_AnimSync.param3);
if (m_AnimSync.param4 != "") EditorGUILayout.LabelField("Param 4", m_AnimSync.param4);
}
}
}
}
#endif

View File

@ -0,0 +1,176 @@
#if ENABLE_UNET
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.Networking;
namespace UnityEditor
{
[CustomEditor(typeof(NetworkBehaviour), true)]
[CanEditMultipleObjects]
public class NetworkBehaviourInspector : Editor
{
bool m_Initialized;
protected List<string> m_SyncVarNames = new List<string>();
Type m_ScriptClass;
bool m_HasOnSerialize;
bool[] m_ShowSyncLists;
GUIContent m_SyncVarIndicatorContent;
protected GUIContent m_NetworkChannelLabel;
protected GUIContent m_NetworkSendIntervalLabel;
internal virtual bool hideScriptField
{
get { return false; }
}
void Init(MonoScript script)
{
m_Initialized = true;
m_ScriptClass = script.GetClass();
m_SyncVarIndicatorContent = new GUIContent("SyncVar", "This variable has been marked with the [SyncVar] attribute.");
m_NetworkChannelLabel = new GUIContent("Network Channel", "QoS channel used for updates. Use the [NetworkSettings] class attribute to change this.");
m_NetworkSendIntervalLabel = new GUIContent("Network Send Interval", "Maximum update rate in seconds. Use the [NetworkSettings] class attribute to change this, or implement GetNetworkSendInterval");
foreach (var field in m_ScriptClass.GetFields(BindingFlags.Public | BindingFlags.Instance))
{
Attribute[] fieldMarkers = (Attribute[])field.GetCustomAttributes(typeof(SyncVarAttribute), true);
if (fieldMarkers.Length > 0)
{
m_SyncVarNames.Add(field.Name);
}
}
var meth = script.GetClass().GetMethod("OnSerialize");
if (meth != null)
{
if (meth.DeclaringType != typeof(NetworkBehaviour))
{
m_HasOnSerialize = true;
}
}
int numSyncLists = 0;
foreach (var f in serializedObject.targetObject.GetType().GetFields())
{
if (f.FieldType.BaseType != null && f.FieldType.BaseType.Name.Contains("SyncList"))
{
numSyncLists += 1;
}
}
if (numSyncLists > 0)
{
m_ShowSyncLists = new bool[numSyncLists];
}
}
public override void OnInspectorGUI()
{
if (!m_Initialized)
{
serializedObject.Update();
SerializedProperty scriptProperty = serializedObject.FindProperty("m_Script");
if (scriptProperty == null)
return;
MonoScript targetScript = scriptProperty.objectReferenceValue as MonoScript;
Init(targetScript);
}
EditorGUI.BeginChangeCheck();
serializedObject.Update();
// Loop through properties and create one field (including children) for each top level property.
SerializedProperty property = serializedObject.GetIterator();
bool expanded = true;
while (property.NextVisible(expanded))
{
bool isSyncVar = m_SyncVarNames.Contains(property.name);
if (property.propertyType == SerializedPropertyType.ObjectReference)
{
if (property.name == "m_Script")
{
if (hideScriptField)
{
continue;
}
EditorGUI.BeginDisabledGroup(true);
}
EditorGUILayout.PropertyField(property, true);
if (isSyncVar)
{
GUILayout.Label(m_SyncVarIndicatorContent, EditorStyles.miniLabel, GUILayout.Width(EditorStyles.miniLabel.CalcSize(m_SyncVarIndicatorContent).x));
}
if (property.name == "m_Script")
{
EditorGUI.EndDisabledGroup();
}
}
else
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(property, true);
if (isSyncVar)
{
GUILayout.Label(m_SyncVarIndicatorContent, EditorStyles.miniLabel, GUILayout.Width(EditorStyles.miniLabel.CalcSize(m_SyncVarIndicatorContent).x));
}
EditorGUILayout.EndHorizontal();
}
expanded = false;
}
serializedObject.ApplyModifiedProperties();
EditorGUI.EndChangeCheck();
// find SyncLists.. they are not properties.
int syncListIndex = 0;
foreach (var field in serializedObject.targetObject.GetType().GetFields())
{
if (field.FieldType.BaseType != null && field.FieldType.BaseType.Name.Contains("SyncList"))
{
m_ShowSyncLists[syncListIndex] = EditorGUILayout.Foldout(m_ShowSyncLists[syncListIndex], "SyncList " + field.Name + " [" + field.FieldType.Name + "]");
if (m_ShowSyncLists[syncListIndex])
{
EditorGUI.indentLevel += 1;
var synclist = field.GetValue(serializedObject.targetObject) as IEnumerable;
if (synclist != null)
{
int index = 0;
var enu = synclist.GetEnumerator();
while (enu.MoveNext())
{
if (enu.Current != null)
{
EditorGUILayout.LabelField("Item:" + index, enu.Current.ToString());
}
index += 1;
}
}
EditorGUI.indentLevel -= 1;
}
syncListIndex += 1;
}
}
if (m_HasOnSerialize)
{
var beh = target as NetworkBehaviour;
if (beh != null)
{
EditorGUILayout.LabelField(m_NetworkChannelLabel, new GUIContent(beh.GetNetworkChannel().ToString()));
EditorGUILayout.LabelField(m_NetworkSendIntervalLabel, new GUIContent(beh.GetNetworkSendInterval().ToString()));
}
}
}
}
} //namespace
#endif //ENABLE_UNET

View File

@ -0,0 +1,132 @@
#if ENABLE_UNET
using System;
using UnityEngine;
using UnityEngine.Networking;
namespace UnityEditor
{
[CustomEditor(typeof(NetworkDiscovery), true)]
[CanEditMultipleObjects]
public class NetworkDiscoveryEditor : Editor
{
bool m_Initialized;
NetworkDiscovery m_Discovery;
SerializedProperty m_BroadcastPortProperty;
SerializedProperty m_BroadcastKeyProperty;
SerializedProperty m_BroadcastVersionProperty;
SerializedProperty m_BroadcastSubVersionProperty;
SerializedProperty m_BroadcastIntervalProperty;
SerializedProperty m_UseNetworkManagerProperty;
SerializedProperty m_BroadcastDataProperty;
SerializedProperty m_ShowGUIProperty;
SerializedProperty m_OffsetXProperty;
SerializedProperty m_OffsetYProperty;
GUIContent m_BroadcastPortLabel;
GUIContent m_BroadcastKeyLabel;
GUIContent m_BroadcastVersionLabel;
GUIContent m_BroadcastSubVersionLabel;
GUIContent m_BroadcastIntervalLabel;
GUIContent m_UseNetworkManagerLabel;
GUIContent m_BroadcastDataLabel;
GUIContent m_ShowGUILabel;
GUIContent m_OffsetXLabel;
GUIContent m_OffsetYLabel;
void Init()
{
if (m_Initialized)
{
if (m_BroadcastPortProperty == null)
{
// need to re-init
}
else
{
return;
}
}
m_Initialized = true;
m_Discovery = target as NetworkDiscovery;
m_BroadcastPortProperty = serializedObject.FindProperty("m_BroadcastPort");
m_BroadcastKeyProperty = serializedObject.FindProperty("m_BroadcastKey");
m_BroadcastVersionProperty = serializedObject.FindProperty("m_BroadcastVersion");
m_BroadcastSubVersionProperty = serializedObject.FindProperty("m_BroadcastSubVersion");
m_BroadcastIntervalProperty = serializedObject.FindProperty("m_BroadcastInterval");
m_UseNetworkManagerProperty = serializedObject.FindProperty("m_UseNetworkManager");
m_BroadcastDataProperty = serializedObject.FindProperty("m_BroadcastData");
m_ShowGUIProperty = serializedObject.FindProperty("m_ShowGUI");
m_OffsetXProperty = serializedObject.FindProperty("m_OffsetX");
m_OffsetYProperty = serializedObject.FindProperty("m_OffsetY");
m_BroadcastPortLabel = new GUIContent("Broadcast Port", "The network port to broadcast to, and listen on.");
m_BroadcastKeyLabel = new GUIContent("Broadcast Key", "The key to broadcast. This key typically identifies the application.");
m_BroadcastVersionLabel = new GUIContent("Broadcast Version", "The version of the application to broadcast. This is used to match versions of the same application.");
m_BroadcastSubVersionLabel = new GUIContent("Broadcast SubVersion", "The sub-version of the application to broadcast.");
m_BroadcastIntervalLabel = new GUIContent("Broadcast Interval", "How often in milliseconds to broadcast when running as a server.");
m_UseNetworkManagerLabel = new GUIContent("Use NetworkManager", "Broadcast information from the NetworkManager, and auto-join matching games using the NetworkManager.");
m_BroadcastDataLabel = new GUIContent("Broadcast Data", "The data to broadcast when not using the NetworkManager");
m_ShowGUILabel = new GUIContent("Show GUI", "Enable to draw the default broadcast control UI.");
m_OffsetXLabel = new GUIContent("Offset X", "The horizonal offset of the GUI.");
m_OffsetYLabel = new GUIContent("Offset Y", "The vertical offset of the GUI.");
}
public override void OnInspectorGUI()
{
Init();
serializedObject.Update();
DrawControls();
serializedObject.ApplyModifiedProperties();
}
void DrawControls()
{
if (m_Discovery == null)
return;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_BroadcastPortProperty, m_BroadcastPortLabel);
EditorGUILayout.PropertyField(m_BroadcastKeyProperty, m_BroadcastKeyLabel);
EditorGUILayout.PropertyField(m_BroadcastVersionProperty, m_BroadcastVersionLabel);
EditorGUILayout.PropertyField(m_BroadcastSubVersionProperty, m_BroadcastSubVersionLabel);
EditorGUILayout.PropertyField(m_BroadcastIntervalProperty, m_BroadcastIntervalLabel);
EditorGUILayout.PropertyField(m_UseNetworkManagerProperty, m_UseNetworkManagerLabel);
if (m_Discovery.useNetworkManager)
{
EditorGUILayout.LabelField(m_BroadcastDataLabel, new GUIContent(m_BroadcastDataProperty.stringValue));
}
else
{
EditorGUILayout.PropertyField(m_BroadcastDataProperty, m_BroadcastDataLabel);
}
EditorGUILayout.Separator();
EditorGUILayout.PropertyField(m_ShowGUIProperty, m_ShowGUILabel);
if (m_Discovery.showGUI)
{
EditorGUILayout.PropertyField(m_OffsetXProperty, m_OffsetXLabel);
EditorGUILayout.PropertyField(m_OffsetYProperty, m_OffsetYLabel);
}
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
}
if (Application.isPlaying)
{
EditorGUILayout.Separator();
EditorGUILayout.LabelField("hostId", m_Discovery.hostId.ToString());
EditorGUILayout.LabelField("running", m_Discovery.running.ToString());
EditorGUILayout.LabelField("isServer", m_Discovery.isServer.ToString());
EditorGUILayout.LabelField("isClient", m_Discovery.isClient.ToString());
}
}
}
}
#endif

View File

@ -0,0 +1,122 @@
#if ENABLE_UNET
using System;
using UnityEngine;
using UnityEngine.Networking;
namespace UnityEditor
{
[CustomEditor(typeof(NetworkIdentity), true)]
[CanEditMultipleObjects]
public class NetworkIdentityEditor : Editor
{
SerializedProperty m_ServerOnlyProperty;
SerializedProperty m_LocalPlayerAuthorityProperty;
GUIContent m_ServerOnlyLabel;
GUIContent m_LocalPlayerAuthorityLabel;
GUIContent m_SpawnLabel;
NetworkIdentity m_NetworkIdentity;
bool m_Initialized;
bool m_ShowObservers;
void Init()
{
if (m_Initialized)
{
return;
}
m_Initialized = true;
m_NetworkIdentity = target as NetworkIdentity;
m_ServerOnlyProperty = serializedObject.FindProperty("m_ServerOnly");
m_LocalPlayerAuthorityProperty = serializedObject.FindProperty("m_LocalPlayerAuthority");
m_ServerOnlyLabel = new GUIContent("Server Only", "True if the object should only exist on the server.");
m_LocalPlayerAuthorityLabel = new GUIContent("Local Player Authority", "True if this object will be controlled by a player on a client.");
m_SpawnLabel = new GUIContent("Spawn Object", "This causes an unspawned server object to be spawned on clients");
}
public override void OnInspectorGUI()
{
if (m_ServerOnlyProperty == null)
{
m_Initialized = false;
}
Init();
serializedObject.Update();
if (m_ServerOnlyProperty.boolValue)
{
EditorGUILayout.PropertyField(m_ServerOnlyProperty, m_ServerOnlyLabel);
EditorGUILayout.LabelField("Local Player Authority cannot be set for server-only objects");
}
else if (m_LocalPlayerAuthorityProperty.boolValue)
{
EditorGUILayout.LabelField("Server Only cannot be set for Local Player Authority objects");
EditorGUILayout.PropertyField(m_LocalPlayerAuthorityProperty, m_LocalPlayerAuthorityLabel);
}
else
{
EditorGUILayout.PropertyField(m_ServerOnlyProperty, m_ServerOnlyLabel);
EditorGUILayout.PropertyField(m_LocalPlayerAuthorityProperty, m_LocalPlayerAuthorityLabel);
}
serializedObject.ApplyModifiedProperties();
if (!Application.isPlaying)
{
return;
}
// Runtime actions below here
EditorGUILayout.Separator();
if (m_NetworkIdentity.observers != null && m_NetworkIdentity.observers.Count > 0)
{
m_ShowObservers = EditorGUILayout.Foldout(m_ShowObservers, "Observers");
if (m_ShowObservers)
{
EditorGUI.indentLevel += 1;
foreach (var o in m_NetworkIdentity.observers)
{
GameObject obj = null;
foreach (var p in o.playerControllers)
{
if (p != null)
{
obj = p.gameObject;
break;
}
}
if (obj)
EditorGUILayout.ObjectField("Connection " + o.connectionId, obj, typeof(GameObject), false);
else
EditorGUILayout.TextField("Connection " + o.connectionId);
}
EditorGUI.indentLevel -= 1;
}
}
PrefabType prefabType = PrefabUtility.GetPrefabType(m_NetworkIdentity.gameObject);
if (prefabType == PrefabType.Prefab)
return;
if (m_NetworkIdentity.gameObject.activeSelf && m_NetworkIdentity.netId.IsEmpty() && NetworkServer.active)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(m_SpawnLabel);
if (GUILayout.Toggle(false, "Spawn", EditorStyles.miniButtonLeft))
{
NetworkServer.Spawn(m_NetworkIdentity.gameObject);
EditorUtility.SetDirty(target); // preview window STILL doens't update immediately..
}
EditorGUILayout.EndHorizontal();
}
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,284 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.Networking
{
[CustomPreview(typeof(GameObject))]
class NetworkInformationPreview : ObjectPreview
{
class NetworkIdentityInfo
{
public GUIContent name;
public GUIContent value;
}
class NetworkBehaviourInfo
{
// This is here just so we can check if it's enabled/disabled
public NetworkBehaviour behaviour;
public GUIContent name;
}
class Styles
{
public GUIStyle labelStyle = new GUIStyle(EditorStyles.label);
public GUIStyle componentName = new GUIStyle(EditorStyles.boldLabel);
public GUIStyle disabledName = new GUIStyle(EditorStyles.miniLabel);
public Styles()
{
Color fontColor = new Color(0.7f, 0.7f, 0.7f);
labelStyle.padding.right += 20;
labelStyle.normal.textColor = fontColor;
labelStyle.active.textColor = fontColor;
labelStyle.focused.textColor = fontColor;
labelStyle.hover.textColor = fontColor;
labelStyle.onNormal.textColor = fontColor;
labelStyle.onActive.textColor = fontColor;
labelStyle.onFocused.textColor = fontColor;
labelStyle.onHover.textColor = fontColor;
componentName.normal.textColor = fontColor;
componentName.active.textColor = fontColor;
componentName.focused.textColor = fontColor;
componentName.hover.textColor = fontColor;
componentName.onNormal.textColor = fontColor;
componentName.onActive.textColor = fontColor;
componentName.onFocused.textColor = fontColor;
componentName.onHover.textColor = fontColor;
disabledName.normal.textColor = fontColor;
disabledName.active.textColor = fontColor;
disabledName.focused.textColor = fontColor;
disabledName.hover.textColor = fontColor;
disabledName.onNormal.textColor = fontColor;
disabledName.onActive.textColor = fontColor;
disabledName.onFocused.textColor = fontColor;
disabledName.onHover.textColor = fontColor;
}
}
List<NetworkIdentityInfo> m_Info;
List<NetworkBehaviourInfo> m_Behaviours;
NetworkIdentity m_Identity;
GUIContent m_Title;
Styles m_Styles = new Styles();
public override void Initialize(UnityObject[] targets)
{
base.Initialize(targets);
GetNetworkInformation(target as GameObject);
}
public override GUIContent GetPreviewTitle()
{
if (m_Title == null)
{
m_Title = new GUIContent("Network Information");
}
return m_Title;
}
public override bool HasPreviewGUI()
{
return m_Info != null && m_Info.Count > 0;
}
public override void OnPreviewGUI(Rect r, GUIStyle background)
{
if (Event.current.type != EventType.Repaint)
return;
if (m_Info == null || m_Info.Count == 0)
return;
if (m_Styles == null)
m_Styles = new Styles();
// Get required label size for the names of the information values we're going to show
// There are two columns, one with label for the name of the info and the next for the value
Vector2 maxNameLabelSize = new Vector2(140, 16);
Vector2 maxValueLabelSize = GetMaxNameLabelSize();
//Apply padding
RectOffset previewPadding = new RectOffset(-5, -5, -5, -5);
r = previewPadding.Add(r);
//Centering
float initialX = r.x + 10;
float initialY = r.y + 10;
Rect labelRect = new Rect(initialX, initialY, maxNameLabelSize.x, maxNameLabelSize.y);
Rect idLabelRect = new Rect(maxNameLabelSize.x, initialY, maxValueLabelSize.x, maxValueLabelSize.y);
foreach (var info in m_Info)
{
GUI.Label(labelRect, info.name, m_Styles.labelStyle);
GUI.Label(idLabelRect, info.value, m_Styles.componentName);
labelRect.y += labelRect.height;
labelRect.x = initialX;
idLabelRect.y += idLabelRect.height;
}
// Show behaviours list in a different way than the name/value pairs above
float lastY = labelRect.y;
if (m_Behaviours != null && m_Behaviours.Count > 0)
{
Vector2 maxBehaviourLabelSize = GetMaxBehaviourLabelSize();
Rect behaviourRect = new Rect(initialX, labelRect.y + 10, maxBehaviourLabelSize.x, maxBehaviourLabelSize.y);
GUI.Label(behaviourRect, new GUIContent("Network Behaviours"), m_Styles.labelStyle);
behaviourRect.x += 20; // indent names
behaviourRect.y += behaviourRect.height;
foreach (var info in m_Behaviours)
{
if (info.behaviour == null)
{
// could be the case in the editor after existing play mode.
continue;
}
if (info.behaviour.enabled)
{
GUI.Label(behaviourRect, info.name, m_Styles.componentName);
}
else
{
GUI.Label(behaviourRect, info.name, m_Styles.disabledName);
}
behaviourRect.y += behaviourRect.height;
lastY = behaviourRect.y;
}
if (m_Identity.observers != null && m_Identity.observers.Count > 0)
{
Rect observerRect = new Rect(initialX, lastY + 10, 200, 20);
GUI.Label(observerRect, new GUIContent("Network observers"), m_Styles.labelStyle);
observerRect.x += 20; // indent names
observerRect.y += observerRect.height;
foreach (var info in m_Identity.observers)
{
GUI.Label(observerRect, info.address + ":" + info.connectionId, m_Styles.componentName);
observerRect.y += observerRect.height;
lastY = observerRect.y;
}
}
if (m_Identity.clientAuthorityOwner != null)
{
Rect ownerRect = new Rect(initialX, lastY + 10, 400, 20);
GUI.Label(ownerRect, new GUIContent("Client Authority: " + m_Identity.clientAuthorityOwner), m_Styles.labelStyle);
}
}
}
// Get the maximum size used by the value of information items
Vector2 GetMaxNameLabelSize()
{
Vector2 maxLabelSize = Vector2.zero;
foreach (var info in m_Info)
{
Vector2 labelSize = m_Styles.labelStyle.CalcSize(info.value);
if (maxLabelSize.x < labelSize.x)
{
maxLabelSize.x = labelSize.x;
}
if (maxLabelSize.y < labelSize.y)
{
maxLabelSize.y = labelSize.y;
}
}
return maxLabelSize;
}
Vector2 GetMaxBehaviourLabelSize()
{
Vector2 maxLabelSize = Vector2.zero;
foreach (var behaviour in m_Behaviours)
{
Vector2 labelSize = m_Styles.labelStyle.CalcSize(behaviour.name);
if (maxLabelSize.x < labelSize.x)
{
maxLabelSize.x = labelSize.x;
}
if (maxLabelSize.y < labelSize.y)
{
maxLabelSize.y = labelSize.y;
}
}
return maxLabelSize;
}
void GetNetworkInformation(GameObject gameObject)
{
m_Identity = gameObject.GetComponent<NetworkIdentity>();
if (m_Identity != null)
{
m_Info = new List<NetworkIdentityInfo>();
m_Info.Add(GetAssetId());
m_Info.Add(GetString("Scene ID", m_Identity.sceneId.ToString()));
if (!Application.isPlaying)
{
return;
}
m_Info.Add(GetString("Network ID", m_Identity.netId.ToString()));
m_Info.Add(GetString("Player Controller ID", m_Identity.playerControllerId.ToString()));
m_Info.Add(GetBoolean("Is Client", m_Identity.isClient));
m_Info.Add(GetBoolean("Is Server", m_Identity.isServer));
m_Info.Add(GetBoolean("Has Authority", m_Identity.hasAuthority));
m_Info.Add(GetBoolean("Is Local Player", m_Identity.isLocalPlayer));
NetworkBehaviour[] behaviours = gameObject.GetComponents<NetworkBehaviour>();
if (behaviours.Length > 0)
{
m_Behaviours = new List<NetworkBehaviourInfo>();
foreach (var behaviour in behaviours)
{
NetworkBehaviourInfo info = new NetworkBehaviourInfo();
info.name = new GUIContent(behaviour.GetType().FullName);
info.behaviour = behaviour;
m_Behaviours.Add(info);
}
}
}
}
NetworkIdentityInfo GetAssetId()
{
string assetId = m_Identity.assetId.ToString();
if (string.IsNullOrEmpty(assetId))
{
assetId = "<object has no prefab>";
}
return GetString("Asset ID", assetId);
}
static NetworkIdentityInfo GetString(string name, string value)
{
NetworkIdentityInfo info = new NetworkIdentityInfo();
info.name = new GUIContent(name);
info.value = new GUIContent(value);
return info;
}
static NetworkIdentityInfo GetBoolean(string name, bool value)
{
NetworkIdentityInfo info = new NetworkIdentityInfo();
info.name = new GUIContent(name);
info.value = new GUIContent((value ? "Yes" : "No"));
return info;
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,255 @@
#if ENABLE_UNET
using System;
using UnityEngine;
using UnityEngine.Networking;
using UnityObject = UnityEngine.Object;
namespace UnityEditor
{
[CustomEditor(typeof(NetworkLobbyManager), true)]
[CanEditMultipleObjects]
class NetworkLobbyManagerEditor : NetworkManagerEditor
{
SerializedProperty m_ShowLobbyGUIProperty;
SerializedProperty m_MaxPlayersProperty;
SerializedProperty m_MaxPlayersPerConnectionProperty;
SerializedProperty m_MinPlayersProperty;
SerializedProperty m_LobbyPlayerPrefabProperty;
SerializedProperty m_GamePlayerPrefabProperty;
GUIContent m_LobbySceneLabel;
GUIContent m_PlaySceneLabel;
GUIContent m_MaxPlayersLabel;
GUIContent m_MaxPlayersPerConnectionLabel;
GUIContent m_MinPlayersLabel;
GUIContent m_ShowLobbyGUILabel;
GUIContent m_LobbyPlayerPrefabLabel;
GUIContent m_GamePlayerPrefabLabel;
bool ShowSlots;
void InitLobby()
{
if (!m_Initialized)
{
m_LobbySceneLabel = new GUIContent("Lobby Scene", "The scene loaded for the lobby.");
m_PlaySceneLabel = new GUIContent("Play Scene", "The scene loaded to play the game.");
m_MaxPlayersLabel = new GUIContent("Max Players", "The maximum number of players allowed in the lobby.");
m_MaxPlayersPerConnectionLabel = new GUIContent("Max Players Per Connection", "The maximum number of players that each connection/client can have in the lobby. Defaults to 1.");
m_MinPlayersLabel = new GUIContent("Minimum Players", "The minimum number of players required to be ready for the game to start. If this is zero then the game can start with any number of players.");
m_ShowLobbyGUILabel = new GUIContent("Show Lobby GUI", "Enable to display the default lobby UI.");
m_LobbyPlayerPrefabLabel = new GUIContent("Lobby Player Prefab", "The prefab to use for a player in the Lobby Scene.");
m_GamePlayerPrefabLabel = new GUIContent("Game Player Prefab", "The prefab to use for a player in the Play Scene.");
m_ShowLobbyGUIProperty = serializedObject.FindProperty("m_ShowLobbyGUI");
m_MaxPlayersProperty = serializedObject.FindProperty("m_MaxPlayers");
m_MaxPlayersPerConnectionProperty = serializedObject.FindProperty("m_MaxPlayersPerConnection");
m_MinPlayersProperty = serializedObject.FindProperty("m_MinPlayers");
m_LobbyPlayerPrefabProperty = serializedObject.FindProperty("m_LobbyPlayerPrefab");
m_GamePlayerPrefabProperty = serializedObject.FindProperty("m_GamePlayerPrefab");
var lobby = target as NetworkLobbyManager;
if (lobby == null)
return;
if (lobby.lobbyScene != "")
{
var offlineObj = GetSceneObject(lobby.lobbyScene);
if (offlineObj == null)
{
Debug.LogWarning("LobbyScene '" + lobby.lobbyScene + "' not found. You must repopulate the LobbyScene slot of the NetworkLobbyManager");
lobby.lobbyScene = "";
}
}
if (lobby.playScene != "")
{
var onlineObj = GetSceneObject(lobby.playScene);
if (onlineObj == null)
{
Debug.LogWarning("PlayScene '" + lobby.playScene + "' not found. You must repopulate the PlayScene slot of the NetworkLobbyManager");
lobby.playScene = "";
}
}
}
Init();
}
public override void OnInspectorGUI()
{
if (m_DontDestroyOnLoadProperty == null || m_DontDestroyOnLoadLabel == null)
m_Initialized = false;
InitLobby();
var lobby = target as NetworkLobbyManager;
if (lobby == null)
return;
serializedObject.Update();
EditorGUILayout.PropertyField(m_DontDestroyOnLoadProperty, m_DontDestroyOnLoadLabel);
EditorGUILayout.PropertyField(m_RunInBackgroundProperty , m_RunInBackgroundLabel);
if (EditorGUILayout.PropertyField(m_LogLevelProperty))
{
LogFilter.currentLogLevel = (int)m_NetworkManager.logLevel;
}
ShowLobbyScenes();
EditorGUILayout.PropertyField(m_ShowLobbyGUIProperty, m_ShowLobbyGUILabel);
EditorGUILayout.PropertyField(m_MaxPlayersProperty, m_MaxPlayersLabel);
EditorGUILayout.PropertyField(m_MaxPlayersPerConnectionProperty, m_MaxPlayersPerConnectionLabel);
EditorGUILayout.PropertyField(m_MinPlayersProperty, m_MinPlayersLabel);
EditorGUILayout.PropertyField(m_LobbyPlayerPrefabProperty, m_LobbyPlayerPrefabLabel);
EditorGUI.BeginChangeCheck();
var newGamPlayer = EditorGUILayout.ObjectField(m_GamePlayerPrefabLabel, lobby.gamePlayerPrefab, typeof(NetworkIdentity), false);
if (EditorGUI.EndChangeCheck())
{
if (newGamPlayer == null)
{
m_GamePlayerPrefabProperty.objectReferenceValue = null;
}
else
{
var newGamePlayerIdentity = newGamPlayer as NetworkIdentity;
if (newGamePlayerIdentity != null)
{
if (newGamePlayerIdentity.gameObject != lobby.gamePlayerPrefab)
{
m_GamePlayerPrefabProperty.objectReferenceValue = newGamePlayerIdentity.gameObject;
}
}
}
}
EditorGUILayout.Separator();
ShowNetworkInfo();
ShowSpawnInfo();
ShowConfigInfo();
ShowSimulatorInfo();
serializedObject.ApplyModifiedProperties();
ShowDerivedProperties(typeof(NetworkLobbyManager), typeof(NetworkManager));
if (!Application.isPlaying)
return;
EditorGUILayout.Separator();
ShowLobbySlots();
}
protected void ShowLobbySlots()
{
var lobby = target as NetworkLobbyManager;
if (lobby == null)
return;
ShowSlots = EditorGUILayout.Foldout(ShowSlots, "LobbySlots");
if (ShowSlots)
{
EditorGUI.indentLevel += 1;
foreach (var slot in lobby.lobbySlots)
{
if (slot == null)
continue;
EditorGUILayout.ObjectField("Slot " + slot.slot, slot.gameObject, typeof(UnityObject), true);
}
EditorGUI.indentLevel -= 1;
}
}
void SetLobbyScene(NetworkLobbyManager lobby, string sceneName)
{
var prop = serializedObject.FindProperty("m_LobbyScene");
prop.stringValue = sceneName;
var offlineProp = serializedObject.FindProperty("m_OfflineScene");
offlineProp.stringValue = sceneName;
EditorUtility.SetDirty(lobby);
}
void SetPlayScene(NetworkLobbyManager lobby, string sceneName)
{
var prop = serializedObject.FindProperty("m_PlayScene");
prop.stringValue = sceneName;
var onlineProp = serializedObject.FindProperty("m_OnlineScene");
onlineProp.stringValue = ""; // this is set to empty deliberately to prevent base class functionality from interfering with LobbyManager
EditorUtility.SetDirty(lobby);
}
protected void ShowLobbyScenes()
{
var lobby = target as NetworkLobbyManager;
if (lobby == null)
return;
var offlineObj = GetSceneObject(lobby.lobbyScene);
EditorGUI.BeginChangeCheck();
var newOfflineScene = EditorGUILayout.ObjectField(m_LobbySceneLabel, offlineObj, typeof(SceneAsset), false);
if (EditorGUI.EndChangeCheck())
{
if (newOfflineScene == null)
{
SetLobbyScene(lobby, "");
}
else
{
if (newOfflineScene.name != lobby.offlineScene)
{
var sceneObj = GetSceneObject(newOfflineScene.name);
if (sceneObj == null)
{
Debug.LogWarning("The scene " + newOfflineScene.name + " cannot be used. To use this scene add it to the build settings for the project");
}
else
{
SetLobbyScene(lobby, newOfflineScene.name);
}
}
}
}
var onlineObj = GetSceneObject(lobby.playScene);
EditorGUI.BeginChangeCheck();
var newOnlineScene = EditorGUILayout.ObjectField(m_PlaySceneLabel, onlineObj, typeof(SceneAsset), false);
if (EditorGUI.EndChangeCheck())
{
if (newOnlineScene == null)
{
SetPlayScene(lobby, "");
}
else
{
if (newOnlineScene.name != m_NetworkManager.onlineScene)
{
var sceneObj = GetSceneObject(newOnlineScene.name);
if (sceneObj == null)
{
Debug.LogWarning("The scene " + newOnlineScene.name + " cannot be used. To use this scene add it to the build settings for the project");
}
else
{
SetPlayScene(lobby, newOnlineScene.name);
}
}
}
}
}
}
}
#endif // ENABLE_UNET

View File

@ -0,0 +1,640 @@
#if ENABLE_UNET
using System;
using System.IO;
using System.Reflection;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.Networking;
using UnityObject = UnityEngine.Object;
namespace UnityEditor
{
[CustomEditor(typeof(NetworkManager), true)]
[CanEditMultipleObjects]
public class NetworkManagerEditor : Editor
{
protected SerializedProperty m_DontDestroyOnLoadProperty;
protected SerializedProperty m_RunInBackgroundProperty;
protected SerializedProperty m_ScriptCRCCheckProperty;
SerializedProperty m_NetworkAddressProperty;
SerializedProperty m_NetworkPortProperty;
SerializedProperty m_ServerBindToIPProperty;
SerializedProperty m_ServerBindAddressProperty;
SerializedProperty m_MaxDelayProperty;
SerializedProperty m_MaxBufferedPacketsProperty;
SerializedProperty m_AllowFragmentationProperty;
protected SerializedProperty m_LogLevelProperty;
SerializedProperty m_MatchHostProperty;
SerializedProperty m_MatchPortProperty;
SerializedProperty m_MatchNameProperty;
SerializedProperty m_MatchSizeProperty;
SerializedProperty m_PlayerPrefabProperty;
SerializedProperty m_AutoCreatePlayerProperty;
SerializedProperty m_PlayerSpawnMethodProperty;
SerializedProperty m_SpawnListProperty;
SerializedProperty m_CustomConfigProperty;
SerializedProperty m_UseWebSocketsProperty;
SerializedProperty m_UseSimulatorProperty;
SerializedProperty m_SimulatedLatencyProperty;
SerializedProperty m_PacketLossPercentageProperty;
SerializedProperty m_ChannelListProperty;
ReorderableList m_ChannelList;
GUIContent m_ShowNetworkLabel;
GUIContent m_ShowSpawnLabel;
GUIContent m_OfflineSceneLabel;
GUIContent m_OnlineSceneLabel;
protected GUIContent m_DontDestroyOnLoadLabel;
protected GUIContent m_RunInBackgroundLabel;
protected GUIContent m_ScriptCRCCheckLabel;
GUIContent m_MaxConnectionsLabel;
GUIContent m_MinUpdateTimeoutLabel;
GUIContent m_ConnectTimeoutLabel;
GUIContent m_DisconnectTimeoutLabel;
GUIContent m_PingTimeoutLabel;
GUIContent m_ThreadAwakeTimeoutLabel;
GUIContent m_ReactorModelLabel;
GUIContent m_ReactorMaximumReceivedMessagesLabel;
GUIContent m_ReactorMaximumSentMessagesLabel;
GUIContent m_MaxBufferedPacketsLabel;
GUIContent m_AllowFragmentationLabel;
GUIContent m_UseWebSocketsLabel;
GUIContent m_UseSimulatorLabel;
GUIContent m_LatencyLabel;
GUIContent m_PacketLossPercentageLabel;
GUIContent m_MatchHostLabel;
GUIContent m_MatchPortLabel;
GUIContent m_MatchNameLabel;
GUIContent m_MatchSizeLabel;
GUIContent m_NetworkAddressLabel;
GUIContent m_NetworkPortLabel;
GUIContent m_ServerBindToIPLabel;
GUIContent m_ServerBindAddressLabel;
GUIContent m_MaxDelayLabel;
GUIContent m_PlayerPrefabLabel;
GUIContent m_AutoCreatePlayerLabel;
GUIContent m_PlayerSpawnMethodLabel;
GUIContent m_AdvancedConfigurationLabel;
ReorderableList m_SpawnList;
protected bool m_Initialized;
protected NetworkManager m_NetworkManager;
protected void Init()
{
if (m_Initialized)
{
return;
}
m_Initialized = true;
m_NetworkManager = target as NetworkManager;
m_ShowNetworkLabel = new GUIContent("Network Info", "Network host settings");
m_ShowSpawnLabel = new GUIContent("Spawn Info", "Registered spawnable objects");
m_OfflineSceneLabel = new GUIContent("Offline Scene", "The scene loaded when the network goes offline (disconnected from server)");
m_OnlineSceneLabel = new GUIContent("Online Scene", "The scene loaded when the network comes online (connected to server)");
m_DontDestroyOnLoadLabel = new GUIContent("Don't Destroy on Load", "Enable to persist the NetworkManager across scene changes.");
m_RunInBackgroundLabel = new GUIContent("Run in Background", "Enable to ensure that the application runs when it does not have focus.\n\nThis is required when testing multiple instances on a single machine, but not recommended for shipping on mobile platforms.");
m_ScriptCRCCheckLabel = new GUIContent("Script CRC Check", "Enable to cause a CRC check between server and client that ensures the NetworkBehaviour scripts match.\n\nThis may not be appropriate in some cases, such as when the client and server are different Unity projects.");
m_MaxConnectionsLabel = new GUIContent("Max Connections", "Maximum number of network connections");
m_MinUpdateTimeoutLabel = new GUIContent("Min Update Timeout", "Minimum time network thread waits for events");
m_ConnectTimeoutLabel = new GUIContent("Connect Timeout", "Time to wait for timeout on connecting");
m_DisconnectTimeoutLabel = new GUIContent("Disconnect Timeout", "Time to wait for detecting disconnect");
m_PingTimeoutLabel = new GUIContent("Ping Timeout", "Time to wait for ping messages");
m_ThreadAwakeTimeoutLabel = new GUIContent("Thread Awake Timeout", "The minimum time period when system will check if there are any messages for send (or receive).");
m_ReactorModelLabel = new GUIContent("Reactor Model", "Defines reactor model for the network library");
m_ReactorMaximumReceivedMessagesLabel = new GUIContent("Reactor Max Recv Messages", "Defines maximum amount of messages in the receive queue");
m_ReactorMaximumSentMessagesLabel = new GUIContent("Reactor Max Sent Messages", "Defines maximum message count in sent queue");
m_MaxBufferedPacketsLabel = new GUIContent("Max Buffered Packets", "The maximum number of packets that can be buffered by a NetworkConnection for each channel. This corresponds to the 'ChannelOption.MaxPendingBuffers' channel option.");
m_AllowFragmentationLabel = new GUIContent("Packet Fragmentation", "Enable to allow NetworkConnection instances to fragment packets that are larger than the maxPacketSize, up to a maximum size of 64K.\n\nThis can cause delays when sending large packets.");
m_UseWebSocketsLabel = new GUIContent("Use WebSockets", "This makes the server listen for connections using WebSockets. This allows WebGL clients to connect to the server.");
m_UseSimulatorLabel = new GUIContent("Use Network Simulator", "This simulates network latency and packet loss on clients. Useful for testing under internet-like conditions");
m_LatencyLabel = new GUIContent("Simulated Average Latency", "The amount of delay in milliseconds to add to network packets");
m_PacketLossPercentageLabel = new GUIContent("Simulated Packet Loss", "The percentage of packets that should be dropped");
m_MatchHostLabel = new GUIContent("MatchMaker Host URI", "The hostname of the matchmaking server.\n\nThe default is mm.unet.unity3d.com, which will connect a client to the nearest data center geographically.");
m_MatchPortLabel = new GUIContent("MatchMaker Port", "The port of the matchmaking service.");
m_MatchNameLabel = new GUIContent("Match Name", "The name that will be used when creating a match in MatchMaker.");
m_MatchSizeLabel = new GUIContent("Maximum Match Size", "The maximum size for the match. This value is compared to the maximum size specified in the service configuration at multiplayer.unity3d.com and the lower of the two is enforced. It must be greater than 1. This is typically used to override the match size for various game modes.");
m_NetworkAddressLabel = new GUIContent("Network Address", "The network address currently in use.");
m_NetworkPortLabel = new GUIContent("Network Port", "The network port currently in use.");
m_ServerBindToIPLabel = new GUIContent("Server Bind to IP", "Enable to bind the server to a specific IP address.");
m_ServerBindAddressLabel = new GUIContent("Server Bind Address Label", "IP to bind the server to, when Server Bind to IP is enabled.");
m_MaxDelayLabel = new GUIContent("Max Delay", "The maximum delay before sending packets on connections.");
m_PlayerPrefabLabel = new GUIContent("Player Prefab", "The default prefab to be used to create player objects on the server.");
m_AutoCreatePlayerLabel = new GUIContent("Auto Create Player", "Enable to automatically create player objects on connect and on Scene change.");
m_PlayerSpawnMethodLabel = new GUIContent("Player Spawn Method", "How to determine which NetworkStartPosition to spawn players at, from all NetworkStartPositions in the Scene.\n\nRandom chooses a random NetworkStartPosition.\n\nRound Robin chooses the next NetworkStartPosition on a round-robin basis.");
m_AdvancedConfigurationLabel = new GUIContent("Advanced Configuration", "Enable to view and edit advanced settings.");
// top-level properties
m_DontDestroyOnLoadProperty = serializedObject.FindProperty("m_DontDestroyOnLoad");
m_RunInBackgroundProperty = serializedObject.FindProperty("m_RunInBackground");
m_ScriptCRCCheckProperty = serializedObject.FindProperty("m_ScriptCRCCheck");
m_LogLevelProperty = serializedObject.FindProperty("m_LogLevel");
// network foldout properties
m_NetworkAddressProperty = serializedObject.FindProperty("m_NetworkAddress");
m_NetworkPortProperty = serializedObject.FindProperty("m_NetworkPort");
m_ServerBindToIPProperty = serializedObject.FindProperty("m_ServerBindToIP");
m_ServerBindAddressProperty = serializedObject.FindProperty("m_ServerBindAddress");
m_MaxDelayProperty = serializedObject.FindProperty("m_MaxDelay");
m_MaxBufferedPacketsProperty = serializedObject.FindProperty("m_MaxBufferedPackets");
m_AllowFragmentationProperty = serializedObject.FindProperty("m_AllowFragmentation");
m_MatchHostProperty = serializedObject.FindProperty("m_MatchHost");
m_MatchPortProperty = serializedObject.FindProperty("m_MatchPort");
m_MatchNameProperty = serializedObject.FindProperty("matchName");
m_MatchSizeProperty = serializedObject.FindProperty("matchSize");
// spawn foldout properties
m_PlayerPrefabProperty = serializedObject.FindProperty("m_PlayerPrefab");
m_AutoCreatePlayerProperty = serializedObject.FindProperty("m_AutoCreatePlayer");
m_PlayerSpawnMethodProperty = serializedObject.FindProperty("m_PlayerSpawnMethod");
m_SpawnListProperty = serializedObject.FindProperty("m_SpawnPrefabs");
m_SpawnList = new ReorderableList(serializedObject, m_SpawnListProperty);
m_SpawnList.drawHeaderCallback = DrawHeader;
m_SpawnList.drawElementCallback = DrawChild;
m_SpawnList.onReorderCallback = Changed;
m_SpawnList.onRemoveCallback = RemoveButton;
m_SpawnList.onChangedCallback = Changed;
m_SpawnList.onReorderCallback = Changed;
m_SpawnList.onAddCallback = AddButton;
m_SpawnList.elementHeight = 16; // this uses a 16x16 icon. other sizes make it stretch.
// network configuration
m_CustomConfigProperty = serializedObject.FindProperty("m_CustomConfig");
m_ChannelListProperty = serializedObject.FindProperty("m_Channels");
m_ChannelList = new ReorderableList(serializedObject, m_ChannelListProperty);
m_ChannelList.drawHeaderCallback = ChannelDrawHeader;
m_ChannelList.drawElementCallback = ChannelDrawChild;
m_ChannelList.onReorderCallback = ChannelChanged;
m_ChannelList.onAddDropdownCallback = ChannelAddButton;
m_ChannelList.onRemoveCallback = ChannelRemoveButton;
m_ChannelList.onChangedCallback = ChannelChanged;
m_ChannelList.onReorderCallback = ChannelChanged;
m_ChannelList.onAddCallback = ChannelChanged;
// Network Simulator
m_UseWebSocketsProperty = serializedObject.FindProperty("m_UseWebSockets");
m_UseSimulatorProperty = serializedObject.FindProperty("m_UseSimulator");
m_SimulatedLatencyProperty = serializedObject.FindProperty("m_SimulatedLatency");
m_PacketLossPercentageProperty = serializedObject.FindProperty("m_PacketLossPercentage");
}
static void ShowPropertySuffix(GUIContent content, SerializedProperty prop, string suffix)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(prop, content);
GUILayout.Label(suffix, EditorStyles.miniLabel, GUILayout.Width(64));
EditorGUILayout.EndHorizontal();
}
protected void ShowSimulatorInfo()
{
EditorGUILayout.PropertyField(m_UseSimulatorProperty, m_UseSimulatorLabel);
if (m_UseSimulatorProperty.boolValue)
{
EditorGUI.indentLevel += 1;
if (Application.isPlaying && m_NetworkManager.client != null)
{
// read only at runtime
EditorGUILayout.LabelField(m_LatencyLabel, new GUIContent(m_NetworkManager.simulatedLatency + " milliseconds"));
EditorGUILayout.LabelField(m_PacketLossPercentageLabel, new GUIContent(m_NetworkManager.packetLossPercentage + "%"));
}
else
{
// Latency
int oldLatency = m_NetworkManager.simulatedLatency;
EditorGUILayout.BeginHorizontal();
int newLatency = EditorGUILayout.IntSlider(m_LatencyLabel, oldLatency, 1, 400);
GUILayout.Label("millsec", EditorStyles.miniLabel, GUILayout.Width(64));
EditorGUILayout.EndHorizontal();
if (newLatency != oldLatency)
{
m_SimulatedLatencyProperty.intValue = newLatency;
}
// Packet Loss
float oldPacketLoss = m_NetworkManager.packetLossPercentage;
EditorGUILayout.BeginHorizontal();
float newPacketLoss = EditorGUILayout.Slider(m_PacketLossPercentageLabel, oldPacketLoss, 0f, 20f);
GUILayout.Label("%", EditorStyles.miniLabel, GUILayout.Width(64));
EditorGUILayout.EndHorizontal();
if (newPacketLoss != oldPacketLoss)
{
m_PacketLossPercentageProperty.floatValue = newPacketLoss;
}
}
EditorGUI.indentLevel -= 1;
}
}
protected void ShowConfigInfo()
{
bool oldCustomConfig = m_NetworkManager.customConfig;
EditorGUILayout.PropertyField(m_CustomConfigProperty, m_AdvancedConfigurationLabel);
// Populate default channels first time a custom config is created.
if (m_CustomConfigProperty.boolValue)
{
if (!oldCustomConfig)
{
if (m_NetworkManager.channels.Count == 0)
{
m_NetworkManager.channels.Add(QosType.ReliableSequenced);
m_NetworkManager.channels.Add(QosType.Unreliable);
m_NetworkManager.customConfig = true;
m_CustomConfigProperty.serializedObject.Update();
m_ChannelList.serializedProperty.serializedObject.Update();
}
}
}
if (m_NetworkManager.customConfig)
{
EditorGUI.indentLevel += 1;
var maxConn = serializedObject.FindProperty("m_MaxConnections");
ShowPropertySuffix(m_MaxConnectionsLabel, maxConn, "connections");
m_ChannelList.DoLayoutList();
maxConn.isExpanded = EditorGUILayout.Foldout(maxConn.isExpanded, "Timeouts");
if (maxConn.isExpanded)
{
EditorGUI.indentLevel += 1;
var minUpdateTimeout = serializedObject.FindProperty("m_ConnectionConfig.m_MinUpdateTimeout");
var connectTimeout = serializedObject.FindProperty("m_ConnectionConfig.m_ConnectTimeout");
var disconnectTimeout = serializedObject.FindProperty("m_ConnectionConfig.m_DisconnectTimeout");
var pingTimeout = serializedObject.FindProperty("m_ConnectionConfig.m_PingTimeout");
ShowPropertySuffix(m_MinUpdateTimeoutLabel, minUpdateTimeout, "millisec");
ShowPropertySuffix(m_ConnectTimeoutLabel, connectTimeout, "millisec");
ShowPropertySuffix(m_DisconnectTimeoutLabel, disconnectTimeout, "millisec");
ShowPropertySuffix(m_PingTimeoutLabel, pingTimeout, "millisec");
EditorGUI.indentLevel -= 1;
}
var threadAwakeTimeout = serializedObject.FindProperty("m_GlobalConfig.m_ThreadAwakeTimeout");
threadAwakeTimeout.isExpanded = EditorGUILayout.Foldout(threadAwakeTimeout.isExpanded, "Global Config");
if (threadAwakeTimeout.isExpanded)
{
EditorGUI.indentLevel += 1;
var reactorModel = serializedObject.FindProperty("m_GlobalConfig.m_ReactorModel");
var reactorMaximumReceivedMessages = serializedObject.FindProperty("m_GlobalConfig.m_ReactorMaximumReceivedMessages");
var reactorMaximumSentMessages = serializedObject.FindProperty("m_GlobalConfig.m_ReactorMaximumSentMessages");
ShowPropertySuffix(m_ThreadAwakeTimeoutLabel, threadAwakeTimeout, "millisec");
EditorGUILayout.PropertyField(reactorModel, m_ReactorModelLabel);
ShowPropertySuffix(m_ReactorMaximumReceivedMessagesLabel, reactorMaximumReceivedMessages, "messages");
ShowPropertySuffix(m_ReactorMaximumSentMessagesLabel, reactorMaximumSentMessages, "messages");
EditorGUI.indentLevel -= 1;
}
EditorGUI.indentLevel -= 1;
}
}
protected void ShowSpawnInfo()
{
m_PlayerPrefabProperty.isExpanded = EditorGUILayout.Foldout(m_PlayerPrefabProperty.isExpanded, m_ShowSpawnLabel);
if (!m_PlayerPrefabProperty.isExpanded)
{
return;
}
EditorGUI.indentLevel += 1;
//The NetworkLobbyManager doesnt use playerPrefab, it has its own player prefab slots, so dont show this
if (!typeof(NetworkLobbyManager).IsAssignableFrom(m_NetworkManager.GetType()))
{
EditorGUILayout.PropertyField(m_PlayerPrefabProperty, m_PlayerPrefabLabel);
}
EditorGUILayout.PropertyField(m_AutoCreatePlayerProperty, m_AutoCreatePlayerLabel);
EditorGUILayout.PropertyField(m_PlayerSpawnMethodProperty, m_PlayerSpawnMethodLabel);
EditorGUI.BeginChangeCheck();
m_SpawnList.DoLayoutList();
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
}
EditorGUI.indentLevel -= 1;
}
protected SceneAsset GetSceneObject(string sceneObjectName)
{
if (string.IsNullOrEmpty(sceneObjectName))
{
return null;
}
foreach (var editorScene in EditorBuildSettings.scenes)
{
var sceneNameWithoutExtension = Path.GetFileNameWithoutExtension(editorScene.path);
if (sceneNameWithoutExtension == sceneObjectName)
{
return AssetDatabase.LoadAssetAtPath(editorScene.path, typeof(SceneAsset)) as SceneAsset;
}
}
if (LogFilter.logWarn) { Debug.LogWarning("Scene [" + sceneObjectName + "] cannot be used with networking. Add this scene to the 'Scenes in the Build' in build settings."); }
return null;
}
protected void ShowNetworkInfo()
{
m_NetworkAddressProperty.isExpanded = EditorGUILayout.Foldout(m_NetworkAddressProperty.isExpanded, m_ShowNetworkLabel);
if (!m_NetworkAddressProperty.isExpanded)
{
return;
}
EditorGUI.indentLevel += 1;
if (EditorGUILayout.PropertyField(m_UseWebSocketsProperty, m_UseWebSocketsLabel))
{
NetworkServer.useWebSockets = m_NetworkManager.useWebSockets;
}
EditorGUILayout.PropertyField(m_NetworkAddressProperty, m_NetworkAddressLabel);
EditorGUILayout.PropertyField(m_NetworkPortProperty, m_NetworkPortLabel);
EditorGUILayout.PropertyField(m_ServerBindToIPProperty, m_ServerBindToIPLabel);
if (m_NetworkManager.serverBindToIP)
{
EditorGUI.indentLevel += 1;
EditorGUILayout.PropertyField(m_ServerBindAddressProperty, m_ServerBindAddressLabel);
EditorGUI.indentLevel -= 1;
}
EditorGUILayout.PropertyField(m_ScriptCRCCheckProperty, m_ScriptCRCCheckLabel);
EditorGUILayout.PropertyField(m_MaxDelayProperty, m_MaxDelayLabel);
EditorGUILayout.PropertyField(m_MaxBufferedPacketsProperty, m_MaxBufferedPacketsLabel);
EditorGUILayout.PropertyField(m_AllowFragmentationProperty, m_AllowFragmentationLabel);
EditorGUILayout.PropertyField(m_MatchHostProperty, m_MatchHostLabel);
EditorGUILayout.PropertyField(m_MatchPortProperty, m_MatchPortLabel);
EditorGUILayout.PropertyField(m_MatchNameProperty, m_MatchNameLabel);
EditorGUILayout.PropertyField(m_MatchSizeProperty, m_MatchSizeLabel);
EditorGUI.indentLevel -= 1;
}
protected void ShowScenes()
{
var offlineObj = GetSceneObject(m_NetworkManager.offlineScene);
var newOfflineScene = EditorGUILayout.ObjectField(m_OfflineSceneLabel, offlineObj, typeof(SceneAsset), false);
if (newOfflineScene == null)
{
var prop = serializedObject.FindProperty("m_OfflineScene");
prop.stringValue = "";
EditorUtility.SetDirty(target);
}
else
{
if (newOfflineScene.name != m_NetworkManager.offlineScene)
{
var sceneObj = GetSceneObject(newOfflineScene.name);
if (sceneObj == null)
{
Debug.LogWarning("The scene " + newOfflineScene.name + " cannot be used. To use this scene add it to the build settings for the project");
}
else
{
var prop = serializedObject.FindProperty("m_OfflineScene");
prop.stringValue = newOfflineScene.name;
EditorUtility.SetDirty(target);
}
}
}
var onlineObj = GetSceneObject(m_NetworkManager.onlineScene);
var newOnlineScene = EditorGUILayout.ObjectField(m_OnlineSceneLabel, onlineObj, typeof(SceneAsset), false);
if (newOnlineScene == null)
{
var prop = serializedObject.FindProperty("m_OnlineScene");
prop.stringValue = "";
EditorUtility.SetDirty(target);
}
else
{
if (newOnlineScene.name != m_NetworkManager.onlineScene)
{
var sceneObj = GetSceneObject(newOnlineScene.name);
if (sceneObj == null)
{
Debug.LogWarning("The scene " + newOnlineScene.name + " cannot be used. To use this scene add it to the build settings for the project");
}
else
{
var prop = serializedObject.FindProperty("m_OnlineScene");
prop.stringValue = newOnlineScene.name;
EditorUtility.SetDirty(target);
}
}
}
}
protected void ShowDerivedProperties(Type baseType, Type superType)
{
bool first = true;
SerializedProperty property = serializedObject.GetIterator();
bool expanded = true;
while (property.NextVisible(expanded))
{
// ignore properties from base class.
var f = baseType.GetField(property.name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var p = baseType.GetProperty(property.name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (f == null && superType != null)
{
f = superType.GetField(property.name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
if (p == null && superType != null)
{
p = superType.GetProperty(property.name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
if (f == null && p == null)
{
if (first)
{
first = false;
EditorGUI.BeginChangeCheck();
serializedObject.Update();
EditorGUILayout.Separator();
}
EditorGUILayout.PropertyField(property, true);
expanded = false;
}
}
if (!first)
{
serializedObject.ApplyModifiedProperties();
EditorGUI.EndChangeCheck();
}
}
public override void OnInspectorGUI()
{
if (m_DontDestroyOnLoadProperty == null || m_DontDestroyOnLoadLabel == null)
m_Initialized = false;
Init();
serializedObject.Update();
EditorGUILayout.PropertyField(m_DontDestroyOnLoadProperty, m_DontDestroyOnLoadLabel);
EditorGUILayout.PropertyField(m_RunInBackgroundProperty , m_RunInBackgroundLabel);
if (EditorGUILayout.PropertyField(m_LogLevelProperty))
{
LogFilter.currentLogLevel = (int)m_NetworkManager.logLevel;
}
ShowScenes();
ShowNetworkInfo();
ShowSpawnInfo();
ShowConfigInfo();
ShowSimulatorInfo();
serializedObject.ApplyModifiedProperties();
ShowDerivedProperties(typeof(NetworkManager), null);
}
static void DrawHeader(Rect headerRect)
{
GUI.Label(headerRect, "Registered Spawnable Prefabs:");
}
internal void DrawChild(Rect r, int index, bool isActive, bool isFocused)
{
SerializedProperty prefab = m_SpawnListProperty.GetArrayElementAtIndex(index);
GameObject go = (GameObject)prefab.objectReferenceValue;
GUIContent label;
if (go == null)
{
label = new GUIContent("Empty", "Drag a prefab with a NetworkIdentity here");
}
else
{
var uv = go.GetComponent<NetworkIdentity>();
if (uv != null)
{
label = new GUIContent(go.name, "AssetId: [" + uv.assetId + "]");
}
else
{
label = new GUIContent(go.name, "No Network Identity");
}
}
var newGameObject = (GameObject)EditorGUI.ObjectField(r, label, go, typeof(GameObject), false);
if (newGameObject != go)
{
if (newGameObject != null && !newGameObject.GetComponent<NetworkIdentity>())
{
if (LogFilter.logError) { Debug.LogError("Prefab " + newGameObject + " cannot be added as spawnable as it doesn't have a NetworkIdentity."); }
return;
}
prefab.objectReferenceValue = newGameObject;
}
}
internal void Changed(ReorderableList list)
{
EditorUtility.SetDirty(target);
}
internal void AddButton(ReorderableList list)
{
m_SpawnListProperty.arraySize += 1;
list.index = m_SpawnListProperty.arraySize - 1;
var obj = m_SpawnListProperty.GetArrayElementAtIndex(m_SpawnListProperty.arraySize - 1);
if (obj.objectReferenceValue != null)
obj.objectReferenceValue = null;
m_SpawnList.index = m_SpawnList.count - 1;
Changed(list);
}
internal void RemoveButton(ReorderableList list)
{
m_SpawnListProperty.DeleteArrayElementAtIndex(m_SpawnList.index);
if (list.index >= m_SpawnListProperty.arraySize)
{
list.index = m_SpawnListProperty.arraySize - 1;
}
}
// List widget functions
static void ChannelDrawHeader(Rect headerRect)
{
GUI.Label(headerRect, "Qos Channels:");
}
internal void ChannelDrawChild(Rect r, int index, bool isActive, bool isFocused)
{
QosType qos = (QosType)m_ChannelListProperty.GetArrayElementAtIndex(index).enumValueIndex;
QosType newValue = (QosType)EditorGUI.EnumPopup(r, "Channel #" + index, qos);
if (newValue != qos)
{
var obj = m_ChannelListProperty.GetArrayElementAtIndex(index);
obj.enumValueIndex = (int)newValue;
}
}
internal void ChannelChanged(ReorderableList list)
{
EditorUtility.SetDirty(target);
}
internal void ChannelAddButton(Rect rect, ReorderableList list)
{
m_ChannelListProperty.arraySize += 1;
var obj = m_ChannelListProperty.GetArrayElementAtIndex(m_ChannelListProperty.arraySize - 1);
obj.enumValueIndex = (int)QosType.ReliableSequenced;
list.index = m_ChannelListProperty.arraySize - 1;
}
internal void ChannelRemoveButton(ReorderableList list)
{
if (m_NetworkManager.channels.Count == 1)
{
if (LogFilter.logError) { Debug.LogError("Cannot remove channel. There must be at least one QoS channel."); }
return;
}
m_ChannelListProperty.DeleteArrayElementAtIndex(m_ChannelList.index);
if (list.index >= m_ChannelListProperty.arraySize - 1)
{
list.index = m_ChannelListProperty.arraySize - 1;
}
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,470 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityObject = UnityEngine.Object;
namespace UnityEditor
{
[CustomEditor(typeof(NetworkManagerHUD), true)]
[CanEditMultipleObjects]
public class NetworkManagerHUDEditor : Editor
{
SerializedProperty m_ShowGUIProperty;
SerializedProperty m_OffsetXProperty;
SerializedProperty m_OffsetYProperty;
protected GUIContent m_ShowNetworkLabel;
protected GUIContent m_ShowServerLabel;
protected GUIContent m_ShowServerConnectionsLabel;
protected GUIContent m_ShowServerObjectsLabel;
protected GUIContent m_ShowClientLabel;
protected GUIContent m_ShowClientObjectsLabel;
protected GUIContent m_ShowMatchMakerLabel;
protected GUIContent m_ShowControlsLabel;
protected GUIContent m_ShowRuntimeGuiLabel;
protected GUIContent m_OffsetXLabel;
protected GUIContent m_OffsetYLabel;
bool m_ShowServer;
bool m_ShowServerConnections;
bool m_ShowServerObjects;
bool m_ShowClient;
bool m_ShowClientObjects;
bool m_ShowMatchMaker;
bool m_ShowControls;
bool m_Initialized;
NetworkManagerHUD m_ManagerHud;
NetworkManager m_Manager;
void Init()
{
if (m_Initialized)
{
if (m_ShowGUIProperty == null)
{
// initialize again.. something got broken
}
else
{
return;
}
}
m_Initialized = true;
m_ManagerHud = target as NetworkManagerHUD;
if (m_ManagerHud != null)
{
m_Manager = m_ManagerHud.manager;
}
m_ShowGUIProperty = serializedObject.FindProperty("showGUI");
m_OffsetXProperty = serializedObject.FindProperty("offsetX");
m_OffsetYProperty = serializedObject.FindProperty("offsetY");
m_ShowServerLabel = new GUIContent("Server Info", "Details of internal server state");
m_ShowServerConnectionsLabel = new GUIContent("Server Connections", "List of local and remote network connections to the server");
m_ShowServerObjectsLabel = new GUIContent("Server Objects", "Networked objects spawned by the server");
m_ShowClientLabel = new GUIContent("Client Info", "Details of internal client state");
m_ShowClientObjectsLabel = new GUIContent("Client Objects", "Networked objects created on the client");
m_ShowMatchMakerLabel = new GUIContent("MatchMaker Info", "Details about the matchmaker state");
m_ShowControlsLabel = new GUIContent("Runtime Controls", "Buttons for controlling network state at runtime");
m_ShowRuntimeGuiLabel = new GUIContent("Show Runtime GUI", "Show the default network control GUI when the game is running");
m_OffsetXLabel = new GUIContent("GUI Horizontal Offset", "Horizontal offset of runtime GUI");
m_OffsetYLabel = new GUIContent("GUI Vertical Offset", "Vertical offset of runtime GUI");
}
List<bool> m_ShowDetailForConnections;
List<bool> m_ShowPlayersForConnections;
List<bool> m_ShowVisibleForConnections;
List<bool> m_ShowOwnedForConnections;
void ShowServerConnections()
{
m_ShowServerConnections = EditorGUILayout.Foldout(m_ShowServerConnections, m_ShowServerConnectionsLabel);
if (m_ShowServerConnections)
{
EditorGUI.indentLevel += 1;
// ensure arrays of bools exists and are large enough
if (m_ShowDetailForConnections == null)
{
m_ShowDetailForConnections = new List<bool>();
m_ShowPlayersForConnections = new List<bool>();
m_ShowVisibleForConnections = new List<bool>();
m_ShowOwnedForConnections = new List<bool>();
}
while (m_ShowDetailForConnections.Count < NetworkServer.connections.Count)
{
m_ShowDetailForConnections.Add(false);
m_ShowPlayersForConnections.Add(false);
m_ShowVisibleForConnections.Add(false);
m_ShowOwnedForConnections.Add(false);
}
// all connections
int index = 0;
foreach (var con in NetworkServer.connections)
{
if (con == null)
{
index += 1;
continue;
}
m_ShowDetailForConnections[index] = EditorGUILayout.Foldout(m_ShowDetailForConnections[index], "Conn: " + con.connectionId + " (" + con.address + ")");
if (m_ShowDetailForConnections[index])
{
EditorGUI.indentLevel += 1;
m_ShowPlayersForConnections[index] = EditorGUILayout.Foldout(m_ShowPlayersForConnections[index], "Players");
if (m_ShowPlayersForConnections[index])
{
EditorGUI.indentLevel += 1;
foreach (var player in con.playerControllers)
{
EditorGUILayout.ObjectField("Player: " + player.playerControllerId, player.gameObject, typeof(GameObject), true);
}
EditorGUI.indentLevel -= 1;
}
m_ShowVisibleForConnections[index] = EditorGUILayout.Foldout(m_ShowVisibleForConnections[index], "Visible Objects");
if (m_ShowVisibleForConnections[index])
{
EditorGUI.indentLevel += 1;
foreach (var v in con.visList)
{
EditorGUILayout.ObjectField("NetId: " + v.netId, v, typeof(NetworkIdentity), true);
}
EditorGUI.indentLevel -= 1;
}
if (con.clientOwnedObjects != null)
{
m_ShowOwnedForConnections[index] = EditorGUILayout.Foldout(m_ShowOwnedForConnections[index], "Owned Objects");
if (m_ShowOwnedForConnections[index])
{
EditorGUI.indentLevel += 1;
foreach (var netId in con.clientOwnedObjects)
{
var obj = NetworkServer.FindLocalObject(netId);
EditorGUILayout.ObjectField("Owned: " + netId, obj, typeof(NetworkIdentity), true);
}
EditorGUI.indentLevel -= 1;
}
}
EditorGUI.indentLevel -= 1;
}
index += 1;
}
EditorGUI.indentLevel -= 1;
}
}
void ShowServerObjects()
{
m_ShowServerObjects = EditorGUILayout.Foldout(m_ShowServerObjects, m_ShowServerObjectsLabel);
if (m_ShowServerObjects)
{
EditorGUI.indentLevel += 1;
foreach (var obj in NetworkServer.objects)
{
string first = "NetId:" + obj.Key;
GameObject value = null;
if (obj.Value != null)
{
NetworkIdentity uv = obj.Value.GetComponent<NetworkIdentity>();
first += " SceneId:" + uv.sceneId;
value = obj.Value.gameObject;
}
EditorGUILayout.ObjectField(first, value, typeof(GameObject), true);
}
EditorGUI.indentLevel -= 1;
}
}
void ShowServerInfo()
{
if (!NetworkServer.active)
{
return;
}
m_ShowServer = EditorGUILayout.Foldout(m_ShowServer, m_ShowServerLabel);
if (!m_ShowServer)
{
return;
}
EditorGUI.indentLevel += 1;
EditorGUILayout.BeginVertical();
ShowServerConnections();
ShowServerObjects();
EditorGUILayout.EndVertical();
EditorGUI.indentLevel -= 1;
}
void ShowClientObjects()
{
m_ShowClientObjects = EditorGUILayout.Foldout(m_ShowClientObjects, m_ShowClientObjectsLabel);
if (m_ShowClientObjects)
{
EditorGUI.indentLevel += 1;
foreach (var obj in ClientScene.objects)
{
string first = "NetId:" + obj.Key;
GameObject value = null;
if (obj.Value != null)
{
NetworkIdentity id = obj.Value.GetComponent<NetworkIdentity>();
first += " SceneId:" + id.sceneId;
value = obj.Value.gameObject;
}
EditorGUILayout.ObjectField(first, value, typeof(GameObject), true);
}
EditorGUI.indentLevel -= 1;
}
}
void ShowClientInfo()
{
if (!NetworkClient.active)
{
return;
}
m_ShowClient = EditorGUILayout.Foldout(m_ShowClient, m_ShowClientLabel);
if (!m_ShowClient)
{
return;
}
EditorGUI.indentLevel += 1;
EditorGUILayout.BeginVertical();
int count = 0;
foreach (var cl in NetworkClient.allClients)
{
if (cl.connection == null)
{
EditorGUILayout.TextField("client " + count + ": ", cl.GetType().Name + " Conn: null");
}
else
{
EditorGUILayout.TextField("client " + count + ":" , cl.GetType().Name + " Conn: " + cl.connection);
EditorGUI.indentLevel += 1;
foreach (var p in cl.connection.playerControllers)
{
EditorGUILayout.LabelField("Player", p.ToString());
}
EditorGUI.indentLevel -= 1;
}
count++;
}
ShowClientObjects();
EditorGUILayout.EndVertical();
EditorGUI.indentLevel -= 1;
}
void ShowMatchMakerInfo()
{
if (m_Manager == null || m_Manager.matchMaker == null)
{
return;
}
m_ShowMatchMaker = EditorGUILayout.Foldout(m_ShowMatchMaker, m_ShowMatchMakerLabel);
if (!m_ShowMatchMaker)
{
return;
}
EditorGUI.indentLevel += 1;
EditorGUILayout.BeginVertical();
EditorGUILayout.LabelField("Match Information", m_Manager.matchInfo == null ? "None" : m_Manager.matchInfo.ToString());
EditorGUILayout.EndVertical();
EditorGUI.indentLevel -= 1;
}
static UnityObject GetSceneObject(string sceneObjectName)
{
if (string.IsNullOrEmpty(sceneObjectName))
{
return null;
}
foreach (var editorScene in EditorBuildSettings.scenes)
{
if (editorScene.path.IndexOf(sceneObjectName) != -1)
{
return AssetDatabase.LoadAssetAtPath(editorScene.path, typeof(UnityObject));
}
}
return null;
}
static Rect GetButtonRect()
{
Rect rect = EditorGUILayout.GetControlRect();
float endcap = rect.width / 6;
Rect newRect = new Rect(rect.xMin + endcap, rect.yMin, rect.width - (endcap * 2), rect.height);
return newRect;
}
void ShowControls()
{
m_ShowControls = EditorGUILayout.Foldout(m_ShowControls, m_ShowControlsLabel);
if (!m_ShowControls)
{
return;
}
if (!string.IsNullOrEmpty(NetworkManager.networkSceneName))
{
EditorGUILayout.ObjectField("Current Scene:", GetSceneObject(NetworkManager.networkSceneName), typeof(UnityObject), true);
}
EditorGUILayout.Separator();
if (!NetworkClient.active && !NetworkServer.active && m_Manager.matchMaker == null)
{
EditorGUILayout.BeginHorizontal();
if (GUILayout.Toggle(false, "LAN Host", EditorStyles.miniButton))
{
m_Manager.StartHost();
}
if (GUILayout.Toggle(false, "LAN Server", EditorStyles.miniButton))
{
m_Manager.StartServer();
}
if (GUILayout.Toggle(false, "LAN Client", EditorStyles.miniButton))
{
m_Manager.StartClient();
}
if (GUILayout.Toggle(false, "Start Matchmaker", EditorStyles.miniButton))
{
m_Manager.StartMatchMaker();
m_ShowMatchMaker = true;
}
EditorGUILayout.EndHorizontal();
}
if (NetworkClient.active && !ClientScene.ready)
{
if (GUI.Button(GetButtonRect(), "Client Ready"))
{
ClientScene.Ready(m_Manager.client.connection);
if (ClientScene.localPlayers.Count == 0)
{
ClientScene.AddPlayer(0);
}
}
}
if (NetworkServer.active || NetworkClient.active)
{
if (GUI.Button(GetButtonRect(), "Stop"))
{
m_Manager.StopServer();
m_Manager.StopClient();
}
}
if (!NetworkServer.active && !NetworkClient.active)
{
EditorGUILayout.Separator();
if (m_Manager.matchMaker != null)
{
if (m_Manager.matchInfo == null)
{
if (m_Manager.matches == null)
{
EditorGUILayout.BeginHorizontal();
if (GUILayout.Toggle(false, "Create Internet Match", EditorStyles.miniButton))
{
m_Manager.matchMaker.CreateMatch(m_Manager.matchName, m_Manager.matchSize, true, "", "", "", 0, 0, m_Manager.OnMatchCreate);
}
if (GUILayout.Toggle(false, "Find Internet Match", EditorStyles.miniButton))
{
m_Manager.matchMaker.ListMatches(0, 20, "", false, 0, 0, m_Manager.OnMatchList);
}
if (GUILayout.Toggle(false, "Stop MatchMaker", EditorStyles.miniButton))
{
m_Manager.StopMatchMaker();
}
EditorGUILayout.EndHorizontal();
m_Manager.matchName = EditorGUILayout.TextField("Room Name:", m_Manager.matchName);
m_Manager.matchSize = (uint)EditorGUILayout.IntField("Room Size:", (int)m_Manager.matchSize);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Toggle(false, "Use Local Relay", EditorStyles.miniButton))
{
m_Manager.SetMatchHost("localhost", 1337, false);
}
if (GUILayout.Toggle(false, "Use Internet Relay", EditorStyles.miniButton))
{
m_Manager.SetMatchHost("mm.unet.unity3d.com", 443, true);
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Separator();
}
else
{
foreach (var match in m_Manager.matches)
{
if (GUI.Button(GetButtonRect(), "Join Match:" + match.name))
{
m_Manager.matchName = match.name;
m_Manager.matchSize = (uint)match.currentSize;
m_Manager.matchMaker.JoinMatch(match.networkId, "", "", "", 0, 0, m_Manager.OnMatchJoined);
}
}
if (GUI.Button(GetButtonRect(), "Stop MatchMaker"))
{
m_Manager.StopMatchMaker();
}
}
}
}
}
EditorGUILayout.Separator();
}
public override void OnInspectorGUI()
{
Init();
serializedObject.Update();
EditorGUILayout.PropertyField(m_ShowGUIProperty, m_ShowRuntimeGuiLabel);
if (m_ManagerHud.showGUI)
{
EditorGUI.indentLevel += 1;
EditorGUILayout.PropertyField(m_OffsetXProperty, m_OffsetXLabel);
EditorGUILayout.PropertyField(m_OffsetYProperty, m_OffsetYLabel);
EditorGUI.indentLevel -= 1;
}
serializedObject.ApplyModifiedProperties();
if (!Application.isPlaying)
{
return;
}
ShowControls();
ShowServerInfo();
ShowClientInfo();
ShowMatchMakerInfo();
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,111 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.Networking
{
[CustomPreview(typeof(NetworkManager))]
class NetworkManagerPreview : ObjectPreview
{
NetworkManager m_Manager;
GUIContent m_Title;
protected GUIContent m_ShowServerMessagesLabel;
protected GUIContent m_ShowClientMessagesLabel;
const int k_Padding = 4;
const int k_ColumnWidth = 120;
const int k_RowHeight = 16;
public override void Initialize(UnityObject[] targets)
{
base.Initialize(targets);
GetNetworkInformation(target as NetworkManager);
m_ShowServerMessagesLabel = new GUIContent("Server Message Handlers:", "Registered network message handler functions");
m_ShowClientMessagesLabel = new GUIContent("Client Message Handlers:", "Registered network message handler functions");
}
public override GUIContent GetPreviewTitle()
{
if (m_Title == null)
{
m_Title = new GUIContent("NetworkManager Message Handlers");
}
return m_Title;
}
public override bool HasPreviewGUI()
{
return m_Manager != null;
}
public override void OnPreviewGUI(Rect r, GUIStyle background)
{
if (Event.current.type != EventType.Repaint)
return;
if (m_Manager == null)
return;
int posY = (int)(r.yMin + k_Padding);
posY = ShowServerMessageHandlers(r, posY);
posY = ShowClientMessageHandlers(r, posY);
}
static string FormatHandler(KeyValuePair<short, NetworkMessageDelegate> handler)
{
return string.Format("{0}:{1}()",
handler.Value.Method.DeclaringType.Name,
handler.Value.Method.Name);
}
int ShowServerMessageHandlers(Rect r, int posY)
{
if (NetworkServer.handlers.Count == 0)
return posY;
GUI.Label(new Rect(r.xMin + k_Padding, posY, 400, k_RowHeight), m_ShowServerMessagesLabel);
posY += k_RowHeight;
foreach (var handler in NetworkServer.handlers)
{
GUI.Label(new Rect(r.xMin + k_Padding * 4, posY, 400, k_RowHeight), MsgType.MsgTypeToString(handler.Key));
GUI.Label(new Rect(r.xMin + k_Padding * 4 + k_ColumnWidth, posY, 400, k_RowHeight), FormatHandler(handler));
posY += k_RowHeight;
}
return posY;
}
int ShowClientMessageHandlers(Rect r, int posY)
{
if (NetworkClient.allClients.Count == 0)
return posY;
NetworkClient client = NetworkClient.allClients[0];
if (client == null)
return posY;
GUI.Label(new Rect(r.xMin + k_Padding, posY, 400, k_RowHeight), m_ShowClientMessagesLabel);
posY += k_RowHeight;
foreach (var handler in client.handlers)
{
GUI.Label(new Rect(r.xMin + k_Padding * 4, posY, 400, k_RowHeight), MsgType.MsgTypeToString(handler.Key));
GUI.Label(new Rect(r.xMin + k_Padding * 4 + k_ColumnWidth, posY, 400, k_RowHeight), FormatHandler(handler));
posY += k_RowHeight;
}
return posY;
}
void GetNetworkInformation(NetworkManager man)
{
m_Manager = man;
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,135 @@
#if ENABLE_UNET
#if ENABLE_UNET_HOST_MIGRATION
using System;
using UnityEngine;
using UnityEngine.Networking;
namespace UnityEditor
{
[CustomEditor(typeof(NetworkMigrationManager), true)]
public class NetworkMigrationManagerEditor : Editor
{
bool m_Initialized;
NetworkMigrationManager m_Manager;
SerializedProperty m_HostMigrationProperty;
SerializedProperty m_ShowGUIProperty;
SerializedProperty m_OffsetXProperty;
SerializedProperty m_OffsetYProperty;
GUIContent m_HostMigrationLabel;
GUIContent m_ShowGUILabel;
GUIContent m_OffsetXLabel;
GUIContent m_OffsetYLabel;
bool m_ShowPeers;
bool m_ShowPlayers;
void Init()
{
if (m_Initialized)
{
if (m_HostMigrationProperty == null)
{
// need to re-init. don't return
}
else
{
return;
}
}
m_Initialized = true;
m_Manager = target as NetworkMigrationManager;
m_HostMigrationProperty = serializedObject.FindProperty("m_HostMigration");
m_ShowGUIProperty = serializedObject.FindProperty("m_ShowGUI");
m_OffsetXProperty = serializedObject.FindProperty("m_OffsetX");
m_OffsetYProperty = serializedObject.FindProperty("m_OffsetY");
m_ShowGUILabel = new GUIContent("Show GUI", "Enable to display the default UI.");
m_OffsetXLabel = new GUIContent("Offset X", "The horizonal offset of the GUI.");
m_OffsetYLabel = new GUIContent("Offset Y", "The vertical offset of the GUI.");
m_HostMigrationLabel = new GUIContent("Use Host Migration", "Enable to use host migration.");
}
public override void OnInspectorGUI()
{
Init();
serializedObject.Update();
DrawControls();
serializedObject.ApplyModifiedProperties();
}
void DrawControls()
{
if (m_Manager == null)
return;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_HostMigrationProperty, m_HostMigrationLabel);
EditorGUILayout.PropertyField(m_ShowGUIProperty, m_ShowGUILabel);
if (m_Manager.showGUI)
{
EditorGUILayout.PropertyField(m_OffsetXProperty, m_OffsetXLabel);
EditorGUILayout.PropertyField(m_OffsetYProperty, m_OffsetYLabel);
}
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
}
if (Application.isPlaying)
{
EditorGUILayout.Separator();
//runtime data
EditorGUILayout.LabelField("Disconnected From Host", m_Manager.disconnectedFromHost.ToString());
EditorGUILayout.LabelField("Waiting to become New Host", m_Manager.waitingToBecomeNewHost.ToString());
EditorGUILayout.LabelField("Waitingto Reconnect to New Host", m_Manager.waitingReconnectToNewHost.ToString());
EditorGUILayout.LabelField("Your ConnectionId", m_Manager.oldServerConnectionId.ToString());
EditorGUILayout.LabelField("New Host Address", m_Manager.newHostAddress);
if (m_Manager.peers != null)
{
m_ShowPeers = EditorGUILayout.Foldout(m_ShowPeers, "Peers");
if (m_ShowPeers)
{
EditorGUI.indentLevel += 1;
foreach (var peer in m_Manager.peers)
{
EditorGUILayout.LabelField("Peer: ", peer.ToString());
}
EditorGUI.indentLevel -= 1;
}
}
if (m_Manager.pendingPlayers != null)
{
m_ShowPlayers = EditorGUILayout.Foldout(m_ShowPlayers, "Pending Players");
if (m_ShowPlayers)
{
EditorGUI.indentLevel += 1;
foreach (var connId in m_Manager.pendingPlayers.Keys)
{
EditorGUILayout.LabelField("Connection: ", connId.ToString());
EditorGUI.indentLevel += 1;
var players = m_Manager.pendingPlayers[connId].players;
foreach (var p in players)
{
EditorGUILayout.ObjectField("Player netId:" + p.netId + " contId:" + p.playerControllerId, p.obj, typeof(GameObject), false);
}
EditorGUI.indentLevel -= 1;
}
EditorGUI.indentLevel -= 1;
}
}
}
}
}
}
#endif
#endif

View File

@ -0,0 +1,51 @@
#if ENABLE_UNET
using System.Collections.Generic;
using UnityEditor.Callbacks;
using UnityEngine;
using UnityEngine.Networking;
namespace UnityEditor
{
public class NetworkScenePostProcess : MonoBehaviour
{
[PostProcessScene]
public static void OnPostProcessScene()
{
var prefabWarnings = new HashSet<string>();
int nextSceneId = 1;
foreach (NetworkIdentity uv in FindObjectsOfType<NetworkIdentity>())
{
// if we had a [ConflictComponent] attribute that would be better than this check.
// also there is no context about which scene this is in.
if (uv.GetComponent<NetworkManager>() != null)
{
Debug.LogError("NetworkManager has a NetworkIdentity component. This will cause the NetworkManager object to be disabled, so it is not recommended.");
}
if (uv.isClient || uv.isServer)
continue;
uv.gameObject.SetActive(false);
uv.ForceSceneId(nextSceneId++);
var prefabGO = UnityEditor.PrefabUtility.GetPrefabParent(uv.gameObject) as GameObject;
if (prefabGO)
{
var prefabRootGO = UnityEditor.PrefabUtility.FindPrefabRoot(prefabGO);
if (prefabRootGO)
{
var identities = prefabRootGO.GetComponentsInChildren<NetworkIdentity>();
if (identities.Length > 1 && !prefabWarnings.Contains(prefabRootGO.name))
{
// make sure we only print one error per prefab
prefabWarnings.Add(prefabRootGO.name);
Debug.LogWarningFormat("Prefab '{0}' has several NetworkIdentity components attached to itself or its children, this is not supported.", prefabRootGO.name);
}
}
}
}
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,39 @@
#if ENABLE_UNET
using UnityEditor;
using UnityEditor.Connect;
using UnityEditor.Web;
namespace UnityEditor
{
[InitializeOnLoad]
internal class NetworkServiceInitialize
{
static NetworkServiceInitialize()
{
UnityEditor.Analytics.CoreStats.OnRequireInBuildHandler += () =>
{
string[] guids = new string[]
{
"870353891bb340e2b2a9c8707e7419ba", // UnityEngine.Networking.dll
"dc443db3e92b4983b9738c1131f555cb" // Standalone/UnityEngine.Networking.dll
};
foreach (var g in guids)
{
string path = AssetDatabase.GUIDToAssetPath(g);
if (!string.IsNullOrEmpty(path))
{
string[] references = BuildPipeline.GetReferencingPlayerAssembliesForDLL(path);
if (references.Length > 0)
{
return true;
}
}
}
return false;
};
}
}
}
#endif

View File

@ -0,0 +1,140 @@
#if ENABLE_UNET
using UnityEditor;
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
namespace UnityEditor
{
[CustomEditor(typeof(NetworkTransformChild), true)]
[CanEditMultipleObjects]
public class NetworkTransformChildEditor : Editor
{
private static GUIContent[] axisOptions = {new GUIContent("None"), new GUIContent("X"), new GUIContent("Y (Top-Down 2D)"), new GUIContent("Z (Side-on 2D)"), new GUIContent("XY (FPS)"), new GUIContent("XZ"), new GUIContent("YZ"), new GUIContent("XYZ (full 3D)")};
bool m_Initialized = false;
NetworkTransformChild sync;
SerializedProperty m_Target;
SerializedProperty m_MovementThreshold;
SerializedProperty m_InterpolateRotation;
SerializedProperty m_InterpolateMovement;
SerializedProperty m_RotationSyncCompression;
protected GUIContent m_TargetLabel;
protected GUIContent m_MovementThresholdLabel;
protected GUIContent m_InterpolateRotationLabel;
protected GUIContent m_InterpolateMovementLabel;
protected GUIContent m_RotationSyncCompressionLabel;
protected GUIContent m_RotationAxisLabel;
SerializedProperty m_NetworkSendIntervalProperty;
GUIContent m_NetworkSendIntervalLabel;
public void Init()
{
if (m_Initialized)
return;
m_Initialized = true;
sync = target as NetworkTransformChild;
m_Target = serializedObject.FindProperty("m_Target");
if (sync.GetComponent<NetworkTransform>() == null)
{
if (LogFilter.logError) { Debug.LogError("NetworkTransformChild must be on the root object with the NetworkTransform, not on the child node"); }
m_Target.objectReferenceValue = null;
}
m_MovementThreshold = serializedObject.FindProperty("m_MovementThreshold");
m_InterpolateRotation = serializedObject.FindProperty("m_InterpolateRotation");
m_InterpolateMovement = serializedObject.FindProperty("m_InterpolateMovement");
m_RotationSyncCompression = serializedObject.FindProperty("m_RotationSyncCompression");
m_NetworkSendIntervalProperty = serializedObject.FindProperty("m_SendInterval");
m_TargetLabel = new GUIContent("Target", "The child transform to be synchronized.");
m_NetworkSendIntervalLabel = new GUIContent("Network Send Rate", "Number of network updates per second.");
EditorGUI.indentLevel += 1;
m_MovementThresholdLabel = new GUIContent("Movement Threshold", "The distance that this object can move without sending a movement synchronization update.");
m_InterpolateRotationLabel = new GUIContent("Interpolate Rotation Factor", "The larger this number is, the faster the object will interpolate to the target facing direction.");
m_InterpolateMovementLabel = new GUIContent("Interpolate Movement Factor", "The larger this number is, the faster the object will interpolate to the target position.");
m_RotationSyncCompressionLabel = new GUIContent("Compress Rotation", "How much to compress rotation sync updates.\n\nChoose None for no compression.\n\nChoose Low for a low amount of compression that preserves accuracy.\n\nChoose High for a high amount of compression that sacrifices accuracy.");
m_RotationAxisLabel = new GUIContent("Rotation Axis", "Which axis to use for rotation.");
EditorGUI.indentLevel -= 1;
}
protected void ShowControls()
{
if (m_Target == null)
{
m_Initialized = false;
}
Init();
serializedObject.Update();
int sendRate = 0;
if (m_NetworkSendIntervalProperty.floatValue != 0)
{
sendRate = (int)(1 / m_NetworkSendIntervalProperty.floatValue);
}
int newSendRate = EditorGUILayout.IntSlider(m_NetworkSendIntervalLabel, sendRate, 0, 30);
if (newSendRate != sendRate)
{
if (newSendRate == 0)
{
m_NetworkSendIntervalProperty.floatValue = 0;
}
else
{
m_NetworkSendIntervalProperty.floatValue = 1.0f / newSendRate;
}
}
if (EditorGUILayout.PropertyField(m_Target, m_TargetLabel))
{
if (sync.GetComponent<NetworkTransform>() == null)
{
if (LogFilter.logError) { Debug.LogError("NetworkTransformChild must be on the root object with the NetworkTransform, not on the child node"); }
m_Target.objectReferenceValue = null;
}
}
EditorGUILayout.PropertyField(m_MovementThreshold, m_MovementThresholdLabel);
if (m_MovementThreshold.floatValue < 0)
{
m_MovementThreshold.floatValue = 0;
EditorUtility.SetDirty(sync);
}
EditorGUILayout.PropertyField(m_InterpolateMovement, m_InterpolateMovementLabel);
EditorGUILayout.PropertyField(m_InterpolateRotation, m_InterpolateRotationLabel);
int newRotation = EditorGUILayout.Popup(
m_RotationAxisLabel,
(int)sync.syncRotationAxis,
axisOptions);
if ((NetworkTransform.AxisSyncMode)newRotation != sync.syncRotationAxis)
{
sync.syncRotationAxis = (NetworkTransform.AxisSyncMode)newRotation;
EditorUtility.SetDirty(sync);
}
EditorGUILayout.PropertyField(m_RotationSyncCompression, m_RotationSyncCompressionLabel);
serializedObject.ApplyModifiedProperties();
}
public override void OnInspectorGUI()
{
ShowControls();
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,212 @@
#if ENABLE_UNET
using System;
using UnityEngine;
using UnityEngine.Networking;
namespace UnityEditor
{
[CustomEditor(typeof(NetworkTransform), true)]
[CanEditMultipleObjects]
public class NetworkTransformEditor : Editor
{
private static GUIContent[] axisOptions = {new GUIContent("None"), new GUIContent("X"), new GUIContent("Y (Top-Down 2D)"), new GUIContent("Z (Side-on 2D)"), new GUIContent("XY (FPS)"), new GUIContent("XZ"), new GUIContent("YZ"), new GUIContent("XYZ (full 3D)")};
bool m_Initialized;
NetworkTransform m_SyncTransform;
SerializedProperty m_TransformSyncMode;
SerializedProperty m_MovementTheshold;
SerializedProperty m_VelocityThreshold;
SerializedProperty m_SnapThreshold;
SerializedProperty m_InterpolateRotation;
SerializedProperty m_InterpolateMovement;
SerializedProperty m_RotationSyncCompression;
SerializedProperty m_SyncSpin;
protected GUIContent m_MovementThesholdLabel;
protected GUIContent m_VelocityThresholdLabel;
protected GUIContent m_SnapThresholdLabel;
protected GUIContent m_InterpolateRotationLabel;
protected GUIContent m_InterpolateMovementLabel;
protected GUIContent m_RotationSyncCompressionLabel;
protected GUIContent m_RotationAxisLabel;
protected GUIContent m_SyncSpinLabel;
SerializedProperty m_NetworkSendIntervalProperty;
GUIContent m_NetworkSendIntervalLabel;
public void Init()
{
if (m_Initialized)
return;
m_Initialized = true;
m_SyncTransform = target as NetworkTransform;
if (m_SyncTransform.transformSyncMode == NetworkTransform.TransformSyncMode.SyncNone)
{
if (m_SyncTransform.GetComponent<Rigidbody>() != null)
{
m_SyncTransform.transformSyncMode = NetworkTransform.TransformSyncMode.SyncRigidbody3D;
m_SyncTransform.syncRotationAxis = NetworkTransform.AxisSyncMode.AxisXYZ;
EditorUtility.SetDirty(m_SyncTransform);
}
else if (m_SyncTransform.GetComponent<Rigidbody2D>() != null)
{
m_SyncTransform.transformSyncMode = NetworkTransform.TransformSyncMode.SyncRigidbody2D;
m_SyncTransform.syncRotationAxis = NetworkTransform.AxisSyncMode.AxisZ;
EditorUtility.SetDirty(m_SyncTransform);
}
else if (m_SyncTransform.GetComponent<CharacterController>() != null)
{
m_SyncTransform.transformSyncMode = NetworkTransform.TransformSyncMode.SyncCharacterController;
m_SyncTransform.syncRotationAxis = NetworkTransform.AxisSyncMode.AxisXYZ;
EditorUtility.SetDirty(m_SyncTransform);
}
else
{
m_SyncTransform.transformSyncMode = NetworkTransform.TransformSyncMode.SyncTransform;
m_SyncTransform.syncRotationAxis = NetworkTransform.AxisSyncMode.AxisXYZ;
EditorUtility.SetDirty(m_SyncTransform);
}
}
m_TransformSyncMode = serializedObject.FindProperty("m_TransformSyncMode");
m_MovementTheshold = serializedObject.FindProperty("m_MovementTheshold");
m_VelocityThreshold = serializedObject.FindProperty("m_VelocityThreshold");
m_SnapThreshold = serializedObject.FindProperty("m_SnapThreshold");
m_InterpolateRotation = serializedObject.FindProperty("m_InterpolateRotation");
m_InterpolateMovement = serializedObject.FindProperty("m_InterpolateMovement");
m_RotationSyncCompression = serializedObject.FindProperty("m_RotationSyncCompression");
m_SyncSpin = serializedObject.FindProperty("m_SyncSpin");
m_NetworkSendIntervalProperty = serializedObject.FindProperty("m_SendInterval");
m_NetworkSendIntervalLabel = new GUIContent("Network Send Rate", "Number of network updates per second.");
EditorGUI.indentLevel += 1;
m_MovementThesholdLabel = new GUIContent("Movement Threshold", "The distance that this object can move without sending a movement synchronization update.");
m_VelocityThresholdLabel = new GUIContent("Velocity Threshold", "The minimum velocity difference that will be synchronized over the network.");
m_SnapThresholdLabel = new GUIContent("Snap Threshold", "If a movement update puts this object further from its current position that this value, it will snap to the updated position instead of moving smoothly.");
m_InterpolateRotationLabel = new GUIContent("Interpolate Rotation Factor", "The larger this number is, the faster the object will interpolate to the target facing direction.");
m_InterpolateMovementLabel = new GUIContent("Interpolate Movement Factor", "The larger this number is, the faster the object will interpolate to the target position.");
m_RotationSyncCompressionLabel = new GUIContent("Compress Rotation", "How much to compress rotation sync updates.\n\nChoose None for no compression.\n\nChoose Low for a low amount of compression that preserves accuracy.\n\nChoose High for a high amount of compression that sacrifices accuracy.");
m_RotationAxisLabel = new GUIContent("Rotation Axis", "Which axis to use for rotation.");
m_SyncSpinLabel = new GUIContent("Sync Angular Velocity", "Enable to sync angular velocity.");
EditorGUI.indentLevel -= 1;
}
protected void ShowControls()
{
if (m_TransformSyncMode == null)
{
m_Initialized = false;
}
Init();
serializedObject.Update();
int sendRate = 0;
if (m_NetworkSendIntervalProperty.floatValue != 0)
{
sendRate = (int)(1 / m_NetworkSendIntervalProperty.floatValue);
}
int newSendRate = EditorGUILayout.IntSlider(m_NetworkSendIntervalLabel, sendRate, 0, 30);
if (newSendRate != sendRate)
{
if (newSendRate == 0)
{
m_NetworkSendIntervalProperty.floatValue = 0;
}
else
{
m_NetworkSendIntervalProperty.floatValue = 1.0f / newSendRate;
}
}
EditorGUILayout.PropertyField(m_TransformSyncMode);
if (m_TransformSyncMode.enumValueIndex == (int)NetworkTransform.TransformSyncMode.SyncRigidbody3D)
{
Rigidbody r3D = m_SyncTransform.GetComponent<Rigidbody>();
if (r3D == null)
{
Debug.LogError("Object has no Rigidbody component.");
m_TransformSyncMode.enumValueIndex = (int)NetworkTransform.TransformSyncMode.SyncTransform;
EditorUtility.SetDirty(m_SyncTransform);
}
}
if (m_TransformSyncMode.enumValueIndex == (int)NetworkTransform.TransformSyncMode.SyncRigidbody2D)
{
Rigidbody2D r2D = m_SyncTransform.GetComponent<Rigidbody2D>();
if (r2D == null)
{
Debug.LogError("Object has no Rigidbody2D component.");
m_TransformSyncMode.enumValueIndex = (int)NetworkTransform.TransformSyncMode.SyncTransform;
EditorUtility.SetDirty(m_SyncTransform);
}
}
if (m_TransformSyncMode.enumValueIndex == (int)NetworkTransform.TransformSyncMode.SyncCharacterController)
{
var cc = m_SyncTransform.GetComponent<CharacterController>();
if (cc == null)
{
Debug.LogError("Object has no CharacterController component.");
m_TransformSyncMode.enumValueIndex = (int)NetworkTransform.TransformSyncMode.SyncTransform;
EditorUtility.SetDirty(m_SyncTransform);
}
}
EditorGUILayout.LabelField("Movement:");
EditorGUI.indentLevel += 1;
EditorGUILayout.PropertyField(m_MovementTheshold, m_MovementThesholdLabel);
if (m_VelocityThreshold.floatValue < 0)
{
m_VelocityThreshold.floatValue = 0;
EditorUtility.SetDirty(m_SyncTransform);
}
if ((m_TransformSyncMode.enumValueIndex == (int)NetworkTransform.TransformSyncMode.SyncRigidbody3D) || (m_TransformSyncMode.enumValueIndex == (int)NetworkTransform.TransformSyncMode.SyncRigidbody2D))
{
EditorGUILayout.PropertyField(m_VelocityThreshold, m_VelocityThresholdLabel);
}
if (m_MovementTheshold.floatValue < 0)
{
m_MovementTheshold.floatValue = 0;
EditorUtility.SetDirty(m_SyncTransform);
}
EditorGUILayout.PropertyField(m_SnapThreshold, m_SnapThresholdLabel);
EditorGUILayout.PropertyField(m_InterpolateMovement, m_InterpolateMovementLabel);
EditorGUI.indentLevel -= 1;
EditorGUILayout.LabelField("Rotation:");
EditorGUI.indentLevel += 1;
int newRotation = EditorGUILayout.Popup(
m_RotationAxisLabel,
(int)m_SyncTransform.syncRotationAxis,
axisOptions);
if ((NetworkTransform.AxisSyncMode)newRotation != m_SyncTransform.syncRotationAxis)
{
m_SyncTransform.syncRotationAxis = (NetworkTransform.AxisSyncMode)newRotation;
EditorUtility.SetDirty(m_SyncTransform);
}
EditorGUILayout.PropertyField(m_InterpolateRotation, m_InterpolateRotationLabel);
EditorGUILayout.PropertyField(m_RotationSyncCompression, m_RotationSyncCompressionLabel);
EditorGUILayout.PropertyField(m_SyncSpin, m_SyncSpinLabel);
EditorGUI.indentLevel -= 1;
serializedObject.ApplyModifiedProperties();
}
public override void OnInspectorGUI()
{
ShowControls();
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,86 @@
#if ENABLE_UNET
using System;
using UnityEngine;
using UnityEngine.Networking;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.Networking
{
[CustomPreview(typeof(GameObject))]
class NetworkTransformPreview : ObjectPreview
{
NetworkTransform m_Transform;
Rigidbody m_Rigidbody3D;
Rigidbody2D m_Rigidbody2D;
GUIContent m_Title;
public override void Initialize(UnityObject[] targets)
{
base.Initialize(targets);
GetNetworkInformation(target as GameObject);
}
public override GUIContent GetPreviewTitle()
{
if (m_Title == null)
{
m_Title = new GUIContent("Network Transform");
}
return m_Title;
}
public override bool HasPreviewGUI()
{
return m_Transform != null;
}
public override void OnPreviewGUI(Rect r, GUIStyle background)
{
if (Event.current.type != EventType.Repaint)
return;
if (m_Transform == null)
return;
const int padding = 4;
int posY = 4;
float posDiff = (m_Transform.transform.position - m_Transform.targetSyncPosition).magnitude;
GUI.Label(new Rect(r.xMin + padding, r.y + posY, 600, 20), "Position: " + m_Transform.transform.position + " Target: " + m_Transform.targetSyncPosition + " Diff: " + posDiff);
posY += 20;
if (m_Rigidbody3D != null)
{
float angleDiff3D = Quaternion.Angle(m_Transform.rigidbody3D.rotation, m_Transform.targetSyncRotation3D);
GUI.Label(new Rect(r.xMin + padding, r.y + posY, 600, 20), "Angle: " + m_Transform.rigidbody3D.rotation + " Target: " + m_Transform.targetSyncRotation3D + " Diff: " + angleDiff3D);
posY += 20;
GUI.Label(new Rect(r.xMin + padding, r.y + posY, 600, 20), "Velocity: " + m_Transform.rigidbody3D.velocity + " Target: " + m_Transform.targetSyncVelocity);
posY += 20;
}
if (m_Rigidbody2D != null)
{
float angleDiff2D = m_Transform.rigidbody2D.rotation - m_Transform.targetSyncRotation2D;
GUI.Label(new Rect(r.xMin + padding, r.y + posY, 600, 20), "Angle: " + m_Transform.rigidbody2D.rotation + " Target: " + m_Transform.targetSyncRotation2D + " Diff: " + angleDiff2D);
posY += 20;
GUI.Label(new Rect(r.xMin + padding, r.y + posY, 600, 20), "Velocity: " + m_Transform.rigidbody2D.velocity + " Target: " + m_Transform.targetSyncVelocity);
posY += 20;
}
GUI.Label(new Rect(r.xMin + padding, r.y + posY, 200, 20), "Last SyncTime: " + (Time.time - m_Transform.lastSyncTime));
posY += 20;
}
void GetNetworkInformation(GameObject gameObject)
{
m_Transform = gameObject.GetComponent<NetworkTransform>();
m_Rigidbody3D = gameObject.GetComponent<Rigidbody>();
m_Rigidbody2D = gameObject.GetComponent<Rigidbody2D>();
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
namespace UnityEditor
{
[CustomEditor(typeof(NetworkTransformVisualizer), true)]
[CanEditMultipleObjects]
public class NetworkTransformVisualizerEditor : NetworkBehaviourInspector
{
internal override bool hideScriptField
{
get
{
return true;
}
}
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("UnityEditor.Networking")]
[assembly: AssemblyDescription("Networking High Level API Editor part")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Unity Technologies")]
[assembly: AssemblyProduct("UnityEditor.Networking")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: InternalsVisibleTo("Assembly-CSharp-Editor-testable")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("5f32cd94-baa9-4578-a686-d4b9d6b660f7")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F290E7F0-596E-495F-BD1F-E66386A1C597}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>UnityEditor.Networking</RootNamespace>
<AssemblyName>UnityEditor.Networking</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;ENABLE_UNET;ENABLE_UNET_HOST_MIGRATION</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;ENABLE_UNET;ENABLE_UNET_HOST_MIGRATION</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="UnityEditor">
<HintPath>..\lib\UnityEditor.dll</HintPath>
</Reference>
<Reference Include="UnityEngine">
<HintPath>..\lib\UnityEngine.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.Networking">
<HintPath>..\Output\Standalone\UnityEngine.Networking.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="NetworkAnimatorEditor.cs" />
<Compile Include="NetworkDiscoveryEditor.cs" />
<Compile Include="NetworkLobbyManagerEditor.cs" />
<Compile Include="NetworkManagerPreview.cs" />
<Compile Include="NetworkTransformChildEditor.cs" />
<Compile Include="NetworkTransformEditor.cs" />
<Compile Include="NetworkTransformPreview.cs" />
<Compile Include="NetworkTransformVisualizerEditor.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="NetworkManagerEditor.cs" />
<Compile Include="NetworkManagerHUDEditor.cs" />
<Compile Include="NetworkBehaviourInspector.cs" />
<Compile Include="NetworkInformationPreview.cs" />
<Compile Include="NetworkServiceInitialize.cs" />
<Compile Include="NetworkScenePostProcess.cs" />
<Compile Include="NetworkIdentityEditor.cs" />
<Compile Include="NetworkMigrationManagerEditor.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="AfterBuild">
<MakeDir Directories="$(ProjectDir)..\Output\Editor" />
<Copy SourceFiles="$(TargetDir)$(TargetName).dll" DestinationFiles="$(ProjectDir)..\Output\Editor\$(TargetName).dll" />
<Copy Condition="'$(Configuration)' == 'Debug' And '$(OS)' == 'Unix'" SourceFiles="$(TargetDir)$(TargetName).dll.mdb" DestinationFiles="$(ProjectDir)..\Output\Editor\$(TargetName).dll.mdb" />
<Copy Condition="'$(Configuration)' == 'Debug' And '$(OS)' != 'Unix'" SourceFiles="$(TargetDir)$(TargetName).pdb" DestinationFiles="$(ProjectDir)..\Output\Editor\$(TargetName).pdb" />
<!--Uncomment the block below and change the destination to copy the built dll into your unity install directory-->
<!--<Copy SourceFiles="$(TargetDir)$(TargetName).dll" DestinationFiles="C:\Program Files\Unity\Editor\Data\UnityExtensions\Unity\Networking\Editor\$(TargetName).dll"/>
<Copy Condition="'$(Configuration)' == 'Debug'" SourceFiles="$(TargetDir)$(TargetName).mdb" DestinationFiles="C:\Program Files\Unity\Editor\Data\UnityExtensions\Unity\Networking\Editor\$(TargetName).mdb"/>-->
<!--<Copy SourceFiles="$(TargetDir)$(TargetName).dll" DestinationFiles="/Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/Networking/Editor/$(TargetName).dll"/>
<Copy Condition="'$(Configuration)' == 'Debug'" SourceFiles="$(TargetDir)$(TargetName).dll.mdb" DestinationFiles="/Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/Networking/Editor/$(TargetName).dll.mdb"/>-->
</Target>
</Project>

View File

@ -0,0 +1,3 @@
Repository: https://github.com/Unity-Technologies/cecil.git
Branch: * unity-master
Commit: b28d33c7da63de8162b41338f4d408b77a59f4c9

View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015, Unity Technologies
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,47 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityEngine.Networking", "Runtime\UnityEngine.Networking.csproj", "{5F1B8F9B-4500-4D09-808B-F43E8337DF05}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityEditor.Networking", "Editor\UnityEditor.Networking.csproj", "{F290E7F0-596E-495F-BD1F-E66386A1C597}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityEngine.Networking-Editor", "Runtime-Editor\UnityEngine.Networking-Editor.csproj", "{F8AD1DD0-E73F-419B-97BB-3C708BCA79C8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UNetWeaver", "Weaver\UNetWeaver.csproj", "{709222FD-15C2-497D-8B31-366ADCC074CD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
Testing|Any CPU = Testing|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5F1B8F9B-4500-4D09-808B-F43E8337DF05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F1B8F9B-4500-4D09-808B-F43E8337DF05}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F1B8F9B-4500-4D09-808B-F43E8337DF05}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F1B8F9B-4500-4D09-808B-F43E8337DF05}.Release|Any CPU.Build.0 = Release|Any CPU
{5F1B8F9B-4500-4D09-808B-F43E8337DF05}.Testing|Any CPU.ActiveCfg = Release|Any CPU
{5F1B8F9B-4500-4D09-808B-F43E8337DF05}.Testing|Any CPU.Build.0 = Release|Any CPU
{709222FD-15C2-497D-8B31-366ADCC074CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{709222FD-15C2-497D-8B31-366ADCC074CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{709222FD-15C2-497D-8B31-366ADCC074CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{709222FD-15C2-497D-8B31-366ADCC074CD}.Release|Any CPU.Build.0 = Release|Any CPU
{709222FD-15C2-497D-8B31-366ADCC074CD}.Testing|Any CPU.ActiveCfg = Release|Any CPU
{709222FD-15C2-497D-8B31-366ADCC074CD}.Testing|Any CPU.Build.0 = Release|Any CPU
{F290E7F0-596E-495F-BD1F-E66386A1C597}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F290E7F0-596E-495F-BD1F-E66386A1C597}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F290E7F0-596E-495F-BD1F-E66386A1C597}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F290E7F0-596E-495F-BD1F-E66386A1C597}.Release|Any CPU.Build.0 = Release|Any CPU
{F290E7F0-596E-495F-BD1F-E66386A1C597}.Testing|Any CPU.ActiveCfg = Release|Any CPU
{F290E7F0-596E-495F-BD1F-E66386A1C597}.Testing|Any CPU.Build.0 = Release|Any CPU
{F8AD1DD0-E73F-419B-97BB-3C708BCA79C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8AD1DD0-E73F-419B-97BB-3C708BCA79C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8AD1DD0-E73F-419B-97BB-3C708BCA79C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8AD1DD0-E73F-419B-97BB-3C708BCA79C8}.Release|Any CPU.Build.0 = Release|Any CPU
{F8AD1DD0-E73F-419B-97BB-3C708BCA79C8}.Testing|Any CPU.ActiveCfg = Release|Any CPU
{F8AD1DD0-E73F-419B-97BB-3C708BCA79C8}.Testing|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,38 @@
# README #
The Unity Networking extension DLL is the open source component of the Unity Multiplayer Networking system. In this DLL we have the whole networking system except the NetworkTransport related APIs and classes. This is all the high level classes and components which make up the user friendly system of creating multiplayer games. This document details how you can compile your own version of the Networking extension DLL and use that in your games and applications.
### What license is the Networking extension DLL shipped under? ###
The Networking extension DLL is released under an MIT/X11 license; see the LICENSE file.
This means that you pretty much can customize and embed it in any software under any license without any other constraints than preserving the copyright and license information while adding your own copyright and license information.
You can keep the source to yourself or share your customized version under the same MIT license or a compatible license.
If you want to contribute patches back, please keep it under the unmodified MIT license so it can be integrated in future versions and shared under the same license.
### How do I get started? ###
* Clone this repository onto a location on your computer.
* Configure your IDE for the Unity coding standard, look in the .editorconfig file for more information
* Open the project in Visual Studio or MonoDevelop
* If you are using MonoDevelop
* Ensure you enable XBuild (Preferences -> Projects -> Build ->"Compile projects using MSBuild/XBuild")
* You may need to restart MonoDevelop
* Build the solution
* A folder will be created in the root directory called "Output", the generated dll's will output here in the correct folder structure
* Windows: Copy the contents of Output folder to: `Data\UnityExtensions\Unity\Networking\{UNITY_VERSION}`
* OSX: Copy the contents of Output folder to: `Unity.app/Contents/UnityExtensions/Unity/Networking/{UNITY_VERSION}`
* For the weaver the files need to be copied to a different place, they appear in "Output/Weaver"
* Windows: Copy the contents of Output/Weaver folder to: `Data\Managed`
* OSX: Copy the contents of Output/Weaver folder to: `Unity.app/Contents\Managed`
* If you want the dll's to copy automatically on build
* For each visual studio project file
* Open the file in a text editor
* Locate the section: <Target Name="AfterBuild">
* Follow the instructions in the comments
### Will you be taking pull requests? ###
We'll consider all incoming pull requests that we get. It's likely we'll take bug fixes this way but anything else will be handled on a case by case basis. Changes will not be applied directly to this repository but to the mainline Unity repository and will then appear here when the code is released in a new Unity version.

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F8AD1DD0-E73F-419B-97BB-3C708BCA79C8}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>UnityEngine.Networking</RootNamespace>
<AssemblyName>UnityEngine.Networking</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;UNITY_EDITOR;ENABLE_UNET;ENABLE_UNET_HOST_MIGRATION</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;UNITY_EDITOR;ENABLE_UNET;ENABLE_UNET_HOST_MIGRATION</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="UnityEditor">
<HintPath>..\lib\UnityEditor.dll</HintPath>
</Reference>
<Reference Include="UnityEngine">
<HintPath>..\lib\UnityEngine.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Runtime\ChannelBuffer.cs" />
<Compile Include="..\Runtime\ChannelPacket.cs" />
<Compile Include="..\Runtime\ClientScene.cs" />
<Compile Include="..\Runtime\ConnectionArray.cs" />
<Compile Include="..\Runtime\CustomAttributes.cs" />
<Compile Include="..\Runtime\DotNetCompatibility.cs" />
<Compile Include="..\Runtime\LocalConnections.cs" />
<Compile Include="..\Runtime\LogFilter.cs" />
<Compile Include="..\Runtime\Messages.cs" />
<Compile Include="..\Runtime\NetworkAnimator.cs" />
<Compile Include="..\Runtime\NetworkBuffer.cs" />
<Compile Include="..\Runtime\NetworkCRC.cs" />
<Compile Include="..\Runtime\NetworkDiscovery.cs" />
<Compile Include="..\Runtime\NetworkHash128.cs" />
<Compile Include="..\Runtime\NetworkInstanceId.cs" />
<Compile Include="..\Runtime\NetworkLobbyManager.cs" />
<Compile Include="..\Runtime\NetworkLobbyPlayer.cs" />
<Compile Include="..\Runtime\NetworkMessageHandlers.cs" />
<Compile Include="..\Runtime\NetworkProximityChecker.cs" />
<Compile Include="..\Runtime\NetworkScene.cs" />
<Compile Include="..\Runtime\NetworkSceneId.cs" />
<Compile Include="..\Runtime\NetworkStartPosition.cs" />
<Compile Include="..\Runtime\NetworkTranformChild.cs" />
<Compile Include="..\Runtime\NetworkTransform.cs" />
<Compile Include="..\Runtime\NetworkTransformVisualizer.cs" />
<Compile Include="..\Runtime\PlayerController.cs" />
<Compile Include="..\Runtime\Properties\AssemblyInfo.cs" />
<Compile Include="..\Runtime\NetworkClient.cs" />
<Compile Include="..\Runtime\NetworkConnection.cs" />
<Compile Include="..\Runtime\LocalClient.cs" />
<Compile Include="..\Runtime\NetworkManager.cs" />
<Compile Include="..\Runtime\NetworkManagerHUD.cs" />
<Compile Include="..\Runtime\NetworkBehaviour.cs" />
<Compile Include="..\Runtime\NetworkIdentity.cs" />
<Compile Include="..\Runtime\UNetwork.cs" />
<Compile Include="..\Runtime\NetworkReader.cs" />
<Compile Include="..\Runtime\NetworkServer.cs" />
<Compile Include="..\Runtime\SyncList.cs" />
<Compile Include="..\Runtime\NetworkWriter.cs" />
<Compile Include="..\Runtime\NetworkMigrationManager.cs" />
<Compile Include="..\Runtime\NetworkServerSimple.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="AfterBuild">
<MakeDir Directories="$(ProjectDir)..\Output" />
<Copy SourceFiles="$(TargetDir)$(TargetName).dll" DestinationFiles="$(ProjectDir)..\Output\$(TargetName).dll" />
<Copy Condition="'$(Configuration)' == 'Debug' And '$(OS)' == 'Unix'" SourceFiles="$(TargetDir)$(TargetName).dll.mdb" DestinationFiles="$(ProjectDir)..\Output\$(TargetName).dll.mdb" />
<Copy Condition="'$(Configuration)' == 'Debug' And '$(OS)' != 'Unix'" SourceFiles="$(TargetDir)$(TargetName).pdb" DestinationFiles="$(ProjectDir)..\Output\$(TargetName).pdb" />
<!--Uncomment the block below and change the destination to copy the built dll into your unity install directory-->
<!--<Copy SourceFiles="$(TargetDir)$(TargetName).dll" DestinationFiles="C:\Program Files\Unity\Editor\Data\UnityExtensions\Unity\Networking\$(TargetName).dll"/>
<Copy Condition="'$(Configuration)' == 'Debug'" SourceFiles="$(TargetDir)$(TargetName).pdb" DestinationFiles="C:\Program Files\Unity\Editor\Data\UnityExtensions\Unity\Networking\$(TargetName).pdb"/>-->
<!--<Copy SourceFiles="$(TargetDir)$(TargetName).dll" DestinationFiles="/Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/Networking/$(TargetName).dll"/>
<Copy Condition="'$(Configuration)' == 'Debug'" SourceFiles="$(TargetDir)$(TargetName).dll.mdb" DestinationFiles="/Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/Networking/$(TargetName).dll.mdb"/>-->
</Target>
</Project>

View File

@ -0,0 +1,409 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
namespace UnityEngine.Networking
{
class ChannelBuffer : IDisposable
{
NetworkConnection m_Connection;
ChannelPacket m_CurrentPacket;
float m_LastFlushTime;
byte m_ChannelId;
int m_MaxPacketSize;
bool m_IsReliable;
bool m_AllowFragmentation;
bool m_IsBroken;
int m_MaxPendingPacketCount;
const int k_MaxFreePacketCount = 512; // this is for all connections. maybe make this configurable
public const int MaxPendingPacketCount = 16; // this is per connection. each is around 1400 bytes (MTU)
public const int MaxBufferedPackets = 512;
Queue<ChannelPacket> m_PendingPackets;
static List<ChannelPacket> s_FreePackets;
static internal int pendingPacketCount; // this is across all connections. only used for profiler metrics.
// config
public float maxDelay = 0.01f;
// stats
float m_LastBufferedMessageCountTimer = Time.realtimeSinceStartup;
public int numMsgsOut { get; private set; }
public int numBufferedMsgsOut { get; private set; }
public int numBytesOut { get; private set; }
public int numMsgsIn { get; private set; }
public int numBytesIn { get; private set; }
public int numBufferedPerSecond { get; private set; }
public int lastBufferedPerSecond { get; private set; }
static NetworkWriter s_SendWriter = new NetworkWriter();
static NetworkWriter s_FragmentWriter = new NetworkWriter();
// We need to reserve some space for header information, this will be taken off the total channel buffer size
const int k_PacketHeaderReserveSize = 100;
public ChannelBuffer(NetworkConnection conn, int bufferSize, byte cid, bool isReliable, bool isSequenced)
{
m_Connection = conn;
m_MaxPacketSize = bufferSize - k_PacketHeaderReserveSize;
m_CurrentPacket = new ChannelPacket(m_MaxPacketSize, isReliable);
m_ChannelId = cid;
m_MaxPendingPacketCount = MaxPendingPacketCount;
m_IsReliable = isReliable;
m_AllowFragmentation = (isReliable && isSequenced);
if (isReliable)
{
m_PendingPackets = new Queue<ChannelPacket>();
if (s_FreePackets == null)
{
s_FreePackets = new List<ChannelPacket>();
}
}
}
// Track whether Dispose has been called.
bool m_Disposed;
public void Dispose()
{
Dispose(true);
// Take yourself off the Finalization queue
// to prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!m_Disposed)
{
if (disposing)
{
if (m_PendingPackets != null)
{
while (m_PendingPackets.Count > 0)
{
pendingPacketCount -= 1;
ChannelPacket packet = m_PendingPackets.Dequeue();
if (s_FreePackets.Count < k_MaxFreePacketCount)
{
s_FreePackets.Add(packet);
}
}
m_PendingPackets.Clear();
}
}
}
m_Disposed = true;
}
public bool SetOption(ChannelOption option, int value)
{
switch (option)
{
case ChannelOption.MaxPendingBuffers:
{
if (!m_IsReliable)
{
// not an error
//if (LogFilter.logError) { Debug.LogError("Cannot set MaxPendingBuffers on unreliable channel " + m_ChannelId); }
return false;
}
if (value < 0 || value >= MaxBufferedPackets)
{
if (LogFilter.logError) { Debug.LogError("Invalid MaxPendingBuffers for channel " + m_ChannelId + ". Must be greater than zero and less than " + k_MaxFreePacketCount); }
return false;
}
m_MaxPendingPacketCount = value;
return true;
}
case ChannelOption.AllowFragmentation:
{
m_AllowFragmentation = (value != 0);
return true;
}
case ChannelOption.MaxPacketSize:
{
if (!m_CurrentPacket.IsEmpty() || m_PendingPackets.Count > 0)
{
if (LogFilter.logError) { Debug.LogError("Cannot set MaxPacketSize after sending data."); }
return false;
}
if (value <= 0)
{
if (LogFilter.logError) { Debug.LogError("Cannot set MaxPacketSize less than one."); }
return false;
}
if (value > m_MaxPacketSize)
{
if (LogFilter.logError) { Debug.LogError("Cannot set MaxPacketSize to greater than the existing maximum (" + m_MaxPacketSize + ")."); }
return false;
}
// rebuild the packet with the new size. the packets doesn't store a size variable, just has the size of the internal buffer
m_CurrentPacket = new ChannelPacket(value, m_IsReliable);
m_MaxPacketSize = value;
return true;
}
}
return false;
}
public void CheckInternalBuffer()
{
if (Time.realtimeSinceStartup - m_LastFlushTime > maxDelay && !m_CurrentPacket.IsEmpty())
{
SendInternalBuffer();
m_LastFlushTime = Time.realtimeSinceStartup;
}
if (Time.realtimeSinceStartup - m_LastBufferedMessageCountTimer > 1.0f)
{
lastBufferedPerSecond = numBufferedPerSecond;
numBufferedPerSecond = 0;
m_LastBufferedMessageCountTimer = Time.realtimeSinceStartup;
}
}
public bool SendWriter(NetworkWriter writer)
{
return SendBytes(writer.AsArraySegment().Array, writer.AsArraySegment().Count);
}
public bool Send(short msgType, MessageBase msg)
{
// build the stream
s_SendWriter.StartMessage(msgType);
msg.Serialize(s_SendWriter);
s_SendWriter.FinishMessage();
numMsgsOut += 1;
return SendWriter(s_SendWriter);
}
internal NetBuffer fragmentBuffer = new NetBuffer();
bool readingFragment = false;
internal bool HandleFragment(NetworkReader reader)
{
int state = reader.ReadByte();
if (state == 0)
{
if (readingFragment == false)
{
fragmentBuffer.SeekZero();
readingFragment = true;
}
byte[] data = reader.ReadBytesAndSize();
fragmentBuffer.WriteBytes(data, (ushort)data.Length);
return false;
}
else
{
readingFragment = false;
return true;
}
}
internal bool SendFragmentBytes(byte[] bytes, int bytesToSend)
{
const int fragmentHeaderSize = 32;
int pos = 0;
while (bytesToSend > 0)
{
int diff = Math.Min(bytesToSend, m_MaxPacketSize - fragmentHeaderSize);
byte[] buffer = new byte[diff];
Array.Copy(bytes, pos, buffer, 0, diff);
s_FragmentWriter.StartMessage(MsgType.Fragment);
s_FragmentWriter.Write((byte)0);
s_FragmentWriter.WriteBytesFull(buffer);
s_FragmentWriter.FinishMessage();
SendWriter(s_FragmentWriter);
pos += diff;
bytesToSend -= diff;
}
// send finish
s_FragmentWriter.StartMessage(MsgType.Fragment);
s_FragmentWriter.Write((byte)1);
s_FragmentWriter.FinishMessage();
SendWriter(s_FragmentWriter);
return true;
}
internal bool SendBytes(byte[] bytes, int bytesToSend)
{
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.HLAPIMsg, "msg", 1);
#endif
if (bytesToSend >= UInt16.MaxValue)
{
if (LogFilter.logError) { Debug.LogError("ChannelBuffer:SendBytes cannot send packet larger than " + UInt16.MaxValue + " bytes"); }
return false;
}
if (bytesToSend <= 0)
{
// zero length packets getting into the packet queues are bad.
if (LogFilter.logError) { Debug.LogError("ChannelBuffer:SendBytes cannot send zero bytes"); }
return false;
}
if (bytesToSend > m_MaxPacketSize)
{
if (m_AllowFragmentation)
{
return SendFragmentBytes(bytes, bytesToSend);
}
else
{
// cannot do HLAPI fragmentation on this channel
if (LogFilter.logError) { Debug.LogError("Failed to send big message of " + bytesToSend + " bytes. The maximum is " + m_MaxPacketSize + " bytes on channel:" + m_ChannelId); }
return false;
}
}
if (!m_CurrentPacket.HasSpace(bytesToSend))
{
if (m_IsReliable)
{
if (m_PendingPackets.Count == 0)
{
// nothing in the pending queue yet, just flush and write
if (!m_CurrentPacket.SendToTransport(m_Connection, m_ChannelId))
{
QueuePacket();
}
m_CurrentPacket.Write(bytes, bytesToSend);
return true;
}
if (m_PendingPackets.Count >= m_MaxPendingPacketCount)
{
if (!m_IsBroken)
{
// only log this once, or it will spam the log constantly
if (LogFilter.logError) { Debug.LogError("ChannelBuffer buffer limit of " + m_PendingPackets.Count + " packets reached."); }
}
m_IsBroken = true;
return false;
}
// calling SendToTransport here would write out-of-order data to the stream. just queue
QueuePacket();
m_CurrentPacket.Write(bytes, bytesToSend);
return true;
}
if (!m_CurrentPacket.SendToTransport(m_Connection, m_ChannelId))
{
if (LogFilter.logError) { Debug.Log("ChannelBuffer SendBytes no space on unreliable channel " + m_ChannelId); }
return false;
}
m_CurrentPacket.Write(bytes, bytesToSend);
return true;
}
m_CurrentPacket.Write(bytes, bytesToSend);
if (maxDelay == 0.0f)
{
return SendInternalBuffer();
}
return true;
}
void QueuePacket()
{
pendingPacketCount += 1;
m_PendingPackets.Enqueue(m_CurrentPacket);
m_CurrentPacket = AllocPacket();
}
ChannelPacket AllocPacket()
{
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.SetStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.HLAPIPending, "msg", pendingPacketCount);
#endif
if (s_FreePackets.Count == 0)
{
return new ChannelPacket(m_MaxPacketSize, m_IsReliable);
}
var packet = s_FreePackets[s_FreePackets.Count - 1];
s_FreePackets.RemoveAt(s_FreePackets.Count - 1);
packet.Reset();
return packet;
}
static void FreePacket(ChannelPacket packet)
{
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.SetStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.HLAPIPending, "msg", pendingPacketCount);
#endif
if (s_FreePackets.Count >= k_MaxFreePacketCount)
{
// just discard this packet, already tracking too many free packets
return;
}
s_FreePackets.Add(packet);
}
public bool SendInternalBuffer()
{
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.LLAPIMsg, "msg", 1);
#endif
if (m_IsReliable && m_PendingPackets.Count > 0)
{
// send until transport can take no more
while (m_PendingPackets.Count > 0)
{
var packet = m_PendingPackets.Dequeue();
if (!packet.SendToTransport(m_Connection, m_ChannelId))
{
m_PendingPackets.Enqueue(packet);
break;
}
pendingPacketCount -= 1;
FreePacket(packet);
if (m_IsBroken && m_PendingPackets.Count < (m_MaxPendingPacketCount / 2))
{
if (LogFilter.logWarn) { Debug.LogWarning("ChannelBuffer recovered from overflow but data was lost."); }
m_IsBroken = false;
}
}
return true;
}
return m_CurrentPacket.SendToTransport(m_Connection, m_ChannelId);
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,81 @@
#if ENABLE_UNET
using System;
namespace UnityEngine.Networking
{
// This is used by the ChannelBuffer when buffering traffic.
// Unreliable channels have a single ChannelPacket, Reliable channels have single "current" packet and a list of buffered ChannelPackets
struct ChannelPacket
{
public ChannelPacket(int packetSize, bool isReliable)
{
m_Position = 0;
m_Buffer = new byte[packetSize];
m_IsReliable = isReliable;
}
public void Reset()
{
m_Position = 0;
}
public bool IsEmpty()
{
return m_Position == 0;
}
public void Write(byte[] bytes, int numBytes)
{
Array.Copy(bytes, 0, m_Buffer, m_Position, numBytes);
m_Position += numBytes;
}
public bool HasSpace(int numBytes)
{
return m_Position + numBytes <= m_Buffer.Length;
}
public bool SendToTransport(NetworkConnection conn, int channelId)
{
byte error;
bool result = true;
if (!conn.TransportSend(m_Buffer, (ushort)m_Position, channelId, out error))
{
if (m_IsReliable && error == (int)NetworkError.NoResources)
{
// handled below
}
else
{
if (LogFilter.logError) { Debug.LogError("Failed to send internal buffer channel:" + channelId + " bytesToSend:" + m_Position); }
result = false;
}
}
if (error != 0)
{
if (m_IsReliable && error == (int)NetworkError.NoResources)
{
// this packet will be buffered by the containing ChannelBuffer, so this is not an error
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.HLAPIResend, "msg", 1);
#endif
return false;
}
if (LogFilter.logError) { Debug.LogError("Send Error: " + (NetworkError)error + " channel:" + channelId + " bytesToSend:" + m_Position); }
result = false;
}
m_Position = 0;
return result;
}
int m_Position;
byte[] m_Buffer;
bool m_IsReliable;
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,871 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
using UnityEngine.Networking.NetworkSystem;
namespace UnityEngine.Networking
{
public class ClientScene
{
static List<PlayerController> s_LocalPlayers = new List<PlayerController>();
static NetworkConnection s_ReadyConnection;
static Dictionary<NetworkSceneId, NetworkIdentity> s_SpawnableObjects;
static bool s_IsReady;
static bool s_IsSpawnFinished;
static NetworkScene s_NetworkScene = new NetworkScene();
// static message objects to avoid runtime-allocations
static ObjectSpawnSceneMessage s_ObjectSpawnSceneMessage = new ObjectSpawnSceneMessage();
static ObjectSpawnFinishedMessage s_ObjectSpawnFinishedMessage = new ObjectSpawnFinishedMessage();
static ObjectDestroyMessage s_ObjectDestroyMessage = new ObjectDestroyMessage();
static ObjectSpawnMessage s_ObjectSpawnMessage = new ObjectSpawnMessage();
static OwnerMessage s_OwnerMessage = new OwnerMessage();
static ClientAuthorityMessage s_ClientAuthorityMessage = new ClientAuthorityMessage();
#if ENABLE_UNET_HOST_MIGRATION
public const int ReconnectIdInvalid = -1;
public const int ReconnectIdHost = 0;
static int s_ReconnectId = ReconnectIdInvalid;
static PeerInfoMessage[] s_Peers;
static bool hasMigrationPending() { return s_ReconnectId != ReconnectIdInvalid; }
static public void SetReconnectId(int newReconnectId, PeerInfoMessage[] peers)
{
s_ReconnectId = newReconnectId;
s_Peers = peers;
if (LogFilter.logDebug) { Debug.Log("ClientScene::SetReconnectId: " + newReconnectId); }
}
#endif
static internal void SetNotReady()
{
s_IsReady = false;
}
struct PendingOwner
{
public NetworkInstanceId netId;
public short playerControllerId;
}
static List<PendingOwner> s_PendingOwnerIds = new List<PendingOwner>();
public static List<PlayerController> localPlayers { get { return s_LocalPlayers; } }
public static bool ready { get { return s_IsReady; } }
public static NetworkConnection readyConnection { get { return s_ReadyConnection; }}
#if ENABLE_UNET_HOST_MIGRATION
public static int reconnectId { get { return s_ReconnectId; }}
#endif
//NOTE: spawn handlers, prefabs and local objects now live in NetworkScene
public static Dictionary<NetworkInstanceId, NetworkIdentity> objects { get { return s_NetworkScene.localObjects; } }
public static Dictionary<NetworkHash128, GameObject> prefabs { get { return NetworkScene.guidToPrefab; } }
public static Dictionary<NetworkSceneId, NetworkIdentity> spawnableObjects { get { return s_SpawnableObjects; } }
internal static void Shutdown()
{
s_NetworkScene.Shutdown();
s_LocalPlayers = new List<PlayerController>();
s_PendingOwnerIds = new List<PendingOwner>();
s_SpawnableObjects = null;
s_ReadyConnection = null;
s_IsReady = false;
s_IsSpawnFinished = false;
#if ENABLE_UNET_HOST_MIGRATION
s_ReconnectId = ReconnectIdInvalid;
#endif
NetworkTransport.Shutdown();
NetworkTransport.Init();
}
internal static bool GetPlayerController(short playerControllerId, out PlayerController player)
{
player = null;
if (playerControllerId >= localPlayers.Count)
{
if (LogFilter.logWarn) { Debug.Log("ClientScene::GetPlayer: no local player found for: " + playerControllerId); }
return false;
}
if (localPlayers[playerControllerId] == null)
{
if (LogFilter.logWarn) { Debug.LogWarning("ClientScene::GetPlayer: local player is null for: " + playerControllerId); }
return false;
}
player = localPlayers[playerControllerId];
return player.gameObject != null;
}
// this is called from message handler for Owner message
internal static void InternalAddPlayer(NetworkIdentity view, short playerControllerId)
{
if (LogFilter.logDebug) { Debug.LogWarning("ClientScene::InternalAddPlayer: playerControllerId : " + playerControllerId); }
if (playerControllerId >= s_LocalPlayers.Count)
{
if (LogFilter.logWarn) { Debug.LogWarning("ClientScene::InternalAddPlayer: playerControllerId higher than expected: " + playerControllerId); }
while (playerControllerId >= s_LocalPlayers.Count)
{
s_LocalPlayers.Add(new PlayerController());
}
}
// NOTE: It can be "normal" when changing scenes for the player to be destroyed and recreated.
// But, the player structures are not cleaned up, we'll just replace the old player
var newPlayer = new PlayerController {gameObject = view.gameObject, playerControllerId = playerControllerId, unetView = view};
s_LocalPlayers[playerControllerId] = newPlayer;
s_ReadyConnection.SetPlayerController(newPlayer);
}
// use this if already ready
public static bool AddPlayer(short playerControllerId)
{
return AddPlayer(null, playerControllerId);
}
// use this to implicitly become ready
public static bool AddPlayer(NetworkConnection readyConn, short playerControllerId)
{
return AddPlayer(readyConn, playerControllerId, null);
}
// use this to implicitly become ready
public static bool AddPlayer(NetworkConnection readyConn, short playerControllerId, MessageBase extraMessage)
{
if (playerControllerId < 0)
{
if (LogFilter.logError) { Debug.LogError("ClientScene::AddPlayer: playerControllerId of " + playerControllerId + " is negative"); }
return false;
}
if (playerControllerId > PlayerController.MaxPlayersPerClient)
{
if (LogFilter.logError) { Debug.LogError("ClientScene::AddPlayer: playerControllerId of " + playerControllerId + " is too high, max is " + PlayerController.MaxPlayersPerClient); }
return false;
}
if (playerControllerId > PlayerController.MaxPlayersPerClient / 2)
{
if (LogFilter.logWarn) { Debug.LogWarning("ClientScene::AddPlayer: playerControllerId of " + playerControllerId + " is unusually high"); }
}
// fill out local players array
while (playerControllerId >= s_LocalPlayers.Count)
{
s_LocalPlayers.Add(new PlayerController());
}
// ensure valid ready connection
if (readyConn == null)
{
if (!s_IsReady)
{
if (LogFilter.logError) { Debug.LogError("Must call AddPlayer() with a connection the first time to become ready."); }
return false;
}
}
else
{
s_IsReady = true;
s_ReadyConnection = readyConn;
}
PlayerController existingPlayerController;
if (s_ReadyConnection.GetPlayerController(playerControllerId, out existingPlayerController))
{
if (existingPlayerController.IsValid && existingPlayerController.gameObject != null)
{
if (LogFilter.logError) { Debug.LogError("ClientScene::AddPlayer: playerControllerId of " + playerControllerId + " already in use."); }
return false;
}
}
if (LogFilter.logDebug) { Debug.Log("ClientScene::AddPlayer() for ID " + playerControllerId + " called with connection [" + s_ReadyConnection + "]"); }
#if ENABLE_UNET_HOST_MIGRATION
if (!hasMigrationPending())
{
#endif
var msg = new AddPlayerMessage();
msg.playerControllerId = playerControllerId;
if (extraMessage != null)
{
var writer = new NetworkWriter();
extraMessage.Serialize(writer);
msg.msgData = writer.ToArray();
msg.msgSize = writer.Position;
}
s_ReadyConnection.Send(MsgType.AddPlayer, msg);
#if ENABLE_UNET_HOST_MIGRATION
}
else
{
return SendReconnectMessage(extraMessage);
}
#endif
return true;
}
#if ENABLE_UNET_HOST_MIGRATION
public static bool SendReconnectMessage(MessageBase extraMessage)
{
if (!hasMigrationPending())
return false;
if (LogFilter.logDebug) { Debug.Log("ClientScene::AddPlayer reconnect " + s_ReconnectId); }
if (s_Peers == null)
{
SetReconnectId(ReconnectIdInvalid, null);
if (LogFilter.logError)
{
Debug.LogError("ClientScene::AddPlayer: reconnecting, but no peers.");
}
return false;
}
// reconnect all the players
for (int i = 0; i < s_Peers.Length; i++)
{
var peer = s_Peers[i];
if (peer.playerIds == null)
{
// this could be empty if this peer had no players
continue;
}
if (peer.connectionId == s_ReconnectId)
{
for (int pid = 0; pid < peer.playerIds.Length; pid++)
{
var msg = new ReconnectMessage();
msg.oldConnectionId = s_ReconnectId;
msg.netId = peer.playerIds[pid].netId;
msg.playerControllerId = peer.playerIds[pid].playerControllerId;
if (extraMessage != null)
{
var writer = new NetworkWriter();
extraMessage.Serialize(writer);
msg.msgData = writer.ToArray();
msg.msgSize = writer.Position;
}
s_ReadyConnection.Send(MsgType.ReconnectPlayer, msg);
}
}
}
// this should only be done once.
SetReconnectId(ReconnectIdInvalid, null);
return true;
}
#endif
public static bool RemovePlayer(short playerControllerId)
{
if (LogFilter.logDebug) { Debug.Log("ClientScene::RemovePlayer() for ID " + playerControllerId + " called with connection [" + s_ReadyConnection + "]"); }
PlayerController playerController;
if (s_ReadyConnection.GetPlayerController(playerControllerId, out playerController))
{
var msg = new RemovePlayerMessage();
msg.playerControllerId = playerControllerId;
s_ReadyConnection.Send(MsgType.RemovePlayer, msg);
s_ReadyConnection.RemovePlayerController(playerControllerId);
s_LocalPlayers[playerControllerId] = new PlayerController();
Object.Destroy(playerController.gameObject);
return true;
}
if (LogFilter.logError) { Debug.LogError("Failed to find player ID " + playerControllerId); }
return false;
}
public static bool Ready(NetworkConnection conn)
{
if (s_IsReady)
{
if (LogFilter.logError) { Debug.LogError("A connection has already been set as ready. There can only be one."); }
return false;
}
if (LogFilter.logDebug) { Debug.Log("ClientScene::Ready() called with connection [" + conn + "]"); }
if (conn != null)
{
var msg = new ReadyMessage();
conn.Send(MsgType.Ready, msg);
s_IsReady = true;
s_ReadyConnection = conn;
s_ReadyConnection.isReady = true;
return true;
}
if (LogFilter.logError) { Debug.LogError("Ready() called with invalid connection object: conn=null"); }
return false;
}
static public NetworkClient ConnectLocalServer()
{
var newClient = new LocalClient();
NetworkServer.instance.ActivateLocalClientScene();
newClient.InternalConnectLocalServer(true);
return newClient;
}
#if ENABLE_UNET_HOST_MIGRATION
static internal NetworkClient ReconnectLocalServer()
{
LocalClient newClient = new LocalClient();
NetworkServer.instance.ActivateLocalClientScene();
newClient.InternalConnectLocalServer(false);
return newClient;
}
static internal void ClearLocalPlayers()
{
s_LocalPlayers.Clear();
}
#endif
static internal void HandleClientDisconnect(NetworkConnection conn)
{
if (s_ReadyConnection == conn && s_IsReady)
{
s_IsReady = false;
s_ReadyConnection = null;
}
}
internal static void PrepareToSpawnSceneObjects()
{
//NOTE: what is there are already objects in this dict?! should we merge with them?
s_SpawnableObjects = new Dictionary<NetworkSceneId, NetworkIdentity>();
var uvs = Resources.FindObjectsOfTypeAll<NetworkIdentity>();
for (int i = 0; i < uvs.Length; i++)
{
var uv = uvs[i];
if (uv.gameObject.activeSelf)
{
// already active, cannot spawn it
continue;
}
if (uv.gameObject.hideFlags == HideFlags.NotEditable || uv.gameObject.hideFlags == HideFlags.HideAndDontSave)
continue;
if (uv.sceneId.IsEmpty())
continue;
s_SpawnableObjects[uv.sceneId] = uv;
if (LogFilter.logDebug) { Debug.Log("ClientScene::PrepareSpawnObjects sceneId:" + uv.sceneId); }
}
}
internal static NetworkIdentity SpawnSceneObject(NetworkSceneId sceneId)
{
if (s_SpawnableObjects.ContainsKey(sceneId))
{
NetworkIdentity foundId = s_SpawnableObjects[sceneId];
s_SpawnableObjects.Remove(sceneId);
return foundId;
}
return null;
}
static internal void RegisterSystemHandlers(NetworkClient client, bool localClient)
{
if (localClient)
{
client.RegisterHandlerSafe(MsgType.ObjectDestroy, OnLocalClientObjectDestroy);
client.RegisterHandlerSafe(MsgType.ObjectHide, OnLocalClientObjectHide);
client.RegisterHandlerSafe(MsgType.ObjectSpawn, OnLocalClientObjectSpawn);
client.RegisterHandlerSafe(MsgType.ObjectSpawnScene, OnLocalClientObjectSpawnScene);
client.RegisterHandlerSafe(MsgType.LocalClientAuthority, OnClientAuthority);
}
else
{
// LocalClient shares the sim/scene with the server, no need for these events
client.RegisterHandlerSafe(MsgType.ObjectSpawn, OnObjectSpawn);
client.RegisterHandlerSafe(MsgType.ObjectSpawnScene, OnObjectSpawnScene);
client.RegisterHandlerSafe(MsgType.SpawnFinished, OnObjectSpawnFinished);
client.RegisterHandlerSafe(MsgType.ObjectDestroy, OnObjectDestroy);
client.RegisterHandlerSafe(MsgType.ObjectHide, OnObjectDestroy);
client.RegisterHandlerSafe(MsgType.UpdateVars, OnUpdateVarsMessage);
client.RegisterHandlerSafe(MsgType.Owner, OnOwnerMessage);
client.RegisterHandlerSafe(MsgType.SyncList, OnSyncListMessage);
client.RegisterHandlerSafe(MsgType.Animation, NetworkAnimator.OnAnimationClientMessage);
client.RegisterHandlerSafe(MsgType.AnimationParameters, NetworkAnimator.OnAnimationParametersClientMessage);
client.RegisterHandlerSafe(MsgType.LocalClientAuthority, OnClientAuthority);
}
client.RegisterHandlerSafe(MsgType.Rpc, OnRPCMessage);
client.RegisterHandlerSafe(MsgType.SyncEvent, OnSyncEventMessage);
client.RegisterHandlerSafe(MsgType.AnimationTrigger, NetworkAnimator.OnAnimationTriggerClientMessage);
}
// ------------------------ NetworkScene pass-throughs ---------------------
static internal string GetStringForAssetId(NetworkHash128 assetId)
{
GameObject prefab;
if (NetworkScene.GetPrefab(assetId, out prefab))
{
return prefab.name;
}
SpawnDelegate handler;
if (NetworkScene.GetSpawnHandler(assetId, out handler))
{
return handler.GetMethodName();
}
return "unknown";
}
// this assigns the newAssetId to the prefab. This is for registering dynamically created game objects for already know assetIds.
static public void RegisterPrefab(GameObject prefab, NetworkHash128 newAssetId)
{
NetworkScene.RegisterPrefab(prefab, newAssetId);
}
static public void RegisterPrefab(GameObject prefab)
{
NetworkScene.RegisterPrefab(prefab);
}
static public void RegisterPrefab(GameObject prefab, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
NetworkScene.RegisterPrefab(prefab, spawnHandler, unspawnHandler);
}
static public void UnregisterPrefab(GameObject prefab)
{
NetworkScene.UnregisterPrefab(prefab);
}
static public void RegisterSpawnHandler(NetworkHash128 assetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
NetworkScene.RegisterSpawnHandler(assetId, spawnHandler, unspawnHandler);
}
static public void UnregisterSpawnHandler(NetworkHash128 assetId)
{
NetworkScene.UnregisterSpawnHandler(assetId);
}
static public void ClearSpawners()
{
NetworkScene.ClearSpawners();
}
static public void DestroyAllClientObjects()
{
s_NetworkScene.DestroyAllClientObjects();
}
static public void SetLocalObject(NetworkInstanceId netId, GameObject obj)
{
// if still receiving initial state, dont set isClient
s_NetworkScene.SetLocalObject(netId, obj, s_IsSpawnFinished, false);
}
static public GameObject FindLocalObject(NetworkInstanceId netId)
{
return s_NetworkScene.FindLocalObject(netId);
}
static void ApplySpawnPayload(NetworkIdentity uv, Vector3 position, byte[] payload, NetworkInstanceId netId, GameObject newGameObject)
{
if (!uv.gameObject.activeSelf)
{
uv.gameObject.SetActive(true);
}
uv.transform.position = position;
if (payload != null && payload.Length > 0)
{
var payloadReader = new NetworkReader(payload);
uv.OnUpdateVars(payloadReader, true);
}
if (newGameObject == null)
{
return;
}
newGameObject.SetActive(true);
uv.SetNetworkInstanceId(netId);
SetLocalObject(netId, newGameObject);
// objects spawned as part of initial state are started on a second pass
if (s_IsSpawnFinished)
{
uv.OnStartClient();
CheckForOwner(uv);
}
}
static void OnObjectSpawn(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_ObjectSpawnMessage);
if (!s_ObjectSpawnMessage.assetId.IsValid())
{
if (LogFilter.logError) { Debug.LogError("OnObjSpawn netId: " + s_ObjectSpawnMessage.netId + " has invalid asset Id"); }
return;
}
if (LogFilter.logDebug) { Debug.Log("Client spawn handler instantiating [netId:" + s_ObjectSpawnMessage.netId + " asset ID:" + s_ObjectSpawnMessage.assetId + " pos:" + s_ObjectSpawnMessage.position + "]"); }
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Incoming,
MsgType.ObjectSpawn, GetStringForAssetId(s_ObjectSpawnMessage.assetId), 1);
#endif
NetworkIdentity localNetworkIdentity;
if (s_NetworkScene.GetNetworkIdentity(s_ObjectSpawnMessage.netId, out localNetworkIdentity))
{
// this object already exists (was in the scene), just apply the update to existing object
ApplySpawnPayload(localNetworkIdentity, s_ObjectSpawnMessage.position, s_ObjectSpawnMessage.payload, s_ObjectSpawnMessage.netId, null);
return;
}
GameObject prefab;
SpawnDelegate handler;
if (NetworkScene.GetPrefab(s_ObjectSpawnMessage.assetId, out prefab))
{
var obj = (GameObject)Object.Instantiate(prefab, s_ObjectSpawnMessage.position, s_ObjectSpawnMessage.rotation);
if (LogFilter.logDebug)
{
Debug.Log("Client spawn handler instantiating [netId:" + s_ObjectSpawnMessage.netId + " asset ID:" + s_ObjectSpawnMessage.assetId + " pos:" + s_ObjectSpawnMessage.position + " rotation: " + s_ObjectSpawnMessage.rotation + "]");
}
localNetworkIdentity = obj.GetComponent<NetworkIdentity>();
if (localNetworkIdentity == null)
{
if (LogFilter.logError) { Debug.LogError("Client object spawned for " + s_ObjectSpawnMessage.assetId + " does not have a NetworkIdentity"); }
return;
}
localNetworkIdentity.Reset();
ApplySpawnPayload(localNetworkIdentity, s_ObjectSpawnMessage.position, s_ObjectSpawnMessage.payload, s_ObjectSpawnMessage.netId, obj);
}
// lookup registered factory for type:
else if (NetworkScene.GetSpawnHandler(s_ObjectSpawnMessage.assetId, out handler))
{
GameObject obj = handler(s_ObjectSpawnMessage.position, s_ObjectSpawnMessage.assetId);
if (obj == null)
{
if (LogFilter.logWarn) { Debug.LogWarning("Client spawn handler for " + s_ObjectSpawnMessage.assetId + " returned null"); }
return;
}
localNetworkIdentity = obj.GetComponent<NetworkIdentity>();
if (localNetworkIdentity == null)
{
if (LogFilter.logError) { Debug.LogError("Client object spawned for " + s_ObjectSpawnMessage.assetId + " does not have a network identity"); }
return;
}
localNetworkIdentity.Reset();
localNetworkIdentity.SetDynamicAssetId(s_ObjectSpawnMessage.assetId);
ApplySpawnPayload(localNetworkIdentity, s_ObjectSpawnMessage.position, s_ObjectSpawnMessage.payload, s_ObjectSpawnMessage.netId, obj);
}
else
{
if (LogFilter.logError) { Debug.LogError("Failed to spawn server object, did you forget to add it to the NetworkManager? assetId=" + s_ObjectSpawnMessage.assetId + " netId=" + s_ObjectSpawnMessage.netId); }
}
}
static void OnObjectSpawnScene(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_ObjectSpawnSceneMessage);
if (LogFilter.logDebug) { Debug.Log("Client spawn scene handler instantiating [netId:" + s_ObjectSpawnSceneMessage.netId + " sceneId:" + s_ObjectSpawnSceneMessage.sceneId + " pos:" + s_ObjectSpawnSceneMessage.position); }
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Incoming,
MsgType.ObjectSpawnScene, "sceneId", 1);
#endif
NetworkIdentity localNetworkIdentity;
if (s_NetworkScene.GetNetworkIdentity(s_ObjectSpawnSceneMessage.netId, out localNetworkIdentity))
{
// this object already exists (was in the scene)
ApplySpawnPayload(localNetworkIdentity, s_ObjectSpawnSceneMessage.position, s_ObjectSpawnSceneMessage.payload, s_ObjectSpawnSceneMessage.netId, localNetworkIdentity.gameObject);
return;
}
NetworkIdentity spawnedId = SpawnSceneObject(s_ObjectSpawnSceneMessage.sceneId);
if (spawnedId == null)
{
if (LogFilter.logError) { Debug.LogError("Spawn scene object not found for " + s_ObjectSpawnSceneMessage.sceneId); }
return;
}
if (LogFilter.logDebug) { Debug.Log("Client spawn for [netId:" + s_ObjectSpawnSceneMessage.netId + "] [sceneId:" + s_ObjectSpawnSceneMessage.sceneId + "] obj:" + spawnedId.gameObject.name); }
ApplySpawnPayload(spawnedId, s_ObjectSpawnSceneMessage.position, s_ObjectSpawnSceneMessage.payload, s_ObjectSpawnSceneMessage.netId, spawnedId.gameObject);
}
static void OnObjectSpawnFinished(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_ObjectSpawnFinishedMessage);
if (LogFilter.logDebug) { Debug.Log("SpawnFinished:" + s_ObjectSpawnFinishedMessage.state); }
if (s_ObjectSpawnFinishedMessage.state == 0)
{
PrepareToSpawnSceneObjects();
s_IsSpawnFinished = false;
return;
}
foreach (var uv in objects.Values)
{
if (!uv.isClient)
{
uv.OnStartClient();
CheckForOwner(uv);
}
}
s_IsSpawnFinished = true;
}
static void OnObjectDestroy(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_ObjectDestroyMessage);
if (LogFilter.logDebug) { Debug.Log("ClientScene::OnObjDestroy netId:" + s_ObjectDestroyMessage.netId); }
NetworkIdentity localObject;
if (s_NetworkScene.GetNetworkIdentity(s_ObjectDestroyMessage.netId, out localObject))
{
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Incoming,
MsgType.ObjectDestroy, GetStringForAssetId(localObject.assetId), 1);
#endif
localObject.OnNetworkDestroy();
if (!NetworkScene.InvokeUnSpawnHandler(localObject.assetId, localObject.gameObject))
{
// default handling
if (localObject.sceneId.IsEmpty())
{
Object.Destroy(localObject.gameObject);
}
else
{
// scene object.. disable it in scene instead of destroying
localObject.gameObject.SetActive(false);
s_SpawnableObjects[localObject.sceneId] = localObject;
}
}
s_NetworkScene.RemoveLocalObject(s_ObjectDestroyMessage.netId);
localObject.MarkForReset();
}
else
{
if (LogFilter.logDebug) { Debug.LogWarning("Did not find target for destroy message for " + s_ObjectDestroyMessage.netId); }
}
}
static void OnLocalClientObjectDestroy(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_ObjectDestroyMessage);
if (LogFilter.logDebug) { Debug.Log("ClientScene::OnLocalObjectObjDestroy netId:" + s_ObjectDestroyMessage.netId); }
s_NetworkScene.RemoveLocalObject(s_ObjectDestroyMessage.netId);
}
static void OnLocalClientObjectHide(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_ObjectDestroyMessage);
if (LogFilter.logDebug) { Debug.Log("ClientScene::OnLocalObjectObjHide netId:" + s_ObjectDestroyMessage.netId); }
NetworkIdentity localObject;
if (s_NetworkScene.GetNetworkIdentity(s_ObjectDestroyMessage.netId, out localObject))
{
localObject.OnSetLocalVisibility(false);
}
}
static void OnLocalClientObjectSpawn(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_ObjectSpawnMessage);
NetworkIdentity localObject;
if (s_NetworkScene.GetNetworkIdentity(s_ObjectSpawnMessage.netId, out localObject))
{
localObject.OnSetLocalVisibility(true);
}
}
static void OnLocalClientObjectSpawnScene(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_ObjectSpawnSceneMessage);
NetworkIdentity localObject;
if (s_NetworkScene.GetNetworkIdentity(s_ObjectSpawnSceneMessage.netId, out localObject))
{
localObject.OnSetLocalVisibility(true);
}
}
static void OnUpdateVarsMessage(NetworkMessage netMsg)
{
NetworkInstanceId netId = netMsg.reader.ReadNetworkId();
if (LogFilter.logDev) { Debug.Log("ClientScene::OnUpdateVarsMessage " + netId + " channel:" + netMsg.channelId); }
NetworkIdentity localObject;
if (s_NetworkScene.GetNetworkIdentity(netId, out localObject))
{
localObject.OnUpdateVars(netMsg.reader, false);
}
else
{
if (LogFilter.logWarn) { Debug.LogWarning("Did not find target for sync message for " + netId); }
}
}
static void OnRPCMessage(NetworkMessage netMsg)
{
var cmdHash = (int)netMsg.reader.ReadPackedUInt32();
var netId = netMsg.reader.ReadNetworkId();
if (LogFilter.logDebug) { Debug.Log("ClientScene::OnRPCMessage hash:" + cmdHash + " netId:" + netId); }
NetworkIdentity uv;
if (s_NetworkScene.GetNetworkIdentity(netId, out uv))
{
uv.HandleRPC(cmdHash, netMsg.reader);
}
else
{
if (LogFilter.logWarn)
{
string errorCmdName = NetworkBehaviour.GetCmdHashHandlerName(cmdHash);
Debug.LogWarningFormat("Could not find target object with netId:{0} for RPC call {1}", netId, errorCmdName);
}
}
}
static void OnSyncEventMessage(NetworkMessage netMsg)
{
var cmdHash = (int)netMsg.reader.ReadPackedUInt32();
var netId = netMsg.reader.ReadNetworkId();
if (LogFilter.logDebug) { Debug.Log("ClientScene::OnSyncEventMessage " + netId); }
NetworkIdentity uv;
if (s_NetworkScene.GetNetworkIdentity(netId, out uv))
{
uv.HandleSyncEvent(cmdHash, netMsg.reader);
}
else
{
if (LogFilter.logWarn) { Debug.LogWarning("Did not find target for SyncEvent message for " + netId); }
}
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.SyncEvent, NetworkBehaviour.GetCmdHashHandlerName(cmdHash), 1);
#endif
}
static void OnSyncListMessage(NetworkMessage netMsg)
{
var netId = netMsg.reader.ReadNetworkId();
var cmdHash = (int)netMsg.reader.ReadPackedUInt32();
if (LogFilter.logDebug) { Debug.Log("ClientScene::OnSyncListMessage " + netId); }
NetworkIdentity uv;
if (s_NetworkScene.GetNetworkIdentity(netId, out uv))
{
uv.HandleSyncList(cmdHash, netMsg.reader);
}
else
{
if (LogFilter.logWarn) { Debug.LogWarning("Did not find target for SyncList message for " + netId); }
}
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.SyncList, NetworkBehaviour.GetCmdHashHandlerName(cmdHash), 1);
#endif
}
static void OnClientAuthority(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_ClientAuthorityMessage);
if (LogFilter.logDebug) { Debug.Log("ClientScene::OnClientAuthority for connectionId=" + netMsg.conn.connectionId + " netId: " + s_ClientAuthorityMessage.netId); }
NetworkIdentity uv;
if (s_NetworkScene.GetNetworkIdentity(s_ClientAuthorityMessage.netId, out uv))
{
uv.HandleClientAuthority(s_ClientAuthorityMessage.authority);
}
}
// OnClientAddedPlayer?
static void OnOwnerMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_OwnerMessage);
if (LogFilter.logDebug) { Debug.Log("ClientScene::OnOwnerMessage - connectionId=" + netMsg.conn.connectionId + " netId: " + s_OwnerMessage.netId); }
// is there already an owner that is a different object??
PlayerController oldOwner;
if (netMsg.conn.GetPlayerController(s_OwnerMessage.playerControllerId, out oldOwner))
{
oldOwner.unetView.SetNotLocalPlayer();
}
NetworkIdentity localNetworkIdentity;
if (s_NetworkScene.GetNetworkIdentity(s_OwnerMessage.netId, out localNetworkIdentity))
{
// this object already exists
localNetworkIdentity.SetConnectionToServer(netMsg.conn);
localNetworkIdentity.SetLocalPlayer(s_OwnerMessage.playerControllerId);
InternalAddPlayer(localNetworkIdentity, s_OwnerMessage.playerControllerId);
}
else
{
var pendingOwner = new PendingOwner { netId = s_OwnerMessage.netId, playerControllerId = s_OwnerMessage.playerControllerId };
s_PendingOwnerIds.Add(pendingOwner);
}
}
static void CheckForOwner(NetworkIdentity uv)
{
for (int i = 0; i < s_PendingOwnerIds.Count; i++)
{
var pendingOwner = s_PendingOwnerIds[i];
if (pendingOwner.netId == uv.netId)
{
// found owner, turn into a local player
// Set isLocalPlayer to true on this NetworkIdentity and trigger OnStartLocalPlayer in all scripts on the same GO
uv.SetConnectionToServer(s_ReadyConnection);
uv.SetLocalPlayer(pendingOwner.playerControllerId);
if (LogFilter.logDev) { Debug.Log("ClientScene::OnOwnerMessage - player=" + uv.gameObject.name); }
if (s_ReadyConnection.connectionId < 0)
{
if (LogFilter.logError) { Debug.LogError("Owner message received on a local client."); }
return;
}
InternalAddPlayer(uv, pendingOwner.playerControllerId);
s_PendingOwnerIds.RemoveAt(i);
break;
}
}
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,126 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
namespace UnityEngine.Networking
{
// This has a list of real connections
// The local or "fake" connections are kept separate because sometimes you
// only want to iterate through those, and not all connections.
class ConnectionArray
{
List<NetworkConnection> m_LocalConnections;
List<NetworkConnection> m_Connections;
internal List<NetworkConnection> localConnections { get { return m_LocalConnections; }}
internal List<NetworkConnection> connections { get { return m_Connections; }}
public int Count { get { return m_Connections.Count; } }
public int LocalIndex { get { return -m_LocalConnections.Count; } }
public ConnectionArray()
{
m_Connections = new List<NetworkConnection>();
m_LocalConnections = new List<NetworkConnection>();
}
public int Add(int connId, NetworkConnection conn)
{
if (connId < 0)
{
if (LogFilter.logWarn) {Debug.LogWarning("ConnectionArray Add bad id " + connId); }
return -1;
}
if (connId < m_Connections.Count && m_Connections[connId] != null)
{
if (LogFilter.logWarn) { Debug.LogWarning("ConnectionArray Add dupe at " + connId); }
return -1;
}
while (connId > (m_Connections.Count - 1))
{
m_Connections.Add(null);
}
m_Connections[connId] = conn;
return connId;
}
// call this if you know the connnection exists
public NetworkConnection Get(int connId)
{
if (connId < 0)
{
return m_LocalConnections[Mathf.Abs(connId) - 1];
}
if (connId < 0 || connId > m_Connections.Count)
{
if (LogFilter.logWarn) { Debug.LogWarning("ConnectionArray Get invalid index " + connId); }
return null;
}
return m_Connections[connId];
}
// call this if the connection may not exist (in disconnect handler)
public NetworkConnection GetUnsafe(int connId)
{
if (connId < 0 || connId > m_Connections.Count)
{
return null;
}
return m_Connections[connId];
}
public void Remove(int connId)
{
if (connId < 0)
{
m_LocalConnections[Mathf.Abs(connId) - 1] = null;
return;
}
if (connId < 0 || connId > m_Connections.Count)
{
if (LogFilter.logWarn) { Debug.LogWarning("ConnectionArray Remove invalid index " + connId); }
return;
}
m_Connections[connId] = null;
}
public int AddLocal(NetworkConnection conn)
{
m_LocalConnections.Add(conn);
int index = -m_LocalConnections.Count;
conn.connectionId = index;
return index;
}
public bool ContainsPlayer(GameObject player, out NetworkConnection conn)
{
conn = null;
if (player == null)
return false;
for (int i = LocalIndex; i < m_Connections.Count; i++)
{
conn = Get(i);
if (conn != null)
{
for (int j = 0; j < conn.playerControllers.Count; j++)
{
if (conn.playerControllers[j].IsValid && conn.playerControllers[j].gameObject == player)
{
return true;
}
}
}
}
return false;
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,65 @@
using System;
#if ENABLE_UNET
namespace UnityEngine.Networking
{
[AttributeUsage(AttributeTargets.Class)]
public class NetworkSettingsAttribute : Attribute
{
public int channel = Channels.DefaultReliable;
public float sendInterval = 0.1f;
}
[AttributeUsage(AttributeTargets.Field)]
public class SyncVarAttribute : Attribute
{
public string hook;
}
[AttributeUsage(AttributeTargets.Method)]
public class CommandAttribute : Attribute
{
public int channel = Channels.DefaultReliable; // this is zero
}
[AttributeUsage(AttributeTargets.Method)]
public class ClientRpcAttribute : Attribute
{
public int channel = Channels.DefaultReliable; // this is zero
}
[AttributeUsage(AttributeTargets.Method)]
public class TargetRpcAttribute : Attribute
{
public int channel = Channels.DefaultReliable; // this is zero
}
[AttributeUsage(AttributeTargets.Event)]
public class SyncEventAttribute : Attribute
{
public int channel = Channels.DefaultReliable; // this is zero
}
[AttributeUsage(AttributeTargets.Method)]
public class ServerAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method)]
public class ServerCallbackAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method)]
public class ClientAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method)]
public class ClientCallbackAttribute : Attribute
{
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Net.Sockets;
namespace UnityEngine.Networking
{
internal static class DotNetCompatibility
{
internal static string GetMethodName(this Delegate func)
{
#if NETFX_CORE
return func.GetMethodInfo().Name;
#else
return func.Method.Name;
#endif
}
internal static Type GetBaseType(this Type type)
{
#if NETFX_CORE
return type.GetTypeInfo().BaseType;
#else
return type.BaseType;
#endif
}
internal static string GetErrorCode(this SocketException e)
{
#if NETFX_CORE
return e.SocketErrorCode.ToString();
#else
return e.ErrorCode.ToString();
#endif
}
#if NETFX_CORE
internal static bool IsSubclassOf(this Type type, Type baseType)
{
return WinRTLegacy.TypeExtensions.IsSubClassOf(type, baseType);
}
#endif
}
}

View File

@ -0,0 +1,175 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
namespace UnityEngine.Networking
{
sealed class LocalClient : NetworkClient
{
const int k_InitialFreeMessagePoolSize = 64;
struct InternalMsg
{
internal byte[] buffer;
internal int channelId;
}
List<InternalMsg> m_InternalMsgs = new List<InternalMsg>();
List<InternalMsg> m_InternalMsgs2 = new List<InternalMsg>();
Stack<InternalMsg> m_FreeMessages;
NetworkServer m_LocalServer;
bool m_Connected;
NetworkMessage s_InternalMessage = new NetworkMessage();
public override void Disconnect()
{
ClientScene.HandleClientDisconnect(m_Connection);
if (m_Connected)
{
PostInternalMessage(MsgType.Disconnect);
m_Connected = false;
}
m_AsyncConnect = ConnectState.Disconnected;
m_LocalServer.RemoveLocalClient(m_Connection);
}
internal void InternalConnectLocalServer(bool generateConnectMsg)
{
if (m_FreeMessages == null)
{
m_FreeMessages = new Stack<InternalMsg>();
for (int i = 0; i < k_InitialFreeMessagePoolSize; i++)
{
InternalMsg msg = new InternalMsg();
m_FreeMessages.Push(msg);
}
}
m_LocalServer = NetworkServer.instance;
m_Connection = new ULocalConnectionToServer(m_LocalServer);
SetHandlers(m_Connection);
m_Connection.connectionId = m_LocalServer.AddLocalClient(this);
m_AsyncConnect = ConnectState.Connected;
SetActive(true);
RegisterSystemHandlers(true);
if (generateConnectMsg)
{
PostInternalMessage(MsgType.Connect);
}
m_Connected = true;
}
internal override void Update()
{
ProcessInternalMessages();
}
// Called by the server to set the LocalClient's LocalPlayer object during NetworkServer.AddPlayer()
internal void AddLocalPlayer(PlayerController localPlayer)
{
if (LogFilter.logDev) Debug.Log("Local client AddLocalPlayer " + localPlayer.gameObject.name + " conn=" + m_Connection.connectionId);
m_Connection.isReady = true;
m_Connection.SetPlayerController(localPlayer);
var uv = localPlayer.unetView;
if (uv != null)
{
ClientScene.SetLocalObject(uv.netId, localPlayer.gameObject);
uv.SetConnectionToServer(m_Connection);
}
// there is no SystemOwnerMessage for local client. add to ClientScene here instead
ClientScene.InternalAddPlayer(uv, localPlayer.playerControllerId);
}
private void PostInternalMessage(byte[] buffer, int channelId)
{
InternalMsg msg;
if (m_FreeMessages.Count == 0)
{
msg = new InternalMsg(); // grow forever?
}
else
{
msg = m_FreeMessages.Pop();
}
msg.buffer = buffer;
msg.channelId = channelId;
m_InternalMsgs.Add(msg);
}
private void PostInternalMessage(short msgType)
{
NetworkWriter writer = new NetworkWriter();
writer.StartMessage(msgType);
writer.FinishMessage();
PostInternalMessage(writer.AsArray(), 0);
}
private void ProcessInternalMessages()
{
if (m_InternalMsgs.Count == 0)
{
return;
}
// new msgs will get put in m_InternalMsgs2
List<InternalMsg> tmp = m_InternalMsgs;
m_InternalMsgs = m_InternalMsgs2;
// iterate through existing set
for (int i = 0; i < tmp.Count; i++)
{
var msg = tmp[i];
if (s_InternalMessage.reader == null)
{
s_InternalMessage.reader = new NetworkReader(msg.buffer);
}
else
{
s_InternalMessage.reader.Replace(msg.buffer);
}
s_InternalMessage.reader.ReadInt16(); //size
s_InternalMessage.channelId = msg.channelId;
s_InternalMessage.conn = connection;
s_InternalMessage.msgType = s_InternalMessage.reader.ReadInt16();
m_Connection.InvokeHandler(s_InternalMessage);
m_FreeMessages.Push(msg);
connection.lastMessageTime = Time.time;
}
// put m_InternalMsgs back and clear it
m_InternalMsgs = tmp;
m_InternalMsgs.Clear();
// add any newly generated msgs in m_InternalMsgs2 and clear it
for (int ii = 0; ii < m_InternalMsgs2.Count; ii++)
{
m_InternalMsgs.Add(m_InternalMsgs2[ii]);
}
m_InternalMsgs2.Clear();
}
// called by the server, to bypass network
internal void InvokeHandlerOnClient(short msgType, MessageBase msg, int channelId)
{
// write the message to a local buffer
NetworkWriter writer = new NetworkWriter();
writer.StartMessage(msgType);
msg.Serialize(writer);
writer.FinishMessage();
InvokeBytesOnClient(writer.AsArray(), channelId);
}
// called by the server, to bypass network
internal void InvokeBytesOnClient(byte[] buffer, int channelId)
{
PostInternalMessage(buffer, channelId);
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,126 @@
using System;
#if ENABLE_UNET
namespace UnityEngine.Networking
{
// a server's connection TO a LocalClient.
// sending messages on this connection causes the client's
// handler function to be invoked directly
class ULocalConnectionToClient : NetworkConnection
{
LocalClient m_LocalClient;
public LocalClient localClient { get { return m_LocalClient; } }
public ULocalConnectionToClient(LocalClient localClient)
{
address = "localClient";
m_LocalClient = localClient;
}
public override bool Send(short msgType, MessageBase msg)
{
m_LocalClient.InvokeHandlerOnClient(msgType, msg, Channels.DefaultReliable);
return true;
}
public override bool SendUnreliable(short msgType, MessageBase msg)
{
m_LocalClient.InvokeHandlerOnClient(msgType, msg, Channels.DefaultUnreliable);
return true;
}
public override bool SendByChannel(short msgType, MessageBase msg, int channelId)
{
m_LocalClient.InvokeHandlerOnClient(msgType, msg, channelId);
return true;
}
public override bool SendBytes(byte[] bytes, int numBytes, int channelId)
{
m_LocalClient.InvokeBytesOnClient(bytes, channelId);
return true;
}
public override bool SendWriter(NetworkWriter writer, int channelId)
{
m_LocalClient.InvokeBytesOnClient(writer.AsArray(), channelId);
return true;
}
public override void GetStatsOut(out int numMsgs, out int numBufferedMsgs, out int numBytes, out int lastBufferedPerSecond)
{
numMsgs = 0;
numBufferedMsgs = 0;
numBytes = 0;
lastBufferedPerSecond = 0;
}
public override void GetStatsIn(out int numMsgs, out int numBytes)
{
numMsgs = 0;
numBytes = 0;
}
}
// a localClient's connection TO a server.
// send messages on this connection causes the server's
// handler function to be invoked directly.
internal class ULocalConnectionToServer : NetworkConnection
{
NetworkServer m_LocalServer;
public ULocalConnectionToServer(NetworkServer localServer)
{
address = "localServer";
m_LocalServer = localServer;
}
public override bool Send(short msgType, MessageBase msg)
{
return m_LocalServer.InvokeHandlerOnServer(this, msgType, msg, Channels.DefaultReliable);
}
public override bool SendUnreliable(short msgType, MessageBase msg)
{
return m_LocalServer.InvokeHandlerOnServer(this, msgType, msg, Channels.DefaultUnreliable);
}
public override bool SendByChannel(short msgType, MessageBase msg, int channelId)
{
return m_LocalServer.InvokeHandlerOnServer(this, msgType, msg, channelId);
}
public override bool SendBytes(byte[] bytes, int numBytes, int channelId)
{
if (numBytes <= 0)
{
if (LogFilter.logError) { Debug.LogError("LocalConnection:SendBytes cannot send zero bytes"); }
return false;
}
return m_LocalServer.InvokeBytes(this, bytes, numBytes, channelId);
}
public override bool SendWriter(NetworkWriter writer, int channelId)
{
return m_LocalServer.InvokeBytes(this, writer.AsArray(), (short)writer.AsArray().Length, channelId);
}
public override void GetStatsOut(out int numMsgs, out int numBufferedMsgs, out int numBytes, out int lastBufferedPerSecond)
{
numMsgs = 0;
numBufferedMsgs = 0;
numBytes = 0;
lastBufferedPerSecond = 0;
}
public override void GetStatsIn(out int numMsgs, out int numBytes)
{
numMsgs = 0;
numBytes = 0;
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,43 @@
using System;
#if ENABLE_UNET
namespace UnityEngine.Networking
{
public class LogFilter
{
// this only exists for inspector UI?!
public enum FilterLevel
{
Developer = 0,
Debug = 1,
Info = 2,
Warn = 3,
Error = 4,
Fatal = 5,
SetInScripting = -1
};
internal const int Developer = 0;
internal const int SetInScripting = -1;
public const int Debug = 1;
public const int Info = 2;
public const int Warn = 3;
public const int Error = 4;
public const int Fatal = 5;
[Obsolete("Use LogFilter.currentLogLevel instead")]
static public FilterLevel current = FilterLevel.Info;
static int s_CurrentLogLevel = Info;
static public int currentLogLevel { get { return s_CurrentLogLevel; } set { s_CurrentLogLevel = value; } }
static internal bool logDev { get { return s_CurrentLogLevel <= Developer; } }
static public bool logDebug { get { return s_CurrentLogLevel <= Debug; } }
static public bool logInfo { get { return s_CurrentLogLevel <= Info; } }
static public bool logWarn { get { return s_CurrentLogLevel <= Warn; } }
static public bool logError { get { return s_CurrentLogLevel <= Error; } }
static public bool logFatal { get { return s_CurrentLogLevel <= Fatal; } }
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,597 @@
using System;
using System.Collections.Generic;
#if ENABLE_UNET
namespace UnityEngine.Networking
{
// This can't be an interface because users don't need to implement the
// serialization functions, we'll code generate it for them when they omit it.
public abstract class MessageBase
{
// De-serialize the contents of the reader into this message
public virtual void Deserialize(NetworkReader reader) {}
// Serialize the contents of this message into the writer
public virtual void Serialize(NetworkWriter writer) {}
}
}
namespace UnityEngine.Networking.NetworkSystem
{
// ---------- General Typed Messages -------------------
public class StringMessage : MessageBase
{
public string value;
public StringMessage()
{
}
public StringMessage(string v)
{
value = v;
}
public override void Deserialize(NetworkReader reader)
{
value = reader.ReadString();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(value);
}
}
public class IntegerMessage : MessageBase
{
public int value;
public IntegerMessage()
{
}
public IntegerMessage(int v)
{
value = v;
}
public override void Deserialize(NetworkReader reader)
{
value = (int)reader.ReadPackedUInt32();
}
public override void Serialize(NetworkWriter writer)
{
writer.WritePackedUInt32((uint)value);
}
}
public class EmptyMessage : MessageBase
{
public override void Deserialize(NetworkReader reader)
{
}
public override void Serialize(NetworkWriter writer)
{
}
}
// ---------- Public System Messages -------------------
public class ErrorMessage : MessageBase
{
public int errorCode;
public override void Deserialize(NetworkReader reader)
{
errorCode = reader.ReadUInt16();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write((ushort)errorCode);
}
}
public class ReadyMessage : EmptyMessage
{
}
public class NotReadyMessage : EmptyMessage
{
}
public class AddPlayerMessage : MessageBase
{
public short playerControllerId;
public int msgSize;
public byte[] msgData;
public override void Deserialize(NetworkReader reader)
{
playerControllerId = (short)reader.ReadUInt16();
msgData = reader.ReadBytesAndSize();
if (msgData == null)
{
msgSize = 0;
}
else
{
msgSize = msgData.Length;
}
}
public override void Serialize(NetworkWriter writer)
{
writer.Write((ushort)playerControllerId);
writer.WriteBytesAndSize(msgData, msgSize);
}
}
public class RemovePlayerMessage : MessageBase
{
public short playerControllerId;
public override void Deserialize(NetworkReader reader)
{
playerControllerId = (short)reader.ReadUInt16();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write((ushort)playerControllerId);
}
}
public class PeerAuthorityMessage : MessageBase
{
public int connectionId;
public NetworkInstanceId netId;
public bool authorityState;
public override void Deserialize(NetworkReader reader)
{
connectionId = (int)reader.ReadPackedUInt32();
netId = reader.ReadNetworkId();
authorityState = reader.ReadBoolean();
}
public override void Serialize(NetworkWriter writer)
{
writer.WritePackedUInt32((uint)connectionId);
writer.Write(netId);
writer.Write(authorityState);
}
}
public struct PeerInfoPlayer
{
public NetworkInstanceId netId;
public short playerControllerId;
}
public class PeerInfoMessage : MessageBase
{
public int connectionId;
public string address;
public int port;
public bool isHost;
public bool isYou;
public PeerInfoPlayer[] playerIds;
public override void Deserialize(NetworkReader reader)
{
connectionId = (int)reader.ReadPackedUInt32();
address = reader.ReadString();
port = (int)reader.ReadPackedUInt32();
isHost = reader.ReadBoolean();
isYou = reader.ReadBoolean();
uint numPlayers = reader.ReadPackedUInt32();
if (numPlayers > 0)
{
List<PeerInfoPlayer> ids = new List<PeerInfoPlayer>();
for (uint i = 0; i < numPlayers; i++)
{
PeerInfoPlayer info;
info.netId = reader.ReadNetworkId();
info.playerControllerId = (short)reader.ReadPackedUInt32();
ids.Add(info);
}
playerIds = ids.ToArray();
}
}
public override void Serialize(NetworkWriter writer)
{
writer.WritePackedUInt32((uint)connectionId);
writer.Write(address);
writer.WritePackedUInt32((uint)port);
writer.Write(isHost);
writer.Write(isYou);
if (playerIds == null)
{
writer.WritePackedUInt32(0);
}
else
{
writer.WritePackedUInt32((uint)playerIds.Length);
for (int i = 0; i < playerIds.Length; i++)
{
writer.Write(playerIds[i].netId);
writer.WritePackedUInt32((uint)playerIds[i].playerControllerId);
}
}
}
public override string ToString()
{
return "PeerInfo conn:" + connectionId + " addr:" + address + ":" + port + " host:" + isHost + " isYou:" + isYou;
}
}
public class PeerListMessage : MessageBase
{
public PeerInfoMessage[] peers;
public int oldServerConnectionId;
public override void Deserialize(NetworkReader reader)
{
oldServerConnectionId = (int)reader.ReadPackedUInt32();
int numPeers = reader.ReadUInt16();
peers = new PeerInfoMessage[numPeers];
for (int i = 0; i < peers.Length; ++i)
{
var peerInfo = new PeerInfoMessage();
peerInfo.Deserialize(reader);
peers[i] = peerInfo;
}
}
public override void Serialize(NetworkWriter writer)
{
writer.WritePackedUInt32((uint)oldServerConnectionId);
writer.Write((ushort)peers.Length);
for (int i = 0; i < peers.Length; i++)
{
peers[i].Serialize(writer);
}
}
}
#if ENABLE_UNET_HOST_MIGRATION
public class ReconnectMessage : MessageBase
{
public int oldConnectionId;
public short playerControllerId;
public NetworkInstanceId netId;
public int msgSize;
public byte[] msgData;
public override void Deserialize(NetworkReader reader)
{
oldConnectionId = (int)reader.ReadPackedUInt32();
playerControllerId = (short)reader.ReadPackedUInt32();
netId = reader.ReadNetworkId();
msgData = reader.ReadBytesAndSize();
msgSize = msgData.Length;
}
public override void Serialize(NetworkWriter writer)
{
writer.WritePackedUInt32((uint)oldConnectionId);
writer.WritePackedUInt32((uint)playerControllerId);
writer.Write(netId);
writer.WriteBytesAndSize(msgData, msgSize);
}
}
#endif
// ---------- System Messages requried for code gen path -------------------
/* These are not used directly but manually serialized, these are here for reference.
public struct CommandMessage
{
public int cmdHash;
public string cmdName;
public byte[] payload;
}
public struct RPCMessage
{
public NetworkId netId;
public int cmdHash;
public byte[] payload;
}
public struct SyncEventMessage
{
public NetworkId netId;
public int cmdHash;
public byte[] payload;
}
internal class SyncListMessage<T> where T: struct
{
public NetworkId netId;
public int cmdHash;
public byte operation;
public int itemIndex;
public T item;
}
*/
// ---------- Internal System Messages -------------------
class ObjectSpawnMessage : MessageBase
{
public NetworkInstanceId netId;
public NetworkHash128 assetId;
public Vector3 position;
public byte[] payload;
public Quaternion rotation;
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadNetworkId();
assetId = reader.ReadNetworkHash128();
position = reader.ReadVector3();
payload = reader.ReadBytesAndSize();
uint extraPayloadSize = sizeof(uint) * 4;
if ((reader.Length - reader.Position) >= extraPayloadSize)
{
rotation = reader.ReadQuaternion();
}
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(netId);
writer.Write(assetId);
writer.Write(position);
writer.WriteBytesFull(payload);
writer.Write(rotation);
}
}
class ObjectSpawnSceneMessage : MessageBase
{
public NetworkInstanceId netId;
public NetworkSceneId sceneId;
public Vector3 position;
public byte[] payload;
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadNetworkId();
sceneId = reader.ReadSceneId();
position = reader.ReadVector3();
payload = reader.ReadBytesAndSize();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(netId);
writer.Write(sceneId);
writer.Write(position);
writer.WriteBytesFull(payload);
}
}
class ObjectSpawnFinishedMessage : MessageBase
{
public uint state;
public override void Deserialize(NetworkReader reader)
{
state = reader.ReadPackedUInt32();
}
public override void Serialize(NetworkWriter writer)
{
writer.WritePackedUInt32(state);
}
}
class ObjectDestroyMessage : MessageBase
{
public NetworkInstanceId netId;
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadNetworkId();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(netId);
}
}
class OwnerMessage : MessageBase
{
public NetworkInstanceId netId;
public short playerControllerId;
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadNetworkId();
playerControllerId = (short)reader.ReadPackedUInt32();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(netId);
writer.WritePackedUInt32((uint)playerControllerId);
}
}
class ClientAuthorityMessage : MessageBase
{
public NetworkInstanceId netId;
public bool authority;
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadNetworkId();
authority = reader.ReadBoolean();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(netId);
writer.Write(authority);
}
}
class OverrideTransformMessage : MessageBase
{
public NetworkInstanceId netId;
public byte[] payload;
public bool teleport;
public int time;
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadNetworkId();
payload = reader.ReadBytesAndSize();
teleport = reader.ReadBoolean();
time = (int)reader.ReadPackedUInt32();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(netId);
writer.WriteBytesFull(payload);
writer.Write(teleport);
writer.WritePackedUInt32((uint)time);
}
}
class AnimationMessage : MessageBase
{
public NetworkInstanceId netId;
public int stateHash; // if non-zero, then Play() this animation, skipping transitions
public float normalizedTime;
public byte[] parameters;
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadNetworkId();
stateHash = (int)reader.ReadPackedUInt32();
normalizedTime = reader.ReadSingle();
parameters = reader.ReadBytesAndSize();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(netId);
writer.WritePackedUInt32((uint)stateHash);
writer.Write(normalizedTime);
if (parameters == null)
writer.WriteBytesAndSize(parameters, 0);
else
writer.WriteBytesAndSize(parameters, parameters.Length);
}
}
class AnimationParametersMessage : MessageBase
{
public NetworkInstanceId netId;
public byte[] parameters;
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadNetworkId();
parameters = reader.ReadBytesAndSize();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(netId);
if (parameters == null)
writer.WriteBytesAndSize(parameters, 0);
else
writer.WriteBytesAndSize(parameters, parameters.Length);
}
}
class AnimationTriggerMessage : MessageBase
{
public NetworkInstanceId netId;
public int hash;
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadNetworkId();
hash = (int)reader.ReadPackedUInt32();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(netId);
writer.WritePackedUInt32((uint)hash);
}
}
class LobbyReadyToBeginMessage : MessageBase
{
public byte slotId;
public bool readyState;
public override void Deserialize(NetworkReader reader)
{
slotId = reader.ReadByte();
readyState = reader.ReadBoolean();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(slotId);
writer.Write(readyState);
}
}
struct CRCMessageEntry
{
public string name;
public byte channel;
}
class CRCMessage : MessageBase
{
public CRCMessageEntry[] scripts;
public override void Deserialize(NetworkReader reader)
{
int numScripts = reader.ReadUInt16();
scripts = new CRCMessageEntry[numScripts];
for (int i = 0; i < scripts.Length; ++i)
{
var entry = new CRCMessageEntry();
entry.name = reader.ReadString();
entry.channel = reader.ReadByte();
scripts[i] = entry;
}
}
public override void Serialize(NetworkWriter writer)
{
writer.Write((ushort)scripts.Length);
for (int i = 0; i < scripts.Length; i++)
{
writer.Write(scripts[i].name);
writer.Write(scripts[i].channel);
}
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,484 @@
#if ENABLE_UNET
using System;
using UnityEngine;
using UnityEngine.Networking.NetworkSystem;
namespace UnityEngine.Networking
{
[DisallowMultipleComponent]
[AddComponentMenu("Network/NetworkAnimator")]
[RequireComponent(typeof(NetworkIdentity))]
[RequireComponent(typeof(Animator))]
public class NetworkAnimator : NetworkBehaviour
{
// configuration
[SerializeField] Animator m_Animator;
[SerializeField] uint m_ParameterSendBits;
// static message objects to avoid runtime-allocations
static AnimationMessage s_AnimationMessage = new AnimationMessage();
static AnimationParametersMessage s_AnimationParametersMessage = new AnimationParametersMessage();
static AnimationTriggerMessage s_AnimationTriggerMessage = new AnimationTriggerMessage();
// properties
public Animator animator
{
get { return m_Animator; }
set
{
m_Animator = value;
ResetParameterOptions();
}
}
public void SetParameterAutoSend(int index, bool value)
{
if (value)
{
m_ParameterSendBits |= (uint)(1 << index);
}
else
{
m_ParameterSendBits &= (uint)(~(1 << index));
}
}
public bool GetParameterAutoSend(int index)
{
return (m_ParameterSendBits & (uint)(1 << index)) != 0;
}
int m_AnimationHash;
int m_TransitionHash;
NetworkWriter m_ParameterWriter;
float m_SendTimer;
// tracking - these should probably move to a Preview component.
public string param0;
public string param1;
public string param2;
public string param3;
public string param4;
public string param5;
bool sendMessagesAllowed
{
get
{
if (isServer)
{
if (!localPlayerAuthority)
return true;
// This is a special case where we have localPlayerAuthority set
// on a NetworkIdentity but we have not assigned the client who has
// authority over it, no animator data will be sent over the network by the server.
//
// So we check here for a clientAuthorityOwner and if it is null we will
// let the server send animation data until we receive an owner.
if (netIdentity != null && netIdentity.clientAuthorityOwner == null)
return true;
}
if (hasAuthority)
return true;
return false;
}
}
internal void ResetParameterOptions()
{
Debug.Log("ResetParameterOptions");
m_ParameterSendBits = 0;
}
void FixedUpdate()
{
if (!sendMessagesAllowed)
return;
if (m_ParameterWriter == null)
m_ParameterWriter = new NetworkWriter();
CheckSendRate();
int stateHash;
float normalizedTime;
if (!CheckAnimStateChanged(out stateHash, out normalizedTime))
{
return;
}
var animMsg = new AnimationMessage();
animMsg.netId = netId;
animMsg.stateHash = stateHash;
animMsg.normalizedTime = normalizedTime;
m_ParameterWriter.SeekZero();
WriteParameters(m_ParameterWriter, false);
animMsg.parameters = m_ParameterWriter.ToArray();
SendMessage(MsgType.Animation, animMsg);
}
bool CheckAnimStateChanged(out int stateHash, out float normalizedTime)
{
stateHash = 0;
normalizedTime = 0;
if (m_Animator.IsInTransition(0))
{
AnimatorTransitionInfo tt = m_Animator.GetAnimatorTransitionInfo(0);
if (tt.fullPathHash != m_TransitionHash)
{
// first time in this transition
m_TransitionHash = tt.fullPathHash;
m_AnimationHash = 0;
return true;
}
return false;
}
AnimatorStateInfo st = m_Animator.GetCurrentAnimatorStateInfo(0);
if (st.fullPathHash != m_AnimationHash)
{
// first time in this animation state
if (m_AnimationHash != 0)
{
// came from another animation directly - from Play()
stateHash = st.fullPathHash;
normalizedTime = st.normalizedTime;
}
m_TransitionHash = 0;
m_AnimationHash = st.fullPathHash;
return true;
}
return false;
}
void CheckSendRate()
{
if (sendMessagesAllowed && GetNetworkSendInterval() != 0 && m_SendTimer < Time.time)
{
m_SendTimer = Time.time + GetNetworkSendInterval();
var animMsg = new AnimationParametersMessage();
animMsg.netId = netId;
m_ParameterWriter.SeekZero();
WriteParameters(m_ParameterWriter, true);
animMsg.parameters = m_ParameterWriter.ToArray();
SendMessage(MsgType.AnimationParameters, animMsg);
}
}
void SendMessage(short type, MessageBase msg)
{
if (isServer)
{
NetworkServer.SendToReady(gameObject, type, msg);
}
else
{
if (ClientScene.readyConnection != null)
{
ClientScene.readyConnection.Send(type, msg);
}
}
}
void SetSendTrackingParam(string p, int i)
{
p = "Sent Param: " + p;
if (i == 0) param0 = p;
if (i == 1) param1 = p;
if (i == 2) param2 = p;
if (i == 3) param3 = p;
if (i == 4) param4 = p;
if (i == 5) param5 = p;
}
void SetRecvTrackingParam(string p, int i)
{
p = "Recv Param: " + p;
if (i == 0) param0 = p;
if (i == 1) param1 = p;
if (i == 2) param2 = p;
if (i == 3) param3 = p;
if (i == 4) param4 = p;
if (i == 5) param5 = p;
}
internal void HandleAnimMsg(AnimationMessage msg, NetworkReader reader)
{
if (hasAuthority)
return;
// usually transitions will be triggered by parameters, if not, play anims directly.
// NOTE: this plays "animations", not transitions, so any transitions will be skipped.
// NOTE: there is no API to play a transition(?)
if (msg.stateHash != 0)
{
m_Animator.Play(msg.stateHash, 0, msg.normalizedTime);
}
ReadParameters(reader, false);
}
internal void HandleAnimParamsMsg(AnimationParametersMessage msg, NetworkReader reader)
{
if (hasAuthority)
return;
ReadParameters(reader, true);
}
internal void HandleAnimTriggerMsg(int hash)
{
m_Animator.SetTrigger(hash);
}
void WriteParameters(NetworkWriter writer, bool autoSend)
{
for (int i = 0; i < m_Animator.parameters.Length; i++)
{
if (autoSend && !GetParameterAutoSend(i))
continue;
AnimatorControllerParameter par = m_Animator.parameters[i];
if (par.type == AnimatorControllerParameterType.Int)
{
writer.WritePackedUInt32((uint)m_Animator.GetInteger(par.nameHash));
SetSendTrackingParam(par.name + ":" + m_Animator.GetInteger(par.nameHash), i);
}
if (par.type == AnimatorControllerParameterType.Float)
{
writer.Write(m_Animator.GetFloat(par.nameHash));
SetSendTrackingParam(par.name + ":" + m_Animator.GetFloat(par.nameHash), i);
}
if (par.type == AnimatorControllerParameterType.Bool)
{
writer.Write(m_Animator.GetBool(par.nameHash));
SetSendTrackingParam(par.name + ":" + m_Animator.GetBool(par.nameHash), i);
}
}
}
void ReadParameters(NetworkReader reader, bool autoSend)
{
for (int i = 0; i < m_Animator.parameters.Length; i++)
{
if (autoSend && !GetParameterAutoSend(i))
continue;
AnimatorControllerParameter par = m_Animator.parameters[i];
if (par.type == AnimatorControllerParameterType.Int)
{
int newValue = (int)reader.ReadPackedUInt32();
m_Animator.SetInteger(par.nameHash, newValue);
SetRecvTrackingParam(par.name + ":" + newValue, i);
}
if (par.type == AnimatorControllerParameterType.Float)
{
float newFloatValue = reader.ReadSingle();
m_Animator.SetFloat(par.nameHash, newFloatValue);
SetRecvTrackingParam(par.name + ":" + newFloatValue, i);
}
if (par.type == AnimatorControllerParameterType.Bool)
{
bool newBoolValue = reader.ReadBoolean();
m_Animator.SetBool(par.nameHash, newBoolValue);
SetRecvTrackingParam(par.name + ":" + newBoolValue, i);
}
}
}
public override bool OnSerialize(NetworkWriter writer, bool forceAll)
{
if (forceAll)
{
if (m_Animator.IsInTransition(0))
{
AnimatorStateInfo st = m_Animator.GetNextAnimatorStateInfo(0);
writer.Write(st.fullPathHash);
writer.Write(st.normalizedTime);
}
else
{
AnimatorStateInfo st = m_Animator.GetCurrentAnimatorStateInfo(0);
writer.Write(st.fullPathHash);
writer.Write(st.normalizedTime);
}
WriteParameters(writer, false);
return true;
}
return false;
}
public override void OnDeserialize(NetworkReader reader, bool initialState)
{
if (initialState)
{
int stateHash = reader.ReadInt32();
float normalizedTime = reader.ReadSingle();
ReadParameters(reader, false);
m_Animator.Play(stateHash, 0, normalizedTime);
}
}
public void SetTrigger(string triggerName)
{
SetTrigger(Animator.StringToHash(triggerName));
}
public void SetTrigger(int hash)
{
var animMsg = new AnimationTriggerMessage();
animMsg.netId = netId;
animMsg.hash = hash;
if (hasAuthority && localPlayerAuthority)
{
if (NetworkClient.allClients.Count > 0)
{
var client = ClientScene.readyConnection;
if (client != null)
{
client.Send(MsgType.AnimationTrigger, animMsg);
}
}
return;
}
if (isServer && !localPlayerAuthority)
{
NetworkServer.SendToReady(gameObject, MsgType.AnimationTrigger, animMsg);
}
}
// ------------------ server message handlers -------------------
static internal void OnAnimationServerMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_AnimationMessage);
if (LogFilter.logDev) { Debug.Log("OnAnimationMessage for netId=" + s_AnimationMessage.netId + " conn=" + netMsg.conn); }
GameObject go = NetworkServer.FindLocalObject(s_AnimationMessage.netId);
if (go == null)
{
return;
}
NetworkAnimator animSync = go.GetComponent<NetworkAnimator>();
if (animSync != null)
{
NetworkReader reader = new NetworkReader(s_AnimationMessage.parameters);
animSync.HandleAnimMsg(s_AnimationMessage, reader);
NetworkServer.SendToReady(go, MsgType.Animation, s_AnimationMessage);
}
}
static internal void OnAnimationParametersServerMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_AnimationParametersMessage);
if (LogFilter.logDev) { Debug.Log("OnAnimationParametersMessage for netId=" + s_AnimationParametersMessage.netId + " conn=" + netMsg.conn); }
GameObject go = NetworkServer.FindLocalObject(s_AnimationParametersMessage.netId);
if (go == null)
{
return;
}
NetworkAnimator animSync = go.GetComponent<NetworkAnimator>();
if (animSync != null)
{
NetworkReader reader = new NetworkReader(s_AnimationParametersMessage.parameters);
animSync.HandleAnimParamsMsg(s_AnimationParametersMessage, reader);
NetworkServer.SendToReady(go, MsgType.AnimationParameters, s_AnimationParametersMessage);
}
}
static internal void OnAnimationTriggerServerMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_AnimationTriggerMessage);
if (LogFilter.logDev) { Debug.Log("OnAnimationTriggerMessage for netId=" + s_AnimationTriggerMessage.netId + " conn=" + netMsg.conn); }
GameObject go = NetworkServer.FindLocalObject(s_AnimationTriggerMessage.netId);
if (go == null)
{
return;
}
NetworkAnimator animSync = go.GetComponent<NetworkAnimator>();
if (animSync != null)
{
animSync.HandleAnimTriggerMsg(s_AnimationTriggerMessage.hash);
NetworkServer.SendToReady(go, MsgType.AnimationTrigger, s_AnimationTriggerMessage);
}
}
// ------------------ client message handlers -------------------
static internal void OnAnimationClientMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_AnimationMessage);
GameObject go = ClientScene.FindLocalObject(s_AnimationMessage.netId);
if (go == null)
{
return;
}
var animSync = go.GetComponent<NetworkAnimator>();
if (animSync != null)
{
var reader = new NetworkReader(s_AnimationMessage.parameters);
animSync.HandleAnimMsg(s_AnimationMessage, reader);
}
}
static internal void OnAnimationParametersClientMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_AnimationParametersMessage);
GameObject go = ClientScene.FindLocalObject(s_AnimationParametersMessage.netId);
if (go == null)
{
return;
}
var animSync = go.GetComponent<NetworkAnimator>();
if (animSync != null)
{
var reader = new NetworkReader(s_AnimationParametersMessage.parameters);
animSync.HandleAnimParamsMsg(s_AnimationParametersMessage, reader);
}
}
static internal void OnAnimationTriggerClientMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_AnimationTriggerMessage);
GameObject go = ClientScene.FindLocalObject(s_AnimationTriggerMessage.netId);
if (go == null)
{
return;
}
var animSync = go.GetComponent<NetworkAnimator>();
if (animSync != null)
{
animSync.HandleAnimTriggerMsg(s_AnimationTriggerMessage.hash);
}
}
}
}
#endif

View File

@ -0,0 +1,650 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace UnityEngine.Networking
{
[RequireComponent(typeof(NetworkIdentity))]
[AddComponentMenu("")]
public class NetworkBehaviour : MonoBehaviour
{
uint m_SyncVarDirtyBits;
float m_LastSendTime;
// this prevents recursion when SyncVar hook functions are called.
bool m_SyncVarGuard;
public bool localPlayerAuthority { get { return myView.localPlayerAuthority; } }
public bool isServer { get { return myView.isServer; } }
public bool isClient { get { return myView.isClient; } }
public bool isLocalPlayer { get { return myView.isLocalPlayer; } }
public bool hasAuthority { get { return myView.hasAuthority; } }
public NetworkInstanceId netId { get { return myView.netId; } }
public NetworkConnection connectionToServer { get { return myView.connectionToServer; } }
public NetworkConnection connectionToClient { get { return myView.connectionToClient; } }
public short playerControllerId { get { return myView.playerControllerId; } }
protected uint syncVarDirtyBits { get { return m_SyncVarDirtyBits; } }
protected bool syncVarHookGuard { get { return m_SyncVarGuard; } set { m_SyncVarGuard = value; }}
internal NetworkIdentity netIdentity { get { return myView; } }
const float k_DefaultSendInterval = 0.1f;
NetworkIdentity m_MyView;
NetworkIdentity myView
{
get
{
if (m_MyView == null)
{
m_MyView = GetComponent<NetworkIdentity>();
if (m_MyView == null)
{
if (LogFilter.logError) { Debug.LogError("There is no NetworkIdentity on this object. Please add one."); }
}
return m_MyView;
}
return m_MyView;
}
}
// ----------------------------- Commands --------------------------------
[EditorBrowsable(EditorBrowsableState.Never)]
protected void SendCommandInternal(NetworkWriter writer, int channelId, string cmdName)
{
// local players can always send commands, regardless of authority, other objects must have authority.
if (!(isLocalPlayer || hasAuthority))
{
if (LogFilter.logWarn) { Debug.LogWarning("Trying to send command for object without authority."); }
return;
}
if (ClientScene.readyConnection == null)
{
if (LogFilter.logError) { Debug.LogError("Send command attempted with no client running [client=" + connectionToServer + "]."); }
return;
}
writer.FinishMessage();
ClientScene.readyConnection.SendWriter(writer, channelId);
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.Command, cmdName, 1);
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual bool InvokeCommand(int cmdHash, NetworkReader reader)
{
if (InvokeCommandDelegate(cmdHash, reader))
{
return true;
}
return false;
}
// ----------------------------- Client RPCs --------------------------------
[EditorBrowsable(EditorBrowsableState.Never)]
protected void SendRPCInternal(NetworkWriter writer, int channelId, string rpcName)
{
// This cannot use NetworkServer.active, as that is not specific to this object.
if (!isServer)
{
if (LogFilter.logWarn) { Debug.LogWarning("ClientRpc call on un-spawned object"); }
return;
}
writer.FinishMessage();
NetworkServer.SendWriterToReady(gameObject, writer, channelId);
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.Rpc, rpcName, 1);
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
protected void SendTargetRPCInternal(NetworkConnection conn, NetworkWriter writer, int channelId, string rpcName)
{
// This cannot use NetworkServer.active, as that is not specific to this object.
if (!isServer)
{
if (LogFilter.logWarn) { Debug.LogWarning("TargetRpc call on un-spawned object"); }
return;
}
writer.FinishMessage();
conn.SendWriter(writer, channelId);
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.Rpc, rpcName, 1);
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual bool InvokeRPC(int cmdHash, NetworkReader reader)
{
if (InvokeRpcDelegate(cmdHash, reader))
{
return true;
}
return false;
}
// ----------------------------- Sync Events --------------------------------
[EditorBrowsable(EditorBrowsableState.Never)]
protected void SendEventInternal(NetworkWriter writer, int channelId, string eventName)
{
if (!NetworkServer.active)
{
if (LogFilter.logWarn) { Debug.LogWarning("SendEvent no server?"); }
return;
}
writer.FinishMessage();
NetworkServer.SendWriterToReady(gameObject, writer, channelId);
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.SyncEvent, eventName, 1);
#endif
}
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual bool InvokeSyncEvent(int cmdHash, NetworkReader reader)
{
if (InvokeSyncEventDelegate(cmdHash, reader))
{
return true;
}
return false;
}
// ----------------------------- Sync Lists --------------------------------
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual bool InvokeSyncList(int cmdHash, NetworkReader reader)
{
if (InvokeSyncListDelegate(cmdHash, reader))
{
return true;
}
return false;
}
// ----------------------------- Code Gen Path Helpers --------------------------------
public delegate void CmdDelegate(NetworkBehaviour obj, NetworkReader reader);
protected delegate void EventDelegate(List<Delegate> targets, NetworkReader reader);
protected enum UNetInvokeType
{
Command,
ClientRpc,
SyncEvent,
SyncList
};
protected class Invoker
{
public UNetInvokeType invokeType;
public Type invokeClass;
public CmdDelegate invokeFunction;
public string DebugString()
{
return invokeType + ":" +
invokeClass + ":" +
invokeFunction.GetMethodName();
}
};
static Dictionary<int, Invoker> s_CmdHandlerDelegates = new Dictionary<int, Invoker>();
[EditorBrowsable(EditorBrowsableState.Never)]
static protected void RegisterCommandDelegate(Type invokeClass, int cmdHash, CmdDelegate func)
{
if (s_CmdHandlerDelegates.ContainsKey(cmdHash))
{
return;
}
Invoker inv = new Invoker();
inv.invokeType = UNetInvokeType.Command;
inv.invokeClass = invokeClass;
inv.invokeFunction = func;
s_CmdHandlerDelegates[cmdHash] = inv;
if (LogFilter.logDev) { Debug.Log("RegisterCommandDelegate hash:" + cmdHash + " " + func.GetMethodName()); }
}
[EditorBrowsable(EditorBrowsableState.Never)]
static protected void RegisterRpcDelegate(Type invokeClass, int cmdHash, CmdDelegate func)
{
if (s_CmdHandlerDelegates.ContainsKey(cmdHash))
{
return;
}
Invoker inv = new Invoker();
inv.invokeType = UNetInvokeType.ClientRpc;
inv.invokeClass = invokeClass;
inv.invokeFunction = func;
s_CmdHandlerDelegates[cmdHash] = inv;
if (LogFilter.logDev) { Debug.Log("RegisterRpcDelegate hash:" + cmdHash + " " + func.GetMethodName()); }
}
[EditorBrowsable(EditorBrowsableState.Never)]
static protected void RegisterEventDelegate(Type invokeClass, int cmdHash, CmdDelegate func)
{
if (s_CmdHandlerDelegates.ContainsKey(cmdHash))
{
return;
}
Invoker inv = new Invoker();
inv.invokeType = UNetInvokeType.SyncEvent;
inv.invokeClass = invokeClass;
inv.invokeFunction = func;
s_CmdHandlerDelegates[cmdHash] = inv;
if (LogFilter.logDev) { Debug.Log("RegisterEventDelegate hash:" + cmdHash + " " + func.GetMethodName()); }
}
[EditorBrowsable(EditorBrowsableState.Never)]
static protected void RegisterSyncListDelegate(Type invokeClass, int cmdHash, CmdDelegate func)
{
if (s_CmdHandlerDelegates.ContainsKey(cmdHash))
{
return;
}
Invoker inv = new Invoker();
inv.invokeType = UNetInvokeType.SyncList;
inv.invokeClass = invokeClass;
inv.invokeFunction = func;
s_CmdHandlerDelegates[cmdHash] = inv;
if (LogFilter.logDev) { Debug.Log("RegisterSyncListDelegate hash:" + cmdHash + " " + func.GetMethodName()); }
}
internal static string GetInvoker(int cmdHash)
{
if (!s_CmdHandlerDelegates.ContainsKey(cmdHash))
{
return null;
}
Invoker inv = s_CmdHandlerDelegates[cmdHash];
return inv.DebugString();
}
// wrapper fucntions for each type of network operation
internal static bool GetInvokerForHashCommand(int cmdHash, out Type invokeClass, out CmdDelegate invokeFunction)
{
return GetInvokerForHash(cmdHash, UNetInvokeType.Command, out invokeClass, out invokeFunction);
}
internal static bool GetInvokerForHashClientRpc(int cmdHash, out Type invokeClass, out CmdDelegate invokeFunction)
{
return GetInvokerForHash(cmdHash, UNetInvokeType.ClientRpc, out invokeClass, out invokeFunction);
}
internal static bool GetInvokerForHashSyncList(int cmdHash, out Type invokeClass, out CmdDelegate invokeFunction)
{
return GetInvokerForHash(cmdHash, UNetInvokeType.SyncList, out invokeClass, out invokeFunction);
}
internal static bool GetInvokerForHashSyncEvent(int cmdHash, out Type invokeClass, out CmdDelegate invokeFunction)
{
return GetInvokerForHash(cmdHash, UNetInvokeType.SyncEvent, out invokeClass, out invokeFunction);
}
static bool GetInvokerForHash(int cmdHash, NetworkBehaviour.UNetInvokeType invokeType, out Type invokeClass, out CmdDelegate invokeFunction)
{
Invoker invoker = null;
if (!s_CmdHandlerDelegates.TryGetValue(cmdHash, out invoker))
{
if (LogFilter.logDev) { Debug.Log("GetInvokerForHash hash:" + cmdHash + " not found"); }
invokeClass = null;
invokeFunction = null;
return false;
}
if (invoker == null)
{
if (LogFilter.logDev) { Debug.Log("GetInvokerForHash hash:" + cmdHash + " invoker null"); }
invokeClass = null;
invokeFunction = null;
return false;
}
if (invoker.invokeType != invokeType)
{
if (LogFilter.logError) { Debug.LogError("GetInvokerForHash hash:" + cmdHash + " mismatched invokeType"); }
invokeClass = null;
invokeFunction = null;
return false;
}
invokeClass = invoker.invokeClass;
invokeFunction = invoker.invokeFunction;
return true;
}
internal static void DumpInvokers()
{
Debug.Log("DumpInvokers size:" + s_CmdHandlerDelegates.Count);
foreach (var inv in s_CmdHandlerDelegates)
{
Debug.Log(" Invoker:" + inv.Value.invokeClass + ":" + inv.Value.invokeFunction.GetMethodName() + " " + inv.Value.invokeType + " " + inv.Key);
}
}
internal bool ContainsCommandDelegate(int cmdHash)
{
return s_CmdHandlerDelegates.ContainsKey(cmdHash);
}
internal bool InvokeCommandDelegate(int cmdHash, NetworkReader reader)
{
if (!s_CmdHandlerDelegates.ContainsKey(cmdHash))
{
return false;
}
Invoker inv = s_CmdHandlerDelegates[cmdHash];
if (inv.invokeType != UNetInvokeType.Command)
{
return false;
}
if (GetType() != inv.invokeClass)
{
if (GetType().IsSubclassOf(inv.invokeClass))
{
// allowed, commands function is on a base class.
}
else
{
return false;
}
}
inv.invokeFunction(this, reader);
return true;
}
internal bool InvokeRpcDelegate(int cmdHash, NetworkReader reader)
{
if (!s_CmdHandlerDelegates.ContainsKey(cmdHash))
{
return false;
}
Invoker inv = s_CmdHandlerDelegates[cmdHash];
if (inv.invokeType != UNetInvokeType.ClientRpc)
{
return false;
}
if (GetType() != inv.invokeClass)
{
if (GetType().IsSubclassOf(inv.invokeClass))
{
// allowed, rpc function is on a base class.
}
else
{
return false;
}
}
inv.invokeFunction(this, reader);
return true;
}
internal bool InvokeSyncEventDelegate(int cmdHash, NetworkReader reader)
{
if (!s_CmdHandlerDelegates.ContainsKey(cmdHash))
{
return false;
}
Invoker inv = s_CmdHandlerDelegates[cmdHash];
if (inv.invokeType != UNetInvokeType.SyncEvent)
{
return false;
}
inv.invokeFunction(this, reader);
return true;
}
internal bool InvokeSyncListDelegate(int cmdHash, NetworkReader reader)
{
if (!s_CmdHandlerDelegates.ContainsKey(cmdHash))
{
return false;
}
Invoker inv = s_CmdHandlerDelegates[cmdHash];
if (inv.invokeType != UNetInvokeType.SyncList)
{
return false;
}
if (GetType() != inv.invokeClass)
{
return false;
}
inv.invokeFunction(this, reader);
return true;
}
static internal string GetCmdHashHandlerName(int cmdHash)
{
if (!s_CmdHandlerDelegates.ContainsKey(cmdHash))
{
return cmdHash.ToString();
}
Invoker inv = s_CmdHandlerDelegates[cmdHash];
return inv.invokeType + ":" + inv.invokeFunction.GetMethodName();
}
static string GetCmdHashPrefixName(int cmdHash, string prefix)
{
if (!s_CmdHandlerDelegates.ContainsKey(cmdHash))
{
return cmdHash.ToString();
}
Invoker inv = s_CmdHandlerDelegates[cmdHash];
var name = inv.invokeFunction.GetMethodName();
int index = name.IndexOf(prefix);
if (index > -1)
{
name = name.Substring(prefix.Length);
}
return name;
}
internal static string GetCmdHashCmdName(int cmdHash)
{
return GetCmdHashPrefixName(cmdHash, "InvokeCmd");
}
internal static string GetCmdHashRpcName(int cmdHash)
{
return GetCmdHashPrefixName(cmdHash, "InvokeRpc");
}
internal static string GetCmdHashEventName(int cmdHash)
{
return GetCmdHashPrefixName(cmdHash, "InvokeSyncEvent");
}
internal static string GetCmdHashListName(int cmdHash)
{
return GetCmdHashPrefixName(cmdHash, "InvokeSyncList");
}
// ----------------------------- Helpers --------------------------------
[EditorBrowsable(EditorBrowsableState.Never)]
protected void SetSyncVarGameObject(GameObject newGameObject, ref GameObject gameObjectField, uint dirtyBit, ref NetworkInstanceId netIdField)
{
if (m_SyncVarGuard)
return;
NetworkInstanceId newGameObjectNetId = new NetworkInstanceId();
if (newGameObject != null)
{
var uv = newGameObject.GetComponent<NetworkIdentity>();
if (uv != null)
{
newGameObjectNetId = uv.netId;
if (newGameObjectNetId.IsEmpty())
{
if (LogFilter.logWarn) { Debug.LogWarning("SetSyncVarGameObject GameObject " + newGameObject + " has a zero netId. Maybe it is not spawned yet?"); }
}
}
}
NetworkInstanceId oldGameObjectNetId = new NetworkInstanceId();
if (gameObjectField != null)
{
oldGameObjectNetId = gameObjectField.GetComponent<NetworkIdentity>().netId;
}
if (newGameObjectNetId != oldGameObjectNetId)
{
if (LogFilter.logDev) { Debug.Log("SetSyncVar GameObject " + GetType().Name + " bit [" + dirtyBit + "] netfieldId:" + oldGameObjectNetId + "->" + newGameObjectNetId); }
SetDirtyBit(dirtyBit);
gameObjectField = newGameObject;
netIdField = newGameObjectNetId;
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
protected void SetSyncVar<T>(T value, ref T fieldValue, uint dirtyBit)
{
bool changed = false;
if (value == null)
{
if (fieldValue != null)
changed = true;
}
else
{
changed = !value.Equals(fieldValue);
}
if (changed)
{
if (LogFilter.logDev) { Debug.Log("SetSyncVar " + GetType().Name + " bit [" + dirtyBit + "] " + fieldValue + "->" + value); }
SetDirtyBit(dirtyBit);
fieldValue = value;
}
}
// these are masks, not bit numbers, ie. 0x004 not 2
public void SetDirtyBit(uint dirtyBit)
{
m_SyncVarDirtyBits |= dirtyBit;
}
public void ClearAllDirtyBits()
{
m_LastSendTime = Time.time;
m_SyncVarDirtyBits = 0;
}
internal int GetDirtyChannel()
{
if (Time.time - m_LastSendTime > GetNetworkSendInterval())
{
if (m_SyncVarDirtyBits != 0)
{
return GetNetworkChannel();
}
}
return -1;
}
public virtual bool OnSerialize(NetworkWriter writer, bool initialState)
{
if (!initialState)
{
writer.WritePackedUInt32(0);
}
return false;
}
public virtual void OnDeserialize(NetworkReader reader, bool initialState)
{
if (!initialState)
{
reader.ReadPackedUInt32();
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual void PreStartClient()
{
}
public virtual void OnNetworkDestroy()
{
}
public virtual void OnStartServer()
{
}
public virtual void OnStartClient()
{
}
public virtual void OnStartLocalPlayer()
{
}
public virtual void OnStartAuthority()
{
}
public virtual void OnStopAuthority()
{
}
public virtual bool OnRebuildObservers(HashSet<NetworkConnection> observers, bool initialize)
{
return false;
}
public virtual void OnSetLocalVisibility(bool vis)
{
}
public virtual bool OnCheckObserver(NetworkConnection conn)
{
return true;
}
public virtual int GetNetworkChannel()
{
return Channels.DefaultReliable;
}
public virtual float GetNetworkSendInterval()
{
return k_DefaultSendInterval;
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,248 @@
#if ENABLE_UNET
using System;
using System.Runtime.InteropServices;
namespace UnityEngine.Networking
{
// A growable buffer class used by NetworkReader and NetworkWriter.
// this is used instead of MemoryStream and BinaryReader/BinaryWriter to avoid allocations.
class NetBuffer
{
byte[] m_Buffer;
uint m_Pos;
const int k_InitialSize = 64;
const float k_GrowthFactor = 1.5f;
const int k_BufferSizeWarning = 1024 * 1024 * 128;
public uint Position { get { return m_Pos; } }
public int Length { get { return m_Buffer.Length; } }
public NetBuffer()
{
m_Buffer = new byte[k_InitialSize];
}
// this does NOT copy the buffer
public NetBuffer(byte[] buffer)
{
m_Buffer = buffer;
}
public byte ReadByte()
{
if (m_Pos >= m_Buffer.Length)
{
throw new IndexOutOfRangeException("NetworkReader:ReadByte out of range:" + ToString());
}
return m_Buffer[m_Pos++];
}
public void ReadBytes(byte[] buffer, uint count)
{
if (m_Pos + count > m_Buffer.Length)
{
throw new IndexOutOfRangeException("NetworkReader:ReadBytes out of range: (" + count + ") " + ToString());
}
for (ushort i = 0; i < count; i++)
{
buffer[i] = m_Buffer[m_Pos + i];
}
m_Pos += count;
}
internal ArraySegment<byte> AsArraySegment()
{
return new ArraySegment<byte>(m_Buffer, 0, (int)m_Pos);
}
public void WriteByte(byte value)
{
WriteCheckForSpace(1);
m_Buffer[m_Pos] = value;
m_Pos += 1;
}
public void WriteByte2(byte value0, byte value1)
{
WriteCheckForSpace(2);
m_Buffer[m_Pos] = value0;
m_Buffer[m_Pos + 1] = value1;
m_Pos += 2;
}
public void WriteByte4(byte value0, byte value1, byte value2, byte value3)
{
WriteCheckForSpace(4);
m_Buffer[m_Pos] = value0;
m_Buffer[m_Pos + 1] = value1;
m_Buffer[m_Pos + 2] = value2;
m_Buffer[m_Pos + 3] = value3;
m_Pos += 4;
}
public void WriteByte8(byte value0, byte value1, byte value2, byte value3, byte value4, byte value5, byte value6, byte value7)
{
WriteCheckForSpace(8);
m_Buffer[m_Pos] = value0;
m_Buffer[m_Pos + 1] = value1;
m_Buffer[m_Pos + 2] = value2;
m_Buffer[m_Pos + 3] = value3;
m_Buffer[m_Pos + 4] = value4;
m_Buffer[m_Pos + 5] = value5;
m_Buffer[m_Pos + 6] = value6;
m_Buffer[m_Pos + 7] = value7;
m_Pos += 8;
}
// every other Write() function in this class writes implicitly at the end-marker m_Pos.
// this is the only Write() function that writes to a specific location within the buffer
public void WriteBytesAtOffset(byte[] buffer, ushort targetOffset, ushort count)
{
uint newEnd = (uint)(count + targetOffset);
WriteCheckForSpace((ushort)newEnd);
if (targetOffset == 0 && count == buffer.Length)
{
buffer.CopyTo(m_Buffer, (int)m_Pos);
}
else
{
//CopyTo doesnt take a count :(
for (int i = 0; i < count; i++)
{
m_Buffer[targetOffset + i] = buffer[i];
}
}
// although this writes within the buffer, it could move the end-marker
if (newEnd > m_Pos)
{
m_Pos = newEnd;
}
}
public void WriteBytes(byte[] buffer, ushort count)
{
WriteCheckForSpace(count);
if (count == buffer.Length)
{
buffer.CopyTo(m_Buffer, (int)m_Pos);
}
else
{
//CopyTo doesnt take a count :(
for (int i = 0; i < count; i++)
{
m_Buffer[m_Pos + i] = buffer[i];
}
}
m_Pos += count;
}
void WriteCheckForSpace(ushort count)
{
if (m_Pos + count < m_Buffer.Length)
return;
int newLen = (int)Math.Ceiling(m_Buffer.Length * k_GrowthFactor);
while (m_Pos + count >= newLen)
{
newLen = (int)Math.Ceiling(newLen * k_GrowthFactor);
if (newLen > k_BufferSizeWarning)
{
Debug.LogWarning("NetworkBuffer size is " + newLen + " bytes!");
}
}
// only do the copy once, even if newLen is increased multiple times
byte[] tmp = new byte[newLen];
m_Buffer.CopyTo(tmp, 0);
m_Buffer = tmp;
}
public void FinishMessage()
{
// two shorts (size and msgType) are in header.
ushort sz = (ushort)(m_Pos - (sizeof(ushort) * 2));
m_Buffer[0] = (byte)(sz & 0xff);
m_Buffer[1] = (byte)((sz >> 8) & 0xff);
}
public void SeekZero()
{
m_Pos = 0;
}
public void Replace(byte[] buffer)
{
m_Buffer = buffer;
m_Pos = 0;
}
public override string ToString()
{
return String.Format("NetBuf sz:{0} pos:{1}", m_Buffer.Length, m_Pos);
}
} // end NetBuffer
// -- helpers for float conversion --
[StructLayout(LayoutKind.Explicit)]
internal struct UIntFloat
{
[FieldOffset(0)]
public float floatValue;
[FieldOffset(0)]
public uint intValue;
[FieldOffset(0)]
public double doubleValue;
[FieldOffset(0)]
public ulong longValue;
}
[StructLayout(LayoutKind.Explicit)]
internal struct UIntDecimal
{
[FieldOffset(0)]
public ulong longValue1;
[FieldOffset(8)]
public ulong longValue2;
[FieldOffset(0)]
public decimal decimalValue;
}
internal class FloatConversion
{
public static float ToSingle(uint value)
{
UIntFloat uf = new UIntFloat();
uf.intValue = value;
return uf.floatValue;
}
public static double ToDouble(ulong value)
{
UIntFloat uf = new UIntFloat();
uf.longValue = value;
return uf.doubleValue;
}
public static decimal ToDecimal(ulong value1, ulong value2)
{
UIntDecimal uf = new UIntDecimal();
uf.longValue1 = value1;
uf.longValue2 = value2;
return uf.decimalValue;
}
}
}
#endif

View File

@ -0,0 +1,121 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine.Networking.NetworkSystem;
namespace UnityEngine.Networking
{
public class NetworkCRC
{
internal static NetworkCRC s_Singleton;
Dictionary<string, int> m_Scripts = new Dictionary<string, int>();
bool m_ScriptCRCCheck;
static internal NetworkCRC singleton
{
get
{
if (s_Singleton == null)
{
s_Singleton = new NetworkCRC();
}
return s_Singleton;
}
}
public Dictionary<string, int> scripts { get { return m_Scripts; } }
static public bool scriptCRCCheck
{
get
{
return singleton.m_ScriptCRCCheck;
}
set
{
singleton.m_ScriptCRCCheck = value;
}
}
// The NetworkCRC cache contain entries from
static public void ReinitializeScriptCRCs(Assembly callingAssembly)
{
singleton.m_Scripts.Clear();
var types = callingAssembly.GetTypes();
for (int i = 0; i < types.Length; i++)
{
var t = types[i];
if (t.GetBaseType() == typeof(NetworkBehaviour))
{
var cctor = t.GetMethod(".cctor", BindingFlags.Static);
if (cctor != null)
{
cctor.Invoke(null, new object[] {});
}
}
}
}
static public void RegisterBehaviour(string name, int channel)
{
singleton.m_Scripts[name] = channel;
}
internal static bool Validate(CRCMessageEntry[] scripts, int numChannels)
{
return singleton.ValidateInternal(scripts, numChannels);
}
bool ValidateInternal(CRCMessageEntry[] remoteScripts, int numChannels)
{
// check count against my channels
if (m_Scripts.Count != remoteScripts.Length)
{
if (LogFilter.logWarn) { Debug.LogWarning("Network configuration mismatch detected. The number of networked scripts on the client does not match the number of networked scripts on the server. This could be caused by lazy loading of scripts on the client. This warning can be disabled by the checkbox in NetworkManager Script CRC Check."); }
Dump(remoteScripts);
return false;
}
// check each script
for (int i = 0; i < remoteScripts.Length; i++)
{
var script = remoteScripts[i];
if (LogFilter.logDebug) { Debug.Log("Script: " + script.name + " Channel: " + script.channel); }
if (m_Scripts.ContainsKey(script.name))
{
int localChannel = m_Scripts[script.name];
if (localChannel != script.channel)
{
if (LogFilter.logError) { Debug.LogError("HLAPI CRC Channel Mismatch. Script: " + script.name + " LocalChannel: " + localChannel + " RemoteChannel: " + script.channel); }
Dump(remoteScripts);
return false;
}
}
if (script.channel >= numChannels)
{
if (LogFilter.logError) { Debug.LogError("HLAPI CRC channel out of range! Script: " + script.name + " Channel: " + script.channel); }
Dump(remoteScripts);
return false;
}
}
return true;
}
void Dump(CRCMessageEntry[] remoteScripts)
{
foreach (var script in m_Scripts.Keys)
{
Debug.Log("CRC Local Dump " + script + " : " + m_Scripts[script]);
}
foreach (var remote in remoteScripts)
{
Debug.Log("CRC Remote Dump " + remote.name + " : " + remote.channel);
}
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,999 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using UnityEngine.Networking.Match;
using UnityEngine.Networking.NetworkSystem;
namespace UnityEngine.Networking
{
public class NetworkClient
{
Type m_NetworkConnectionClass = typeof(NetworkConnection);
const int k_MaxEventsPerFrame = 500;
static List<NetworkClient> s_Clients = new List<NetworkClient>();
static bool s_IsActive;
public static List<NetworkClient> allClients { get { return s_Clients; } }
public static bool active { get { return s_IsActive; } }
HostTopology m_HostTopology;
int m_HostPort;
bool m_UseSimulator;
int m_SimulatedLatency;
float m_PacketLoss;
string m_ServerIp = "";
int m_ServerPort;
int m_ClientId = -1;
int m_ClientConnectionId = -1;
//int m_RelaySlotId = -1;
int m_StatResetTime;
EndPoint m_RemoteEndPoint;
// static message objects to avoid runtime-allocations
static CRCMessage s_CRCMessage = new CRCMessage();
NetworkMessageHandlers m_MessageHandlers = new NetworkMessageHandlers();
protected NetworkConnection m_Connection;
byte[] m_MsgBuffer;
NetworkReader m_MsgReader;
protected enum ConnectState
{
None,
Resolving,
Resolved,
Connecting,
Connected,
Disconnected,
Failed
}
protected ConnectState m_AsyncConnect = ConnectState.None;
string m_RequestedServerHost = "";
internal void SetHandlers(NetworkConnection conn)
{
conn.SetHandlers(m_MessageHandlers);
}
public string serverIp { get { return m_ServerIp; } }
public int serverPort { get { return m_ServerPort; } }
public NetworkConnection connection { get { return m_Connection; } }
#if ENABLE_UNET_HOST_MIGRATION
[Obsolete("Moved to NetworkMigrationManager.")]
#else
[Obsolete("Removed")]
#endif
public PeerInfoMessage[] peers { get { return null; } }
internal int hostId { get { return m_ClientId; } }
public Dictionary<short, NetworkMessageDelegate> handlers { get { return m_MessageHandlers.GetHandlers(); } }
public int numChannels { get { return m_HostTopology.DefaultConfig.ChannelCount; } }
public HostTopology hostTopology { get { return m_HostTopology; }}
public int hostPort
{
get { return m_HostPort; }
set
{
if (value < 0)
throw new ArgumentException("Port must not be a negative number.");
if (value > 65535)
throw new ArgumentException("Port must not be greater than 65535.");
m_HostPort = value;
}
}
public bool isConnected { get { return m_AsyncConnect == ConnectState.Connected; }}
public Type networkConnectionClass
{
get { return m_NetworkConnectionClass; }
}
public void SetNetworkConnectionClass<T>() where T : NetworkConnection
{
m_NetworkConnectionClass = typeof(T);
}
public NetworkClient()
{
if (LogFilter.logDev) { Debug.Log("Client created version " + Version.Current); }
m_MsgBuffer = new byte[NetworkMessage.MaxMessageSize];
m_MsgReader = new NetworkReader(m_MsgBuffer);
AddClient(this);
}
public NetworkClient(NetworkConnection conn)
{
if (LogFilter.logDev) { Debug.Log("Client created version " + Version.Current); }
m_MsgBuffer = new byte[NetworkMessage.MaxMessageSize];
m_MsgReader = new NetworkReader(m_MsgBuffer);
AddClient(this);
SetActive(true);
m_Connection = conn;
m_AsyncConnect = ConnectState.Connected;
conn.SetHandlers(m_MessageHandlers);
RegisterSystemHandlers(false);
}
public bool Configure(ConnectionConfig config, int maxConnections)
{
HostTopology top = new HostTopology(config, maxConnections);
return Configure(top);
}
public bool Configure(HostTopology topology)
{
//NOTE: this maxConnections is across all clients that use this tuner, so it is
// effectively the number of _clients_.
m_HostTopology = topology;
return true;
}
public void Connect(MatchInfo matchInfo)
{
PrepareForConnect();
ConnectWithRelay(matchInfo);
}
#if ENABLE_UNET_HOST_MIGRATION
public bool ReconnectToNewHost(string serverIp, int serverPort)
{
if (!NetworkClient.active)
{
if (LogFilter.logError) { Debug.LogError("Reconnect - NetworkClient must be active"); }
return false;
}
if (m_Connection == null)
{
if (LogFilter.logError) { Debug.LogError("Reconnect - no old connection exists"); }
return false;
}
if (LogFilter.logInfo) { Debug.Log("NetworkClient Reconnect " + serverIp + ":" + serverPort); }
ClientScene.HandleClientDisconnect(m_Connection);
ClientScene.ClearLocalPlayers();
m_Connection.Disconnect();
m_Connection = null;
m_ClientId = NetworkTransport.AddHost(m_HostTopology, m_HostPort);
string hostnameOrIp = serverIp;
m_ServerPort = serverPort;
//TODO: relay reconnect
/*
if (Match.NetworkMatch.matchSingleton != null)
{
hostnameOrIp = Match.NetworkMatch.matchSingleton.address;
m_ServerPort = Match.NetworkMatch.matchSingleton.port;
}*/
if (UnityEngine.Application.platform == RuntimePlatform.WebGLPlayer)
{
m_ServerIp = hostnameOrIp;
m_AsyncConnect = ConnectState.Resolved;
}
else if (serverIp.Equals("127.0.0.1") || serverIp.Equals("localhost"))
{
m_ServerIp = "127.0.0.1";
m_AsyncConnect = ConnectState.Resolved;
}
else
{
if (LogFilter.logDebug) { Debug.Log("Async DNS START:" + hostnameOrIp); }
m_AsyncConnect = ConnectState.Resolving;
Dns.BeginGetHostAddresses(hostnameOrIp, new AsyncCallback(GetHostAddressesCallback), this);
}
return true;
}
public bool ReconnectToNewHost(EndPoint secureTunnelEndPoint)
{
if (!NetworkClient.active)
{
if (LogFilter.logError) { Debug.LogError("Reconnect - NetworkClient must be active"); }
return false;
}
if (m_Connection == null)
{
if (LogFilter.logError) { Debug.LogError("Reconnect - no old connection exists"); }
return false;
}
if (LogFilter.logInfo) { Debug.Log("NetworkClient Reconnect to remoteSockAddr"); }
ClientScene.HandleClientDisconnect(m_Connection);
ClientScene.ClearLocalPlayers();
m_Connection.Disconnect();
m_Connection = null;
m_ClientId = NetworkTransport.AddHost(m_HostTopology, m_HostPort);
if (secureTunnelEndPoint == null)
{
if (LogFilter.logError) { Debug.LogError("Reconnect failed: null endpoint passed in"); }
m_AsyncConnect = ConnectState.Failed;
return false;
}
// Make sure it's either IPv4 or IPv6
if (secureTunnelEndPoint.AddressFamily != AddressFamily.InterNetwork && secureTunnelEndPoint.AddressFamily != AddressFamily.InterNetworkV6)
{
if (LogFilter.logError) { Debug.LogError("Reconnect failed: Endpoint AddressFamily must be either InterNetwork or InterNetworkV6"); }
m_AsyncConnect = ConnectState.Failed;
return false;
}
// Make sure it's an Endpoint we know what to do with
string endPointType = secureTunnelEndPoint.GetType().FullName;
if (endPointType == "System.Net.IPEndPoint")
{
IPEndPoint tmp = (IPEndPoint)secureTunnelEndPoint;
Connect(tmp.Address.ToString(), tmp.Port);
return m_AsyncConnect != ConnectState.Failed;
}
if ((endPointType != "UnityEngine.XboxOne.XboxOneEndPoint") && (endPointType != "UnityEngine.PS4.SceEndPoint"))
{
if (LogFilter.logError) { Debug.LogError("Reconnect failed: invalid Endpoint (not IPEndPoint or XboxOneEndPoint or SceEndPoint)"); }
m_AsyncConnect = ConnectState.Failed;
return false;
}
byte error = 0;
// regular non-relay connect
m_RemoteEndPoint = secureTunnelEndPoint;
m_AsyncConnect = ConnectState.Connecting;
try
{
m_ClientConnectionId = NetworkTransport.ConnectEndPoint(m_ClientId, m_RemoteEndPoint, 0, out error);
}
catch (Exception ex)
{
if (LogFilter.logError) { Debug.LogError("Reconnect failed: Exception when trying to connect to EndPoint: " + ex); }
m_AsyncConnect = ConnectState.Failed;
return false;
}
if (m_ClientConnectionId == 0)
{
if (LogFilter.logError) { Debug.LogError("Reconnect failed: Unable to connect to EndPoint (" + error + ")"); }
m_AsyncConnect = ConnectState.Failed;
return false;
}
m_Connection = (NetworkConnection)Activator.CreateInstance(m_NetworkConnectionClass);
m_Connection.SetHandlers(m_MessageHandlers);
m_Connection.Initialize(m_ServerIp, m_ClientId, m_ClientConnectionId, m_HostTopology);
return true;
}
#endif
public void ConnectWithSimulator(string serverIp, int serverPort, int latency, float packetLoss)
{
m_UseSimulator = true;
m_SimulatedLatency = latency;
m_PacketLoss = packetLoss;
Connect(serverIp, serverPort);
}
static bool IsValidIpV6(string address)
{
for (int i = 0; i < address.Length; i++)
{
var c = address[i];
if (
(c == ':') ||
(c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F')
)
{
continue;
}
return false;
}
return true;
}
public void Connect(string serverIp, int serverPort)
{
PrepareForConnect();
if (LogFilter.logDebug) { Debug.Log("Client Connect: " + serverIp + ":" + serverPort); }
string hostnameOrIp = serverIp;
m_ServerPort = serverPort;
if (UnityEngine.Application.platform == RuntimePlatform.WebGLPlayer)
{
m_ServerIp = hostnameOrIp;
m_AsyncConnect = ConnectState.Resolved;
}
else if (serverIp.Equals("127.0.0.1") || serverIp.Equals("localhost"))
{
m_ServerIp = "127.0.0.1";
m_AsyncConnect = ConnectState.Resolved;
}
else if (serverIp.IndexOf(":") != -1 && IsValidIpV6(serverIp))
{
m_ServerIp = serverIp;
m_AsyncConnect = ConnectState.Resolved;
}
else
{
if (LogFilter.logDebug) { Debug.Log("Async DNS START:" + hostnameOrIp); }
m_RequestedServerHost = hostnameOrIp;
m_AsyncConnect = ConnectState.Resolving;
Dns.BeginGetHostAddresses(hostnameOrIp, GetHostAddressesCallback, this);
}
}
public void Connect(EndPoint secureTunnelEndPoint)
{
bool usePlatformSpecificProtocols = NetworkTransport.DoesEndPointUsePlatformProtocols(secureTunnelEndPoint);
PrepareForConnect(usePlatformSpecificProtocols);
if (LogFilter.logDebug) { Debug.Log("Client Connect to remoteSockAddr"); }
if (secureTunnelEndPoint == null)
{
if (LogFilter.logError) { Debug.LogError("Connect failed: null endpoint passed in"); }
m_AsyncConnect = ConnectState.Failed;
return;
}
// Make sure it's either IPv4 or IPv6
if (secureTunnelEndPoint.AddressFamily != AddressFamily.InterNetwork && secureTunnelEndPoint.AddressFamily != AddressFamily.InterNetworkV6)
{
if (LogFilter.logError) { Debug.LogError("Connect failed: Endpoint AddressFamily must be either InterNetwork or InterNetworkV6"); }
m_AsyncConnect = ConnectState.Failed;
return;
}
// Make sure it's an Endpoint we know what to do with
string endPointType = secureTunnelEndPoint.GetType().FullName;
if (endPointType == "System.Net.IPEndPoint")
{
IPEndPoint tmp = (IPEndPoint)secureTunnelEndPoint;
Connect(tmp.Address.ToString(), tmp.Port);
return;
}
if ((endPointType != "UnityEngine.XboxOne.XboxOneEndPoint") && (endPointType != "UnityEngine.PS4.SceEndPoint") && (endPointType != "UnityEngine.PSVita.SceEndPoint"))
{
if (LogFilter.logError) { Debug.LogError("Connect failed: invalid Endpoint (not IPEndPoint or XboxOneEndPoint or SceEndPoint)"); }
m_AsyncConnect = ConnectState.Failed;
return;
}
byte error = 0;
// regular non-relay connect
m_RemoteEndPoint = secureTunnelEndPoint;
m_AsyncConnect = ConnectState.Connecting;
try
{
m_ClientConnectionId = NetworkTransport.ConnectEndPoint(m_ClientId, m_RemoteEndPoint, 0, out error);
}
catch (Exception ex)
{
if (LogFilter.logError) { Debug.LogError("Connect failed: Exception when trying to connect to EndPoint: " + ex); }
m_AsyncConnect = ConnectState.Failed;
return;
}
if (m_ClientConnectionId == 0)
{
if (LogFilter.logError) { Debug.LogError("Connect failed: Unable to connect to EndPoint (" + error + ")"); }
m_AsyncConnect = ConnectState.Failed;
return;
}
m_Connection = (NetworkConnection)Activator.CreateInstance(m_NetworkConnectionClass);
m_Connection.SetHandlers(m_MessageHandlers);
m_Connection.Initialize(m_ServerIp, m_ClientId, m_ClientConnectionId, m_HostTopology);
}
void PrepareForConnect()
{
PrepareForConnect(false);
}
void PrepareForConnect(bool usePlatformSpecificProtocols)
{
SetActive(true);
RegisterSystemHandlers(false);
if (m_HostTopology == null)
{
var config = new ConnectionConfig();
config.AddChannel(QosType.ReliableSequenced);
config.AddChannel(QosType.Unreliable);
config.UsePlatformSpecificProtocols = usePlatformSpecificProtocols;
m_HostTopology = new HostTopology(config, 8);
}
if (m_UseSimulator)
{
int minTimeout = (m_SimulatedLatency / 3) - 1;
if (minTimeout < 1)
{
minTimeout = 1;
}
int maxTimeout = m_SimulatedLatency * 3;
if (LogFilter.logDebug) { Debug.Log("AddHost Using Simulator " + minTimeout + "/" + maxTimeout); }
m_ClientId = NetworkTransport.AddHostWithSimulator(m_HostTopology, minTimeout, maxTimeout, m_HostPort);
}
else
{
m_ClientId = NetworkTransport.AddHost(m_HostTopology, m_HostPort);
}
}
// this called in another thread! Cannot call Update() here.
internal static void GetHostAddressesCallback(IAsyncResult ar)
{
try
{
IPAddress[] ip = Dns.EndGetHostAddresses(ar);
NetworkClient client = (NetworkClient)ar.AsyncState;
if (ip.Length == 0)
{
if (LogFilter.logError) { Debug.LogError("DNS lookup failed for:" + client.m_RequestedServerHost); }
client.m_AsyncConnect = ConnectState.Failed;
return;
}
client.m_ServerIp = ip[0].ToString();
client.m_AsyncConnect = ConnectState.Resolved;
if (LogFilter.logDebug) { Debug.Log("Async DNS Result:" + client.m_ServerIp + " for " + client.m_RequestedServerHost + ": " + client.m_ServerIp); }
}
catch (SocketException e)
{
NetworkClient client = (NetworkClient)ar.AsyncState;
if (LogFilter.logError) { Debug.LogError("DNS resolution failed: " + e.GetErrorCode()); }
if (LogFilter.logDebug) { Debug.Log("Exception:" + e); }
client.m_AsyncConnect = ConnectState.Failed;
}
}
internal void ContinueConnect()
{
byte error;
// regular non-relay connect
if (m_UseSimulator)
{
int simLatency = m_SimulatedLatency / 3;
if (simLatency < 1)
{
simLatency = 1;
}
if (LogFilter.logDebug) { Debug.Log("Connect Using Simulator " + (m_SimulatedLatency / 3) + "/" + m_SimulatedLatency); }
var simConfig = new ConnectionSimulatorConfig(
simLatency,
m_SimulatedLatency,
simLatency,
m_SimulatedLatency,
m_PacketLoss);
m_ClientConnectionId = NetworkTransport.ConnectWithSimulator(m_ClientId, m_ServerIp, m_ServerPort, 0, out error, simConfig);
}
else
{
m_ClientConnectionId = NetworkTransport.Connect(m_ClientId, m_ServerIp, m_ServerPort, 0, out error);
}
m_Connection = (NetworkConnection)Activator.CreateInstance(m_NetworkConnectionClass);
m_Connection.SetHandlers(m_MessageHandlers);
m_Connection.Initialize(m_ServerIp, m_ClientId, m_ClientConnectionId, m_HostTopology);
}
void ConnectWithRelay(MatchInfo info)
{
m_AsyncConnect = ConnectState.Connecting;
Update();
byte error;
m_ClientConnectionId = NetworkTransport.ConnectToNetworkPeer(
m_ClientId,
info.address,
info.port,
0,
0,
info.networkId,
Utility.GetSourceID(),
info.nodeId,
out error);
m_Connection = (NetworkConnection)Activator.CreateInstance(m_NetworkConnectionClass);
m_Connection.SetHandlers(m_MessageHandlers);
m_Connection.Initialize(info.address, m_ClientId, m_ClientConnectionId, m_HostTopology);
if (error != 0) { Debug.LogError("ConnectToNetworkPeer Error: " + error); }
}
public virtual void Disconnect()
{
m_AsyncConnect = ConnectState.Disconnected;
ClientScene.HandleClientDisconnect(m_Connection);
if (m_Connection != null)
{
m_Connection.Disconnect();
m_Connection.Dispose();
m_Connection = null;
if (m_ClientId != -1)
{
NetworkTransport.RemoveHost(m_ClientId);
m_ClientId = -1;
}
}
}
public bool Send(short msgType, MessageBase msg)
{
if (m_Connection != null)
{
if (m_AsyncConnect != ConnectState.Connected)
{
if (LogFilter.logError) { Debug.LogError("NetworkClient Send when not connected to a server"); }
return false;
}
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.UserMessage, msgType.ToString() + ":" + msg.GetType().Name, 1);
#endif
return m_Connection.Send(msgType, msg);
}
if (LogFilter.logError) { Debug.LogError("NetworkClient Send with no connection"); }
return false;
}
public bool SendWriter(NetworkWriter writer, int channelId)
{
if (m_Connection != null)
{
if (m_AsyncConnect != ConnectState.Connected)
{
if (LogFilter.logError) { Debug.LogError("NetworkClient SendWriter when not connected to a server"); }
return false;
}
return m_Connection.SendWriter(writer, channelId);
}
if (LogFilter.logError) { Debug.LogError("NetworkClient SendWriter with no connection"); }
return false;
}
public bool SendBytes(byte[] data, int numBytes, int channelId)
{
if (m_Connection != null)
{
if (m_AsyncConnect != ConnectState.Connected)
{
if (LogFilter.logError) { Debug.LogError("NetworkClient SendBytes when not connected to a server"); }
return false;
}
return m_Connection.SendBytes(data, numBytes, channelId);
}
if (LogFilter.logError) { Debug.LogError("NetworkClient SendBytes with no connection"); }
return false;
}
public bool SendUnreliable(short msgType, MessageBase msg)
{
if (m_Connection != null)
{
if (m_AsyncConnect != ConnectState.Connected)
{
if (LogFilter.logError) { Debug.LogError("NetworkClient SendUnreliable when not connected to a server"); }
return false;
}
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.UserMessage, msgType.ToString() + ":" + msg.GetType().Name, 1);
#endif
return m_Connection.SendUnreliable(msgType, msg);
}
if (LogFilter.logError) { Debug.LogError("NetworkClient SendUnreliable with no connection"); }
return false;
}
public bool SendByChannel(short msgType, MessageBase msg, int channelId)
{
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.UserMessage, msgType.ToString() + ":" + msg.GetType().Name, 1);
#endif
if (m_Connection != null)
{
if (m_AsyncConnect != ConnectState.Connected)
{
if (LogFilter.logError) { Debug.LogError("NetworkClient SendByChannel when not connected to a server"); }
return false;
}
return m_Connection.SendByChannel(msgType, msg, channelId);
}
if (LogFilter.logError) { Debug.LogError("NetworkClient SendByChannel with no connection"); }
return false;
}
public void SetMaxDelay(float seconds)
{
if (m_Connection == null)
{
if (LogFilter.logWarn) { Debug.LogWarning("SetMaxDelay failed, not connected."); }
return;
}
m_Connection.SetMaxDelay(seconds);
}
public void Shutdown()
{
if (LogFilter.logDebug) Debug.Log("Shutting down client " + m_ClientId);
if (m_ClientId != -1)
{
NetworkTransport.RemoveHost(m_ClientId);
m_ClientId = -1;
}
RemoveClient(this);
if (s_Clients.Count == 0)
{
SetActive(false);
}
}
internal virtual void Update()
{
if (m_ClientId == -1)
{
return;
}
switch (m_AsyncConnect)
{
case ConnectState.None:
case ConnectState.Resolving:
case ConnectState.Disconnected:
return;
case ConnectState.Failed:
GenerateConnectError((int)NetworkError.DNSFailure);
m_AsyncConnect = ConnectState.Disconnected;
return;
case ConnectState.Resolved:
m_AsyncConnect = ConnectState.Connecting;
ContinueConnect();
return;
case ConnectState.Connecting:
case ConnectState.Connected:
{
break;
}
}
if (m_Connection != null)
{
if ((int)Time.time != m_StatResetTime)
{
m_Connection.ResetStats();
m_StatResetTime = (int)Time.time;
}
}
int numEvents = 0;
NetworkEventType networkEvent;
do
{
int connectionId;
int channelId;
int receivedSize;
byte error;
networkEvent = NetworkTransport.ReceiveFromHost(m_ClientId, out connectionId, out channelId, m_MsgBuffer, (ushort)m_MsgBuffer.Length, out receivedSize, out error);
if (m_Connection != null) m_Connection.lastError = (NetworkError)error;
if (networkEvent != NetworkEventType.Nothing)
{
if (LogFilter.logDev) { Debug.Log("Client event: host=" + m_ClientId + " event=" + networkEvent + " error=" + error); }
}
switch (networkEvent)
{
case NetworkEventType.ConnectEvent:
if (LogFilter.logDebug) { Debug.Log("Client connected"); }
if (error != 0)
{
GenerateConnectError(error);
return;
}
m_AsyncConnect = ConnectState.Connected;
m_Connection.InvokeHandlerNoData(MsgType.Connect);
break;
case NetworkEventType.DataEvent:
if (error != 0)
{
GenerateDataError(error);
return;
}
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Incoming,
MsgType.LLAPIMsg, "msg", 1);
#endif
m_MsgReader.SeekZero();
m_Connection.TransportReceive(m_MsgBuffer, receivedSize, channelId);
break;
case NetworkEventType.DisconnectEvent:
if (LogFilter.logDebug) { Debug.Log("Client disconnected"); }
m_AsyncConnect = ConnectState.Disconnected;
if (error != 0)
{
if ((NetworkError)error != NetworkError.Timeout)
{
GenerateDisconnectError(error);
}
}
ClientScene.HandleClientDisconnect(m_Connection);
if (m_Connection != null)
{
m_Connection.InvokeHandlerNoData(MsgType.Disconnect);
}
break;
case NetworkEventType.Nothing:
break;
default:
if (LogFilter.logError) { Debug.LogError("Unknown network message type received: " + networkEvent); }
break;
}
if (++numEvents >= k_MaxEventsPerFrame)
{
if (LogFilter.logDebug) { Debug.Log("MaxEventsPerFrame hit (" + k_MaxEventsPerFrame + ")"); }
break;
}
if (m_ClientId == -1)
{
break;
}
}
while (networkEvent != NetworkEventType.Nothing);
if (m_Connection != null && m_AsyncConnect == ConnectState.Connected)
m_Connection.FlushChannels();
}
void GenerateConnectError(int error)
{
if (LogFilter.logError) { Debug.LogError("UNet Client Error Connect Error: " + error); }
GenerateError(error);
}
void GenerateDataError(int error)
{
NetworkError dataError = (NetworkError)error;
if (LogFilter.logError) { Debug.LogError("UNet Client Data Error: " + dataError); }
GenerateError(error);
}
void GenerateDisconnectError(int error)
{
NetworkError disconnectError = (NetworkError)error;
if (LogFilter.logError) { Debug.LogError("UNet Client Disconnect Error: " + disconnectError); }
GenerateError(error);
}
void GenerateError(int error)
{
NetworkMessageDelegate msgDelegate = m_MessageHandlers.GetHandler(MsgType.Error);
if (msgDelegate == null)
{
msgDelegate = m_MessageHandlers.GetHandler(MsgType.Error);
}
if (msgDelegate != null)
{
ErrorMessage msg = new ErrorMessage();
msg.errorCode = error;
// write the message to a local buffer
byte[] errorBuffer = new byte[200];
NetworkWriter writer = new NetworkWriter(errorBuffer);
msg.Serialize(writer);
// pass a reader (attached to local buffer) to handler
NetworkReader reader = new NetworkReader(errorBuffer);
NetworkMessage netMsg = new NetworkMessage();
netMsg.msgType = MsgType.Error;
netMsg.reader = reader;
netMsg.conn = m_Connection;
netMsg.channelId = 0;
msgDelegate(netMsg);
}
}
public void GetStatsOut(out int numMsgs, out int numBufferedMsgs, out int numBytes, out int lastBufferedPerSecond)
{
numMsgs = 0;
numBufferedMsgs = 0;
numBytes = 0;
lastBufferedPerSecond = 0;
if (m_Connection != null)
{
m_Connection.GetStatsOut(out numMsgs, out numBufferedMsgs, out numBytes, out lastBufferedPerSecond);
}
}
public void GetStatsIn(out int numMsgs, out int numBytes)
{
numMsgs = 0;
numBytes = 0;
if (m_Connection != null)
{
m_Connection.GetStatsIn(out numMsgs, out numBytes);
}
}
public Dictionary<short, NetworkConnection.PacketStat> GetConnectionStats()
{
if (m_Connection == null)
return null;
return m_Connection.packetStats;
}
public void ResetConnectionStats()
{
if (m_Connection == null)
return;
m_Connection.ResetStats();
}
public int GetRTT()
{
if (m_ClientId == -1)
return 0;
byte err;
return NetworkTransport.GetCurrentRTT(m_ClientId, m_ClientConnectionId, out err);
}
internal void RegisterSystemHandlers(bool localClient)
{
ClientScene.RegisterSystemHandlers(this, localClient);
RegisterHandlerSafe(MsgType.CRC, OnCRC);
RegisterHandlerSafe(MsgType.Fragment, NetworkConnection.OnFragment);
}
void OnCRC(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_CRCMessage);
NetworkCRC.Validate(s_CRCMessage.scripts, numChannels);
}
public void RegisterHandler(short msgType, NetworkMessageDelegate handler)
{
m_MessageHandlers.RegisterHandler(msgType, handler);
}
public void RegisterHandlerSafe(short msgType, NetworkMessageDelegate handler)
{
m_MessageHandlers.RegisterHandlerSafe(msgType, handler);
}
public void UnregisterHandler(short msgType)
{
m_MessageHandlers.UnregisterHandler(msgType);
}
static public Dictionary<short, NetworkConnection.PacketStat> GetTotalConnectionStats()
{
Dictionary<short, NetworkConnection.PacketStat> stats = new Dictionary<short, NetworkConnection.PacketStat>();
for (int i = 0; i < s_Clients.Count; i++)
{
var client = s_Clients[i];
var clientStats = client.GetConnectionStats();
foreach (short k in clientStats.Keys)
{
if (stats.ContainsKey(k))
{
NetworkConnection.PacketStat s = stats[k];
s.count += clientStats[k].count;
s.bytes += clientStats[k].bytes;
stats[k] = s;
}
else
{
stats[k] = new NetworkConnection.PacketStat(clientStats[k]);
}
}
}
return stats;
}
internal static void AddClient(NetworkClient client)
{
s_Clients.Add(client);
}
internal static bool RemoveClient(NetworkClient client)
{
return s_Clients.Remove(client);
}
static internal void UpdateClients()
{
for (int i = 0; i < s_Clients.Count; ++i)
{
if (s_Clients[i] != null)
s_Clients[i].Update();
else
s_Clients.RemoveAt(i);
}
}
static public void ShutdownAll()
{
while (s_Clients.Count != 0)
{
s_Clients[0].Shutdown();
}
s_Clients = new List<NetworkClient>();
s_IsActive = false;
ClientScene.Shutdown();
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.ResetAll();
#endif
}
internal static void SetActive(bool state)
{
// what is this check?
//if (state == false && s_Clients.Count != 0)
// return;
if (!s_IsActive && state)
{
NetworkTransport.Init();
}
s_IsActive = state;
}
};
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,612 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
using System.Text;
namespace UnityEngine.Networking
{
/*
* wire protocol is a list of : size | msgType | payload
* (short) (variable) (buffer)
*/
public class NetworkConnection : IDisposable
{
ChannelBuffer[] m_Channels;
List<PlayerController> m_PlayerControllers = new List<PlayerController>();
NetworkMessage m_NetMsg = new NetworkMessage();
HashSet<NetworkIdentity> m_VisList = new HashSet<NetworkIdentity>();
internal HashSet<NetworkIdentity> visList { get { return m_VisList; } }
NetworkWriter m_Writer;
Dictionary<short, NetworkMessageDelegate> m_MessageHandlersDict;
NetworkMessageHandlers m_MessageHandlers;
HashSet<NetworkInstanceId> m_ClientOwnedObjects;
NetworkMessage m_MessageInfo = new NetworkMessage();
const int k_MaxMessageLogSize = 150;
private NetworkError error;
public int hostId = -1;
public int connectionId = -1;
public bool isReady;
public string address;
public float lastMessageTime;
public List<PlayerController> playerControllers { get { return m_PlayerControllers; } }
public HashSet<NetworkInstanceId> clientOwnedObjects { get { return m_ClientOwnedObjects; } }
public bool logNetworkMessages = false;
public bool isConnected { get { return hostId != -1; }}
public class PacketStat
{
public PacketStat()
{
msgType = 0;
count = 0;
bytes = 0;
}
public PacketStat(PacketStat s)
{
msgType = s.msgType;
count = s.count;
bytes = s.bytes;
}
public short msgType;
public int count;
public int bytes;
public override string ToString()
{
return MsgType.MsgTypeToString(msgType) + ": count=" + count + " bytes=" + bytes;
}
}
public NetworkError lastError { get { return error; } internal set { error = value; } }
Dictionary<short, PacketStat> m_PacketStats = new Dictionary<short, PacketStat>();
internal Dictionary<short, PacketStat> packetStats { get { return m_PacketStats; }}
#if UNITY_EDITOR
static int s_MaxPacketStats = 255;//the same as maximum message types
#endif
public virtual void Initialize(string networkAddress, int networkHostId, int networkConnectionId, HostTopology hostTopology)
{
m_Writer = new NetworkWriter();
address = networkAddress;
hostId = networkHostId;
connectionId = networkConnectionId;
int numChannels = hostTopology.DefaultConfig.ChannelCount;
int packetSize = hostTopology.DefaultConfig.PacketSize;
if ((hostTopology.DefaultConfig.UsePlatformSpecificProtocols) && (UnityEngine.Application.platform != RuntimePlatform.PS4) && (UnityEngine.Application.platform != RuntimePlatform.PSP2))
throw new ArgumentOutOfRangeException("Platform specific protocols are not supported on this platform");
m_Channels = new ChannelBuffer[numChannels];
for (int i = 0; i < numChannels; i++)
{
var qos = hostTopology.DefaultConfig.Channels[i];
int actualPacketSize = packetSize;
if (qos.QOS == QosType.ReliableFragmented || qos.QOS == QosType.UnreliableFragmented)
{
actualPacketSize = hostTopology.DefaultConfig.FragmentSize * 128;
}
m_Channels[i] = new ChannelBuffer(this, actualPacketSize, (byte)i, IsReliableQoS(qos.QOS), IsSequencedQoS(qos.QOS));
}
}
// Track whether Dispose has been called.
bool m_Disposed;
~NetworkConnection()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
// Take yourself off the Finalization queue
// to prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!m_Disposed && m_Channels != null)
{
for (int i = 0; i < m_Channels.Length; i++)
{
m_Channels[i].Dispose();
}
}
m_Channels = null;
if (m_ClientOwnedObjects != null)
{
foreach (var netId in m_ClientOwnedObjects)
{
var obj = NetworkServer.FindLocalObject(netId);
if (obj != null)
{
obj.GetComponent<NetworkIdentity>().ClearClientOwner();
}
}
}
m_ClientOwnedObjects = null;
m_Disposed = true;
}
static bool IsSequencedQoS(QosType qos)
{
return (qos == QosType.ReliableSequenced || qos == QosType.UnreliableSequenced);
}
static bool IsReliableQoS(QosType qos)
{
return (qos == QosType.Reliable || qos == QosType.ReliableFragmented || qos == QosType.ReliableSequenced || qos == QosType.ReliableStateUpdate);
}
public bool SetChannelOption(int channelId, ChannelOption option, int value)
{
if (m_Channels == null)
return false;
if (channelId < 0 || channelId >= m_Channels.Length)
return false;
return m_Channels[channelId].SetOption(option, value);
}
public NetworkConnection()
{
m_Writer = new NetworkWriter();
}
public void Disconnect()
{
address = "";
isReady = false;
ClientScene.HandleClientDisconnect(this);
if (hostId == -1)
{
return;
}
byte error;
NetworkTransport.Disconnect(hostId, connectionId, out error);
RemoveObservers();
}
internal void SetHandlers(NetworkMessageHandlers handlers)
{
m_MessageHandlers = handlers;
m_MessageHandlersDict = handlers.GetHandlers();
}
public bool CheckHandler(short msgType)
{
return m_MessageHandlersDict.ContainsKey(msgType);
}
public bool InvokeHandlerNoData(short msgType)
{
return InvokeHandler(msgType, null, 0);
}
public bool InvokeHandler(short msgType, NetworkReader reader, int channelId)
{
if (m_MessageHandlersDict.ContainsKey(msgType))
{
m_MessageInfo.msgType = msgType;
m_MessageInfo.conn = this;
m_MessageInfo.reader = reader;
m_MessageInfo.channelId = channelId;
NetworkMessageDelegate msgDelegate = m_MessageHandlersDict[msgType];
if (msgDelegate == null)
{
if (LogFilter.logError) { Debug.LogError("NetworkConnection InvokeHandler no handler for " + msgType); }
return false;
}
msgDelegate(m_MessageInfo);
return true;
}
return false;
}
public bool InvokeHandler(NetworkMessage netMsg)
{
if (m_MessageHandlersDict.ContainsKey(netMsg.msgType))
{
NetworkMessageDelegate msgDelegate = m_MessageHandlersDict[netMsg.msgType];
msgDelegate(netMsg);
return true;
}
return false;
}
internal void HandleFragment(NetworkReader reader, int channelId)
{
if (channelId < 0 || channelId >= m_Channels.Length)
{
return;
}
var channel = m_Channels[channelId];
if (channel.HandleFragment(reader))
{
NetworkReader msgReader = new NetworkReader(channel.fragmentBuffer.AsArraySegment().Array);
msgReader.ReadInt16(); // size
short msgType = msgReader.ReadInt16();
InvokeHandler(msgType, msgReader, channelId);
}
}
public void RegisterHandler(short msgType, NetworkMessageDelegate handler)
{
m_MessageHandlers.RegisterHandler(msgType, handler);
}
public void UnregisterHandler(short msgType)
{
m_MessageHandlers.UnregisterHandler(msgType);
}
internal void SetPlayerController(PlayerController player)
{
while (player.playerControllerId >= m_PlayerControllers.Count)
{
m_PlayerControllers.Add(new PlayerController());
}
m_PlayerControllers[player.playerControllerId] = player;
}
internal void RemovePlayerController(short playerControllerId)
{
int count = m_PlayerControllers.Count;
while (count >= 0)
{
if (playerControllerId == count && playerControllerId == m_PlayerControllers[count].playerControllerId)
{
m_PlayerControllers[count] = new PlayerController();
return;
}
count -= 1;
}
if (LogFilter.logError) { Debug.LogError("RemovePlayer player at playerControllerId " + playerControllerId + " not found"); }
}
// Get player controller from connection's list
internal bool GetPlayerController(short playerControllerId, out PlayerController playerController)
{
playerController = null;
if (playerControllers.Count > 0)
{
for (int i = 0; i < playerControllers.Count; i++)
{
if (playerControllers[i].IsValid && playerControllers[i].playerControllerId == playerControllerId)
{
playerController = playerControllers[i];
return true;
}
}
return false;
}
return false;
}
public void FlushChannels()
{
if (m_Channels == null)
{
return;
}
for (int channelId = 0; channelId < m_Channels.Length; channelId++)
{
m_Channels[channelId].CheckInternalBuffer();
}
}
public void SetMaxDelay(float seconds)
{
if (m_Channels == null)
{
return;
}
for (int channelId = 0; channelId < m_Channels.Length; channelId++)
{
m_Channels[channelId].maxDelay = seconds;
}
}
public virtual bool Send(short msgType, MessageBase msg)
{
return SendByChannel(msgType, msg, Channels.DefaultReliable);
}
public virtual bool SendUnreliable(short msgType, MessageBase msg)
{
return SendByChannel(msgType, msg, Channels.DefaultUnreliable);
}
public virtual bool SendByChannel(short msgType, MessageBase msg, int channelId)
{
m_Writer.StartMessage(msgType);
msg.Serialize(m_Writer);
m_Writer.FinishMessage();
return SendWriter(m_Writer, channelId);
}
public virtual bool SendBytes(byte[] bytes, int numBytes, int channelId)
{
if (logNetworkMessages)
{
LogSend(bytes);
}
return CheckChannel(channelId) && m_Channels[channelId].SendBytes(bytes, numBytes);
}
public virtual bool SendWriter(NetworkWriter writer, int channelId)
{
if (logNetworkMessages)
{
LogSend(writer.ToArray());
}
return CheckChannel(channelId) && m_Channels[channelId].SendWriter(writer);
}
void LogSend(byte[] bytes)
{
NetworkReader reader = new NetworkReader(bytes);
var msgSize = reader.ReadUInt16();
var msgId = reader.ReadUInt16();
const int k_PayloadStartPosition = 4;
StringBuilder msg = new StringBuilder();
for (int i = k_PayloadStartPosition; i < k_PayloadStartPosition + msgSize; i++)
{
msg.AppendFormat("{0:X2}", bytes[i]);
if (i > k_MaxMessageLogSize) break;
}
Debug.Log("ConnectionSend con:" + connectionId + " bytes:" + msgSize + " msgId:" + msgId + " " + msg);
}
bool CheckChannel(int channelId)
{
if (m_Channels == null)
{
if (LogFilter.logWarn) { Debug.LogWarning("Channels not initialized sending on id '" + channelId); }
return false;
}
if (channelId < 0 || channelId >= m_Channels.Length)
{
if (LogFilter.logError) { Debug.LogError("Invalid channel when sending buffered data, '" + channelId + "'. Current channel count is " + m_Channels.Length); }
return false;
}
return true;
}
public void ResetStats()
{
#if UNITY_EDITOR
for (short i = 0; i < s_MaxPacketStats; i++)
{
if (m_PacketStats.ContainsKey(i))
{
var value = m_PacketStats[i];
value.count = 0;
value.bytes = 0;
NetworkTransport.SetPacketStat(0, i, 0, 0);
NetworkTransport.SetPacketStat(1, i, 0, 0);
}
}
#endif
}
protected void HandleBytes(
byte[] buffer,
int receivedSize,
int channelId)
{
// build the stream form the buffer passed in
NetworkReader reader = new NetworkReader(buffer);
HandleReader(reader, receivedSize, channelId);
}
protected void HandleReader(
NetworkReader reader,
int receivedSize,
int channelId)
{
// read until size is reached.
// NOTE: stream.Capacity is 1300, NOT the size of the available data
while (reader.Position < receivedSize)
{
// the reader passed to user code has a copy of bytes from the real stream. user code never touches the real stream.
// this ensures it can never get out of sync if user code reads less or more than the real amount.
ushort sz = reader.ReadUInt16();
short msgType = reader.ReadInt16();
// create a reader just for this message
byte[] msgBuffer = reader.ReadBytes(sz);
NetworkReader msgReader = new NetworkReader(msgBuffer);
if (logNetworkMessages)
{
StringBuilder msg = new StringBuilder();
for (int i = 0; i < sz; i++)
{
msg.AppendFormat("{0:X2}", msgBuffer[i]);
if (i > k_MaxMessageLogSize) break;
}
Debug.Log("ConnectionRecv con:" + connectionId + " bytes:" + sz + " msgId:" + msgType + " " + msg);
}
NetworkMessageDelegate msgDelegate = null;
if (m_MessageHandlersDict.ContainsKey(msgType))
{
msgDelegate = m_MessageHandlersDict[msgType];
}
if (msgDelegate != null)
{
m_NetMsg.msgType = msgType;
m_NetMsg.reader = msgReader;
m_NetMsg.conn = this;
m_NetMsg.channelId = channelId;
msgDelegate(m_NetMsg);
lastMessageTime = Time.time;
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Incoming,
MsgType.HLAPIMsg, "msg", 1);
if (msgType > MsgType.Highest)
{
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Incoming,
MsgType.UserMessage, msgType.ToString() + ":" + msgType.GetType().Name, 1);
}
#endif
#if UNITY_EDITOR
if (m_PacketStats.ContainsKey(msgType))
{
PacketStat stat = m_PacketStats[msgType];
stat.count += 1;
stat.bytes += sz;
}
else
{
PacketStat stat = new PacketStat();
stat.msgType = msgType;
stat.count += 1;
stat.bytes += sz;
m_PacketStats[msgType] = stat;
}
#endif
}
else
{
//NOTE: this throws away the rest of the buffer. Need moar error codes
if (LogFilter.logError) { Debug.LogError("Unknown message ID " + msgType + " connId:" + connectionId); }
break;
}
}
}
public virtual void GetStatsOut(out int numMsgs, out int numBufferedMsgs, out int numBytes, out int lastBufferedPerSecond)
{
numMsgs = 0;
numBufferedMsgs = 0;
numBytes = 0;
lastBufferedPerSecond = 0;
for (int channelId = 0; channelId < m_Channels.Length; channelId++)
{
var channel = m_Channels[channelId];
numMsgs += channel.numMsgsOut;
numBufferedMsgs += channel.numBufferedMsgsOut;
numBytes += channel.numBytesOut;
lastBufferedPerSecond += channel.lastBufferedPerSecond;
}
}
public virtual void GetStatsIn(out int numMsgs, out int numBytes)
{
numMsgs = 0;
numBytes = 0;
for (int channelId = 0; channelId < m_Channels.Length; channelId++)
{
var channel = m_Channels[channelId];
numMsgs += channel.numMsgsIn;
numBytes += channel.numBytesIn;
}
}
public override string ToString()
{
return string.Format("hostId: {0} connectionId: {1} isReady: {2} channel count: {3}", hostId, connectionId, isReady, (m_Channels != null ? m_Channels.Length : 0));
}
internal void AddToVisList(NetworkIdentity uv)
{
m_VisList.Add(uv);
// spawn uv for this conn
NetworkServer.ShowForConnection(uv, this);
}
internal void RemoveFromVisList(NetworkIdentity uv, bool isDestroyed)
{
m_VisList.Remove(uv);
if (!isDestroyed)
{
// hide uv for this conn
NetworkServer.HideForConnection(uv, this);
}
}
internal void RemoveObservers()
{
foreach (var uv in m_VisList)
{
uv.RemoveObserverInternal(this);
}
m_VisList.Clear();
}
public virtual void TransportReceive(byte[] bytes, int numBytes, int channelId)
{
HandleBytes(bytes, numBytes, channelId);
}
[Obsolete("TransportRecieve has been deprecated. Use TransportReceive instead (UnityUpgradable) -> TransportReceive(*)", false)]
public virtual void TransportRecieve(byte[] bytes, int numBytes, int channelId)
{
TransportReceive(bytes, numBytes, channelId);
}
public virtual bool TransportSend(byte[] bytes, int numBytes, int channelId, out byte error)
{
return NetworkTransport.Send(hostId, connectionId, channelId, bytes, numBytes, out error);
}
internal void AddOwnedObject(NetworkIdentity obj)
{
if (m_ClientOwnedObjects == null)
{
m_ClientOwnedObjects = new HashSet<NetworkInstanceId>();
}
m_ClientOwnedObjects.Add(obj.netId);
}
internal void RemoveOwnedObject(NetworkIdentity obj)
{
if (m_ClientOwnedObjects == null)
{
return;
}
m_ClientOwnedObjects.Remove(obj.netId);
}
internal static void OnFragment(NetworkMessage netMsg)
{
netMsg.conn.HandleFragment(netMsg.reader, netMsg.channelId);
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,435 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEngine.Networking
{
public struct NetworkBroadcastResult
{
public string serverAddress;
public byte[] broadcastData;
}
[DisallowMultipleComponent]
[AddComponentMenu("Network/NetworkDiscovery")]
public class NetworkDiscovery : MonoBehaviour
{
const int k_MaxBroadcastMsgSize = 1024;
// config data
[SerializeField]
int m_BroadcastPort = 47777;
[SerializeField]
int m_BroadcastKey = 2222;
[SerializeField]
int m_BroadcastVersion = 1;
[SerializeField]
int m_BroadcastSubVersion = 1;
[SerializeField]
int m_BroadcastInterval = 1000;
[SerializeField]
bool m_UseNetworkManager = false;
[SerializeField]
string m_BroadcastData = "HELLO";
[SerializeField]
bool m_ShowGUI = true;
[SerializeField]
int m_OffsetX;
[SerializeField]
int m_OffsetY;
// runtime data
int m_HostId = -1;
bool m_Running;
bool m_IsServer;
bool m_IsClient;
byte[] m_MsgOutBuffer;
byte[] m_MsgInBuffer;
HostTopology m_DefaultTopology;
Dictionary<string, NetworkBroadcastResult> m_BroadcastsReceived;
public int broadcastPort
{
get { return m_BroadcastPort; }
set { m_BroadcastPort = value; }
}
public int broadcastKey
{
get { return m_BroadcastKey; }
set { m_BroadcastKey = value; }
}
public int broadcastVersion
{
get { return m_BroadcastVersion; }
set { m_BroadcastVersion = value; }
}
public int broadcastSubVersion
{
get { return m_BroadcastSubVersion; }
set { m_BroadcastSubVersion = value; }
}
public int broadcastInterval
{
get { return m_BroadcastInterval; }
set { m_BroadcastInterval = value; }
}
public bool useNetworkManager
{
get { return m_UseNetworkManager; }
set { m_UseNetworkManager = value; }
}
public string broadcastData
{
get { return m_BroadcastData; }
set
{
m_BroadcastData = value;
m_MsgOutBuffer = StringToBytes(m_BroadcastData);
if (m_UseNetworkManager)
{
if (LogFilter.logWarn) { Debug.LogWarning("NetworkDiscovery broadcast data changed while using NetworkManager. This can prevent clients from finding the server. The format of the broadcast data must be 'NetworkManager:IPAddress:Port'."); }
}
}
}
public bool showGUI
{
get { return m_ShowGUI; }
set { m_ShowGUI = value; }
}
public int offsetX
{
get { return m_OffsetX; }
set { m_OffsetX = value; }
}
public int offsetY
{
get { return m_OffsetY; }
set { m_OffsetY = value; }
}
public int hostId
{
get { return m_HostId; }
set { m_HostId = value; }
}
public bool running
{
get { return m_Running; }
set { m_Running = value; }
}
public bool isServer
{
get { return m_IsServer; }
set { m_IsServer = value; }
}
public bool isClient
{
get { return m_IsClient; }
set { m_IsClient = value; }
}
public Dictionary<string, NetworkBroadcastResult> broadcastsReceived
{
get { return m_BroadcastsReceived; }
}
static byte[] StringToBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
static string BytesToString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
public bool Initialize()
{
if (m_BroadcastData.Length >= k_MaxBroadcastMsgSize)
{
if (LogFilter.logError) { Debug.LogError("NetworkDiscovery Initialize - data too large. max is " + k_MaxBroadcastMsgSize); }
return false;
}
if (!NetworkTransport.IsStarted)
{
NetworkTransport.Init();
}
if (m_UseNetworkManager && NetworkManager.singleton != null)
{
m_BroadcastData = "NetworkManager:" + NetworkManager.singleton.networkAddress + ":" + NetworkManager.singleton.networkPort;
if (LogFilter.logInfo) { Debug.Log("NetworkDiscovery set broadcast data to:" + m_BroadcastData); }
}
m_MsgOutBuffer = StringToBytes(m_BroadcastData);
m_MsgInBuffer = new byte[k_MaxBroadcastMsgSize];
m_BroadcastsReceived = new Dictionary<string, NetworkBroadcastResult>();
ConnectionConfig cc = new ConnectionConfig();
cc.AddChannel(QosType.Unreliable);
m_DefaultTopology = new HostTopology(cc, 1);
if (m_IsServer)
StartAsServer();
if (m_IsClient)
StartAsClient();
return true;
}
// listen for broadcasts
public bool StartAsClient()
{
if (m_HostId != -1 || m_Running)
{
if (LogFilter.logWarn) { Debug.LogWarning("NetworkDiscovery StartAsClient already started"); }
return false;
}
if (m_MsgInBuffer == null)
{
if (LogFilter.logError) { Debug.LogError("NetworkDiscovery StartAsClient, NetworkDiscovery is not initialized"); }
return false;
}
m_HostId = NetworkTransport.AddHost(m_DefaultTopology, m_BroadcastPort);
if (m_HostId == -1)
{
if (LogFilter.logError) { Debug.LogError("NetworkDiscovery StartAsClient - addHost failed"); }
return false;
}
byte error;
NetworkTransport.SetBroadcastCredentials(m_HostId, m_BroadcastKey, m_BroadcastVersion, m_BroadcastSubVersion, out error);
m_Running = true;
m_IsClient = true;
if (LogFilter.logDebug) { Debug.Log("StartAsClient Discovery listening"); }
return true;
}
// perform actual broadcasts
public bool StartAsServer()
{
if (m_HostId != -1 || m_Running)
{
if (LogFilter.logWarn) { Debug.LogWarning("NetworkDiscovery StartAsServer already started"); }
return false;
}
m_HostId = NetworkTransport.AddHost(m_DefaultTopology, 0);
if (m_HostId == -1)
{
if (LogFilter.logError) { Debug.LogError("NetworkDiscovery StartAsServer - addHost failed"); }
return false;
}
byte err;
if (!NetworkTransport.StartBroadcastDiscovery(m_HostId, m_BroadcastPort, m_BroadcastKey, m_BroadcastVersion, m_BroadcastSubVersion, m_MsgOutBuffer, m_MsgOutBuffer.Length, m_BroadcastInterval, out err))
{
if (LogFilter.logError) { Debug.LogError("NetworkDiscovery StartBroadcast failed err: " + err); }
return false;
}
m_Running = true;
m_IsServer = true;
if (LogFilter.logDebug) { Debug.Log("StartAsServer Discovery broadcasting"); }
DontDestroyOnLoad(gameObject);
return true;
}
public void StopBroadcast()
{
if (m_HostId == -1)
{
if (LogFilter.logError) { Debug.LogError("NetworkDiscovery StopBroadcast not initialized"); }
return;
}
if (!m_Running)
{
Debug.LogWarning("NetworkDiscovery StopBroadcast not started");
return;
}
if (m_IsServer)
{
NetworkTransport.StopBroadcastDiscovery();
}
NetworkTransport.RemoveHost(m_HostId);
m_HostId = -1;
m_Running = false;
m_IsServer = false;
m_IsClient = false;
m_MsgInBuffer = null;
m_BroadcastsReceived = null;
if (LogFilter.logDebug) { Debug.Log("Stopped Discovery broadcasting"); }
}
void Update()
{
if (m_HostId == -1)
return;
if (m_IsServer)
return;
NetworkEventType networkEvent;
do
{
int connectionId;
int channelId;
int receivedSize;
byte error;
networkEvent = NetworkTransport.ReceiveFromHost(m_HostId, out connectionId, out channelId, m_MsgInBuffer, k_MaxBroadcastMsgSize, out receivedSize, out error);
if (networkEvent == NetworkEventType.BroadcastEvent)
{
NetworkTransport.GetBroadcastConnectionMessage(m_HostId, m_MsgInBuffer, k_MaxBroadcastMsgSize, out receivedSize, out error);
string senderAddr;
int senderPort;
NetworkTransport.GetBroadcastConnectionInfo(m_HostId, out senderAddr, out senderPort, out error);
var recv = new NetworkBroadcastResult();
recv.serverAddress = senderAddr;
recv.broadcastData = new byte[receivedSize];
Buffer.BlockCopy(m_MsgInBuffer, 0, recv.broadcastData, 0, receivedSize);
m_BroadcastsReceived[senderAddr] = recv;
OnReceivedBroadcast(senderAddr, BytesToString(m_MsgInBuffer));
}
}
while (networkEvent != NetworkEventType.Nothing);
}
void OnDestroy()
{
if (m_IsServer && m_Running && m_HostId != -1)
{
NetworkTransport.StopBroadcastDiscovery();
NetworkTransport.RemoveHost(m_HostId);
}
if (m_IsClient && m_Running && m_HostId != -1)
{
NetworkTransport.RemoveHost(m_HostId);
}
}
public virtual void OnReceivedBroadcast(string fromAddress, string data)
{
//Debug.Log("Got broadcast from [" + fromAddress + "] " + data);
}
void OnGUI()
{
if (!m_ShowGUI)
return;
int xpos = 10 + m_OffsetX;
int ypos = 40 + m_OffsetY;
const int spacing = 24;
if (UnityEngine.Application.platform == RuntimePlatform.WebGLPlayer)
{
GUI.Box(new Rect(xpos, ypos, 200, 20), "( WebGL cannot broadcast )");
return;
}
if (m_MsgInBuffer == null)
{
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Initialize Broadcast"))
{
Initialize();
}
return;
}
string suffix = "";
if (m_IsServer)
suffix = " (server)";
if (m_IsClient)
suffix = " (client)";
GUI.Label(new Rect(xpos, ypos, 200, 20), "initialized" + suffix);
ypos += spacing;
if (m_Running)
{
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Stop"))
{
StopBroadcast();
}
ypos += spacing;
if (m_BroadcastsReceived != null)
{
foreach (var addr in m_BroadcastsReceived.Keys)
{
var value = m_BroadcastsReceived[addr];
if (GUI.Button(new Rect(xpos, ypos + 20, 200, 20), "Game at " + addr) && m_UseNetworkManager)
{
string dataString = BytesToString(value.broadcastData);
var items = dataString.Split(':');
if (items.Length == 3 && items[0] == "NetworkManager")
{
if (NetworkManager.singleton != null && NetworkManager.singleton.client == null)
{
NetworkManager.singleton.networkAddress = items[1];
NetworkManager.singleton.networkPort = Convert.ToInt32(items[2]);
NetworkManager.singleton.StartClient();
}
}
}
ypos += spacing;
}
}
}
else
{
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Start Broadcasting"))
{
StartAsServer();
}
ypos += spacing;
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Listen for Broadcast"))
{
StartAsClient();
}
ypos += spacing;
}
}
}
}
#endif

View File

@ -0,0 +1,107 @@
#if ENABLE_UNET
using System;
namespace UnityEngine.Networking
{
// unrolled for your pleasure.
[Serializable]
public struct NetworkHash128
{
// struct cannot have embedded arrays..
public byte i0;
public byte i1;
public byte i2;
public byte i3;
public byte i4;
public byte i5;
public byte i6;
public byte i7;
public byte i8;
public byte i9;
public byte i10;
public byte i11;
public byte i12;
public byte i13;
public byte i14;
public byte i15;
public void Reset()
{
i0 = 0;
i1 = 0;
i2 = 0;
i3 = 0;
i4 = 0;
i5 = 0;
i6 = 0;
i7 = 0;
i8 = 0;
i9 = 0;
i10 = 0;
i11 = 0;
i12 = 0;
i13 = 0;
i14 = 0;
i15 = 0;
}
public bool IsValid()
{
return (i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7 | i8 | i9 | i10 | i11 | i12 | i13 | i14 | i15) != 0;
}
static int HexToNumber(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
return 0;
}
public static NetworkHash128 Parse(string text)
{
NetworkHash128 hash;
// add leading zeros if required
int l = text.Length;
if (l < 32)
{
string tmp = "";
for (int i = 0; i < 32 - l; i++)
{
tmp += "0";
}
text = (tmp + text);
}
hash.i0 = (byte)(HexToNumber(text[0]) * 16 + HexToNumber(text[1]));
hash.i1 = (byte)(HexToNumber(text[2]) * 16 + HexToNumber(text[3]));
hash.i2 = (byte)(HexToNumber(text[4]) * 16 + HexToNumber(text[5]));
hash.i3 = (byte)(HexToNumber(text[6]) * 16 + HexToNumber(text[7]));
hash.i4 = (byte)(HexToNumber(text[8]) * 16 + HexToNumber(text[9]));
hash.i5 = (byte)(HexToNumber(text[10]) * 16 + HexToNumber(text[11]));
hash.i6 = (byte)(HexToNumber(text[12]) * 16 + HexToNumber(text[13]));
hash.i7 = (byte)(HexToNumber(text[14]) * 16 + HexToNumber(text[15]));
hash.i8 = (byte)(HexToNumber(text[16]) * 16 + HexToNumber(text[17]));
hash.i9 = (byte)(HexToNumber(text[18]) * 16 + HexToNumber(text[19]));
hash.i10 = (byte)(HexToNumber(text[20]) * 16 + HexToNumber(text[21]));
hash.i11 = (byte)(HexToNumber(text[22]) * 16 + HexToNumber(text[23]));
hash.i12 = (byte)(HexToNumber(text[24]) * 16 + HexToNumber(text[25]));
hash.i13 = (byte)(HexToNumber(text[26]) * 16 + HexToNumber(text[27]));
hash.i14 = (byte)(HexToNumber(text[28]) * 16 + HexToNumber(text[29]));
hash.i15 = (byte)(HexToNumber(text[30]) * 16 + HexToNumber(text[31]));
return hash;
}
public override string ToString()
{
return String.Format("{0:x2}{1:x2}{2:x2}{3:x2}{4:x2}{5:x2}{6:x2}{7:x2}{8:x2}{9:x2}{10:x2}{11:x2}{12:x2}{13:x2}{14:x2}{15:x2}",
i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);
}
}
}
#endif //ENABLE_UNET

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
#if ENABLE_UNET
using System;
namespace UnityEngine.Networking
{
[Serializable]
public struct NetworkInstanceId
{
public NetworkInstanceId(uint value)
{
m_Value = value;
}
[SerializeField]
readonly uint m_Value;
public bool IsEmpty()
{
return m_Value == 0;
}
public override int GetHashCode()
{
return (int)m_Value;
}
public override bool Equals(object obj)
{
return obj is NetworkInstanceId && this == (NetworkInstanceId)obj;
}
public static bool operator==(NetworkInstanceId c1, NetworkInstanceId c2)
{
return c1.m_Value == c2.m_Value;
}
public static bool operator!=(NetworkInstanceId c1, NetworkInstanceId c2)
{
return c1.m_Value != c2.m_Value;
}
public override string ToString()
{
return m_Value.ToString();
}
public uint Value { get { return m_Value; } }
public static NetworkInstanceId Invalid = new NetworkInstanceId(uint.MaxValue);
internal static NetworkInstanceId Zero = new NetworkInstanceId(0);
}
}
#endif

View File

@ -0,0 +1,774 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Networking.NetworkSystem;
using UnityEngine.SceneManagement;
namespace UnityEngine.Networking
{
[AddComponentMenu("Network/NetworkLobbyManager")]
public class NetworkLobbyManager : NetworkManager
{
struct PendingPlayer
{
public NetworkConnection conn;
public GameObject lobbyPlayer;
}
// configuration
[SerializeField] bool m_ShowLobbyGUI = true;
[SerializeField] int m_MaxPlayers = 4;
[SerializeField] int m_MaxPlayersPerConnection = 1;
[SerializeField] int m_MinPlayers;
[SerializeField] NetworkLobbyPlayer m_LobbyPlayerPrefab;
[SerializeField] GameObject m_GamePlayerPrefab;
[SerializeField] string m_LobbyScene = "";
[SerializeField] string m_PlayScene = "";
// runtime data
List<PendingPlayer> m_PendingPlayers = new List<PendingPlayer>();
public NetworkLobbyPlayer[] lobbySlots;
// static message objects to avoid runtime-allocations
static LobbyReadyToBeginMessage s_ReadyToBeginMessage = new LobbyReadyToBeginMessage();
static IntegerMessage s_SceneLoadedMessage = new IntegerMessage();
static LobbyReadyToBeginMessage s_LobbyReadyToBeginMessage = new LobbyReadyToBeginMessage();
// properties
public bool showLobbyGUI { get { return m_ShowLobbyGUI; } set { m_ShowLobbyGUI = value; } }
public int maxPlayers { get { return m_MaxPlayers; } set { m_MaxPlayers = value; } }
public int maxPlayersPerConnection { get { return m_MaxPlayersPerConnection; } set { m_MaxPlayersPerConnection = value; } }
public int minPlayers { get { return m_MinPlayers; } set { m_MinPlayers = value; } }
public NetworkLobbyPlayer lobbyPlayerPrefab { get { return m_LobbyPlayerPrefab; } set { m_LobbyPlayerPrefab = value; } }
public GameObject gamePlayerPrefab { get { return m_GamePlayerPrefab; } set { m_GamePlayerPrefab = value; } }
public string lobbyScene { get { return m_LobbyScene; } set { m_LobbyScene = value; offlineScene = value; } }
public string playScene { get { return m_PlayScene; } set { m_PlayScene = value; } }
void OnValidate()
{
if (m_MaxPlayers <= 0)
{
m_MaxPlayers = 1;
}
if (m_MaxPlayersPerConnection <= 0)
{
m_MaxPlayersPerConnection = 1;
}
if (m_MaxPlayersPerConnection > maxPlayers)
{
m_MaxPlayersPerConnection = maxPlayers;
}
if (m_MinPlayers < 0)
{
m_MinPlayers = 0;
}
if (m_MinPlayers > m_MaxPlayers)
{
m_MinPlayers = m_MaxPlayers;
}
if (m_LobbyPlayerPrefab != null)
{
var uv = m_LobbyPlayerPrefab.GetComponent<NetworkIdentity>();
if (uv == null)
{
m_LobbyPlayerPrefab = null;
Debug.LogWarning("LobbyPlayer prefab must have a NetworkIdentity component.");
}
}
if (m_GamePlayerPrefab != null)
{
var uv = m_GamePlayerPrefab.GetComponent<NetworkIdentity>();
if (uv == null)
{
m_GamePlayerPrefab = null;
Debug.LogWarning("GamePlayer prefab must have a NetworkIdentity component.");
}
}
}
Byte FindSlot()
{
for (byte i = 0; i < maxPlayers; i++)
{
if (lobbySlots[i] == null)
{
return i;
}
}
return Byte.MaxValue;
}
void SceneLoadedForPlayer(NetworkConnection conn, GameObject lobbyPlayerGameObject)
{
var lobbyPlayer = lobbyPlayerGameObject.GetComponent<NetworkLobbyPlayer>();
if (lobbyPlayer == null)
{
// not a lobby player.. dont replace it
return;
}
string loadedSceneName = SceneManager.GetSceneAt(0).name;
if (LogFilter.logDebug) { Debug.Log("NetworkLobby SceneLoadedForPlayer scene:" + loadedSceneName + " " + conn); }
if (loadedSceneName == m_LobbyScene)
{
// cant be ready in lobby, add to ready list
PendingPlayer pending;
pending.conn = conn;
pending.lobbyPlayer = lobbyPlayerGameObject;
m_PendingPlayers.Add(pending);
return;
}
var controllerId = lobbyPlayerGameObject.GetComponent<NetworkIdentity>().playerControllerId;
var gamePlayer = OnLobbyServerCreateGamePlayer(conn, controllerId);
if (gamePlayer == null)
{
// get start position from base class
Transform startPos = GetStartPosition();
if (startPos != null)
{
gamePlayer = (GameObject)Instantiate(gamePlayerPrefab, startPos.position, startPos.rotation);
}
else
{
gamePlayer = (GameObject)Instantiate(gamePlayerPrefab, Vector3.zero, Quaternion.identity);
}
}
if (!OnLobbyServerSceneLoadedForPlayer(lobbyPlayerGameObject, gamePlayer))
{
return;
}
// replace lobby player with game player
NetworkServer.ReplacePlayerForConnection(conn, gamePlayer, controllerId);
}
static int CheckConnectionIsReadyToBegin(NetworkConnection conn)
{
int countPlayers = 0;
for (int i = 0; i < conn.playerControllers.Count; i++)
{
var player = conn.playerControllers[i];
if (player.IsValid)
{
var lobbyPlayer = player.gameObject.GetComponent<NetworkLobbyPlayer>();
if (lobbyPlayer.readyToBegin)
{
countPlayers += 1;
}
}
}
return countPlayers;
}
public void CheckReadyToBegin()
{
string loadedSceneName = SceneManager.GetSceneAt(0).name;
if (loadedSceneName != m_LobbyScene)
{
return;
}
int readyCount = 0;
int playerCount = 0;
for (int i = 0; i < NetworkServer.connections.Count; i++)
{
var conn = NetworkServer.connections[i];
if (conn == null)
continue;
playerCount += 1;
readyCount += CheckConnectionIsReadyToBegin(conn);
}
if (m_MinPlayers > 0 && readyCount < m_MinPlayers)
{
// not enough players ready yet.
return;
}
if (readyCount < playerCount)
{
// not all players are ready yet
return;
}
m_PendingPlayers.Clear();
OnLobbyServerPlayersReady();
}
public void ServerReturnToLobby()
{
if (!NetworkServer.active)
{
Debug.Log("ServerReturnToLobby called on client");
return;
}
ServerChangeScene(m_LobbyScene);
}
void CallOnClientEnterLobby()
{
OnLobbyClientEnter();
for (int i = 0; i < lobbySlots.Length; i++)
{
var player = lobbySlots[i];
if (player == null)
continue;
player.readyToBegin = false;
player.OnClientEnterLobby();
}
}
void CallOnClientExitLobby()
{
OnLobbyClientExit();
for (int i = 0; i < lobbySlots.Length; i++)
{
var player = lobbySlots[i];
if (player == null)
continue;
player.OnClientExitLobby();
}
}
public bool SendReturnToLobby()
{
if (client == null || !client.isConnected)
{
return false;
}
var msg = new EmptyMessage();
client.Send(MsgType.LobbyReturnToLobby, msg);
return true;
}
// ------------------------ server handlers ------------------------
public override void OnServerConnect(NetworkConnection conn)
{
// numPlayers returns the player count including this one, so ok to be equal
if (numPlayers > maxPlayers)
{
if (LogFilter.logWarn) { Debug.LogWarning("NetworkLobbyManager can't accept new connection [" + conn + "], too many players connected."); }
conn.Disconnect();
return;
}
// cannot join game in progress
string loadedSceneName = SceneManager.GetSceneAt(0).name;
if (loadedSceneName != m_LobbyScene)
{
if (LogFilter.logWarn) { Debug.LogWarning("NetworkLobbyManager can't accept new connection [" + conn + "], not in lobby and game already in progress."); }
conn.Disconnect();
return;
}
base.OnServerConnect(conn);
// when a new client connects, set all old players as dirty so their current ready state is sent out
for (int i = 0; i < lobbySlots.Length; ++i)
{
if (lobbySlots[i])
{
lobbySlots[i].SetDirtyBit(1);
}
}
OnLobbyServerConnect(conn);
}
public override void OnServerDisconnect(NetworkConnection conn)
{
base.OnServerDisconnect(conn);
// if lobbyplayer for this connection has not been destroyed by now, then destroy it here
for (int i = 0; i < lobbySlots.Length; i++)
{
var player = lobbySlots[i];
if (player == null)
continue;
if (player.connectionToClient == conn)
{
lobbySlots[i] = null;
NetworkServer.Destroy(player.gameObject);
}
}
OnLobbyServerDisconnect(conn);
}
public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
string loadedSceneName = SceneManager.GetSceneAt(0).name;
if (loadedSceneName != m_LobbyScene)
{
return;
}
// check MaxPlayersPerConnection
int numPlayersForConnection = 0;
for (int i = 0; i < conn.playerControllers.Count; i++)
{
if (conn.playerControllers[i].IsValid)
numPlayersForConnection += 1;
}
if (numPlayersForConnection >= maxPlayersPerConnection)
{
if (LogFilter.logWarn) { Debug.LogWarning("NetworkLobbyManager no more players for this connection."); }
var errorMsg = new EmptyMessage();
conn.Send(MsgType.LobbyAddPlayerFailed, errorMsg);
return;
}
byte slot = FindSlot();
if (slot == Byte.MaxValue)
{
if (LogFilter.logWarn) { Debug.LogWarning("NetworkLobbyManager no space for more players"); }
var errorMsg = new EmptyMessage();
conn.Send(MsgType.LobbyAddPlayerFailed, errorMsg);
return;
}
var newLobbyGameObject = OnLobbyServerCreateLobbyPlayer(conn, playerControllerId);
if (newLobbyGameObject == null)
{
newLobbyGameObject = (GameObject)Instantiate(lobbyPlayerPrefab.gameObject, Vector3.zero, Quaternion.identity);
}
var newLobbyPlayer = newLobbyGameObject.GetComponent<NetworkLobbyPlayer>();
newLobbyPlayer.slot = slot;
lobbySlots[slot] = newLobbyPlayer;
NetworkServer.AddPlayerForConnection(conn, newLobbyGameObject, playerControllerId);
}
public override void OnServerRemovePlayer(NetworkConnection conn, PlayerController player)
{
var playerControllerId = player.playerControllerId;
byte slot = player.gameObject.GetComponent<NetworkLobbyPlayer>().slot;
lobbySlots[slot] = null;
base.OnServerRemovePlayer(conn, player);
for (int i = 0; i < lobbySlots.Length; i++)
{
var lobbyPlayer = lobbySlots[i];
if (lobbyPlayer != null)
{
lobbyPlayer.GetComponent<NetworkLobbyPlayer>().readyToBegin = false;
s_LobbyReadyToBeginMessage.slotId = lobbyPlayer.slot;
s_LobbyReadyToBeginMessage.readyState = false;
NetworkServer.SendToReady(null, MsgType.LobbyReadyToBegin, s_LobbyReadyToBeginMessage);
}
}
OnLobbyServerPlayerRemoved(conn, playerControllerId);
}
public override void ServerChangeScene(string sceneName)
{
if (sceneName == m_LobbyScene)
{
for (int i = 0; i < lobbySlots.Length; i++)
{
var lobbyPlayer = lobbySlots[i];
if (lobbyPlayer == null)
continue;
// find the game-player object for this connection, and destroy it
var uv = lobbyPlayer.GetComponent<NetworkIdentity>();
PlayerController playerController;
if (uv.connectionToClient.GetPlayerController(uv.playerControllerId, out playerController))
{
NetworkServer.Destroy(playerController.gameObject);
}
if (NetworkServer.active)
{
// re-add the lobby object
lobbyPlayer.GetComponent<NetworkLobbyPlayer>().readyToBegin = false;
NetworkServer.ReplacePlayerForConnection(uv.connectionToClient, lobbyPlayer.gameObject, uv.playerControllerId);
}
}
}
base.ServerChangeScene(sceneName);
}
public override void OnServerSceneChanged(string sceneName)
{
if (sceneName != m_LobbyScene)
{
// call SceneLoadedForPlayer on any players that become ready while we were loading the scene.
for (int i = 0; i < m_PendingPlayers.Count; i++)
{
var pending = m_PendingPlayers[i];
SceneLoadedForPlayer(pending.conn, pending.lobbyPlayer);
}
m_PendingPlayers.Clear();
}
OnLobbyServerSceneChanged(sceneName);
}
void OnServerReadyToBeginMessage(NetworkMessage netMsg)
{
if (LogFilter.logDebug) { Debug.Log("NetworkLobbyManager OnServerReadyToBeginMessage"); }
netMsg.ReadMessage(s_ReadyToBeginMessage);
PlayerController lobbyController;
if (!netMsg.conn.GetPlayerController((short)s_ReadyToBeginMessage.slotId, out lobbyController))
{
if (LogFilter.logError) { Debug.LogError("NetworkLobbyManager OnServerReadyToBeginMessage invalid playerControllerId " + s_ReadyToBeginMessage.slotId); }
return;
}
// set this player ready
var lobbyPlayer = lobbyController.gameObject.GetComponent<NetworkLobbyPlayer>();
lobbyPlayer.readyToBegin = s_ReadyToBeginMessage.readyState;
// tell every player that this player is ready
var outMsg = new LobbyReadyToBeginMessage();
outMsg.slotId = lobbyPlayer.slot;
outMsg.readyState = s_ReadyToBeginMessage.readyState;
NetworkServer.SendToReady(null, MsgType.LobbyReadyToBegin, outMsg);
// maybe start the game
CheckReadyToBegin();
}
void OnServerSceneLoadedMessage(NetworkMessage netMsg)
{
if (LogFilter.logDebug) { Debug.Log("NetworkLobbyManager OnSceneLoadedMessage"); }
netMsg.ReadMessage(s_SceneLoadedMessage);
PlayerController lobbyController;
if (!netMsg.conn.GetPlayerController((short)s_SceneLoadedMessage.value, out lobbyController))
{
if (LogFilter.logError) { Debug.LogError("NetworkLobbyManager OnServerSceneLoadedMessage invalid playerControllerId " + s_SceneLoadedMessage.value); }
return;
}
SceneLoadedForPlayer(netMsg.conn, lobbyController.gameObject);
}
void OnServerReturnToLobbyMessage(NetworkMessage netMsg)
{
if (LogFilter.logDebug) { Debug.Log("NetworkLobbyManager OnServerReturnToLobbyMessage"); }
ServerReturnToLobby();
}
public override void OnStartServer()
{
if (string.IsNullOrEmpty(m_LobbyScene))
{
if (LogFilter.logError) { Debug.LogError("NetworkLobbyManager LobbyScene is empty. Set the LobbyScene in the inspector for the NetworkLobbyMangaer"); }
return;
}
if (string.IsNullOrEmpty(m_PlayScene))
{
if (LogFilter.logError) { Debug.LogError("NetworkLobbyManager PlayScene is empty. Set the PlayScene in the inspector for the NetworkLobbyMangaer"); }
return;
}
if (lobbySlots.Length == 0)
{
lobbySlots = new NetworkLobbyPlayer[maxPlayers];
}
NetworkServer.RegisterHandler(MsgType.LobbyReadyToBegin, OnServerReadyToBeginMessage);
NetworkServer.RegisterHandler(MsgType.LobbySceneLoaded, OnServerSceneLoadedMessage);
NetworkServer.RegisterHandler(MsgType.LobbyReturnToLobby, OnServerReturnToLobbyMessage);
OnLobbyStartServer();
}
public override void OnStartHost()
{
OnLobbyStartHost();
}
public override void OnStopHost()
{
OnLobbyStopHost();
}
// ------------------------ client handlers ------------------------
public override void OnStartClient(NetworkClient lobbyClient)
{
if (lobbySlots.Length == 0)
{
lobbySlots = new NetworkLobbyPlayer[maxPlayers];
}
if (m_LobbyPlayerPrefab == null || m_LobbyPlayerPrefab.gameObject == null)
{
if (LogFilter.logError) { Debug.LogError("NetworkLobbyManager no LobbyPlayer prefab is registered. Please add a LobbyPlayer prefab."); }
}
else
{
ClientScene.RegisterPrefab(m_LobbyPlayerPrefab.gameObject);
}
if (m_GamePlayerPrefab == null)
{
if (LogFilter.logError) { Debug.LogError("NetworkLobbyManager no GamePlayer prefab is registered. Please add a GamePlayer prefab."); }
}
else
{
ClientScene.RegisterPrefab(m_GamePlayerPrefab);
}
lobbyClient.RegisterHandler(MsgType.LobbyReadyToBegin, OnClientReadyToBegin);
lobbyClient.RegisterHandler(MsgType.LobbyAddPlayerFailed, OnClientAddPlayerFailedMessage);
OnLobbyStartClient(lobbyClient);
}
public override void OnClientConnect(NetworkConnection conn)
{
OnLobbyClientConnect(conn);
CallOnClientEnterLobby();
base.OnClientConnect(conn);
}
public override void OnClientDisconnect(NetworkConnection conn)
{
OnLobbyClientDisconnect(conn);
base.OnClientDisconnect(conn);
}
public override void OnStopClient()
{
OnLobbyStopClient();
CallOnClientExitLobby();
}
public override void OnClientSceneChanged(NetworkConnection conn)
{
string loadedSceneName = SceneManager.GetSceneAt(0).name;
if (loadedSceneName == m_LobbyScene)
{
if (client.isConnected)
{
CallOnClientEnterLobby();
}
}
else
{
CallOnClientExitLobby();
}
base.OnClientSceneChanged(conn);
OnLobbyClientSceneChanged(conn);
}
void OnClientReadyToBegin(NetworkMessage netMsg)
{
netMsg.ReadMessage(s_LobbyReadyToBeginMessage);
if (s_LobbyReadyToBeginMessage.slotId >= lobbySlots.Count())
{
if (LogFilter.logError) { Debug.LogError("NetworkLobbyManager OnClientReadyToBegin invalid lobby slot " + s_LobbyReadyToBeginMessage.slotId); }
return;
}
var lobbyPlayer = lobbySlots[s_LobbyReadyToBeginMessage.slotId];
if (lobbyPlayer == null || lobbyPlayer.gameObject == null)
{
if (LogFilter.logError) { Debug.LogError("NetworkLobbyManager OnClientReadyToBegin no player at lobby slot " + s_LobbyReadyToBeginMessage.slotId); }
return;
}
lobbyPlayer.readyToBegin = s_LobbyReadyToBeginMessage.readyState;
lobbyPlayer.OnClientReady(s_LobbyReadyToBeginMessage.readyState);
}
void OnClientAddPlayerFailedMessage(NetworkMessage netMsg)
{
if (LogFilter.logDebug) { Debug.Log("NetworkLobbyManager Add Player failed."); }
OnLobbyClientAddPlayerFailed();
}
// ------------------------ lobby server virtuals ------------------------
public virtual void OnLobbyStartHost()
{
}
public virtual void OnLobbyStopHost()
{
}
public virtual void OnLobbyStartServer()
{
}
public virtual void OnLobbyServerConnect(NetworkConnection conn)
{
}
public virtual void OnLobbyServerDisconnect(NetworkConnection conn)
{
}
public virtual void OnLobbyServerSceneChanged(string sceneName)
{
}
public virtual GameObject OnLobbyServerCreateLobbyPlayer(NetworkConnection conn, short playerControllerId)
{
return null;
}
public virtual GameObject OnLobbyServerCreateGamePlayer(NetworkConnection conn, short playerControllerId)
{
return null;
}
public virtual void OnLobbyServerPlayerRemoved(NetworkConnection conn, short playerControllerId)
{
}
// for users to apply settings from their lobby player object to their in-game player object
public virtual bool OnLobbyServerSceneLoadedForPlayer(GameObject lobbyPlayer, GameObject gamePlayer)
{
return true;
}
public virtual void OnLobbyServerPlayersReady()
{
// all players are readyToBegin, start the game
ServerChangeScene(m_PlayScene);
}
// ------------------------ lobby client virtuals ------------------------
public virtual void OnLobbyClientEnter()
{
}
public virtual void OnLobbyClientExit()
{
}
public virtual void OnLobbyClientConnect(NetworkConnection conn)
{
}
public virtual void OnLobbyClientDisconnect(NetworkConnection conn)
{
}
public virtual void OnLobbyStartClient(NetworkClient lobbyClient)
{
}
public virtual void OnLobbyStopClient()
{
}
public virtual void OnLobbyClientSceneChanged(NetworkConnection conn)
{
}
// for users to handle adding a player failed on the server
public virtual void OnLobbyClientAddPlayerFailed()
{
}
// ------------------------ optional UI ------------------------
void OnGUI()
{
if (!showLobbyGUI)
return;
string loadedSceneName = SceneManager.GetSceneAt(0).name;
if (loadedSceneName != m_LobbyScene)
return;
Rect backgroundRec = new Rect(90 , 180, 500, 150);
GUI.Box(backgroundRec, "Players:");
if (NetworkClient.active)
{
Rect addRec = new Rect(100, 300, 120, 20);
if (GUI.Button(addRec, "Add Player"))
{
TryToAddPlayer();
}
}
}
public void TryToAddPlayer()
{
if (NetworkClient.active)
{
short controllerId = -1;
var controllers = NetworkClient.allClients[0].connection.playerControllers;
if (controllers.Count < maxPlayers)
{
controllerId = (short)controllers.Count;
}
else
{
for (short i = 0; i < maxPlayers; i++)
{
if (!controllers[i].IsValid)
{
controllerId = i;
break;
}
}
}
if (LogFilter.logDebug) { Debug.Log("NetworkLobbyManager TryToAddPlayer controllerId " + controllerId + " ready:" + ClientScene.ready); }
if (controllerId == -1)
{
if (LogFilter.logDebug) { Debug.Log("NetworkLobbyManager No Space!"); }
return;
}
if (ClientScene.ready)
{
ClientScene.AddPlayer(controllerId);
}
else
{
ClientScene.AddPlayer(NetworkClient.allClients[0].connection, controllerId);
}
}
else
{
if (LogFilter.logDebug) { Debug.Log("NetworkLobbyManager NetworkClient not active!"); }
}
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,226 @@
#if ENABLE_UNET
using System;
using UnityEngine;
using UnityEngine.Networking.NetworkSystem;
using UnityEngine.SceneManagement;
namespace UnityEngine.Networking
{
[DisallowMultipleComponent]
[AddComponentMenu("Network/NetworkLobbyPlayer")]
public class NetworkLobbyPlayer : NetworkBehaviour
{
[Tooltip("Enable to show the default lobby GUI for this player.")]
[SerializeField] public bool ShowLobbyGUI = true;
byte m_Slot;
bool m_ReadyToBegin;
public byte slot { get { return m_Slot; } set { m_Slot = value; }}
public bool readyToBegin { get { return m_ReadyToBegin; } set { m_ReadyToBegin = value; } }
void Start()
{
DontDestroyOnLoad(gameObject);
}
void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
public override void OnStartClient()
{
var lobby = NetworkManager.singleton as NetworkLobbyManager;
if (lobby)
{
lobby.lobbySlots[m_Slot] = this;
m_ReadyToBegin = false;
OnClientEnterLobby();
}
else
{
Debug.LogError("LobbyPlayer could not find a NetworkLobbyManager. The LobbyPlayer requires a NetworkLobbyManager object to function. Make sure that there is one in the scene.");
}
}
public void SendReadyToBeginMessage()
{
if (LogFilter.logDebug) { Debug.Log("NetworkLobbyPlayer SendReadyToBeginMessage"); }
var lobby = NetworkManager.singleton as NetworkLobbyManager;
if (lobby)
{
var msg = new LobbyReadyToBeginMessage();
msg.slotId = (byte)playerControllerId;
msg.readyState = true;
lobby.client.Send(MsgType.LobbyReadyToBegin, msg);
}
}
public void SendNotReadyToBeginMessage()
{
if (LogFilter.logDebug) { Debug.Log("NetworkLobbyPlayer SendReadyToBeginMessage"); }
var lobby = NetworkManager.singleton as NetworkLobbyManager;
if (lobby)
{
var msg = new LobbyReadyToBeginMessage();
msg.slotId = (byte)playerControllerId;
msg.readyState = false;
lobby.client.Send(MsgType.LobbyReadyToBegin, msg);
}
}
public void SendSceneLoadedMessage()
{
if (LogFilter.logDebug) { Debug.Log("NetworkLobbyPlayer SendSceneLoadedMessage"); }
var lobby = NetworkManager.singleton as NetworkLobbyManager;
if (lobby)
{
var msg = new IntegerMessage(playerControllerId);
lobby.client.Send(MsgType.LobbySceneLoaded, msg);
}
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
var lobby = NetworkManager.singleton as NetworkLobbyManager;
if (lobby)
{
// dont even try this in the startup scene
// Should we check if the LoadSceneMode is Single or Additive??
// Can the lobby scene be loaded Additively??
string loadedSceneName = scene.name;
if (loadedSceneName == lobby.lobbyScene)
{
return;
}
}
if (isLocalPlayer)
{
SendSceneLoadedMessage();
}
}
public void RemovePlayer()
{
if (isLocalPlayer && !m_ReadyToBegin)
{
if (LogFilter.logDebug) { Debug.Log("NetworkLobbyPlayer RemovePlayer"); }
ClientScene.RemovePlayer(GetComponent<NetworkIdentity>().playerControllerId);
}
}
// ------------------------ callbacks ------------------------
public virtual void OnClientEnterLobby()
{
}
public virtual void OnClientExitLobby()
{
}
public virtual void OnClientReady(bool readyState)
{
}
// ------------------------ Custom Serialization ------------------------
public override bool OnSerialize(NetworkWriter writer, bool initialState)
{
// dirty flag
writer.WritePackedUInt32(1);
writer.Write(m_Slot);
writer.Write(m_ReadyToBegin);
return true;
}
public override void OnDeserialize(NetworkReader reader, bool initialState)
{
var dirty = reader.ReadPackedUInt32();
if (dirty == 0)
return;
m_Slot = reader.ReadByte();
m_ReadyToBegin = reader.ReadBoolean();
}
// ------------------------ optional UI ------------------------
void OnGUI()
{
if (!ShowLobbyGUI)
return;
var lobby = NetworkManager.singleton as NetworkLobbyManager;
if (lobby)
{
if (!lobby.showLobbyGUI)
return;
string loadedSceneName = SceneManager.GetSceneAt(0).name;
if (loadedSceneName != lobby.lobbyScene)
return;
}
Rect rec = new Rect(100 + m_Slot * 100, 200, 90, 20);
if (isLocalPlayer)
{
string youStr;
if (m_ReadyToBegin)
{
youStr = "(Ready)";
}
else
{
youStr = "(Not Ready)";
}
GUI.Label(rec, youStr);
if (m_ReadyToBegin)
{
rec.y += 25;
if (GUI.Button(rec, "STOP"))
{
SendNotReadyToBeginMessage();
}
}
else
{
rec.y += 25;
if (GUI.Button(rec, "START"))
{
SendReadyToBeginMessage();
}
rec.y += 25;
if (GUI.Button(rec, "Remove"))
{
ClientScene.RemovePlayer(GetComponent<NetworkIdentity>().playerControllerId);
}
}
}
else
{
GUI.Label(rec, "Player [" + netId + "]");
rec.y += 25;
GUI.Label(rec, "Ready [" + m_ReadyToBegin + "]");
}
}
}
}
#endif // ENABLE_UNET

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,274 @@
using System;
using System.ComponentModel;
#if ENABLE_UNET
namespace UnityEngine.Networking
{
[AddComponentMenu("Network/NetworkManagerHUD")]
[RequireComponent(typeof(NetworkManager))]
[EditorBrowsable(EditorBrowsableState.Never)]
public class NetworkManagerHUD : MonoBehaviour
{
public NetworkManager manager;
[SerializeField] public bool showGUI = true;
[SerializeField] public int offsetX;
[SerializeField] public int offsetY;
// Runtime variable
bool m_ShowServer;
void Awake()
{
manager = GetComponent<NetworkManager>();
}
void Update()
{
if (!showGUI)
return;
if (!manager.IsClientConnected() && !NetworkServer.active && manager.matchMaker == null)
{
if (UnityEngine.Application.platform != RuntimePlatform.WebGLPlayer)
{
if (Input.GetKeyDown(KeyCode.S))
{
manager.StartServer();
}
if (Input.GetKeyDown(KeyCode.H))
{
manager.StartHost();
}
}
if (Input.GetKeyDown(KeyCode.C))
{
manager.StartClient();
}
}
if (NetworkServer.active)
{
if (manager.IsClientConnected())
{
if (Input.GetKeyDown(KeyCode.X))
{
manager.StopHost();
}
}
else
{
if (Input.GetKeyDown(KeyCode.X))
{
manager.StopServer();
}
}
}
}
void OnGUI()
{
if (!showGUI)
return;
int xpos = 10 + offsetX;
int ypos = 40 + offsetY;
const int spacing = 24;
bool noConnection = (manager.client == null || manager.client.connection == null ||
manager.client.connection.connectionId == -1);
if (!manager.IsClientConnected() && !NetworkServer.active && manager.matchMaker == null)
{
if (noConnection)
{
if (UnityEngine.Application.platform != RuntimePlatform.WebGLPlayer)
{
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "LAN Host(H)"))
{
manager.StartHost();
}
ypos += spacing;
}
if (GUI.Button(new Rect(xpos, ypos, 105, 20), "LAN Client(C)"))
{
manager.StartClient();
}
manager.networkAddress = GUI.TextField(new Rect(xpos + 100, ypos, 95, 20), manager.networkAddress);
ypos += spacing;
if (UnityEngine.Application.platform == RuntimePlatform.WebGLPlayer)
{
// cant be a server in webgl build
GUI.Box(new Rect(xpos, ypos, 200, 25), "( WebGL cannot be server )");
ypos += spacing;
}
else
{
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "LAN Server Only(S)"))
{
manager.StartServer();
}
ypos += spacing;
}
}
else
{
GUI.Label(new Rect(xpos, ypos, 200, 20), "Connecting to " + manager.networkAddress + ":" + manager.networkPort + "..");
ypos += spacing;
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Cancel Connection Attempt"))
{
manager.StopClient();
}
}
}
else
{
if (NetworkServer.active)
{
string serverMsg = "Server: port=" + manager.networkPort;
if (manager.useWebSockets)
{
serverMsg += " (Using WebSockets)";
}
GUI.Label(new Rect(xpos, ypos, 300, 20), serverMsg);
ypos += spacing;
}
if (manager.IsClientConnected())
{
GUI.Label(new Rect(xpos, ypos, 300, 20), "Client: address=" + manager.networkAddress + " port=" + manager.networkPort);
ypos += spacing;
}
}
if (manager.IsClientConnected() && !ClientScene.ready)
{
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Client Ready"))
{
ClientScene.Ready(manager.client.connection);
if (ClientScene.localPlayers.Count == 0)
{
ClientScene.AddPlayer(0);
}
}
ypos += spacing;
}
if (NetworkServer.active || manager.IsClientConnected())
{
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Stop (X)"))
{
manager.StopHost();
}
ypos += spacing;
}
if (!NetworkServer.active && !manager.IsClientConnected() && noConnection)
{
ypos += 10;
if (UnityEngine.Application.platform == RuntimePlatform.WebGLPlayer)
{
GUI.Box(new Rect(xpos - 5, ypos, 220, 25), "(WebGL cannot use Match Maker)");
return;
}
if (manager.matchMaker == null)
{
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Enable Match Maker (M)"))
{
manager.StartMatchMaker();
}
ypos += spacing;
}
else
{
if (manager.matchInfo == null)
{
if (manager.matches == null)
{
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Create Internet Match"))
{
manager.matchMaker.CreateMatch(manager.matchName, manager.matchSize, true, "", "", "", 0, 0, manager.OnMatchCreate);
}
ypos += spacing;
GUI.Label(new Rect(xpos, ypos, 100, 20), "Room Name:");
manager.matchName = GUI.TextField(new Rect(xpos + 100, ypos, 100, 20), manager.matchName);
ypos += spacing;
ypos += 10;
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Find Internet Match"))
{
manager.matchMaker.ListMatches(0, 20, "", false, 0, 0, manager.OnMatchList);
}
ypos += spacing;
}
else
{
for (int i = 0; i < manager.matches.Count; i++)
{
var match = manager.matches[i];
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Join Match:" + match.name))
{
manager.matchName = match.name;
manager.matchMaker.JoinMatch(match.networkId, "", "", "", 0, 0, manager.OnMatchJoined);
}
ypos += spacing;
}
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Back to Match Menu"))
{
manager.matches = null;
}
ypos += spacing;
}
}
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Change MM server"))
{
m_ShowServer = !m_ShowServer;
}
if (m_ShowServer)
{
ypos += spacing;
if (GUI.Button(new Rect(xpos, ypos, 100, 20), "Local"))
{
manager.SetMatchHost("localhost", 1337, false);
m_ShowServer = false;
}
ypos += spacing;
if (GUI.Button(new Rect(xpos, ypos, 100, 20), "Internet"))
{
manager.SetMatchHost("mm.unet.unity3d.com", 443, true);
m_ShowServer = false;
}
ypos += spacing;
if (GUI.Button(new Rect(xpos, ypos, 100, 20), "Staging"))
{
manager.SetMatchHost("staging-mm.unet.unity3d.com", 443, true);
m_ShowServer = false;
}
}
ypos += spacing;
GUI.Label(new Rect(xpos, ypos, 300, 20), "MM Uri: " + manager.matchMaker.baseUri);
ypos += spacing;
if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Disable Match Maker"))
{
manager.StopMatchMaker();
}
ypos += spacing;
}
}
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,78 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
namespace UnityEngine.Networking
{
internal class NetworkMessageHandlers
{
Dictionary<short, NetworkMessageDelegate> m_MsgHandlers = new Dictionary<short, NetworkMessageDelegate>();
internal void RegisterHandlerSafe(short msgType, NetworkMessageDelegate handler)
{
if (handler == null)
{
if (LogFilter.logError) { Debug.LogError("RegisterHandlerSafe id:" + msgType + " handler is null"); }
return;
}
if (LogFilter.logDebug) { Debug.Log("RegisterHandlerSafe id:" + msgType + " handler:" + handler.GetMethodName()); }
if (m_MsgHandlers.ContainsKey(msgType))
{
//if (LogFilter.logError) { Debug.LogError("RegisterHandlerSafe id:" + msgType + " handler:" + handler.GetMethodName() + " conflict"); }
return;
}
m_MsgHandlers.Add(msgType, handler);
}
public void RegisterHandler(short msgType, NetworkMessageDelegate handler)
{
if (handler == null)
{
if (LogFilter.logError) { Debug.LogError("RegisterHandler id:" + msgType + " handler is null"); }
return;
}
if (msgType <= MsgType.InternalHighest)
{
if (LogFilter.logError) { Debug.LogError("RegisterHandler: Cannot replace system message handler " + msgType); }
return;
}
if (m_MsgHandlers.ContainsKey(msgType))
{
if (LogFilter.logDebug) { Debug.Log("RegisterHandler replacing " + msgType); }
m_MsgHandlers.Remove(msgType);
}
if (LogFilter.logDebug) { Debug.Log("RegisterHandler id:" + msgType + " handler:" + handler.GetMethodName()); }
m_MsgHandlers.Add(msgType, handler);
}
public void UnregisterHandler(short msgType)
{
m_MsgHandlers.Remove(msgType);
}
internal NetworkMessageDelegate GetHandler(short msgType)
{
if (m_MsgHandlers.ContainsKey(msgType))
{
return m_MsgHandlers[msgType];
}
return null;
}
internal Dictionary<short, NetworkMessageDelegate> GetHandlers()
{
return m_MsgHandlers;
}
internal void ClearMessageHandlers()
{
m_MsgHandlers.Clear();
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,936 @@
#if ENABLE_UNET
#if ENABLE_UNET_HOST_MIGRATION
using System;
using System.Collections.Generic;
using UnityEngine.Networking.Match;
using UnityEngine.Networking.NetworkSystem;
using UnityEngine.Networking.Types;
namespace UnityEngine.Networking
{
[AddComponentMenu("Network/NetworkMigrationManager")]
public class NetworkMigrationManager : MonoBehaviour
{
public enum SceneChangeOption
{
StayInOnlineScene,
SwitchToOfflineScene
}
[SerializeField]
bool m_HostMigration = true;
[SerializeField]
bool m_ShowGUI = true;
[SerializeField]
int m_OffsetX = 10;
[SerializeField]
int m_OffsetY = 300;
NetworkClient m_Client;
bool m_WaitingToBecomeNewHost;
bool m_WaitingReconnectToNewHost;
bool m_DisconnectedFromHost;
bool m_HostWasShutdown;
MatchInfo m_MatchInfo;
int m_OldServerConnectionId = -1;
string m_NewHostAddress;
PeerInfoMessage m_NewHostInfo = new PeerInfoMessage();
PeerListMessage m_PeerListMessage = new PeerListMessage();
PeerInfoMessage[] m_Peers;
// There can be multiple pending players for a connectionId, distinguished by oldNetId/playerControllerId
public struct PendingPlayerInfo
{
public NetworkInstanceId netId;
public short playerControllerId;
public GameObject obj;
}
public struct ConnectionPendingPlayers
{
public List<PendingPlayerInfo> players;
}
Dictionary<int, ConnectionPendingPlayers> m_PendingPlayers = new Dictionary<int, ConnectionPendingPlayers>();
void AddPendingPlayer(GameObject obj, int connectionId, NetworkInstanceId netId, short playerControllerId)
{
if (!m_PendingPlayers.ContainsKey(connectionId))
{
var pending = new ConnectionPendingPlayers();
pending.players = new List<PendingPlayerInfo>();
m_PendingPlayers[connectionId] = pending;
}
PendingPlayerInfo info = new PendingPlayerInfo();
info.netId = netId;
info.playerControllerId = playerControllerId;
info.obj = obj;
m_PendingPlayers[connectionId].players.Add(info);
}
GameObject FindPendingPlayer(int connectionId, NetworkInstanceId netId, short playerControllerId)
{
if (m_PendingPlayers.ContainsKey(connectionId))
{
for (int i = 0; i < m_PendingPlayers[connectionId].players.Count; i++)
{
var info = m_PendingPlayers[connectionId].players[i];
if (info.netId == netId && info.playerControllerId == playerControllerId)
{
return info.obj;
}
}
}
return null;
}
void RemovePendingPlayer(int connectionId)
{
m_PendingPlayers.Remove(connectionId);
}
public bool hostMigration
{
get { return m_HostMigration; }
set { m_HostMigration = value; }
}
public bool showGUI
{
get { return m_ShowGUI; }
set { m_ShowGUI = value; }
}
public int offsetX
{
get { return m_OffsetX; }
set { m_OffsetX = value; }
}
public int offsetY
{
get { return m_OffsetY; }
set { m_OffsetY = value; }
}
public NetworkClient client
{
get { return m_Client; }
}
public bool waitingToBecomeNewHost
{
get { return m_WaitingToBecomeNewHost; }
set { m_WaitingToBecomeNewHost = value; }
}
public bool waitingReconnectToNewHost
{
get { return m_WaitingReconnectToNewHost; }
set { m_WaitingReconnectToNewHost = value; }
}
public bool disconnectedFromHost
{
get { return m_DisconnectedFromHost; }
}
public bool hostWasShutdown
{
get { return m_HostWasShutdown; }
}
public MatchInfo matchInfo
{
get { return m_MatchInfo; }
}
public int oldServerConnectionId
{
get { return m_OldServerConnectionId; }
}
public string newHostAddress
{
get { return m_NewHostAddress; }
set { m_NewHostAddress = value; }
}
public PeerInfoMessage[] peers
{
get { return m_Peers; }
}
public Dictionary<int, ConnectionPendingPlayers> pendingPlayers
{
get { return m_PendingPlayers; }
}
void Start()
{
Reset(ClientScene.ReconnectIdInvalid);
}
public void Reset(int reconnectId)
{
m_OldServerConnectionId = -1;
m_WaitingToBecomeNewHost = false;
m_WaitingReconnectToNewHost = false;
m_DisconnectedFromHost = false;
m_HostWasShutdown = false;
ClientScene.SetReconnectId(reconnectId, m_Peers);
if (NetworkManager.singleton != null)
{
NetworkManager.singleton.SetupMigrationManager(this);
}
}
internal void AssignAuthorityCallback(NetworkConnection conn, NetworkIdentity uv, bool authorityState)
{
var msg = new PeerAuthorityMessage();
msg.connectionId = conn.connectionId;
msg.netId = uv.netId;
msg.authorityState = authorityState;
if (LogFilter.logDebug) { Debug.Log("AssignAuthorityCallback send for netId" + uv.netId); }
for (int i = 0; i < NetworkServer.connections.Count; i++)
{
var c = NetworkServer.connections[i];
if (c != null)
{
c.Send(MsgType.PeerClientAuthority, msg);
}
}
}
public void Initialize(NetworkClient newClient, MatchInfo newMatchInfo)
{
if (LogFilter.logDev) { Debug.Log("NetworkMigrationManager initialize"); }
m_Client = newClient;
m_MatchInfo = newMatchInfo;
newClient.RegisterHandlerSafe(MsgType.NetworkInfo, OnPeerInfo);
newClient.RegisterHandlerSafe(MsgType.PeerClientAuthority, OnPeerClientAuthority);
NetworkIdentity.clientAuthorityCallback = AssignAuthorityCallback;
}
public void DisablePlayerObjects()
{
if (LogFilter.logDev) { Debug.Log("NetworkMigrationManager DisablePlayerObjects"); }
if (m_Peers == null)
return;
for (int peerId = 0; peerId < m_Peers.Length; peerId++)
{
var peer = m_Peers[peerId];
if (peer.playerIds != null)
{
for (int i = 0; i < peer.playerIds.Length; i++)
{
var info = peer.playerIds[i];
if (LogFilter.logDev) { Debug.Log("DisablePlayerObjects disable player for " + peer.address + " netId:" + info.netId + " control:" + info.playerControllerId); }
GameObject playerObj = ClientScene.FindLocalObject(info.netId);
if (playerObj != null)
{
playerObj.SetActive(false);
AddPendingPlayer(playerObj, peer.connectionId, info.netId, info.playerControllerId);
}
else
{
if (LogFilter.logWarn) { Debug.LogWarning("DisablePlayerObjects didnt find player Conn:" + peer.connectionId + " NetId:" + info.netId); }
}
}
}
}
}
public void SendPeerInfo()
{
if (!m_HostMigration)
return;
var listMsg = new PeerListMessage();
var addresses = new List<PeerInfoMessage>();
for (int i = 0; i < NetworkServer.connections.Count; i++)
{
var conn = NetworkServer.connections[i];
if (conn != null)
{
var peerInfo = new PeerInfoMessage();
string address;
int port;
NetworkID networkId;
NodeID node;
byte error2;
NetworkTransport.GetConnectionInfo(NetworkServer.serverHostId, conn.connectionId, out address, out port, out networkId, out node, out error2);
peerInfo.connectionId = conn.connectionId;
peerInfo.port = port;
if (i == 0)
{
peerInfo.port = NetworkServer.listenPort;
peerInfo.isHost = true;
peerInfo.address = "<host>";
}
else
{
peerInfo.address = address;
peerInfo.isHost = false;
}
var playerIds = new List<PeerInfoPlayer>();
for (int pid = 0; pid < conn.playerControllers.Count; pid++)
{
var player = conn.playerControllers[pid];
if (player != null && player.unetView != null)
{
PeerInfoPlayer info;
info.netId = player.unetView.netId;
info.playerControllerId = player.unetView.playerControllerId;
playerIds.Add(info);
}
}
if (conn.clientOwnedObjects != null)
{
foreach (var netId in conn.clientOwnedObjects)
{
var obj = NetworkServer.FindLocalObject(netId);
if (obj == null)
continue;
var objUV = obj.GetComponent<NetworkIdentity>();
if (objUV.playerControllerId != -1)
{
// already added players
continue;
}
PeerInfoPlayer info;
info.netId = netId;
info.playerControllerId = -1;
playerIds.Add(info);
}
}
if (playerIds.Count > 0)
{
peerInfo.playerIds = playerIds.ToArray();
}
addresses.Add(peerInfo);
}
}
listMsg.peers = addresses.ToArray();
// (re)send all peers to all peers (including the new one)
for (int i = 0; i < NetworkServer.connections.Count; i++)
{
var conn = NetworkServer.connections[i];
if (conn != null)
{
listMsg.oldServerConnectionId = conn.connectionId;
conn.Send(MsgType.NetworkInfo, listMsg);
}
}
}
// received on both host and clients
void OnPeerClientAuthority(NetworkMessage netMsg)
{
var msg = netMsg.ReadMessage<PeerAuthorityMessage>();
if (LogFilter.logDebug) { Debug.Log("OnPeerClientAuthority for netId:" + msg.netId); }
if (m_Peers == null)
{
// havent received peers yet. just ignore this. the peer list will contain this data.
return;
}
// find the peer for connId
for (int peerId = 0; peerId < m_Peers.Length; peerId++)
{
var p = m_Peers[peerId];
if (p.connectionId == msg.connectionId)
{
if (p.playerIds == null)
{
p.playerIds = new PeerInfoPlayer[0];
}
if (msg.authorityState)
{
for (int i = 0; i < p.playerIds.Length; i++)
{
if (p.playerIds[i].netId == msg.netId)
{
// already in list
return;
}
}
var newPlayerId = new PeerInfoPlayer();
newPlayerId.netId = msg.netId;
newPlayerId.playerControllerId = -1;
var pl = new List<PeerInfoPlayer>(p.playerIds);
pl.Add(newPlayerId);
p.playerIds = pl.ToArray();
}
else
{
for (int i = 0; i < p.playerIds.Length; i++)
{
if (p.playerIds[i].netId == msg.netId)
{
var pl = new List<PeerInfoPlayer>(p.playerIds);
pl.RemoveAt(i);
p.playerIds = pl.ToArray();
break;
}
}
}
}
}
var foundObj = ClientScene.FindLocalObject(msg.netId);
OnAuthorityUpdated(foundObj, msg.connectionId, msg.authorityState);
}
// recieved on both host and clients
void OnPeerInfo(NetworkMessage netMsg)
{
if (LogFilter.logDebug) { Debug.Log("OnPeerInfo"); }
netMsg.ReadMessage(m_PeerListMessage);
m_Peers = m_PeerListMessage.peers;
m_OldServerConnectionId = m_PeerListMessage.oldServerConnectionId;
for (int i = 0; i < m_Peers.Length; i++)
{
if (LogFilter.logDebug) { Debug.Log("peer conn " + m_Peers[i].connectionId + " your conn " + m_PeerListMessage.oldServerConnectionId); }
if (m_Peers[i].connectionId == m_PeerListMessage.oldServerConnectionId)
{
m_Peers[i].isYou = true;
break;
}
}
OnPeersUpdated(m_PeerListMessage);
}
void OnServerReconnectPlayerMessage(NetworkMessage netMsg)
{
var msg = netMsg.ReadMessage<ReconnectMessage>();
if (LogFilter.logDev) { Debug.Log("OnReconnectMessage: connId=" + msg.oldConnectionId + " playerControllerId:" + msg.playerControllerId + " netId:" + msg.netId); }
var playerObject = FindPendingPlayer(msg.oldConnectionId, msg.netId, msg.playerControllerId);
if (playerObject == null)
{
if (LogFilter.logError) { Debug.LogError("OnReconnectMessage connId=" + msg.oldConnectionId + " player null for netId:" + msg.netId + " msg.playerControllerId:" + msg.playerControllerId); }
return;
}
if (playerObject.activeSelf)
{
if (LogFilter.logError) { Debug.LogError("OnReconnectMessage connId=" + msg.oldConnectionId + " player already active?"); }
return;
}
if (LogFilter.logDebug) { Debug.Log("OnReconnectMessage: player=" + playerObject); }
NetworkReader extraDataReader = null;
if (msg.msgSize != 0)
{
extraDataReader = new NetworkReader(msg.msgData);
}
if (msg.playerControllerId != -1)
{
if (extraDataReader == null)
{
OnServerReconnectPlayer(netMsg.conn, playerObject, msg.oldConnectionId, msg.playerControllerId);
}
else
{
OnServerReconnectPlayer(netMsg.conn, playerObject, msg.oldConnectionId, msg.playerControllerId, extraDataReader);
}
}
else
{
OnServerReconnectObject(netMsg.conn, playerObject, msg.oldConnectionId);
}
}
// call this on the server to re-setup an object for a new connection
public bool ReconnectObjectForConnection(NetworkConnection newConnection, GameObject oldObject, int oldConnectionId)
{
if (!NetworkServer.active)
{
if (LogFilter.logError) { Debug.LogError("ReconnectObjectForConnection must have active server"); }
return false;
}
if (LogFilter.logDebug) { Debug.Log("ReconnectObjectForConnection: oldConnId=" + oldConnectionId + " obj=" + oldObject + " conn:" + newConnection); }
if (!m_PendingPlayers.ContainsKey(oldConnectionId))
{
if (LogFilter.logError) { Debug.LogError("ReconnectObjectForConnection oldConnId=" + oldConnectionId + " not found."); }
return false;
}
oldObject.SetActive(true);
oldObject.GetComponent<NetworkIdentity>().SetNetworkInstanceId(new NetworkInstanceId(0));
if (!NetworkServer.SpawnWithClientAuthority(oldObject, newConnection))
{
if (LogFilter.logError) { Debug.LogError("ReconnectObjectForConnection oldConnId=" + oldConnectionId + " SpawnWithClientAuthority failed."); }
return false;
}
return true;
}
// call this on the server to re-setup a reconnecting player for a new connection
public bool ReconnectPlayerForConnection(NetworkConnection newConnection, GameObject oldPlayer, int oldConnectionId, short playerControllerId)
{
if (!NetworkServer.active)
{
if (LogFilter.logError) { Debug.LogError("ReconnectPlayerForConnection must have active server"); }
return false;
}
if (LogFilter.logDebug) { Debug.Log("ReconnectPlayerForConnection: oldConnId=" + oldConnectionId + " player=" + oldPlayer + " conn:" + newConnection); }
if (!m_PendingPlayers.ContainsKey(oldConnectionId))
{
if (LogFilter.logError) { Debug.LogError("ReconnectPlayerForConnection oldConnId=" + oldConnectionId + " not found."); }
return false;
}
oldPlayer.SetActive(true);
// this ensures the observers are rebuilt for the player object
NetworkServer.Spawn(oldPlayer);
if (!NetworkServer.AddPlayerForConnection(newConnection, oldPlayer, playerControllerId))
{
if (LogFilter.logError) { Debug.LogError("ReconnectPlayerForConnection oldConnId=" + oldConnectionId + " AddPlayerForConnection failed."); }
return false;
}
//NOTE. cannot remove the pending player here - could be more owned objects to come in later messages.
if (NetworkServer.localClientActive)
{
SendPeerInfo();
}
return true;
}
// called by NetworkManager on clients when connection to host is lost.
// return true to stay in online scene
public bool LostHostOnClient(NetworkConnection conn)
{
if (LogFilter.logDebug) { Debug.Log("NetworkMigrationManager client OnDisconnectedFromHost"); }
if (UnityEngine.Application.platform == RuntimePlatform.WebGLPlayer)
{
if (LogFilter.logError) { Debug.LogError("LostHostOnClient: Host migration not supported on WebGL"); }
return false;
}
if (m_Client == null)
{
if (LogFilter.logError) { Debug.LogError("NetworkMigrationManager LostHostOnHost client was never initialized."); }
return false;
}
if (!m_HostMigration)
{
if (LogFilter.logError) { Debug.LogError("NetworkMigrationManager LostHostOnHost migration not enabled."); }
return false;
}
m_DisconnectedFromHost = true;
DisablePlayerObjects();
byte error;
NetworkTransport.Disconnect(m_Client.hostId, m_Client.connection.connectionId, out error);
if (m_OldServerConnectionId != -1)
{
// only call this if we actually connected
SceneChangeOption sceneOption;
OnClientDisconnectedFromHost(conn, out sceneOption);
return sceneOption == SceneChangeOption.StayInOnlineScene;
}
// never entered the online scene
return false;
}
// called by NetworkManager on host when host is closed
public void LostHostOnHost()
{
if (LogFilter.logDebug) { Debug.Log("NetworkMigrationManager LostHostOnHost"); }
if (UnityEngine.Application.platform == RuntimePlatform.WebGLPlayer)
{
if (LogFilter.logError) { Debug.LogError("LostHostOnHost: Host migration not supported on WebGL"); }
return;
}
OnServerHostShutdown();
if (m_Peers == null)
{
if (LogFilter.logError) { Debug.LogError("NetworkMigrationManager LostHostOnHost no peers"); }
return;
}
if (m_Peers.Length != 1)
{
// there was another player that could become the host
m_HostWasShutdown = true;
}
}
public bool BecomeNewHost(int port)
{
if (LogFilter.logDebug) { Debug.Log("NetworkMigrationManager BecomeNewHost " + m_MatchInfo); }
NetworkServer.RegisterHandler(MsgType.ReconnectPlayer, OnServerReconnectPlayerMessage);
var newClient = NetworkServer.BecomeHost(m_Client, port, m_MatchInfo, oldServerConnectionId, peers);
if (newClient != null)
{
if (NetworkManager.singleton != null)
{
NetworkManager.singleton.RegisterServerMessages();
NetworkManager.singleton.UseExternalClient(newClient);
}
else
{
Debug.LogWarning("MigrationManager BecomeNewHost - No NetworkManager.");
}
newClient.RegisterHandlerSafe(MsgType.NetworkInfo, OnPeerInfo);
RemovePendingPlayer(m_OldServerConnectionId);
Reset(ClientScene.ReconnectIdInvalid);
SendPeerInfo();
return true;
}
else
{
if (LogFilter.logError) { Debug.LogError("NetworkServer.BecomeHost failed"); }
return false;
}
}
// ----------------------------- Callbacks ---------------------------------------
// called on client after the connection to host is lost. controls whether to switch scenes
protected virtual void OnClientDisconnectedFromHost(NetworkConnection conn, out SceneChangeOption sceneChange)
{
sceneChange = SceneChangeOption.StayInOnlineScene;
}
// called on host after the host is lost. host MUST change scenes
protected virtual void OnServerHostShutdown()
{
}
// called on new host (server) when a client from the old host re-connects a player
protected virtual void OnServerReconnectPlayer(NetworkConnection newConnection, GameObject oldPlayer, int oldConnectionId, short playerControllerId)
{
ReconnectPlayerForConnection(newConnection, oldPlayer, oldConnectionId, playerControllerId);
}
// called on new host (server) when a client from the old host re-connects a player
protected virtual void OnServerReconnectPlayer(NetworkConnection newConnection, GameObject oldPlayer, int oldConnectionId, short playerControllerId, NetworkReader extraMessageReader)
{
// extraMessageReader is not used in the default version, but it is available for custom versions to use
ReconnectPlayerForConnection(newConnection, oldPlayer, oldConnectionId, playerControllerId);
}
// called on new host (server) when a client from the old host re-connects an object with authority
protected virtual void OnServerReconnectObject(NetworkConnection newConnection, GameObject oldObject, int oldConnectionId)
{
ReconnectObjectForConnection(newConnection, oldObject, oldConnectionId);
}
// called on both host and client when the set of peers is updated
protected virtual void OnPeersUpdated(PeerListMessage peers)
{
if (LogFilter.logDev) { Debug.Log("NetworkMigrationManager NumPeers " + peers.peers.Length); }
}
// called on both host and client when authority changes on a non-player object
protected virtual void OnAuthorityUpdated(GameObject go, int connectionId, bool authorityState)
{
if (LogFilter.logDev) { Debug.Log("NetworkMigrationManager OnAuthorityUpdated for " + go + " conn:" + connectionId + " state:" + authorityState); }
}
// utility function called by the default UI on client after connection to host was lost, to pick a new host.
public virtual bool FindNewHost(out NetworkSystem.PeerInfoMessage newHostInfo, out bool youAreNewHost)
{
if (m_Peers == null)
{
if (LogFilter.logError) { Debug.LogError("NetworkMigrationManager FindLowestHost no peers"); }
newHostInfo = null;
youAreNewHost = false;
return false;
}
if (LogFilter.logDev) { Debug.Log("NetworkMigrationManager FindLowestHost"); }
const int k_FakeConnectionId = 50000;
newHostInfo = new PeerInfoMessage();
newHostInfo.connectionId = k_FakeConnectionId;
newHostInfo.address = "";
newHostInfo.port = 0;
int yourConnectionId = -1;
youAreNewHost = false;
if (m_Peers == null)
return false;
for (int peerId = 0; peerId < m_Peers.Length; peerId++)
{
var peer = m_Peers[peerId];
if (peer.connectionId == 0)
{
continue;
}
if (peer.isHost)
{
continue;
}
if (peer.isYou)
{
yourConnectionId = peer.connectionId;
}
if (peer.connectionId < newHostInfo.connectionId)
{
newHostInfo = peer;
}
}
if (newHostInfo.connectionId == k_FakeConnectionId)
{
return false;
}
if (newHostInfo.connectionId == yourConnectionId)
{
youAreNewHost = true;
}
if (LogFilter.logDev) { Debug.Log("FindNewHost new host is " + newHostInfo.address); }
return true;
}
// ----------------------------- GUI ---------------------------------------
void OnGUIHost()
{
int ypos = m_OffsetY;
const int spacing = 25;
GUI.Label(new Rect(m_OffsetX, ypos, 200, 40), "Host Was Shutdown ID(" + m_OldServerConnectionId + ")");
ypos += spacing;
if (UnityEngine.Application.platform == RuntimePlatform.WebGLPlayer)
{
GUI.Label(new Rect(m_OffsetX, ypos, 200, 40), "Host Migration not supported for WebGL");
return;
}
if (m_WaitingReconnectToNewHost)
{
if (GUI.Button(new Rect(m_OffsetX, ypos, 200, 20), "Reconnect as Client"))
{
Reset(ClientScene.ReconnectIdHost);
if (NetworkManager.singleton != null)
{
NetworkManager.singleton.networkAddress = GUI.TextField(new Rect(m_OffsetX + 100, ypos, 95, 20), NetworkManager.singleton.networkAddress);
NetworkManager.singleton.StartClient();
}
else
{
Debug.LogWarning("MigrationManager Old Host Reconnect - No NetworkManager.");
}
}
ypos += spacing;
}
else
{
if (GUI.Button(new Rect(m_OffsetX, ypos, 200, 20), "Pick New Host"))
{
bool youAreNewHost;
if (FindNewHost(out m_NewHostInfo, out youAreNewHost))
{
m_NewHostAddress = m_NewHostInfo.address;
if (youAreNewHost)
{
// you cannot be the new host.. you were the old host..?
Debug.LogWarning("MigrationManager FindNewHost - new host is self?");
}
else
{
m_WaitingReconnectToNewHost = true;
}
}
}
ypos += spacing;
}
if (GUI.Button(new Rect(m_OffsetX, ypos, 200, 20), "Leave Game"))
{
if (NetworkManager.singleton != null)
{
NetworkManager.singleton.SetupMigrationManager(null);
NetworkManager.singleton.StopHost();
}
else
{
Debug.LogWarning("MigrationManager Old Host LeaveGame - No NetworkManager.");
}
Reset(ClientScene.ReconnectIdInvalid);
}
ypos += spacing;
}
void OnGUIClient()
{
int ypos = m_OffsetY;
const int spacing = 25;
GUI.Label(new Rect(m_OffsetX, ypos, 200, 40), "Lost Connection To Host ID(" + m_OldServerConnectionId + ")");
ypos += spacing;
if (UnityEngine.Application.platform == RuntimePlatform.WebGLPlayer)
{
GUI.Label(new Rect(m_OffsetX, ypos, 200, 40), "Host Migration not supported for WebGL");
return;
}
if (m_WaitingToBecomeNewHost)
{
GUI.Label(new Rect(m_OffsetX, ypos, 200, 40), "You are the new host");
ypos += spacing;
if (GUI.Button(new Rect(m_OffsetX, ypos, 200, 20), "Start As Host"))
{
if (NetworkManager.singleton != null)
{
BecomeNewHost(NetworkManager.singleton.networkPort);
}
else
{
Debug.LogWarning("MigrationManager Client BecomeNewHost - No NetworkManager.");
}
}
ypos += spacing;
}
else if (m_WaitingReconnectToNewHost)
{
GUI.Label(new Rect(m_OffsetX, ypos, 200, 40), "New host is " + m_NewHostAddress);
ypos += spacing;
if (GUI.Button(new Rect(m_OffsetX, ypos, 200, 20), "Reconnect To New Host"))
{
Reset(m_OldServerConnectionId);
if (NetworkManager.singleton != null)
{
NetworkManager.singleton.networkAddress = m_NewHostAddress;
NetworkManager.singleton.client.ReconnectToNewHost(m_NewHostAddress, NetworkManager.singleton.networkPort);
}
else
{
Debug.LogWarning("MigrationManager Client reconnect - No NetworkManager.");
}
}
ypos += spacing;
}
else
{
if (GUI.Button(new Rect(m_OffsetX, ypos, 200, 20), "Pick New Host"))
{
bool youAreNewHost;
if (FindNewHost(out m_NewHostInfo, out youAreNewHost))
{
m_NewHostAddress = m_NewHostInfo.address;
if (youAreNewHost)
{
m_WaitingToBecomeNewHost = true;
}
else
{
m_WaitingReconnectToNewHost = true;
}
}
}
ypos += spacing;
}
if (GUI.Button(new Rect(m_OffsetX, ypos, 200, 20), "Leave Game"))
{
if (NetworkManager.singleton != null)
{
NetworkManager.singleton.SetupMigrationManager(null);
NetworkManager.singleton.StopHost();
}
else
{
Debug.LogWarning("MigrationManager Client LeaveGame - No NetworkManager.");
}
Reset(ClientScene.ReconnectIdInvalid);
}
ypos += spacing;
}
void OnGUI()
{
if (!m_ShowGUI)
return;
if (m_HostWasShutdown)
{
OnGUIHost();
return;
}
if (m_DisconnectedFromHost && m_OldServerConnectionId != -1)
{
OnGUIClient();
}
}
}
}
#endif
#endif

View File

@ -0,0 +1,139 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEngine.Networking
{
[AddComponentMenu("Network/NetworkProximityChecker")]
[RequireComponent(typeof(NetworkIdentity))]
public class NetworkProximityChecker : NetworkBehaviour
{
public enum CheckMethod
{
Physics3D,
Physics2D
};
[TooltipAttribute("The maximum range that objects will be visible at.")]
public int visRange = 10;
[TooltipAttribute("How often (in seconds) that this object should update the set of players that can see it.")]
public float visUpdateInterval = 1.0f; // in seconds
[TooltipAttribute("Which method to use for checking proximity of players.\n\nPhysics3D uses 3D physics to determine proximity.\n\nPhysics2D uses 2D physics to determine proximity.")]
public CheckMethod checkMethod = CheckMethod.Physics3D;
[TooltipAttribute("Enable to force this object to be hidden from players.")]
public bool forceHidden = false;
float m_VisUpdateTime;
void Update()
{
if (!NetworkServer.active)
return;
if (Time.time - m_VisUpdateTime > visUpdateInterval)
{
GetComponent<NetworkIdentity>().RebuildObservers(false);
m_VisUpdateTime = Time.time;
}
}
// called when a new player enters
public override bool OnCheckObserver(NetworkConnection newObserver)
{
if (forceHidden)
return false;
// this cant use newObserver.playerControllers[0]. must iterate to find a valid player.
GameObject player = null;
for (int i = 0; i < newObserver.playerControllers.Count; i++)
{
var p = newObserver.playerControllers[i];
if (p != null && p.gameObject != null)
{
player = p.gameObject;
break;
}
}
if (player == null)
return false;
var pos = player.transform.position;
return (pos - transform.position).magnitude < visRange;
}
public override bool OnRebuildObservers(HashSet<NetworkConnection> observers, bool initial)
{
if (forceHidden)
{
// ensure player can still see themself
var uv = GetComponent<NetworkIdentity>();
if (uv.connectionToClient != null)
{
observers.Add(uv.connectionToClient);
}
return true;
}
// find players within range
switch (checkMethod)
{
case CheckMethod.Physics3D:
{
var hits = Physics.OverlapSphere(transform.position, visRange);
for (int i = 0; i < hits.Length; i++)
{
var hit = hits[i];
// (if an object has a connectionToClient, it is a player)
var uv = hit.GetComponent<NetworkIdentity>();
if (uv != null && uv.connectionToClient != null)
{
observers.Add(uv.connectionToClient);
}
}
return true;
}
case CheckMethod.Physics2D:
{
var hits = Physics2D.OverlapCircleAll(transform.position, visRange);
for (int i = 0; i < hits.Length; i++)
{
var hit = hits[i];
// (if an object has a connectionToClient, it is a player)
var uv = hit.GetComponent<NetworkIdentity>();
if (uv != null && uv.connectionToClient != null)
{
observers.Add(uv.connectionToClient);
}
}
return true;
}
}
return false;
}
// called hiding and showing objects on the host
public override void OnSetLocalVisibility(bool vis)
{
SetVis(gameObject, vis);
}
static void SetVis(GameObject go, bool vis)
{
foreach (var r in go.GetComponents<Renderer>())
{
r.enabled = vis;
}
for (int i = 0; i < go.transform.childCount; i++)
{
var t = go.transform.GetChild(i);
SetVis(t.gameObject, vis);
}
}
}
}
#endif

View File

@ -0,0 +1,510 @@
#if ENABLE_UNET
using System;
using System.Text;
using UnityEngine;
namespace UnityEngine.Networking
{
public class NetworkReader
{
NetBuffer m_buf;
const int k_MaxStringLength = 1024 * 32;
const int k_InitialStringBufferSize = 1024;
static byte[] s_StringReaderBuffer;
static Encoding s_Encoding;
public NetworkReader()
{
m_buf = new NetBuffer();
Initialize();
}
public NetworkReader(NetworkWriter writer)
{
m_buf = new NetBuffer(writer.AsArray());
Initialize();
}
public NetworkReader(byte[] buffer)
{
m_buf = new NetBuffer(buffer);
Initialize();
}
static void Initialize()
{
if (s_Encoding == null)
{
s_StringReaderBuffer = new byte[k_InitialStringBufferSize];
s_Encoding = new UTF8Encoding();
}
}
public uint Position { get { return m_buf.Position; } }
public int Length { get { return m_buf.Length; } }
public void SeekZero()
{
m_buf.SeekZero();
}
internal void Replace(byte[] buffer)
{
m_buf.Replace(buffer);
}
// http://sqlite.org/src4/doc/trunk/www/varint.wiki
// NOTE: big endian.
public UInt32 ReadPackedUInt32()
{
byte a0 = ReadByte();
if (a0 < 241)
{
return a0;
}
byte a1 = ReadByte();
if (a0 >= 241 && a0 <= 248)
{
return (UInt32)(240 + 256 * (a0 - 241) + a1);
}
byte a2 = ReadByte();
if (a0 == 249)
{
return (UInt32)(2288 + 256 * a1 + a2);
}
byte a3 = ReadByte();
if (a0 == 250)
{
return a1 + (((UInt32)a2) << 8) + (((UInt32)a3) << 16);
}
byte a4 = ReadByte();
if (a0 >= 251)
{
return a1 + (((UInt32)a2) << 8) + (((UInt32)a3) << 16) + (((UInt32)a4) << 24);
}
throw new IndexOutOfRangeException("ReadPackedUInt32() failure: " + a0);
}
public UInt64 ReadPackedUInt64()
{
byte a0 = ReadByte();
if (a0 < 241)
{
return a0;
}
byte a1 = ReadByte();
if (a0 >= 241 && a0 <= 248)
{
return 240 + 256 * (a0 - ((UInt64)241)) + a1;
}
byte a2 = ReadByte();
if (a0 == 249)
{
return 2288 + (((UInt64)256) * a1) + a2;
}
byte a3 = ReadByte();
if (a0 == 250)
{
return a1 + (((UInt64)a2) << 8) + (((UInt64)a3) << 16);
}
byte a4 = ReadByte();
if (a0 == 251)
{
return a1 + (((UInt64)a2) << 8) + (((UInt64)a3) << 16) + (((UInt64)a4) << 24);
}
byte a5 = ReadByte();
if (a0 == 252)
{
return a1 + (((UInt64)a2) << 8) + (((UInt64)a3) << 16) + (((UInt64)a4) << 24) + (((UInt64)a5) << 32);
}
byte a6 = ReadByte();
if (a0 == 253)
{
return a1 + (((UInt64)a2) << 8) + (((UInt64)a3) << 16) + (((UInt64)a4) << 24) + (((UInt64)a5) << 32) + (((UInt64)a6) << 40);
}
byte a7 = ReadByte();
if (a0 == 254)
{
return a1 + (((UInt64)a2) << 8) + (((UInt64)a3) << 16) + (((UInt64)a4) << 24) + (((UInt64)a5) << 32) + (((UInt64)a6) << 40) + (((UInt64)a7) << 48);
}
byte a8 = ReadByte();
if (a0 == 255)
{
return a1 + (((UInt64)a2) << 8) + (((UInt64)a3) << 16) + (((UInt64)a4) << 24) + (((UInt64)a5) << 32) + (((UInt64)a6) << 40) + (((UInt64)a7) << 48) + (((UInt64)a8) << 56);
}
throw new IndexOutOfRangeException("ReadPackedUInt64() failure: " + a0);
}
public NetworkInstanceId ReadNetworkId()
{
return new NetworkInstanceId(ReadPackedUInt32());
}
public NetworkSceneId ReadSceneId()
{
return new NetworkSceneId(ReadPackedUInt32());
}
public byte ReadByte()
{
return m_buf.ReadByte();
}
public sbyte ReadSByte()
{
return (sbyte)m_buf.ReadByte();
}
public short ReadInt16()
{
ushort value = 0;
value |= m_buf.ReadByte();
value |= (ushort)(m_buf.ReadByte() << 8);
return (short)value;
}
public ushort ReadUInt16()
{
ushort value = 0;
value |= m_buf.ReadByte();
value |= (ushort)(m_buf.ReadByte() << 8);
return value;
}
public int ReadInt32()
{
uint value = 0;
value |= m_buf.ReadByte();
value |= (uint)(m_buf.ReadByte() << 8);
value |= (uint)(m_buf.ReadByte() << 16);
value |= (uint)(m_buf.ReadByte() << 24);
return (int)value;
}
public uint ReadUInt32()
{
uint value = 0;
value |= m_buf.ReadByte();
value |= (uint)(m_buf.ReadByte() << 8);
value |= (uint)(m_buf.ReadByte() << 16);
value |= (uint)(m_buf.ReadByte() << 24);
return value;
}
public long ReadInt64()
{
ulong value = 0;
ulong other = m_buf.ReadByte();
value |= other;
other = ((ulong)m_buf.ReadByte()) << 8;
value |= other;
other = ((ulong)m_buf.ReadByte()) << 16;
value |= other;
other = ((ulong)m_buf.ReadByte()) << 24;
value |= other;
other = ((ulong)m_buf.ReadByte()) << 32;
value |= other;
other = ((ulong)m_buf.ReadByte()) << 40;
value |= other;
other = ((ulong)m_buf.ReadByte()) << 48;
value |= other;
other = ((ulong)m_buf.ReadByte()) << 56;
value |= other;
return (long)value;
}
public ulong ReadUInt64()
{
ulong value = 0;
ulong other = m_buf.ReadByte();
value |= other;
other = ((ulong)m_buf.ReadByte()) << 8;
value |= other;
other = ((ulong)m_buf.ReadByte()) << 16;
value |= other;
other = ((ulong)m_buf.ReadByte()) << 24;
value |= other;
other = ((ulong)m_buf.ReadByte()) << 32;
value |= other;
other = ((ulong)m_buf.ReadByte()) << 40;
value |= other;
other = ((ulong)m_buf.ReadByte()) << 48;
value |= other;
other = ((ulong)m_buf.ReadByte()) << 56;
value |= other;
return value;
}
public decimal ReadDecimal()
{
Int32[] bits = new Int32[4];
bits[0] = ReadInt32();
bits[1] = ReadInt32();
bits[2] = ReadInt32();
bits[3] = ReadInt32();
return new decimal(bits);
}
public float ReadSingle()
{
uint value = ReadUInt32();
return FloatConversion.ToSingle(value);
}
public double ReadDouble()
{
ulong value = ReadUInt64();
return FloatConversion.ToDouble(value);
}
public string ReadString()
{
UInt16 numBytes = ReadUInt16();
if (numBytes == 0)
return "";
if (numBytes >= k_MaxStringLength)
{
throw new IndexOutOfRangeException("ReadString() too long: " + numBytes);
}
while (numBytes > s_StringReaderBuffer.Length)
{
s_StringReaderBuffer = new byte[s_StringReaderBuffer.Length * 2];
}
m_buf.ReadBytes(s_StringReaderBuffer, numBytes);
char[] chars = s_Encoding.GetChars(s_StringReaderBuffer, 0, numBytes);
return new string(chars);
}
public char ReadChar()
{
return (char)m_buf.ReadByte();
}
public bool ReadBoolean()
{
int value = m_buf.ReadByte();
return value == 1;
}
public byte[] ReadBytes(int count)
{
if (count < 0)
{
throw new IndexOutOfRangeException("NetworkReader ReadBytes " + count);
}
byte[] value = new byte[count];
m_buf.ReadBytes(value, (uint)count);
return value;
}
public byte[] ReadBytesAndSize()
{
ushort sz = ReadUInt16();
if (sz == 0)
return new byte[0];
return ReadBytes(sz);
}
public Vector2 ReadVector2()
{
return new Vector2(ReadSingle(), ReadSingle());
}
public Vector3 ReadVector3()
{
return new Vector3(ReadSingle(), ReadSingle(), ReadSingle());
}
public Vector4 ReadVector4()
{
return new Vector4(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle());
}
public Color ReadColor()
{
return new Color(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle());
}
public Color32 ReadColor32()
{
return new Color32(ReadByte(), ReadByte(), ReadByte(), ReadByte());
}
public Quaternion ReadQuaternion()
{
return new Quaternion(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle());
}
public Rect ReadRect()
{
return new Rect(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle());
}
public Plane ReadPlane()
{
return new Plane(ReadVector3(), ReadSingle());
}
public Ray ReadRay()
{
return new Ray(ReadVector3(), ReadVector3());
}
public Matrix4x4 ReadMatrix4x4()
{
Matrix4x4 m = new Matrix4x4();
m.m00 = ReadSingle();
m.m01 = ReadSingle();
m.m02 = ReadSingle();
m.m03 = ReadSingle();
m.m10 = ReadSingle();
m.m11 = ReadSingle();
m.m12 = ReadSingle();
m.m13 = ReadSingle();
m.m20 = ReadSingle();
m.m21 = ReadSingle();
m.m22 = ReadSingle();
m.m23 = ReadSingle();
m.m30 = ReadSingle();
m.m31 = ReadSingle();
m.m32 = ReadSingle();
m.m33 = ReadSingle();
return m;
}
public NetworkHash128 ReadNetworkHash128()
{
NetworkHash128 hash;
hash.i0 = ReadByte();
hash.i1 = ReadByte();
hash.i2 = ReadByte();
hash.i3 = ReadByte();
hash.i4 = ReadByte();
hash.i5 = ReadByte();
hash.i6 = ReadByte();
hash.i7 = ReadByte();
hash.i8 = ReadByte();
hash.i9 = ReadByte();
hash.i10 = ReadByte();
hash.i11 = ReadByte();
hash.i12 = ReadByte();
hash.i13 = ReadByte();
hash.i14 = ReadByte();
hash.i15 = ReadByte();
return hash;
}
public Transform ReadTransform()
{
NetworkInstanceId netId = ReadNetworkId();
if (netId.IsEmpty())
{
return null;
}
GameObject go = ClientScene.FindLocalObject(netId);
if (go == null)
{
if (LogFilter.logDebug) { Debug.Log("ReadTransform netId:" + netId); }
return null;
}
return go.transform;
}
public GameObject ReadGameObject()
{
NetworkInstanceId netId = ReadNetworkId();
if (netId.IsEmpty())
{
return null;
}
GameObject go;
if (NetworkServer.active)
{
go = NetworkServer.FindLocalObject(netId);
}
else
{
go = ClientScene.FindLocalObject(netId);
}
if (go == null)
{
if (LogFilter.logDebug) { Debug.Log("ReadGameObject netId:" + netId + "go: null"); }
}
return go;
}
public NetworkIdentity ReadNetworkIdentity()
{
NetworkInstanceId netId = ReadNetworkId();
if (netId.IsEmpty())
{
return null;
}
GameObject go;
if (NetworkServer.active)
{
go = NetworkServer.FindLocalObject(netId);
}
else
{
go = ClientScene.FindLocalObject(netId);
}
if (go == null)
{
if (LogFilter.logDebug) { Debug.Log("ReadNetworkIdentity netId:" + netId + "go: null"); }
return null;
}
return go.GetComponent<NetworkIdentity>();
}
public override string ToString()
{
return m_buf.ToString();
}
public TMsg ReadMessage<TMsg>() where TMsg : MessageBase, new()
{
var msg = new TMsg();
msg.Deserialize(this);
return msg;
}
};
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,287 @@
#if ENABLE_UNET
using System;
using System.Collections.Generic;
namespace UnityEngine.Networking
{
// This is an internal class to allow the client and server to share scene-related functionality.
// This code (mostly) used to be in ClientScene.
internal class NetworkScene
{
// localObjects is NOT static. For the Host, even though there is one scene and gameObjects are
// shared with the localClient, the set of active objects for each must be separate to prevent
// out-of-order object initialization problems.
Dictionary<NetworkInstanceId, NetworkIdentity> m_LocalObjects = new Dictionary<NetworkInstanceId, NetworkIdentity>();
static Dictionary<NetworkHash128, GameObject> s_GuidToPrefab = new Dictionary<NetworkHash128, GameObject>();
static Dictionary<NetworkHash128, SpawnDelegate> s_SpawnHandlers = new Dictionary<NetworkHash128, SpawnDelegate>();
static Dictionary<NetworkHash128, UnSpawnDelegate> s_UnspawnHandlers = new Dictionary<NetworkHash128, UnSpawnDelegate>();
internal Dictionary<NetworkInstanceId, NetworkIdentity> localObjects { get { return m_LocalObjects; }}
static internal Dictionary<NetworkHash128, GameObject> guidToPrefab { get { return s_GuidToPrefab; }}
static internal Dictionary<NetworkHash128, SpawnDelegate> spawnHandlers { get { return s_SpawnHandlers; }}
static internal Dictionary<NetworkHash128, UnSpawnDelegate> unspawnHandlers { get { return s_UnspawnHandlers; }}
internal void Shutdown()
{
ClearLocalObjects();
ClearSpawners();
}
internal void SetLocalObject(NetworkInstanceId netId, GameObject obj, bool isClient, bool isServer)
{
if (LogFilter.logDev) { Debug.Log("SetLocalObject " + netId + " " + obj); }
if (obj == null)
{
m_LocalObjects[netId] = null;
return;
}
NetworkIdentity foundNetworkIdentity = null;
if (m_LocalObjects.ContainsKey(netId))
{
foundNetworkIdentity = m_LocalObjects[netId];
}
if (foundNetworkIdentity == null)
{
foundNetworkIdentity = obj.GetComponent<NetworkIdentity>();
m_LocalObjects[netId] = foundNetworkIdentity;
}
foundNetworkIdentity.UpdateClientServer(isClient, isServer);
}
// this lets the client take an instance ID from the server and find
// the local object that it corresponds too. This is temporary until
// object references can be serialized transparently.
internal GameObject FindLocalObject(NetworkInstanceId netId)
{
if (m_LocalObjects.ContainsKey(netId))
{
var uv = m_LocalObjects[netId];
if (uv != null)
{
return uv.gameObject;
}
}
return null;
}
internal bool GetNetworkIdentity(NetworkInstanceId netId, out NetworkIdentity uv)
{
if (m_LocalObjects.ContainsKey(netId) && m_LocalObjects[netId] != null)
{
uv = m_LocalObjects[netId];
return true;
}
uv = null;
return false;
}
internal bool RemoveLocalObject(NetworkInstanceId netId)
{
return m_LocalObjects.Remove(netId);
}
internal bool RemoveLocalObjectAndDestroy(NetworkInstanceId netId)
{
if (m_LocalObjects.ContainsKey(netId))
{
NetworkIdentity localObject = m_LocalObjects[netId];
Object.Destroy(localObject.gameObject);
return m_LocalObjects.Remove(netId);
}
return false;
}
internal void ClearLocalObjects()
{
m_LocalObjects.Clear();
}
static internal void RegisterPrefab(GameObject prefab, NetworkHash128 newAssetId)
{
NetworkIdentity view = prefab.GetComponent<NetworkIdentity>();
if (view)
{
view.SetDynamicAssetId(newAssetId);
if (LogFilter.logDebug) { Debug.Log("Registering prefab '" + prefab.name + "' as asset:" + view.assetId); }
s_GuidToPrefab[view.assetId] = prefab;
}
else
{
if (LogFilter.logError) { Debug.LogError("Could not register '" + prefab.name + "' since it contains no NetworkIdentity component"); }
}
}
static internal void RegisterPrefab(GameObject prefab)
{
NetworkIdentity view = prefab.GetComponent<NetworkIdentity>();
if (view)
{
if (LogFilter.logDebug) { Debug.Log("Registering prefab '" + prefab.name + "' as asset:" + view.assetId); }
s_GuidToPrefab[view.assetId] = prefab;
var uvs = prefab.GetComponentsInChildren<NetworkIdentity>();
if (uvs.Length > 1)
{
if (LogFilter.logWarn)
{
Debug.LogWarning("The prefab '" + prefab.name +
"' has multiple NetworkIdentity components. There can only be one NetworkIdentity on a prefab, and it must be on the root object.");
}
}
}
else
{
if (LogFilter.logError) { Debug.LogError("Could not register '" + prefab.name + "' since it contains no NetworkIdentity component"); }
}
}
static internal bool GetPrefab(NetworkHash128 assetId, out GameObject prefab)
{
if (!assetId.IsValid())
{
prefab = null;
return false;
}
if (s_GuidToPrefab.ContainsKey(assetId) && s_GuidToPrefab[assetId] != null)
{
prefab = s_GuidToPrefab[assetId];
return true;
}
prefab = null;
return false;
}
static internal void ClearSpawners()
{
s_GuidToPrefab.Clear();
s_SpawnHandlers.Clear();
s_UnspawnHandlers.Clear();
}
static public void UnregisterSpawnHandler(NetworkHash128 assetId)
{
s_SpawnHandlers.Remove(assetId);
s_UnspawnHandlers.Remove(assetId);
}
static internal void RegisterSpawnHandler(NetworkHash128 assetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
if (spawnHandler == null || unspawnHandler == null)
{
if (LogFilter.logError) { Debug.LogError("RegisterSpawnHandler custom spawn function null for " + assetId); }
return;
}
if (LogFilter.logDebug) { Debug.Log("RegisterSpawnHandler asset '" + assetId + "' " + spawnHandler.GetMethodName() + "/" + unspawnHandler.GetMethodName()); }
s_SpawnHandlers[assetId] = spawnHandler;
s_UnspawnHandlers[assetId] = unspawnHandler;
}
static internal void UnregisterPrefab(GameObject prefab)
{
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
if (LogFilter.logError) { Debug.LogError("Could not unregister '" + prefab.name + "' since it contains no NetworkIdentity component"); }
return;
}
s_SpawnHandlers.Remove(identity.assetId);
s_UnspawnHandlers.Remove(identity.assetId);
}
static internal void RegisterPrefab(GameObject prefab, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
{
NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
if (identity == null)
{
if (LogFilter.logError) { Debug.LogError("Could not register '" + prefab.name + "' since it contains no NetworkIdentity component"); }
return;
}
if (spawnHandler == null || unspawnHandler == null)
{
if (LogFilter.logError) { Debug.LogError("RegisterPrefab custom spawn function null for " + identity.assetId); }
return;
}
if (!identity.assetId.IsValid())
{
if (LogFilter.logError) { Debug.LogError("RegisterPrefab game object " + prefab.name + " has no prefab. Use RegisterSpawnHandler() instead?"); }
return;
}
if (LogFilter.logDebug) { Debug.Log("Registering custom prefab '" + prefab.name + "' as asset:" + identity.assetId + " " + spawnHandler.GetMethodName() + "/" + unspawnHandler.GetMethodName()); }
s_SpawnHandlers[identity.assetId] = spawnHandler;
s_UnspawnHandlers[identity.assetId] = unspawnHandler;
}
static internal bool GetSpawnHandler(NetworkHash128 assetId, out SpawnDelegate handler)
{
if (s_SpawnHandlers.ContainsKey(assetId))
{
handler = s_SpawnHandlers[assetId];
return true;
}
handler = null;
return false;
}
static internal bool InvokeUnSpawnHandler(NetworkHash128 assetId, GameObject obj)
{
if (s_UnspawnHandlers.ContainsKey(assetId) && s_UnspawnHandlers[assetId] != null)
{
UnSpawnDelegate handler = s_UnspawnHandlers[assetId];
handler(obj);
return true;
}
return false;
}
internal void DestroyAllClientObjects()
{
foreach (var netId in m_LocalObjects.Keys)
{
NetworkIdentity uv = m_LocalObjects[netId];
if (uv != null && uv.gameObject != null)
{
if (!InvokeUnSpawnHandler(uv.assetId, uv.gameObject))
{
if (uv.sceneId.IsEmpty())
{
Object.Destroy(uv.gameObject);
}
else
{
uv.MarkForReset();
uv.gameObject.SetActive(false);
}
}
}
}
ClearLocalObjects();
}
internal void DumpAllClientObjects()
{
foreach (var netId in m_LocalObjects.Keys)
{
NetworkIdentity uv = m_LocalObjects[netId];
if (uv != null)
Debug.Log("ID:" + netId + " OBJ:" + uv.gameObject + " AS:" + uv.assetId);
else
Debug.Log("ID:" + netId + " OBJ: null");
}
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,50 @@
#if ENABLE_UNET
using System;
namespace UnityEngine.Networking
{
[Serializable]
public struct NetworkSceneId
{
public NetworkSceneId(uint value)
{
m_Value = value;
}
[SerializeField]
uint m_Value;
public bool IsEmpty()
{
return m_Value == 0;
}
public override int GetHashCode()
{
return (int)m_Value;
}
public override bool Equals(object obj)
{
return obj is NetworkSceneId && this == (NetworkSceneId)obj;
}
public static bool operator==(NetworkSceneId c1, NetworkSceneId c2)
{
return c1.m_Value == c2.m_Value;
}
public static bool operator!=(NetworkSceneId c1, NetworkSceneId c2)
{
return c1.m_Value != c2.m_Value;
}
public override string ToString()
{
return m_Value.ToString();
}
public uint Value { get { return m_Value; } }
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,464 @@
using System;
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Networking.Types;
using System.Collections.ObjectModel;
#if ENABLE_UNET
namespace UnityEngine.Networking
{
public class NetworkServerSimple
{
bool m_Initialized = false;
int m_ListenPort;
int m_ServerHostId = -1;
int m_RelaySlotId = -1;
bool m_UseWebSockets;
byte[] m_MsgBuffer = null;
NetworkReader m_MsgReader = null;
Type m_NetworkConnectionClass = typeof(NetworkConnection);
HostTopology m_HostTopology;
List<NetworkConnection> m_Connections = new List<NetworkConnection>();
ReadOnlyCollection<NetworkConnection> m_ConnectionsReadOnly;
NetworkMessageHandlers m_MessageHandlers = new NetworkMessageHandlers();
public int listenPort { get { return m_ListenPort; } set { m_ListenPort = value; }}
public int serverHostId { get { return m_ServerHostId; } set { m_ServerHostId = value; }}
public HostTopology hostTopology { get { return m_HostTopology; }}
public bool useWebSockets { get { return m_UseWebSockets; } set { m_UseWebSockets = value; } }
public ReadOnlyCollection<NetworkConnection> connections { get { return m_ConnectionsReadOnly; }}
public Dictionary<short, NetworkMessageDelegate> handlers { get { return m_MessageHandlers.GetHandlers(); } }
public byte[] messageBuffer { get { return m_MsgBuffer; }}
public NetworkReader messageReader { get { return m_MsgReader; }}
public Type networkConnectionClass
{
get { return m_NetworkConnectionClass; }
}
public void SetNetworkConnectionClass<T>() where T : NetworkConnection
{
m_NetworkConnectionClass = typeof(T);
}
public NetworkServerSimple()
{
m_ConnectionsReadOnly = new ReadOnlyCollection<NetworkConnection>(m_Connections);
}
public virtual void Initialize()
{
if (m_Initialized)
return;
m_Initialized = true;
NetworkTransport.Init();
m_MsgBuffer = new byte[NetworkMessage.MaxMessageSize];
m_MsgReader = new NetworkReader(m_MsgBuffer);
if (m_HostTopology == null)
{
var config = new ConnectionConfig();
config.AddChannel(QosType.ReliableSequenced);
config.AddChannel(QosType.Unreliable);
m_HostTopology = new HostTopology(config, 8);
}
if (LogFilter.logDebug) { Debug.Log("NetworkServerSimple initialize."); }
}
public bool Configure(ConnectionConfig config, int maxConnections)
{
HostTopology top = new HostTopology(config, maxConnections);
return Configure(top);
}
public bool Configure(HostTopology topology)
{
m_HostTopology = topology;
return true;
}
public bool Listen(string ipAddress, int serverListenPort)
{
Initialize();
m_ListenPort = serverListenPort;
if (m_UseWebSockets)
{
m_ServerHostId = NetworkTransport.AddWebsocketHost(m_HostTopology, serverListenPort, ipAddress);
}
else
{
m_ServerHostId = NetworkTransport.AddHost(m_HostTopology, serverListenPort, ipAddress);
}
if (m_ServerHostId == -1)
{
return false;
}
if (LogFilter.logDebug) { Debug.Log("NetworkServerSimple listen: " + ipAddress + ":" + m_ListenPort); }
return true;
}
public bool Listen(int serverListenPort)
{
return Listen(serverListenPort, m_HostTopology);
}
public bool Listen(int serverListenPort, HostTopology topology)
{
m_HostTopology = topology;
Initialize();
m_ListenPort = serverListenPort;
if (m_UseWebSockets)
{
m_ServerHostId = NetworkTransport.AddWebsocketHost(m_HostTopology, serverListenPort);
}
else
{
m_ServerHostId = NetworkTransport.AddHost(m_HostTopology, serverListenPort);
}
if (m_ServerHostId == -1)
{
return false;
}
if (LogFilter.logDebug) { Debug.Log("NetworkServerSimple listen " + m_ListenPort); }
return true;
}
public void ListenRelay(string relayIp, int relayPort, NetworkID netGuid, SourceID sourceId, NodeID nodeId)
{
Initialize();
m_ServerHostId = NetworkTransport.AddHost(m_HostTopology, listenPort);
if (LogFilter.logDebug) { Debug.Log("Server Host Slot Id: " + m_ServerHostId); }
Update();
byte error;
NetworkTransport.ConnectAsNetworkHost(
m_ServerHostId,
relayIp,
relayPort,
netGuid,
sourceId,
nodeId,
out error);
m_RelaySlotId = 0;
if (LogFilter.logDebug) { Debug.Log("Relay Slot Id: " + m_RelaySlotId); }
}
public void Stop()
{
if (LogFilter.logDebug) { Debug.Log("NetworkServerSimple stop "); }
NetworkTransport.RemoveHost(m_ServerHostId);
m_ServerHostId = -1;
}
internal void RegisterHandlerSafe(short msgType, NetworkMessageDelegate handler)
{
m_MessageHandlers.RegisterHandlerSafe(msgType, handler);
}
public void RegisterHandler(short msgType, NetworkMessageDelegate handler)
{
m_MessageHandlers.RegisterHandler(msgType, handler);
}
public void UnregisterHandler(short msgType)
{
m_MessageHandlers.UnregisterHandler(msgType);
}
public void ClearHandlers()
{
m_MessageHandlers.ClearMessageHandlers();
}
// this can be used independantly of Update() - such as when using external connections and not listening.
public void UpdateConnections()
{
for (int i = 0; i < m_Connections.Count; i++)
{
NetworkConnection conn = m_Connections[i];
if (conn != null)
conn.FlushChannels();
}
}
public void Update()
{
if (m_ServerHostId == -1)
return;
int connectionId;
int channelId;
int receivedSize;
byte error;
var networkEvent = NetworkEventType.DataEvent;
if (m_RelaySlotId != -1)
{
networkEvent = NetworkTransport.ReceiveRelayEventFromHost(m_ServerHostId, out error);
if (NetworkEventType.Nothing != networkEvent)
{
if (LogFilter.logDebug) { Debug.Log("NetGroup event:" + networkEvent); }
}
if (networkEvent == NetworkEventType.ConnectEvent)
{
if (LogFilter.logDebug) { Debug.Log("NetGroup server connected"); }
}
if (networkEvent == NetworkEventType.DisconnectEvent)
{
if (LogFilter.logDebug) { Debug.Log("NetGroup server disconnected"); }
}
}
do
{
networkEvent = NetworkTransport.ReceiveFromHost(m_ServerHostId, out connectionId, out channelId, m_MsgBuffer, (int)m_MsgBuffer.Length, out receivedSize, out error);
if (networkEvent != NetworkEventType.Nothing)
{
if (LogFilter.logDev) { Debug.Log("Server event: host=" + m_ServerHostId + " event=" + networkEvent + " error=" + error); }
}
switch (networkEvent)
{
case NetworkEventType.ConnectEvent:
{
HandleConnect(connectionId, error);
break;
}
case NetworkEventType.DataEvent:
{
HandleData(connectionId, channelId, receivedSize, error);
break;
}
case NetworkEventType.DisconnectEvent:
{
HandleDisconnect(connectionId, error);
break;
}
case NetworkEventType.Nothing:
break;
default:
if (LogFilter.logError) { Debug.LogError("Unknown network message type received: " + networkEvent); }
break;
}
}
while (networkEvent != NetworkEventType.Nothing);
UpdateConnections();
}
public NetworkConnection FindConnection(int connectionId)
{
if (connectionId < 0 || connectionId >= m_Connections.Count)
return null;
return m_Connections[connectionId];
}
public bool SetConnectionAtIndex(NetworkConnection conn)
{
while (m_Connections.Count <= conn.connectionId)
{
m_Connections.Add(null);
}
if (m_Connections[conn.connectionId] != null)
{
// already a connection at this index
return false;
}
m_Connections[conn.connectionId] = conn;
conn.SetHandlers(m_MessageHandlers);
return true;
}
public bool RemoveConnectionAtIndex(int connectionId)
{
if (connectionId < 0 || connectionId >= m_Connections.Count)
return false;
m_Connections[connectionId] = null;
return true;
}
void HandleConnect(int connectionId, byte error)
{
if (LogFilter.logDebug) { Debug.Log("NetworkServerSimple accepted client:" + connectionId); }
if (error != 0)
{
OnConnectError(connectionId, error);
return;
}
string address;
int port;
NetworkID networkId;
NodeID node;
byte error2;
NetworkTransport.GetConnectionInfo(m_ServerHostId, connectionId, out address, out port, out networkId, out node, out error2);
NetworkConnection conn = (NetworkConnection)Activator.CreateInstance(m_NetworkConnectionClass);
conn.SetHandlers(m_MessageHandlers);
conn.Initialize(address, m_ServerHostId, connectionId, m_HostTopology);
conn.lastError = (NetworkError)error2;
// add connection at correct index
while (m_Connections.Count <= connectionId)
{
m_Connections.Add(null);
}
m_Connections[connectionId] = conn;
OnConnected(conn);
}
void HandleDisconnect(int connectionId, byte error)
{
if (LogFilter.logDebug) { Debug.Log("NetworkServerSimple disconnect client:" + connectionId); }
var conn = FindConnection(connectionId);
if (conn == null)
{
return;
}
conn.lastError = (NetworkError)error;
if (error != 0)
{
if ((NetworkError)error != NetworkError.Timeout)
{
m_Connections[connectionId] = null;
if (LogFilter.logError) { Debug.LogError("Server client disconnect error, connectionId: " + connectionId + " error: " + (NetworkError)error); }
OnDisconnectError(conn, error);
return;
}
}
conn.Disconnect();
m_Connections[connectionId] = null;
if (LogFilter.logDebug) { Debug.Log("Server lost client:" + connectionId); }
OnDisconnected(conn);
}
void HandleData(int connectionId, int channelId, int receivedSize, byte error)
{
var conn = FindConnection(connectionId);
if (conn == null)
{
if (LogFilter.logError) { Debug.LogError("HandleData Unknown connectionId:" + connectionId); }
return;
}
conn.lastError = (NetworkError)error;
if (error != 0)
{
OnDataError(conn, error);
return;
}
m_MsgReader.SeekZero();
OnData(conn, receivedSize, channelId);
}
public void SendBytesTo(int connectionId, byte[] bytes, int numBytes, int channelId)
{
var outConn = FindConnection(connectionId);
if (outConn == null)
{
return;
}
outConn.SendBytes(bytes, numBytes, channelId);
}
public void SendWriterTo(int connectionId, NetworkWriter writer, int channelId)
{
var outConn = FindConnection(connectionId);
if (outConn == null)
{
return;
}
outConn.SendWriter(writer, channelId);
}
public void Disconnect(int connectionId)
{
var outConn = FindConnection(connectionId);
if (outConn == null)
{
return;
}
outConn.Disconnect();
m_Connections[connectionId] = null;
}
public void DisconnectAllConnections()
{
for (int i = 0; i < m_Connections.Count; i++)
{
NetworkConnection conn = m_Connections[i];
if (conn != null)
{
conn.Disconnect();
conn.Dispose();
}
}
}
// --------------------------- virtuals ---------------------------------------
public virtual void OnConnectError(int connectionId, byte error)
{
Debug.LogError("OnConnectError error:" + error);
}
public virtual void OnDataError(NetworkConnection conn, byte error)
{
Debug.LogError("OnDataError error:" + error);
}
public virtual void OnDisconnectError(NetworkConnection conn, byte error)
{
Debug.LogError("OnDisconnectError error:" + error);
}
public virtual void OnConnected(NetworkConnection conn)
{
conn.InvokeHandlerNoData(MsgType.Connect);
}
public virtual void OnDisconnected(NetworkConnection conn)
{
conn.InvokeHandlerNoData(MsgType.Disconnect);
}
public virtual void OnData(NetworkConnection conn, int receivedSize, int channelId)
{
conn.TransportReceive(m_MsgBuffer, receivedSize, channelId);
}
}
}
#endif

View File

@ -0,0 +1,22 @@
#if ENABLE_UNET
using System;
using UnityEngine;
namespace UnityEngine.Networking
{
[DisallowMultipleComponent]
[AddComponentMenu("Network/NetworkStartPosition")]
public class NetworkStartPosition : MonoBehaviour
{
public void Awake()
{
NetworkManager.RegisterStartPosition(transform);
}
public void OnDestroy()
{
NetworkManager.UnRegisterStartPosition(transform);
}
}
}
#endif

View File

@ -0,0 +1,482 @@
#if ENABLE_UNET
using System;
using UnityEngine;
namespace UnityEngine.Networking
{
[AddComponentMenu("Network/NetworkTransformChild")]
public class NetworkTransformChild : NetworkBehaviour
{
[SerializeField]
Transform m_Target;
[SerializeField]
uint m_ChildIndex;
NetworkTransform m_Root;
[SerializeField] float m_SendInterval = 0.1f;
[SerializeField] NetworkTransform.AxisSyncMode m_SyncRotationAxis = NetworkTransform.AxisSyncMode.AxisXYZ;
[SerializeField] NetworkTransform.CompressionSyncMode m_RotationSyncCompression = NetworkTransform.CompressionSyncMode.None;
[SerializeField] float m_MovementThreshold = 0.001f;
[SerializeField] float m_InterpolateRotation = 0.5f;
[SerializeField] float m_InterpolateMovement = 0.5f;
[SerializeField] NetworkTransform.ClientMoveCallback3D m_ClientMoveCallback3D;
// movement smoothing
Vector3 m_TargetSyncPosition;
Quaternion m_TargetSyncRotation3D;
float m_LastClientSyncTime; // last time client received a sync from server
float m_LastClientSendTime; // last time client send a sync to server
Vector3 m_PrevPosition;
Quaternion m_PrevRotation;
const float k_LocalMovementThreshold = 0.00001f;
const float k_LocalRotationThreshold = 0.00001f;
NetworkWriter m_LocalTransformWriter;
// settings
public Transform target { get {return m_Target; } set { m_Target = value; OnValidate(); } }
public uint childIndex { get { return m_ChildIndex; }}
public float sendInterval { get { return m_SendInterval; } set { m_SendInterval = value; } }
public NetworkTransform.AxisSyncMode syncRotationAxis { get { return m_SyncRotationAxis; } set { m_SyncRotationAxis = value; } }
public NetworkTransform.CompressionSyncMode rotationSyncCompression { get { return m_RotationSyncCompression; } set { m_RotationSyncCompression = value; } }
public float movementThreshold { get { return m_MovementThreshold; } set { m_MovementThreshold = value; } }
public float interpolateRotation { get { return m_InterpolateRotation; } set { m_InterpolateRotation = value; } }
public float interpolateMovement { get { return m_InterpolateMovement; } set { m_InterpolateMovement = value; } }
public NetworkTransform.ClientMoveCallback3D clientMoveCallback3D { get { return m_ClientMoveCallback3D; } set { m_ClientMoveCallback3D = value; } }
// runtime data
public float lastSyncTime { get { return m_LastClientSyncTime; } }
public Vector3 targetSyncPosition { get { return m_TargetSyncPosition; } }
public Quaternion targetSyncRotation3D { get { return m_TargetSyncRotation3D; } }
void OnValidate()
{
// root parent of target must have a NetworkTransform
if (m_Target != null)
{
Transform parent = m_Target.parent;
if (parent == null)
{
if (LogFilter.logError) { Debug.LogError("NetworkTransformChild target cannot be the root transform."); }
m_Target = null;
return;
}
while (parent.parent != null)
{
parent = parent.parent;
}
m_Root = parent.gameObject.GetComponent<NetworkTransform>();
if (m_Root == null)
{
if (LogFilter.logError) { Debug.LogError("NetworkTransformChild root must have NetworkTransform"); }
m_Target = null;
return;
}
}
if (m_Root != null)
{
// childIndex is the index within all the NetworkChildTransforms on the root
m_ChildIndex = UInt32.MaxValue;
var childTransforms = m_Root.GetComponents<NetworkTransformChild>();
for (uint i = 0; i < childTransforms.Length; i++)
{
if (childTransforms[i] == this)
{
m_ChildIndex = i;
break;
}
}
if (m_ChildIndex == UInt32.MaxValue)
{
if (LogFilter.logError) { Debug.LogError("NetworkTransformChild component must be a child in the same hierarchy"); }
m_Target = null;
}
}
if (m_SendInterval < 0)
{
m_SendInterval = 0;
}
if (m_SyncRotationAxis < NetworkTransform.AxisSyncMode.None || m_SyncRotationAxis > NetworkTransform.AxisSyncMode.AxisXYZ)
{
m_SyncRotationAxis = NetworkTransform.AxisSyncMode.None;
}
if (movementThreshold < 0)
{
movementThreshold = 0.00f;
}
if (interpolateRotation < 0)
{
interpolateRotation = 0.01f;
}
if (interpolateRotation > 1.0f)
{
interpolateRotation = 1.0f;
}
if (interpolateMovement < 0)
{
interpolateMovement = 0.01f;
}
if (interpolateMovement > 1.0f)
{
interpolateMovement = 1.0f;
}
}
void Awake()
{
m_PrevPosition = m_Target.localPosition;
m_PrevRotation = m_Target.localRotation;
// cache these to avoid per-frame allocations.
if (localPlayerAuthority)
{
m_LocalTransformWriter = new NetworkWriter();
}
}
public override bool OnSerialize(NetworkWriter writer, bool initialState)
{
if (initialState)
{
// always write initial state, no dirty bits
}
else if (syncVarDirtyBits == 0)
{
writer.WritePackedUInt32(0);
return false;
}
else
{
// dirty bits
writer.WritePackedUInt32(1);
}
SerializeModeTransform(writer);
return true;
}
void SerializeModeTransform(NetworkWriter writer)
{
// position
writer.Write(m_Target.localPosition);
// rotation
if (m_SyncRotationAxis != NetworkTransform.AxisSyncMode.None)
{
NetworkTransform.SerializeRotation3D(writer, m_Target.localRotation, syncRotationAxis, rotationSyncCompression);
}
m_PrevPosition = m_Target.localPosition;
m_PrevRotation = m_Target.localRotation;
}
public override void OnDeserialize(NetworkReader reader, bool initialState)
{
if (isServer && NetworkServer.localClientActive)
return;
if (!initialState)
{
if (reader.ReadPackedUInt32() == 0)
return;
}
UnserializeModeTransform(reader, initialState);
m_LastClientSyncTime = Time.time;
}
void UnserializeModeTransform(NetworkReader reader, bool initialState)
{
if (hasAuthority)
{
// this component must read the data that the server wrote, even if it ignores it.
// otherwise the NetworkReader stream will still contain that data for the next component.
// position
reader.ReadVector3();
if (syncRotationAxis != NetworkTransform.AxisSyncMode.None)
{
NetworkTransform.UnserializeRotation3D(reader, syncRotationAxis, rotationSyncCompression);
}
return;
}
if (isServer && m_ClientMoveCallback3D != null)
{
var pos = reader.ReadVector3();
var vel = Vector3.zero;
var rot = Quaternion.identity;
if (syncRotationAxis != NetworkTransform.AxisSyncMode.None)
{
rot = NetworkTransform.UnserializeRotation3D(reader, syncRotationAxis, rotationSyncCompression);
}
if (m_ClientMoveCallback3D(ref pos, ref vel, ref rot))
{
m_TargetSyncPosition = pos;
if (syncRotationAxis != NetworkTransform.AxisSyncMode.None)
{
m_TargetSyncRotation3D = rot;
}
}
else
{
// rejected by callback
return;
}
}
else
{
// position
m_TargetSyncPosition = reader.ReadVector3();
// rotation
if (syncRotationAxis != NetworkTransform.AxisSyncMode.None)
{
m_TargetSyncRotation3D = NetworkTransform.UnserializeRotation3D(reader, syncRotationAxis, rotationSyncCompression);
}
}
}
void FixedUpdate()
{
if (isServer)
{
FixedUpdateServer();
}
if (isClient)
{
FixedUpdateClient();
}
}
void FixedUpdateServer()
{
if (syncVarDirtyBits != 0)
return;
// dont run if network isn't active
if (!NetworkServer.active)
return;
// dont run if we haven't been spawned yet
if (!isServer)
return;
// dont' auto-dirty if no send interval
if (GetNetworkSendInterval() == 0)
return;
float distance = (m_Target.localPosition - m_PrevPosition).sqrMagnitude;
if (distance < movementThreshold)
{
distance = Quaternion.Angle(m_PrevRotation, m_Target.localRotation);
if (distance < movementThreshold)
{
return;
}
}
// This will cause transform to be sent
SetDirtyBit(1);
}
void FixedUpdateClient()
{
// dont run if we haven't received any sync data
if (m_LastClientSyncTime == 0)
return;
// dont run if network isn't active
if (!NetworkServer.active && !NetworkClient.active)
return;
// dont run if we haven't been spawned yet
if (!isServer && !isClient)
return;
// dont run if not expecting continuous updates
if (GetNetworkSendInterval() == 0)
return;
// dont run this if this client has authority over this player object
if (hasAuthority)
return;
// interpolate on client
if (m_LastClientSyncTime != 0)
{
if (m_InterpolateMovement > 0)
{
m_Target.localPosition = Vector3.Lerp(m_Target.localPosition, m_TargetSyncPosition, m_InterpolateMovement);
}
else
{
m_Target.localPosition = m_TargetSyncPosition;
}
if (m_InterpolateRotation > 0)
{
m_Target.localRotation = Quaternion.Slerp(m_Target.localRotation, m_TargetSyncRotation3D, m_InterpolateRotation);
}
else
{
m_Target.localRotation = m_TargetSyncRotation3D;
}
}
}
// --------------------- local transform sync ------------------------
void Update()
{
if (!hasAuthority)
return;
if (!localPlayerAuthority)
return;
if (NetworkServer.active)
return;
if (Time.time - m_LastClientSendTime > GetNetworkSendInterval())
{
SendTransform();
m_LastClientSendTime = Time.time;
}
}
bool HasMoved()
{
float diff = 0;
// check if position has changed
diff = (m_Target.localPosition - m_PrevPosition).sqrMagnitude;
if (diff > k_LocalMovementThreshold)
{
return true;
}
// check if rotation has changed
diff = Quaternion.Angle(m_Target.localRotation, m_PrevRotation);
if (diff > k_LocalRotationThreshold)
{
return true;
}
// check if velocty has changed
return false;
}
[Client]
void SendTransform()
{
if (!HasMoved() || ClientScene.readyConnection == null)
{
return;
}
m_LocalTransformWriter.StartMessage(MsgType.LocalChildTransform);
m_LocalTransformWriter.Write(netId);
m_LocalTransformWriter.WritePackedUInt32(m_ChildIndex);
SerializeModeTransform(m_LocalTransformWriter);
m_PrevPosition = m_Target.localPosition;
m_PrevRotation = m_Target.localRotation;
m_LocalTransformWriter.FinishMessage();
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.LocalChildTransform, "16:LocalChildTransform", 1);
#endif
ClientScene.readyConnection.SendWriter(m_LocalTransformWriter, GetNetworkChannel());
}
static internal void HandleChildTransform(NetworkMessage netMsg)
{
NetworkInstanceId netId = netMsg.reader.ReadNetworkId();
uint childIndex = netMsg.reader.ReadPackedUInt32();
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Incoming,
MsgType.LocalChildTransform, "16:LocalChildTransform", 1);
#endif
GameObject foundObj = NetworkServer.FindLocalObject(netId);
if (foundObj == null)
{
if (LogFilter.logError) { Debug.LogError("Received NetworkTransformChild data for GameObject that doesn't exist"); }
return;
}
var children = foundObj.GetComponents<NetworkTransformChild>();
if (children == null || children.Length == 0)
{
if (LogFilter.logError) { Debug.LogError("HandleChildTransform no children"); }
return;
}
if (childIndex >= children.Length)
{
if (LogFilter.logError) { Debug.LogError("HandleChildTransform childIndex invalid"); }
return;
}
NetworkTransformChild foundSync = children[childIndex];
if (foundSync == null)
{
if (LogFilter.logError) { Debug.LogError("HandleChildTransform null target"); }
return;
}
if (!foundSync.localPlayerAuthority)
{
if (LogFilter.logError) { Debug.LogError("HandleChildTransform no localPlayerAuthority"); }
return;
}
if (!netMsg.conn.clientOwnedObjects.Contains(netId))
{
if (LogFilter.logWarn) { Debug.LogWarning("NetworkTransformChild netId:" + netId + " is not for a valid player"); }
return;
}
foundSync.UnserializeModeTransform(netMsg.reader, false);
foundSync.m_LastClientSyncTime = Time.time;
if (!foundSync.isClient)
{
// dedicated server wont interpolate, so snap.
foundSync.m_Target.localPosition = foundSync.m_TargetSyncPosition;
foundSync.m_Target.localRotation = foundSync.m_TargetSyncRotation3D;
}
}
public override int GetNetworkChannel()
{
return Channels.DefaultUnreliable;
}
public override float GetNetworkSendInterval()
{
return m_SendInterval;
}
}
}
#endif //ENABLE_UNET

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,168 @@
#if ENABLE_UNET
using System;
using System.ComponentModel;
using UnityEngine;
namespace UnityEngine.Networking
{
[DisallowMultipleComponent]
[AddComponentMenu("Network/NetworkTransformVisualizer")]
[RequireComponent(typeof(NetworkTransform))]
[EditorBrowsable(EditorBrowsableState.Never)]
public class NetworkTransformVisualizer : NetworkBehaviour
{
[Tooltip("The prefab to use for the visualization object.")]
[SerializeField] GameObject m_VisualizerPrefab;
NetworkTransform m_NetworkTransform;
GameObject m_Visualizer;
public GameObject visualizerPrefab { get { return m_VisualizerPrefab; } set { m_VisualizerPrefab = value; }}
public override void OnStartClient()
{
if (m_VisualizerPrefab != null)
{
m_NetworkTransform = GetComponent<NetworkTransform>();
CreateLineMaterial();
m_Visualizer = (GameObject)Instantiate(m_VisualizerPrefab, transform.position, Quaternion.identity);
}
}
public override void OnStartLocalPlayer()
{
if (m_Visualizer == null)
return;
if (m_NetworkTransform.localPlayerAuthority || isServer)
{
Destroy(m_Visualizer);
}
}
void OnDestroy()
{
if (m_Visualizer != null)
{
Destroy(m_Visualizer);
}
}
[ClientCallback]
void FixedUpdate()
{
if (m_Visualizer == null)
return;
// dont run if network isn't active
if (!NetworkServer.active && !NetworkClient.active)
return;
// dont run if we haven't been spawned yet
if (!isServer && !isClient)
return;
// dont run this if this client has authority over this player object
if (hasAuthority && m_NetworkTransform.localPlayerAuthority)
return;
m_Visualizer.transform.position = m_NetworkTransform.targetSyncPosition;
if (m_NetworkTransform.rigidbody3D != null && m_Visualizer.GetComponent<Rigidbody>() != null)
{
m_Visualizer.GetComponent<Rigidbody>().velocity = m_NetworkTransform.targetSyncVelocity;
}
if (m_NetworkTransform.rigidbody2D != null && m_Visualizer.GetComponent<Rigidbody2D>() != null)
{
m_Visualizer.GetComponent<Rigidbody2D>().velocity = m_NetworkTransform.targetSyncVelocity;
}
Quaternion targetFacing = Quaternion.identity;
if (m_NetworkTransform.rigidbody3D != null)
{
targetFacing = m_NetworkTransform.targetSyncRotation3D;
}
if (m_NetworkTransform.rigidbody2D != null)
{
targetFacing = Quaternion.Euler(0, 0, m_NetworkTransform.targetSyncRotation2D);
}
m_Visualizer.transform.rotation = targetFacing;
}
// --------------------- local transform sync ------------------------
void OnRenderObject()
{
if (m_Visualizer == null)
return;
if (m_NetworkTransform.localPlayerAuthority && hasAuthority)
return;
if (m_NetworkTransform.lastSyncTime == 0)
return;
s_LineMaterial.SetPass(0);
GL.Begin(GL.LINES);
GL.Color(Color.white);
GL.Vertex3(transform.position.x, transform.position.y, transform.position.z);
GL.Vertex3(m_NetworkTransform.targetSyncPosition.x, m_NetworkTransform.targetSyncPosition.y, m_NetworkTransform.targetSyncPosition.z);
GL.End();
DrawRotationInterpolation();
}
void DrawRotationInterpolation()
{
Quaternion targetFacing = Quaternion.identity;
if (m_NetworkTransform.rigidbody3D != null)
{
targetFacing = m_NetworkTransform.targetSyncRotation3D;
}
if (m_NetworkTransform.rigidbody2D != null)
{
targetFacing = Quaternion.Euler(0, 0, m_NetworkTransform.targetSyncRotation2D);
}
if (targetFacing == Quaternion.identity)
return;
// draw line for actual facing
GL.Begin(GL.LINES);
GL.Color(Color.yellow);
GL.Vertex3(transform.position.x, transform.position.y, transform.position.z);
Vector3 actualFront = transform.position + transform.right;
GL.Vertex3(actualFront.x, actualFront.y, actualFront.z);
GL.End();
// draw line for target (server) facing
GL.Begin(GL.LINES);
GL.Color(Color.green);
GL.Vertex3(transform.position.x, transform.position.y, transform.position.z);
Vector3 targetPositionOffset = (targetFacing * Vector3.right);
Vector3 targetFront = transform.position + targetPositionOffset;
GL.Vertex3(targetFront.x, targetFront.y, targetFront.z);
GL.End();
}
static Material s_LineMaterial;
static void CreateLineMaterial()
{
if (s_LineMaterial)
return;
var shader = Shader.Find("Hidden/Internal-Colored");
if (!shader)
{
Debug.LogWarning("Could not find Colored builtin shader");
return;
}
s_LineMaterial = new Material(shader);
s_LineMaterial.hideFlags = HideFlags.HideAndDontSave;
s_LineMaterial.SetInt("_ZWrite", 0);
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,548 @@
#if ENABLE_UNET
using System;
using System.Text;
using UnityEngine;
namespace UnityEngine.Networking
{
/*
// Binary stream Writer. Supports simple types, buffers, arrays, structs, and nested types
*/
public class NetworkWriter
{
const int k_MaxStringLength = 1024 * 32;
NetBuffer m_Buffer;
static Encoding s_Encoding;
static byte[] s_StringWriteBuffer;
public NetworkWriter()
{
m_Buffer = new NetBuffer();
if (s_Encoding == null)
{
s_Encoding = new UTF8Encoding();
s_StringWriteBuffer = new byte[k_MaxStringLength];
}
}
public NetworkWriter(byte[] buffer)
{
m_Buffer = new NetBuffer(buffer);
if (s_Encoding == null)
{
s_Encoding = new UTF8Encoding();
s_StringWriteBuffer = new byte[k_MaxStringLength];
}
}
public short Position { get { return (short)m_Buffer.Position; } }
public byte[] ToArray()
{
var newArray = new byte[m_Buffer.AsArraySegment().Count];
Array.Copy(m_Buffer.AsArraySegment().Array, newArray, m_Buffer.AsArraySegment().Count);
return newArray;
}
public byte[] AsArray()
{
return AsArraySegment().Array;
}
internal ArraySegment<byte> AsArraySegment()
{
return m_Buffer.AsArraySegment();
}
// http://sqlite.org/src4/doc/trunk/www/varint.wiki
public void WritePackedUInt32(UInt32 value)
{
if (value <= 240)
{
Write((byte)value);
return;
}
if (value <= 2287)
{
Write((byte)((value - 240) / 256 + 241));
Write((byte)((value - 240) % 256));
return;
}
if (value <= 67823)
{
Write((byte)249);
Write((byte)((value - 2288) / 256));
Write((byte)((value - 2288) % 256));
return;
}
if (value <= 16777215)
{
Write((byte)250);
Write((byte)(value & 0xFF));
Write((byte)((value >> 8) & 0xFF));
Write((byte)((value >> 16) & 0xFF));
return;
}
// all other values of uint
Write((byte)251);
Write((byte)(value & 0xFF));
Write((byte)((value >> 8) & 0xFF));
Write((byte)((value >> 16) & 0xFF));
Write((byte)((value >> 24) & 0xFF));
}
public void WritePackedUInt64(UInt64 value)
{
if (value <= 240)
{
Write((byte)value);
return;
}
if (value <= 2287)
{
Write((byte)((value - 240) / 256 + 241));
Write((byte)((value - 240) % 256));
return;
}
if (value <= 67823)
{
Write((byte)249);
Write((byte)((value - 2288) / 256));
Write((byte)((value - 2288) % 256));
return;
}
if (value <= 16777215)
{
Write((byte)250);
Write((byte)(value & 0xFF));
Write((byte)((value >> 8) & 0xFF));
Write((byte)((value >> 16) & 0xFF));
return;
}
if (value <= 4294967295)
{
Write((byte)251);
Write((byte)(value & 0xFF));
Write((byte)((value >> 8) & 0xFF));
Write((byte)((value >> 16) & 0xFF));
Write((byte)((value >> 24) & 0xFF));
return;
}
if (value <= 1099511627775)
{
Write((byte)252);
Write((byte)(value & 0xFF));
Write((byte)((value >> 8) & 0xFF));
Write((byte)((value >> 16) & 0xFF));
Write((byte)((value >> 24) & 0xFF));
Write((byte)((value >> 32) & 0xFF));
return;
}
if (value <= 281474976710655)
{
Write((byte)253);
Write((byte)(value & 0xFF));
Write((byte)((value >> 8) & 0xFF));
Write((byte)((value >> 16) & 0xFF));
Write((byte)((value >> 24) & 0xFF));
Write((byte)((value >> 32) & 0xFF));
Write((byte)((value >> 40) & 0xFF));
return;
}
if (value <= 72057594037927935)
{
Write((byte)254);
Write((byte)(value & 0xFF));
Write((byte)((value >> 8) & 0xFF));
Write((byte)((value >> 16) & 0xFF));
Write((byte)((value >> 24) & 0xFF));
Write((byte)((value >> 32) & 0xFF));
Write((byte)((value >> 40) & 0xFF));
Write((byte)((value >> 48) & 0xFF));
return;
}
// all others
{
Write((byte)255);
Write((byte)(value & 0xFF));
Write((byte)((value >> 8) & 0xFF));
Write((byte)((value >> 16) & 0xFF));
Write((byte)((value >> 24) & 0xFF));
Write((byte)((value >> 32) & 0xFF));
Write((byte)((value >> 40) & 0xFF));
Write((byte)((value >> 48) & 0xFF));
Write((byte)((value >> 56) & 0xFF));
}
}
public void Write(NetworkInstanceId value)
{
WritePackedUInt32(value.Value);
}
public void Write(NetworkSceneId value)
{
WritePackedUInt32(value.Value);
}
public void Write(char value)
{
m_Buffer.WriteByte((byte)value);
}
public void Write(byte value)
{
m_Buffer.WriteByte(value);
}
public void Write(sbyte value)
{
m_Buffer.WriteByte((byte)value);
}
public void Write(short value)
{
m_Buffer.WriteByte2((byte)(value & 0xff), (byte)((value >> 8) & 0xff));
}
public void Write(ushort value)
{
m_Buffer.WriteByte2((byte)(value & 0xff), (byte)((value >> 8) & 0xff));
}
public void Write(int value)
{
// little endian...
m_Buffer.WriteByte4(
(byte)(value & 0xff),
(byte)((value >> 8) & 0xff),
(byte)((value >> 16) & 0xff),
(byte)((value >> 24) & 0xff));
}
public void Write(uint value)
{
m_Buffer.WriteByte4(
(byte)(value & 0xff),
(byte)((value >> 8) & 0xff),
(byte)((value >> 16) & 0xff),
(byte)((value >> 24) & 0xff));
}
public void Write(long value)
{
m_Buffer.WriteByte8(
(byte)(value & 0xff),
(byte)((value >> 8) & 0xff),
(byte)((value >> 16) & 0xff),
(byte)((value >> 24) & 0xff),
(byte)((value >> 32) & 0xff),
(byte)((value >> 40) & 0xff),
(byte)((value >> 48) & 0xff),
(byte)((value >> 56) & 0xff));
}
public void Write(ulong value)
{
m_Buffer.WriteByte8(
(byte)(value & 0xff),
(byte)((value >> 8) & 0xff),
(byte)((value >> 16) & 0xff),
(byte)((value >> 24) & 0xff),
(byte)((value >> 32) & 0xff),
(byte)((value >> 40) & 0xff),
(byte)((value >> 48) & 0xff),
(byte)((value >> 56) & 0xff));
}
static UIntFloat s_FloatConverter;
public void Write(float value)
{
s_FloatConverter.floatValue = value;
Write(s_FloatConverter.intValue);
}
public void Write(double value)
{
s_FloatConverter.doubleValue = value;
Write(s_FloatConverter.longValue);
}
public void Write(decimal value)
{
Int32[] bits = decimal.GetBits(value);
Write(bits[0]);
Write(bits[1]);
Write(bits[2]);
Write(bits[3]);
}
public void Write(string value)
{
if (value == null)
{
m_Buffer.WriteByte2(0, 0);
return;
}
int len = s_Encoding.GetByteCount(value);
if (len >= k_MaxStringLength)
{
throw new IndexOutOfRangeException("Serialize(string) too long: " + value.Length);
}
Write((ushort)(len));
int numBytes = s_Encoding.GetBytes(value, 0, value.Length, s_StringWriteBuffer, 0);
m_Buffer.WriteBytes(s_StringWriteBuffer, (ushort)numBytes);
}
public void Write(bool value)
{
if (value)
m_Buffer.WriteByte(1);
else
m_Buffer.WriteByte(0);
}
public void Write(byte[] buffer, int count)
{
if (count > UInt16.MaxValue)
{
if (LogFilter.logError) { Debug.LogError("NetworkWriter Write: buffer is too large (" + count + ") bytes. The maximum buffer size is 64K bytes."); }
return;
}
m_Buffer.WriteBytes(buffer, (UInt16)count);
}
public void Write(byte[] buffer, int offset, int count)
{
if (count > UInt16.MaxValue)
{
if (LogFilter.logError) { Debug.LogError("NetworkWriter Write: buffer is too large (" + count + ") bytes. The maximum buffer size is 64K bytes."); }
return;
}
m_Buffer.WriteBytesAtOffset(buffer, (ushort)offset, (ushort)count);
}
public void WriteBytesAndSize(byte[] buffer, int count)
{
if (buffer == null || count == 0)
{
Write((UInt16)0);
return;
}
if (count > UInt16.MaxValue)
{
if (LogFilter.logError) { Debug.LogError("NetworkWriter WriteBytesAndSize: buffer is too large (" + count + ") bytes. The maximum buffer size is 64K bytes."); }
return;
}
Write((UInt16)count);
m_Buffer.WriteBytes(buffer, (UInt16)count);
}
//NOTE: this will write the entire buffer.. including trailing empty space!
public void WriteBytesFull(byte[] buffer)
{
if (buffer == null)
{
Write((UInt16)0);
return;
}
if (buffer.Length > UInt16.MaxValue)
{
if (LogFilter.logError) { Debug.LogError("NetworkWriter WriteBytes: buffer is too large (" + buffer.Length + ") bytes. The maximum buffer size is 64K bytes."); }
return;
}
Write((UInt16)buffer.Length);
m_Buffer.WriteBytes(buffer, (UInt16)buffer.Length);
}
public void Write(Vector2 value)
{
Write(value.x);
Write(value.y);
}
public void Write(Vector3 value)
{
Write(value.x);
Write(value.y);
Write(value.z);
}
public void Write(Vector4 value)
{
Write(value.x);
Write(value.y);
Write(value.z);
Write(value.w);
}
public void Write(Color value)
{
Write(value.r);
Write(value.g);
Write(value.b);
Write(value.a);
}
public void Write(Color32 value)
{
Write(value.r);
Write(value.g);
Write(value.b);
Write(value.a);
}
public void Write(Quaternion value)
{
Write(value.x);
Write(value.y);
Write(value.z);
Write(value.w);
}
public void Write(Rect value)
{
Write(value.xMin);
Write(value.yMin);
Write(value.width);
Write(value.height);
}
public void Write(Plane value)
{
Write(value.normal);
Write(value.distance);
}
public void Write(Ray value)
{
Write(value.direction);
Write(value.origin);
}
public void Write(Matrix4x4 value)
{
Write(value.m00);
Write(value.m01);
Write(value.m02);
Write(value.m03);
Write(value.m10);
Write(value.m11);
Write(value.m12);
Write(value.m13);
Write(value.m20);
Write(value.m21);
Write(value.m22);
Write(value.m23);
Write(value.m30);
Write(value.m31);
Write(value.m32);
Write(value.m33);
}
public void Write(NetworkHash128 value)
{
Write(value.i0);
Write(value.i1);
Write(value.i2);
Write(value.i3);
Write(value.i4);
Write(value.i5);
Write(value.i6);
Write(value.i7);
Write(value.i8);
Write(value.i9);
Write(value.i10);
Write(value.i11);
Write(value.i12);
Write(value.i13);
Write(value.i14);
Write(value.i15);
}
public void Write(NetworkIdentity value)
{
if (value == null)
{
WritePackedUInt32(0);
return;
}
Write(value.netId);
}
public void Write(Transform value)
{
if (value == null || value.gameObject == null)
{
WritePackedUInt32(0);
return;
}
var uv = value.gameObject.GetComponent<NetworkIdentity>();
if (uv != null)
{
Write(uv.netId);
}
else
{
if (LogFilter.logWarn) { Debug.LogWarning("NetworkWriter " + value + " has no NetworkIdentity"); }
WritePackedUInt32(0);
}
}
public void Write(GameObject value)
{
if (value == null)
{
WritePackedUInt32(0);
return;
}
var uv = value.GetComponent<NetworkIdentity>();
if (uv != null)
{
Write(uv.netId);
}
else
{
if (LogFilter.logWarn) { Debug.LogWarning("NetworkWriter " + value + " has no NetworkIdentity"); }
WritePackedUInt32(0);
}
}
public void Write(MessageBase msg)
{
msg.Serialize(this);
}
public void SeekZero()
{
m_Buffer.SeekZero();
}
public void StartMessage(short msgType)
{
SeekZero();
// two bytes for size, will be filled out in FinishMessage
m_Buffer.WriteByte2(0, 0);
// two bytes for message type
Write(msgType);
}
public void FinishMessage()
{
// writes correct size into space at start of buffer
m_Buffer.FinishMessage();
}
};
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,39 @@
using System;
#if ENABLE_UNET
namespace UnityEngine.Networking
{
// This class represents the player entity in a network game, there can be multiple players per client
// when there are multiple people playing on one machine
// The server has one connection per client, and the connection has the player instances of that client
// The client has player instances as member variables (should this be removed and just go though the connection like the server does?)
public class PlayerController
{
internal const short kMaxLocalPlayers = 8;
public short playerControllerId = -1;
public NetworkIdentity unetView;
public GameObject gameObject;
public const int MaxPlayersPerClient = 32;
public PlayerController()
{
}
public bool IsValid { get { return playerControllerId != -1; } }
internal PlayerController(GameObject go, short playerControllerId)
{
gameObject = go;
unetView = go.GetComponent<NetworkIdentity>();
this.playerControllerId = playerControllerId;
}
public override string ToString()
{
return string.Format("ID={0} NetworkIdentity NetID={1} Player={2}", new object[] { playerControllerId, (unetView != null ? unetView.netId.ToString() : "null"), (gameObject != null ? gameObject.name : "null") });
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,39 @@
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("UnityEngine.Networking")]
[assembly: AssemblyDescription("Networking High Level API")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Unity Technologies")]
[assembly: AssemblyProduct("UnityEngine.Networking")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: InternalsVisibleTo("UnityEditor.Networking")]
[assembly: InternalsVisibleTo("Assembly-CSharp-Editor-testable")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("87035389-1bb3-40e2-b2a9-c8707e7419ba")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,477 @@
#if ENABLE_UNET
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
namespace UnityEngine.Networking
{
public sealed class SyncListString : SyncList<string>
{
protected override void SerializeItem(NetworkWriter writer, string item)
{
writer.Write(item);
}
protected override string DeserializeItem(NetworkReader reader)
{
return reader.ReadString();
}
[System.Obsolete("ReadReference is now used instead")]
static public SyncListString ReadInstance(NetworkReader reader)
{
ushort count = reader.ReadUInt16();
var result = new SyncListString();
for (ushort i = 0; i < count; i++)
{
result.AddInternal(reader.ReadString());
}
return result;
}
static public void ReadReference(NetworkReader reader, SyncListString syncList)
{
ushort count = reader.ReadUInt16();
syncList.Clear();
for (ushort i = 0; i < count; i++)
{
syncList.AddInternal(reader.ReadString());
}
}
static public void WriteInstance(NetworkWriter writer, SyncListString items)
{
writer.Write((ushort)items.Count);
for (int i = 0; i < items.Count; i++)
{
writer.Write(items[i]);
}
}
}
public sealed class SyncListFloat : SyncList<float>
{
protected override void SerializeItem(NetworkWriter writer, float item)
{
writer.Write(item);
}
protected override float DeserializeItem(NetworkReader reader)
{
return reader.ReadSingle();
}
[System.Obsolete("ReadReference is now used instead")]
static public SyncListFloat ReadInstance(NetworkReader reader)
{
ushort count = reader.ReadUInt16();
var result = new SyncListFloat();
for (ushort i = 0; i < count; i++)
{
result.AddInternal(reader.ReadSingle());
}
return result;
}
static public void ReadReference(NetworkReader reader, SyncListFloat syncList)
{
ushort count = reader.ReadUInt16();
syncList.Clear();
for (ushort i = 0; i < count; i++)
{
syncList.AddInternal(reader.ReadSingle());
}
}
static public void WriteInstance(NetworkWriter writer, SyncListFloat items)
{
writer.Write((ushort)items.Count);
for (int i = 0; i < items.Count; i++)
{
writer.Write(items[i]);
}
}
}
public class SyncListInt : SyncList<int>
{
protected override void SerializeItem(NetworkWriter writer, int item)
{
writer.WritePackedUInt32((uint)item);
}
protected override int DeserializeItem(NetworkReader reader)
{
return (int)reader.ReadPackedUInt32();
}
[System.Obsolete("ReadReference is now used instead")]
static public SyncListInt ReadInstance(NetworkReader reader)
{
ushort count = reader.ReadUInt16();
var result = new SyncListInt();
for (ushort i = 0; i < count; i++)
{
result.AddInternal((int)reader.ReadPackedUInt32());
}
return result;
}
static public void ReadReference(NetworkReader reader, SyncListInt syncList)
{
ushort count = reader.ReadUInt16();
syncList.Clear();
for (ushort i = 0; i < count; i++)
{
syncList.AddInternal((int)reader.ReadPackedUInt32());
}
}
static public void WriteInstance(NetworkWriter writer, SyncListInt items)
{
writer.Write((ushort)items.Count);
for (int i = 0; i < items.Count; i++)
{
writer.WritePackedUInt32((uint)items[i]);
}
}
}
public class SyncListUInt : SyncList<uint>
{
protected override void SerializeItem(NetworkWriter writer, uint item)
{
writer.WritePackedUInt32(item);
}
protected override uint DeserializeItem(NetworkReader reader)
{
return reader.ReadPackedUInt32();
}
[System.Obsolete("ReadReference is now used instead")]
static public SyncListUInt ReadInstance(NetworkReader reader)
{
ushort count = reader.ReadUInt16();
var result = new SyncListUInt();
for (ushort i = 0; i < count; i++)
{
result.AddInternal(reader.ReadPackedUInt32());
}
return result;
}
static public void ReadReference(NetworkReader reader, SyncListUInt syncList)
{
ushort count = reader.ReadUInt16();
syncList.Clear();
for (ushort i = 0; i < count; i++)
{
syncList.AddInternal(reader.ReadPackedUInt32());
}
}
static public void WriteInstance(NetworkWriter writer, SyncListUInt items)
{
writer.Write((ushort)items.Count);
for (int i = 0; i < items.Count; i++)
{
writer.WritePackedUInt32(items[i]);
}
}
}
public class SyncListBool : SyncList<bool>
{
protected override void SerializeItem(NetworkWriter writer, bool item)
{
writer.Write(item);
}
protected override bool DeserializeItem(NetworkReader reader)
{
return reader.ReadBoolean();
}
[System.Obsolete("ReadReference is now used instead")]
static public SyncListBool ReadInstance(NetworkReader reader)
{
ushort count = reader.ReadUInt16();
var result = new SyncListBool();
for (ushort i = 0; i < count; i++)
{
result.AddInternal(reader.ReadBoolean());
}
return result;
}
static public void ReadReference(NetworkReader reader, SyncListBool syncList)
{
ushort count = reader.ReadUInt16();
syncList.Clear();
for (ushort i = 0; i < count; i++)
{
syncList.AddInternal(reader.ReadBoolean());
}
}
static public void WriteInstance(NetworkWriter writer, SyncListBool items)
{
writer.Write((ushort)items.Count);
for (int i = 0; i < items.Count; i++)
{
writer.Write(items[i]);
}
}
}
public class SyncListStruct<T> : SyncList<T> where T : struct
{
new public void AddInternal(T item)
{
base.AddInternal(item);
}
protected override void SerializeItem(NetworkWriter writer, T item)
{
}
protected override T DeserializeItem(NetworkReader reader)
{
return new T();
}
public T GetItem(int i)
{
return base[i];
}
new public ushort Count { get { return (ushort)base.Count; } }
}
[EditorBrowsable(EditorBrowsableState.Never)]
abstract public class SyncList<T> : IList<T>
{
public delegate void SyncListChanged(Operation op, int itemIndex);
List<T> m_Objects = new List<T>();
public int Count { get { return m_Objects.Count; } }
public bool IsReadOnly { get { return false; } }
public SyncListChanged Callback { get { return m_Callback; } set { m_Callback = value; } }
public enum Operation
{
OP_ADD,
OP_CLEAR,
OP_INSERT,
OP_REMOVE,
OP_REMOVEAT,
OP_SET,
OP_DIRTY
};
NetworkBehaviour m_Behaviour;
int m_CmdHash;
SyncListChanged m_Callback;
abstract protected void SerializeItem(NetworkWriter writer, T item);
abstract protected T DeserializeItem(NetworkReader reader);
public void InitializeBehaviour(NetworkBehaviour beh, int cmdHash)
{
m_Behaviour = beh;
m_CmdHash = cmdHash;
}
void SendMsg(Operation op, int itemIndex, T item)
{
if (m_Behaviour == null)
{
if (LogFilter.logError) { Debug.LogError("SyncList not initialized"); }
return;
}
var uv = m_Behaviour.GetComponent<NetworkIdentity>();
if (uv == null)
{
if (LogFilter.logError) { Debug.LogError("SyncList no NetworkIdentity"); }
return;
}
if (!uv.isServer)
{
// object is not spawned yet, so no need to send updates.
return;
}
NetworkWriter writer = new NetworkWriter();
writer.StartMessage(MsgType.SyncList);
writer.Write(uv.netId);
writer.WritePackedUInt32((uint)m_CmdHash);
writer.Write((byte)op);
writer.WritePackedUInt32((uint)itemIndex);
SerializeItem(writer, item);
writer.FinishMessage();
NetworkServer.SendWriterToReady(uv.gameObject, writer, m_Behaviour.GetNetworkChannel());
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
MsgType.SyncList, op.ToString(), 1);
#endif
// ensure it is invoked on host
if (m_Behaviour.isServer && m_Behaviour.isClient && m_Callback != null)
{
m_Callback.Invoke(op, itemIndex);
}
}
void SendMsg(Operation op, int itemIndex)
{
SendMsg(op, itemIndex, default(T));
}
public void HandleMsg(NetworkReader reader)
{
byte op = reader.ReadByte();
int itemIndex = (int)reader.ReadPackedUInt32();
T item = DeserializeItem(reader);
switch ((Operation)op)
{
case Operation.OP_ADD:
m_Objects.Add(item);
break;
case Operation.OP_CLEAR:
m_Objects.Clear();
break;
case Operation.OP_INSERT:
m_Objects.Insert(itemIndex, item);
break;
case Operation.OP_REMOVE:
m_Objects.Remove(item);
break;
case Operation.OP_REMOVEAT:
m_Objects.RemoveAt(itemIndex);
break;
case Operation.OP_SET:
case Operation.OP_DIRTY:
m_Objects[itemIndex] = item;
break;
}
if (m_Callback != null)
{
m_Callback.Invoke((Operation)op, itemIndex);
}
}
// used to bypass Add message.
internal void AddInternal(T item)
{
m_Objects.Add(item);
}
public void Add(T item)
{
m_Objects.Add(item);
SendMsg(Operation.OP_ADD, m_Objects.Count - 1, item);
}
public void Clear()
{
m_Objects.Clear();
SendMsg(Operation.OP_CLEAR, 0);
}
public bool Contains(T item)
{
return m_Objects.Contains(item);
}
public void CopyTo(T[] array, int index)
{
m_Objects.CopyTo(array, index);
}
public int IndexOf(T item)
{
return m_Objects.IndexOf(item);
}
public void Insert(int index, T item)
{
m_Objects.Insert(index, item);
SendMsg(Operation.OP_INSERT, index, item);
}
public bool Remove(T item)
{
var result = m_Objects.Remove(item);
if (result)
{
SendMsg(Operation.OP_REMOVE, 0, item);
}
return result;
}
public void RemoveAt(int index)
{
m_Objects.RemoveAt(index);
SendMsg(Operation.OP_REMOVEAT, index);
}
public void Dirty(int index)
{
SendMsg(Operation.OP_DIRTY, index, m_Objects[index]);
}
public T this[int i]
{
get { return m_Objects[i]; }
set
{
bool changed = false;
if (m_Objects[i] == null)
{
if (value == null)
return;
else
changed = true;
}
else
{
changed = !m_Objects[i].Equals(value);
}
m_Objects[i] = value;
if (changed)
{
SendMsg(Operation.OP_SET, i, value);
}
}
}
public IEnumerator<T> GetEnumerator()
{
return m_Objects.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,194 @@
using System;
#if ENABLE_UNET
namespace UnityEngine.Networking
{
// Handles network messages on client and server
public delegate void NetworkMessageDelegate(NetworkMessage netMsg);
// Handles requests to spawn objects on the client
public delegate GameObject SpawnDelegate(Vector3 position, NetworkHash128 assetId);
// Handles requests to unspawn objects on the client
public delegate void UnSpawnDelegate(GameObject spawned);
// built-in system network messages
public class MsgType
{
// internal system messages - cannot be replaced by user code
public const short ObjectDestroy = 1;
public const short Rpc = 2;
public const short ObjectSpawn = 3;
public const short Owner = 4;
public const short Command = 5;
public const short LocalPlayerTransform = 6;
public const short SyncEvent = 7;
public const short UpdateVars = 8;
public const short SyncList = 9;
public const short ObjectSpawnScene = 10;
public const short NetworkInfo = 11;
public const short SpawnFinished = 12;
public const short ObjectHide = 13;
public const short CRC = 14;
public const short LocalClientAuthority = 15;
public const short LocalChildTransform = 16;
public const short Fragment = 17;
public const short PeerClientAuthority = 18;
// used for profiling
internal const short UserMessage = 0;
internal const short HLAPIMsg = 28;
internal const short LLAPIMsg = 29;
internal const short HLAPIResend = 30;
internal const short HLAPIPending = 31;
public const short InternalHighest = 31;
// public system messages - can be replaced by user code
public const short Connect = 32;
public const short Disconnect = 33;
public const short Error = 34;
public const short Ready = 35;
public const short NotReady = 36;
public const short AddPlayer = 37;
public const short RemovePlayer = 38;
public const short Scene = 39;
public const short Animation = 40;
public const short AnimationParameters = 41;
public const short AnimationTrigger = 42;
public const short LobbyReadyToBegin = 43;
public const short LobbySceneLoaded = 44;
public const short LobbyAddPlayerFailed = 45;
public const short LobbyReturnToLobby = 46;
#if ENABLE_UNET_HOST_MIGRATION
public const short ReconnectPlayer = 47;
#endif
//NOTE: update msgLabels below if this is changed.
public const short Highest = 47;
static internal string[] msgLabels =
{
"none",
"ObjectDestroy",
"Rpc",
"ObjectSpawn",
"Owner",
"Command",
"LocalPlayerTransform",
"SyncEvent",
"UpdateVars",
"SyncList",
"ObjectSpawnScene", // 10
"NetworkInfo",
"SpawnFinished",
"ObjectHide",
"CRC",
"LocalClientAuthority",
"LocalChildTransform",
"Fragment",
"PeerClientAuthority",
"",
"", // 20
"",
"",
"",
"",
"",
"",
"",
"",
"",
"", // 30
"", // - SystemInternalHighest
"Connect", // 32,
"Disconnect",
"Error",
"Ready",
"NotReady",
"AddPlayer",
"RemovePlayer",
"Scene",
"Animation", // 40
"AnimationParams",
"AnimationTrigger",
"LobbyReadyToBegin",
"LobbySceneLoaded",
"LobbyAddPlayerFailed", // 45
"LobbyReturnToLobby", // 46
#if ENABLE_UNET_HOST_MIGRATION
"ReconnectPlayer", // 47
#endif
};
static public string MsgTypeToString(short value)
{
if (value < 0 || value > Highest)
{
return String.Empty;
}
string result = msgLabels[value];
if (string.IsNullOrEmpty(result))
{
result = "[" + value + "]";
}
return result;
}
}
public class NetworkMessage
{
public const int MaxMessageSize = (64 * 1024) - 1;
public short msgType;
public NetworkConnection conn;
public NetworkReader reader;
public int channelId;
public static string Dump(byte[] payload, int sz)
{
string outStr = "[";
for (int i = 0; i < sz; i++)
{
outStr += (payload[i] + " ");
}
outStr += "]";
return outStr;
}
public TMsg ReadMessage<TMsg>() where TMsg : MessageBase, new()
{
var msg = new TMsg();
msg.Deserialize(reader);
return msg;
}
public void ReadMessage<TMsg>(TMsg msg) where TMsg : MessageBase
{
msg.Deserialize(reader);
}
}
public enum Version
{
Current = 1
}
public class Channels
{
public const int DefaultReliable = 0;
public const int DefaultUnreliable = 1;
}
public enum ChannelOption
{
MaxPendingBuffers = 1,
AllowFragmentation = 2,
MaxPacketSize = 3
// maybe add an InitialCapacity for Pending Buffers list if needed in the future
}
}
#endif //ENABLE_UNET

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{5F1B8F9B-4500-4D09-808B-F43E8337DF05}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>UnityEngine.Networking</RootNamespace>
<AssemblyName>UnityEngine.Networking</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProductVersion>12.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;ENABLE_UNET;ENABLE_UNET_HOST_MIGRATION</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;ENABLE_UNET;ENABLE_UNET_HOST_MIGRATION</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="UnityEngine">
<HintPath>..\lib\UnityEngine.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ChannelBuffer.cs" />
<Compile Include="ChannelPacket.cs" />
<Compile Include="ClientScene.cs" />
<Compile Include="ConnectionArray.cs" />
<Compile Include="CustomAttributes.cs" />
<Compile Include="DotNetCompatibility.cs" />
<Compile Include="LocalConnections.cs" />
<Compile Include="LogFilter.cs" />
<Compile Include="Messages.cs" />
<Compile Include="NetworkAnimator.cs" />
<Compile Include="NetworkBuffer.cs" />
<Compile Include="NetworkCRC.cs" />
<Compile Include="NetworkDiscovery.cs" />
<Compile Include="NetworkHash128.cs" />
<Compile Include="NetworkInstanceId.cs" />
<Compile Include="NetworkLobbyManager.cs" />
<Compile Include="NetworkLobbyPlayer.cs" />
<Compile Include="NetworkMessageHandlers.cs" />
<Compile Include="NetworkProximityChecker.cs" />
<Compile Include="NetworkScene.cs" />
<Compile Include="NetworkSceneId.cs" />
<Compile Include="NetworkStartPosition.cs" />
<Compile Include="NetworkTranformChild.cs" />
<Compile Include="NetworkTransform.cs" />
<Compile Include="NetworkTransformVisualizer.cs" />
<Compile Include="PlayerController.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="NetworkClient.cs" />
<Compile Include="NetworkConnection.cs" />
<Compile Include="LocalClient.cs" />
<Compile Include="NetworkManager.cs" />
<Compile Include="NetworkManagerHUD.cs" />
<Compile Include="NetworkBehaviour.cs" />
<Compile Include="NetworkIdentity.cs" />
<Compile Include="UNetwork.cs" />
<Compile Include="NetworkReader.cs" />
<Compile Include="NetworkServer.cs" />
<Compile Include="SyncList.cs" />
<Compile Include="NetworkWriter.cs" />
<Compile Include="NetworkMigrationManager.cs" />
<Compile Include="NetworkServerSimple.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="AfterBuild">
<MakeDir Directories="$(ProjectDir)..\Output\Standalone" />
<Copy SourceFiles="$(TargetDir)$(TargetName).dll" DestinationFiles="$(ProjectDir)..\Output\Standalone\$(TargetName).dll" />
<Copy Condition="'$(Configuration)' == 'Debug' And '$(OS)' == 'Unix'" SourceFiles="$(TargetDir)$(TargetName).dll.mdb" DestinationFiles="$(ProjectDir)..\Output\Standalone\$(TargetName).dll.mdb" />
<Copy Condition="'$(Configuration)' == 'Debug' And '$(OS)' != 'Unix'" SourceFiles="$(TargetDir)$(TargetName).pdb" DestinationFiles="$(ProjectDir)..\Output\Standalone\$(TargetName).pdb" />
<!--Uncomment the block below and change the destination to copy the built dll into your unity install directory-->
<!--<Copy SourceFiles="$(TargetDir)$(TargetName).dll" DestinationFiles="C:\Program Files\Unity\Editor\Data\UnityExtensions\Unity\Networking\Standalone\$(TargetName).dll"/>
<Copy Condition="'$(Configuration)' == 'Debug'" SourceFiles="$(TargetDir)$(TargetName).mdb" DestinationFiles="C:\Program Files\Unity\Editor\Data\UnityExtensions\Unity\Networking\Standalone\$(TargetName).mdb"/>-->
<!--<Copy SourceFiles="$(TargetDir)$(TargetName).dll" DestinationFiles="/Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/Networking/Standalone/$(TargetName).dll"/>
<Copy Condition="'$(Configuration)' == 'Debug'" SourceFiles="$(TargetDir)$(TargetName).dll.mdb" DestinationFiles="/Applications/Unity/Unity.app/Contents/UnityExtensions/Unity/Networking/Standalone/$(TargetName).dll.mdb"/>-->
</Target>
</Project>

View File

@ -0,0 +1,28 @@
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("Unity.UNetWeaver")]
[assembly: AssemblyDescription("UNET assembly post processor for code generation.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Unity Technologies")]
[assembly: AssemblyProduct("Unity.UNetWeaver")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: InternalsVisibleTo("Assembly-CSharp-Editor-testable")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@ -0,0 +1,227 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Mdb;
using Mono.Cecil.Pdb;
namespace Unity.UNetWeaver
{
class Helpers
{
// This code is taken from SerializationWeaver
class AddSearchDirectoryHelper
{
delegate void AddSearchDirectoryDelegate(string directory);
readonly AddSearchDirectoryDelegate _addSearchDirectory;
public AddSearchDirectoryHelper(IAssemblyResolver assemblyResolver)
{
// reflection is used because IAssemblyResolver doesn't implement AddSearchDirectory but both DefaultAssemblyResolver and NuGetAssemblyResolver do
var addSearchDirectory = assemblyResolver.GetType().GetMethod("AddSearchDirectory", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) }, null);
if (addSearchDirectory == null)
throw new Exception("Assembly resolver doesn't implement AddSearchDirectory method.");
_addSearchDirectory = (AddSearchDirectoryDelegate)Delegate.CreateDelegate(typeof(AddSearchDirectoryDelegate), assemblyResolver, addSearchDirectory);
}
public void AddSearchDirectory(string directory)
{
_addSearchDirectory(directory);
}
}
public static string UnityEngineDLLDirectoryName()
{
var directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase);
return directoryName != null ? directoryName.Replace(@"file:\", "") : null;
}
public static ISymbolReaderProvider GetSymbolReaderProvider(string inputFile)
{
string nakedFileName = inputFile.Substring(0, inputFile.Length - 4);
if (File.Exists(nakedFileName + ".pdb"))
{
Console.WriteLine("Symbols will be read from " + nakedFileName + ".pdb");
return new PdbReaderProvider();
}
if (File.Exists(nakedFileName + ".dll.mdb"))
{
Console.WriteLine("Symbols will be read from " + nakedFileName + ".dll.mdb");
return new MdbReaderProvider();
}
Console.WriteLine("No symbols for " + inputFile);
return null;
}
public static bool InheritsFromSyncList(TypeReference typeRef)
{
try
{
// value types cant inherit from SyncList<T>
if (typeRef.IsValueType)
{
return false;
}
foreach (var type in ResolveInheritanceHierarchy(typeRef))
{
// only need to check for generic instances, as we're looking for SyncList<T>
if (type.IsGenericInstance)
{
// resolves the instance type to it's generic type definition, for example SyncList<Int> to SyncList<T>
var typeDef = type.Resolve();
if (typeDef.HasGenericParameters && typeDef.FullName == Weaver.SyncListType.FullName)
{
return true;
}
}
}
}
catch
{
// sometimes this will fail if we reference a weird library that can't be resolved, so we just swallow that exception and return false
}
return false;
}
public static IEnumerable<TypeReference> ResolveInheritanceHierarchy(TypeReference type)
{
// for value types the hierarchy is pre-defined as "<Self> : System.ValueType : System.Object"
if (type.IsValueType)
{
yield return type;
yield return Weaver.valueTypeType;
yield return Weaver.objectType;
yield break;
}
// resolve entire hierarchy from <Self> to System.Object
while (type != null && type.FullName != Weaver.objectType.FullName)
{
yield return type;
try
{
var typeDef = type.Resolve();
if (typeDef == null)
{
break;
}
else
{
type = typeDef.BaseType;
}
}
catch
{
// when calling type.Resolve() we can sometimes get an exception if some dependant library
// could not be loaded (for whatever reason) so just swallow it and break out of the loop
break;
}
}
yield return Weaver.objectType;
}
public static string DestinationFileFor(string outputDir, string assemblyPath)
{
var fileName = Path.GetFileName(assemblyPath);
Debug.Assert(fileName != null, "fileName != null");
return Path.Combine(outputDir, fileName);
}
public static string PrettyPrintType(TypeReference type)
{
// generic instances, such as List<Int32>
if (type.IsGenericInstance)
{
var giType = (GenericInstanceType)type;
return giType.Name.Substring(0, giType.Name.Length - 2) + "<" + String.Join(", ", giType.GenericArguments.Select<TypeReference, String>(PrettyPrintType).ToArray()) + ">";
}
// generic types, such as List<T>
if (type.HasGenericParameters)
{
return type.Name.Substring(0, type.Name.Length - 2) + "<" + String.Join(", ", type.GenericParameters.Select<GenericParameter, String>(x => x.Name).ToArray()) + ">";
}
// non-generic type such as Int
return type.Name;
}
public static ReaderParameters ReaderParameters(string assemblyPath, IEnumerable<string> extraPaths, IAssemblyResolver assemblyResolver, string unityEngineDLLPath, string unityUNetDLLPath)
{
var parameters = new ReaderParameters();
if (assemblyResolver == null)
assemblyResolver = new DefaultAssemblyResolver();
var helper = new AddSearchDirectoryHelper(assemblyResolver);
helper.AddSearchDirectory(Path.GetDirectoryName(assemblyPath));
helper.AddSearchDirectory(Helpers.UnityEngineDLLDirectoryName());
helper.AddSearchDirectory(Path.GetDirectoryName(unityEngineDLLPath));
helper.AddSearchDirectory(Path.GetDirectoryName(unityUNetDLLPath));
if (extraPaths != null)
{
foreach (var path in extraPaths)
helper.AddSearchDirectory(path);
}
parameters.AssemblyResolver = assemblyResolver;
parameters.SymbolReaderProvider = GetSymbolReaderProvider(assemblyPath);
return parameters;
}
public static WriterParameters GetWriterParameters(ReaderParameters readParams)
{
var writeParams = new WriterParameters();
if (readParams.SymbolReaderProvider is PdbReaderProvider)
{
//Log("Will export symbols of pdb format");
writeParams.SymbolWriterProvider = new PdbWriterProvider();
}
else if (readParams.SymbolReaderProvider is MdbReaderProvider)
{
//Log("Will export symbols of mdb format");
writeParams.SymbolWriterProvider = new MdbWriterProvider();
}
return writeParams;
}
public static TypeReference MakeGenericType(TypeReference self, params TypeReference[] arguments)
{
if (self.GenericParameters.Count != arguments.Length)
throw new ArgumentException();
var instance = new GenericInstanceType(self);
foreach (var argument in arguments)
instance.GenericArguments.Add(argument);
return instance;
}
// used to get a specialized method on a generic class, such as SyncList<T>::HandleMsg()
public static MethodReference MakeHostInstanceGeneric(MethodReference self, params TypeReference[] arguments)
{
var reference = new MethodReference(self.Name, self.ReturnType, MakeGenericType(self.DeclaringType, arguments))
{
HasThis = self.HasThis,
ExplicitThis = self.ExplicitThis,
CallingConvention = self.CallingConvention
};
foreach (var parameter in self.Parameters)
reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType));
foreach (var genericParameter in self.GenericParameters)
reference.GenericParameters.Add(new GenericParameter(genericParameter.Name, reference));
return reference;
}
}
}

View File

@ -0,0 +1,152 @@
using System;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Unity.UNetWeaver
{
class MessageClassProcessor
{
TypeDefinition m_td;
public MessageClassProcessor(TypeDefinition td)
{
Weaver.DLog(td, "MessageClassProcessor for " + td.Name);
m_td = td;
}
public void Process()
{
Weaver.DLog(m_td, "MessageClassProcessor Start");
Weaver.ResetRecursionCount();
GenerateSerialization();
if (Weaver.fail)
{
return;
}
GenerateDeSerialization();
Weaver.DLog(m_td, "MessageClassProcessor Done");
}
void GenerateSerialization()
{
Weaver.DLog(m_td, " GenerateSerialization");
foreach (var m in m_td.Methods)
{
if (m.Name == "Serialize")
return;
}
if (m_td.Fields.Count == 0)
{
return;
}
// check for self-referencing types
foreach (var field in m_td.Fields)
{
if (field.FieldType.FullName == m_td.FullName)
{
Weaver.fail = true;
Log.Error("GenerateSerialization for " + m_td.Name + " [" + field.FullName + "]. [MessageBase] member cannot be self referencing.");
return;
}
}
MethodDefinition serializeFunc = new MethodDefinition("Serialize", MethodAttributes.Public |
MethodAttributes.Virtual |
MethodAttributes.HideBySig,
Weaver.voidType);
serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkWriterType)));
ILProcessor serWorker = serializeFunc.Body.GetILProcessor();
foreach (var field in m_td.Fields)
{
if (field.IsStatic || field.IsPrivate || field.IsSpecialName)
continue;
if (field.FieldType.Resolve().HasGenericParameters)
{
Weaver.fail = true;
Log.Error("GenerateSerialization for " + m_td.Name + " [" + field.FieldType + "/" + field.FieldType.FullName + "]. [MessageBase] member cannot have generic parameters.");
return;
}
if (field.FieldType.Resolve().IsInterface)
{
Weaver.fail = true;
Log.Error("GenerateSerialization for " + m_td.Name + " [" + field.FieldType + "/" + field.FieldType.FullName + "]. [MessageBase] member cannot be an interface.");
return;
}
MethodReference writeFunc = Weaver.GetWriteFunc(field.FieldType);
if (writeFunc != null)
{
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
serWorker.Append(serWorker.Create(OpCodes.Ldfld, field));
serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc));
}
else
{
Weaver.fail = true;
Log.Error("GenerateSerialization for " + m_td.Name + " unknown type [" + field.FieldType + "/" + field.FieldType.FullName + "]. [MessageBase] member variables must be basic types.");
return;
}
}
serWorker.Append(serWorker.Create(OpCodes.Ret));
m_td.Methods.Add(serializeFunc);
}
void GenerateDeSerialization()
{
Weaver.DLog(m_td, " GenerateDeserialization");
foreach (var m in m_td.Methods)
{
if (m.Name == "Deserialize")
return;
}
if (m_td.Fields.Count == 0)
{
return;
}
MethodDefinition serializeFunc = new MethodDefinition("Deserialize", MethodAttributes.Public |
MethodAttributes.Virtual |
MethodAttributes.HideBySig,
Weaver.voidType);
serializeFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkReaderType)));
ILProcessor serWorker = serializeFunc.Body.GetILProcessor();
foreach (var field in m_td.Fields)
{
if (field.IsStatic || field.IsPrivate || field.IsSpecialName)
continue;
MethodReference readerFunc = Weaver.GetReadFunc(field.FieldType);
if (readerFunc != null)
{
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
serWorker.Append(serWorker.Create(OpCodes.Call, readerFunc));
serWorker.Append(serWorker.Create(OpCodes.Stfld, field));
}
else
{
Weaver.fail = true;
Log.Error("GenerateDeSerialization for " + m_td.Name + " unknown type [" + field.FieldType + "]. [SyncVar] member variables must be basic types.");
return;
}
}
serWorker.Append(serWorker.Create(OpCodes.Ret));
m_td.Methods.Add(serializeFunc);
}
}
}

View File

@ -0,0 +1,95 @@
using System;
using System.Linq;
using Mono.Cecil;
namespace Unity.UNetWeaver
{
class MonoBehaviourProcessor
{
TypeDefinition m_td;
public MonoBehaviourProcessor(TypeDefinition td)
{
m_td = td;
}
public void Process()
{
ProcessSyncVars();
ProcessMethods();
}
void ProcessSyncVars()
{
// find syncvars
foreach (FieldDefinition fd in m_td.Fields)
{
foreach (var ca in fd.CustomAttributes)
{
if (ca.AttributeType.FullName == Weaver.SyncVarType.FullName)
{
Log.Error("Script " + m_td.FullName + " uses [SyncVar] " + fd.Name + " but is not a NetworkBehaviour.");
Weaver.fail = true;
}
}
if (Helpers.InheritsFromSyncList(fd.FieldType))
{
Log.Error(string.Format("Script {0} defines field {1} with type {2}, but it's not a NetworkBehaviour", m_td.FullName, fd.Name, Helpers.PrettyPrintType(fd.FieldType)));
Weaver.fail = true;
}
}
}
void ProcessMethods()
{
// find command and RPC functions
foreach (MethodDefinition md in m_td.Methods)
{
foreach (var ca in md.CustomAttributes)
{
if (ca.AttributeType.FullName == Weaver.CommandType.FullName)
{
Log.Error("Script " + m_td.FullName + " uses [Command] " + md.Name + " but is not a NetworkBehaviour.");
Weaver.fail = true;
}
if (ca.AttributeType.FullName == Weaver.ClientRpcType.FullName)
{
Log.Error("Script " + m_td.FullName + " uses [ClientRpc] " + md.Name + " but is not a NetworkBehaviour.");
Weaver.fail = true;
}
if (ca.AttributeType.FullName == Weaver.TargetRpcType.FullName)
{
Log.Error("Script " + m_td.FullName + " uses [TargetRpc] " + md.Name + " but is not a NetworkBehaviour.");
Weaver.fail = true;
}
var attrName = ca.Constructor.DeclaringType.ToString();
if (attrName == "UnityEngine.Networking.ServerAttribute")
{
Log.Error("Script " + m_td.FullName + " uses the attribute [Server] on the method " + md.Name + " but is not a NetworkBehaviour.");
Weaver.fail = true;
}
else if (attrName == "UnityEngine.Networking.ServerCallbackAttribute")
{
Log.Error("Script " + m_td.FullName + " uses the attribute [ServerCallback] on the method " + md.Name + " but is not a NetworkBehaviour.");
Weaver.fail = true;
}
else if (attrName == "UnityEngine.Networking.ClientAttribute")
{
Log.Error("Script " + m_td.FullName + " uses the attribute [Client] on the method " + md.Name + " but is not a NetworkBehaviour.");
Weaver.fail = true;
}
else if (attrName == "UnityEngine.Networking.ClientCallbackAttribute")
{
Log.Error("Script " + m_td.FullName + " uses the attribute [ClientCallback] on the method " + md.Name + " but is not a NetworkBehaviour.");
Weaver.fail = true;
}
}
}
}
};
}

View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.IO;
using Mono.Cecil;
namespace Unity.UNetWeaver
{
public static class Log
{
public static Action<string> WarningMethod;
public static Action<string> ErrorMethod;
public static void Warning(string msg)
{
WarningMethod("UNetWeaver warning: " + msg);
}
public static void Error(string msg)
{
ErrorMethod("UNetWeaver error: " + msg);
}
}
public class Program
{
public static bool Process(string unityEngine, string unetDLL, string outputDirectory, string[] assemblies, string[] extraAssemblyPaths, IAssemblyResolver assemblyResolver, Action<string> printWarning, Action<string> printError)
{
CheckDLLPath(unityEngine);
CheckDLLPath(unetDLL);
CheckOutputDirectory(outputDirectory);
CheckAssemblies(assemblies);
Log.WarningMethod = printWarning;
Log.ErrorMethod = printError;
return Weaver.WeaveAssemblies(assemblies, extraAssemblyPaths, assemblyResolver, outputDirectory, unityEngine, unetDLL);
}
private static void CheckDLLPath(string path)
{
if (!File.Exists(path))
throw new Exception("dll could not be located at " + path + "!");
}
private static void CheckAssemblies(IEnumerable<string> assemblyPaths)
{
foreach (var assemblyPath in assemblyPaths)
CheckAssemblyPath(assemblyPath);
}
private static void CheckAssemblyPath(string assemblyPath)
{
if (!File.Exists(assemblyPath))
throw new Exception("Assembly " + assemblyPath + " does not exist!");
}
private static void CheckOutputDirectory(string outputDir)
{
if (!Directory.Exists(outputDir))
Directory.CreateDirectory(outputDir);
}
}
}

View File

@ -0,0 +1,353 @@
using System;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Unity.UNetWeaver
{
class SyncListStructProcessor
{
TypeDefinition m_TypeDef;
TypeReference m_ItemType;
public SyncListStructProcessor(TypeDefinition typeDef)
{
Weaver.DLog(typeDef, "SyncListStructProcessor for " + typeDef.Name);
m_TypeDef = typeDef;
}
public void Process()
{
// find item type
var gt = (GenericInstanceType)m_TypeDef.BaseType;
if (gt.GenericArguments.Count == 0)
{
Weaver.fail = true;
Log.Error("SyncListStructProcessor no generic args");
return;
}
m_ItemType = Weaver.scriptDef.MainModule.ImportReference(gt.GenericArguments[0]);
Weaver.DLog(m_TypeDef, "SyncListStructProcessor Start item:" + m_ItemType.FullName);
Weaver.ResetRecursionCount();
var writeItemFunc = GenerateSerialization();
if (Weaver.fail)
{
return;
}
var readItemFunc = GenerateDeserialization();
if (readItemFunc == null || writeItemFunc == null)
return;
GenerateReadFunc(readItemFunc);
GenerateWriteFunc(writeItemFunc);
Weaver.DLog(m_TypeDef, "SyncListStructProcessor Done");
}
/* deserialization of entire list. generates code like:
*
static public void ReadStructBuf(NetworkReader reader, SyncListBuf instance)
{
ushort count = reader.ReadUInt16();
instance.Clear()
for (ushort i = 0; i < count; i++)
{
instance.AddInternal(instance.DeserializeItem(reader));
}
}
*/
void GenerateReadFunc(MethodReference readItemFunc)
{
var functionName = "_ReadStruct" + m_TypeDef.Name + "_";
if (m_TypeDef.DeclaringType != null)
{
functionName += m_TypeDef.DeclaringType.Name;
}
else
{
functionName += "None";
}
// create new reader for this type
MethodDefinition readerFunc = new MethodDefinition(functionName,
MethodAttributes.Public |
MethodAttributes.Static |
MethodAttributes.HideBySig,
Weaver.voidType);
readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkReaderType)));
readerFunc.Parameters.Add(new ParameterDefinition("instance", ParameterAttributes.None, m_TypeDef));
readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.uint16Type));
readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.uint16Type));
readerFunc.Body.InitLocals = true;
ILProcessor worker = readerFunc.Body.GetILProcessor();
worker.Append(worker.Create(OpCodes.Ldarg_0));
worker.Append(worker.Create(OpCodes.Callvirt, Weaver.NetworkReadUInt16));
worker.Append(worker.Create(OpCodes.Stloc_0));
// Call Clear() from the base class
worker.Append(worker.Create(OpCodes.Ldarg_1));
MethodReference genericClearMethod = Helpers.MakeHostInstanceGeneric(Weaver.SyncListClear, m_ItemType);
worker.Append(worker.Create(OpCodes.Callvirt, genericClearMethod));
worker.Append(worker.Create(OpCodes.Ldc_I4_0));
worker.Append(worker.Create(OpCodes.Stloc_1));
var loopCheckLabel = worker.Create(OpCodes.Nop);
worker.Append(worker.Create(OpCodes.Br, loopCheckLabel));
// loop body
var loopHeadLabel = worker.Create(OpCodes.Nop);
worker.Append(loopHeadLabel);
worker.Append(worker.Create(OpCodes.Ldarg_1));
worker.Append(worker.Create(OpCodes.Ldarg_1));
worker.Append(worker.Create(OpCodes.Ldarg_0));
worker.Append(worker.Create(OpCodes.Callvirt, readItemFunc));
// call the generic AddInternal from the base class
var addInternal = Weaver.ResolveMethod(Weaver.SyncListStructType, "AddInternal");
var addInternalTyped = Helpers.MakeHostInstanceGeneric(addInternal, m_ItemType);
worker.Append(worker.Create(OpCodes.Callvirt, addInternalTyped));
worker.Append(worker.Create(OpCodes.Ldloc_1));
worker.Append(worker.Create(OpCodes.Ldc_I4_1));
worker.Append(worker.Create(OpCodes.Add));
worker.Append(worker.Create(OpCodes.Conv_U2));
worker.Append(worker.Create(OpCodes.Stloc_1));
// loop check
worker.Append(loopCheckLabel);
worker.Append(worker.Create(OpCodes.Ldloc_1));
worker.Append(worker.Create(OpCodes.Ldloc_0));
worker.Append(worker.Create(OpCodes.Blt, loopHeadLabel));
// done
//worker.Append(worker.Create(OpCodes.Ldloc_1));
worker.Append(worker.Create(OpCodes.Ret));
Weaver.RegisterReadByReferenceFunc(m_TypeDef.FullName, readerFunc);
}
/*serialization of entire list. generates code like:
*
static public void WriteStructBuf(NetworkWriter writer, SyncListBuf items)
{
ushort count = (ushort)items.Count;
writer.Write(count);
for (ushort i=0; i < count; i++)
{
items.SerializeItem(writer, items.GetItem(i));
}
}
*/
void GenerateWriteFunc(MethodReference writeItemFunc)
{
var functionName = "_WriteStruct" + m_TypeDef.GetElementType().Name + "_";
if (m_TypeDef.DeclaringType != null)
{
functionName += m_TypeDef.DeclaringType.Name;
}
else
{
functionName += "None";
}
// create new writer for this type
MethodDefinition writerFunc = new MethodDefinition(functionName,
MethodAttributes.Public |
MethodAttributes.Static |
MethodAttributes.HideBySig,
Weaver.voidType);
writerFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkWriterType)));
writerFunc.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(m_TypeDef)));
writerFunc.Body.Variables.Add(new VariableDefinition(Weaver.uint16Type));
writerFunc.Body.Variables.Add(new VariableDefinition(Weaver.uint16Type));
writerFunc.Body.InitLocals = true;
ILProcessor worker = writerFunc.Body.GetILProcessor();
worker.Append(worker.Create(OpCodes.Ldarg_1));
// call the generic Count from the base class
var getCount = Weaver.ResolveMethod(Weaver.SyncListStructType, "get_Count");
var getCountTyped = Helpers.MakeHostInstanceGeneric(getCount, m_ItemType);
worker.Append(worker.Create(OpCodes.Callvirt, getCountTyped));
worker.Append(worker.Create(OpCodes.Stloc_0));
worker.Append(worker.Create(OpCodes.Ldarg_0));
worker.Append(worker.Create(OpCodes.Ldloc_0));
worker.Append(worker.Create(OpCodes.Callvirt, Weaver.NetworkWriteUInt16));
worker.Append(worker.Create(OpCodes.Ldc_I4_0));
worker.Append(worker.Create(OpCodes.Stloc_1));
var loopCheckLabel = worker.Create(OpCodes.Nop);
worker.Append(worker.Create(OpCodes.Br, loopCheckLabel));
//loop start
var loopStartLabel = worker.Create(OpCodes.Nop);
worker.Append(loopStartLabel);
worker.Append(worker.Create(OpCodes.Ldarg_1));
worker.Append(worker.Create(OpCodes.Ldarg_0));
worker.Append(worker.Create(OpCodes.Ldarg_1));
worker.Append(worker.Create(OpCodes.Ldloc_1));
// call the generic [] from the base class
var getItem = Weaver.ResolveMethod(Weaver.SyncListStructType, "GetItem");
var getItemTyped = Helpers.MakeHostInstanceGeneric(getItem, m_ItemType);
worker.Append(worker.Create(OpCodes.Callvirt, getItemTyped));
worker.Append(worker.Create(OpCodes.Callvirt, writeItemFunc));
worker.Append(worker.Create(OpCodes.Ldloc_1));
worker.Append(worker.Create(OpCodes.Ldc_I4_1));
worker.Append(worker.Create(OpCodes.Add));
worker.Append(worker.Create(OpCodes.Conv_U2));
worker.Append(worker.Create(OpCodes.Stloc_1));
worker.Append(loopCheckLabel);
worker.Append(worker.Create(OpCodes.Ldloc_1));
worker.Append(worker.Create(OpCodes.Ldloc_0));
worker.Append(worker.Create(OpCodes.Blt, loopStartLabel));
worker.Append(worker.Create(OpCodes.Ret));
Weaver.RegisterWriteFunc(m_TypeDef.FullName, writerFunc);
}
// serialization of individual element
MethodReference GenerateSerialization()
{
Weaver.DLog(m_TypeDef, " GenerateSerialization");
foreach (var m in m_TypeDef.Methods)
{
if (m.Name == "SerializeItem")
return m;
}
MethodDefinition serializeFunc = new MethodDefinition("SerializeItem", MethodAttributes.Public |
MethodAttributes.Virtual |
MethodAttributes.Public |
MethodAttributes.HideBySig,
Weaver.voidType);
serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkWriterType)));
serializeFunc.Parameters.Add(new ParameterDefinition("item", ParameterAttributes.None, m_ItemType));
ILProcessor serWorker = serializeFunc.Body.GetILProcessor();
if (m_ItemType.IsGenericInstance)
{
Weaver.fail = true;
Log.Error("GenerateSerialization for " + Helpers.PrettyPrintType(m_ItemType) + " failed. Struct passed into SyncListStruct<T> can't have generic parameters");
return null;
}
foreach (var field in m_ItemType.Resolve().Fields)
{
if (field.IsStatic || field.IsPrivate || field.IsSpecialName)
continue;
var importedField = Weaver.scriptDef.MainModule.ImportReference(field);
var ft = importedField.FieldType.Resolve();
if (ft.HasGenericParameters)
{
Weaver.fail = true;
Log.Error("GenerateSerialization for " + m_TypeDef.Name + " [" + ft + "/" + ft.FullName + "]. UNet [MessageBase] member cannot have generic parameters.");
return null;
}
if (ft.IsInterface)
{
Weaver.fail = true;
Log.Error("GenerateSerialization for " + m_TypeDef.Name + " [" + ft + "/" + ft.FullName + "]. UNet [MessageBase] member cannot be an interface.");
return null;
}
MethodReference writeFunc = Weaver.GetWriteFunc(field.FieldType);
if (writeFunc != null)
{
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
serWorker.Append(serWorker.Create(OpCodes.Ldfld, importedField));
serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc));
}
else
{
Weaver.fail = true;
Log.Error("GenerateSerialization for " + m_TypeDef.Name + " unknown type [" + ft + "/" + ft.FullName + "]. UNet [MessageBase] member variables must be basic types.");
return null;
}
}
serWorker.Append(serWorker.Create(OpCodes.Ret));
m_TypeDef.Methods.Add(serializeFunc);
return serializeFunc;
}
MethodReference GenerateDeserialization()
{
Weaver.DLog(m_TypeDef, " GenerateDeserialization");
foreach (var m in m_TypeDef.Methods)
{
if (m.Name == "DeserializeItem")
return m;
}
MethodDefinition serializeFunc = new MethodDefinition("DeserializeItem", MethodAttributes.Public |
MethodAttributes.Virtual |
MethodAttributes.Public |
MethodAttributes.HideBySig,
m_ItemType);
serializeFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkReaderType)));
ILProcessor serWorker = serializeFunc.Body.GetILProcessor();
serWorker.Body.InitLocals = true;
serWorker.Body.Variables.Add(new VariableDefinition(m_ItemType));
// init item instance
serWorker.Append(serWorker.Create(OpCodes.Ldloca, 0));
serWorker.Append(serWorker.Create(OpCodes.Initobj, m_ItemType));
foreach (var field in m_ItemType.Resolve().Fields)
{
if (field.IsStatic || field.IsPrivate || field.IsSpecialName)
continue;
var importedField = Weaver.scriptDef.MainModule.ImportReference(field);
var ft = importedField.FieldType.Resolve();
MethodReference readerFunc = Weaver.GetReadFunc(field.FieldType);
if (readerFunc != null)
{
serWorker.Append(serWorker.Create(OpCodes.Ldloca, 0));
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
serWorker.Append(serWorker.Create(OpCodes.Call, readerFunc));
serWorker.Append(serWorker.Create(OpCodes.Stfld, importedField));
}
else
{
Weaver.fail = true;
Log.Error("GenerateDeserialization for " + m_TypeDef.Name + " unknown type [" + ft + "]. UNet [SyncVar] member variables must be basic types.");
return null;
}
}
serWorker.Append(serWorker.Create(OpCodes.Ldloc_0));
serWorker.Append(serWorker.Create(OpCodes.Ret));
m_TypeDef.Methods.Add(serializeFunc);
return serializeFunc;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{709222FD-15C2-497D-8B31-366ADCC074CD}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Unity.UNetWeaver</RootNamespace>
<AssemblyName>Unity.UNetWeaver</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="Unity.Cecil">
<HintPath>..\External\Unity.Cecil\lib\net35\Unity.Cecil.dll</HintPath>
</Reference>
<Reference Include="Unity.Cecil.Mdb">
<HintPath>..\External\Unity.Cecil\lib\net35\Unity.Cecil.Mdb.dll</HintPath>
</Reference>
<Reference Include="Unity.Cecil.Pdb">
<HintPath>..\External\Unity.Cecil\lib\net35\Unity.Cecil.Pdb.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="MessageClassProcessor.cs" />
<Compile Include="MonoBehaviourProcessor.cs" />
<Compile Include="Program.cs" />
<Compile Include="SyncListStructProcessor.cs" />
<Compile Include="UNetBehaviourProcessor.cs" />
<Compile Include="UNetWeaver.cs" />
<Compile Include="Helpers.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Target Name="AfterBuild">
<MakeDir Directories="$(ProjectDir)..\Output\Weaver" />
<Copy SourceFiles="$(TargetDir)$(TargetName).dll" DestinationFiles="$(ProjectDir)..\Output\Weaver\$(TargetName).dll" />
<Copy Condition="'$(Configuration)' == 'Debug' And '$(OS)' == 'Unix'" SourceFiles="$(TargetDir)$(TargetName).dll.mdb" DestinationFiles="$(ProjectDir)..\Output\Weaver\$(TargetName).dll.mdb" />
<Copy Condition="'$(Configuration)' == 'Debug' And '$(OS)' != 'Unix'" SourceFiles="$(TargetDir)$(TargetName).pdb" DestinationFiles="$(ProjectDir)..\Output\Weaver\$(TargetName).pdb" />
<!--Uncomment the block below and change the destination to copy the built dll into your unity install directory-->
<!--<Copy SourceFiles="$(TargetDir)$(TargetName).dll" DestinationFiles="C:\Program Files\Unity\Editor\Data\Managed\$(TargetName).dll"/>
<Copy Condition="'$(Configuration)' == 'Debug'" SourceFiles="$(TargetDir)$(TargetName).mdb" DestinationFiles="C:\Program Files\Unity\Editor\Data\Managed\$(TargetName).mdb"/>-->
<!--<Copy SourceFiles="$(TargetDir)$(TargetName).dll" DestinationFiles="/Applications/Unity/Unity.app/Contents/Managed/$(TargetName).dll" />
<Copy Condition="'$(Configuration)' == 'Debug'" SourceFiles="$(TargetDir)$(TargetName).dll.mdb" DestinationFiles="/Applications/Unity/Unity.app/Contents/Managed/$(TargetName).dll.mdb" />-->
</Target>
</Project>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.