changed some grid code to be easier to manipulate

This commit is contained in:
Faraphel 2023-03-05 11:32:36 +01:00
parent 8048a3d43b
commit 5bdffd40de
36 changed files with 247 additions and 381 deletions

2
.gitignore vendored
View file

@ -137,3 +137,5 @@ dmypy.json
/.idea/inspectionProfiles/Project_Default.xml
/.idea/Projet_S6.iml
/.idea/vcs.xml
/.save/

View file

@ -1,227 +0,0 @@
{
"grid_ally": {
"columns": 8,
"rows": 8,
"boats": [
[
{
"length": 5,
"orientation": "H"
},
[
0,
0
]
],
[
{
"length": 4,
"orientation": "V"
},
[
1,
2
]
],
[
{
"length": 4,
"orientation": "H"
},
[
3,
4
]
],
[
{
"length": 3,
"orientation": "V"
},
[
0,
5
]
],
[
{
"length": 2,
"orientation": "H"
},
[
2,
6
]
]
],
"bombs": [
[
false,
false,
true,
true,
true,
true,
true,
true
],
[
true,
true,
false,
true,
true,
true,
true,
true
],
[
true,
false,
true,
false,
true,
true,
true,
true
],
[
true,
true,
true,
true,
true,
true,
true,
true
],
[
true,
true,
true,
true,
true,
true,
true,
true
],
[
true,
true,
false,
true,
true,
false,
true,
true
],
[
true,
false,
true,
true,
true,
true,
true,
true
],
[
true,
true,
true,
true,
true,
true,
true,
true
]
]
},
"grid_enemy": {
"columns": 8,
"rows": 8,
"boats": [],
"bombs": [
[
true,
false,
true,
true,
true,
false,
true,
true
],
[
true,
true,
true,
true,
true,
true,
true,
true
],
[
false,
false,
false,
false,
true,
true,
false,
true
],
[
true,
true,
true,
true,
true,
true,
true,
true
],
[
true,
true,
false,
true,
true,
true,
true,
true
],
[
true,
true,
true,
true,
true,
true,
true,
true
],
[
true,
true,
true,
true,
true,
true,
true,
true
],
[
true,
true,
true,
true,
true,
true,
true,
true
]
]
}
}

View file

@ -12,13 +12,13 @@ A faire :
- Changer les images, rajouter les fonds, ...
3. Hypothétique :
- Vrai musique
- Vraie musique
- Voir si les event listener intégré à pyglet sont plus pratiques que l'event propagation (?)
- Faire une scène incluant par défaut les boutons "Retour" (?)
Bug :
- /
- Dans de rare cas (souvent en fermant brutalement la fenêtre) le processus ne s'arrête pas
Autre :

View file

Before

Width:  |  Height:  |  Size: 156 B

After

Width:  |  Height:  |  Size: 156 B

View file

Before

Width:  |  Height:  |  Size: 572 B

After

Width:  |  Height:  |  Size: 572 B

View file

Before

Width:  |  Height:  |  Size: 609 B

After

Width:  |  Height:  |  Size: 609 B

View file

Before

Width:  |  Height:  |  Size: 644 B

After

Width:  |  Height:  |  Size: 644 B

View file

Before

Width:  |  Height:  |  Size: 695 B

After

Width:  |  Height:  |  Size: 695 B

View file

Before

Width:  |  Height:  |  Size: 712 B

After

Width:  |  Height:  |  Size: 712 B

View file

Before

Width:  |  Height:  |  Size: 753 B

After

Width:  |  Height:  |  Size: 753 B

View file

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 766 B

View file

Before

Width:  |  Height:  |  Size: 708 B

After

Width:  |  Height:  |  Size: 708 B

View file

Before

Width:  |  Height:  |  Size: 691 B

After

Width:  |  Height:  |  Size: 691 B

View file

Before

Width:  |  Height:  |  Size: 533 B

After

Width:  |  Height:  |  Size: 533 B

View file

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 192 B

View file

Before

Width:  |  Height:  |  Size: 418 B

After

Width:  |  Height:  |  Size: 418 B

View file

Before

Width:  |  Height:  |  Size: 339 B

After

Width:  |  Height:  |  Size: 339 B

View file

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 264 B

View file

Before

Width:  |  Height:  |  Size: 213 B

After

Width:  |  Height:  |  Size: 213 B

View file

Before

Width:  |  Height:  |  Size: 231 B

After

Width:  |  Height:  |  Size: 231 B

View file

Before

Width:  |  Height:  |  Size: 281 B

After

Width:  |  Height:  |  Size: 281 B

View file

Before

Width:  |  Height:  |  Size: 321 B

After

Width:  |  Height:  |  Size: 321 B

View file

Before

Width:  |  Height:  |  Size: 381 B

After

Width:  |  Height:  |  Size: 381 B

View file

Before

Width:  |  Height:  |  Size: 445 B

After

Width:  |  Height:  |  Size: 445 B

View file

Before

Width:  |  Height:  |  Size: 467 B

After

Width:  |  Height:  |  Size: 467 B

View file

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 513 B

View file

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 498 B

View file

Before

Width:  |  Height:  |  Size: 621 B

After

Width:  |  Height:  |  Size: 621 B

View file

@ -13,27 +13,24 @@ class Board:
Boat can be added and bomb can be placed.
"""
__slots__ = ("_columns", "_rows", "_boats", "_bombs")
__slots__ = ("width", "height", "boats", "bombs")
def __init__(
self,
rows: int,
columns: int = None,
boats: dict[Boat, Point2D] = None,
bombs: np.array = None
) -> None:
width: int, height: int = None,
self._rows: int = rows
self._columns: int = rows if columns is None else columns
boats: np.array = None,
bombs: np.array = None) -> None:
# associate the boats to their position
self._boats: dict[Boat, Point2D] = {} if boats is None else boats
self.height: int = width
self.width: int = width if height is None else height
# position that have been shot by a bomb
self._bombs: np.array = np.ones((self._rows, self._columns), dtype=np.bool_) if bombs is None else bombs
# associate the boats and the bombs to array
self.boats: np.array = np.zeros((self.height, self.width), dtype=np.ushort) if boats is None else boats
self.bombs: np.array = np.ones((self.height, self.width), dtype=np.bool_) if bombs is None else bombs
def __repr__(self) -> str:
return f"<{self.__class__.__name__} width={self._columns}, height={self._rows}>"
return f"<{self.__class__.__name__} width={self.width}, height={self.height}>"
def __str__(self) -> str:
return str(self.get_matrice())
@ -46,33 +43,31 @@ class Board:
:raise: InvalidBoatPosition if the boat position is not valid
"""
# get the sum of the boat
boat_mat: np.array = boat.get_matrice()
boat_mat_sum: int = boat_mat.sum()
# get the old board matrice sum
board_mat: np.array = self.get_matrice()
board_mat_sum_old: int = board_mat.sum()
board_matrice = self.boats.copy()
board_matrice_sum_old: int = board_matrice.sum()
board_matrice_max = np.max(board_matrice)
# get the sum of the boat
boat_matrice: np.array = boat.get_matrice(board_matrice_max+1)
boat_matrice_sum: int = boat_matrice.sum()
# add the boat to the board matrice
try: copy_array_offset(boat_mat, board_mat, offset=position)
except ValueError: raise InvalidBoatPosition(boat, position)
try:
copy_array_offset(boat_matrice, board_matrice, offset=position)
except ValueError:
raise InvalidBoatPosition(boat, position)
# get the new board matrice sum
board_mat_sum_new: int = board_mat.sum()
board_matrice_sum_new: int = board_matrice.sum()
# if the sum of the old board plus the boat sum is different from the new board sum,
# then the boat have been incorrectly placed (overlapping, outside of bounds, ...)
if board_mat_sum_old + boat_mat_sum != board_mat_sum_new: raise InvalidBoatPosition(boat, position)
if board_matrice_sum_old + boat_matrice_sum != board_matrice_sum_new:
raise InvalidBoatPosition(boat, position)
# otherwise accept the boat in the boats dict
self._boats[boat] = position
def remove_boat(self, boat: Boat) -> None:
"""
Remove a boat from the boat dict
"""
self._boats.pop(boat)
self.boats = board_matrice
def bomb(self, position: Point2D) -> BombState:
"""
@ -83,16 +78,16 @@ class Board:
# if the bomb is inside the board
x, y = position
if x >= self._columns or y >= self._rows: raise InvalidBombPosition(position)
if x >= self.width or y >= self.height: raise InvalidBombPosition(position)
# if this position have already been shot
if not self._bombs[y, x]: raise PositionAlreadyShot(position)
if not self.bombs[y, x]: raise PositionAlreadyShot(position)
# get the old board matrice
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)
self._bombs[y, x] = False
self.bombs[y, x] = False
# get the new board matrice
board_mat_new = self.get_matrice()
@ -116,42 +111,34 @@ class Board:
def get_matrice(self) -> np.array:
"""
:return: the boat represented as a matrice
:return: the boats and bombs represented as a matrice
"""
board = np.zeros((self._rows, self._columns), dtype=np.ushort)
for index, (boat, position) in enumerate(self._boats.items(), start=1):
# Paste the boat into the board at the correct position.
# The boat is represented by a number representing its order in the boats list
copy_array_offset(boat.get_matrice(value=index), board, offset=position)
board *= self._bombs # Remove the position that have been bombed
return board
return self.boats * self.bombs # Remove the position that have been bombed
def to_json(self) -> dict:
return {
"columns": self._columns,
"rows": self._rows,
"boats": [[boat.to_json(), position] for boat, position in self._boats.items()],
"bombs": self._bombs.tolist()
"columns": self.width,
"rows": self.height,
"boats": [[boat.to_json(), position] for boat, position in self.boats.items()],
"bombs": self.bombs.tolist()
}
@classmethod
def from_json(cls, json_: dict) -> "Board":
return Board(
rows=json_["columns"],
columns=json_["rows"],
width=json_["columns"],
height=json_["rows"],
boats={Boat.from_json(boat_json): tuple(position) for boat_json, position in json_["boats"]},
bombs=np.array(json_["bombs"], dtype=np.bool_)
)
def __copy__(self):
return self.__class__(
rows=self._rows,
columns=self._columns,
boats=self._boats.copy(),
bombs=self._bombs.copy(),
height=self.height,
width=self.width,
boats=self.boats.copy(),
bombs=self.bombs.copy(),
)

View file

@ -25,10 +25,13 @@ class Game(Scene):
boats_length: list,
name_ally: str,
name_enemy: str,
grid_width: int,
grid_height: int,
my_turn: bool,
grid_width: int = None,
grid_height: int = None,
board_ally_data: dict = None,
board_enemy_data: dict = None,
**kwargs):
super().__init__(window, **kwargs)
@ -57,8 +60,9 @@ class Game(Scene):
grid_style=texture.Grid.Style1,
boat_style=texture.Grid.Boat.Style1,
bomb_style=texture.Grid.Bomb.Style1,
rows=self.grid_height, columns=self.grid_width
rows=self.grid_height, columns=self.grid_width,
board_data=board_ally_data
)
def board_ally_ready(widget):
@ -74,8 +78,9 @@ class Game(Scene):
grid_style=texture.Grid.Style1,
boat_style=texture.Grid.Boat.Style1,
bomb_style=texture.Grid.Bomb.Style1,
rows=self.grid_height, columns=self.grid_width
rows=self.grid_height, columns=self.grid_width,
board_data=board_enemy_data
)
def board_enemy_bomb(widget, cell: Point2D):
@ -167,6 +172,11 @@ class Game(Scene):
)
def ask_save(widget, x, y, button, modifiers):
if not (self._boat_ready_ally and self._boat_ready_enemy):
self.chat_new_message("System", "Veuillez poser vos bateaux avant de sauvegarder.")
return
# TODO: Pas spam le bouton
PacketAskSave().send_connection(self.connection)
self.chat_new_message("System", "demande de sauvegarde envoyé.")
@ -201,6 +211,10 @@ class Game(Scene):
self._boat_broken_ally: int = 0
self._boat_broken_enemy: int = 0
if len(boats_length) == 0: # s'il n'y a pas de bateau à placé
self._boat_ready_ally = True # défini l'état de notre planche comme prête
PacketBoatPlaced().send_connection(connection) # indique à l'adversaire que notre planche est prête
self._refresh_turn_text()
# refresh
@ -273,10 +287,35 @@ class Game(Scene):
def to_json(self) -> dict:
return {
"my_turn": self.my_turn,
"grid_ally": self.grid_ally.board.to_json(),
"grid_enemy": self.grid_enemy.board.to_json(),
}
@classmethod
def from_json(cls,
data: dict,
window: "Window",
thread: StoppableThread,
connection: socket.socket,
name_ally: str,
name_enemy: str) -> "Game":
return cls(
window=window,
thread=thread,
connection=connection,
boats_length=[],
name_ally=name_ally,
name_enemy=name_enemy,
my_turn=data["my_turn"],
board_ally_data=data["grid_ally"],
board_enemy_data=data["grid_enemy"]
)
def save(self, value: bool):
self.chat_new_message(
"System",
@ -284,9 +323,12 @@ class Game(Scene):
)
if not value: return
ip_address, _ = self.connection.getpeername()
ip_address, port = self.connection.getpeername()
# Le nom du fichier est l'IP de l'opposent, suivi d'un entier indiquant si c'est à notre tour ou non.
# Cet entier permet aux localhost de toujours pouvoir sauvegarder et charger sans problème.
filename: str = f"{ip_address}-{int(self.my_turn)}.bn-save"
with open(path_save / (ip_address + ".bn-save"), "w", encoding="utf-8") as file:
with open(path_save / filename, "w", encoding="utf-8") as file:
json.dump(self.to_json(), file, ensure_ascii=False, indent=4)
def game_end(self, won: bool):

View file

@ -4,7 +4,6 @@ from .type import Texture, Animation
path = path / "grid"
path_boat = path / "boat"
path_bomb = path / "bomb"
class Grid:
@ -13,16 +12,14 @@ class Grid:
class Boat:
class Style1(Style):
_animation = sorted(
(path_boat / "animation").iterdir(),
key=lambda path: int(path.stem)
)
body = Texture(path_boat / "body.png")
edge = Texture(path_boat / "edge.png")
solo = Texture(path_boat / "solo.png")
class Bomb:
class Style1(Style):
_animation = sorted(
(path_bomb / "animation").iterdir(),
key=lambda path: int(path.stem)
)
missed = Animation([*_animation, path_bomb / "missed.png"], 0.03, False)
touched = Animation([*_animation, path_bomb / "touched.png"], 0.03, False)
missed = Animation([*_animation, path_boat / "missed.png"], 0.03, False)
touched = Animation([*_animation, path_boat / "touched.png"], 0.03, False)

View file

@ -24,12 +24,8 @@ class GameGrid(BoxWidget):
def __init__(self, scene: "Scene",
rows: int,
columns: int,
grid_style: Type[Style],
boat_style: Type[Style],
bomb_style: Type[Style],
x: Distance = 0,
y: Distance = 0,
@ -39,29 +35,36 @@ class GameGrid(BoxWidget):
preview_color: ColorRGB = (150, 255, 150),
boats_length: list[int] = None,
rows: int = None,
columns: int = None,
board_data: dict = None,
**kwargs):
self.cell_sprites: dict[Point2D, "Sprite"] = {}
if (rows is None or columns is None) and board_data is None:
raise ValueError(f"{self.__class__} object need to set rows and columns, or the board_data")
self.cell_sprites: dict[Point2D, tuple["Sprite", hash]] = {}
super().__init__(scene, x, y, width, height)
self.group_cursor = pyglet.graphics.Group(order=1)
self.group_line = pyglet.graphics.Group(order=2)
self.rows = rows
self.columns = columns
# the list of the size of the boats to place
self.boats_length = [] if boats_length is None else sorted(boats_length, reverse=True)
self.preview_color = preview_color
self.board = Board(rows=self.rows, columns=self.columns)
# créer la planche du jeu
self.board = Board(width=rows, height=columns) if board_data is None else Board.from_json(board_data)
self.rows = self.board.height
self.columns = self.board.width
self.orientation: Orientation = Orientation.HORIZONTAL
self._boat_kwargs = dict_filter_prefix("boat_", kwargs)
self._bomb_kwargs = dict_filter_prefix("bomb_", kwargs)
self.grid_style = grid_style
self.boat_style = boat_style
self.bomb_style = bomb_style
self.background = Sprite(
img=grid_style.get("background"),
@ -91,6 +94,7 @@ class GameGrid(BoxWidget):
self.add_listener("on_hover", lambda _, *args: self._refresh_cursor(*args))
self._refresh_size()
self.display_board(self.board)
def get_cell_from_rel(self, rel_x: int, rel_y: int) -> tuple[int, int]:
"""
@ -124,7 +128,7 @@ class GameGrid(BoxWidget):
# sprites
for (x, y), sprite in self.cell_sprites.items():
for (x, y), (sprite, hash_) in self.cell_sprites.items():
# calcul des décalages à cause de la rotation qui est faite par rapport à l'origine de l'image
offset_x = 0 if sprite.rotation <= 90 else self.cell_width
@ -147,7 +151,7 @@ class GameGrid(BoxWidget):
self.cursor.y = self.y + cell_y * self.height / self.rows
self.cursor.width, self.cursor.height = self.cell_size
self.preview_boat((cell_x, cell_y)) # display the previsualisation of the boat on this cell
self.preview_boat((cell_x, cell_y)) # display the preview of the boat on this cell
# function
@ -155,17 +159,28 @@ class GameGrid(BoxWidget):
self.cursor.width, self.cursor.height = 0, 0
def display_board(self, board: Board, preview: bool = False):
self.cell_sprites: dict[Point2D, "Sprite"] = {}
# remplacer par l'utilisation de board.boats ?
matrice = board.get_matrice()
max_boat: int = matrice.max()
matrice = board.boats
max_boat: int = np.max(matrice)
for (y, x), value in np.ndenumerate(matrice):
if value == 0: continue
bombed: bool = not board.bombs[y, x] # cette case a déjà été attaqué si la valeur est "False".
if value == 0 and not bombed:
if (x, y) in self.cell_sprites:
self.cell_sprites.pop((x, y))
continue # ignore s'il n'y a ni bombe, ni bateau.
# calcul de la forme et de la rotation de cette cellule du bateau
form, rotation = (
# bombe
("touched", 0) if bombed and value != 0 else
("missed", 0) if bombed else
# corps
("body", 0) if 0 < y < (self.rows-1) and matrice[y-1, x] == matrice[y+1, x] == value else # colonne
("body", 1) if 0 < x < (self.columns-1) and matrice[y, x-1] == matrice[y, x+1] == value else # ligne
@ -180,17 +195,25 @@ class GameGrid(BoxWidget):
("solo", 0)
)
# si le bateau est le dernier placé et qu'on est en prévisualisation, change sa teinte.
color: ColorRGB = self.preview_color if preview and value == max_boat else (255, 255, 255)
hash_new = hash((form, rotation, color))
sprite_old, hash_old = self.cell_sprites.get((x, y), (None, None))
if hash_old == hash_new:
# si la texture n'a pas changé, ne rafraichi pas le sprite
continue
sprite = Sprite(
img=self.boat_style.get(form),
batch=self.scene.batch,
**self._boat_kwargs
)
sprite.rotation = rotation * 90
sprite.color = color
if preview and value == max_boat: # if in preview and it is the latest boat
sprite.color = self.preview_color # make the image more greenish
self.cell_sprites[(x, y)] = sprite
self.cell_sprites[x, y] = (sprite, hash_new)
self._refresh_size()
@ -208,14 +231,15 @@ class GameGrid(BoxWidget):
Boat(self.boats_length[0], orientation=self.orientation),
cell
)
except InvalidBoatPosition: pass # if the boat can't be placed, ignore
except InvalidBoatPosition:
pass # if the boat can't be placed, ignore
else: # if the boat have been placed
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) # rafraichi l'affichage
def preview_boat(self, cell: Point2D):
if len(self.boats_length) == 0: return
@ -226,23 +250,19 @@ class GameGrid(BoxWidget):
Boat(self.boats_length[0], orientation=self.orientation),
cell
)
except InvalidBoatPosition:
self.display_board(self.board) # if the boat can't be placed, ignore
except InvalidBoatPosition: self.display_board(self.board) # if the boat can't be placed, ignore
else: self.display_board(preview_board, preview=True)
def place_bomb(self, cell: Point2D, force_touched: bool = None) -> BombState:
bomb_state = self.board.bomb(cell)
self.cell_sprites[cell] = Sprite(
img=self.bomb_style.get(
"touched" if (bomb_state.success if force_touched is None else force_touched) else "missed"
),
batch=self.scene.batch,
**self._bomb_kwargs
)
self._refresh_size()
if force_touched is not None:
x, y = cell
self.board.boats[y, x] = int(force_touched)
self.display_board(self.board)
return bomb_state
def on_click_release(self, rel_x: int, rel_y: int, button: int, modifiers: int):

View file

@ -38,7 +38,8 @@ class Image(BoxWidget):
# refresh
def _refresh_size(self):
self.image.x, self.image.y, self.image.width, self.image.height = self.bbox
self.image.x, self.image.y = self.xy
self.image.width, self.image.height = self.size
# event

View file

@ -1,3 +1,4 @@
import json
import socket
from pathlib import Path
from typing import TYPE_CHECKING, Any, Optional
@ -37,17 +38,21 @@ class Client(StoppableThread):
# sauvegarde
# attend que l'hôte indique s'il a trouvé une ancienne sauvegarde
packet_save_found = PacketHaveSaveBeenFound.from_connection(connection)
load_old_save: bool = False
if packet_save_found.value:
# attend que l'hôte indique s'il a trouvé une ancienne sauvegarde
packet_save_found = PacketHaveSaveBeenFound.from_connection(connection).value
if packet_save_found:
# si l'hôte a trouvé une ancienne sauvegarde, vérifier de notre côté également.
path_old_save: Optional[Path] = None
ip_address, _ = connection.getpeername()
for file in path_save.iterdir():
if file.stem == ip_address:
for file in reversed(list(path_save.iterdir())):
# la liste est inversée dans le cas où le fichier est en localhost, afin que l'hôte
# prenne le fichier en -0.bn-save et le client en -1.bn-save
if file.stem.startswith(ip_address):
path_old_save = file
break
@ -63,23 +68,38 @@ class Client(StoppableThread):
while True:
# attend la décision de l'hôte
try:
load_old_save = PacketLoadOldSave.from_connection(connection)
load_old_save = PacketLoadOldSave.from_connection(connection).value
break
except socket.timeout:
if self.stopped: return
print("accept load", load_old_save)
if load_old_save:
if load_old_save.value:
...
# TODO: Charger nos données
# charge la sauvegarde
with open(path_old_save, "r", encoding="utf-8") as file:
save_data = json.load(file)
# paramètres & jeu
settings: Any = PacketSettings.from_connection(connection)
PacketUsername(username=self.username).send_data_connection(connection)
packet_username = PacketUsername.from_connection(connection)
enemy_username = PacketUsername.from_connection(connection).username
if load_old_save:
game_scene = in_pyglet_context(
self.window.set_scene,
scene.Game.from_json, # depuis le fichier json
data=save_data,
thread=self,
connection=connection,
name_ally=self.username,
name_enemy=enemy_username,
)
else:
game_scene = in_pyglet_context(
self.window.set_scene,
scene.Game,
@ -89,7 +109,7 @@ class Client(StoppableThread):
boats_length=settings.boats_length,
name_ally=self.username,
name_enemy=packet_username.username,
name_enemy=enemy_username,
grid_width=settings.grid_width,
grid_height=settings.grid_height,
my_turn=not settings.host_start

View file

@ -1,3 +1,4 @@
import json
import socket
from pathlib import Path
from typing import TYPE_CHECKING, Optional
@ -29,7 +30,7 @@ class Host(StoppableThread):
self.port = port
self.condition_load = Condition()
self.accept_load: Optional[bool] = None
self.accept_load: bool = False
def run(self) -> None:
print("[Serveur] Thread démarré")
@ -55,7 +56,7 @@ class Host(StoppableThread):
path_old_save: Optional[Path] = None
for file in path_save.iterdir(): # cherche une ancienne sauvegarde correspondant à l'ip de l'adversaire
if file.stem == ip_address:
if file.stem.startswith(ip_address):
path_old_save = file
break
@ -64,10 +65,10 @@ class Host(StoppableThread):
if path_old_save is not None:
# si une ancienne sauvegarde a été trouvée, attend que l'adversaire confirme avoir également la save
packet_save_found = PacketHaveSaveBeenFound.from_connection(connection)
packet_save_found = PacketHaveSaveBeenFound.from_connection(connection).value
# si l'adversaire à également la sauvegarde, demande à l'hôte de confirmer l'utilisation de la save
if packet_save_found.value:
if packet_save_found:
from source.gui.scene import GameLoad
in_pyglet_context(self.window.set_scene, GameLoad, thread_host=self)
@ -77,15 +78,32 @@ class Host(StoppableThread):
PacketLoadOldSave(value=self.accept_load).send_data_connection(connection)
if self.accept_load:
...
# TODO: Charger nos données
# paramètres & jeu
# charge la sauvegarde
with open(path_old_save, "r", encoding="utf-8") as file:
save_data = json.load(file)
# paramètres et jeu
self.settings.send_data_connection(connection)
packet_username = PacketUsername.from_connection(connection)
enemy_username = PacketUsername.from_connection(connection).username
PacketUsername(username=self.username).send_data_connection(connection)
if self.accept_load:
game_scene = in_pyglet_context(
self.window.set_scene,
scene.Game.from_json, # depuis le fichier json
data=save_data,
thread=self,
connection=connection,
name_ally=self.username,
name_enemy=enemy_username,
)
else:
game_scene = in_pyglet_context(
self.window.set_scene,
scene.Game,
@ -95,7 +113,7 @@ class Host(StoppableThread):
boats_length=self.settings.boats_length,
name_ally=self.username,
name_enemy=packet_username.username,
name_enemy=enemy_username,
grid_width=self.settings.grid_width,
grid_height=self.settings.grid_height,
my_turn=self.settings.host_start

View file

@ -1,3 +1,4 @@
import builtins
import socket
from typing import Type, Callable
@ -47,9 +48,14 @@ def game_network(
if thread.stopped: return # vérifie si le thread n'est pas censé s'arrêter
except Exception as e:
# TODO: meilleur messages
except Exception as exception:
message: str = "Erreur :\n"
match type(exception):
case builtins.ConnectionResetError:
message += "Perte de connexion avec l'adversaire."
case _:
message += str(exception)
from source.gui.scene import GameError
in_pyglet_context(game_scene.window.set_scene, GameError, text=f"Une erreur est survenu :\n{str(e)}")
print(type(e), e)
in_pyglet_context(game_scene.window.set_scene, GameError, text=message)