Could









How do I use Could
Below are practical examples compiled from projects for learning and reference purposes

Featured Snippets

Line Code Ex..
141 List channels = new List(this.chatClient.PublicChannels.Keys); // this could be cached 1
325 this.chatClient.PublishMessage(channel, "says 'hi' in OnSubscribed(). "); // you don't HAVE to send a msg on join but you could. 2
103 demoDescription = "Marco Polo Tutorial\n\nFinal result you could get when you do the Marco Polo Tutorial.\nSlightly modified to be more compatible with this package."; 3
76 Debug.Log("OnPhotonInstantiate " + info.sender); // you could use this info to store this or react 4
90 view.prefix = -1; // TODO: prefix could be settable via inspector per scene?! 5
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."); 6
1525 this.State = global::PeerState.PeerCreated; // if we set another state here, we could keep clients from connecting in OnDisconnectedFromPhoton right here. 7
1888 if (this.DebugOut >= DebugLevel.ERROR) Debug.LogError("Ev Destroy Failed. Could not find PhotonView with instantiationId " + instantiationId + ". Sent by actorNr: " + actorNr); 8
1984 Debug.LogError("Could not find RPC with index: " + rpcIndex + ". Going to ignore! Check PhotonServerSettings.RpcList"); 9
2354 Debug.LogError("PhotonNetwork error: Could not Instantiate the prefab [" + prefabName + "]. Please verify you have this gameobject in a Resources folder."); 10

File name: ChatGui.cs Copy
103     public void OnGUI()
104     {
105         if (!this.IsVisible)
106         {
107             return;
108         }
109
110         GUI.skin.label.wordWrap = true;
111         //GUI.skin.button.richText = true; // this allows toolbar buttons to have bold/colored text. nice to indicate new msgs
112         //GUILayout.Button("lala"); // as richText, html tags could be in text
113
114
115         if (Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.KeypadEnter || Event.current.keyCode == KeyCode.Return))
116         {
117             if ("ChatInput".Equals(GUI.GetNameOfFocusedControl()))
118             {
119                 // focus on input -> submit it
120                 GuiSendsMsg();
121                 return; // showing the now modified list would result in an error. to avoid this, we just skip this single frame
122             }
123             else
124             {
125                 // assign focus to input
126                 GUI.FocusControl("ChatInput");
127             }
128         }
129
130         GUI.SetNextControlName("");
131         GUILayout.BeginArea(this.GuiRect);
132
133         GUILayout.FlexibleSpace();
134
135         if (this.chatClient.State != ChatState.ConnectedToFrontEnd)
136         {
137             GUILayout.Label("Not in chat yet.");
138         }
139         else
140         {
141             List channels = new List(this.chatClient.PublicChannels.Keys); // this could be cached
142             int countOfPublicChannels = channels.Count;
143             channels.AddRange(this.chatClient.PrivateChannels.Keys);
144
145             if (channels.Count > 0)
146             {
147                 int previouslySelectedChannelIndex = this.selectedChannelIndex;
148                 int channelIndex = channels.IndexOf(this.selectedChannelName);
149                 this.selectedChannelIndex = (channelIndex >= 0) ? channelIndex : 0;
150
151                 this.selectedChannelIndex = GUILayout.Toolbar(this.selectedChannelIndex, channels.ToArray(), GUILayout.ExpandWidth(false));
152                 this.scrollPos = GUILayout.BeginScrollView(this.scrollPos);
153
154                 this.doingPrivateChat = (this.selectedChannelIndex >= countOfPublicChannels);
155                 this.selectedChannelName = channels[this.selectedChannelIndex];
156
157                 if (this.selectedChannelIndex != previouslySelectedChannelIndex)
158                 {
159                     // changed channel -> scroll down, if private: pre-fill "to" field with target user's name
160                     this.scrollPos.y = float.MaxValue;
161                     if (this.doingPrivateChat)
162                     {
163                         string[] pieces = this.selectedChannelName.Split(new char[] {':'}, 3);
164                         this.userIdInput = pieces[1];
165                     }
166                 }
167
168                 GUILayout.Label(ChatGui.WelcomeText);
169
170                 if (this.chatClient.TryGetChannel(selectedChannelName, this.doingPrivateChat, out this.selectedChannel))
171                 {
172                     for (int i = 0; i < this.selectedChannel.Messages.Count; i++)
173                     {
174                         string sender = this.selectedChannel.Senders[i];
175                         object message = this.selectedChannel.Messages[i];
176                         GUILayout.Label(string.Format("{0}: {1}", sender, message));
177                     }
178                 }
179
180                 GUILayout.EndScrollView();
181             }
182         }
183
184
185         GUILayout.BeginHorizontal();
186         if (doingPrivateChat)
187         {
188             GUILayout.Label("to:", GUILayout.ExpandWidth(false));
189             GUI.SetNextControlName("WhisperTo");
190             this.userIdInput = GUILayout.TextField(this.userIdInput, GUILayout.MinWidth(100), GUILayout.ExpandWidth(false));
191             string focussed = GUI.GetNameOfFocusedControl();
192             if (focussed.Equals("WhisperTo"))
193             {
194                 if (this.userIdInput.Equals("username"))
195                 {
196                     this.userIdInput = "";
197                 }
198             }
199             else if (string.IsNullOrEmpty(this.userIdInput))
200             {
201                 this.userIdInput = "username";
202             }
203
204         }
205         GUI.SetNextControlName("ChatInput");
206         inputLine = GUILayout.TextField(inputLine);
207         if (GUILayout.Button("Send", GUILayout.ExpandWidth(false)))
208         {
209             GuiSendsMsg();
210         }
211         GUILayout.EndHorizontal();
212         GUILayout.EndArea();
213     }
File name: ChatGui.cs Copy
317     public void OnSubscribed(string[] channels, bool[] results)
318     {
319
320         // this demo can automatically send a "hi" to subscribed channels. in a game you usually only send user's input!!
321         if (this.DemoPublishOnSubscribe)
322         {
323             foreach (string channel in channels)
324             {
325                 this.chatClient.PublishMessage(channel, "says 'hi' in OnSubscribed(). "); // you don't HAVE to send a msg on join but you could.
326             }
327         }
328     }
File name: HubGui.cs Copy
28     void OnGUI()
29     {
30         GUI.skin = this.Skin;
31         GUILayout.Space(10);
32
33         GUILayout.BeginHorizontal();
34         GUILayout.Space(10);
35         scrollPos = GUILayout.BeginScrollView(scrollPos, GUILayout.Width(320));
36
37         GUILayout.Label("Basics", m_Headline);
38         if (GUILayout.Button("Demo Boxes", GUILayout.Width(280)))
39         {
40             demoDescription = "Demo Boxes\n\nUses ConnectAndJoinRandom script.\n(joins a random room or creates one)\n\nInstantiates simple prefab.\nSynchronizes positions without smoothing.";
41             demoBtn = new DemoBtn() { Text = "Start", Link = "DemoBoxes-Scene" };
42         }
43         if (GUILayout.Button("Demo Worker", GUILayout.Width(280)))
44         {
45             demoDescription = "Demo Worker\n\nJoins the default lobby and shows existing rooms.\nLets you create or join a room.\nInstantiates an animated character.\nSynchronizes position and animation state of character with smoothing.\nImplements simple in-room Chat via RPC calls.";
46             demoBtn = new DemoBtn() { Text = "Start", Link = "DemoWorker-Scene" };
47         }
48         if (GUILayout.Button("Movement Smoothing", GUILayout.Width(280)))
49         {
50             demoDescription = "Movement Smoothing\n\nUses ConnectAndJoinRandom script.\nShows several basic ways to update positions of remote objects.";
51             demoBtn = new DemoBtn() { Text = "Start", Link = "DemoSynchronization-Scene" };
52         }
53
54         GUILayout.Label("Advanced", m_Headline);
55         if (GUILayout.Button("Ownership Transfer", GUILayout.Width(280)))
56         {
57             demoDescription = "Ownership Transfer\n\nShows how to transfer the ownership of a PhotonView.\nThe owner will send position updates of the GameObject.\nTransfer can be edited per PhotonView and set to Fixed (no transfer), Request (owner has to agree) or Takeover (owner can't object).";
58             this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoChangeOwner-Scene" };
59             this.webLink = new DemoBtn();
60         }
61         if (GUILayout.Button("Pickup, Teams, Scores", GUILayout.Width(280)))
62         {
63             demoDescription = "Pickup, Teams, Scores\n\nUses ConnectAndJoinRandom script.\nImplements item pickup with RPCs.\nUses Custom Properties for Teams.\nCounts score per player and team.\nUses PhotonPlayer extension methods for easy Custom Property access.";
64             this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoPickup-Scene" };
65             this.webLink = new DemoBtn();
66         }
67
68         GUILayout.Label("Feature Demos", m_Headline);
69         if (GUILayout.Button("Chat", GUILayout.Width(280)))
70         {
71             demoDescription = "Chat\n\nUses the Chat API (now part of PUN).\nSimple UI.\nYou can enter any User ID.\nAutomatically subscribes some channels.\nAllows simple commands via text.\n\nRequires configuration of Chat App ID in scene.";
72             this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoChat-Scene" };
73             this.webLink = new DemoBtn();
74         }
75         if (GUILayout.Button("RPG Movement", GUILayout.Width(280)))
76         {
77             demoDescription = "RPG Movement\n\nDemonstrates how to use the PhotonTransformView component to synchronize position updates smoothly using inter- and extrapolation.\n\nThis demo also shows how to setup a Mecanim Animator to update animations automatically based on received position updates (without sending explicit animation updates).";
78             this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoRPGMovement-Scene" };
79             this.webLink = new DemoBtn();
80         }
81         if (GUILayout.Button("Mecanim Animations", GUILayout.Width(280)))
82         {
83             demoDescription = "Mecanim Animations\n\nThis demo shows how to use the PhotonAnimatorView component to easily synchronize Mecanim animations.\n\nIt also demonstrates another feature of the PhotonTransformView component which gives you more control how position updates are inter-/extrapolated by telling the component how fast the object moves and turns using SetSynchronizedValues().";
84             this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoMecanim-Scene" };
85             this.webLink = new DemoBtn();
86         }
87         if (GUILayout.Button("2D Game", GUILayout.Width(280)))
88         {
89             demoDescription = "2D Game Demo\n\nSynchronizes animations, positions and physics in a 2D scene.";
90             this.demoBtn = new DemoBtn() { Text = "Start", Link = "Demo2DJumpAndRunWithPhysics-Scene" };
91             this.webLink = new DemoBtn();
92         }
93         if (GUILayout.Button("Friends & Authentication", GUILayout.Width(280)))
94         {
95             demoDescription = "Friends & Authentication\n\nShows connect with or without (server-side) authentication.\n\nAuthentication requires minor server-side setup (in Dashboard).\n\nOnce connected, you can find (made up) friends.\nJoin a room just to see how that gets visible in friends list.";
96             this.demoBtn = new DemoBtn() { Text = "Start", Link = "DemoFriends-Scene" };
97             this.webLink = new DemoBtn();
98         }
99
100         GUILayout.Label("Tutorial", m_Headline);
101         if (GUILayout.Button("Marco Polo Tutorial", GUILayout.Width(280)))
102         {
103             demoDescription = "Marco Polo Tutorial\n\nFinal result you could get when you do the Marco Polo Tutorial.\nSlightly modified to be more compatible with this package.";
104             this.demoBtn = new DemoBtn() { Text = "Start", Link = "MarcoPolo-Scene" };
105             this.webLink = new DemoBtn() { Text = "Open Tutorial (www)", Link = "http://tinyurl.com/nmylf44" };
106         }
107         GUILayout.EndScrollView();
108
109         GUILayout.BeginVertical(GUILayout.Width(Screen.width - 345));
110         GUILayout.Label(demoDescription);
111         GUILayout.Space(10);
112         if (!string.IsNullOrEmpty(this.demoBtn.Text))
113         {
114             if (GUILayout.Button(this.demoBtn.Text))
115             {
116                 Application.LoadLevel(this.demoBtn.Link);
117             }
118         }
119         if (!string.IsNullOrEmpty(this.webLink.Text))
120         {
121             if (GUILayout.Button(this.webLink.Text))
122             {
123                 Application.OpenURL(this.webLink.Link);
124             }
125         }
126         GUILayout.EndVertical();
127
128
129         GUILayout.EndHorizontal();
130     }
File name: WorkerInGame.cs Copy
74     public void OnPhotonInstantiate(PhotonMessageInfo info)
75     {
76         Debug.Log("OnPhotonInstantiate " + info.sender); // you could use this info to store this or react
77     }
File name: PhotonViewHandler.cs Copy
25     internal static void HierarchyChange()
26     {
27         if (Application.isPlaying)
28         {
29             //Debug.Log("HierarchyChange ignored, while running.");
30             CheckSceneForStuckHandlers = true; // done once AFTER play mode.
31             return;
32         }
33
34         if (CheckSceneForStuckHandlers)
35         {
36             CheckSceneForStuckHandlers = false;
37             PhotonNetwork.InternalCleanPhotonMonoFromSceneIfStuck();
38         }
39
40         HashSet pvInstances = new HashSet();
41         HashSet usedInstanceViewNumbers = new HashSet();
42         bool fixedSomeId = false;
43
44         //// the following code would be an option if we only checked scene objects (but we can check all PVs)
45         //PhotonView[] pvObjects = GameObject.FindSceneObjectsOfType(typeof(PhotonView)) as PhotonView[];
46         //Debug.Log("HierarchyChange. PV Count: " + pvObjects.Length);
47
48         string levelName = Application.loadedLevelName;
49         #if UNITY_EDITOR
50         levelName = System.IO.Path.GetFileNameWithoutExtension(EditorApplication.currentScene);
51         #endif
52         int minViewIdInThisScene = PunSceneSettings.MinViewIdForScene(levelName);
53         //Debug.Log("Level '" + Application.loadedLevelName + "' has a minimum ViewId of: " + minViewIdInThisScene);
54
55         PhotonView[] pvObjects = Resources.FindObjectsOfTypeAll(typeof(PhotonView)) as PhotonView[];
56
57         foreach (PhotonView view in pvObjects)
58         {
59             // first pass: fix prefabs to viewID 0 if they got a view number assigned (cause they should not have one!)
60             if (EditorUtility.IsPersistent(view.gameObject))
61             {
62                 if (view.viewID != 0 || view.prefixBackup != -1 || view.instantiationId != -1)
63                 {
64                     Debug.LogWarning("PhotonView on persistent object being fixed (id and prefix must be 0). Was: " + view);
65                     view.viewID = 0;
66                     view.prefixBackup = -1;
67                     view.instantiationId = -1;
68                     EditorUtility.SetDirty(view);
69                     fixedSomeId = true;
70                 }
71             }
72             else
73             {
74                 // keep all scene-instanced PVs for later re-check
75                 pvInstances.Add(view);
76             }
77         }
78
79         Dictionary idPerObject = new Dictionary();
80
81         // second pass: check all used-in-scene viewIDs for duplicate viewIDs (only checking anything non-prefab)
82         // scene-PVs must have user == 0 (scene/room) and a subId != 0
83         foreach (PhotonView view in pvInstances)
84         {
85             if (view.ownerId > 0)
86             {
87                 Debug.Log("Re-Setting Owner ID of: " + view);
88             }
89             view.ownerId = 0; // simply make sure no owner is set (cause room always uses 0)
90             view.prefix = -1; // TODO: prefix could be settable via inspector per scene?!
91
92             if (view.viewID != 0)
93             {
94                 if (view.viewID < minViewIdInThisScene || usedInstanceViewNumbers.Contains(view.viewID))
95                 {
96                     view.viewID = 0; // avoid duplicates and negative values by assigning 0 as (temporary) number to be fixed in next pass
97                 }
98                 else
99                 {
100                     usedInstanceViewNumbers.Add(view.viewID); // builds a list of currently used viewIDs
101
102                     int instId = 0;
103                     if (idPerObject.TryGetValue(view.gameObject, out instId))
104                     {
105                         view.instantiationId = instId;
106                     }
107                     else
108                     {
109                         view.instantiationId = view.viewID;
110                         idPerObject[view.gameObject] = view.instantiationId;
111                     }
112                 }
113             }
114
115         }
116
117         // third pass: anything that's now 0 must get a new (not yet used) ID (starting at 0)
118         int lastUsedId = (minViewIdInThisScene > 0) ? minViewIdInThisScene - 1 : 0;
119
120         foreach (PhotonView view in pvInstances)
121         {
122             if (view.viewID == 0)
123             {
124                 // Debug.LogWarning("setting scene ID: " + view.gameObject.name + " ID: " + view.subId.ID + " scene ID: " + view.GetSceneID() + " IsPersistent: " + EditorUtility.IsPersistent(view.gameObject) + " IsSceneViewIDFree: " + IsSceneViewIDFree(view.subId.ID, view));
125                 int nextViewId = PhotonViewHandler.GetID(lastUsedId, usedInstanceViewNumbers);
126
127                 view.viewID = nextViewId;
128
129                 int instId = 0;
130                 if (idPerObject.TryGetValue(view.gameObject, out instId))
131                 {
132                     Debug.Log("Set inst ID");
133                     view.instantiationId = instId;
134                 }
135                 else
136                 {
137                     view.instantiationId = view.viewID;
138                     idPerObject[view.gameObject] = nextViewId;
139                 }
140
141                 //// when using the Editor's serialization (view.subId in this case), this is not needed, it seems
142                 //PrefabUtility.RecordPrefabInstancePropertyModifications(view);
143
144                 lastUsedId = nextViewId;
145                 EditorUtility.SetDirty(view);
146                 fixedSomeId = true;
147             }
148         }
149
150
151         if (fixedSomeId)
152         {
153             //Debug.LogWarning("Some subId was adjusted."); // this log is only interesting for Exit Games
154         }
155     }
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(regions.Length);
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 friendList = new List(this.friendListRequested.Length);
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
1631     public void OnEvent(EventData photonEvent)
1632     {
1633         if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
1634             Debug.Log(string.Format("OnEvent: {0}", photonEvent.ToString()));
1635
1636         int actorNr = -1;
1637         PhotonPlayer originatingPlayer = null;
1638
1639         if (photonEvent.Parameters.ContainsKey(ParameterCode.ActorNr))
1640         {
1641             actorNr = (int)photonEvent[ParameterCode.ActorNr];
1642             if (this.mActors.ContainsKey(actorNr))
1643             {
1644                 originatingPlayer = (PhotonPlayer)this.mActors[actorNr];
1645             }
1646             //else
1647             //{
1648             // // the actor sending this event is not in actorlist. this is usually no problem
1649             // if (photonEvent.Code != (byte)LiteOpCode.Join)
1650             // {
1651             // Debug.LogWarning("Received event, but we do not have this actor: " + actorNr);
1652             // }
1653             //}
1654         }
1655
1656         switch (photonEvent.Code)
1657         {
1658             case PunEvent.OwnershipRequest:
1659             {
1660                 int[] requestValues = (int[]) photonEvent.Parameters[ParameterCode.CustomEventContent];
1661                 int requestedViewId = requestValues[0];
1662                 int currentOwner = requestValues[1];
1663                 Debug.Log("Ev OwnershipRequest: " + photonEvent.Parameters.ToStringFull() + " ViewID: " + requestedViewId + " from: " + currentOwner + " Time: " + Environment.TickCount%1000);
1664
1665                 PhotonView requestedView = PhotonView.Find(requestedViewId);
1666                 if (requestedView == null)
1667                 {
1668                     Debug.LogWarning("Can't find PhotonView of incoming OwnershipRequest. ViewId not found: " + requestedViewId);
1669                     break;
1670                 }
1671
1672                 Debug.Log("Ev OwnershipRequest PhotonView.ownershipTransfer: " + requestedView.ownershipTransfer + " .ownerId: " + requestedView.ownerId + " isOwnerActive: " + requestedView.isOwnerActive + ". This client's player: " + PhotonNetwork.player.ToStringFull());
1673
1674                 switch (requestedView.ownershipTransfer)
1675                 {
1676                     case OwnershipOption.Fixed:
1677                         Debug.LogWarning("Ownership mode == fixed. Ignoring request.");
1678                         break;
1679                     case OwnershipOption.Takeover:
1680                         if (currentOwner == requestedView.ownerId)
1681                         {
1682                             // a takeover is successful automatically, if taken from current owner
1683                             requestedView.ownerId = actorNr;
1684                         }
1685                         break;
1686                     case OwnershipOption.Request:
1687                         if (currentOwner == PhotonNetwork.player.ID || PhotonNetwork.player.isMasterClient)
1688                         {
1689                             if ((requestedView.ownerId == PhotonNetwork.player.ID) || (PhotonNetwork.player.isMasterClient && !requestedView.isOwnerActive))
1690                             {
1691                                 SendMonoMessage(PhotonNetworkingMessage.OnOwnershipRequest, new object[] {requestedView, originatingPlayer});
1692                             }
1693                         }
1694                         break;
1695                     default:
1696                         break;
1697                 }
1698             }
1699                 break;
1700
1701             case PunEvent.OwnershipTransfer:
1702                 {
1703                     int[] transferViewToUserID = (int[]) photonEvent.Parameters[ParameterCode.CustomEventContent];
1704                     Debug.Log("Ev OwnershipTransfer. ViewID " + transferViewToUserID[0] + " to: " + transferViewToUserID[1] + " Time: " + Environment.TickCount%1000);
1705
1706                     int requestedViewId = transferViewToUserID[0];
1707                     int newOwnerId = transferViewToUserID[1];
1708
1709                     PhotonView pv = PhotonView.Find(requestedViewId);
1710                     pv.ownerId = newOwnerId;
1711
1712                     break;
1713                 }
1714             case EventCode.GameList:
1715                 {
1716                     this.mGameList = new Dictionary();
1717                     Hashtable games = (Hashtable)photonEvent[ParameterCode.GameList];
1718                     foreach (DictionaryEntry game in games)
1719                     {
1720                         string gameName = (string)game.Key;
1721                         this.mGameList[gameName] = new RoomInfo(gameName, (Hashtable)game.Value);
1722                     }
1723                     mGameListCopy = new RoomInfo[mGameList.Count];
1724                     mGameList.Values.CopyTo(mGameListCopy, 0);
1725                     SendMonoMessage(PhotonNetworkingMessage.OnReceivedRoomListUpdate);
1726                     break;
1727                 }
1728
1729             case EventCode.GameListUpdate:
1730                 {
1731                     Hashtable games = (Hashtable)photonEvent[ParameterCode.GameList];
1732                     foreach (DictionaryEntry room in games)
1733                     {
1734                         string gameName = (string)room.Key;
1735                         RoomInfo game = new RoomInfo(gameName, (Hashtable)room.Value);
1736                         if (game.removedFromList)
1737                         {
1738                             this.mGameList.Remove(gameName);
1739                         }
1740                         else
1741                         {
1742                             this.mGameList[gameName] = game;
1743                         }
1744                     }
1745                     this.mGameListCopy = new RoomInfo[this.mGameList.Count];
1746                     this.mGameList.Values.CopyTo(this.mGameListCopy, 0);
1747                     SendMonoMessage(PhotonNetworkingMessage.OnReceivedRoomListUpdate);
1748                     break;
1749                 }
1750
1751             case EventCode.QueueState:
1752                 // not used anymore
1753                 break;
1754
1755             case EventCode.AppStats:
1756                 // Debug.LogInfo("Received stats!");
1757                 this.mPlayersInRoomsCount = (int)photonEvent[ParameterCode.PeerCount];
1758                 this.mPlayersOnMasterCount = (int)photonEvent[ParameterCode.MasterPeerCount];
1759                 this.mGameCount = (int)photonEvent[ParameterCode.GameCount];
1760                 break;
1761
1762             case EventCode.Join:
1763                 // actorNr is fetched out of event above
1764                 Hashtable actorProperties = (Hashtable)photonEvent[ParameterCode.PlayerProperties];
1765                 if (originatingPlayer == null)
1766                 {
1767                     bool isLocal = this.mLocalActor.ID == actorNr;
1768                     this.AddNewPlayer(actorNr, new PhotonPlayer(isLocal, actorNr, actorProperties));
1769                     this.ResetPhotonViewsOnSerialize(); // This sets the correct OnSerializeState for Reliable OnSerialize
1770                 }
1771
1772                 if (actorNr == this.mLocalActor.ID)
1773                 {
1774                     // in this player's 'own' join event, we get a complete list of players in the room, so check if we know all players
1775                     int[] actorsInRoom = (int[])photonEvent[ParameterCode.ActorList];
1776                     foreach (int actorNrToCheck in actorsInRoom)
1777                     {
1778                         if (this.mLocalActor.ID != actorNrToCheck && !this.mActors.ContainsKey(actorNrToCheck))
1779                         {
1780                             this.AddNewPlayer(actorNrToCheck, new PhotonPlayer(false, actorNrToCheck, string.Empty));
1781                         }
1782                     }
1783
1784                     // joinWithCreateOnDemand can turn an OpJoin into creating the room. Then actorNumber is 1 and callback: OnCreatedRoom()
1785                     if (this.mLastJoinType == JoinType.JoinOrCreateOnDemand && this.mLocalActor.ID == 1)
1786                     {
1787                         SendMonoMessage(PhotonNetworkingMessage.OnCreatedRoom);
1788                     }
1789                     SendMonoMessage(PhotonNetworkingMessage.OnJoinedRoom); //Always send OnJoinedRoom
1790
1791                 }
1792                 else
1793                 {
1794                     SendMonoMessage(PhotonNetworkingMessage.OnPhotonPlayerConnected, this.mActors[actorNr]);
1795                 }
1796                 break;
1797
1798             case EventCode.Leave:
1799                 this.HandleEventLeave(actorNr);
1800                 break;
1801
1802             case EventCode.PropertiesChanged:
1803                 int targetActorNr = (int)photonEvent[ParameterCode.TargetActorNr];
1804                 Hashtable gameProperties = null;
1805                 Hashtable actorProps = null;
1806                 if (targetActorNr == 0)
1807                 {
1808                     gameProperties = (Hashtable)photonEvent[ParameterCode.Properties];
1809                 }
1810                 else
1811                 {
1812                     actorProps = (Hashtable)photonEvent[ParameterCode.Properties];
1813                 }
1814
1815                 this.ReadoutProperties(gameProperties, actorProps, targetActorNr);
1816                 break;
1817
1818             case PunEvent.RPC:
1819                 //ts: each event now contains a single RPC. execute this
1820                 // Debug.Log("Ev RPC from: " + originatingPlayer);
1821                 this.ExecuteRPC(photonEvent[ParameterCode.Data] as Hashtable, originatingPlayer);
1822                 break;
1823
1824             case PunEvent.SendSerialize:
1825             case PunEvent.SendSerializeReliable:
1826                 Hashtable serializeData = (Hashtable)photonEvent[ParameterCode.Data];
1827                 //Debug.Log(serializeData.ToStringFull());
1828
1829                 int remoteUpdateServerTimestamp = (int)serializeData[(byte)0];
1830                 short remoteLevelPrefix = -1;
1831                 short initialDataIndex = 1;
1832                 if (serializeData.ContainsKey((byte)1))
1833                 {
1834                     remoteLevelPrefix = (short)serializeData[(byte)1];
1835                     initialDataIndex = 2;
1836                 }
1837
1838                 for (short s = initialDataIndex; s < serializeData.Count; s++)
1839                 {
1840                     this.OnSerializeRead(serializeData[s] as Hashtable, originatingPlayer, remoteUpdateServerTimestamp, remoteLevelPrefix);
1841                 }
1842                 break;
1843
1844             case PunEvent.Instantiation:
1845                 this.DoInstantiate((Hashtable)photonEvent[ParameterCode.Data], originatingPlayer, null);
1846                 break;
1847
1848             case PunEvent.CloseConnection:
1849                 // MasterClient "requests" a disconnection from us
1850                 if (originatingPlayer == null || !originatingPlayer.isMasterClient)
1851                 {
1852                     Debug.LogError("Error: Someone else(" + originatingPlayer + ") then the masterserver requests a disconnect!");
1853                 }
1854                 else
1855                 {
1856                     PhotonNetwork.LeaveRoom();
1857                 }
1858
1859                 break;
1860
1861             case PunEvent.DestroyPlayer:
1862                 Hashtable evData = (Hashtable)photonEvent[ParameterCode.Data];
1863                 int targetPlayerId = (int)evData[(byte)0];
1864                 if (targetPlayerId >= 0)
1865                 {
1866                     this.DestroyPlayerObjects(targetPlayerId, true);
1867                 }
1868                 else
1869                 {
1870                     if (this.DebugOut >= DebugLevel.INFO) Debug.Log("Ev DestroyAll! By PlayerId: " + actorNr);
1871                     this.DestroyAll(true);
1872                 }
1873                 break;
1874
1875             case PunEvent.Destroy:
1876                 evData = (Hashtable)photonEvent[ParameterCode.Data];
1877                 int instantiationId = (int)evData[(byte)0];
1878                 // Debug.Log("Ev Destroy for viewId: " + instantiationId + " sent by owner: " + (instantiationId / PhotonNetwork.MAX_VIEW_IDS == actorNr) + " this client is owner: " + (instantiationId / PhotonNetwork.MAX_VIEW_IDS == this.mLocalActor.ID));
1879
1880
1881                 PhotonView pvToDestroy = null;
1882                 if (this.photonViewList.TryGetValue(instantiationId, out pvToDestroy))
1883                 {
1884                     this.RemoveInstantiatedGO(pvToDestroy.gameObject, true);
1885                 }
1886                 else
1887                 {
1888                     if (this.DebugOut >= DebugLevel.ERROR) Debug.LogError("Ev Destroy Failed. Could not find PhotonView with instantiationId " + instantiationId + ". Sent by actorNr: " + actorNr);
1889                 }
1890
1891                 break;
1892
1893             case PunEvent.AssignMaster:
1894                 evData = (Hashtable)photonEvent[ParameterCode.Data];
1895                 int newMaster = (int)evData[(byte)1];
1896                 this.SetMasterClient(newMaster, false);
1897                 break;
1898
1899             default:
1900                 if (photonEvent.Code < 200 && PhotonNetwork.OnEventCall != null)
1901                 {
1902                     object content = photonEvent[ParameterCode.Data];
1903                     PhotonNetwork.OnEventCall(photonEvent.Code, content, actorNr);
1904                 }
1905                 else
1906                 {
1907                     // actorNr might be null. it is fetched out of event on top of method
1908                     // Hashtable eventContent = (Hashtable) photonEvent[ParameterCode.Data];
1909                     // this.mListener.customEventAction(actorNr, eventCode, eventContent);
1910                     Debug.LogError("Error. Unhandled event: " + photonEvent);
1911                 }
1912                 break;
1913         }
1914
1915         this.externalListener.OnEvent(photonEvent);
1916     }
File name: NetworkingPeer.cs Copy
1962     public void ExecuteRPC(Hashtable rpcData, PhotonPlayer sender)
1963     {
1964         if (rpcData == null || !rpcData.ContainsKey((byte)0))
1965         {
1966             Debug.LogError("Malformed RPC; this should never occur. Content: " + SupportClass.DictionaryToString(rpcData));
1967             return;
1968         }
1969
1970         // ts: updated with "flat" event data
1971         int netViewID = (int)rpcData[(byte)0]; // LIMITS PHOTONVIEWS&PLAYERS
1972         int otherSidePrefix = 0; // by default, the prefix is 0 (and this is not being sent)
1973         if (rpcData.ContainsKey((byte)1))
1974         {
1975             otherSidePrefix = (short)rpcData[(byte)1];
1976         }
1977
1978         string inMethodName;
1979         if (rpcData.ContainsKey((byte)5))
1980         {
1981             int rpcIndex = (byte)rpcData[(byte)5]; // LIMITS RPC COUNT
1982             if (rpcIndex > PhotonNetwork.PhotonServerSettings.RpcList.Count - 1)
1983             {
1984                 Debug.LogError("Could not find RPC with index: " + rpcIndex + ". Going to ignore! Check PhotonServerSettings.RpcList");
1985                 return;
1986             }
1987             else
1988             {
1989                 inMethodName = PhotonNetwork.PhotonServerSettings.RpcList[rpcIndex];
1990             }
1991         }
1992         else
1993         {
1994             inMethodName = (string)rpcData[(byte)3];
1995         }
1996
1997         object[] inMethodParameters = null;
1998         if (rpcData.ContainsKey((byte)4))
1999         {
2000             inMethodParameters = (object[])rpcData[(byte)4];
2001         }
2002
2003         if (inMethodParameters == null)
2004         {
2005             inMethodParameters = new object[0];
2006         }
2007
2008         PhotonView photonNetview = this.GetPhotonView(netViewID);
2009         if (photonNetview == null)
2010         {
2011             int viewOwnerId = netViewID/PhotonNetwork.MAX_VIEW_IDS;
2012             bool owningPv = (viewOwnerId == this.mLocalActor.ID);
2013             bool ownerSent = (viewOwnerId == sender.ID);
2014
2015             if (owningPv)
2016             {
2017                 Debug.LogWarning("Received RPC \"" + inMethodName + "\" for viewID " + netViewID + " but this PhotonView does not exist! View was/is ours." + (ownerSent ? " Owner called." : " Remote called.") + " By: " + sender.ID);
2018             }
2019             else
2020             {
2021                 Debug.LogWarning("Received RPC \"" + inMethodName + "\" for viewID " + netViewID + " but this PhotonView does not exist! Was remote PV." + (ownerSent ? " Owner called." : " Remote called.") + " By: " + sender.ID + " Maybe GO was destroyed but RPC not cleaned up.");
2022             }
2023             return;
2024         }
2025
2026         if (photonNetview.prefix != otherSidePrefix)
2027         {
2028             Debug.LogError(
2029                 "Received RPC \"" + inMethodName + "\" on viewID " + netViewID + " with a prefix of " + otherSidePrefix
2030                 + ", our prefix is " + photonNetview.prefix + ". The RPC has been ignored.");
2031             return;
2032         }
2033
2034         // Get method name
2035         if (inMethodName == string.Empty)
2036         {
2037             Debug.LogError("Malformed RPC; this should never occur. Content: " + SupportClass.DictionaryToString(rpcData));
2038             return;
2039         }
2040
2041         if (PhotonNetwork.logLevel >= PhotonLogLevel.Full)
2042             Debug.Log("Received RPC: " + inMethodName);
2043
2044
2045         // SetReceiving filtering
2046         if (photonNetview.group != 0 && !allowedReceivingGroups.Contains(photonNetview.group))
2047         {
2048             return; // Ignore group
2049         }
2050
2051         Type[] argTypes = new Type[0];
2052         if (inMethodParameters.Length > 0)
2053         {
2054             argTypes = new Type[inMethodParameters.Length];
2055             int i = 0;
2056             for (int index = 0; index < inMethodParameters.Length; index++)
2057             {
2058                 object objX = inMethodParameters[index];
2059                 if (objX == null)
2060                 {
2061                     argTypes[i] = null;
2062                 }
2063                 else
2064                 {
2065                     argTypes[i] = objX.GetType();
2066                 }
2067
2068                 i++;
2069             }
2070         }
2071
2072         int receivers = 0;
2073         int foundMethods = 0;
2074         MonoBehaviour[] mbComponents = photonNetview.GetComponents(); // NOTE: we could possibly also cache MonoBehaviours per view?!
2075         for (int componentsIndex = 0; componentsIndex < mbComponents.Length; componentsIndex++)
2076         {
2077             MonoBehaviour monob = mbComponents[componentsIndex];
2078             if (monob == null)
2079             {
2080                 Debug.LogError("ERROR You have missing MonoBehaviours on your gameobjects!");
2081                 continue;
2082             }
2083
2084             Type type = monob.GetType();
2085
2086             // Get [RPC] methods from cache
2087             List cachedRPCMethods = null;
2088             if (this.monoRPCMethodsCache.ContainsKey(type))
2089             {
2090                 cachedRPCMethods = this.monoRPCMethodsCache[type];
2091             }
2092
2093             if (cachedRPCMethods == null)
2094             {
2095                 List entries = SupportClass.GetMethods(type, typeof(RPC));
2096
2097                 this.monoRPCMethodsCache[type] = entries;
2098                 cachedRPCMethods = entries;
2099             }
2100
2101             if (cachedRPCMethods == null)
2102             {
2103                 continue;
2104             }
2105
2106             // Check cache for valid methodname+arguments
2107             for (int index = 0; index < cachedRPCMethods.Count; index++)
2108             {
2109                 MethodInfo mInfo = cachedRPCMethods[index];
2110                 if (mInfo.Name == inMethodName)
2111                 {
2112                     foundMethods++;
2113                     ParameterInfo[] pArray = mInfo.GetParameters();
2114                     if (pArray.Length == argTypes.Length)
2115                     {
2116                         // Normal, PhotonNetworkMessage left out
2117                         if (this.CheckTypeMatch(pArray, argTypes))
2118                         {
2119                             receivers++;
2120                             object result = mInfo.Invoke((object)monob, inMethodParameters);
2121                             if (mInfo.ReturnType == typeof(IEnumerator))
2122                             {
2123                                 monob.StartCoroutine((IEnumerator)result);
2124                             }
2125                         }
2126                     }
2127                     else if ((pArray.Length - 1) == argTypes.Length)
2128                     {
2129                         // Check for PhotonNetworkMessage being the last
2130                         if (this.CheckTypeMatch(pArray, argTypes))
2131                         {
2132                             if (pArray[pArray.Length - 1].ParameterType == typeof(PhotonMessageInfo))
2133                             {
2134                                 receivers++;
2135
2136                                 int sendTime = (int)rpcData[(byte)2];
2137                                 object[] deParamsWithInfo = new object[inMethodParameters.Length + 1];
2138                                 inMethodParameters.CopyTo(deParamsWithInfo, 0);
2139                                 deParamsWithInfo[deParamsWithInfo.Length - 1] = new PhotonMessageInfo(sender, sendTime, photonNetview);
2140
2141                                 object result = mInfo.Invoke((object)monob, deParamsWithInfo);
2142                                 if (mInfo.ReturnType == typeof(IEnumerator))
2143                                 {
2144                                     monob.StartCoroutine((IEnumerator)result);
2145                                 }
2146                             }
2147                         }
2148                     }
2149                     else if (pArray.Length == 1 && pArray[0].ParameterType.IsArray)
2150                     {
2151                         receivers++;
2152                         object result = mInfo.Invoke((object)monob, new object[] { inMethodParameters });
2153                         if (mInfo.ReturnType == typeof(IEnumerator))
2154                         {
2155                             monob.StartCoroutine((IEnumerator)result);
2156                         }
2157                     }
2158                 }
2159             }
2160         }
2161
2162         // Error handling
2163         if (receivers != 1)
2164         {
2165             string argsString = string.Empty;
2166             for (int index = 0; index < argTypes.Length; index++)
2167             {
2168                 Type ty = argTypes[index];
2169                 if (argsString != string.Empty)
2170                 {
2171                     argsString += ", ";
2172                 }
2173
2174                 if (ty == null)
2175                 {
2176                     argsString += "null";
2177                 }
2178                 else
2179                 {
2180                     argsString += ty.Name;
2181                 }
2182             }
2183
2184             if (receivers == 0)
2185             {
2186                 if (foundMethods == 0)
2187                 {
2188                     Debug.LogError("PhotonView with ID " + netViewID + " has no method \"" + inMethodName + "\" marked with the [RPC](C#) or @RPC(JS) property! Args: " + argsString);
2189                 }
2190                 else
2191                 {
2192                     Debug.LogError("PhotonView with ID " + netViewID + " has no method \"" + inMethodName + "\" that takes " + argTypes.Length + " argument(s): " + argsString);
2193                 }
2194             }
2195             else
2196             {
2197                 Debug.LogError("PhotonView with ID " + netViewID + " has " + receivers + " methods \"" + inMethodName + "\" that takes " + argTypes.Length + " argument(s): " + argsString + ". Should be just one?");
2198             }
2199         }
2200     }
File name: NetworkingPeer.cs Copy
2279     internal GameObject DoInstantiate(Hashtable evData, PhotonPlayer photonPlayer, GameObject resourceGameObject)
2280     {
2281         // some values always present:
2282         string prefabName = (string)evData[(byte)0];
2283         int serverTime = (int)evData[(byte)6];
2284         int instantiationId = (int)evData[(byte)7];
2285
2286         Vector3 position;
2287         if (evData.ContainsKey((byte)1))
2288         {
2289             position = (Vector3)evData[(byte)1];
2290         }
2291         else
2292         {
2293             position = Vector3.zero;
2294         }
2295
2296         Quaternion rotation = Quaternion.identity;
2297         if (evData.ContainsKey((byte)2))
2298         {
2299             rotation = (Quaternion)evData[(byte)2];
2300         }
2301
2302         int group = 0;
2303         if (evData.ContainsKey((byte)3))
2304         {
2305             group = (int)evData[(byte)3];
2306         }
2307
2308         short objLevelPrefix = 0;
2309         if (evData.ContainsKey((byte)8))
2310         {
2311             objLevelPrefix = (short)evData[(byte)8];
2312         }
2313
2314         int[] viewsIDs;
2315         if (evData.ContainsKey((byte)4))
2316         {
2317             viewsIDs = (int[])evData[(byte)4];
2318         }
2319         else
2320         {
2321             viewsIDs = new int[1] { instantiationId };
2322         }
2323
2324         object[] incomingInstantiationData;
2325         if (evData.ContainsKey((byte)5))
2326         {
2327             incomingInstantiationData = (object[])evData[(byte)5];
2328         }
2329         else
2330         {
2331             incomingInstantiationData = null;
2332         }
2333
2334         // SetReceiving filtering
2335         if (group != 0 && !this.allowedReceivingGroups.Contains(group))
2336         {
2337             return null; // Ignore group
2338         }
2339
2340         // load prefab, if it wasn't loaded before (calling methods might do this)
2341         if (resourceGameObject == null)
2342         {
2343             if (!NetworkingPeer.UsePrefabCache || !NetworkingPeer.PrefabCache.TryGetValue(prefabName, out resourceGameObject))
2344             {
2345                 resourceGameObject = (GameObject)Resources.Load(prefabName, typeof(GameObject));
2346                 if (NetworkingPeer.UsePrefabCache)
2347                 {
2348                     NetworkingPeer.PrefabCache.Add(prefabName, resourceGameObject);
2349                 }
2350             }
2351
2352             if (resourceGameObject == null)
2353             {
2354                 Debug.LogError("PhotonNetwork error: Could not Instantiate the prefab [" + prefabName + "]. Please verify you have this gameobject in a Resources folder.");
2355                 return null;
2356             }
2357         }
2358
2359         // now modify the loaded "blueprint" object before it becomes a part of the scene (by instantiating it)
2360         PhotonView[] resourcePVs = resourceGameObject.GetPhotonViewsInChildren();
2361         if (resourcePVs.Length != viewsIDs.Length)
2362         {
2363             throw new Exception("Error in Instantiation! The resource's PhotonView count is not the same as in incoming data.");
2364         }
2365
2366         for (int i = 0; i < viewsIDs.Length; i++)
2367         {
2368             // NOTE instantiating the loaded resource will keep the viewID but would not copy instantiation data, so it's set below
2369             // so we only set the viewID and instantiationId now. the instantiationData can be fetched
2370             resourcePVs[i].viewID = viewsIDs[i];
2371             resourcePVs[i].prefix = objLevelPrefix;
2372             resourcePVs[i].instantiationId = instantiationId;
2373             resourcePVs[i].isRuntimeInstantiated = true;
2374         }
2375
2376         this.StoreInstantiationData(instantiationId, incomingInstantiationData);
2377
2378         // load the resource and set it's values before instantiating it:
2379         GameObject go = (GameObject)GameObject.Instantiate(resourceGameObject, position, rotation);
2380
2381         for (int i = 0; i < viewsIDs.Length; i++)
2382         {
2383             // NOTE instantiating the loaded resource will keep the viewID but would not copy instantiation data, so it's set below
2384             // so we only set the viewID and instantiationId now. the instantiationData can be fetched
2385             resourcePVs[i].viewID = 0;
2386             resourcePVs[i].prefix = -1;
2387             resourcePVs[i].prefixBackup = -1;
2388             resourcePVs[i].instantiationId = -1;
2389             resourcePVs[i].isRuntimeInstantiated = false;
2390         }
2391
2392         this.RemoveInstantiationData(instantiationId);
2393
2394         // Send OnPhotonInstantiate callback to newly created GO.
2395         // GO will be enabled when instantiated from Prefab and it does not matter if the script is enabled or disabled.
2396         go.SendMessage(PhotonNetworkingMessage.OnPhotonInstantiate.ToString(), new PhotonMessageInfo(photonPlayer, serverTime, null), SendMessageOptions.DontRequireReceiver);
2397         return go;
2398     }

Could 134 lượt xem

Gõ tìm kiếm nhanh...