public PyPacket CreateEmptySessionChange() { // Fill all the packet data, except the dest/source SessionChangeNotification scn = new SessionChangeNotification(); scn.changes = session.EncodeChanges(); if (scn.changes.Dictionary.Count == 0) { // Nothing to do return null; } // Add all the nodeIDs foreach (int node in NodeManager.nodes.Keys) { if (node == 0) continue; scn.nodesOfInterest.Items.Add(new PyInt(node)); } PyPacket p = new PyPacket(); p.type_string = "macho.SessionChangeNotification"; p.type = Macho.MachoNetMsg_Type.SESSIONCHANGENOTIFICATION; p.userID = (uint)ClientManager.GetClientID(this); p.payload = scn.Encode().As<PyTuple>(); p.named_payload = new PyDict(); p.named_payload.Set("channel", new PyString("sessionchange")); return p; }
public void UpdateSession(PyPacket from) { Log.Debug("Client", "Updating session for client"); // We should add a Decode method to SessionChangeNotification... PyTuple payload = from.payload; PyDict changes = payload[0].As<PyTuple>()[1].As<PyTuple>()[0].As<PyDict>(); // Update our local session foreach(PyString key in changes.Dictionary.Keys) { session.Set(key.Value, changes[key.Value].As<PyTuple>()[1]); } }
public void Run() { while (true) { Thread.Sleep(1); try { byte[] data = new byte[socket.Available]; int bytes = socket.Recv(data); if (bytes == -1) { throw new DisconnectException(); } else if (bytes > 0) { packetizer.QueuePackets(data, bytes); int p = packetizer.ProcessPackets(); for (int i = 0; i < p; i++) { byte[] packet = packetizer.PopItem(); PyObject obj = Unmarshal.Process<PyObject>(packet); if (obj.Type == PyObjectType.ObjectData) { Log.Warning("Node", PrettyPrinter.Print(obj)); PyObjectData item = obj as PyObjectData; if (item.Name == "macho.CallRsp") { PyPacket final = new PyPacket(); if (final.Decode(item) == true) { if (final.dest.type == PyAddress.AddrType.Client) { try { ClientManager.NotifyClient((int)final.userID, obj); } catch (Exception) { Log.Error("Node", "Trying to send a packet to a non-existing client"); } } else if (final.dest.type == PyAddress.AddrType.Node) { NodeManager.NotifyNode((int)final.dest.typeID, obj); } else if (final.dest.type == PyAddress.AddrType.Broadcast) { // This should not be coded like this here, but will do the trick for now // TODO: Add a ClientManager ClientManager.NotifyClients(obj); } } } } else { Log.Error("Node", "Unknown type"); } } } } catch (SocketException ex) { if (ex.ErrorCode != 10035) break; } catch (DisconnectException) { Log.Error("Node", "Node " + NodeManager.GetNodeID(this) + " disconnected"); break; } catch (Exception) { } } }
private void Send(PyPacket packet) { Send(packet.Encode()); }
private void SendServer(PyPacket data) { SendServer(data.Encode()); }
private void SendClient(PyPacket data) { SendClient(data.Encode()); }
private PyObject OldHandle(PyObject packet) { // Check for login packets and just forward them if (packet is PyTuple) { // Those are the first packets, sent by both client and server return packet; } else if (packet is PyInt) { // This is only sent by the server return packet; } else if (packet is PyString) { // This is only sent by the server return packet; } else if (packet is PyDict) { // Packet sent by the client(HandshakeAck) // We need to modify it in order to put our own client address, as it isnt the same as the address that the server sends PyDict handshake = packet as PyDict; PyDict session = handshake.Get("session_init") as PyDict; session.Set("address", new PyString(socket.GetAddress())); handshake.Set("session_init", session); return handshake; } else if (packet is PyObjectEx) // Exceptions... just check the type and decide what to do { PyException exception = new PyException(); if (exception.Decode(packet) == true) // Ignore the error { Log.Debug("Exceptions", "Got exception of type " + exception.exception_type); } return packet; } else // Normal packets { PyPacket p = new PyPacket(); if (p.Decode(packet) == false) { // Big problem here, we dont know who to send this Log.Error("Client", "Cannot decode PyPacket"); } else { return HandlePyPacket(p); } return packet; } }
private PyObject HandlePyPacket(PyPacket data) { // Just forward it if we dont want to look for a specific one if (data.dest.type == PyAddress.AddrType.Client) { // Look for SessionChangeNotifications if (data.type == Macho.MachoNetMsg_Type.SESSIONCHANGENOTIFICATION) { // Search for address change in session PyTuple payload = data.payload; PyDict session = payload.Items[0].As<PyTuple>().Items[1].As<PyDict>(); if (session.Contains("address") == true) { PyTuple address = session.Get("address").As<PyTuple>(); address[0] = new PyString(socket.GetAddress()); address[1] = new PyString(socket.GetAddress()); session.Set("address", address); } payload.Items[0].As<PyTuple>().Items[1] = session; data.payload = payload; } // SendClient(data); } else if (data.dest.type == PyAddress.AddrType.Node) { // SendServer(data); } else if (data.dest.type == PyAddress.AddrType.Broadcast) { // What to do now ? Log.Error("Client", "Broadcast packets not supported yet"); // throw new NotImplementedException("Broadcast packets are not supported yet"); } return data.Encode(); }
public void ReceiveClientAsync(IAsyncResult ar) { try { AsyncState state = (AsyncState)(ar.AsyncState); int bytes = Socket.Socket.EndReceive(ar); packetizer.QueuePackets(state.buffer, bytes); int p = packetizer.ProcessPackets(); for (int i = 0; i < p; i++) { byte[] actual = packetizer.PopItem(); PyObject obj = Unmarshal.Process<PyObject>(actual); if (obj == null) { continue; } if (obj is PyObjectEx) { // PyException Log.Error("Client", "Got exception from client"); } else { PyPacket packet = new PyPacket(); if (packet.Decode(obj) == false) { Log.Error("Client", "Error decoding PyPacket"); } else { if (packet.dest.type == PyAddress.AddrType.Node) { if (packet.source.type != PyAddress.AddrType.Client) { Log.Error("Client", string.Format("Wrong source data, expected client but got {0}", packet.source.type)); } // Notify the node, be careful here, the client will be able to send packets to game clients if (packet.dest.typeID == 0xFFAA) { Log.Warning("Client", "Sending packet to proxy"); ConnectionManager.NotifyNode((int)(packet.dest.typeID), obj); } else { ConnectionManager.NotifyNode((int)(packet.dest.typeID), obj); } } } } } Socket.Socket.BeginReceive(state.buffer, 0, 8192, SocketFlags.None, recvAsync, state); } catch (ObjectDisposedException) { Log.Debug("Client", "Disconnected"); ConnectionManager.RemoveConnection(this); } catch (SocketException) { Log.Debug("Client", "Disconnected"); ConnectionManager.RemoveConnection(this); } catch (Exception ex) { Log.Error("Client", "Caught unhandled exception: " + ex.ToString()); } }
private void Run() { try { while (true) { Thread.Sleep(1); byte[] data = new byte[socket.Available]; int bytes = 0; try { bytes = socket.Recv(data); } catch (SocketException ex) { if (ex.ErrorCode != 10035) throw new DisconnectException(); } catch (Exception) { throw new DisconnectException(); } if (bytes == -1) // Client disconnected { throw new DisconnectException(); } else if (bytes > 0) { packetizer.QueuePackets(data, bytes); int p = packetizer.ProcessPackets(); byte[] actual = null; for (int i = 0; i < p; i++) { actual = packetizer.PopItem(); PyObject obj = Unmarshal.Process<PyObject>(actual); if (obj is PyObjectEx) { // PyException Log.Error("Client", "Got exception from client"); } else { PyPacket packet = new PyPacket(); if (packet.Decode(obj) == false) { Log.Error("Client", "Error decoding PyPacket"); } else { // Get the node ID to send if (packet.dest.type == PyAddress.AddrType.Node) { if (packet.dest.typeID == 1) { packet.dest.typeID = (ulong)nodeID; // We dont want to receive packets in the proxy } if (packet.source.type != PyAddress.AddrType.Client) { Log.Error("Client", string.Format("Wrong source data, expected client but got {0}", packet.source.type)); } Log.Warning("Client", PrettyPrinter.Print(packet.Encode())); if (NodeManager.NotifyNode((int)packet.dest.typeID, obj) == false) { // We cant send the data to the node, what to do? Log.Error("Client", "Trying to send a packet to a non-existing node"); throw new DisconnectException(); } } } } } } } } catch (ThreadAbortException) { } catch (DisconnectException) { } catch (Exception ex) { Log.Error("Client", "Unhandled exception... " + ex.Message); Log.Error("ExceptionHandler", "Stack trace: " + ex.StackTrace); } // We should notify our node about this Log.Error("Client", "Client disconnected"); socket.Close(); ClientManager.RemoveClient(this); }
public PyObject SetSessionChangeDestination(PyPacket p, int node) { // The session change info should never come from the client p.source.type = PyAddress.AddrType.Node; p.source.typeID = (ulong)1; p.source.callID = 0; p.dest.type = PyAddress.AddrType.Node; p.dest.typeID = (ulong)node; p.dest.callID = 0; return p.Encode(); }
public PyObject SetSessionChangeDestination(PyPacket p) { p.source.type = PyAddress.AddrType.Node; p.source.typeID = (ulong)nodeID; p.source.callID = 0; p.dest.type = PyAddress.AddrType.Client; p.dest.typeID = (ulong)ClientManager.GetClientID(this); p.dest.callID = 0; return p.Encode(); }
public static void HandlePacket(object input) { PyPacket packet = (PyPacket)input; PyPacket res = new PyPacket(); if (packet.type == Macho.MachoNetMsg_Type.CALL_REQ) { PyTuple callInfo = packet.payload.As<PyTuple>().Items[0].As<PyTuple>()[1].As<PySubStream>().Data.As<PyTuple>(); string call = callInfo.Items[1].As<PyString>().Value; PyTuple args = callInfo.Items[2].As<PyTuple>(); PyDict sub = callInfo.Items[3].As<PyDict>(); if (Program.SvcMgr.FindService(packet.dest.service) == false) { Log.Error("Client", "Cannot find service " + packet.dest.service + " to call " + call); return; } if (Program.SvcMgr.GetService(packet.dest.service).FindServiceCall(call) == false) { Log.Error("Client", "Service " + packet.dest.service + " doesnt contains a call to " + call); return; } PyObject callRes = Program.SvcMgr.Call(packet.dest.service, call, args, null); if (callRes == null) { return; } if (callRes.Type == PyObjectType.Tuple) { res.type_string = "macho.CallRsp"; res.type = Macho.MachoNetMsg_Type.CALL_RSP; res.source = packet.dest; res.dest.type = PyAddress.AddrType.Client; res.dest.typeID = (ulong)clients[packet.userID].GetAccountID(); res.dest.callID = packet.source.callID; res.userID = (uint)clients[packet.userID].GetAccountID(); res.payload = new PyTuple(); res.payload.Items.Add(new PySubStream(callRes)); Send(res.Encode()); } } else if (packet.type == Macho.MachoNetMsg_Type.SESSIONCHANGENOTIFICATION) { Log.Debug("Main", "Updating session for client " + packet.userID); // Check if the client isnt assigned to this node yet if(clients.ContainsKey(packet.userID) == false) { Client cli = new Client(); clients.Add(packet.userID, cli); } // Update client session clients[packet.userID].UpdateSession(packet); } }
static void Main(string[] args) { Log.Init("evesharp"); Log.Info("Main", "Starting node..."); Log.Trace("Database", "Connecting to database..."); if (Database.Database.Init() == false) { Log.Error("Main", "Cannot connect to database"); while (true) ; } /* DBRowDescriptor descriptor = new DBRowDescriptor(); descriptor.AddColumn("itemID", FieldType.I4); descriptor.AddColumn("custominfo", FieldType.Str); PyPackedRow packed = new PyPackedRow(descriptor); packed.SetValue("itemID", new PyInt(500)); packed.SetValue("custominfo", new PyString("hello world")); byte[] marshaled = Marshal.Marshal.Process(packed); PyPackedRow unmarshaled = Unmarshal.Process<PyPackedRow>(marshaled); Console.WriteLine(PrettyPrinter.Print(unmarshaled)); */ byte[] raw = new byte[] { 1, 0, 55, 1, 22, 33, 0, 33, 25, 33, 14, 0, 0, 25, 45 }; MemoryStream output = new MemoryStream(raw); BinaryReader reader = new BinaryReader(output); MemoryStream stream = new MemoryStream(); BinaryWriter streamWriter = new BinaryWriter(stream); BinaryReader streamReader = new BinaryReader(stream); PyPackedRow.ZeroCompress(reader, output, streamWriter); byte[] compressed = stream.ToArray(); stream.Seek(0, SeekOrigin.Begin); byte[] uncompress = PyPackedRow.LoadZeroCompressed(streamReader); while (true) Thread.Sleep(1); /* SHA1 sha1 = SHA1.Create(); byte[] hash = sha1.ComputeHash(Encoding.ASCII.GetBytes("password")); char[] strHash = new char[20]; for (int i = 0; i < 20; i++) { strHash[i] = (char)hash[i]; } string str = new string(strHash); Database.Database.Query("INSERT INTO account(accountID, accountName, password, role, online, banned)VALUES(NULL, 'Username', '" + str + "', 2, 0, 0);"); */ Log.Info("Main", "Connection to the DB sucessfull"); Log.Trace("Main", "Registering services..."); SvcMgr.AddService(new Services.Network.machoNet()); SvcMgr.AddService(new Services.Network.alert()); SvcMgr.AddService(new Services.CacheSvc.objectCaching()); Log.Info("Main", "Done"); Log.Info("Main", "Connecting to proxy..."); proxyConnection = new TCPSocket(ushort.Parse(proxy[0, 1]), false); if (proxyConnection.Connect(proxy[0, 0]) == false) { Log.Error("Main", "Cannot connect to proxy. Halting"); Database.Database.Stop(); while (true) ; } Log.Trace("Main", "Server started"); while (true) { Thread.Sleep(1); try { byte[] data = new byte[proxyConnection.Available]; int bytes = proxyConnection.Recv(data); if (bytes == -1) { // Proxy is closing, shutdown the node break; } else if (bytes > 0) { packetizer.QueuePackets(data, bytes); int p = packetizer.ProcessPackets(); for (int i = 0; i < p; i++) { byte[] packet = packetizer.PopItem(); PyObject obj = Unmarshal.Process<PyObject>(packet); if (obj is PyObjectData) { PyObjectData info = obj as PyObjectData; if (info.Name == "machoNet.nodeInfo") { // Update our local info NodeInfo nodeinfo = new NodeInfo(); if (nodeinfo.Decode(info) == true) { nodeID = nodeinfo.nodeID; SystemManager.LoadSolarSystems(nodeinfo.solarSystems); } } else { // Client packet PyPacket clientpacket = new PyPacket(); if (clientpacket.Decode(info) == false) { Log.Error("Main", "Unknown packet"); } else { // Something similar to Async calls new Thread(new ParameterizedThreadStart(HandlePacket)).Start(clientpacket); } } } else if (obj is PyChecksumedStream) // Checksumed packets { PyPacket clientpacket = new PyPacket(); if (clientpacket.Decode(obj) == false) { Log.Error("Main", "Cannot decode packet"); } else { new Thread(new ParameterizedThreadStart(HandlePacket)).Start(clientpacket); } } else if (obj is PyTuple) { // The only tuple packet is the LowLevelVersionExchange LowLevelVersionExchange ex = new LowLevelVersionExchange(); if (ex.Decode(obj) == false) { Log.Error("Main", "LowLevelVersionExchange error"); } // Reply with the node LowLevelVersionExchange LowLevelVersionExchange reply = new LowLevelVersionExchange(); reply.codename = Common.Constants.Game.codename; reply.birthday = Common.Constants.Game.birthday; reply.build = Common.Constants.Game.build; reply.machoVersion = Common.Constants.Game.machoVersion; reply.version = Common.Constants.Game.version; reply.region = Common.Constants.Game.region; Send(reply.Encode(true)); } else if (obj is PyObjectEx) { Log.Error("PyObjectEx", PrettyPrinter.Print(obj)); } else { Log.Error("Main", PrettyPrinter.Print(obj)); Log.Error("Main", "Unhandled packet type"); } } } } catch (Exception) { } } /* Code to ADD an account: SHA1 sha1 = SHA1.Create(); byte[] hash = sha1.ComputeHash(Encoding.ASCII.GetBytes("password")); char[] strHash = new char[20]; for (int i = 0; i < 20; i++) { strHash[i] = (char)hash[i]; } string str = new string(strHash); Database.Database.Query("INSERT INTO account(accountID, accountName, password, role, online, banned)VALUES(NULL, 'Username', '" + str + "', 2, 0, 0);"); */ }
public void ReceiveNodeAsync(IAsyncResult ar) { try { AsyncState state = (AsyncState)(ar.AsyncState); int bytes = Socket.Socket.EndReceive(ar); packetizer.QueuePackets(state.buffer, bytes); int p = packetizer.ProcessPackets(); for (int i = 0; i < p; i++) { byte[] packet = packetizer.PopItem(); PyObject obj = Unmarshal.Process<PyObject>(packet); if (obj == null) { Log.Debug("Node", "Null packet received"); continue; } if ((obj is PyObjectData) == false) { Log.Debug("Node", "Non-valid node packet. Dropping"); continue; } PyObjectData item = obj as PyObjectData; if (item.Name == "macho.CallRsp") { PyPacket final = new PyPacket(); if (final.Decode(item) == false) { Log.Error("Node", "Cannot decode packet"); continue; } if (final.dest.type == PyAddress.AddrType.Client) { ConnectionManager.NotifyClient((int)(final.userID), obj); } else if (final.dest.type == PyAddress.AddrType.Node) { ConnectionManager.NotifyNode((int)(final.dest.typeID), obj); } else if (final.dest.type == PyAddress.AddrType.Broadcast) { Log.Error("Node", "Broadcast packets not supported yet"); } // TODO: Handle Broadcast packets } else { Log.Error("Node", string.Format("Wrong packet name: {0}", item.Name)); } } Socket.Socket.BeginReceive(state.buffer, 0, 8192, SocketFlags.None, recvAsync, state); } catch (ObjectDisposedException) { Log.Debug("Node", "Disconnected"); ConnectionManager.RemoveConnection(this); } catch (SocketException) { Log.Debug("Node", "Disconnected"); ConnectionManager.RemoveConnection(this); } catch (Exception ex) { Log.Error("Node", "Caught unhandled exception: " + ex.ToString()); } }
static void Main(string[] args) { Log.Init("evesharp"); Log.Info("Main", "Starting node..."); Log.Trace("Database", "Connecting to database..."); if (Database.Database.Init() == false) { Log.Error("Main", "Cannot connect to database"); while (true) ; } /* SHA1 sha1 = SHA1.Create(); byte[] hash = sha1.ComputeHash(Encoding.ASCII.GetBytes("password")); char[] strHash = new char[20]; for (int i = 0; i < 20; i++) { strHash[i] = (char)hash[i]; } string str = new string(strHash); Database.Database.Query("INSERT INTO account(accountID, accountName, password, role, online, banned)VALUES(NULL, 'Username', '" + str + "', 2, 0, 0);"); */ Log.Info("Main", "Connection to the DB sucessfull"); Log.Info("Main", "Generating default cache data"); Cache.GenerateCache(); Log.Debug("Main", "Done"); Log.Info("Main", "Connecting to proxy..."); proxyConnection = new TCPSocket(ushort.Parse(proxy[0, 1]), false); if (proxyConnection.Connect(proxy[0, 0]) == false) { Log.Error("Main", "Cannot connect to proxy. Halting"); Database.Database.Stop(); while (true) ; } Log.Trace("Main", "Server started"); while (true) { Thread.Sleep(1); try { byte[] data = new byte[proxyConnection.Available]; int bytes = proxyConnection.Recv(data); if (bytes == -1) { // Proxy is closing, shutdown the node break; } else if (bytes > 0) { packetizer.QueuePackets(data, bytes); int p = packetizer.ProcessPackets(); for (int i = 0; i < p; i++) { byte[] packet = packetizer.PopItem(); PyObject obj = Unmarshal.Process<PyObject>(packet); if (obj is PyObjectData) { PyObjectData info = obj as PyObjectData; if (info.Name == "machoNet.nodeInfo") { // Update our local info NodeInfo nodeinfo = new NodeInfo(); if (nodeinfo.Decode(info) == true) { nodeID = nodeinfo.nodeID; Log.Debug("Main", "Found machoNet.nodeInfo, our new node id is " + nodeID.ToString("X4")); SystemManager.LoadSolarSystems(nodeinfo.solarSystems); } } else { // Client packet PyPacket clientpacket = new PyPacket(); if (clientpacket.Decode(info) == false) { Log.Error("Main", "Unknown packet"); } else { // Something similar to Async calls new Thread(new ParameterizedThreadStart(HandlePacket)).Start(clientpacket); } } } else if (obj is PyChecksumedStream) // Checksumed packets { PyPacket clientpacket = new PyPacket(); if (clientpacket.Decode(obj) == false) { Log.Error("Main", "Cannot decode packet"); } else { new Thread(new ParameterizedThreadStart(HandlePacket)).Start(clientpacket); } } else if (obj is PyTuple) { // The only tuple packet is the LowLevelVersionExchange LowLevelVersionExchange ex = new LowLevelVersionExchange(); if (ex.Decode(obj) == false) { Log.Error("Main", "LowLevelVersionExchange error"); } // Reply with the node LowLevelVersionExchange LowLevelVersionExchange reply = new LowLevelVersionExchange(); reply.codename = Common.Constants.Game.codename; reply.birthday = Common.Constants.Game.birthday; reply.build = Common.Constants.Game.build; reply.machoVersion = Common.Constants.Game.machoVersion; reply.version = Common.Constants.Game.version; reply.region = Common.Constants.Game.region; Send(reply.Encode(true)); } else if (obj is PyObjectEx) { Log.Error("PyObjectEx", PrettyPrinter.Print(obj)); } else { Log.Error("Main", PrettyPrinter.Print(obj)); Log.Error("Main", "Unhandled packet type"); } } } } catch (Exception) { } } /* Code to ADD an account: SHA1 sha1 = SHA1.Create(); byte[] hash = sha1.ComputeHash(Encoding.ASCII.GetBytes("password")); char[] strHash = new char[20]; for (int i = 0; i < 20; i++) { strHash[i] = (char)hash[i]; } string str = new string(strHash); Database.Database.Query("INSERT INTO account(accountID, accountName, password, role, online, banned)VALUES(NULL, 'Username', '" + str + "', 2, 0, 0);"); */ }
public static void HandlePacket(object input) { PyPacket packet = (PyPacket)input; PyPacket res = new PyPacket(); if (packet.type == Macho.MachoNetMsg_Type.CALL_REQ) { PyTuple callInfo = packet.payload.As<PyTuple>().Items[0].As<PyTuple>()[1].As<PySubStream>().Data.As<PyTuple>(); string call = callInfo.Items[1].As<PyString>().Value; PyTuple args = callInfo.Items[2].As<PyTuple>(); PyDict sub = callInfo.Items[3].As<PyDict>(); PyObject callRes = null; try { callRes = Program.SvcMgr.ServiceCall(packet.dest.service, call, args, null); } catch (ServiceDoesNotContainCallException) { Log.Error("HandlePacket", "The service " + packet.dest.service + " does not contain a definition for " + call); } catch (ServiceDoesNotExistsException) { Log.Error("HandlePacket", "The requested service(" + packet.dest.service + ")does not exists"); } catch (Exception ex) { Log.Error("HandlePacket", "Unhadled exception: " + ex.ToString()); } if (callRes == null) { return; } if (callRes.Type == PyObjectType.Tuple) { res.type_string = "macho.CallRsp"; res.type = Macho.MachoNetMsg_Type.CALL_RSP; res.source = packet.dest; res.dest = packet.source; /* res.dest.type = PyAddress.AddrType.Client; res.dest.typeID = (ulong)clients[packet.userID].AccountID; res.dest.callID = packet.source.callID; */ res.userID = packet.userID; res.payload = new PyTuple(); res.payload.Items.Add(new PySubStream(callRes)); Send(res.Encode()); } } else if (packet.type == Macho.MachoNetMsg_Type.SESSIONCHANGENOTIFICATION) { Log.Debug("Main", "Updating session for client " + packet.userID); // Check if the client isnt assigned to this node yet if(clients.ContainsKey(packet.userID) == false) { Client cli = new Client(); clients.Add(packet.userID, cli); } // Update client session clients[packet.userID].UpdateSession(packet); } }
public PyPacket CreateEmptySessionChange() { // Fill all the packet data, except the dest/source SessionChangeNotification scn = new SessionChangeNotification(); scn.changes = Session.EncodeChanges(); if (scn.changes.Dictionary.Count == 0) { // Nothing to do return null; } Dictionary<int, Connection> nodes = ConnectionManager.Nodes; // Add all the nodeIDs foreach (KeyValuePair<int, Connection> node in nodes) { scn.nodesOfInterest.Items.Add(new PyInt(node.Key)); } PyPacket p = new PyPacket(); p.type_string = "macho.SessionChangeNotification"; p.type = Macho.MachoNetMsg_Type.SESSIONCHANGENOTIFICATION; p.userID = (uint)AccountID; p.payload = scn.Encode().As<PyTuple>(); p.named_payload = new PyDict(); p.named_payload.Set("channel", new PyString("sessionchange")); return p; }