public void TickSocket(Socket sock, ref byte[] rd, ref int rdsf) { int avail = sock.Available; if (avail <= 0) { return; } if (avail + rdsf > MAX) { avail = MAX - rdsf; if (avail == 0) { throw new Exception("Received overly massive packet?!"); } } sock.Receive(rd, rdsf, avail, SocketFlags.None); rdsf += avail; if (rdsf < 5) { return; } while (true) { byte[] len_bytes = new byte[4]; Array.Copy(rd, len_bytes, 4); int len = Utilities.BytesToInt(len_bytes); if (len + 5 > MAX) { throw new Exception("Unreasonably huge packet!"); } if (rdsf < 5 + len) { return; } ServerToClientPacket packetID = (ServerToClientPacket)rd[4]; byte[] data = new byte[len]; Array.Copy(rd, 5, data, 0, len); byte[] rem_data = new byte[rdsf - (len + 5)]; if (rem_data.Length > 0) { Array.Copy(rd, len + 5, rem_data, 0, rem_data.Length); Array.Copy(rem_data, rd, rem_data.Length); } rdsf -= len + 5; AbstractPacketIn packet; bool asyncable = false; NetUsageType usage; switch (packetID) // TODO: Packet registry! { case ServerToClientPacket.PING: packet = new PingPacketIn(); usage = NetUsageType.PINGS; break; case ServerToClientPacket.YOUR_POSITION: packet = new YourPositionPacketIn(); usage = NetUsageType.PLAYERS; break; case ServerToClientPacket.SPAWN_ENTITY: packet = new SpawnEntityPacketIn(); usage = NetUsageType.ENTITIES; break; case ServerToClientPacket.PHYSICS_ENTITY_UPDATE: packet = new PhysicsEntityUpdatePacketIn(); usage = NetUsageType.ENTITIES; break; case ServerToClientPacket.MESSAGE: packet = new MessagePacketIn(); usage = NetUsageType.GENERAL; break; case ServerToClientPacket.CHARACTER_UPDATE: packet = new CharacterUpdatePacketIn(); usage = NetUsageType.PLAYERS; break; case ServerToClientPacket.TOPS: packet = new TopsPacketIn(); usage = NetUsageType.CHUNKS; break; case ServerToClientPacket.DESPAWN_ENTITY: packet = new DespawnEntityPacketIn(); usage = NetUsageType.ENTITIES; break; case ServerToClientPacket.NET_STRING: packet = new NetStringPacketIn(); usage = NetUsageType.GENERAL; break; case ServerToClientPacket.SPAWN_ITEM: packet = new SpawnItemPacketIn(); usage = NetUsageType.GENERAL; break; case ServerToClientPacket.YOUR_STATUS: packet = new YourStatusPacketIn(); usage = NetUsageType.PLAYERS; break; case ServerToClientPacket.ADD_JOINT: packet = new AddJointPacketIn(); usage = NetUsageType.ENTITIES; break; case ServerToClientPacket.YOUR_EID: packet = new YourEIDPacketIn(); usage = NetUsageType.GENERAL; break; case ServerToClientPacket.DESTROY_JOINT: packet = new DestroyJointPacketIn(); usage = NetUsageType.ENTITIES; break; case ServerToClientPacket.TOPS_DATA: packet = new TopsDataPacketIn(); usage = NetUsageType.CHUNKS; break; case ServerToClientPacket.PRIMITIVE_ENTITY_UPDATE: packet = new PrimitiveEntityUpdatePacketIn(); usage = NetUsageType.ENTITIES; break; case ServerToClientPacket.ANIMATION: packet = new AnimationPacketIn(); usage = NetUsageType.PLAYERS; break; case ServerToClientPacket.FLASHLIGHT: packet = new FlashLightPacketIn(); usage = NetUsageType.PLAYERS; break; case ServerToClientPacket.REMOVE_ITEM: packet = new RemoveItemPacketIn(); usage = NetUsageType.GENERAL; break; case ServerToClientPacket.SET_ITEM: packet = new SetItemPacketIn(); usage = NetUsageType.GENERAL; break; case ServerToClientPacket.CVAR_SET: packet = new CVarSetPacketIn(); usage = NetUsageType.GENERAL; break; case ServerToClientPacket.SET_HELD_ITEM: packet = new SetHeldItemPacketIn(); usage = NetUsageType.GENERAL; break; case ServerToClientPacket.CHUNK_INFO: packet = new ChunkInfoPacketIn(); usage = NetUsageType.CHUNKS; break; case ServerToClientPacket.BLOCK_EDIT: packet = new BlockEditPacketIn(); usage = NetUsageType.CHUNKS; break; case ServerToClientPacket.SUN_ANGLE: packet = new SunAnglePacketIn(); usage = NetUsageType.EFFECTS; break; case ServerToClientPacket.TELEPORT: packet = new TeleportPacketIn(); usage = NetUsageType.PLAYERS; break; case ServerToClientPacket.OPERATION_STATUS: packet = new OperationStatusPacketIn(); usage = NetUsageType.GENERAL; break; case ServerToClientPacket.PARTICLE_EFFECT: packet = new ParticleEffectPacketIn(); usage = NetUsageType.EFFECTS; break; case ServerToClientPacket.PATH: packet = new PathPacketIn(); usage = NetUsageType.EFFECTS; break; case ServerToClientPacket.CHUNK_FORGET: packet = new ChunkForgetPacketIn(); usage = NetUsageType.CHUNKS; break; case ServerToClientPacket.FLAG_ENTITY: packet = new FlagEntityPacketIn(); usage = NetUsageType.ENTITIES; break; case ServerToClientPacket.DEFAULT_SOUND: packet = new DefaultSoundPacketIn(); usage = NetUsageType.EFFECTS; break; case ServerToClientPacket.GAIN_CONTROL_OF_VEHICLE: packet = new GainControlOfVehiclePacketIn(); usage = NetUsageType.ENTITIES; break; case ServerToClientPacket.ADD_CLOUD: packet = new AddCloudPacketIn(); usage = NetUsageType.CLOUDS; break; case ServerToClientPacket.REMOVE_CLOUD: packet = new RemoveCloudPacketIn(); usage = NetUsageType.CLOUDS; break; case ServerToClientPacket.ADD_TO_CLOUD: packet = new AddToCloudPacketIn(); usage = NetUsageType.CLOUDS; break; case ServerToClientPacket.YOUR_VEHICLE: packet = new YourVehiclePacketIn(); usage = NetUsageType.ENTITIES; break; case ServerToClientPacket.SET_STATUS: packet = new SetStatusPacketIn(); usage = NetUsageType.PLAYERS; break; case ServerToClientPacket.HIGHLIGHT: packet = new HighlightPacketIn(); usage = NetUsageType.EFFECTS; break; case ServerToClientPacket.PLAY_SOUND: packet = new PlaySoundPacketIn(); usage = NetUsageType.EFFECTS; break; case ServerToClientPacket.LOD_MODEL: packet = new LODModelPacketIn(); usage = NetUsageType.ENTITIES; break; case ServerToClientPacket.LOSE_CONTROL_OF_VEHICLE: packet = new LoseControlOfVehiclePacketIn(); usage = NetUsageType.ENTITIES; break; case ServerToClientPacket.JOINT_UPDATE: packet = new JointUpdatePacketIn(); usage = NetUsageType.ENTITIES; break; default: throw new Exception("Invalid packet ID: " + packetID); } UsagesThisSecond[(int)usage] += 5 + data.Length; UsagesTotal[(int)usage] += 5 + data.Length; packet.TheClient = TheClient; packet.ChunkN = sock == ChunkSocket; ServerToClientPacket pid = packetID; if (asyncable) { // TODO: StartAsyncTask? if (!packet.ParseBytesAndExecute(data)) { SysConsole.Output(OutputType.ERROR, "Bad async packet (ID=" + pid + ") data!"); } } else { TheClient.Schedule.ScheduleSyncTask(() => { try { if (!packet.ParseBytesAndExecute(data)) { SysConsole.Output(OutputType.ERROR, "Bad sync packet (ID=" + pid + ") data!"); } } catch (Exception ex) { if (ex is ThreadAbortException) { throw ex; } SysConsole.Output(OutputType.ERROR, "Bad sync packet (ID=" + pid + ") data: " + ex.ToString()); } }); } } }
/// <summary> /// Ticks the socket. /// </summary> public void Tick() { if (!TickMe) { return; } int av = InternalSocket.Available; if (av > 0) { if (received + av > Max) { InternalSocket.Close(); TickMe = false; } received += InternalSocket.Receive(recd, received, av, SocketFlags.None); if (Step == 0) { if (received > 4) { if (recd[0] == 'G' && recd[1] == 'E' && recd[2] == 'T' && recd[3] == ' ') { // TODO: Try for 'GET ' SysConsole.Output(OutputType.INFO, "Connection (" + InternalSocket.RemoteEndPoint.ToString() + ") discarded: invalid header (GET)."); InternalSocket.Close(); TickMe = false; } else if (recd[0] == 'P' && recd[1] == 'O' && recd[2] == 'S' && recd[3] == 'T' && recd[4] == ' ') { // TODO: Try for 'POST ' SysConsole.Output(OutputType.INFO, "Connection (" + InternalSocket.RemoteEndPoint.ToString() + ") discarded: invalid header (POST)."); InternalSocket.Close(); TickMe = false; } else if (recd[0] == 'H' && recd[1] == 'E' && recd[2] == 'A' && recd[3] == 'D' && recd[4] == ' ') { // TODO: Try for 'HEAD ' SysConsole.Output(OutputType.INFO, "Connection (" + InternalSocket.RemoteEndPoint.ToString() + ") discarded: invalid header (HEAD)."); InternalSocket.Close(); TickMe = false; } else if (recd[0] == 'V' && recd[1] == 'O' && recd[2] == 'X' && recd[3] == '_' && recd[4] == ' ') { // Try for 'VOX_ ' int pos = -1; for (int i = 0; i < received; i++) { if (recd[i] == '\n') { pos = i; } } if (pos > 0) { string datastr = Utilities.encoding.GetString(recd, 0, pos); string[] split = datastr.Split('\r'); if (split.Length == 5) { // VOX_ \rUsername\rEntrykey\rHost\rPort\n string username = split[1]; string entrykey = split[2]; string host = split[3]; string port = split[4]; byte[] temp = new byte[Max]; Array.Copy(recd, pos + 1, temp, 0, Max - (pos + 1)); received -= pos + 1; recd = temp; Step = 1; if (!Utilities.ValidateUsername(username)) { SysConsole.Output(OutputType.INFO, "Connection (" + InternalSocket.RemoteEndPoint.ToString() + ") discarded: entirely invalid username (" + username + ") [probably an edited client]."); InternalSocket.Close(); TickMe = false; } else { player = new Player(this); player.Username = username; player.ConnectedHost = host; player.ConnectedPort = port; player.ConnectionKey = entrykey; player.JoinTime = ServerMain.GlobalTickTime; player.LastPing = ServerMain.GlobalTickTime; player.LastSecondaryPing = ServerMain.GlobalTickTime; InternalSocket.Send(FileHandler.encoding.GetBytes("ACCEPT\n")); // ServerMain.SpawnPlayer(player); ServerMain.WaitingPlayers.Add(player); SysConsole.Output(OutputType.INFO, "Connection (" + InternalSocket.RemoteEndPoint.ToString() + ") accepted: Username="******", connected to " + host + ":" + port); IsChunkNetwork = false; } } else if (split.Length == 2) { // VOX_ \rEntrykey\n string key = split[1]; byte[] temp = new byte[Max]; Array.Copy(recd, pos + 1, temp, 0, Max - (pos + 1)); received -= pos + 1; recd = temp; Step = 1; player = null; for (int i = 0; i < ServerMain.WaitingPlayers.Count; i++) { if (ServerMain.WaitingPlayers[i].ConnectionKey == key) { player = ServerMain.WaitingPlayers[i]; break; } } if (player == null) { SysConsole.Output(OutputType.INFO, "Connection (" + InternalSocket.RemoteEndPoint.ToString() + ") discarded: invalid header (VOX_ secondary with unknown key)."); InternalSocket.Close(); TickMe = false; } else { InternalSocket.Send(FileHandler.encoding.GetBytes("ACCEPT\n")); ServerMain.WaitingPlayers.Remove(player); player.ChunkNetwork = this; ServerMain.SpawnPlayer(player); IsChunkNetwork = true; SysConsole.Output(OutputType.INFO, "Connection (" + InternalSocket.RemoteEndPoint.ToString() + ") accepted: Username="******", now joining!"); } } else { SysConsole.Output(OutputType.INFO, "Connection (" + InternalSocket.RemoteEndPoint.ToString() + ") discarded: invalid header (VOX_ with invalid parameters)."); InternalSocket.Close(); TickMe = false; } } } else { SysConsole.Output(OutputType.INFO, "Connection (" + InternalSocket.RemoteEndPoint.ToString() + ") discarded: invalid header (unknown)."); InternalSocket.Close(); TickMe = false; } } } else if (Step == 1) { if (received > 4) { while (true) { int len = BitConverter.ToInt32(recd, 0); byte type = recd[4]; if (received - 5 >= len) { byte[] data = new byte[len]; if (len > 0) { Array.Copy(recd, 5, data, 0, len); } received -= 5 + len; byte[] newdata = new byte[Max]; if (received > 0) { Array.Copy(recd, 5 + len, newdata, 0, received); } recd = newdata; AbstractPacketIn packet; switch (type) { case 1: packet = new PingPacketIn(player, IsChunkNetwork); break; case 2: packet = new MoveKeysPacketIn(player, IsChunkNetwork); break; case 3: packet = new CommandPacketIn(player, IsChunkNetwork); break; case 4: packet = new SelectionPacketIn(player, IsChunkNetwork); break; case 255: packet = new DisconnectPacketIn(player, IsChunkNetwork); return; default: player.Kick("Invalid packet " + (int)type); return; } try { if (packet.ReadBytes(data)) { if (packet is PingPacketIn) { packet.Apply(); } else { lock (player.Packets) { player.Packets.Add(packet); } } } else { player.Kick("Impure packet " + (int)type); } } catch (Exception ex) { SysConsole.Output(OutputType.ERROR, "Networking / player / receive packet: " + ex.ToString()); player.Kick("Invalid packet " + (int)type); } } else { break; } } } } } }
public void Tick(double delta) { try { Time += delta; if (!GotBase && Time >= MaxTime) { throw new Exception("Connection timed out!"); } int avail = PrimarySocket.Available; if (avail <= 0) { return; } if (avail + recdsofar > MAX) { avail = MAX - recdsofar; if (avail == 0) { throw new Exception("Received overly massive packet?!"); } } PrimarySocket.Receive(recd, recdsofar, avail, SocketFlags.None); recdsofar += avail; if (recdsofar < 5) { return; } if (trying) { return; } if (GotBase) { while (true) { byte[] len_bytes = new byte[4]; Array.Copy(recd, len_bytes, 4); int len = Utilities.BytesToInt(len_bytes); if (len + 5 > MAX) { throw new Exception("Unreasonably huge packet!"); } if (recdsofar < 5 + len) { return; } ClientToServerPacket packetID = (ClientToServerPacket)recd[4]; byte[] data = new byte[len]; Array.Copy(recd, 5, data, 0, len); byte[] rem_data = new byte[recdsofar - (len + 5)]; if (rem_data.Length > 0) { Array.Copy(recd, len + 5, rem_data, 0, rem_data.Length); Array.Copy(rem_data, recd, rem_data.Length); } recdsofar -= len + 5; AbstractPacketIn packet; switch (packetID) // TODO: Packet registry? { case ClientToServerPacket.PING: packet = new PingPacketIn(); break; case ClientToServerPacket.KEYS: packet = new KeysPacketIn(); break; case ClientToServerPacket.COMMAND: packet = new CommandPacketIn(); break; case ClientToServerPacket.HOLD_ITEM: packet = new HoldItemPacketIn(); break; case ClientToServerPacket.DISCONNECT: packet = new DisconnectPacketIn(); break; case ClientToServerPacket.SET_STATUS: packet = new SetStatusPacketIn(); break; case ClientToServerPacket.PLEASE_REDEFINE: packet = new PleaseRedefinePacketIn(); break; default: throw new Exception("Invalid packet ID: " + packetID); } packet.Chunk = PE.ChunkNetwork == this; packet.Player = PE; DataReader dr = new DataReader(new DataStream(data)); PE.TheRegion.TheWorld.Schedule.ScheduleSyncTask(() => { if (!packet.ParseBytesAndExecute(dr)) { throw new Exception("Imperfect packet data for " + packetID); } }); } } else { if (recd[0] == 'G' && recd[1] == 'E' && recd[2] == 'T' && recd[3] == ' ' && recd[4] == '/') { // HTTP GET if (recd[recdsofar - 1] == '\n' && (recd[recdsofar - 2] == '\n' || recd[recdsofar - 3] == '\n')) { WebPage wp = new WebPage(TheServer, this); wp.Init(FileHandler.encoding.GetString(recd, 0, recdsofar)); PrimarySocket.Send(wp.GetFullData()); PrimarySocket.Close(5); Alive = false; } } else if (recd[0] == 'P' && recd[1] == 'O' && recd[2] == 'S' && recd[3] == 'T' && recd[4] == ' ') { // HTTP POST throw new NotImplementedException("HTTP POST not yet implemented"); } else if (recd[0] == 'H' && recd[1] == 'E' && recd[2] == 'A' && recd[3] == 'D' && recd[4] == ' ') { // HTTP HEAD if (recd[recdsofar - 1] == '\n' && (recd[recdsofar - 2] == '\n' || recd[recdsofar - 3] == '\n')) { WebPage wp = new WebPage(TheServer, this); wp.Init(FileHandler.encoding.GetString(recd, 0, recdsofar)); PrimarySocket.Send(FileHandler.encoding.GetBytes(wp.GetHeaders())); PrimarySocket.Close(5); Alive = false; } } else if (recd[0] == 'V' && recd[1] == 'O' && recd[2] == 'X' && recd[3] == 'p' && recd[4] == '_') { // VOXALIA ping if (recd[recdsofar - 1] == '\n') { PrimarySocket.Send(FileHandler.encoding.GetBytes("SUCCESS\rVoxalia Server Online\n")); PrimarySocket.Close(5); Alive = false; } } else if (recd[0] == 'V' && recd[1] == 'O' && recd[2] == 'X' && recd[3] == '_' && recd[4] == '_') { // VOXALIA connect if (recd[recdsofar - 1] == '\n') { string data = FileHandler.encoding.GetString(recd, 6, recdsofar - 7); string[] datums = data.SplitFast('\r'); if (datums.Length != 5) { throw new Exception("Invalid VOX__ connection details!"); } string name = datums[0]; string key = datums[1]; string host = datums[2]; string port = datums[3]; string rdist = datums[4]; string[] rds = rdist.SplitFast(','); if (rds.Length != 7) { throw new Exception("Invalid VOX__ connection details: RenderDist!"); } if (!Utilities.ValidateUsername(name)) { throw new Exception("Invalid connection - unreasonable username!"); } trying = true; TheServer.Schedule.StartAsyncTask(() => { try { CheckWebSession(name, key); TheServer.LoadedWorlds[0].Schedule.ScheduleSyncTask(() => { // TODO: Additional details? // TODO: Choose a world smarter. PlayerEntity player = new PlayerEntity(TheServer.LoadedWorlds[0].MainRegion, this, name) { SessionKey = key, Host = host, Port = port, IP = PrimarySocket.RemoteEndPoint.ToString(), ViewRadiusInChunks = Math.Min(TheServer.CVars.g_maxrenderdist.ValueI, Math.Max(1, Utilities.StringToInt(rds[0]))), ViewRadExtra2 = Math.Min(TheServer.CVars.g_maxrenderdist.ValueI, Math.Max(0, Utilities.StringToInt(rds[1]))), ViewRadExtra2Height = Math.Min(TheServer.CVars.g_maxrenderdist.ValueI, Math.Max(0, Utilities.StringToInt(rds[2]))), ViewRadExtra5 = Math.Min(TheServer.CVars.g_maxrenderdist.ValueI, Math.Max(0, Utilities.StringToInt(rds[3]))), ViewRadExtra5Height = Math.Min(TheServer.CVars.g_maxrenderdist.ValueI, Math.Max(0, Utilities.StringToInt(rds[4]))), ViewRadExtra6 = Math.Min(TheServer.CVars.g_maxlodrenderdist.ValueI, Math.Max(0, Utilities.StringToInt(rds[5]))), ViewRadExtra15 = Math.Min(TheServer.CVars.g_maxlodrenderdist.ValueI, Math.Max(0, Utilities.StringToInt(rds[6]))) }; PE = player; player.Host = host; TheServer.Schedule.ScheduleSyncTask(() => { TheServer.PlayersWaiting.Add(player); PrimarySocket.Send(FileHandler.encoding.GetBytes("ACCEPT\n")); }); GotBase = true; recdsofar = 0; trying = false; }); } catch (Exception ex) { TheServer.Schedule.ScheduleSyncTask(() => { if (!Alive) { return; } PrimarySocket.Close(); Utilities.CheckException(ex); SysConsole.Output(OutputType.WARNING, "Forcibly disconnected client: " + ex.GetType().Name + ": " + ex.Message); if (TheServer.CVars.s_debug.ValueB) { SysConsole.Output(ex); } Alive = false; }); } }); } } else if (recd[0] == 'V' && recd[1] == 'O' && recd[2] == 'X' && recd[3] == 'c' && recd[4] == '_') { // VOXALIA chunk connect if (recd[recdsofar - 1] == '\n') { string data = FileHandler.encoding.GetString(recd, 6, recdsofar - 7); string[] datums = data.SplitFast('\r'); if (datums.Length != 4) { throw new Exception("Invalid VOXc_ connection details!"); } string name = datums[0]; string key = datums[1]; string host = datums[2]; string port = datums[3]; if (!Utilities.ValidateUsername(name)) { throw new Exception("Invalid connection - unreasonable username!"); } TheServer.Schedule.ScheduleSyncTask(() => { PlayerEntity player = null; for (int i = 0; i < TheServer.PlayersWaiting.Count; i++) { if (TheServer.PlayersWaiting[i].Name == name && TheServer.PlayersWaiting[i].Host == host && TheServer.PlayersWaiting[i].Port == port && TheServer.PlayersWaiting[i].SessionKey == key) { player = TheServer.PlayersWaiting[i]; TheServer.PlayersWaiting.RemoveAt(i); break; } } PE = player ?? throw new Exception("Can't find player for VOXc_:" + name + ", " + host + ", " + port + ", " + key.Length); player.ChunkNetwork = this; PrimarySocket.Send(FileHandler.encoding.GetBytes("ACCEPT\n")); // TODO: What if the world disappears during connect sequence? player.LastPingByte = 0; player.LastCPingByte = 0; PrimarySocket.SendBufferSize *= 10; SendPacket(new PingPacketOut(0)); player.Network.SendPacket(new PingPacketOut(0)); player.SendStatus(); GotBase = true; recdsofar = 0; player.TheRegion.TheWorld.Schedule.ScheduleSyncTask(() => { player.InitPlayer(); player.TheRegion.SpawnEntity(player); }); }); } } else { throw new Exception("Unknown initial byte set!"); } } } catch (Exception ex) { PrimarySocket.Close(); try { if (PE != null) { PE.Kick("Internal exception."); } } finally { Utilities.CheckException(ex); SysConsole.Output(OutputType.WARNING, "Forcibly disconnected client: " + ex.GetType().Name + ": " + ex.Message); if (TheServer.CVars.s_debug.ValueB) { SysConsole.Output(ex); } Alive = false; } } }
/// <summary> /// Tick the entire network engine. /// </summary> public static void Tick() { if (!Connected) { return; } try { int waiting = Connection.Available; if (waiting > 1024 * 1024 - bufferpos) { waiting = 1024 * 1024 - bufferpos; } if (waiting > 0) { Connection.Receive(buffer, bufferpos, waiting, SocketFlags.None); bufferpos += waiting; while (true) { if (bufferpos < 5) { break; } if (!Connected) { break; } int recd = BitConverter.ToInt32(buffer, 0); if (bufferpos < 5 + recd) { break; } byte[] packet = new byte[recd]; Array.Copy(buffer, 5, packet, 0, recd); int ID = buffer[4]; Array.Copy(buffer, recd + 5, buffer, 0, bufferpos - (recd + 5)); bufferpos -= recd + 5; AbstractPacketIn apacket = null; switch (ID) { case 1: apacket = new PingPacketIn(); break; case 2: apacket = new ConfirmPositionPacketIn(); break; case 3: apacket = new MessagePacketIn(); break; case 4: apacket = new NewEntityPacketIn(); break; case 5: apacket = new DespawnEntityPacketIn(); break; case 6: apacket = new EntityPositionPacketIn(); break; case 255: apacket = new DisconnectPacketIn(); break; default: UIConsole.WriteLine("Invalid packet from server, ID " + ID); break; } if (apacket != null) { ReceivePacket(ID, apacket, packet, false); } } } } catch (Exception ex) { SysConsole.Output(OutputType.ERROR, "Networking: " + ex.ToString()); Disconnect(); } try { int waiting = ChunkConnection.Available; if (waiting > 1024 * 1024 - bufferpos2) { waiting = 1024 * 1024 - bufferpos2; } if (waiting > 0) { ChunkConnection.Receive(buffer2, bufferpos2, waiting, SocketFlags.None); bufferpos2 += waiting; while (true) { if (bufferpos2 < 5) { break; } if (!Connected) { break; } int recd = BitConverter.ToInt32(buffer2, 0); if (bufferpos2 < 5 + recd) { break; } byte[] packet = new byte[recd]; Array.Copy(buffer2, 5, packet, 0, recd); int ID = buffer2[4]; Array.Copy(buffer2, recd + 5, buffer2, 0, bufferpos2 - (recd + 5)); bufferpos2 -= recd + 5; AbstractPacketIn apacket = null; switch (ID) { case 0: apacket = new ChunkPacketIn(); break; case 1: apacket = new PingPacketIn(); break; case 4: apacket = new BlockPacketIn(); break; default: UIConsole.WriteLine("Invalid secondary packet from server, ID " + ID); break; } if (apacket != null) { ReceivePacket(ID, apacket, packet, true); } } } } catch (Exception ex) { SysConsole.Output(OutputType.ERROR, "Networking (Secondary): " + ex.ToString()); Disconnect(); } }