Need
How do I use Need
Below are practical examples compiled from projects for learning and reference purposes
Featured Snippets
File name: PhotonConverter.cs
Copy
18 public static void RunConversion()
19 {
20 //Ask if user has made a backup.
21 int option = EditorUtility.DisplayDialogComplex("Conversion", "Attempt automatic conversion from Unity Networking to Photon Unity Networking \"PUN\"?", "Yes", "No!", "Pick Script Folder");
22 switch (option)
23 {
24 case 0:
25 break;
26 case 1:
27 return;
28 case 2:
29 PickFolderAndConvertScripts();
30 return;
31 default:
32 return;
33 }
34
35 //REAAAALY?
36 bool result = EditorUtility.DisplayDialog("Conversion", "Disclaimer: The code conversion feature is quite crude, but should do it's job well (see the sourcecode). A backup is therefore strongly recommended!", "Yes, I've made a backup: GO", "Abort");
37 if (!result)
38 {
39 return;
40 }
41 Output(EditorApplication.timeSinceStartup + " Started conversion of Unity networking -> Photon");
42
43 //Ask to save current scene (optional)
44 EditorApplication.SaveCurrentSceneIfUserWantsTo();
45
46 EditorUtility.DisplayProgressBar("Converting..", "Starting.", 0);
47
48 //Convert NetworkViews to PhotonViews in Project prefabs
49 //Ask the user if we can move all prefabs to a resources folder
50 bool movePrefabs = EditorUtility.DisplayDialog("Conversion", "Can all prefabs that use a PhotonView be moved to a Resources/ folder? You need this if you use Network.Instantiate.", "Yes", "No");
51
52
53 string[] prefabs = Directory.GetFiles("Assets/", "*.prefab", SearchOption.AllDirectories);
54 foreach (string prefab in prefabs)
55 {
56 EditorUtility.DisplayProgressBar("Converting..", "Object:" + prefab, 0.6f);
57
58 Object[] objs = (Object[])AssetDatabase.LoadAllAssetsAtPath(prefab);
59 int converted = 0;
60 foreach (Object obj in objs)
61 {
62 if (obj != null && obj.GetType() == typeof(GameObject))
63 converted += ConvertNetworkView(((GameObject)obj).GetComponents
64 }
65 if (movePrefabs && converted > 0)
66 {
67 //This prefab needs to be under the root of a Resources folder!
68 string path = prefab.Replace("\\", "/");
69 int lastSlash = path.LastIndexOf("/");
70 int resourcesIndex = path.LastIndexOf("/Resources/");
71 if (resourcesIndex != lastSlash - 10)
72 {
73 if (path.Contains("/Resources/"))
74 {
75 Debug.LogWarning("Warning, prefab [" + prefab + "] was already in a resources folder. But has been placed in the root of another one!");
76 }
77 //This prefab NEEDS to be placed under a resources folder
78 string resourcesFolder = path.Substring(0, lastSlash) + "/Resources/";
79 EnsureFolder(resourcesFolder);
80 string newPath = resourcesFolder + path.Substring(lastSlash + 1);
81 string error = AssetDatabase.MoveAsset(prefab, newPath);
82 if (error != "")
83 Debug.LogError(error);
84 Output("Fixed prefab [" + prefab + "] by moving it into a resources folder.");
85 }
86 }
87 }
88
89 //Convert NetworkViews to PhotonViews in scenes
90 string[] sceneFiles = Directory.GetFiles("Assets/", "*.unity", SearchOption.AllDirectories);
91 foreach (string sceneName in sceneFiles)
92 {
93 EditorApplication.OpenScene(sceneName);
94 EditorUtility.DisplayProgressBar("Converting..", "Scene:" + sceneName, 0.2f);
95
96 int converted2 = ConvertNetworkView((NetworkView[])GameObject.FindObjectsOfType(typeof(NetworkView)), true);
97 if (converted2 > 0)
98 {
99 //This will correct all prefabs: The prefabs have gotten new components, but the correct ID's were lost in this case
100 PhotonViewHandler.HierarchyChange(); //TODO: most likely this is triggered on change or on save
101
102 Output("Replaced " + converted2 + " NetworkViews with PhotonViews in scene: " + sceneName);
103 EditorApplication.SaveScene(EditorApplication.currentScene);
104 }
105
106 }
107
108 //Convert C#/JS scripts (API stuff)
109 List
110
111 EditorUtility.DisplayProgressBar("Converting..", "Scripts..", 0.9f);
112 ConvertScripts(scripts);
113
114 Output(EditorApplication.timeSinceStartup + " Completed conversion!");
115 EditorUtility.ClearProgressBar();
116
117 EditorUtility.DisplayDialog("Completed the conversion", "Don't forget to add \"PhotonNetwork.ConnectWithDefaultSettings();\" to connect to the Photon server before using any multiplayer functionality.", "OK");
118 }
File name: PhotonConverter.cs
Copy
120 public static void PickFolderAndConvertScripts()
121 {
122 string folderPath = EditorUtility.OpenFolderPanel("Pick source folder to convert", Directory.GetCurrentDirectory(), "");
123 if (string.IsNullOrEmpty(folderPath))
124 {
125 EditorUtility.DisplayDialog("Script Conversion", "No folder was selected. No files were changed. Please start over.", "Ok.");
126 return;
127 }
128
129 bool result = EditorUtility.DisplayDialog("Script Conversion", "Scripts in this folder will be modified:\n\n" + folderPath + "\n\nMake sure you have backups of these scripts.\nConversion is not guaranteed to work!", "Backup done. Go!", "Abort");
130 if (!result)
131 {
132 return;
133 }
134
135 List
136 ConvertScripts(scripts);
137
138 EditorUtility.DisplayDialog("Script Conversion", "Scripts are now converted to PUN.\n\nYou will need to update\n- scenes\n- components\n- prefabs and\n- add \"PhotonNetwork.ConnectWithDefaultSettings();\"", "Ok");
139 }
File name: PhotonViewHandler.cs
Copy
173 //TODO: check if this can be internal protected (as source in editor AND as dll)
174 public static void LoadAllScenesToFix()
175 {
176 string[] scenes = System.IO.Directory.GetFiles(".", "*.unity", SearchOption.AllDirectories);
177
178 foreach (string scene in scenes)
179 {
180 EditorApplication.OpenScene(scene);
181
182 PhotonViewHandler.HierarchyChange();//TODO: most likely on load also triggers a hierarchy change
183
184 EditorApplication.SaveScene();
185 }
186
187 Debug.Log("Corrected scene views where needed.");
188 }
File name: PhotonViewInspector.cs
Copy
21 public override void OnInspectorGUI()
22 {
23 #if UNITY_3_5
24 EditorGUIUtility.LookLikeInspector();
25 #endif
26 //EditorGUI.indentLevel = 1;
27
28 m_Target = (PhotonView)this.target;
29 bool isProjectPrefab = EditorUtility.IsPersistent(m_Target.gameObject);
30
31 if( m_Target.ObservedComponents == null )
32 {
33 m_Target.ObservedComponents = new System.Collections.Generic.List
34 }
35
36 if( m_Target.ObservedComponents.Count == 0 )
37 {
38 m_Target.ObservedComponents.Add( null );
39 }
40
41 EditorGUILayout.BeginHorizontal();
42 // Owner
43 if (isProjectPrefab)
44 {
45 EditorGUILayout.LabelField("Owner:", "Set at runtime");
46 }
47 else if (m_Target.isSceneView)
48 {
49 EditorGUILayout.LabelField("Owner", "Scene");
50 }
51 else
52 {
53 PhotonPlayer owner = m_Target.owner;
54 string ownerInfo = (owner != null) ? owner.name : "
55
56 if (string.IsNullOrEmpty(ownerInfo))
57 {
58 ownerInfo = "
59 }
60
61 EditorGUILayout.LabelField("Owner", "[" + m_Target.ownerId + "] " + ownerInfo);
62 }
63
64 // ownership requests
65 EditorGUI.BeginDisabledGroup(Application.isPlaying);
66 m_Target.ownershipTransfer = (OwnershipOption)EditorGUILayout.EnumPopup(m_Target.ownershipTransfer, GUILayout.Width(100));
67 EditorGUI.EndDisabledGroup();
68
69 EditorGUILayout.EndHorizontal();
70
71
72 // View ID
73 if (isProjectPrefab)
74 {
75 EditorGUILayout.LabelField("View ID", "Set at runtime");
76 }
77 else if (EditorApplication.isPlaying)
78 {
79 EditorGUILayout.LabelField("View ID", m_Target.viewID.ToString());
80 }
81 else
82 {
83 int idValue = EditorGUILayout.IntField("View ID [1.."+(PhotonNetwork.MAX_VIEW_IDS-1)+"]", m_Target.viewID);
84 m_Target.viewID = idValue;
85 }
86
87
88
89 // Locally Controlled
90 if (EditorApplication.isPlaying)
91 {
92 string masterClientHint = PhotonNetwork.isMasterClient ? "(master)" : "";
93 EditorGUILayout.Toggle("Controlled locally: " + masterClientHint, m_Target.isMine);
94 }
95
96
97
98 //DrawOldObservedItem();
99 ConvertOldObservedItemToObservedList();
100
101
102 // ViewSynchronization (reliability)
103 if (m_Target.synchronization == ViewSynchronization.Off)
104 {
105 GUI.color = Color.grey;
106 }
107
108 EditorGUILayout.PropertyField( serializedObject.FindProperty( "synchronization" ), new GUIContent( "Observe option:" ) );
109
110 if( m_Target.synchronization != ViewSynchronization.Off &&
111 m_Target.ObservedComponents.FindAll( item => item != null ).Count == 0 )
112 {
113 GUILayout.BeginVertical( GUI.skin.box );
114 GUILayout.Label( "Warning", EditorStyles.boldLabel );
115 GUILayout.Label( "Setting the synchronization option only makes sense if you observe something." );
116 GUILayout.EndVertical();
117 }
118
119 /*ViewSynchronization vsValue = (ViewSynchronization)EditorGUILayout.EnumPopup("Observe option:", m_Target.synchronization);
120 if (vsValue != m_Target.synchronization)
121 {
122 m_Target.synchronization = vsValue;
123 if (m_Target.synchronization != ViewSynchronization.Off && m_Target.observed == null)
124 {
125 EditorUtility.DisplayDialog("Warning", "Setting the synchronization option only makes sense if you observe something.", "OK, I will fix it.");
126 }
127 }*/
128
129 DrawSpecificTypeSerializationOptions();
130
131 GUI.color = Color.white;
132 DrawObservedComponentsList();
133
134 // Cleanup: save and fix look
135 if (GUI.changed)
136 {
137 EditorUtility.SetDirty(m_Target);
138 PhotonViewHandler.HierarchyChange(); // TODO: check if needed
139 }
140
141 GUI.color = Color.white;
142 EditorGUIUtility.LookLikeControls();
143 }
File name: ServerSettingsInspector.cs
Copy
17 public override void OnInspectorGUI()
18 {
19 ServerSettings settings = (ServerSettings)this.target;
20
21 #if UNITY_3_5
22 EditorGUIUtility.LookLikeInspector();
23 #endif
24
25
26 settings.HostType = (ServerSettings.HostingOption)EditorGUILayout.EnumPopup("Hosting", settings.HostType);
27 EditorGUI.indentLevel = 1;
28
29 switch (settings.HostType)
30 {
31 case ServerSettings.HostingOption.BestRegion:
32 case ServerSettings.HostingOption.PhotonCloud:
33 if (settings.HostType == ServerSettings.HostingOption.PhotonCloud)
34 settings.PreferredRegion = (CloudRegionCode)EditorGUILayout.EnumPopup("Region", settings.PreferredRegion);
35 settings.AppID = EditorGUILayout.TextField("AppId", settings.AppID);
36 settings.Protocol = (ConnectionProtocol)EditorGUILayout.EnumPopup("Protocol", settings.Protocol);
37
38 if (string.IsNullOrEmpty(settings.AppID) || settings.AppID.Equals("master"))
39 {
40 EditorGUILayout.HelpBox("The Photon Cloud needs an AppId (GUID) set.\nYou can find it online in your Dashboard.", MessageType.Warning);
41 }
42 break;
43
44 case ServerSettings.HostingOption.SelfHosted:
45 bool hidePort = false;
46 if (settings.Protocol == ConnectionProtocol.Udp && (settings.ServerPort == 4530 || settings.ServerPort == 0))
47 {
48 settings.ServerPort = 5055;
49 }
50 else if (settings.Protocol == ConnectionProtocol.Tcp && (settings.ServerPort == 5055 || settings.ServerPort == 0))
51 {
52 settings.ServerPort = 4530;
53 }
54 #if RHTTP
55 if (settings.Protocol == ConnectionProtocol.RHttp)
56 {
57 settings.ServerPort = 0;
58 hidePort = true;
59 }
60 #endif
61 settings.ServerAddress = EditorGUILayout.TextField("Server Address", settings.ServerAddress);
62 settings.ServerAddress = settings.ServerAddress.Trim();
63 if (!hidePort)
64 {
65 settings.ServerPort = EditorGUILayout.IntField("Server Port", settings.ServerPort);
66 }
67 settings.Protocol = (ConnectionProtocol)EditorGUILayout.EnumPopup("Protocol", settings.Protocol);
68 settings.AppID = EditorGUILayout.TextField("AppId", settings.AppID);
69 break;
70
71 case ServerSettings.HostingOption.OfflineMode:
72 EditorGUI.indentLevel = 0;
73 EditorGUILayout.HelpBox("In 'Offline Mode', the client does not communicate with a server.\nAll settings are hidden currently.", MessageType.Info);
74 break;
75
76 case ServerSettings.HostingOption.NotSet:
77 EditorGUI.indentLevel = 0;
78 EditorGUILayout.HelpBox("Hosting is 'Not Set'.\nConnectUsingSettings() will not be able to connect.\nSelect another option or run the PUN Wizard.", MessageType.Info);
79 break;
80
81 default:
82 DrawDefaultInspector();
83 break;
84 }
85
86 if (PhotonEditor.CheckPunPlus())
87 {
88 settings.Protocol = ConnectionProtocol.Udp;
89 EditorGUILayout.HelpBox("You seem to use PUN+.\nPUN+ only supports reliable UDP so the protocol is locked.", MessageType.Info);
90 }
91
92 settings.AppID = settings.AppID.Trim();
93
94 EditorGUI.indentLevel = 0;
95 SerializedObject sObj = new SerializedObject(this.target);
96 SerializedProperty sRpcs = sObj.FindProperty("RpcList");
97 EditorGUILayout.PropertyField(sRpcs, true);
98 sObj.ApplyModifiedProperties();
99
100 GUILayout.BeginHorizontal();
101 GUILayout.Space(20);
102 if (GUILayout.Button("Refresh RPCs"))
103 {
104 PhotonEditor.UpdateRpcList();
105 Repaint();
106 }
107 if (GUILayout.Button("Clear RPCs"))
108 {
109 PhotonEditor.ClearRpcList();
110 }
111 if (GUILayout.Button("Log HashCode"))
112 {
113 Debug.Log("RPC-List HashCode: " + RpcListHashCode() + ". Make sure clients that send each other RPCs have the same RPC-List.");
114 }
115 GUILayout.Space(20);
116 GUILayout.EndHorizontal();
117
118 //SerializedProperty sp = serializedObject.FindProperty("RpcList");
119 //EditorGUILayout.PropertyField(sp, true);
120
121 if (GUI.changed)
122 {
123 EditorUtility.SetDirty(target);
124 }
125 }
File name: NetworkingPeer.cs
Copy
495 protected internal void LocalCleanupAnythingInstantiated(bool destroyInstantiatedGameObjects)
496 {
497 if (tempInstantiationData.Count > 0)
498 {
499 Debug.LogWarning("It seems some instantiation is not completed, as instantiation data is used. You should make sure instantiations are paused when calling this method. Cleaning now, despite this.");
500 }
501
502 // Destroy GO's (if we should)
503 if (destroyInstantiatedGameObjects)
504 {
505 // Fill list with Instantiated objects
506 HashSet
507 foreach (PhotonView view in this.photonViewList.Values)
508 {
509 if (view.isRuntimeInstantiated)
510 {
511 instantiatedGos.Add(view.gameObject); // HashSet keeps each object only once
512 }
513 }
514
515 foreach (GameObject go in instantiatedGos)
516 {
517 this.RemoveInstantiatedGO(go, true);
518 }
519 }
520
521 // photonViewList is cleared of anything instantiated (so scene items are left inside)
522 // any other lists can be
523 this.tempInstantiationData.Clear(); // should be empty but to be safe we clear (no new list needed)
524 PhotonNetwork.lastUsedViewSubId = 0;
525 PhotonNetwork.lastUsedViewSubIdStatic = 0;
526 }
File name: NetworkingPeer.cs
Copy
1016 public void OnOperationResponse(OperationResponse operationResponse)
1017 {
1018 if (PhotonNetwork.networkingPeer.State == global::PeerState.Disconnecting)
1019 {
1020 if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
1021 {
1022 Debug.Log("OperationResponse ignored while disconnecting. Code: " + operationResponse.OperationCode);
1023 }
1024 return;
1025 }
1026
1027 // extra logging for error debugging (helping developers with a bit of automated analysis)
1028 if (operationResponse.ReturnCode == 0)
1029 {
1030 if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
1031 Debug.Log(operationResponse.ToString());
1032 }
1033 else
1034 {
1035 if (operationResponse.ReturnCode == ErrorCode.OperationNotAllowedInCurrentState)
1036 {
1037 Debug.LogError("Operation " + operationResponse.OperationCode + " could not be executed (yet). Wait for state JoinedLobby or ConnectedToMaster and their callbacks before calling operations. WebRPCs need a server-side configuration. Enum OperationCode helps identify the operation.");
1038 }
1039 else if (operationResponse.ReturnCode == ErrorCode.WebHookCallFailed)
1040 {
1041 Debug.LogError("Operation " + operationResponse.OperationCode + " failed in a server-side plugin. Check the configuration in the Dashboard. Message from server-plugin: " + operationResponse.DebugMessage);
1042 }
1043 else if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
1044 {
1045 Debug.LogError("Operation failed: " + operationResponse.ToStringFull() + " Server: " + this.server);
1046 }
1047 }
1048
1049 // use the "secret" or "token" whenever we get it. doesn't really matter if it's in AuthResponse.
1050 if (operationResponse.Parameters.ContainsKey(ParameterCode.Secret))
1051 {
1052 if (this.CustomAuthenticationValues == null)
1053 {
1054 this.CustomAuthenticationValues = new AuthenticationValues();
1055 // this.DebugReturn(DebugLevel.ERROR, "Server returned secret. Created CustomAuthenticationValues.");
1056 }
1057
1058 this.CustomAuthenticationValues.Secret = operationResponse[ParameterCode.Secret] as string;
1059 }
1060
1061 switch (operationResponse.OperationCode)
1062 {
1063 case OperationCode.Authenticate:
1064 {
1065 // PeerState oldState = this.State;
1066
1067 if (operationResponse.ReturnCode != 0)
1068 {
1069 if (operationResponse.ReturnCode == ErrorCode.InvalidOperationCode)
1070 {
1071 Debug.LogError(string.Format("If you host Photon yourself, make sure to start the 'Instance LoadBalancing' "+ this.ServerAddress));
1072 }
1073 else if (operationResponse.ReturnCode == ErrorCode.InvalidAuthentication)
1074 {
1075 Debug.LogError(string.Format("The appId this client sent is unknown on the server (Cloud). Check settings. If using the Cloud, check account."));
1076 SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, DisconnectCause.InvalidAuthentication);
1077 }
1078 else if (operationResponse.ReturnCode == ErrorCode.CustomAuthenticationFailed)
1079 {
1080 Debug.LogError(string.Format("Custom Authentication failed (either due to user-input or configuration or AuthParameter string format). Calling: OnCustomAuthenticationFailed()"));
1081 SendMonoMessage(PhotonNetworkingMessage.OnCustomAuthenticationFailed, operationResponse.DebugMessage);
1082 }
1083 else
1084 {
1085 Debug.LogError(string.Format("Authentication failed: '{0}' Code: {1}", operationResponse.DebugMessage, operationResponse.ReturnCode));
1086 }
1087
1088 this.State = global::PeerState.Disconnecting;
1089 this.Disconnect();
1090
1091 if (operationResponse.ReturnCode == ErrorCode.MaxCcuReached)
1092 {
1093 if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
1094 Debug.LogWarning(string.Format("Currently, the limit of users is reached for this title. Try again later. Disconnecting"));
1095 SendMonoMessage(PhotonNetworkingMessage.OnPhotonMaxCccuReached);
1096 SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, DisconnectCause.MaxCcuReached);
1097 }
1098 else if (operationResponse.ReturnCode == ErrorCode.InvalidRegion)
1099 {
1100 if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
1101 Debug.LogError(string.Format("The used master server address is not available with the subscription currently used. Got to Photon Cloud Dashboard or change URL. Disconnecting."));
1102 SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, DisconnectCause.InvalidRegion);
1103 }
1104 else if (operationResponse.ReturnCode == ErrorCode.AuthenticationTicketExpired)
1105 {
1106 if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
1107 Debug.LogError(string.Format("The authentication ticket expired. You need to connect (and authenticate) again. Disconnecting."));
1108 SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, DisconnectCause.AuthenticationTicketExpired);
1109 }
1110 break;
1111 }
1112 else
1113 {
1114 if (this.server == ServerConnection.NameServer)
1115 {
1116 // on the NameServer, authenticate returns the MasterServer address for a region and we hop off to there
1117 this.MasterServerAddress = operationResponse[ParameterCode.Address] as string;
1118 this.DisconnectToReconnect();
1119 }
1120 else if (this.server == ServerConnection.MasterServer)
1121 {
1122 if (PhotonNetwork.autoJoinLobby)
1123 {
1124 this.State = global::PeerState.Authenticated;
1125 this.OpJoinLobby(this.lobby);
1126 }
1127 else
1128 {
1129 this.State = global::PeerState.ConnectedToMaster;
1130 NetworkingPeer.SendMonoMessage(PhotonNetworkingMessage.OnConnectedToMaster);
1131 }
1132 }
1133 else if (this.server == ServerConnection.GameServer)
1134 {
1135 this.State = global::PeerState.Joining;
1136
1137 if (this.mLastJoinType == JoinType.JoinGame || this.mLastJoinType == JoinType.JoinRandomGame || this.mLastJoinType == JoinType.JoinOrCreateOnDemand)
1138 {
1139 // if we just "join" the game, do so. if we wanted to "create the room on demand", we have to send this to the game server as well.
1140 this.OpJoinRoom(this.mRoomToGetInto.name, this.mRoomOptionsForCreate, this.mRoomToEnterLobby, this.mLastJoinType == JoinType.JoinOrCreateOnDemand);
1141 }
1142 else if (this.mLastJoinType == JoinType.CreateGame)
1143 {
1144 // on the game server, we have to apply the room properties that were chosen for creation of the room, so we use this.mRoomToGetInto
1145 this.OpCreateGame(this.mRoomToGetInto.name, this.mRoomOptionsForCreate, this.mRoomToEnterLobby);
1146 }
1147
1148 break;
1149 }
1150 }
1151 break;
1152 }
1153
1154 case OperationCode.GetRegions:
1155 // Debug.Log("GetRegions returned: " + operationResponse.ToStringFull());
1156
1157 if (operationResponse.ReturnCode == ErrorCode.InvalidAuthentication)
1158 {
1159 Debug.LogError(string.Format("The appId this client sent is unknown on the server (Cloud). Check settings. If using the Cloud, check account."));
1160 SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, DisconnectCause.InvalidAuthentication);
1161
1162 this.State = global::PeerState.Disconnecting;
1163 this.Disconnect();
1164 return;
1165 }
1166
1167 string[] regions = operationResponse[ParameterCode.Region] as string[];
1168 string[] servers = operationResponse[ParameterCode.Address] as string[];
1169
1170 if (regions == null || servers == null || regions.Length != servers.Length)
1171 {
1172 Debug.LogError("The region arrays from Name Server are not ok. Must be non-null and same length.");
1173 break;
1174 }
1175
1176 this.AvailableRegions = new List
1177 for (int i = 0; i < regions.Length; i++)
1178 {
1179 string regionCodeString = regions[i];
1180 if (string.IsNullOrEmpty(regionCodeString))
1181 {
1182 continue;
1183 }
1184 regionCodeString = regionCodeString.ToLower();
1185
1186 CloudRegionCode code = Region.Parse(regionCodeString);
1187 this.AvailableRegions.Add(new Region() { Code = code, HostAndPort = servers[i] });
1188 }
1189
1190 // PUN assumes you fetch the name-server's list of regions to ping them
1191 if (PhotonNetwork.PhotonServerSettings.HostType == ServerSettings.HostingOption.BestRegion)
1192 {
1193 PhotonHandler.PingAvailableRegionsAndConnectToBest();
1194 }
1195 break;
1196
1197 case OperationCode.CreateGame:
1198 {
1199 if (this.server == ServerConnection.GameServer)
1200 {
1201 this.GameEnteredOnGameServer(operationResponse);
1202 }
1203 else
1204 {
1205 if (operationResponse.ReturnCode != 0)
1206 {
1207 if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
1208 Debug.LogWarning(string.Format("CreateRoom failed, client stays on masterserver: {0}.", operationResponse.ToStringFull()));
1209
1210 SendMonoMessage(PhotonNetworkingMessage.OnPhotonCreateRoomFailed);
1211 break;
1212 }
1213
1214 string gameID = (string) operationResponse[ParameterCode.RoomName];
1215 if (!string.IsNullOrEmpty(gameID))
1216 {
1217 // is only sent by the server's response, if it has not been
1218 // sent with the client's request before!
1219 this.mRoomToGetInto.name = gameID;
1220 }
1221
1222 this.mGameserver = (string)operationResponse[ParameterCode.Address];
1223 this.DisconnectToReconnect();
1224 }
1225
1226 break;
1227 }
1228
1229 case OperationCode.JoinGame:
1230 {
1231 if (this.server != ServerConnection.GameServer)
1232 {
1233 if (operationResponse.ReturnCode != 0)
1234 {
1235 if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
1236 Debug.Log(string.Format("JoinRoom failed (room maybe closed by now). Client stays on masterserver: {0}. State: {1}", operationResponse.ToStringFull(), this.State));
1237
1238 SendMonoMessage(PhotonNetworkingMessage.OnPhotonJoinRoomFailed);
1239 break;
1240 }
1241
1242 this.mGameserver = (string)operationResponse[ParameterCode.Address];
1243 this.DisconnectToReconnect();
1244 }
1245 else
1246 {
1247 this.GameEnteredOnGameServer(operationResponse);
1248 }
1249
1250 break;
1251 }
1252
1253 case OperationCode.JoinRandomGame:
1254 {
1255 // happens only on master. on gameserver, this is a regular join (we don't need to find a random game again)
1256 // the operation OpJoinRandom either fails (with returncode 8) or returns game-to-join information
1257 if (operationResponse.ReturnCode != 0)
1258 {
1259 if (operationResponse.ReturnCode == ErrorCode.NoRandomMatchFound)
1260 {
1261 if (PhotonNetwork.logLevel >= PhotonLogLevel.Full)
1262 Debug.Log("JoinRandom failed: No open game. Calling: OnPhotonRandomJoinFailed() and staying on master server.");
1263 }
1264 else if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
1265 {
1266 Debug.LogWarning(string.Format("JoinRandom failed: {0}.", operationResponse.ToStringFull()));
1267 }
1268
1269 SendMonoMessage(PhotonNetworkingMessage.OnPhotonRandomJoinFailed, operationResponse.ReturnCode, operationResponse.DebugMessage);
1270 break;
1271 }
1272
1273 string roomName = (string)operationResponse[ParameterCode.RoomName];
1274 this.mRoomToGetInto.name = roomName;
1275 this.mGameserver = (string)operationResponse[ParameterCode.Address];
1276 this.DisconnectToReconnect();
1277 break;
1278 }
1279
1280 case OperationCode.JoinLobby:
1281 this.State = global::PeerState.JoinedLobby;
1282 this.insideLobby = true;
1283 SendMonoMessage(PhotonNetworkingMessage.OnJoinedLobby);
1284
1285 // this.mListener.joinLobbyReturn();
1286 break;
1287 case OperationCode.LeaveLobby:
1288 this.State = global::PeerState.Authenticated;
1289 this.LeftLobbyCleanup(); // will set insideLobby = false
1290 break;
1291
1292 case OperationCode.Leave:
1293 this.DisconnectToReconnect();
1294 break;
1295
1296 case OperationCode.SetProperties:
1297 // this.mListener.setPropertiesReturn(returnCode, debugMsg);
1298 break;
1299
1300 case OperationCode.GetProperties:
1301 {
1302 Hashtable actorProperties = (Hashtable)operationResponse[ParameterCode.PlayerProperties];
1303 Hashtable gameProperties = (Hashtable)operationResponse[ParameterCode.GameProperties];
1304 this.ReadoutProperties(gameProperties, actorProperties, 0);
1305
1306 // RemoveByteTypedPropertyKeys(actorProperties, false);
1307 // RemoveByteTypedPropertyKeys(gameProperties, false);
1308 // this.mListener.getPropertiesReturn(gameProperties, actorProperties, returnCode, debugMsg);
1309 break;
1310 }
1311
1312 case OperationCode.RaiseEvent:
1313 // this usually doesn't give us a result. only if the caching is affected the server will send one.
1314 break;
1315
1316 case OperationCode.FindFriends:
1317 bool[] onlineList = operationResponse[ParameterCode.FindFriendsResponseOnlineList] as bool[];
1318 string[] roomList = operationResponse[ParameterCode.FindFriendsResponseRoomIdList] as string[];
1319
1320 if (onlineList != null && roomList != null && this.friendListRequested != null && onlineList.Length == this.friendListRequested.Length)
1321 {
1322 List
1323 for (int index = 0; index < this.friendListRequested.Length; index++)
1324 {
1325 FriendInfo friend = new FriendInfo();
1326 friend.Name = this.friendListRequested[index];
1327 friend.Room = roomList[index];
1328 friend.IsOnline = onlineList[index];
1329 friendList.Insert(index, friend);
1330 }
1331 PhotonNetwork.Friends = friendList;
1332 }
1333 else
1334 {
1335 // any of the lists is null and shouldn't. print a error
1336 Debug.LogError("FindFriends failed to apply the result, as a required value wasn't provided or the friend list length differed from result.");
1337 }
1338
1339 this.friendListRequested = null;
1340 this.isFetchingFriends = false;
1341 this.friendListTimestamp = Environment.TickCount;
1342 if (this.friendListTimestamp == 0)
1343 {
1344 this.friendListTimestamp = 1; // makes sure the timestamp is not accidentally 0
1345 }
1346
1347 SendMonoMessage(PhotonNetworkingMessage.OnUpdatedFriendList);
1348 break;
1349
1350 case OperationCode.WebRpc:
1351 SendMonoMessage(PhotonNetworkingMessage.OnWebRpcResponse, operationResponse);
1352 break;
1353
1354 default:
1355 Debug.LogWarning(string.Format("OperationResponse unhandled: {0}", operationResponse.ToString()));
1356 break;
1357 }
1358
1359 this.externalListener.OnOperationResponse(operationResponse);
1360 }
File name: NetworkingPeer.cs
Copy
1411 public void OnStatusChanged(StatusCode statusCode)
1412 {
1413 if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
1414 Debug.Log(string.Format("OnStatusChanged: {0}", statusCode.ToString()));
1415
1416 switch (statusCode)
1417 {
1418 case StatusCode.Connect:
1419 if (this.State == global::PeerState.ConnectingToNameServer)
1420 {
1421 if (PhotonNetwork.logLevel >= PhotonLogLevel.Full)
1422 Debug.Log("Connected to NameServer.");
1423
1424 this.server = ServerConnection.NameServer;
1425 if (this.CustomAuthenticationValues != null)
1426 {
1427 this.CustomAuthenticationValues.Secret = null; // when connecting to NameServer, invalidate any auth values
1428 }
1429 }
1430
1431 if (this.State == global::PeerState.ConnectingToGameserver)
1432 {
1433 if (PhotonNetwork.logLevel >= PhotonLogLevel.Full)
1434 Debug.Log("Connected to gameserver.");
1435
1436 this.server = ServerConnection.GameServer;
1437 this.State = global::PeerState.ConnectedToGameserver;
1438 }
1439
1440 if (this.State == global::PeerState.ConnectingToMasterserver)
1441 {
1442 if (PhotonNetwork.logLevel >= PhotonLogLevel.Full)
1443 Debug.Log("Connected to masterserver.");
1444
1445 this.server = ServerConnection.MasterServer;
1446 this.State = global::PeerState.ConnectedToMaster;
1447
1448 if (this.IsInitialConnect)
1449 {
1450 this.IsInitialConnect = false; // after handling potential initial-connect issues with special messages, we are now sure we can reach a server
1451 SendMonoMessage(PhotonNetworkingMessage.OnConnectedToPhoton);
1452 }
1453 }
1454
1455 this.EstablishEncryption(); // always enable encryption
1456
1457 if (this.IsAuthorizeSecretAvailable)
1458 {
1459 // if we have a token we don't have to wait for encryption (it is encrypted anyways, so encryption is just optional later on)
1460 this.didAuthenticate = this.OpAuthenticate(this.mAppId, this.mAppVersionPun, this.PlayerName, this.CustomAuthenticationValues, this.CloudRegion.ToString());
1461 if (this.didAuthenticate)
1462 {
1463 this.State = global::PeerState.Authenticating;
1464 }
1465 }
1466 break;
1467
1468 case StatusCode.EncryptionEstablished:
1469 // on nameserver, the "process" is stopped here, so the developer/game can either get regions or authenticate with a specific region
1470 if (this.server == ServerConnection.NameServer)
1471 {
1472 this.State = global::PeerState.ConnectedToNameServer;
1473
1474 if (!this.didAuthenticate && this.CloudRegion == CloudRegionCode.none)
1475 {
1476 // this client is not setup to connect to a default region. find out which regions there are!
1477 this.OpGetRegions(this.mAppId);
1478 }
1479 }
1480
1481 // we might need to authenticate automatically now, so the client can do anything at all
1482 if (!this.didAuthenticate && (!this.IsUsingNameServer || this.CloudRegion != CloudRegionCode.none))
1483 {
1484 // once encryption is availble, the client should send one (secure) authenticate. it includes the AppId (which identifies your app on the Photon Cloud)
1485 this.didAuthenticate = this.OpAuthenticate(this.mAppId, this.mAppVersionPun, this.PlayerName, this.CustomAuthenticationValues, this.CloudRegion.ToString());
1486 if (this.didAuthenticate)
1487 {
1488 this.State = global::PeerState.Authenticating;
1489 }
1490 }
1491 break;
1492
1493 case StatusCode.EncryptionFailedToEstablish:
1494 Debug.LogError("Encryption wasn't established: " + statusCode + ". Going to authenticate anyways.");
1495 this.OpAuthenticate(this.mAppId, this.mAppVersionPun, this.PlayerName, this.CustomAuthenticationValues, this.CloudRegion.ToString()); // TODO: check if there are alternatives
1496 break;
1497
1498 case StatusCode.Disconnect:
1499 this.didAuthenticate = false;
1500 this.isFetchingFriends = false;
1501 if (server == ServerConnection.GameServer) this.LeftRoomCleanup();
1502 if (server == ServerConnection.MasterServer) this.LeftLobbyCleanup();
1503
1504 if (this.State == global::PeerState.DisconnectingFromMasterserver)
1505 {
1506 if (this.Connect(this.mGameserver, ServerConnection.GameServer))
1507 {
1508 this.State = global::PeerState.ConnectingToGameserver;
1509 }
1510 }
1511 else if (this.State == global::PeerState.DisconnectingFromGameserver || this.State == global::PeerState.DisconnectingFromNameServer)
1512 {
1513 if (this.Connect(this.MasterServerAddress, ServerConnection.MasterServer))
1514 {
1515 this.State = global::PeerState.ConnectingToMasterserver;
1516 }
1517 }
1518 else
1519 {
1520 if (this.CustomAuthenticationValues != null)
1521 {
1522 this.CustomAuthenticationValues.Secret = null; // invalidate any custom auth secrets
1523 }
1524
1525 this.State = global::PeerState.PeerCreated; // if we set another state here, we could keep clients from connecting in OnDisconnectedFromPhoton right here.
1526 SendMonoMessage(PhotonNetworkingMessage.OnDisconnectedFromPhoton);
1527 }
1528 break;
1529
1530 case StatusCode.SecurityExceptionOnConnect:
1531 case StatusCode.ExceptionOnConnect:
1532 this.State = global::PeerState.PeerCreated;
1533 if (this.CustomAuthenticationValues != null)
1534 {
1535 this.CustomAuthenticationValues.Secret = null; // invalidate any custom auth secrets
1536 }
1537
1538 DisconnectCause cause = (DisconnectCause)statusCode;
1539 SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, cause);
1540 break;
1541
1542 case StatusCode.Exception:
1543 if (this.IsInitialConnect)
1544 {
1545 Debug.LogError("Exception while connecting to: " + this.ServerAddress + ". Check if the server is available.");
1546 if (this.ServerAddress == null || this.ServerAddress.StartsWith("127.0.0.1"))
1547 {
1548 Debug.LogWarning("The server address is 127.0.0.1 (localhost): Make sure the server is running on this machine. Android and iOS emulators have their own localhost.");
1549 if (this.ServerAddress == this.mGameserver)
1550 {
1551 Debug.LogWarning("This might be a misconfiguration in the game server config. You need to edit it to a (public) address.");
1552 }
1553 }
1554
1555 this.State = global::PeerState.PeerCreated;
1556 cause = (DisconnectCause)statusCode;
1557 SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, cause);
1558 }
1559 else
1560 {
1561 this.State = global::PeerState.PeerCreated;
1562
1563 cause = (DisconnectCause)statusCode;
1564 SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, cause);
1565 }
1566
1567 this.Disconnect();
1568 break;
1569
1570 case StatusCode.TimeoutDisconnect:
1571 case StatusCode.ExceptionOnReceive:
1572 case StatusCode.DisconnectByServer:
1573 case StatusCode.DisconnectByServerLogic:
1574 case StatusCode.DisconnectByServerUserLimit:
1575 if (this.IsInitialConnect)
1576 {
1577 Debug.LogWarning(statusCode + " while connecting to: " + this.ServerAddress + ". Check if the server is available.");
1578
1579 cause = (DisconnectCause)statusCode;
1580 SendMonoMessage(PhotonNetworkingMessage.OnFailedToConnectToPhoton, cause);
1581 }
1582 else
1583 {
1584 cause = (DisconnectCause)statusCode;
1585 SendMonoMessage(PhotonNetworkingMessage.OnConnectionFail, cause);
1586 }
1587 if (this.CustomAuthenticationValues != null)
1588 {
1589 this.CustomAuthenticationValues.Secret = null; // invalidate any custom auth secrets
1590 }
1591
1592 this.Disconnect();
1593 break;
1594
1595 case StatusCode.SendError:
1596 // this.mListener.clientErrorReturn(statusCode);
1597 break;
1598
1599 case StatusCode.QueueOutgoingReliableWarning:
1600 case StatusCode.QueueOutgoingUnreliableWarning:
1601 case StatusCode.QueueOutgoingAcksWarning:
1602 case StatusCode.QueueSentWarning:
1603 // this.mListener.warningReturn(statusCode);
1604 break;
1605
1606 case StatusCode.QueueIncomingReliableWarning:
1607 case StatusCode.QueueIncomingUnreliableWarning:
1608 Debug.Log(statusCode + ". This client buffers many incoming messages. This is OK temporarily. With lots of these warnings, check if you send too much or execute messages too slow. " + (PhotonNetwork.isMessageQueueRunning? "":"Your isMessageQueueRunning is false. This can cause the issue temporarily.") );
1609 break;
1610
1611 // // TCP "routing" is an option of Photon that's not currently needed (or supported) by PUN
1612 //case StatusCode.TcpRouterResponseOk:
1613 // break;
1614 //case StatusCode.TcpRouterResponseEndpointUnknown:
1615 //case StatusCode.TcpRouterResponseNodeIdUnknown:
1616 //case StatusCode.TcpRouterResponseNodeNotReady:
1617
1618 // this.DebugReturn(DebugLevel.ERROR, "Unexpected router response: " + statusCode);
1619 // break;
1620
1621 default:
1622
1623 // this.mListener.serverErrorReturn(statusCode.value());
1624 Debug.LogError("Received unknown status code: " + statusCode);
1625 break;
1626 }
1627
1628 this.externalListener.OnStatusChanged(statusCode);
1629 }
File name: NetworkingPeer.cs
Copy
2493 protected internal void RemoveInstantiatedGO(GameObject go, bool localOnly)
2494 {
2495 if (go == null)
2496 {
2497 Debug.LogError("Failed to 'network-remove' GameObject because it's null.");
2498 return;
2499 }
2500
2501 // Don't remove the GO if it doesn't have any PhotonView
2502 PhotonView[] views = go.GetComponentsInChildren
2503 if (views == null || views.Length <= 0)
2504 {
2505 Debug.LogError("Failed to 'network-remove' GameObject because has no PhotonView components: " + go);
2506 return;
2507 }
2508
2509 PhotonView viewZero = views[0];
2510 int creatorId = viewZero.CreatorActorNr; // creatorId of obj is needed to delete EvInstantiate (only if it's from that user)
2511 int instantiationId = viewZero.instantiationId; // actual, live InstantiationIds start with 1 and go up
2512
2513 // Don't remove GOs that are owned by others (unless this is the master and the remote player left)
2514 if (!localOnly)
2515 {
2516 if (!viewZero.isMine)
2517 {
2518 Debug.LogError("Failed to 'network-remove' GameObject. Client is neither owner nor masterClient taking over for owner who left: " + viewZero);
2519 return;
2520 }
2521
2522 // Don't remove the Instantiation from the server, if it doesn't have a proper ID
2523 if (instantiationId < 1)
2524 {
2525 Debug.LogError("Failed to 'network-remove' GameObject because it is missing a valid InstantiationId on view: " + viewZero + ". Not Destroying GameObject or PhotonViews!");
2526 return;
2527 }
2528 }
2529
2530
2531 // cleanup instantiation (event and local list)
2532 if (!localOnly)
2533 {
2534 this.ServerCleanInstantiateAndDestroy(instantiationId, creatorId, viewZero.isRuntimeInstantiated); // server cleaning
2535 }
2536
2537
2538 // cleanup PhotonViews and their RPCs events (if not localOnly)
2539 for (int j = views.Length - 1; j >= 0; j--)
2540 {
2541 PhotonView view = views[j];
2542 if (view == null)
2543 {
2544 continue;
2545 }
2546
2547 // we only destroy/clean PhotonViews that were created by PhotonNetwork.Instantiate (and those have an instantiationId!)
2548 if (view.instantiationId >= 1)
2549 {
2550 this.LocalCleanPhotonView(view);
2551 }
2552 if (!localOnly)
2553 {
2554 this.OpCleanRpcBuffer(view);
2555 }
2556 }
2557
2558 if (PhotonNetwork.logLevel >= PhotonLogLevel.Full)
2559 Debug.Log("Network destroy Instantiated GO: " + go.name);
2560
2561 GameObject.Destroy(go);
2562 }
File name: NetworkingPeer.cs
Copy
3147 public void RunViewUpdate()
3148 {
3149 if (!PhotonNetwork.connected || PhotonNetwork.offlineMode)
3150 {
3151 return;
3152 }
3153
3154 if (this.mActors == null ||
3155#if !PHOTON_DEVELOP
3156 this.mActors.Count <= 1
3157#endif
3158 )
3159 {
3160 return; // No need to send OnSerialize messages (these are never buffered anyway)
3161 }
3162
3163 dataPerGroupReliable.Clear();
3164 dataPerGroupUnreliable.Clear();
3165
3166 /* Format of the data hashtable:
3167 * Hasthable dataPergroup*
3168 * [(byte)0] = this.ServerTimeInMilliSeconds;
3169 * OPTIONAL: [(byte)1] = currentLevelPrefix;
3170 * + data
3171 */
3172
3173 foreach (KeyValuePair
3174 {
3175 PhotonView view = kvp.Value;
3176
3177 if (view.synchronization != ViewSynchronization.Off)
3178 {
3179 // Fetch all sending photonViews
3180 if (view.isMine)
3181 {
3182 #if UNITY_2_6_1 || UNITY_2_6 || UNITY_3_0 || UNITY_3_0_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5
3183 if (!view.gameObject.active)
3184 {
3185 continue; // Only on actives
3186 }
3187 #else
3188 if (!view.gameObject.activeInHierarchy)
3189 {
3190 continue; // Only on actives
3191 }
3192 #endif
3193
3194 if (this.blockSendingGroups.Contains(view.group))
3195 {
3196 continue; // Block sending on this group
3197 }
3198
3199 // Run it trough its OnSerialize
3200 Hashtable evData = this.OnSerializeWrite(view);
3201 if (evData == null)
3202 {
3203 continue;
3204 }
3205
3206 if (view.synchronization == ViewSynchronization.ReliableDeltaCompressed || view.mixedModeIsReliable)
3207 {
3208 if (!evData.ContainsKey((byte)1) && !evData.ContainsKey((byte)2))
3209 {
3210 // Everything has been removed by compression, nothing to send
3211 }
3212 else
3213 {
3214 if (!dataPerGroupReliable.ContainsKey(view.group))
3215 {
3216 dataPerGroupReliable[view.group] = new Hashtable();
3217 dataPerGroupReliable[view.group][(byte)0] = this.ServerTimeInMilliSeconds;
3218 if (currentLevelPrefix >= 0)
3219 {
3220 dataPerGroupReliable[view.group][(byte)1] = this.currentLevelPrefix;
3221 }
3222 }
3223 Hashtable groupHashtable = dataPerGroupReliable[view.group];
3224 groupHashtable.Add((short)groupHashtable.Count, evData);
3225 }
3226 }
3227 else
3228 {
3229 if (!dataPerGroupUnreliable.ContainsKey(view.group))
3230 {
3231 dataPerGroupUnreliable[view.group] = new Hashtable();
3232 dataPerGroupUnreliable[view.group][(byte)0] = this.ServerTimeInMilliSeconds;
3233 if (currentLevelPrefix >= 0)
3234 {
3235 dataPerGroupUnreliable[view.group][(byte)1] = this.currentLevelPrefix;
3236 }
3237 }
3238 Hashtable groupHashtable = dataPerGroupUnreliable[view.group];
3239 groupHashtable.Add((short)groupHashtable.Count, evData);
3240 }
3241 }
3242 else
3243 {
3244 // Debug.Log(" NO OBS on " + view.name + " " + view.owner);
3245 }
3246 }
3247 else
3248 {
3249 }
3250 }
3251
3252 //Send the messages: every group is send in it's own message and unreliable and reliable are split as well
3253 RaiseEventOptions options = new RaiseEventOptions();
3254
3255#if PHOTON_DEVELOP
3256 options.Receivers = ReceiverGroup.All;
3257#endif
3258
3259 foreach (KeyValuePair
3260 {
3261 options.InterestGroup = (byte)kvp.Key;
3262 this.OpRaiseEvent(PunEvent.SendSerializeReliable, kvp.Value, true, options);
3263 }
3264 foreach (KeyValuePair
3265 {
3266 options.InterestGroup = (byte)kvp.Key;
3267 this.OpRaiseEvent(PunEvent.SendSerialize, kvp.Value, false, options);
3268 }
3269 }
Download file with original file name:Need
Need 169 lượt xem
Gõ tìm kiếm nhanh...