summaryrefslogtreecommitdiff
path: root/Client/Assembly-CSharp/InnerNet/InnerNetClient.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Client/Assembly-CSharp/InnerNet/InnerNetClient.cs')
-rw-r--r--Client/Assembly-CSharp/InnerNet/InnerNetClient.cs1726
1 files changed, 1726 insertions, 0 deletions
diff --git a/Client/Assembly-CSharp/InnerNet/InnerNetClient.cs b/Client/Assembly-CSharp/InnerNet/InnerNetClient.cs
new file mode 100644
index 0000000..7cff87c
--- /dev/null
+++ b/Client/Assembly-CSharp/InnerNet/InnerNetClient.cs
@@ -0,0 +1,1726 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Threading;
+using Assets.CoreScripts;
+using Hazel;
+using Hazel.Udp;
+using UnityEngine;
+using UnityEngine.SceneManagement;
+
+namespace InnerNet
+{
+ public abstract class InnerNetClient : MonoBehaviour
+ {
+ private bool AmConnected
+ {
+ get
+ {
+ return this.connection != null;
+ }
+ }
+
+ public int Ping
+ {
+ get
+ {
+ if (this.connection == null)
+ {
+ return 0;
+ }
+ return (int)this.connection.AveragePingMs;
+ }
+ }
+
+ public bool AmHost
+ {
+ get
+ {
+ return this.HostId == this.ClientId;
+ }
+ }
+
+ public bool AmClient
+ {
+ get
+ {
+ return this.ClientId > 0;
+ }
+ }
+
+ public bool IsGamePublic { get; private set; }
+
+ public bool IsGameStarted
+ {
+ get
+ {
+ return this.GameState == InnerNetClient.GameStates.Started;
+ }
+ }
+
+ public bool IsGameOver
+ {
+ get
+ {
+ return this.GameState == InnerNetClient.GameStates.Ended;
+ }
+ }
+
+ private static readonly DisconnectReasons[] disconnectReasons = new DisconnectReasons[]
+ {
+ DisconnectReasons.Error,
+ DisconnectReasons.GameFull,
+ DisconnectReasons.GameStarted,
+ DisconnectReasons.GameNotFound,
+ DisconnectReasons.IncorrectVersion,
+ DisconnectReasons.Banned,
+ DisconnectReasons.Kicked,
+ DisconnectReasons.ServerFull,
+ DisconnectReasons.Custom
+ };
+
+ public const int NoClientId = -1;
+
+ private string networkAddress = "127.0.0.1";
+
+ private int networkPort;
+
+ private UdpClientConnection connection;
+
+ public MatchMakerModes mode;
+
+ public int GameId = 32;
+
+ public int HostId;
+
+ public int ClientId = -1;
+
+ public List<ClientData> allClients = new List<ClientData>();
+
+ public DisconnectReasons LastDisconnectReason;
+
+ public string LastCustomDisconnect;
+
+ private readonly List<Action> PreSpawnDispatcher = new List<Action>();
+
+ //c 网络消息队列,网络线程写入,主线程调用
+ private readonly List<Action> Dispatcher = new List<Action>();
+
+ public InnerNetClient.GameStates GameState;
+
+ private List<Action> TempQueue = new List<Action>();
+
+ private volatile bool appPaused;
+
+ public const int CurrentClient = -3;
+
+ public const int InvalidClient = -2;
+
+ internal const byte DataFlag = 1;
+
+ internal const byte RpcFlag = 2;
+
+ internal const byte SpawnFlag = 4;
+
+ internal const byte DespawnFlag = 5;
+
+ internal const byte SceneChangeFlag = 6;
+
+ internal const byte ReadyFlag = 7;
+
+ internal const byte ChangeSettingsFlag = 8;
+
+ // 每次发送数据的间隔,每过0.1s发送一次
+ public float MinSendInterval = 0.1f;
+
+ private uint NetIdCnt = 1U;
+
+ private float timer;
+
+ public InnerNetObject[] SpawnableObjects;
+
+ private bool InOnlineScene;
+
+ private HashSet<uint> DestroyedObjects = new HashSet<uint>();
+
+ // 所有要同步的数据,包括InnerNetObject的所有派生类,场景内所有的对象的数据
+ public List<InnerNetObject> allObjects = new List<InnerNetObject>();
+
+ private Dictionary<uint, InnerNetObject> allObjectsFast = new Dictionary<uint, InnerNetObject>();
+
+ private MessageWriter[] Streams;
+
+ public enum GameStates
+ {
+ NotJoined,
+ Joined,
+ Started,
+ Ended
+ }
+
+ public void SetEndpoint(string addr, ushort port)
+ {
+ this.networkAddress = addr;
+ this.networkPort = (int)port;
+ }
+
+ public virtual void Start()
+ {
+ SceneManager.activeSceneChanged += delegate(Scene oldScene, Scene scene)
+ {
+ this.SendSceneChange(scene.name);
+ };
+ this.ClientId = -1;
+ this.GameId = 32;
+ }
+
+ private void SendOrDisconnect(MessageWriter msg)
+ {
+ try
+ {
+ this.connection.Send(msg);
+ }
+ catch
+ {
+ this.EnqueueDisconnect(DisconnectReasons.Error, "Failed to send message");
+ }
+ }
+
+ public ClientData GetHost()
+ {
+ List<ClientData> obj = this.allClients;
+ lock (obj)
+ {
+ for (int i = 0; i < this.allClients.Count; i++)
+ {
+ ClientData clientData = this.allClients[i];
+ if (clientData.Id == this.HostId)
+ {
+ return clientData;
+ }
+ }
+ }
+ return null;
+ }
+
+ public int GetClientIdFromCharacter(InnerNetObject character)
+ {
+ if (!character)
+ {
+ return -1;
+ }
+ List<ClientData> obj = this.allClients;
+ lock (obj)
+ {
+ for (int i = 0; i < this.allClients.Count; i++)
+ {
+ ClientData clientData = this.allClients[i];
+ if (clientData.Character == character)
+ {
+ return clientData.Id;
+ }
+ }
+ }
+ return -1;
+ }
+
+ public virtual void OnDestroy()
+ {
+ if (this.AmConnected)
+ {
+ this.DisconnectInternal(DisconnectReasons.Destroy, null);
+ }
+ }
+
+ public IEnumerator CoConnect()
+ {
+ if (this.AmConnected)
+ {
+ yield break;
+ }
+ DestroyableSingleton<DisconnectPopup>.Instance.Close();
+ this.LastDisconnectReason = DisconnectReasons.ExitGame;
+ this.NetIdCnt = 1U;
+ this.DestroyedObjects.Clear();
+ if (this.Streams == null)
+ {
+ this.Streams = new MessageWriter[2];
+ for (int i = 0; i < this.Streams.Length; i++)
+ {
+ this.Streams[i] = MessageWriter.Get((SendOption)i);
+ }
+ }
+ for (int j = 0; j < this.Streams.Length; j++)
+ {
+ MessageWriter messageWriter = this.Streams[j];
+ messageWriter.Clear((SendOption)j);
+ messageWriter.StartMessage(5);
+ messageWriter.Write(this.GameId);
+ }
+ IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(this.networkAddress), this.networkPort);
+ this.connection = new UdpClientConnection(remoteEndPoint, IPMode.IPv4);
+ this.connection.KeepAliveInterval = 1500;
+ this.connection.DisconnectTimeout = 7500;
+ this.connection.ResendPingMultiplier = 2f;
+ this.connection.DataReceived += this.OnMessageReceived; // 注册到网络线程的消息处理函数
+ this.connection.Disconnected += this.OnDisconnect; // 连接断开时的回调函数
+ this.connection.ConnectAsync(this.GetConnectionData(), 5000);
+
+ yield return this.WaitWithTimeout(() => this.connection == null || this.connection.State == ConnectionState.Connected);
+
+ yield break;
+ }
+
+ private void Connection_DataReceivedRaw(byte[] data)
+ {
+ Debug.Log("Client Got: " + string.Join(" ", from b in data
+ select b.ToString()));
+ }
+
+ private void Connection_DataSentRaw(byte[] data, int length)
+ {
+ Debug.Log("Client Sent: " + string.Join(" ", (from b in data
+ select b.ToString()).ToArray<string>(), 0, length));
+ }
+
+ public void Connect(MatchMakerModes mode)
+ {
+ base.StartCoroutine(this.CoConnect(mode));
+ }
+
+ private IEnumerator CoConnect(MatchMakerModes mode)
+ {
+ if (this.mode != MatchMakerModes.None)
+ {
+ this.DisconnectInternal(DisconnectReasons.NewConnection, null);
+ }
+ this.mode = mode;
+ yield return this.CoConnect();
+ if (!this.AmConnected)
+ {
+ yield break;
+ }
+ MatchMakerModes matchMakerModes = this.mode;
+ if (matchMakerModes == MatchMakerModes.Client)
+ {
+ this.JoinGame();
+ yield return this.WaitWithTimeout(() => this.ClientId >= 0);
+ bool amConnected = this.AmConnected;
+ yield break;
+ }
+ if (matchMakerModes != MatchMakerModes.HostAndClient)
+ {
+ yield break;
+ }
+ this.GameId = 0;
+ PlayerControl.GameOptions = SaveManager.GameHostOptions;
+ this.HostGame(PlayerControl.GameOptions);
+ yield return this.WaitWithTimeout(() => this.GameId != 0);
+ if (!this.AmConnected)
+ {
+ yield break;
+ }
+ this.JoinGame();
+ yield return this.WaitWithTimeout(() => this.ClientId >= 0);
+ bool amConnected2 = this.AmConnected;
+ yield break;
+ }
+
+ public IEnumerator WaitForConnectionOrFail()
+ {
+ while (this.AmConnected)
+ {
+ switch (this.mode)
+ {
+ case MatchMakerModes.None:
+ goto IL_5F;
+ case MatchMakerModes.Client:
+ if (this.ClientId >= 0)
+ {
+ yield break;
+ }
+ break;
+ case MatchMakerModes.HostAndClient:
+ if (this.GameId != 0 && this.ClientId >= 0)
+ {
+ yield break;
+ }
+ break;
+ default:
+ goto IL_5F;
+ }
+ yield return null;
+ continue;
+ IL_5F:
+ yield break;
+ }
+ yield break;
+ }
+
+ private IEnumerator WaitWithTimeout(Func<bool> success)
+ {
+ bool failed = true;
+ for (float timer = 0f; timer < 5f; timer += Time.deltaTime)
+ {
+ if (success())
+ {
+ failed = false;
+ break;
+ }
+ if (!this.AmConnected)
+ {
+ yield break;
+ }
+ yield return null;
+ }
+ if (failed)
+ {
+ this.DisconnectInternal(DisconnectReasons.Error, null);
+ }
+ yield break;
+ }
+
+ //c 执行从网络线程收到的回调Dispatcher
+ public void Update()
+ {
+ if (Input.GetKeyDown(KeyCode.Return) && (Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt)))
+ {
+ ResolutionManager.ToggleFullscreen();
+ }
+ this.TempQueue.Clear();
+ List<Action> obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.TempQueue.AddAll(this.Dispatcher);
+ this.Dispatcher.Clear();
+ }
+ for (int i = 0; i < this.TempQueue.Count; i++)
+ {
+ Action action = this.TempQueue[i];
+ try
+ {
+ action();
+ }
+ catch (Exception exception)
+ {
+ Debug.LogException(exception);
+ }
+ }
+ if (this.InOnlineScene)
+ {
+ this.TempQueue.Clear();
+ obj = this.PreSpawnDispatcher;
+ lock (obj)
+ {
+ this.TempQueue.AddAll(this.PreSpawnDispatcher);
+ this.PreSpawnDispatcher.Clear();
+ }
+ for (int j = 0; j < this.TempQueue.Count; j++)
+ {
+ Action action2 = this.TempQueue[j];
+ try
+ {
+ action2();
+ }
+ catch (Exception exception2)
+ {
+ Debug.LogException(exception2);
+ }
+ }
+ }
+ }
+
+ private void OnDisconnect(object sender, DisconnectedEventArgs e)
+ {
+ if (!e.Reason.Contains("The remote sent a"))
+ {
+ this.LastCustomDisconnect = "You disconnected from the server.\r\n\r\n" + e.Reason;
+ this.EnqueueDisconnect(DisconnectReasons.Custom, e.Reason);
+ return;
+ }
+ this.EnqueueDisconnect(DisconnectReasons.Error, e.Reason);
+ }
+
+ public void HandleDisconnect(DisconnectReasons reason, string stringReason = null)
+ {
+ base.StopAllCoroutines();
+ DestroyableSingleton<Telemetry>.Instance.WriteDisconnect(this.LastDisconnectReason);
+ this.DisconnectInternal(reason, stringReason);
+ this.OnDisconnected();
+ }
+
+ protected void EnqueueDisconnect(DisconnectReasons reason, string stringReason = null)
+ {
+ UdpClientConnection udpClientConnection = this.connection;
+ List<Action> dispatcher = this.Dispatcher;
+ lock (dispatcher)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.HandleDisconnect(reason, stringReason);
+ });
+ }
+ }
+
+ protected void DisconnectInternal(DisconnectReasons reason, string stringReason = null)
+ {
+ if (reason != DisconnectReasons.NewConnection && reason != DisconnectReasons.FocusLostBackground)
+ {
+ this.LastDisconnectReason = reason;
+ if (reason != DisconnectReasons.ExitGame && DestroyableSingleton<DisconnectPopup>.InstanceExists)
+ {
+ DestroyableSingleton<DisconnectPopup>.Instance.Show();
+ }
+ }
+ if (this.mode == MatchMakerModes.HostAndClient)
+ {
+ this.GameId = 0;
+ }
+ if (this.mode == MatchMakerModes.Client || this.mode == MatchMakerModes.HostAndClient)
+ {
+ this.ClientId = -1;
+ }
+ this.mode = MatchMakerModes.None;
+ this.GameState = InnerNetClient.GameStates.NotJoined;
+ UdpClientConnection udpClientConnection = this.connection;
+ this.connection = null;
+ if (udpClientConnection != null)
+ {
+ try
+ {
+ udpClientConnection.Dispose();
+ }
+ catch (Exception exception)
+ {
+ Debug.LogException(exception);
+ }
+ }
+ if (DestroyableSingleton<InnerNetServer>.InstanceExists)
+ {
+ DestroyableSingleton<InnerNetServer>.Instance.StopServer();
+ }
+ List<Action> obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.Dispatcher.Clear();
+ }
+ obj = this.PreSpawnDispatcher;
+ lock (obj)
+ {
+ this.PreSpawnDispatcher.Clear();
+ }
+ if (reason != DisconnectReasons.Error)
+ {
+ this.TempQueue.Clear();
+ }
+ this.allObjects.Clear();
+ this.allClients.Clear();
+ this.allObjectsFast.Clear();
+ }
+
+ public void HostGame(IBytesSerializable settings)
+ {
+ this.IsGamePublic = false;
+ MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
+ messageWriter.StartMessage(0);
+ messageWriter.WriteBytesAndSize(settings.ToBytes());
+ messageWriter.EndMessage();
+ this.SendOrDisconnect(messageWriter);
+ messageWriter.Recycle();
+ Debug.Log("Client requesting new game.");
+ }
+
+ public void JoinGame()
+ {
+ this.ClientId = -1;
+ if (!this.AmConnected)
+ {
+ this.HandleDisconnect(DisconnectReasons.Error, null);
+ return;
+ }
+ Debug.Log("Client joining game: " + InnerNetClient.IntToGameName(this.GameId));
+ MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
+ messageWriter.StartMessage(1);
+ messageWriter.Write(this.GameId);
+ messageWriter.EndMessage();
+ this.SendOrDisconnect(messageWriter);
+ messageWriter.Recycle();
+ }
+
+ public bool CanBan()
+ {
+ return this.AmHost && !this.IsGameStarted;
+ }
+
+ public bool CanKick()
+ {
+ return this.IsGameStarted || this.AmHost;
+ }
+
+ public void KickPlayer(int clientId, bool ban)
+ {
+ if (!this.AmHost)
+ {
+ return;
+ }
+ MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
+ messageWriter.StartMessage(11);
+ messageWriter.Write(this.GameId);
+ messageWriter.WritePacked(clientId);
+ messageWriter.Write(ban);
+ messageWriter.EndMessage();
+ this.SendOrDisconnect(messageWriter);
+ messageWriter.Recycle();
+ }
+
+ public MessageWriter StartEndGame()
+ {
+ MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
+ messageWriter.StartMessage(8);
+ messageWriter.Write(this.GameId);
+ return messageWriter;
+ }
+
+ public void FinishEndGame(MessageWriter msg)
+ {
+ msg.EndMessage();
+ this.SendOrDisconnect(msg);
+ msg.Recycle();
+ }
+
+ protected void SendLateRejection(int targetId, DisconnectReasons reason)
+ {
+ MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
+ messageWriter.StartMessage(4);
+ messageWriter.Write(this.GameId);
+ messageWriter.WritePacked(targetId);
+ messageWriter.Write((byte)reason);
+ messageWriter.EndMessage();
+ this.SendOrDisconnect(messageWriter);
+ messageWriter.Recycle();
+ }
+
+ protected void SendClientReady()
+ {
+ if (!this.AmHost)
+ {
+ MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
+ messageWriter.StartMessage(5);
+ messageWriter.Write(this.GameId);
+ messageWriter.StartMessage(7);
+ messageWriter.WritePacked(this.ClientId);
+ messageWriter.EndMessage();
+ messageWriter.EndMessage();
+ this.SendOrDisconnect(messageWriter);
+ messageWriter.Recycle();
+ return;
+ }
+ ClientData clientData = this.FindClientById(this.ClientId);
+ if (clientData == null)
+ {
+ this.HandleDisconnect(DisconnectReasons.Error, "Couldn't find self as host");
+ return;
+ }
+ clientData.IsReady = true;
+ }
+
+ protected void SendStartGame()
+ {
+ MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
+ messageWriter.StartMessage(2);
+ messageWriter.Write(this.GameId);
+ messageWriter.EndMessage();
+ this.SendOrDisconnect(messageWriter);
+ messageWriter.Recycle();
+ }
+
+ public void RequestGameList(bool includePrivate, IBytesSerializable settings)
+ {
+ MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
+ messageWriter.StartMessage(9);
+ messageWriter.Write(includePrivate);
+ messageWriter.WriteBytesAndSize(settings.ToBytes());
+ messageWriter.EndMessage();
+ this.SendOrDisconnect(messageWriter);
+ messageWriter.Recycle();
+ }
+
+ public void ChangeGamePublic(bool isPublic)
+ {
+ if (this.AmHost)
+ {
+ MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
+ messageWriter.StartMessage(10);
+ messageWriter.Write(this.GameId);
+ messageWriter.Write(1);
+ messageWriter.Write(isPublic);
+ messageWriter.EndMessage();
+ this.SendOrDisconnect(messageWriter);
+ messageWriter.Recycle();
+ this.IsGamePublic = isPublic;
+ }
+ }
+
+ //c 收到数据,在网络线程
+ private void OnMessageReceived(DataReceivedEventArgs e)
+ {
+ MessageReader message = e.Message;
+ try
+ {
+ while (message.Position < message.Length)
+ {
+ this.HandleMessage(message.ReadMessage());
+ }
+ }
+ finally
+ {
+ message.Recycle();
+ }
+ }
+
+
+ //c 从imposter搞过来的
+ //c 后来发现Tags.cs里有
+ private static readonly Dictionary<byte, string> TagMap = new Dictionary<byte, string>
+ {
+ {0, "HostGame"},
+ {1, "JoinGame"},
+ {2, "StartGame"},
+ {3, "RemoveGame"},
+ {4, "RemovePlayer"},
+ {5, "GameData"},
+ {6, "GameDataTo"},
+ {7, "JoinedGame"},
+ {8, "EndGame"},
+ {9, "GetGameList"},
+ {10, "AlterGame"},
+ {11, "KickPlayer"},
+ {12, "WaitForHost"},
+ {13, "Redirect"},
+ {14, "ReselectServer"},
+ {16, "GetGameListV2"}
+ };
+
+
+ private enum TagAlias
+ {
+ HostGame = 0, // 创建
+ StartGame = 2, // 开始游戏
+ Disconnect = 3, // 断开
+ SubMessage = 6, //
+ JoinGame = 7, // 加入游戏
+ Gameover = 8, // 游戏结束
+ }
+
+ //c 处理收到的数据
+ private void HandleMessage(MessageReader reader)
+ {
+ List<Action> obj;
+ switch (reader.Tag)
+ {
+ case (int)TagAlias.HostGame:
+ this.GameId = reader.ReadInt32();
+ Debug.Log("Client hosting game: " + InnerNetClient.IntToGameName(this.GameId));
+ obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.OnGameCreated(InnerNetClient.IntToGameName(this.GameId));
+ });
+ return;
+ }
+ break;
+ case 1:
+ goto IL_2F5;
+ case (int)TagAlias.StartGame:
+ this.GameState = InnerNetClient.GameStates.Started;
+ obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.OnStartGame();
+ });
+ return;
+ }
+ goto IL_675;
+ case (int)TagAlias.Disconnect:
+ {
+ DisconnectReasons reason3 = DisconnectReasons.ServerRequest;
+ if (reader.Position < reader.Length)
+ {
+ reason3 = (DisconnectReasons)reader.ReadByte();
+ }
+ this.EnqueueDisconnect(reason3, null);
+ return;
+ }
+ case 4:
+ break;
+ case 5:
+ case (int)TagAlias.SubMessage: // 把这类消息存在队列里,主线程后续调用
+ {
+ int num = reader.ReadInt32();
+ if (this.GameId == num)
+ {
+ if (reader.Tag == 6)
+ {
+ int num2 = reader.ReadPackedInt32();
+ if (this.ClientId != num2)
+ {
+ Debug.LogWarning(string.Format("Got data meant for {0}", num2));
+ return;
+ }
+ }
+ MessageReader subReader;
+ if (this.InOnlineScene)
+ {
+ subReader = MessageReader.Get(reader);
+ obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.HandleGameData(subReader, 0); // 在主线程调用
+ });
+ return;
+ }
+ }
+ Debug.Log("Stored early game data");
+ subReader = MessageReader.Get(reader);
+ obj = this.PreSpawnDispatcher;
+ lock (obj)
+ {
+ this.PreSpawnDispatcher.Add(delegate
+ {
+ this.HandleGameData(subReader, 0); // 在主线程调用
+ });
+ return;
+ }
+ goto IL_517;
+ }
+ return;
+ }
+ case (int)TagAlias.JoinGame:
+ goto IL_235;
+ case (int)TagAlias.Gameover:
+ {
+ int num3 = reader.ReadInt32();
+ if (this.GameId == num3 && this.GameState != InnerNetClient.GameStates.Ended)
+ {
+ this.GameState = InnerNetClient.GameStates.Ended;
+ List<ClientData> obj2 = this.allClients;
+ lock (obj2)
+ {
+ this.allClients.Clear();
+ }
+ GameOverReason reason = (GameOverReason)reader.ReadByte();
+ bool showAd = reader.ReadBoolean();
+ obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.OnGameEnd(reason, showAd);
+ });
+ return;
+ }
+ goto IL_1DD;
+ }
+ return;
+ }
+ case 9:
+ goto IL_517;
+ case 10:
+ goto IL_5BC;
+ case 11:
+ goto IL_675;
+ case 12:
+ goto IL_1DD;
+ case 13:
+ {
+ uint address = reader.ReadUInt32();
+ ushort port = reader.ReadUInt16();
+ AmongUsClient.Instance.SetEndpoint(InnerNetClient.AddressToString(address), port);
+ obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ Debug.Log(string.Format("Redirected to: {0}:{1}", this.networkAddress, this.networkPort));
+ base.StopAllCoroutines();
+ this.Connect(this.mode);
+ });
+ return;
+ }
+ goto IL_70A;
+ }
+ default:
+ goto IL_70A;
+ }
+ int num4 = reader.ReadInt32();
+ if (this.GameId == num4)
+ {
+ int playerIdThatLeft = reader.ReadInt32();
+ int hostId = reader.ReadInt32();
+ DisconnectReasons reason2 = (DisconnectReasons)reader.ReadByte();
+ if (!this.AmHost)
+ {
+ this.HostId = hostId;
+ if (this.AmHost)
+ {
+ obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.OnBecomeHost();
+ });
+ }
+ }
+ }
+ this.RemovePlayer(playerIdThatLeft, reason2);
+ return;
+ }
+ return;
+ IL_1DD:
+ int num5 = reader.ReadInt32();
+ if (this.GameId != num5)
+ {
+ return;
+ }
+ this.ClientId = reader.ReadInt32();
+ obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.OnWaitForHost(InnerNetClient.IntToGameName(this.GameId));
+ });
+ return;
+ }
+ IL_235:
+ int num6 = reader.ReadInt32();
+ if (this.GameId != num6 || this.GameState == InnerNetClient.GameStates.Joined)
+ {
+ return;
+ }
+ this.GameState = InnerNetClient.GameStates.Joined;
+ this.ClientId = reader.ReadInt32();
+ ClientData myClient = this.GetOrCreateClient(this.ClientId);
+ this.HostId = reader.ReadInt32();
+ int num7 = reader.ReadPackedInt32();
+ for (int i = 0; i < num7; i++)
+ {
+ this.GetOrCreateClient(reader.ReadPackedInt32());
+ }
+ obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.OnGameJoined(InnerNetClient.IntToGameName(this.GameId), myClient);
+ });
+ return;
+ }
+ IL_2F5:
+ int num8 = reader.ReadInt32();
+ DisconnectReasons disconnectReasons = (DisconnectReasons)num8;
+ if (InnerNetClient.disconnectReasons.Contains(disconnectReasons))
+ {
+ if (disconnectReasons == DisconnectReasons.Custom)
+ {
+ this.LastCustomDisconnect = reader.ReadString();
+ }
+ this.GameId = -1;
+ this.EnqueueDisconnect(disconnectReasons, null);
+ return;
+ }
+ if (this.GameId == num8)
+ {
+ int num9 = reader.ReadInt32();
+ bool amHost = this.AmHost;
+ this.HostId = reader.ReadInt32();
+ ClientData client = this.GetOrCreateClient(num9);
+ Debug.Log(string.Format("Player {0} joined", num9));
+ obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.OnPlayerJoined(client);
+ });
+ }
+ if (!this.AmHost || amHost)
+ {
+ return;
+ }
+ obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.OnBecomeHost();
+ });
+ return;
+ }
+ }
+ this.EnqueueDisconnect(DisconnectReasons.IncorrectGame, null);
+ return;
+ IL_517:
+ int totalGames = reader.ReadPackedInt32();
+ List<GameListing> output = new List<GameListing>();
+ while (reader.Position < reader.Length)
+ {
+ output.Add(new GameListing(reader.ReadInt32(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadPackedInt32(), reader.ReadString()));
+ }
+ obj = this.Dispatcher;
+ lock (obj)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.OnGetGameList(totalGames, output);
+ });
+ return;
+ }
+ IL_5BC:
+ int num10 = reader.ReadInt32();
+ if (this.GameId != num10)
+ {
+ return;
+ }
+ byte b = reader.ReadByte();
+ if (b == 1)
+ {
+ this.IsGamePublic = reader.ReadBoolean();
+ string str = "Alter Public = ";
+ bool flag = this.IsGamePublic;
+ Debug.Log(str + flag.ToString());
+ return;
+ }
+ Debug.Log("Alter unknown");
+ return;
+ IL_675:
+ int num11 = reader.ReadInt32();
+ if (this.GameId == num11 && reader.ReadPackedInt32() == this.ClientId)
+ {
+ this.EnqueueDisconnect(reader.ReadBoolean() ? DisconnectReasons.Banned : DisconnectReasons.Kicked, null);
+ return;
+ }
+ return;
+ IL_70A:
+ Debug.Log(string.Format("Bad tag {0} at {1}+{2}={3}: ", new object[]
+ {
+ reader.Tag,
+ reader.Offset,
+ reader.Position,
+ reader.Length
+ }) + string.Join<byte>(" ", reader.Buffer));
+ }
+
+ private static string AddressToString(uint address)
+ {
+ return string.Format("{0}.{1}.{2}.{3}", new object[]
+ {
+ (byte)address,
+ (byte)(address >> 8),
+ (byte)(address >> 16),
+ (byte)(address >> 24)
+ });
+ }
+
+ private ClientData GetOrCreateClient(int clientId)
+ {
+ List<ClientData> obj = this.allClients;
+ ClientData clientData;
+ lock (obj)
+ {
+ clientData = this.allClients.FirstOrDefault((ClientData c) => c.Id == clientId);
+ if (clientData == null)
+ {
+ clientData = new ClientData(clientId);
+ this.allClients.Add(clientData);
+ }
+ }
+ return clientData;
+ }
+
+ private void RemovePlayer(int playerIdThatLeft, DisconnectReasons reason)
+ {
+ ClientData client = null;
+ List<ClientData> obj = this.allClients;
+ lock (obj)
+ {
+ for (int i = 0; i < this.allClients.Count; i++)
+ {
+ ClientData clientData = this.allClients[i];
+ if (clientData.Id == playerIdThatLeft)
+ {
+ client = clientData;
+ this.allClients.RemoveAt(i);
+ break;
+ }
+ }
+ }
+ if (client != null)
+ {
+ List<Action> dispatcher = this.Dispatcher;
+ lock (dispatcher)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.OnPlayerLeft(client, reason);
+ });
+ }
+ }
+ }
+
+ protected virtual void OnApplicationPause(bool pause)
+ {
+ this.appPaused = pause;
+ if (!pause)
+ {
+ Debug.Log("Resumed Game");
+ if (this.AmHost)
+ {
+ this.RemoveUnownedObjects();
+ return;
+ }
+ }
+ else if (this.GameState != InnerNetClient.GameStates.Ended && this.AmConnected)
+ {
+ Debug.Log("Lost focus during game");
+ ThreadPool.QueueUserWorkItem(new WaitCallback(this.WaitToDisconnect));
+ }
+ }
+
+ private void WaitToDisconnect(object state)
+ {
+ int num = 0;
+ while (num < 10 && this.appPaused)
+ {
+ Thread.Sleep(1000);
+ num++;
+ }
+ if (this.appPaused && this.GameState != InnerNetClient.GameStates.Ended && this.AmConnected)
+ {
+ this.DisconnectInternal(DisconnectReasons.FocusLostBackground, null);
+ this.EnqueueDisconnect(DisconnectReasons.FocusLost, null);
+ }
+ }
+
+ protected void SendInitialData(int clientId)
+ {
+ MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
+ messageWriter.StartMessage(6);
+ messageWriter.Write(this.GameId);
+ messageWriter.WritePacked(clientId);
+ List<InnerNetObject> obj = this.allObjects;
+ lock (obj)
+ {
+ HashSet<GameObject> hashSet = new HashSet<GameObject>();
+ for (int i = 0; i < this.allObjects.Count; i++)
+ {
+ InnerNetObject innerNetObject = this.allObjects[i];
+ if (innerNetObject && hashSet.Add(innerNetObject.gameObject))
+ {
+ this.WriteSpawnMessage(innerNetObject, innerNetObject.OwnerId, innerNetObject.SpawnFlags, messageWriter);
+ }
+ }
+ }
+ messageWriter.EndMessage();
+ this.SendOrDisconnect(messageWriter);
+ messageWriter.Recycle();
+ }
+
+ protected abstract void OnGameCreated(string gameIdString);
+
+ protected abstract void OnGameJoined(string gameIdString, ClientData client);
+
+ protected abstract void OnWaitForHost(string gameIdString);
+
+ protected abstract void OnStartGame();
+
+ protected abstract void OnGameEnd(GameOverReason reason, bool showAd);
+
+ protected abstract void OnBecomeHost();
+
+ protected abstract void OnPlayerJoined(ClientData client);
+
+ protected abstract void OnPlayerChangedScene(ClientData client, string targetScene);
+
+ protected abstract void OnPlayerLeft(ClientData client, DisconnectReasons reason);
+
+ protected abstract void OnDisconnected();
+
+ protected abstract void OnGetGameList(int totalGames, List<GameListing> availableGames);
+
+ protected abstract byte[] GetConnectionData();
+
+ protected ClientData FindClientById(int id)
+ {
+ if (id < 0)
+ {
+ return null;
+ }
+ List<ClientData> obj = this.allClients;
+ ClientData result;
+ lock (obj)
+ {
+ for (int i = 0; i < this.allClients.Count; i++)
+ {
+ ClientData clientData = this.allClients[i];
+ if (clientData.Id == id)
+ {
+ return clientData;
+ }
+ }
+ result = null;
+ }
+ return result;
+ }
+
+ public static string IntToGameName(int gameId)
+ {
+ char[] array = new char[]
+ {
+ (char)(gameId & 255),
+ (char)(gameId >> 8 & 255),
+ (char)(gameId >> 16 & 255),
+ (char)(gameId >> 24 & 255)
+ };
+ if (array.Any((char c) => c < 'A' || c > 'z'))
+ {
+ return null;
+ }
+ return new string(array);
+ }
+
+ public static int GameNameToInt(string gameId)
+ {
+ if (gameId.Length != 4)
+ {
+ return -1;
+ }
+ gameId = gameId.ToUpperInvariant();
+ return (int)(gameId[0] | (int)gameId[1] << 8 | (int)gameId[2] << 16 | (int)gameId[3] << 24);
+ }
+
+ private void FixedUpdate()
+ {
+ if (this.mode == MatchMakerModes.None || this.Streams == null)
+ {
+ this.timer = 0f;
+ return;
+ }
+ this.timer += Time.fixedDeltaTime;
+ if (this.timer < this.MinSendInterval)
+ {
+ return;
+ }
+ this.timer = 0f;
+
+ //c 写入所有场景内包含InnerNetObject派生类的数据
+ List<InnerNetObject> obj = this.allObjects;
+ lock (obj)
+ {
+ for (int i = 0; i < this.allObjects.Count; i++)
+ {
+ InnerNetObject innerNetObject = this.allObjects[i];
+ if (innerNetObject && innerNetObject.DirtyBits != 0U && (innerNetObject.AmOwner || (innerNetObject.OwnerId == -2 && this.AmHost)))
+ {
+ MessageWriter messageWriter = this.Streams[(int)innerNetObject.sendMode];
+ messageWriter.StartMessage(1);
+ messageWriter.WritePacked(innerNetObject.NetId);
+ if (innerNetObject.Serialize(messageWriter, false))
+ {
+ messageWriter.EndMessage();
+ }
+ else
+ {
+ messageWriter.CancelMessage();
+ }
+ }
+ }
+ }
+
+ for (int j = 0; j < this.Streams.Length; j++)
+ {
+ MessageWriter messageWriter2 = this.Streams[j];
+ if (messageWriter2.HasBytes(7))
+ {
+ messageWriter2.EndMessage();
+ this.SendOrDisconnect(messageWriter2);
+ messageWriter2.Clear((SendOption)j);
+ messageWriter2.StartMessage(5);
+ messageWriter2.Write(this.GameId);
+ }
+ }
+ }
+
+ public T FindObjectByNetId<T>(uint netId) where T : InnerNetObject
+ {
+ InnerNetObject innerNetObject;
+ if (this.allObjectsFast.TryGetValue(netId, out innerNetObject))
+ {
+ return (T)((object)innerNetObject);
+ }
+ return default(T);
+ }
+
+ public void SendRpcImmediately(uint targetNetId, byte callId, SendOption option)
+ {
+ MessageWriter messageWriter = MessageWriter.Get(option);
+ messageWriter.StartMessage(5);
+ messageWriter.Write(this.GameId);
+ messageWriter.StartMessage(2);
+ messageWriter.WritePacked(targetNetId);
+ messageWriter.Write(callId);
+ messageWriter.EndMessage();
+ messageWriter.EndMessage();
+ this.connection.Send(messageWriter);
+ messageWriter.Recycle();
+ }
+
+ public MessageWriter StartRpcImmediately(uint targetNetId, byte callId, SendOption option, int targetClientId = -1)
+ {
+ MessageWriter messageWriter = MessageWriter.Get(option);
+ if (targetClientId < 0)
+ {
+ messageWriter.StartMessage(5);
+ messageWriter.Write(this.GameId);
+ }
+ else
+ {
+ messageWriter.StartMessage(6);
+ messageWriter.Write(this.GameId);
+ messageWriter.WritePacked(targetClientId);
+ }
+ messageWriter.StartMessage(2);
+ messageWriter.WritePacked(targetNetId);
+ messageWriter.Write(callId);
+ return messageWriter;
+ }
+
+ public void FinishRpcImmediately(MessageWriter msg)
+ {
+ msg.EndMessage();
+ msg.EndMessage();
+ this.SendOrDisconnect(msg);
+ msg.Recycle();
+ }
+
+ public void SendRpc(uint targetNetId, byte callId, SendOption option = SendOption.Reliable)
+ {
+ this.StartRpc(targetNetId, callId, option).EndMessage();
+ }
+
+ public MessageWriter StartRpc(uint targetNetId, byte callId, SendOption option = SendOption.Reliable)
+ {
+ MessageWriter messageWriter = this.Streams[(int)option];
+ messageWriter.StartMessage(2);
+ messageWriter.WritePacked(targetNetId);
+ messageWriter.Write(callId);
+ return messageWriter;
+ }
+
+ private void SendSceneChange(string sceneName)
+ {
+ this.InOnlineScene = string.Equals(sceneName, "OnlineGame");
+ if (!this.AmConnected)
+ {
+ return;
+ }
+ Debug.Log("Changed To " + sceneName);
+ base.StartCoroutine(this.CoSendSceneChange(sceneName));
+ }
+
+ private IEnumerator CoSendSceneChange(string sceneName)
+ {
+ List<InnerNetObject> obj = this.allObjects;
+ lock (obj)
+ {
+ for (int i = this.allObjects.Count - 1; i > -1; i--)
+ {
+ if (!this.allObjects[i])
+ {
+ this.allObjects.RemoveAt(i);
+ }
+ }
+ goto IL_BF;
+ }
+ IL_A8:
+ yield return null;
+ IL_BF:
+ if (this.AmConnected && this.ClientId < 0)
+ {
+ goto IL_A8;
+ }
+ if (!this.AmConnected)
+ {
+ yield break;
+ }
+ if (!this.AmHost && this.connection.State == ConnectionState.Connected)
+ {
+ MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
+ messageWriter.StartMessage(5);
+ messageWriter.Write(this.GameId);
+ messageWriter.StartMessage(6);
+ messageWriter.WritePacked(this.ClientId);
+ messageWriter.Write(sceneName);
+ messageWriter.EndMessage();
+ messageWriter.EndMessage();
+ this.SendOrDisconnect(messageWriter);
+ messageWriter.Recycle();
+ }
+ ClientData client = this.FindClientById(this.ClientId);
+ if (client != null)
+ {
+ Debug.Log(string.Format("Self changed scene: {0} {1}", this.ClientId, sceneName));
+ List<Action> dispatcher = this.Dispatcher;
+ lock (dispatcher)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ this.OnPlayerChangedScene(client, sceneName);
+ });
+ yield break;
+ }
+ }
+ Debug.Log(string.Format("Couldn't find self in clients: {0}: ", this.ClientId) + sceneName);
+ yield break;
+ }
+
+ public void Spawn(InnerNetObject netObjParent, int ownerId = -2, SpawnFlags flags = SpawnFlags.None)
+ {
+ if (this.AmHost)
+ {
+ ownerId = ((ownerId == -3) ? this.ClientId : ownerId);
+ MessageWriter msg = this.Streams[1];
+ this.WriteSpawnMessage(netObjParent, ownerId, flags, msg);
+ return;
+ }
+ if (!this.AmClient)
+ {
+ return;
+ }
+ Debug.LogError("Tried to spawn while not host:" + netObjParent);
+ }
+
+ private void WriteSpawnMessage(InnerNetObject netObjParent, int ownerId, SpawnFlags flags, MessageWriter msg)
+ {
+ msg.StartMessage(4);
+ msg.WritePacked(netObjParent.SpawnId);
+ msg.WritePacked(ownerId);
+ msg.Write((byte)flags);
+ InnerNetObject[] componentsInChildren = netObjParent.GetComponentsInChildren<InnerNetObject>();
+ msg.WritePacked(componentsInChildren.Length);
+ foreach (InnerNetObject innerNetObject in componentsInChildren)
+ {
+ innerNetObject.OwnerId = ownerId;
+ innerNetObject.SpawnFlags = flags;
+ if (innerNetObject.NetId == 0U)
+ {
+ InnerNetObject innerNetObject2 = innerNetObject;
+ uint netIdCnt = this.NetIdCnt;
+ this.NetIdCnt = netIdCnt + 1U;
+ innerNetObject2.NetId = netIdCnt;
+ this.allObjects.Add(innerNetObject);
+ this.allObjectsFast.Add(innerNetObject.NetId, innerNetObject);
+ }
+ msg.WritePacked(innerNetObject.NetId);
+ msg.StartMessage(1);
+ innerNetObject.Serialize(msg, true);
+ msg.EndMessage();
+ }
+ msg.EndMessage();
+ }
+
+ public void Despawn(InnerNetObject objToDespawn)
+ {
+ if (objToDespawn.NetId < 1U)
+ {
+ Debug.LogError("Tried to net destroy: " + objToDespawn);
+ return;
+ }
+ MessageWriter messageWriter = this.Streams[1];
+ messageWriter.StartMessage(5);
+ messageWriter.WritePacked(objToDespawn.NetId);
+ messageWriter.EndMessage();
+ this.RemoveNetObject(objToDespawn);
+ }
+
+ private bool AddNetObject(InnerNetObject obj)
+ {
+ uint num = obj.NetId + 1U;
+ if (num > this.NetIdCnt)
+ {
+ this.NetIdCnt = num;
+ }
+ if (!this.allObjectsFast.ContainsKey(obj.NetId))
+ {
+ this.allObjects.Add(obj);
+ this.allObjectsFast.Add(obj.NetId, obj);
+ return true;
+ }
+ return false;
+ }
+
+ public void RemoveNetObject(InnerNetObject obj)
+ {
+ int num = this.allObjects.IndexOf(obj);
+ if (num > -1)
+ {
+ this.allObjects.RemoveAt(num);
+ }
+ this.allObjectsFast.Remove(obj.NetId);
+ obj.NetId = uint.MaxValue;
+ }
+
+ public void RemoveUnownedObjects()
+ {
+ HashSet<int> hashSet = new HashSet<int>();
+ hashSet.Add(-2);
+ List<ClientData> obj = this.allClients;
+ lock (obj)
+ {
+ for (int i = 0; i < this.allClients.Count; i++)
+ {
+ ClientData clientData = this.allClients[i];
+ if (clientData.Character)
+ {
+ hashSet.Add(clientData.Id);
+ }
+ }
+ }
+ List<InnerNetObject> obj2 = this.allObjects;
+ lock (obj2)
+ {
+ for (int j = this.allObjects.Count - 1; j > -1; j--)
+ {
+ InnerNetObject innerNetObject = this.allObjects[j];
+ if (!innerNetObject)
+ {
+ this.allObjects.RemoveAt(j);
+ }
+ else if (!hashSet.Contains(innerNetObject.OwnerId))
+ {
+ innerNetObject.OwnerId = this.ClientId;
+ UnityEngine.Object.Destroy(innerNetObject.gameObject);
+ }
+ }
+ }
+ }
+
+ private void HandleGameData(MessageReader parentReader, int cnt = 0)
+ {
+ try
+ {
+ while (parentReader.Position < parentReader.Length)
+ {
+ this.HandleGameDataInner(parentReader.ReadMessage(), cnt);
+ }
+ }
+ finally
+ {
+ parentReader.Recycle();
+ }
+ }
+
+ //c 辅助tag别名
+ private enum SubTagAlias
+ {
+ Normal = 1, // 游戏内的简单数据,比如同步角色位置、动画等
+ Rpc = 2, // 远程调用Remote Procedure Call
+ SpawnCharacter = 4, // 生成角色
+ RemoveNetObjectByNetId = 5, // 删除数据
+ ChangeScene = 6, // 切换场景
+ PlayerReady = 7, // 角色准备好了
+ }
+
+ //c 处理收到的数据,用来同步
+ //c 这个方法是在主线程调用的
+ private void HandleGameDataInner(MessageReader reader, int cnt)
+ {
+ switch (reader.Tag)
+ {
+ case (int)SubTagAlias.Normal:
+ {
+ uint num = reader.ReadPackedUInt32();
+ InnerNetObject innerNetObject;
+ if (this.allObjectsFast.TryGetValue(num, out innerNetObject))
+ {
+ innerNetObject.Deserialize(reader, false);
+ return;
+ }
+ if (!this.DestroyedObjects.Contains(num))
+ {
+ this.DeferMessage(cnt, reader, "Stored data for " + num);
+ return;
+ }
+ return;
+ }
+ case (int)SubTagAlias.Rpc:
+ {
+ // 根据编号找到对应的同步数据
+ uint index = reader.ReadPackedUInt32();
+ InnerNetObject innerNetObject2;
+ if (this.allObjectsFast.TryGetValue(index, out innerNetObject2))
+ {
+ byte callId = reader.ReadByte();
+ innerNetObject2.HandleRpc(callId, reader);
+ return;
+ }
+ if (!this.DestroyedObjects.Contains(index))
+ {
+ this.DeferMessage(cnt, reader, "Stored RPC for " + index);
+ return;
+ }
+ return;
+ }
+ case (int)SubTagAlias.SpawnCharacter:
+ {
+ uint num3 = reader.ReadPackedUInt32();
+ if ((ulong)num3 >= (ulong)((long)this.SpawnableObjects.Length))
+ {
+ Debug.LogError("Couldn't find spawnable prefab: " + num3);
+ return;
+ }
+ int num4 = reader.ReadPackedInt32();
+ ClientData clientData = this.FindClientById(num4);
+ if (num4 > 0 && clientData == null)
+ {
+ this.DeferMessage(cnt, reader, "Delay spawn for unowned " + num3);
+ return;
+ }
+ // 创建角色对象并设置参数
+ InnerNetObject innerNetObject3 = UnityEngine.Object.Instantiate<InnerNetObject>(this.SpawnableObjects[(int)num3]);
+ innerNetObject3.SpawnFlags = (SpawnFlags)reader.ReadByte();
+ if ((innerNetObject3.SpawnFlags & SpawnFlags.IsClientCharacter) != SpawnFlags.None)
+ {
+ if (!clientData.Character)
+ {
+ clientData.InScene = true;
+ clientData.Character = (innerNetObject3 as PlayerControl);
+ }
+ else if (innerNetObject3)
+ {
+ Debug.LogWarning(string.Format("Double spawn character: {0} already has {1}", clientData.Id, clientData.Character.NetId));
+ UnityEngine.Object.Destroy(innerNetObject3.gameObject);
+ return;
+ }
+ }
+ int num5 = reader.ReadPackedInt32();
+ InnerNetObject[] componentsInChildren = innerNetObject3.GetComponentsInChildren<InnerNetObject>();
+ if (num5 != componentsInChildren.Length)
+ {
+ Debug.LogError("Children didn't match for spawnable " + num3);
+ UnityEngine.Object.Destroy(innerNetObject3.gameObject);
+ return;
+ }
+ for (int i = 0; i < num5; i++)
+ {
+ InnerNetObject innerNetObject4 = componentsInChildren[i];
+ innerNetObject4.NetId = reader.ReadPackedUInt32();
+ innerNetObject4.OwnerId = num4;
+ if (this.DestroyedObjects.Contains(innerNetObject4.NetId))
+ {
+ innerNetObject3.NetId = uint.MaxValue;
+ UnityEngine.Object.Destroy(innerNetObject3.gameObject);
+ return;
+ }
+ if (!this.AddNetObject(innerNetObject4))
+ {
+ innerNetObject3.NetId = uint.MaxValue;
+ UnityEngine.Object.Destroy(innerNetObject3.gameObject);
+ return;
+ }
+ MessageReader messageReader = reader.ReadMessage();
+ if (messageReader.Length > 0)
+ {
+ innerNetObject4.Deserialize(messageReader, true);
+ }
+ }
+ return;
+ }
+ case (int)SubTagAlias.RemoveNetObjectByNetId:
+ {
+ uint netId = reader.ReadPackedUInt32();
+ this.DestroyedObjects.Add(netId);
+ InnerNetObject innerNetObject5 = this.FindObjectByNetId<InnerNetObject>(netId);
+ if (innerNetObject5)
+ {
+ this.RemoveNetObject(innerNetObject5);
+ UnityEngine.Object.Destroy(innerNetObject5.gameObject);
+ return;
+ }
+ return;
+ }
+ case (int)SubTagAlias.ChangeScene:
+ {
+ int id = reader.ReadPackedInt32();
+ ClientData client = this.FindClientById(id); // 找到对应的玩家
+ string targetScene = reader.ReadString();
+ if (client != null && !string.IsNullOrWhiteSpace(targetScene))
+ {
+ Debug.Log(string.Format("Client {0} changed scene to {1}", client.Id, targetScene));
+ List<Action> dispatcher = this.Dispatcher;
+ lock (dispatcher)
+ {
+ this.Dispatcher.Add(delegate
+ {
+ // 切换场景
+ this.OnPlayerChangedScene(client, targetScene);
+ });
+ return;
+ }
+ }
+ Debug.Log(string.Format("Couldn't find client {0} to change scene to {1}", id, targetScene));
+ return;
+ }
+ case (int)SubTagAlias.PlayerReady:
+ {
+ ClientData clientData2 = this.FindClientById(reader.ReadPackedInt32());
+ if (clientData2 != null)
+ {
+ Debug.Log(string.Format("Client {0} ready", clientData2.Id));
+ clientData2.IsReady = true;
+ return;
+ }
+ return;
+ }
+ }
+
+ Debug.Log(string.Format("Bad tag {0} at {1}+{2}={3}: ", new object[]
+ {
+ reader.Tag,
+ reader.Offset,
+ reader.Position,
+ reader.Length
+ }) + string.Join<byte>(" ", reader.Buffer));
+ }
+
+ private void DeferMessage(int cnt, MessageReader reader, string logMsg)
+ {
+ if (cnt > 10)
+ {
+ Debug.Log("Giving up on: " + logMsg);
+ return;
+ }
+ int cnt2 = cnt;
+ cnt = cnt2 + 1;
+ Debug.Log(logMsg);
+ MessageReader copy = MessageReader.CopyMessageIntoParent(reader);
+ List<Action> preSpawnDispatcher = this.PreSpawnDispatcher;
+ lock (preSpawnDispatcher)
+ {
+ this.PreSpawnDispatcher.Add(delegate
+ {
+ this.HandleGameData(copy, cnt);
+ });
+ }
+ }
+ }
+}