-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathclient_receiver.py
More file actions
119 lines (102 loc) · 4.02 KB
/
client_receiver.py
File metadata and controls
119 lines (102 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
"""
Client receives game state from server and draws it.
"""
import asyncio
import aiohttp
import pyglet
pyglet.options['shadow_window'] = False
import click
from time import monotonic
from util_network import tick_asyncio
from backend import State
from frontend import draw_state, create_window
# How long one state from the log should be displayed (in seconds)
LOG_FRAME_TIME = 0.2
class Receiver:
def __init__(self, hostname):
self.window = None
self.state = None
self.available_robots = None
self.winner_time = 0
self.hostname = hostname
# Log of states to display in the future
self.log_to_play = []
# Starting point of the current animation
self.last_robots = None
# Time at which the current animation started
self.animation_start = 0
def window_draw(self):
"""
Draw the game state (board and robots).
"""
self.window.clear()
animation_pos = (monotonic() - self.animation_start) / LOG_FRAME_TIME
if animation_pos < 0:
animation_pos = 0
if animation_pos > 1:
animation_pos = 1
draw_state(
self.state, self.winner_time, self.available_robots, self.window,
last_robots=self.last_robots, animation_pos=animation_pos,
)
def reset_last_robots(self):
"""Set the starting point of the animation to the current state.
"""
self.last_robots = {robot.name: robot for robot in self.state.robots}
async def tick_log(self):
"""
Set the game state for the first element from the recorded game log
and delete it, meaning effectively play the step.
After the given delay (in seconds), repeat.
"""
while True:
if self.state:
self.reset_last_robots()
if self.log_to_play:
self.animation_start = monotonic()
new_state = self.log_to_play.pop(0)
if new_state == None:
if self.winner_time == 0:
self.winner_time = monotonic()
else:
self.state.robots = self.state.robots_from_dict(new_state)
await asyncio.sleep(LOG_FRAME_TIME)
async def get_game_state(self):
"""
Connect to server and receive messages.
Process information from server.
"""
task = asyncio.create_task(self.tick_log())
async with aiohttp.ClientSession() as session:
async with session.ws_connect('http://' + self.hostname + ':8080/receiver/') as ws:
# for loop is finished when client disconnects from server
async for message in ws:
message = message.json()
if "game_state" in message:
self.state = State.whole_from_dict(message)
self.reset_last_robots()
if self.window is None:
self.window = create_window(self.state, self.window_draw)
if "available_robots" in message:
self.available_robots = self.state.robots_from_dict({"robots": message["available_robots"]})
if 'log' in message:
self.log_to_play.extend(message['log'])
if "winner" in message:
self.state.winners = message["winner"]
self.log_to_play.append(None)
task.cancel()
@click.command()
@click.option("-h", "--hostname", default="localhost",
help="Server's hostname.")
def main(hostname):
receiver = Receiver(hostname)
pyglet.clock.schedule_interval(tick_asyncio, 1/30)
# Schedule the "client" task
# More about Futures - official documentation
# https://docs.python.org/3/library/asyncio-future.html
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
asyncio.ensure_future(receiver.get_game_state())
pyglet.app.run()
if __name__ == "__main__":
main()