public void RebuildObservers(bool initialize) { if (m_Observers == null) { return; } bool changed = false; bool result = false; HashSet <NetworkConnection> newObservers = new HashSet <NetworkConnection>(); HashSet <NetworkConnection> oldObservers = new HashSet <NetworkConnection>(m_Observers); for (int i = 0; i < m_NetworkBehaviours.Length; i++) { NetworkBehaviour comp = m_NetworkBehaviours[i]; result |= comp.OnRebuildObservers(newObservers, initialize); } if (!result) { // none of the behaviours rebuilt our observers, use built-in rebuild method if (initialize) { for (int i = 0; i < NetworkServer.connections.Count; i++) { var conn = NetworkServer.connections[i]; if (conn != null && conn.isReady) { AddObserver(conn); } } if (NetworkServer.localConnection != null && NetworkServer.localConnection.isReady) { AddObserver(NetworkServer.localConnection); } } return; } // apply changes from rebuild foreach (var conn in newObservers) { if (conn == null) { continue; } if (!conn.isReady) { if (LogFilter.logWarn) { Debug.LogWarning("Observer is not ready for " + gameObject + " " + conn); } continue; } if (initialize || !oldObservers.Contains(conn)) { // new observer conn.AddToVisList(this); if (LogFilter.logDebug) { Debug.Log("New Observer for " + gameObject + " " + conn); } changed = true; } } foreach (var conn in oldObservers) { if (!newObservers.Contains(conn)) { // removed observer conn.RemoveFromVisList(this, false); if (LogFilter.logDebug) { Debug.Log("Removed Observer for " + gameObject + " " + conn); } changed = true; } } // special case for local client. if (initialize) { if (!newObservers.Contains(NetworkServer.localConnection)) { OnSetLocalVisibility(false); } } if (changed) { m_Observers = new List <NetworkConnection>(newObservers); // rebuild hashset once we have the final set of new observers m_ObserverConnections.Clear(); for (int i = 0; i < m_Observers.Count; i++) { m_ObserverConnections.Add(m_Observers[i].connectionId); } } }
internal void OnStartServer(bool allowNonZeroNetId) { if (m_IsServer) { return; } m_IsServer = true; m_HasAuthority = !m_LocalPlayerAuthority; m_Observers = new List <NetworkConnection>(); m_ObserverConnections = new HashSet <int>(); CacheBehaviours(); // If the instance/net ID is invalid here then this is an object instantiated from a prefab and the server should assign a valid ID if (netId.IsEmpty()) { m_NetId = GetNextNetworkId(); } else { if (!allowNonZeroNetId) { if (LogFilter.logError) { Debug.LogError("Object has non-zero netId " + netId + " for " + gameObject); } return; } } if (LogFilter.logDev) { Debug.Log("OnStartServer " + gameObject + " GUID:" + netId); } NetworkServer.SetLocalObjectOnServer(netId, gameObject); for (int i = 0; i < m_NetworkBehaviours.Length; i++) { NetworkBehaviour comp = m_NetworkBehaviours[i]; try { comp.OnStartServer(); } catch (Exception e) { Debug.LogError("Exception in OnStartServer:" + e.Message + " " + e.StackTrace); } } if (NetworkClient.active && NetworkServer.localClientActive) { // there will be no spawn message, so start the client here too ClientScene.SetLocalObject(netId, gameObject); OnStartClient(); } if (m_HasAuthority) { OnStartAuthority(); } }
public void InitializeBehaviour(NetworkBehaviour beh, int cmdHash) { m_Behaviour = beh; m_CmdHash = cmdHash; }
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 (FieldInfo 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; if (field.GetValue(serializedObject.targetObject) is IEnumerable synclist) { int index = 0; IEnumerator enu = synclist.GetEnumerator(); while (enu.MoveNext()) { if (enu.Current != null) { EditorGUILayout.LabelField("Item:" + index, enu.Current.ToString()); } index += 1; } } EditorGUI.indentLevel -= 1; } syncListIndex += 1; } } // only show SyncInterval if we have an OnSerialize function. // No need to show it if the class only has Cmds/Rpcs and no sync. if (m_SyncsAnything) { NetworkBehaviour networkBehaviour = target as NetworkBehaviour; if (networkBehaviour != null) { // [0,2] should be enough. anything >2s is too laggy anyway. serializedObject.FindProperty("syncInterval").floatValue = EditorGUILayout.Slider( new GUIContent("Network Sync Interval", "Time in seconds until next change is synchronized to the client. '0' means send immediately if changed. '0.5' means only send changes every 500ms.\n(This is for state synchronization like SyncVars, SyncLists, OnSerialize. Not for Cmds, Rpcs, etc.)"), networkBehaviour.syncInterval, 0, 2); serializedObject.ApplyModifiedProperties(); } } }
public override void OnInspectorGUI() { if (!initialized) { serializedObject.Update(); SerializedProperty scriptProperty = serializedObject.FindProperty("m_Script"); if (scriptProperty == null) { return; } MonoScript targetScript = scriptProperty.objectReferenceValue as MonoScript; Init(targetScript); } #if ODIN_INSPECTOR base.Tree.DrawMonoScriptObjectField = !HideScriptField; // Draw the default properties with Odin; SyncVarDrawer<T> will take care of making SyncVar's look right, instead of the code below. DrawDefaultInspector(); #else 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 = syncVarNames.Contains(property.name); if (property.name == "m_Script") { if (HideScriptField) { continue; } EditorGUI.BeginDisabledGroup(true); } if (isSyncVar) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginVertical(); } EditorGUILayout.PropertyField(property, true); if (isSyncVar) { EditorGUILayout.EndVertical(); GUILayout.Label(syncVarIndicatorContent, EditorStyles.miniLabel, GUILayout.Width(EditorStyles.miniLabel.CalcSize(syncVarIndicatorContent).x)); EditorGUILayout.EndHorizontal(); } if (property.name == "m_Script") { EditorGUI.EndDisabledGroup(); } expanded = false; } serializedObject.ApplyModifiedProperties(); EditorGUI.EndChangeCheck(); #endif // ODIN_INSPECTOR // find SyncLists.. they are not properties. int syncListIndex = 0; foreach (FieldInfo field in serializedObject.targetObject.GetType().GetFields()) { if (field.FieldType.BaseType != null && field.FieldType.BaseType.Name.Contains("SyncList")) { showSyncLists[syncListIndex] = EditorGUILayout.Foldout(showSyncLists[syncListIndex], "SyncList " + field.Name + " [" + field.FieldType.Name + "]"); if (showSyncLists[syncListIndex]) { EditorGUI.indentLevel += 1; if (field.GetValue(serializedObject.targetObject) is IEnumerable synclist) { int index = 0; IEnumerator enu = synclist.GetEnumerator(); while (enu.MoveNext()) { if (enu.Current != null) { EditorGUILayout.LabelField("Item:" + index, enu.Current.ToString()); } index += 1; } } EditorGUI.indentLevel -= 1; } syncListIndex += 1; } } // does it sync anything? then show extra properties // (no need to show it if the class only has Cmds/Rpcs and no sync) if (syncsAnything) { NetworkBehaviour networkBehaviour = target as NetworkBehaviour; if (networkBehaviour != null) { // syncMode serializedObject.FindProperty("syncMode").enumValueIndex = (int)(SyncMode) EditorGUILayout.EnumPopup("Network Sync Mode", networkBehaviour.syncMode); // syncInterval // [0,2] should be enough. anything >2s is too laggy anyway. serializedObject.FindProperty("syncInterval").floatValue = EditorGUILayout.Slider( new GUIContent("Network Sync Interval", "Time in seconds until next change is synchronized to the client. '0' means send immediately if changed. '0.5' means only send changes every 500ms.\n(This is for state synchronization like SyncVars, SyncLists, OnSerialize. Not for Cmds, Rpcs, etc.)"), networkBehaviour.syncInterval, 0, 2); // apply serializedObject.ApplyModifiedProperties(); } } }