/// <summary> /// Keep receiving incoming packets. /// </summary> void Update() { Buffer buffer; bool changed = false; long time = System.DateTime.UtcNow.Ticks / 10000; // Automatically try to connect and reconnect if not connected if (mRemoteAddress != null && mTcp.stage == TcpProtocol.Stage.NotConnected && mNextConnect < time) { mNextConnect = time + 5000; mTcp.Connect(mRemoteAddress); } // TCP-based lobby while (mTcp.ReceivePacket(out buffer)) { if (buffer.size > 0) { try { BinaryReader reader = buffer.BeginReading(); Packet response = (Packet)reader.ReadByte(); if (response == Packet.ResponseID) { if (mTcp.VerifyResponseID(response, reader)) { isActive = true; // Request the server list -- with TCP this only needs to be done once mTcp.BeginSend(Packet.RequestServerList).Write(GameServer.gameID); mTcp.EndSend(); } } else if (response == Packet.Disconnect) { knownServers.Clear(); isActive = false; changed = true; errorString = ""; } else if (response == Packet.ResponseServerList) { lock (knownServers.list) knownServers.list.Clear(); knownServers.ReadFrom(reader, time); changed = true; errorString = ""; } else if (response == Packet.Error) { errorString = reader.ReadString(); Debug.LogWarning(errorString); changed = true; } } catch (System.Exception ex) { errorString = ex.Message; Debug.LogWarning(ex.Message); mTcp.Close(false); } } buffer.Recycle(); } // Trigger the listener callback if (changed && onChange != null) { onChange(); } }
/// <summary> /// Send periodic updates. /// </summary> void ThreadFunction() { mInternal = new IPEndPoint(Tools.localAddress, mGameServer.tcpPort); mExternal = new IPEndPoint(Tools.externalAddress, mGameServer.tcpPort); for (; ;) { long time = DateTime.UtcNow.Ticks / 10000; if (mShutdown) { mTcp.Disconnect(); mThread = null; #if STANDALONE Tools.Print("TcpLobbyLink shut down"); #endif break; } #if !STANDALONE if (TNManager.isPaused) { Thread.Sleep(500); continue; } #endif Buffer buffer; // Try to establish a connection if (mGameServer != null && !mTcp.isConnected && !mTcp.isTryingToConnect && mNextConnect < time) { #if STANDALONE Tools.Print("TcpLobbyLink is connecting to " + mRemoteAddress + "..."); #endif mUpdateNeeded = true; mNextConnect = time + 15000; mTcp.Connect(mRemoteAddress); } while (mTcp.ReceivePacket(out buffer)) { BinaryReader reader = buffer.BeginReading(); Packet response = (Packet)reader.ReadByte(); if (mTcp.stage == TcpProtocol.Stage.Verifying) { if (mTcp.VerifyResponseID(response, reader)) { mTimeDifference = reader.ReadInt64() - (System.DateTime.UtcNow.Ticks / 10000); mWasConnected = true; #if STANDALONE Tools.Print("TcpLobbyLink connection established"); #endif } else { #if STANDALONE Tools.Print("TcpLobbyLink Error: Protocol version mismatch"); #endif mThread = null; return; } } else if (response == Packet.RequestPing) { } #if STANDALONE else if (response == Packet.Error) { Tools.Print("TcpLobbyLink Error: " + reader.ReadString()); } else if (response == Packet.Disconnect) { Tools.Print("TcpLobbyLink disconnected"); } else { Tools.Print("TcpLobbyLink can't handle this packet: " + response); } #endif buffer.Recycle(); } // Automatically try to re-establish a connection on disconnect if (mWasConnected && !mTcp.isConnected && !mTcp.isTryingToConnect) { mNextConnect = time + 5000; mWasConnected = false; } else if (mGameServer != null && mTcp.isConnected && (mUpdateNeeded || mNextSend < time)) { mUpdateNeeded = false; mNextSend = time + 5000; Buffer buff = Buffer.Create(); BinaryWriter writer = buff.BeginPacket(Packet.RequestAddServer); writer.Write(GameServer.gameID); writer.Write(mGameServer.name); writer.Write((short)mGameServer.playerCount); Tools.Serialize(writer, mInternal); Tools.Serialize(writer, mExternal); buff.EndPacket(); mTcp.SendTcpPacket(buff); buff.Recycle(); } try { Thread.Sleep(10); } catch (System.Threading.ThreadInterruptedException) { return; } } }
/// <summary> /// Process a single incoming packet. Returns whether we should keep processing packets or not. /// </summary> bool ProcessPacket(Buffer buffer, IPEndPoint ip) { mPacketSource = ip; BinaryReader reader = buffer.BeginReading(); if (buffer.size == 0) { return(true); } int packetID = reader.ReadByte(); Packet response = (Packet)packetID; // Verification step must be passed first if (response == Packet.ResponseID || mTcp.stage == TcpProtocol.Stage.Verifying) { if (mTcp.VerifyResponseID(response, reader)) { mTimeDifference = reader.ReadInt64() - (System.DateTime.UtcNow.Ticks / 10000); #if !UNITY_WEBPLAYER if (mUdp.isActive) { // If we have a UDP listener active, tell the server BeginSend(Packet.RequestSetUDP).Write((ushort)mUdp.listeningPort); EndSend(); } #endif mCanPing = true; if (onConnect != null) { onConnect(true, null); } } return(true); } //#if !UNITY_EDITOR // DEBUG // if (response != Packet.ResponsePing) Console.WriteLine("Client: " + response + " " + buffer.position + " of " + buffer.size + ((ip == null) ? " (TCP)" : " (UDP)")); //#else // if (response != Packet.ResponsePing) UnityEngine.Debug.Log("Client: " + response + " " + buffer.position + " of " + buffer.size + ((ip == null) ? " (TCP)" : " (UDP)")); //#endif OnPacket callback; if (packetHandlers.TryGetValue((byte)response, out callback) && callback != null) { callback(response, reader, ip); return(true); } switch (response) { case Packet.Empty: break; case Packet.ForwardToAll: case Packet.ForwardToOthers: case Packet.ForwardToAllSaved: case Packet.ForwardToOthersSaved: case Packet.ForwardToHost: case Packet.Broadcast: { if (onForwardedPacket != null) { onForwardedPacket(reader); } break; } case Packet.ForwardToPlayer: { // Skip the player ID reader.ReadInt32(); if (onForwardedPacket != null) { onForwardedPacket(reader); } break; } case Packet.ForwardByName: { // Skip the player name reader.ReadString(); if (onForwardedPacket != null) { onForwardedPacket(reader); } break; } case Packet.SyncPlayerData: { Player target = GetPlayer(reader.ReadInt32()); if (target != null) { target.data = reader.ReadObject(); if (onPlayerSync != null) { onPlayerSync(target); } } break; } case Packet.ResponsePing: { int ping = (int)(mMyTime - mPingTime); if (ip != null) { if (onPing != null && ip != null) { onPing(ip, ping); } } else { mCanPing = true; mPing = ping; } break; } case Packet.ResponseSetUDP: { #if !UNITY_WEBPLAYER // The server has a new port for UDP traffic ushort port = reader.ReadUInt16(); if (port != 0) { IPAddress ipa = new IPAddress(mTcp.tcpEndPoint.Address.GetAddressBytes()); mServerUdpEndPoint = new IPEndPoint(ipa, port); // Send the first UDP packet to the server if (mUdp.isActive) { mBuffer = Buffer.Create(); mBuffer.BeginPacket(Packet.RequestActivateUDP).Write(playerID); mBuffer.EndPacket(); mUdp.Send(mBuffer, mServerUdpEndPoint); mBuffer.Recycle(); mBuffer = null; } } else { mServerUdpEndPoint = null; } #endif break; } case Packet.ResponseJoiningChannel: { mIsInChannel = true; mDictionary.Clear(); players.Clear(); mChannelID = reader.ReadInt32(); int count = reader.ReadInt16(); for (int i = 0; i < count; ++i) { Player p = new Player(); p.id = reader.ReadInt32(); p.name = reader.ReadString(); p.data = reader.ReadObject(); mDictionary.Add(p.id, p); players.Add(p); } break; } case Packet.ResponseLoadLevel: { // Purposely return after loading a level, ensuring that all future callbacks happen after loading if (onLoadLevel != null) { onLoadLevel(reader.ReadString()); } return(false); } case Packet.ResponsePlayerLeft: { Player p = GetPlayer(reader.ReadInt32()); if (p != null) { mDictionary.Remove(p.id); } players.Remove(p); if (onPlayerLeft != null) { onPlayerLeft(p); } break; } case Packet.ResponsePlayerJoined: { Player p = new Player(); p.id = reader.ReadInt32(); p.name = reader.ReadString(); p.data = reader.ReadObject(); mDictionary.Add(p.id, p); players.Add(p); if (onPlayerJoined != null) { onPlayerJoined(p); } break; } case Packet.ResponseSetHost: { mHost = reader.ReadInt32(); if (onSetHost != null) { onSetHost(isHosting); } break; } case Packet.ResponseSetChannelData: { mData = reader.ReadString(); if (onSetChannelData != null) { onSetChannelData(mData); } break; } case Packet.ResponseJoinChannel: { mIsInChannel = reader.ReadBoolean(); if (onJoinChannel != null) { onJoinChannel(mIsInChannel, mIsInChannel ? null : reader.ReadString()); } break; } case Packet.ResponseLeaveChannel: { mData = ""; mChannelID = 0; mIsInChannel = false; mDictionary.Clear(); players.Clear(); if (onLeftChannel != null) { onLeftChannel(); } break; } case Packet.ResponseRenamePlayer: { Player p = GetPlayer(reader.ReadInt32()); string oldName = p.name; if (p != null) { p.name = reader.ReadString(); } if (onRenamePlayer != null) { onRenamePlayer(p, oldName); } break; } case Packet.ResponseCreate: { if (onCreate != null) { int playerID = reader.ReadInt32(); ushort index = reader.ReadUInt16(); uint objID = reader.ReadUInt32(); onCreate(playerID, index, objID, reader); } break; } case Packet.ResponseDestroy: { if (onDestroy != null) { int count = reader.ReadUInt16(); for (int i = 0; i < count; ++i) { onDestroy(reader.ReadUInt32()); } } break; } case Packet.Error: { if (mTcp.stage != TcpProtocol.Stage.Connected && onConnect != null) { onConnect(false, reader.ReadString()); } else if (onError != null) { onError(reader.ReadString()); } break; } case Packet.Disconnect: { mData = ""; if (isInChannel && onLeftChannel != null) { onLeftChannel(); } players.Clear(); mDictionary.Clear(); mTcp.Close(false); mLoadFiles.Clear(); if (onDisconnect != null) { onDisconnect(); } break; } case Packet.ResponseLoadFile: { string filename = reader.ReadString(); int size = reader.ReadInt32(); byte[] data = reader.ReadBytes(size); OnLoadFile lfc = mLoadFiles.Pop(); if (lfc != null) { lfc(filename, data); } break; } } return(true); }
/// <summary> /// Process a single incoming packet. Returns whether we should keep processing packets or not. /// </summary> bool ProcessPacket(Buffer buffer, IPEndPoint ip) { mPacketSource = ip; BinaryReader reader = buffer.BeginReading(); if (buffer.size == 0) { return(true); } int packetID = reader.ReadByte(); Packet response = (Packet)packetID; #if DEBUG_PACKETS && !STANDALONE if (response != Packet.ResponsePing && response != Packet.Broadcast) { UnityEngine.Debug.Log("Client: " + response + " (" + buffer.size + " bytes) " + ((ip == null) ? "(TCP)" : "(UDP)")); } #endif // Verification step must be passed first if (response == Packet.ResponseID || mTcp.stage == TcpProtocol.Stage.Verifying) { if (mTcp.VerifyResponseID(response, reader)) { mTimeDifference = reader.ReadInt64() - (System.DateTime.UtcNow.Ticks / 10000); #if !UNITY_WEBPLAYER if (mUdp.isActive) { // If we have a UDP listener active, tell the server BeginSend(Packet.RequestSetUDP).Write((ushort)mUdp.listeningPort); EndSend(); } #endif mCanPing = true; if (onConnect != null) { onConnect(true, null); } } return(true); } OnPacket callback; if (packetHandlers.TryGetValue((byte)response, out callback) && callback != null) { callback(response, reader, ip); return(true); } switch (response) { case Packet.Empty: break; case Packet.ForwardToAll: case Packet.ForwardToOthers: case Packet.ForwardToAllSaved: case Packet.ForwardToOthersSaved: case Packet.ForwardToHost: case Packet.BroadcastAdmin: case Packet.Broadcast: { packetSourceID = reader.ReadInt32(); int channelID = reader.ReadInt32(); if (onForwardedPacket != null) { onForwardedPacket(channelID, reader); } break; } case Packet.ForwardToPlayer: { packetSourceID = reader.ReadInt32(); reader.ReadInt32(); // Skip the target player ID int channelID = reader.ReadInt32(); if (onForwardedPacket != null) { onForwardedPacket(channelID, reader); } break; } case Packet.ForwardByName: { packetSourceID = reader.ReadInt32(); reader.ReadString(); // Skip the player name int channelID = reader.ReadInt32(); if (onForwardedPacket != null) { onForwardedPacket(channelID, reader); } break; } case Packet.ResponseSetPlayerData: { int pid = reader.ReadInt32(); Player target = GetPlayer(pid); if (target != null) { string path = reader.ReadString(); DataNode node = target.Set(path, reader.ReadObject()); if (onSetPlayerData != null) { onSetPlayerData(target, path, node); } } else { UnityEngine.Debug.LogError("Not found: " + pid); } break; } case Packet.ResponsePing: { int ping = (int)(mMyTime - mPingTime); if (ip != null) { if (onPing != null && ip != null) { onPing(ip, ping); } } else { mCanPing = true; mPing = ping; } break; } case Packet.ResponseSetUDP: { #if !UNITY_WEBPLAYER // The server has a new port for UDP traffic ushort port = reader.ReadUInt16(); if (port != 0 && mTcp.tcpEndPoint != null) { IPAddress ipa = new IPAddress(mTcp.tcpEndPoint.Address.GetAddressBytes()); mServerUdpEndPoint = new IPEndPoint(ipa, port); // Send the first UDP packet to the server if (mUdp.isActive) { mBuffer = Buffer.Create(); mBuffer.BeginPacket(Packet.RequestActivateUDP).Write(playerID); mBuffer.EndPacket(); mUdp.Send(mBuffer, mServerUdpEndPoint); mBuffer.Recycle(); mBuffer = null; } } else { mServerUdpEndPoint = null; } #endif break; } case Packet.ResponseJoiningChannel: { int channelID = reader.ReadInt32(); int count = reader.ReadInt16(); Channel ch = GetChannel(channelID, true); for (int i = 0; i < count; ++i) { int pid = reader.ReadInt32(); Player p = GetPlayer(pid, true); if (reader.ReadBoolean()) { p.name = reader.ReadString(); p.dataNode = reader.ReadDataNode(); } ch.players.Add(p); } break; } case Packet.ResponseLoadLevel: { // Purposely return after loading a level, ensuring that all future callbacks happen after loading int channelID = reader.ReadInt32(); string scene = reader.ReadString(); if (onLoadLevel != null) { onLoadLevel(channelID, scene); } return(false); } case Packet.ResponsePlayerJoined: { int channelID = reader.ReadInt32(); Channel ch = GetChannel(channelID); if (ch != null) { Player p = GetPlayer(reader.ReadInt32(), true); if (reader.ReadBoolean()) { p.name = reader.ReadString(); p.dataNode = reader.ReadDataNode(); } ch.players.Add(p); if (onPlayerJoin != null) { onPlayerJoin(channelID, p); } } break; } case Packet.ResponsePlayerLeft: { int channelID = reader.ReadInt32(); int playerID = reader.ReadInt32(); Channel ch = GetChannel(channelID); if (ch != null) { Player p = ch.GetPlayer(playerID); ch.players.Remove(p); RebuildPlayerDictionary(); if (onPlayerLeave != null) { onPlayerLeave(channelID, p); } } break; } case Packet.ResponseSetHost: { int channelID = reader.ReadInt32(); int hostID = reader.ReadInt32(); for (int i = 0; i < mChannels.size; ++i) { Channel ch = mChannels[i]; if (ch.id == channelID) { ch.host = GetPlayer(hostID); if (onHostChanged != null) { onHostChanged(ch); } break; } } break; } case Packet.ResponseSetChannelData: { int channelID = reader.ReadInt32(); Channel ch = GetChannel(channelID); if (ch != null) { string path = reader.ReadString(); DataNode node = ch.Set(path, reader.ReadObject()); if (onSetChannelData != null) { onSetChannelData(ch, path, node); } } break; } case Packet.ResponseJoinChannel: { int channelID = reader.ReadInt32(); bool success = reader.ReadBoolean(); string msg = success ? null : reader.ReadString(); // mJoining can contain -2 and -1 when joining random channels if (!mJoining.Remove(channelID)) { for (int i = 0; i < mJoining.size; ++i) { int id = mJoining[i]; if (id < 0) { mJoining.RemoveAt(i); break; } } } #if UNITY_EDITOR if (!success) { UnityEngine.Debug.LogError("ResponseJoinChannel: " + success + ", " + msg); } #endif if (onJoinChannel != null) { onJoinChannel(channelID, success, msg); } break; } case Packet.ResponseLeaveChannel: { int channelID = reader.ReadInt32(); for (int i = 0; i < mChannels.size; ++i) { Channel ch = mChannels[i]; if (ch.id == channelID) { mChannels.RemoveAt(i); break; } } RebuildPlayerDictionary(); if (onLeaveChannel != null) { onLeaveChannel(channelID); } // Purposely exit after receiving a "left channel" notification so that other packets get handled in the next frame. return(false); } case Packet.ResponseRenamePlayer: { Player p = GetPlayer(reader.ReadInt32()); string oldName = p.name; if (p != null) { p.name = reader.ReadString(); } if (onRenamePlayer != null) { onRenamePlayer(p, oldName); } break; } case Packet.ResponseCreateObject: { if (onCreate != null) { int playerID = reader.ReadInt32(); int channelID = reader.ReadInt32(); uint objID = reader.ReadUInt32(); onCreate(channelID, playerID, objID, reader); } break; } case Packet.ResponseDestroyObject: { if (onDestroy != null) { int channelID = reader.ReadInt32(); int count = reader.ReadUInt16(); for (int i = 0; i < count; ++i) { uint val = reader.ReadUInt32(); onDestroy(channelID, val); } } break; } case Packet.ResponseTransferObject: { if (onTransfer != null) { int from = reader.ReadInt32(); int to = reader.ReadInt32(); uint id0 = reader.ReadUInt32(); uint id1 = reader.ReadUInt32(); onTransfer(from, to, id0, id1); } break; } case Packet.Error: { string err = reader.ReadString(); if (onError != null) { onError(err); } if (mTcp.stage != TcpProtocol.Stage.Connected && onConnect != null) { onConnect(false, err); } break; } case Packet.Disconnect: { if (onLeaveChannel != null) { while (mChannels.size > 0) { int index = mChannels.size - 1; Channel ch = mChannels[index]; mChannels.RemoveAt(index); onLeaveChannel(ch.id); } } mChannels.Clear(); mGetChannelsCallbacks.Clear(); mDictionary.Clear(); mTcp.Close(false); mLoadFiles.Clear(); mGetFiles.Clear(); mJoining.Clear(); mIsAdmin = false; if (mLocalServer != null) { mLocalServer.localClient = null; mLocalServer = null; } if (onDisconnect != null) { onDisconnect(); } mConfig = new DataNode("Version", Player.version); break; } case Packet.ResponseGetFileList: { string filename = reader.ReadString(); int size = reader.ReadInt32(); string[] files = null; if (size > 0) { files = new string[size]; for (int i = 0; i < size; ++i) { files[i] = reader.ReadString(); } } OnGetFiles cb = null; if (mGetFiles.TryGetValue(filename, out cb)) { mGetFiles.Remove(filename); } if (cb != null) { try { cb(filename, files); } #if UNITY_EDITOR catch (System.Exception ex) { Debug.LogError(ex.Message + ex.StackTrace); } #else catch (System.Exception) {} #endif } break; } case Packet.ResponseLoadFile: { string filename = reader.ReadString(); int size = reader.ReadInt32(); byte[] data = reader.ReadBytes(size); OnLoadFile cb = null; if (mLoadFiles.TryGetValue(filename, out cb)) { mLoadFiles.Remove(filename); } if (cb != null) { try { cb(filename, data); } #if UNITY_EDITOR catch (System.Exception ex) { Debug.LogError(ex.Message + ex.StackTrace); } #else catch (System.Exception) {} #endif } break; } case Packet.ResponseVerifyAdmin: { int pid = reader.ReadInt32(); Player p = GetPlayer(pid); if (p == player) { mIsAdmin = true; } if (onSetAdmin != null) { onSetAdmin(p); } break; } case Packet.ResponseSetServerData: { string path = reader.ReadString(); object obj = reader.ReadObject(); if (obj != null) { DataNode node = mConfig.SetHierarchy(path, obj); if (onSetServerData != null) { onSetServerData(path, node); } } else { DataNode node = mConfig.RemoveHierarchy(path); if (onSetServerData != null) { onSetServerData(path, node); } } break; } case Packet.ResponseChannelList: { if (mGetChannelsCallbacks.Count != 0) { OnGetChannels cb = mGetChannelsCallbacks.Dequeue(); List <Channel.Info> channels = new List <Channel.Info>(); int count = reader.ReadInt32(); for (int i = 0; i < count; ++i) { Channel.Info info = new Channel.Info(); info.id = reader.ReadInt32(); info.players = reader.ReadUInt16(); info.limit = reader.ReadUInt16(); info.hasPassword = reader.ReadBoolean(); info.isPersistent = reader.ReadBoolean(); info.level = reader.ReadString(); info.data = reader.ReadDataNode(); channels.Add(info); } if (cb != null) { cb(channels); } } break; } case Packet.ResponseLockChannel: { int channelID = reader.ReadInt32(); bool isLocked = reader.ReadBoolean(); Channel ch = GetChannel(channelID); if (ch != null) { ch.isLocked = isLocked; } if (onLockChannel != null) { onLockChannel(channelID, isLocked); } break; } } return(true); }
/// <summary> /// Process a single incoming packet. Returns whether we should keep processing packets or not. /// </summary> bool ProcessPacket(Buffer buffer, IPEndPoint ip) { mPacketSource = ip; BinaryReader reader = buffer.BeginReading(); if (buffer.size == 0) { return(true); } int packetID = reader.ReadByte(); Packet response = (Packet)packetID; // Verification step must be passed first if (mTcp.stage == TcpProtocol.Stage.Verifying) { if (mTcp.VerifyResponseID(response, reader)) { #if !UNITY_WEBPLAYER if (mUdp.isActive) { // If we have a UDP listener active, tell the server BeginSend(Packet.RequestSetUDP).Write(mUdp.isActive ? (ushort)mUdp.listeningPort : (ushort)0); EndSend(); } #endif mCanPing = true; if (onConnect != null) { onConnect(true, null); } } else if (onConnect != null) { onConnect(false, "Protocol version mismatch!"); } return(true); } //#if !UNITY_EDITOR // DEBUG // if (response != Packet.ResponsePing) Console.WriteLine("Client: " + response + " " + buffer.position + " of " + buffer.size + ((ip == null) ? " (TCP)" : " (UDP)")); //#else // if (response != Packet.ResponsePing) UnityEngine.Debug.Log("Client: " + response + " " + buffer.position + " of " + buffer.size + ((ip == null) ? " (TCP)" : " (UDP)")); //#endif switch (response) { case Packet.Empty: break; case Packet.ForwardToAll: case Packet.ForwardToOthers: case Packet.ForwardToAllSaved: case Packet.ForwardToOthersSaved: case Packet.ForwardToHost: { if (onForwardedPacket != null) { onForwardedPacket(reader); } break; } case Packet.ForwardToPlayer: { // Skip the player ID reader.ReadInt32(); if (onForwardedPacket != null) { onForwardedPacket(reader); } break; } case Packet.ResponsePing: { mPing = (int)(mTime - mPingTime); mCanPing = true; break; } case Packet.ResponseSetUDP: { #if !UNITY_WEBPLAYER // The server has a new port for UDP traffic ushort port = reader.ReadUInt16(); if (port != 0) { IPAddress ipa = new IPAddress(mTcp.tcpEndPoint.Address.GetAddressBytes()); mServerUdpEndPoint = new IPEndPoint(ipa, port); // Send an empty packet to the server, opening up the communication channel if (mUdp.isActive) { mUdp.SendEmptyPacket(mServerUdpEndPoint); } } else { mServerUdpEndPoint = null; } #endif break; } case Packet.ResponseJoiningChannel: { mIsInChannel = true; mDictionary.Clear(); players.Clear(); mChannelID = reader.ReadInt32(); int count = reader.ReadInt16(); for (int i = 0; i < count; ++i) { Player p = new Player(); p.id = reader.ReadInt32(); p.name = reader.ReadString(); mDictionary.Add(p.id, p); players.Add(p); } break; } case Packet.ResponseLoadLevel: { // Purposely return after loading a level, ensuring that all future callbacks happen after loading if (onLoadLevel != null) { onLoadLevel(reader.ReadString()); } return(false); } case Packet.ResponsePlayerLeft: { Player p = GetPlayer(reader.ReadInt32()); if (p != null) { mDictionary.Remove(p.id); } players.Remove(p); if (onPlayerLeft != null) { onPlayerLeft(p); } break; } case Packet.ResponsePlayerJoined: { Player p = new Player(); p.id = reader.ReadInt32(); p.name = reader.ReadString(); mDictionary.Add(p.id, p); players.Add(p); if (onPlayerJoined != null) { onPlayerJoined(p); } break; } case Packet.ResponseSetHost: { mHost = reader.ReadInt32(); if (onSetHost != null) { onSetHost(isHosting); } break; } case Packet.ResponseSetChannelData: { mData = reader.ReadString(); if (onSetChannelData != null) { onSetChannelData(mData); } break; } case Packet.ResponseJoinChannel: { mIsInChannel = reader.ReadBoolean(); if (onJoinChannel != null) { onJoinChannel(mIsInChannel, mIsInChannel ? null : reader.ReadString()); } break; } case Packet.ResponseLeaveChannel: { mData = ""; mChannelID = 0; mIsInChannel = false; mDictionary.Clear(); players.Clear(); if (onLeftChannel != null) { onLeftChannel(); } break; } case Packet.ResponseRenamePlayer: { Player p = GetPlayer(reader.ReadInt32()); string oldName = p.name; if (p != null) { p.name = reader.ReadString(); } if (onRenamePlayer != null) { onRenamePlayer(p, oldName); } break; } case Packet.ResponseCreate: { if (onCreate != null) { int playerID = reader.ReadInt32(); short index = reader.ReadInt16(); uint objID = reader.ReadUInt32(); onCreate(playerID, index, objID, reader); } break; } case Packet.ResponseDestroy: { if (onDestroy != null) { int count = reader.ReadUInt16(); for (int i = 0; i < count; ++i) { onDestroy(reader.ReadUInt32()); } } break; } case Packet.Error: { if (mTcp.stage != TcpProtocol.Stage.Connected && onConnect != null) { onConnect(false, reader.ReadString()); } else if (onError != null) { onError(reader.ReadString()); } break; } case Packet.Disconnect: { mData = ""; if (isInChannel && onLeftChannel != null) { onLeftChannel(); } players.Clear(); mDictionary.Clear(); mTcp.Close(false); if (onDisconnect != null) { onDisconnect(); } break; } default: { OnPacket callback; if (packetHandlers.TryGetValue((byte)response, out callback)) { if (callback != null) { callback(response, reader, ip); } } break; } } return(true); }
/// <summary> /// Send periodic updates. /// </summary> void ThreadFunction() { mInternal = new IPEndPoint(Tools.localAddress, mGameServer.tcpPort); mExternal = new IPEndPoint(Tools.externalAddress, mGameServer.tcpPort); for (; ;) { long time = DateTime.UtcNow.Ticks / 10000; if (mShutdown) { mTcp.Disconnect(); mThread = null; break; } Buffer buffer; // Try to establish a connection if (mGameServer != null && !mTcp.isConnected && mNextConnect < time) { mNextConnect = time + 15000; mTcp.Connect(mRemoteAddress); } while (mTcp.ReceivePacket(out buffer)) { BinaryReader reader = buffer.BeginReading(); Packet response = (Packet)reader.ReadByte(); if (mTcp.stage == TcpProtocol.Stage.Verifying) { if (mTcp.VerifyResponseID(response, reader)) { mTimeDifference = reader.ReadInt64() - (System.DateTime.UtcNow.Ticks / 10000); mWasConnected = true; } else { #if STANDALONE Console.WriteLine("TcpLobbyLink: Protocol version mismatch"); #endif mThread = null; return; } } else if (response == Packet.Error) { // Automatically try to re-establish a connection on disconnect mNextConnect = mWasConnected ? 0 : time + 30000; #if STANDALONE Console.WriteLine("TcpLobbyLink: " + reader.ReadString()); #endif } #if STANDALONE else { Console.WriteLine("TcpLobbyLink can't handle this packet: " + response); } #endif buffer.Recycle(); } if (mGameServer != null && mTcp.isConnected) { BinaryWriter writer = mTcp.BeginSend(Packet.RequestAddServer); writer.Write(GameServer.gameID); writer.Write(mGameServer.name); writer.Write((short)mGameServer.playerCount); Tools.Serialize(writer, mInternal); Tools.Serialize(writer, mExternal); mTcp.EndSend(); mGameServer = null; } Thread.Sleep(10); } }