import time import threading import socket import handlers import log from httpserver import HTTPServer from outchannel import BufferOverload class Engine(object): def __init__(self, config, game): self.config = config self.game = game self.clients = {} self._quit = False def initialize(self): # XXX cross-references! handlers.CommandPipe.engine = handlers.ClientEventPage.engine = self self.server = server = HTTPServer(self.config, handlers.application) server.engine = self server.initialize() self.game.initialize(self) self.gamethread = gt = threading.Thread(target=self.gameloop) gt.start() def run(self, use_poll=True, timeout=None, count=None): if not self.server: raise SystemError('please initialize first') try: self.server.serve(use_poll=use_poll, timeout=timeout, count=count) except (KeyboardInterrupt, SystemExit): pass except: raise def close(self): self._quit = True while self.gamethread.isAlive(): time.sleep(0.1) self.server.close() def add_client(self, id, client): log.log(log.DEBUG, 'adding client %s' % (id,)) self.clients[int(id)] = client self.game.add_user(id) def del_client(self, id): log.log(log.DEBUG, 'deleting client %s' % (id,)) self.game.del_user(id) client = self.clients.pop(int(id)) client.closed = True def gameloop(self): frametime = 1.0 / self.config.framerate prevtime = time.time() while not self._quit: starttime = time.time() self.update_game(starttime - prevtime) prevtime = starttime timespent = time.time() - starttime if timespent < frametime: time.sleep(frametime - timespent) def update_game(self, timespent): framestates = dict([(id, client.inchannel.pop_state()) for id, client in self.clients.iteritems()]) self.game.calculate_state(framestates, timespent) self.game.handle_changes(framestates, timespent) clientscopy = self.clients.copy() initialized = [] for id, client in clientscopy.iteritems(): if not client.initialized: initialized.append(id) client.initialized = True for command in self.game.get_create_commands(): client.push_command(command) todelete = [] for id, command in self.game.get_frame_commands(): if id == -1: clients = clientscopy.iteritems() elif id == -2: clients = (t for t in clientscopy.iteritems() if t[0] not in initialized) else: clients = [(id, clientscopy[id])] for id, client in clients: try: client.push_command(command.clone()) except BufferOverload: print 'overload for client', client.id # client are sent to that client itself... not a very # charming way to fix it, but not sure of a better one if not client.closed: self.del_client(client.id) if self.server: self.server.poll_next() def __del__(self): del self.game.engine del self.game