Hello everyone,<br><br>I've recently discovered stackless, and it looks ideal for my project (a python MUD). Unfortuantly, I'm still having some trouble wrapping my brain around how, exactly, to use stackless.<br><br>I played around with the chat server on the Example page, but I must confess, I don't quite understand it. When I tried to add a player class to the MUD, I get a:
<br><br>Exception exceptions.RuntimeError: 'maximum recursion depth exceeded' in <bound<br>method Player.__del__ of <Player object at 0x00A9B7B0>> ignored<br><br>error.<br><br>Source code:<br><br>import stackless
<br>import stacklesssocket as socket<br>import traceback<br><br>import mud<br><br>class Entity(object):<br> def __init__(self):<br> <a href="http://self.name">self.name</a> = ''<br> self.description = ''<br>
<br><br>class Player(Entity, socket.stacklesssocket):<br> def __init__(self, clientSocket, clientAddress, name='', description=''):<br> Entity.__init__(self)<br> socket.stacklesssocket.__init__(self, clientSocket)
<br> self.address = clientAddress<br> <br> def close(self):<br> # Notify the server.<br> if self.disconnectChannel is not None:<br> # This will not block. The channel is set to schedule
<br> # receivers and return to the sender immediately.<br> self.disconnectChannel.send(self)<br> self.disconnectChannel = None<br> # Do the standard socket closure handling. But we can't
<br> # call the underlying function as it doesn't exist on the<br> # superclass, and trying to call it there anyway won't get it<br> # routed through getattr.<br> self.dispatcher.close()<br>
<br><br>class World(object):<br> def __init__(self):<br> self.players = {}<br> self.nextConnectionID = 1<br><br> def addPlayer(self, clientSocket, clientAddress):<br> clientSocket.connectionID =
self.nextConnectionID<br> player = Player(clientSocket, clientAddress)<br> self.players[clientSocket.connectionID] = player<br> self.nextConnectionID += 1<br> print "Received connection for player #",
clientSocket.connectionID, "from", clientAddress<br> return player<br> <br> def monitorIncomingConnection(self, player):<br> clientSocket.send("Welcome to a less basic Stackless Python MUD server.\r\n")
<br> try:<br> while clientSocket.connected:<br> clientSocket.send("> ")<br> line = clientSocket.readline()[:-2].strip()<br> words = [ word.strip() for word in
line.split(" ") ]<br> verb = words[0]<br> <br> if verb == "look":<br> clientSocket.send("There are %d users connected:\r\n" % len(infoByConnectionID))
<br> clientSocket.send("Name\tHost\t\tPort\r\n")<br> clientSocket.send("-" * 40 +"\r\n")<br> for clientAddress2, clientSocket2 in infoByConnectionID.itervalues
():<br> clientSocket.send("Unknown\t"+ str(clientAddress2[0]) +"\t"+ str(clientAddress2[1]) +"\r\n")<br> elif verb == "say":<br> line = line[4:]
<br> secondPartyPrefix = "Someone says: "<br> for clientAddress2, clientSocket2 in infoByConnectionID.itervalues():<br> if clientSocket2 is clientSocket:
<br> prefix = "You say: "<br> else:<br> prefix = secondPartyPrefix<br> clientSocket2.send(prefix + "\"%s\"\r\n" % line)
<br> elif verb == "quit":<br> clientSocket.close()<br> elif verb == "help":<br> clientSocket.send("Commands:\r\n")<br> for verb in [ "look", "say", "quit", "help" ]:
<br> clientSocket.send(" "+ verb +"\r\n")<br> else:<br> clientSocket.send("Unknown command. Type 'help' to see a list of available commands.\r\n")
<br> stackless.schedule()<br> except socket.error:<br> print "MonitorIncomingConnection.socket.error"<br> traceback.print_exc()<br> <br> def runServer(self, host, port):
<br> listenSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br> listenSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)<br> listenSocket.bind((host, port))<br> listenSocket.listen
(5)<br> <br> self.disconnectChannel = stackless.channel()<br> self.disconnectChannel.preference = 1<br> stackless.tasklet(self.monitorDisconnections)()<br> <br> print "Accepting connections on", host, port
<br> try:<br> while listenSocket.accepting:<br> clientSocket, clientAddress = listenSocket.accept()<br> clientSocket.disconnectChannel = self.disconnectChannel<br> player =
self.addPlayer(clientSocket, clientAddress)<br> stackless.tasklet(self.monitorIncomingConnection)(player)<br> stackless.schedule()<br> except socket.error:<br> print "RunServer.error
"<br> traceback.print_exc()<br> <br> print "RunServer.exit"<br><br> def monitorDisconnections(self):<br> try:<br> while True:<br> clientSocket =
self.disconnectChannel.receive()<br> print "Received disconnection of #", clientSocket.connectionID, "from", self.players[clientSocket.connectionID].address<br> self.removePlayer
(clientSocket.connectionID)<br> except socket.error:<br> print "MonitorDisconnections.error"<br> traceback.print_exc()<br> print "MonitorDisconnections.exit"<br>
<br> def removePlayer(self, connectionID):<br> del self.players[connectionID]<br><br>if __name__ == "__main__":<br> host = "<a href="http://127.0.0.1">127.0.0.1</a>"<br> port = 3000<br>
<br> socket.managerRunning = True<br> <br> world = World()<br> <br> t = stackless.tasklet(world.runServer)(host, port)<br> t.run()<br> <br> try:<br> socket.ManageSockets()<br> except KeyboardInterrupt:
<br> print "** Detected ctrl-c in the console"<br> except:<br> print "main error"<br> traceback.print_exc()<br> print "EXIT"<br><br><br>What I am trying to do is this:
<br><br>Every character (both player and mob) should be instances of the Player or Character class, and I want a World object to store them all. I want the MUD to be as abstracted from the networking part as possible. I.e
., once the character instance is in the list of players in the World class, I can just call like "character.writeWithPrompt('stuff') or whatnot.<br><br> The instance should have a reference to the network layer so I can send data back out to the connected player (assuming they are a player and not a mob). If there is no network layer (as in the case of a mob), it just catches the exception silently.
<br><br>World is divided into zones, then rooms, etc. I'm planning on zones to have collections of tasklets for rooms, each item to have one, each mob/player to have one.<br><br>This is all just to give you some idea of what I would like to accomplish with the code. Any help would be *greatly* appreciated!
<br><br>Thanks,<br>-Kuros<br>