- def send_to(self, connection_id, msg):
- """Send msg to client of connection_id."""
- self.queues_out[connection_id].put(msg)
-
- def send_all(self, msg):
- """Send msg to all clients."""
- for connection_id in self.queues_out:
- self.send_to(connection_id, msg)
-
- def stringify_yx(self, tuple_):
- """Transform tuple (y,x) into string 'Y:'+str(y)+',X:'+str(x)."""
- return 'Y:' + str(tuple_[0]) + ',X:' + str(tuple_[1])
-
- def quoted(self, string):
- """Quote and escape string so client interprets it as single token."""
- quoted = []
- quoted += ['"']
- for c in string:
- if c in {'"', '\\'}:
- quoted += ['\\']
- quoted += [c]
- quoted += ['"']
- return ''.join(quoted)
-
- def proceed_to_next_player_turn(self, connection_id):
- """Run game world turns until player can decide their next step.
-
- Sends a 'TURN_FINISHED' message, then iterates through all non-player
- things, on each step furthering them in their tasks (and letting them
- decide new ones if they finish). The iteration order is: first all
- things that come after the player in the world things list, then (after
- incrementing the world turn) all that come before the player; then the
- player's .proceed() is run, and if it does not finish his task, the
- loop starts at the beginning. Once the player's task is finished, the
- loop breaks, and client-relevant game data is sent.
- """
- self.send_all('TURN_FINISHED ' + str(self.world.turn))
- while True:
- for thing in self.world.things[self.world.player_i+1:]:
- thing.proceed()
- self.world.turn += 1
- for thing in self.world.things[:self.world.player_i]:
- thing.proceed()
- self.world.player.proceed(is_AI=False)
- if self.world.player.task is None:
- break
- self.send_all('NEW_TURN ' + str(self.world.turn))
- self.send_all('MAP_SIZE ' + self.stringify_yx(self.world.map_size))
- self.send_all('TERRAIN\n' + self.quoted(self.world.map_))
+ def handle_input(self, input_, connection_id=None, store=True):
+ """Process input_ to command grammar, call command handler if found."""
+ from inspect import signature
+
+ def answer(connection_id, msg):
+ if connection_id:
+ self.send(msg, connection_id)
+ else:
+ print(msg)
+
+ try:
+ command = self.parser.parse(input_)
+ if command is None:
+ answer(connection_id, 'UNHANDLED INPUT')
+ else:
+ if 'connection_id' in list(signature(command).parameters):
+ command(connection_id=connection_id)
+ else:
+ command()
+ if store:
+ with open(self.game_file_name, 'a') as f:
+ f.write(input_ + '\n')
+ except parser.ArgError as e:
+ answer(connection_id, 'ARGUMENT ERROR: ' + str(e))
+ except server_.game.GameError as e:
+ answer(connection_id, 'GAME ERROR: ' + str(e))
+
+ def send(self, msg, connection_id=None):
+ if connection_id:
+ self.queues_out[connection_id].put(msg)
+ else:
+ for connection_id in self.queues_out:
+ self.queues_out[connection_id].put(msg)
+
+ def send_gamestate(self, connection_id=None):
+ """Send out game state data relevant to clients."""
+
+ def stringify_yx(tuple_):
+ """Transform tuple (y,x) into string 'Y:'+str(y)+',X:'+str(x)."""
+ return 'Y:' + str(tuple_[0]) + ',X:' + str(tuple_[1])
+
+ def quoted(string):
+ """Quote & escape string so client interprets it as single token."""
+ quoted = []
+ quoted += ['"']
+ for c in string:
+ if c in {'"', '\\'}:
+ quoted += ['\\']
+ quoted += [c]
+ quoted += ['"']
+ return ''.join(quoted)
+
+ self.send('NEW_TURN ' + str(self.world.turn))
+ self.send('MAP_SIZE ' + stringify_yx(self.world.map_size))
+ for y in range(self.world.map_size[0]):
+ width = self.world.map_size[1]
+ terrain_line = self.world.terrain_map[y * width:(y + 1) * width]
+ self.send('TERRAIN_LINE %5s %s' % (y, quoted(terrain_line)))