Toggle Navigation
Hatchery
Eggs
CityControl
backend.py
Users
Badges
Login
Register
backend.py
raw
Content
import uasyncio import uso_client import utils import uso_protocol import lobby import easydraw import static_pages import display import game import main import buttons import mch22 import sys import time import random class GameClient: """SocketIO transport.""" def __init__(self, event_loop, create_game=True, namespace="/", game_code=None): print("Network instance created") self.namespace = namespace self.socketio = uso_client.connect(utils.BACKEND_URL) self.host = create_game self.uid = None self.lobby = None self.game_id = game_code self.loop = event_loop self.joining_game = False self.game_in_progress = False self.current_level = 1 self.instruction_task = None print("After GameClient __init__ run") server = self @self.socketio.on("welcome") async def set_uid_on_welcome(message): server.uid = message["uid"] print("received welcome", message) if self.host: await self.create_game("TestGame", public=False) else: await self.join_game(server.game_id) @self.socketio.on("game_info") async def game_joined(game_info): # Someone else joined if server.lobby: server.lobby.update_game_info(game_info) server.lobby.draw_lobby() else: # We just joined game_code = utils.code_string_to_code(game_info["konami"]) server.lobby = lobby.Lobby(game_code, server.uid, game_info) server.lobby.draw_lobby() server.joining_game = False # No signal ready functionality for now, # so just mark as ready right away await server.ready() @self.socketio.on("game_started") async def call_print_on_game_started(message): print("Game Starting") server.instruction_task = server.loop.create_task( server.instructions_task() ) @self.socketio.on("game_over") async def game_over_screen(message): print("Game Over") await server.exit_game(cancel_socketio_task=False) WIDTH = display.width() - 50 utils.draw_background(logo=False) easydraw.lineCentered( 30, "GAME OVER", utils.ARCADE_FONT[18], utils.TEXT_HIGHLIGHT ) utils.draw_lines( random.choice(utils.GAME_OVER_PRIMARY), y_start=65, vertical_padding=3, width=WIDTH, font=utils.ARCADE_FONT[9], ) utils.draw_lines( random.choice(utils.GAME_OVER_SECONDARY), y_start=100, vertical_padding=3, width=WIDTH, font=utils.ARCADE_FONT[9], ) easydraw.lineCentered( 150, "YOU ACHIEVED:", utils.ARCADE_FONT[8], utils.TEXT_MAIN ) easydraw.lineCentered( 165, "LEVEL %d" % server.current_level, utils.ARCADE_FONT[18], utils.TEXT_HIGHLIGHT, ) utils.draw_lines( "Press MENU to return to the main menu", y_start=195, vertical_padding=3, width=WIDTH, font=utils.ARCADE_FONT[8], ) display.flush() mch22.set_handler(buttons.hwButtons.__callback) @self.socketio.on("player_disconnected") async def connection_lost(message): print("Someone disconnected, game over") await server.player_disconnected() @self.socketio.on("command") async def set_command(command): print("Command received:", command) server.game.update_assignment(command) @self.socketio.on("grid") async def set_grid(grid): if not server.game_in_progress: server.game_in_progress = True server.loop.create_task(server.timer_update_loop()) print("Grid received:", grid) server.game = game.GameState(grid) @self.socketio.on("health_info") async def set_health_on_health_info(message): print("received health_info", message) server.game.update_health_info(message) @self.socketio.on("next_level") async def next_level(message): print("Achieved next level") server.game_in_progress = False server.current_level += 1 # Recap utils.draw_background(logo=False) easydraw.lineCentered( 80, random.choice(utils.LEVEL_TRANSITION_ENCOURAGEMENTS).upper(), utils.ARCADE_FONT[18], utils.TEXT_HIGHLIGHT, ) for i, line in enumerate(random.choice(utils.LEVEL_TRANSITION_NARRATIVES)): easydraw.lineCentered( 120 + i * 20, line.upper(), utils.ARCADE_FONT[12], utils.TEXT_MAIN ) display.flush() await uasyncio.sleep(3) # Prepare utils.draw_background(logo=False) easydraw.lineCentered( 100, f"Level {str(server.current_level)}".upper(), utils.ARCADE_FONT[18], utils.TEXT_HIGHLIGHT, ) easydraw.lineCentered( 135, random.choice(utils.LEVEL_TRANSITION_PREPARE).upper(), utils.ARCADE_FONT[12], utils.TEXT_MAIN, ) display.flush() await uasyncio.sleep(2) await server.intro_done() @self.socketio.on("game_join_fail") async def join_failed(message): if server.joining_game: utils.draw_background() easydraw.lineCentered( 180, "Failed to join game", utils.ARCADE_FONT[12], utils.TEXT_MAIN ) easydraw.lineCentered( 200, "Please try again", utils.ARCADE_FONT[12], utils.TEXT_MAIN ) display.flush() await uasyncio.sleep(3) await server.socketio.close() server.loop.stop() server.loop.close() uasyncio.new_event_loop() mch22.set_handler(buttons.hwButtons.__callback) static_pages.join_lobby_input() self.task = self.loop.create_task(self.receive_event_loop()) async def receive_event_loop(self): print("Starting SocketIO receive_event_loop") await self.socketio.run_forever() async def connect(self, namespace=None): print("Sending connect message") await self.socketio._send_message(uso_protocol.MESSAGE_CONNECT, data=None) async def create_game(self, name, public=False): await self.socketio.emit( "create_game", data={ "name": name, "public": public, }, ) async def instructions_task(self): try: MAIN_FONT = utils.ARCADE_FONT[9] LINE_SPACING = 4 width = display.width() - 50 utils.draw_background(logo=True) easydraw.lineCentered( 160, "Level 1 Starting", utils.ARCADE_FONT[12], utils.TEXT_HIGHLIGHT ) easydraw.lineCentered( 185, "Press START to", utils.ARCADE_FONT[9], utils.TEXT_MAIN ) easydraw.lineCentered( 200, "skip instructions", utils.ARCADE_FONT[9], utils.TEXT_MAIN ) display.flush() await uasyncio.sleep(3) utils.draw_background(logo=False) easydraw.lineCentered( 35, "INSTRUCTIONS", utils.ARCADE_FONT[18], utils.TEXT_HIGHLIGHT ) y = 55 y = utils.draw_lines( "+ Every player has their own unique set of controls", y, LINE_SPACING, width, MAIN_FONT, ) y += 5 y = utils.draw_lines( "+ Every player receives unique instructions", y, LINE_SPACING, width, MAIN_FONT, ) y += 5 y = utils.draw_lines( "+ The player with the control in their city dashboard has to carry out the instruction", y, LINE_SPACING, width, MAIN_FONT, ) y += 5 utils.draw_lines( "+ Instructions have to be carried out within the time limit (top left)", y, LINE_SPACING, width, MAIN_FONT, ) display.flush() await uasyncio.sleep(15) utils.draw_background(logo=False) easydraw.lineCentered( 80, "ARE YOU READY?", utils.ARCADE_FONT[18], utils.TEXT_HIGHLIGHT ) y = utils.draw_lines( "Work as a team to stay ahead of the algorithm", 110, LINE_SPACING, width, utils.ARCADE_FONT[12], ) utils.draw_lines( "Good luck!", y + 10, LINE_SPACING, width, utils.ARCADE_FONT[12] ) display.flush() await uasyncio.sleep(7) finally: # Irrespective of if the task gets cancelled or finishes, # we need to signal intro_done to the server print("Sending intro_done from instructions_task") utils.draw_background(logo=True) easydraw.lineCentered( 170, "Waiting for", utils.ARCADE_FONT[12], utils.TEXT_HIGHLIGHT ) easydraw.lineCentered( 190, "other players...", utils.ARCADE_FONT[12], utils.TEXT_HIGHLIGHT ) display.flush() await self.intro_done() async def join_game(self, konami_code): await self.socketio.emit("join_game", data={"konami": konami_code}) async def ready(self): await self.socketio.emit("ready") async def start_game(self): if self.lobby and self.lobby.can_start: self.lobby.can_start = False await self.socketio.emit("start_game") async def intro_done(self): await self.socketio.emit("intro_done") async def game_button_pressed(self, button): command_data = self.game.handle_button_press(button) if command_data: await self.socketio.emit("command", command_data) else: print("Handled button press, but did not get command data") async def report_exception(self, exception): try: await self.socketio.emit("exception", utils.get_exception_string(exception)) except Exception: print("Failed to report exception") async def timer_update_loop(self): last_ticks = time.ticks_ms() - 1000 while self.game_in_progress: if self.game_in_progress and self.game: try: self.game.trigger_counter() except Exception as exception: print("Failed to update, received exception:") sys.print_exception(exception) await self.report_exception(exception) cur_ticks = time.ticks_ms() drift = time.ticks_diff(cur_ticks, last_ticks) - 1000 ms_to_sleep = 1000 - drift last_ticks = cur_ticks await uasyncio.sleep_ms(ms_to_sleep) async def player_disconnected(self): await self.exit_game(cancel_socketio_task=False) WIDTH = display.width() - 50 utils.draw_background(logo=False) easydraw.lineCentered( 20, "LOST", utils.ARCADE_FONT[18], utils.TEXT_HIGHLIGHT ) easydraw.lineCentered( 40, "CONNECTION", utils.ARCADE_FONT[18], utils.TEXT_HIGHLIGHT ) y = utils.draw_lines( "Someone lost connection to the server or exited the game.", y_start=65, vertical_padding=3, width=WIDTH, font=utils.ARCADE_FONT[12], ) easydraw.lineCentered( y + 20, "YOU ACHIEVED:", utils.ARCADE_FONT[8], utils.TEXT_MAIN ) easydraw.lineCentered( y + 35, "LEVEL %d" % self.current_level, utils.ARCADE_FONT[18], utils.TEXT_HIGHLIGHT, ) utils.draw_lines( "Press MENU to return to the main menu", y_start=195, vertical_padding=3, width=WIDTH, font=utils.ARCADE_FONT[8], ) display.flush() mch22.set_handler(buttons.hwButtons.__callback) async def exit_game(self, cancel_socketio_task=True): self.game_in_progress = False if cancel_socketio_task: self.task.cancel() if self.socketio and self.socketio.websocket.open: await self.socketio.close() self.loop.stop() self.loop.close() uasyncio.new_event_loop()