home · contact · privacy
Minor client improvements.
[plomrogue2-experiments] / new2 / plomrogue / io.py
1 import queue
2 import threading
3 import inspect
4
5
6
7 class GameIO():
8
9     def __init__(self, game, save_file='savefile'):
10         from plomrogue.parser import Parser
11         self.parser = Parser(game)
12         self.game = game
13         self.save_file = save_file
14         self.servers = []
15
16     def loop(self, q):
17         """Handle commands coming through queue q, run game, send results back."""
18         while True:
19             try:
20                 command, connection_id = q.get(timeout=0.001)
21                 self.handle_input(connection_id, command)
22             except queue.Empty:
23                 self.game.run_tick()
24
25     def start_loop(self):
26         """Start game loop, set up self.queue to communicate with it.
27
28         The game loop works sequentially through game commands received
29         via self.queue from connected servers' clients."""
30         self.queue = queue.Queue()
31         c = threading.Thread(target=self.loop, args=(self.queue,))
32         c.start()
33
34     def start_server(self, port, server_class, certfile=None, keyfile=None):
35         """Start server of server_class in talk with game loop.
36
37         The server communicates with the game loop via self.queue.
38         """
39         if 'certfile' in list(inspect.signature(server_class.__init__).parameters):
40             server = server_class(self.queue, port, certfile=certfile, keyfile=keyfile)
41         else:
42             server = server_class(self.queue, port)
43         self.servers += [server]
44         c = threading.Thread(target=server.serve_forever)
45         c.start()
46
47     def handle_input(self, input_, connection_id=None, god_mode=False):
48         """Process input_ to command grammar, call command handler if found.
49
50         Command handlers that have no connectin_i argument in their
51         signature will only be called if god_mode is set.
52
53         """
54         from plomrogue.errors import GameError, ArgError, PlayError
55         from plomrogue.misc import quote
56
57         def answer(connection_id, msg):
58             if connection_id:
59                 self.send(msg, connection_id)
60             else:
61                 print(msg)
62
63         try:
64             command, args = self.parser.parse(input_)
65             if command is None:
66                 answer(connection_id, 'UNHANDLED_INPUT')
67             else:
68                 if 'connection_id' in list(inspect.signature(command).parameters):
69                     command(*args, connection_id=connection_id)
70                 elif god_mode:
71                     command(*args)
72                     #if store and not hasattr(command, 'dont_save'):
73                     #    with open(self.game_file_name, 'a') as f:
74                     #        f.write(input_ + '\n')
75         except ArgError as e:
76             answer(connection_id, 'ARGUMENT_ERROR ' + quote(str(e)))
77         except PlayError as e:
78             answer(connection_id, 'PLAY_ERROR ' + quote(str(e)))
79         except GameError as e:
80             answer(connection_id, 'GAME_ERROR ' + quote(str(e)))
81
82     def send(self, msg, connection_id=None):
83         """Send message msg to servers' client(s).
84
85         If a specific client is identified by connection_id, only
86         sends msg to that one. Else, sends it to all client sessions.
87
88         """
89         if connection_id:
90             for server in self.servers:
91                  if connection_id in server.clients:
92                     client = server.clients[connection_id]
93                     client.put(msg)
94         else:
95             for c_id in self.game.sessions:
96                 for server in self.servers:
97                     if c_id in server.clients:
98                         client = server.clients[c_id]
99                         client.put(msg)
100                         break