implemented more of the game with the network
This commit is contained in:
parent
972327cdc7
commit
4e376bc009
17 changed files with 327 additions and 66 deletions
4
NOTE.md
4
NOTE.md
|
@ -5,6 +5,8 @@ A faire :
|
||||||
- Faire une scène incluant par défaut les boutons "Retour" (?)
|
- Faire une scène incluant par défaut les boutons "Retour" (?)
|
||||||
- Police d'écriture
|
- Police d'écriture
|
||||||
|
|
||||||
|
- Voir si les event listener intégré à pyglet sont plus pratique que l'event propagation
|
||||||
|
|
||||||
Bug :
|
Bug :
|
||||||
- /
|
- /
|
||||||
|
|
||||||
|
@ -17,4 +19,4 @@ Autre :
|
||||||
|
|
||||||
|
|
||||||
Bonus ultime :
|
Bonus ultime :
|
||||||
- Envoyer la texture de la grille à l'adversaire
|
- Envoyer la texture de la grille à l'adversaire (???)
|
|
@ -81,13 +81,13 @@ class Board:
|
||||||
if x >= self._columns or y >= self._rows: raise InvalidBombPosition(position)
|
if x >= self._columns or y >= self._rows: raise InvalidBombPosition(position)
|
||||||
|
|
||||||
# if this position have already been shot
|
# if this position have already been shot
|
||||||
if not self._bombs[position]: raise PositionAlreadyShot(position)
|
if not self._bombs[y, x]: raise PositionAlreadyShot(position)
|
||||||
|
|
||||||
# get the old board matrice
|
# get the old board matrice
|
||||||
board_mat_old_sum = self.get_matrice().sum()
|
board_mat_old_sum = self.get_matrice().sum()
|
||||||
|
|
||||||
# place the bomb (setting the position to False cause the matrice multiplication to remove the boat if any)
|
# place the bomb (setting the position to False cause the matrice multiplication to remove the boat if any)
|
||||||
self._bombs[position] = False
|
self._bombs[y, x] = False
|
||||||
|
|
||||||
# get the new board matrice
|
# get the new board matrice
|
||||||
board_mat_new = self.get_matrice()
|
board_mat_new = self.get_matrice()
|
||||||
|
|
|
@ -8,3 +8,10 @@ class BombState(Enum):
|
||||||
WON = 3
|
WON = 3
|
||||||
|
|
||||||
ERROR = 10
|
ERROR = 10
|
||||||
|
|
||||||
|
def to_bytes(self) -> bytes:
|
||||||
|
return self.value.to_bytes(1, "big")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, data: bytes):
|
||||||
|
return cls(int.from_bytes(data, "big"))
|
||||||
|
|
|
@ -8,6 +8,8 @@ from source.gui import widget, texture
|
||||||
from source.gui.widget.grid import GameGridAlly, GameGridEnemy
|
from source.gui.widget.grid import GameGridAlly, GameGridEnemy
|
||||||
from source import core
|
from source import core
|
||||||
from source.network.SocketType import SocketType
|
from source.network.SocketType import SocketType
|
||||||
|
from source.network.packet.Bomb import Bomb
|
||||||
|
from source.type import Point2D
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from source.gui.window import Window
|
from source.gui.window import Window
|
||||||
|
@ -53,6 +55,11 @@ class Game(Scene):
|
||||||
boat_batch=self.batch_grid_boat,
|
boat_batch=self.batch_grid_boat,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def board_ally_ready():
|
||||||
|
connection.send(SocketType.BOAT_PLACED.value.to_bytes(1, "big"))
|
||||||
|
|
||||||
|
self.grid_ally.add_listener("on_all_boats_placed", board_ally_ready)
|
||||||
|
|
||||||
self.grid_enemy = self.add_widget(
|
self.grid_enemy = self.add_widget(
|
||||||
GameGridEnemy,
|
GameGridEnemy,
|
||||||
|
|
||||||
|
@ -68,6 +75,12 @@ class Game(Scene):
|
||||||
bomb_batch=self.batch_grid_bomb
|
bomb_batch=self.batch_grid_bomb
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def board_enemy_bomb(cell: Point2D):
|
||||||
|
connection.send(SocketType.BOMB.value.to_bytes(1, "big"))
|
||||||
|
connection.send(Bomb(x=cell[0], y=cell[1]).to_bytes())
|
||||||
|
|
||||||
|
self.grid_enemy.add_listener("on_request_place_bomb", board_enemy_bomb)
|
||||||
|
|
||||||
self.name_ally = self.add_widget(
|
self.name_ally = self.add_widget(
|
||||||
widget.Text,
|
widget.Text,
|
||||||
|
|
||||||
|
@ -119,10 +132,10 @@ class Game(Scene):
|
||||||
self.chat_log = self.add_widget(
|
self.chat_log = self.add_widget(
|
||||||
widget.Text,
|
widget.Text,
|
||||||
|
|
||||||
x=10, y=70, width=0.5,
|
x=10, y=35, width=0.5,
|
||||||
|
|
||||||
text="FARAPHEL - HELLO BILLY\nLEO - HELLO BOLLO",
|
text="",
|
||||||
anchor_x="left", anchor_y="baseline",
|
anchor_x="left",
|
||||||
multiline=True,
|
multiline=True,
|
||||||
|
|
||||||
batch=self.batch_label,
|
batch=self.batch_label,
|
||||||
|
@ -131,7 +144,7 @@ class Game(Scene):
|
||||||
self.chat_input = self.add_widget(
|
self.chat_input = self.add_widget(
|
||||||
widget.Input,
|
widget.Input,
|
||||||
|
|
||||||
x=10, y=10, width=0.5, height=50,
|
x=10, y=10, width=0.5, height=30,
|
||||||
|
|
||||||
style=texture.Button.Style1,
|
style=texture.Button.Style1,
|
||||||
|
|
||||||
|
@ -140,8 +153,14 @@ class Game(Scene):
|
||||||
)
|
)
|
||||||
|
|
||||||
def send_chat():
|
def send_chat():
|
||||||
|
text = self.chat_input.text
|
||||||
|
self.chat_input.text = ""
|
||||||
|
|
||||||
|
self.chat_log.text += "\n" + text
|
||||||
|
self.chat_log.label.y = self.chat_log.y + self.chat_log.label.content_height
|
||||||
|
|
||||||
connection.send(SocketType["CHAT"].value.to_bytes(1, "big"))
|
connection.send(SocketType["CHAT"].value.to_bytes(1, "big"))
|
||||||
connection.send(self.chat_input.text.encode())
|
connection.send(text.encode())
|
||||||
|
|
||||||
self.chat_input.add_listener("on_enter", send_chat)
|
self.chat_input.add_listener("on_enter", send_chat)
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import pyglet
|
import pyglet
|
||||||
import requests
|
|
||||||
|
|
||||||
from source import network
|
|
||||||
from source.gui.scene.abc import Scene
|
|
||||||
from source.gui import widget, texture
|
from source.gui import widget, texture
|
||||||
|
from source.gui.scene import RoomHost
|
||||||
|
from source.gui.scene.abc import Scene
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from source.gui.window import Window
|
from source.gui.window import Window
|
||||||
|
@ -15,16 +14,9 @@ class RoomCreate(Scene):
|
||||||
def __init__(self, window: "Window", **kwargs):
|
def __init__(self, window: "Window", **kwargs):
|
||||||
super().__init__(window, **kwargs)
|
super().__init__(window, **kwargs)
|
||||||
|
|
||||||
"""r = requests.get('https://api.ipify.org')
|
|
||||||
r.raise_for_status()
|
|
||||||
ip_address: str = r.content.decode('utf8')
|
|
||||||
port: int = 52321"""
|
|
||||||
|
|
||||||
ip_address = "127.0.0.1"
|
|
||||||
port = 52321
|
|
||||||
|
|
||||||
self.batch_button_background = pyglet.graphics.Batch()
|
|
||||||
self.batch_label = pyglet.graphics.Batch()
|
self.batch_label = pyglet.graphics.Batch()
|
||||||
|
self.batch_input_background = pyglet.graphics.Batch()
|
||||||
|
self.batch_button_background = pyglet.graphics.Batch()
|
||||||
|
|
||||||
self.back = self.add_widget(
|
self.back = self.add_widget(
|
||||||
widget.Button,
|
widget.Button,
|
||||||
|
@ -38,39 +30,74 @@ class RoomCreate(Scene):
|
||||||
label_batch=self.batch_label
|
label_batch=self.batch_label
|
||||||
)
|
)
|
||||||
|
|
||||||
self.back.add_listener("on_click_release", self.button_back_callback)
|
|
||||||
|
|
||||||
self.label_ip = self.add_widget(
|
|
||||||
widget.Text,
|
|
||||||
|
|
||||||
x=0.5, y=0.55,
|
|
||||||
|
|
||||||
anchor_x="center", anchor_y="center",
|
|
||||||
text=f"Votre IP - {ip_address}:{port}",
|
|
||||||
font_size=20,
|
|
||||||
|
|
||||||
batch=self.batch_label
|
|
||||||
)
|
|
||||||
|
|
||||||
self.description = self.add_widget(
|
|
||||||
widget.Text,
|
|
||||||
|
|
||||||
x=0.5, y=0.45,
|
|
||||||
|
|
||||||
anchor_x="center", anchor_y="center",
|
|
||||||
text="En attente d'un second joueur...",
|
|
||||||
|
|
||||||
batch=self.batch_label
|
|
||||||
)
|
|
||||||
|
|
||||||
self.thread = network.Host(window=self.window, daemon=True, username="Host")
|
|
||||||
self.thread.start()
|
|
||||||
|
|
||||||
def button_back_callback(self, *_):
|
|
||||||
self.thread.stop()
|
|
||||||
from source.gui.scene import MainMenu
|
from source.gui.scene import MainMenu
|
||||||
self.window.set_scene(MainMenu)
|
self.back.add_listener("on_click_release", lambda *_: self.window.set_scene(MainMenu))
|
||||||
|
|
||||||
|
self.add_widget(
|
||||||
|
widget.Text,
|
||||||
|
|
||||||
|
x=0.1, y=0.9,
|
||||||
|
anchor_x="center", anchor_y="center",
|
||||||
|
text=f"Largeur de la grille",
|
||||||
|
|
||||||
|
batch=self.batch_label
|
||||||
|
)
|
||||||
|
|
||||||
|
input_width = self.add_widget(
|
||||||
|
widget.Input,
|
||||||
|
|
||||||
|
x=0.2, y=0.86, width=0.1, height=0.08,
|
||||||
|
|
||||||
|
regex=r"\d+",
|
||||||
|
|
||||||
|
style=texture.Input.Style1,
|
||||||
|
|
||||||
|
label_text="8",
|
||||||
|
|
||||||
|
background_batch=self.batch_input_background,
|
||||||
|
label_batch=self.batch_label
|
||||||
|
)
|
||||||
|
|
||||||
|
self.add_widget(
|
||||||
|
widget.Text,
|
||||||
|
|
||||||
|
x=0.1, y=0.8,
|
||||||
|
anchor_x="center", anchor_y="center",
|
||||||
|
text=f"Longueur de la grille",
|
||||||
|
|
||||||
|
batch=self.batch_label
|
||||||
|
)
|
||||||
|
|
||||||
|
input_height = self.add_widget(
|
||||||
|
widget.Input,
|
||||||
|
|
||||||
|
x=0.2, y=0.76, width=0.1, height=0.08,
|
||||||
|
|
||||||
|
regex=r"\d+",
|
||||||
|
|
||||||
|
style=texture.Input.Style1,
|
||||||
|
|
||||||
|
label_text="8",
|
||||||
|
|
||||||
|
background_batch=self.batch_input_background,
|
||||||
|
label_batch=self.batch_label
|
||||||
|
)
|
||||||
|
|
||||||
|
self.start = self.add_widget(
|
||||||
|
widget.Button,
|
||||||
|
x=lambda widget: widget.scene.window.width - 20 - widget.width, y=20, width=0.2, height=0.1,
|
||||||
|
|
||||||
|
label_text="Continuer",
|
||||||
|
|
||||||
|
style=texture.Button.Style1,
|
||||||
|
|
||||||
|
background_batch=self.batch_button_background,
|
||||||
|
label_batch=self.batch_label
|
||||||
|
)
|
||||||
|
|
||||||
|
self.start.add_listener("on_click_release", lambda *_: self.window.set_scene(RoomHost))
|
||||||
|
|
||||||
def on_draw(self):
|
def on_draw(self):
|
||||||
|
self.batch_input_background.draw()
|
||||||
self.batch_button_background.draw()
|
self.batch_button_background.draw()
|
||||||
self.batch_label.draw()
|
self.batch_label.draw()
|
||||||
|
|
76
source/gui/scene/RoomHost.py
Normal file
76
source/gui/scene/RoomHost.py
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import pyglet
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from source import network
|
||||||
|
from source.gui.scene.abc import Scene
|
||||||
|
from source.gui import widget, texture
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from source.gui.window import Window
|
||||||
|
|
||||||
|
|
||||||
|
class RoomHost(Scene):
|
||||||
|
def __init__(self, window: "Window", **kwargs):
|
||||||
|
super().__init__(window, **kwargs)
|
||||||
|
|
||||||
|
"""r = requests.get('https://api.ipify.org')
|
||||||
|
r.raise_for_status()
|
||||||
|
ip_address: str = r.content.decode('utf8')
|
||||||
|
port: int = 52321"""
|
||||||
|
|
||||||
|
ip_address = "127.0.0.1"
|
||||||
|
port = 52321
|
||||||
|
|
||||||
|
self.batch_button_background = pyglet.graphics.Batch()
|
||||||
|
self.batch_label = pyglet.graphics.Batch()
|
||||||
|
|
||||||
|
self.back = self.add_widget(
|
||||||
|
widget.Button,
|
||||||
|
x=20, y=20, width=0.2, height=0.1,
|
||||||
|
|
||||||
|
label_text="Retour",
|
||||||
|
|
||||||
|
style=texture.Button.Style1,
|
||||||
|
|
||||||
|
background_batch=self.batch_button_background,
|
||||||
|
label_batch=self.batch_label
|
||||||
|
)
|
||||||
|
|
||||||
|
self.back.add_listener("on_click_release", self.button_back_callback)
|
||||||
|
|
||||||
|
self.label_ip = self.add_widget(
|
||||||
|
widget.Text,
|
||||||
|
|
||||||
|
x=0.5, y=0.55,
|
||||||
|
|
||||||
|
anchor_x="center", anchor_y="center",
|
||||||
|
text=f"Votre IP - {ip_address}:{port}",
|
||||||
|
font_size=20,
|
||||||
|
|
||||||
|
batch=self.batch_label
|
||||||
|
)
|
||||||
|
|
||||||
|
self.description = self.add_widget(
|
||||||
|
widget.Text,
|
||||||
|
|
||||||
|
x=0.5, y=0.45,
|
||||||
|
|
||||||
|
anchor_x="center", anchor_y="center",
|
||||||
|
text="En attente d'un second joueur...",
|
||||||
|
|
||||||
|
batch=self.batch_label
|
||||||
|
)
|
||||||
|
|
||||||
|
self.thread = network.Host(window=self.window, daemon=True, username="Host")
|
||||||
|
self.thread.start()
|
||||||
|
|
||||||
|
def button_back_callback(self, *_):
|
||||||
|
self.thread.stop()
|
||||||
|
from source.gui.scene import MainMenu
|
||||||
|
self.window.set_scene(MainMenu)
|
||||||
|
|
||||||
|
def on_draw(self):
|
||||||
|
self.batch_button_background.draw()
|
||||||
|
self.batch_label.draw()
|
|
@ -1,6 +1,7 @@
|
||||||
from .Game import Game
|
from .Game import Game
|
||||||
from .Settings import Settings
|
from .Settings import Settings
|
||||||
from .RoomCreate import RoomCreate
|
from .RoomHost import RoomHost
|
||||||
from .RoomJoin import RoomJoin
|
from .RoomJoin import RoomJoin
|
||||||
|
from .RoomCreate import RoomCreate
|
||||||
|
|
||||||
from .MainMenu import MainMenu
|
from .MainMenu import MainMenu
|
||||||
|
|
|
@ -20,8 +20,8 @@ class Grid:
|
||||||
class Bomb:
|
class Bomb:
|
||||||
class Style1(Style):
|
class Style1(Style):
|
||||||
_animation = sorted(
|
_animation = sorted(
|
||||||
(path_bomb / "animation").iterdir(),
|
(path_bomb / "animation").iterdir(),
|
||||||
key=lambda path: int(path.stem)
|
key=lambda path: int(path.stem)
|
||||||
)
|
)
|
||||||
|
|
||||||
missed = [*_animation, path_bomb / "missed.png"], 0.03, False
|
missed = [*_animation, path_bomb / "missed.png"], 0.03, False
|
||||||
|
|
|
@ -32,6 +32,14 @@ class Text(BoxWidget):
|
||||||
|
|
||||||
self._refresh_size()
|
self._refresh_size()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self):
|
||||||
|
return self.label.text
|
||||||
|
|
||||||
|
@text.setter
|
||||||
|
def text(self, text: str):
|
||||||
|
self.label.text = text
|
||||||
|
|
||||||
def _refresh_size(self):
|
def _refresh_size(self):
|
||||||
self.label.x, self.label.y = self.xy
|
self.label.x, self.label.y = self.xy
|
||||||
self.label.width, self.label.height = self.size
|
self.label.width, self.label.height = self.size
|
||||||
|
|
|
@ -6,7 +6,6 @@ import numpy as np
|
||||||
|
|
||||||
from source.core.enums import Orientation
|
from source.core.enums import Orientation
|
||||||
from source.core.error import InvalidBoatPosition
|
from source.core.error import InvalidBoatPosition
|
||||||
from source.gui import texture
|
|
||||||
from source.gui.sprite import Sprite
|
from source.gui.sprite import Sprite
|
||||||
from source.gui.texture.abc import Style
|
from source.gui.texture.abc import Style
|
||||||
from source.gui.widget.grid.abc import GameGrid
|
from source.gui.widget.grid.abc import GameGrid
|
||||||
|
@ -126,6 +125,8 @@ class GameGridAlly(GameGrid):
|
||||||
|
|
||||||
else: # if the boat have been placed
|
else: # if the boat have been placed
|
||||||
self.boats_length.pop(0) # remove the boat from the list of boat to place
|
self.boats_length.pop(0) # remove the boat from the list of boat to place
|
||||||
|
if len(self.boats_length) == 0:
|
||||||
|
self.trigger_event("on_all_boats_placed")
|
||||||
|
|
||||||
self.display_board(self.board)
|
self.display_board(self.board)
|
||||||
|
|
||||||
|
|
|
@ -40,11 +40,9 @@ class GameGridEnemy(GameGrid):
|
||||||
sprite.width = self.cell_width
|
sprite.width = self.cell_width
|
||||||
sprite.height = self.cell_height
|
sprite.height = self.cell_height
|
||||||
|
|
||||||
def place_bomb(self, cell: Point2D):
|
def place_bomb(self, cell: Point2D, touched: bool):
|
||||||
from random import randint
|
|
||||||
|
|
||||||
self.cell_sprites[cell] = Sprite(
|
self.cell_sprites[cell] = Sprite(
|
||||||
img=self.bomb_style.get("touched" if randint(0, 1) else "missed"),
|
img=self.bomb_style.get("touched" if touched else "missed"),
|
||||||
**self._bomb_kwargs
|
**self._bomb_kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,7 +52,7 @@ class GameGridEnemy(GameGrid):
|
||||||
cell = self.get_cell_from_rel(rel_x, rel_y)
|
cell = self.get_cell_from_rel(rel_x, rel_y)
|
||||||
|
|
||||||
if button == pyglet.window.mouse.LEFT:
|
if button == pyglet.window.mouse.LEFT:
|
||||||
self.place_bomb(cell)
|
self.trigger_event("on_request_place_bomb", cell)
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
self.background.draw()
|
self.background.draw()
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
import socket
|
import socket
|
||||||
|
from queue import Queue
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import pyglet.clock
|
import pyglet.clock
|
||||||
|
|
||||||
|
from source.core.enums import BombState
|
||||||
|
from source.core.error import PositionAlreadyShot, InvalidBombPosition
|
||||||
from source.gui import scene
|
from source.gui import scene
|
||||||
from source.network.SocketType import SocketType
|
from source.network.SocketType import SocketType
|
||||||
|
from source.network.packet.Bomb import Bomb
|
||||||
|
from source.network.packet.PacketBombState import PacketBombState
|
||||||
from source.utils import StoppableThread
|
from source.utils import StoppableThread
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -29,7 +34,13 @@ class Client(StoppableThread):
|
||||||
|
|
||||||
print(f"[Client] Connecté avec {connection}")
|
print(f"[Client] Connecté avec {connection}")
|
||||||
|
|
||||||
pyglet.clock.schedule_once(lambda dt: self.window.set_scene(scene.Game, connection=connection), 0)
|
def create_game_scene(dt: float, queue: Queue):
|
||||||
|
game_scene = self.window.set_scene(scene.Game, connection=connection)
|
||||||
|
queue.put(game_scene)
|
||||||
|
|
||||||
|
queue = Queue()
|
||||||
|
pyglet.clock.schedule_once(create_game_scene, 0, queue)
|
||||||
|
game_scene = queue.get()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
data = None
|
data = None
|
||||||
|
@ -43,7 +54,31 @@ class Client(StoppableThread):
|
||||||
|
|
||||||
socket_type = SocketType(int.from_bytes(data, "big"))
|
socket_type = SocketType(int.from_bytes(data, "big"))
|
||||||
|
|
||||||
print(socket_type)
|
|
||||||
|
|
||||||
match socket_type:
|
match socket_type:
|
||||||
case SocketType.CHAT: print(connection.recv(1024).decode())
|
case SocketType.CHAT: print(connection.recv(1024).decode())
|
||||||
|
case SocketType.BOAT_PLACED: print("adversaire à posé ses bateaux")
|
||||||
|
case SocketType.BOMB:
|
||||||
|
bomb = Bomb.from_bytes(connection.recv(2))
|
||||||
|
|
||||||
|
try: bomb_state = game_scene.grid_ally.board.bomb((bomb.x, bomb.y))
|
||||||
|
except (InvalidBombPosition, PositionAlreadyShot): pass # TODO: gérer les erreurs
|
||||||
|
|
||||||
|
connection.send(SocketType.BOMB_STATE.value.to_bytes(1, "big"))
|
||||||
|
|
||||||
|
packet_bomb_state = PacketBombState(
|
||||||
|
x=bomb.x,
|
||||||
|
y=bomb.y,
|
||||||
|
bomb_state=bomb_state
|
||||||
|
)
|
||||||
|
connection.send(packet_bomb_state.to_bytes())
|
||||||
|
|
||||||
|
case SocketType.BOMB_STATE:
|
||||||
|
packet_bomb_state = PacketBombState.from_bytes(connection.recv(3))
|
||||||
|
|
||||||
|
touched = packet_bomb_state.bomb_state in [BombState.TOUCHED, BombState.SUNKEN, BombState.WON]
|
||||||
|
|
||||||
|
pyglet.clock.schedule_once(
|
||||||
|
lambda dt: game_scene.grid_enemy.place_bomb((packet_bomb_state.x, packet_bomb_state.y),
|
||||||
|
touched),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
import socket
|
import socket
|
||||||
|
from queue import Queue
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import pyglet
|
import pyglet
|
||||||
|
|
||||||
|
from source.core.enums import BombState
|
||||||
|
from source.core.error import InvalidBombPosition, PositionAlreadyShot
|
||||||
from source.gui import scene
|
from source.gui import scene
|
||||||
from source.network.SocketType import SocketType
|
from source.network.SocketType import SocketType
|
||||||
|
from source.network.packet.Bomb import Bomb
|
||||||
|
from source.network.packet.PacketBombState import PacketBombState
|
||||||
from source.utils import StoppableThread
|
from source.utils import StoppableThread
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -38,7 +43,13 @@ class Host(StoppableThread):
|
||||||
|
|
||||||
print(f"[Serveur] Connecté avec {address}")
|
print(f"[Serveur] Connecté avec {address}")
|
||||||
|
|
||||||
pyglet.clock.schedule_once(lambda dt: self.window.set_scene(scene.Game, connection=connection), 0)
|
def create_game_scene(dt: float, queue: Queue):
|
||||||
|
game_scene = self.window.set_scene(scene.Game, connection=connection)
|
||||||
|
queue.put(game_scene)
|
||||||
|
|
||||||
|
queue = Queue()
|
||||||
|
pyglet.clock.schedule_once(create_game_scene, 0, queue)
|
||||||
|
game_scene = queue.get()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
data = None
|
data = None
|
||||||
|
@ -52,7 +63,31 @@ class Host(StoppableThread):
|
||||||
|
|
||||||
socket_type = SocketType(int.from_bytes(data, "big"))
|
socket_type = SocketType(int.from_bytes(data, "big"))
|
||||||
|
|
||||||
print(socket_type)
|
|
||||||
|
|
||||||
match socket_type:
|
match socket_type:
|
||||||
case SocketType.CHAT: print(connection.recv(1024).decode())
|
case SocketType.CHAT: print(connection.recv(1024).decode())
|
||||||
|
case SocketType.BOAT_PLACED: print("adversaire à posé ses bateaux")
|
||||||
|
case SocketType.BOMB:
|
||||||
|
bomb = Bomb.from_bytes(connection.recv(2))
|
||||||
|
|
||||||
|
try: bomb_state = game_scene.grid_ally.board.bomb((bomb.x, bomb.y))
|
||||||
|
except (InvalidBombPosition, PositionAlreadyShot): pass # TODO: gérer les erreurs
|
||||||
|
|
||||||
|
connection.send(SocketType.BOMB_STATE.value.to_bytes(1, "big"))
|
||||||
|
|
||||||
|
packet_bomb_state = PacketBombState(
|
||||||
|
x=bomb.x,
|
||||||
|
y=bomb.y,
|
||||||
|
bomb_state=bomb_state
|
||||||
|
)
|
||||||
|
connection.send(packet_bomb_state.to_bytes())
|
||||||
|
|
||||||
|
case SocketType.BOMB_STATE:
|
||||||
|
packet_bomb_state = PacketBombState.from_bytes(connection.recv(3))
|
||||||
|
|
||||||
|
touched = packet_bomb_state.bomb_state in [BombState.TOUCHED, BombState.SUNKEN, BombState.WON]
|
||||||
|
|
||||||
|
pyglet.clock.schedule_once(
|
||||||
|
lambda dt: game_scene.grid_enemy.place_bomb((packet_bomb_state.x, packet_bomb_state.y),
|
||||||
|
touched),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
|
@ -5,3 +5,4 @@ class SocketType(Enum):
|
||||||
CHAT = 0
|
CHAT = 0
|
||||||
BOAT_PLACED = 1
|
BOAT_PLACED = 1
|
||||||
BOMB = 2
|
BOMB = 2
|
||||||
|
BOMB_STATE = 3
|
||||||
|
|
20
source/network/packet/Bomb.py
Normal file
20
source/network/packet/Bomb.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Bomb:
|
||||||
|
x: int = field()
|
||||||
|
y: int = field()
|
||||||
|
|
||||||
|
def to_bytes(self) -> bytes:
|
||||||
|
return (
|
||||||
|
self.x.to_bytes(1, "big") +
|
||||||
|
self.y.to_bytes(1, "big")
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, data: bytes):
|
||||||
|
return cls(
|
||||||
|
x=int.from_bytes(data[0:1], "big"),
|
||||||
|
y=int.from_bytes(data[1:2], "big"),
|
||||||
|
)
|
6
source/network/packet/Chat.py
Normal file
6
source/network/packet/Chat.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Chat:
|
||||||
|
message: str = field()
|
25
source/network/packet/PacketBombState.py
Normal file
25
source/network/packet/PacketBombState.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
from source.core.enums import BombState
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PacketBombState:
|
||||||
|
x: int = field()
|
||||||
|
y: int = field()
|
||||||
|
bomb_state: BombState = field()
|
||||||
|
|
||||||
|
def to_bytes(self) -> bytes:
|
||||||
|
return (
|
||||||
|
self.x.to_bytes(1, "big") +
|
||||||
|
self.y.to_bytes(1, "big") +
|
||||||
|
self.bomb_state.value.to_bytes()
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bytes(cls, data: bytes):
|
||||||
|
return cls(
|
||||||
|
x=int.from_bytes(data[0:1], "big"),
|
||||||
|
y=int.from_bytes(data[1:2], "big"),
|
||||||
|
bomb_state=BombState.from_bytes(data[2:3])
|
||||||
|
)
|
Loading…
Reference in a new issue