I have been considering networking options for months, and over the last couple of weeks have had time to explore specific options. I initially made exploratory forays into two disparate implementations: One approach was to write the game logic in ‘inside-out’ form so that everything could be done by callback; the other approach was to put the network code into another process, and pipe data to and from it via os pipes.
The ‘inside-out’ approach would add significant burden to coding the game logic, and was abandoned after an evenings work. The separate process approach was making some headway, but I have put it aside as well, for yet another approach.
What I want(1) is a twisted reactor that can be exited and reentered. I could then use the substantial asset of proven twisted code for various high and low level operations, but use a conventional subroutine-oriented code structure. When an engine needs to exit, it can have the reactor yield to its caller; the caller then follows game logic to set up another engine, which resumes the reactor operation. The timing constraints would be the same as for a call-back, (ie: don’t delay the reactor more than necessary), but the game logic would be more readable and more writable without having to put everything in callbacks.
The usage would be like:
class Engine()
def iterate(self):
# do per frame stuff
if self._done: reactor.release() # yield to engine's caller
else: reactor.callLater(0, self.iterate)
def run(self):
# init stuff
reactor.callLater(0, self.iterate)
if reactor.isRunning(): reactor.resume()
else: reactor.run()
def intro():
# set up intro pages
eng = Engine()
eng.add(intro_pages)
eng.run()
def room(room_context):
eng = Engine()
eng.add(room_context)
eng.run()
return eng.retval
def main():
intro()
# set up lobby context
next = room(lobby_context)
while next != GAME_EXIT:
# set up context for next room
next = room(room_context)
The code is fairly readable, with more specialized function in specialized subroutines. Calls to the engine can be from main(), or from a subroutine a few calls deep.
See my next post for the reactor subclass itself.
1)
OK, what I really want is a file-like connection object:
con = Connection(‘gameserver.org’)
con.write(‘game update data’, game_data)
news = con.read()
check = con.read_non_blocking()
But I am not going to find (or write) that, so I’ll settle for an pause-able reactor.
11 December 2007 at 12:13 pm
[...] Add an option 6. Create a Twisted reactor subclass that can be exited and resumed. See later blogposts here for details. [...]