more comment in all modules (except GUI)
This commit is contained in:
parent
88e89209ac
commit
f6f2e1ed52
32 changed files with 142 additions and 98 deletions
5
NOTE.md
5
NOTE.md
|
@ -1,8 +1,5 @@
|
||||||
A faire :
|
|
||||||
|
|
||||||
|
|
||||||
1. Principal :
|
1. Principal :
|
||||||
- Documenter (Docstring, README, ...)
|
- Documenter (Docstring, ...)
|
||||||
- mode d'emploi (video + pdf) expliquant le fonctionnement
|
- mode d'emploi (video + pdf) expliquant le fonctionnement
|
||||||
|
|
||||||
2. Bonus :
|
2. Bonus :
|
||||||
|
|
7
main.pyw
7
main.pyw
|
@ -6,13 +6,13 @@ from source.gui.scene import MainMenu
|
||||||
from source.gui.window import GameWindow
|
from source.gui.window import GameWindow
|
||||||
|
|
||||||
|
|
||||||
from source.path import path_font
|
from source.path import path_font, path_image
|
||||||
from source.gui.better_pyglet import Label
|
from source.gui.better_pyglet import Label
|
||||||
|
|
||||||
|
|
||||||
# Change la police par défaut utilisé pour le Century Gothic
|
# Change la police par défaut utilisé pour le Century Gothic
|
||||||
pyglet.font.add_directory(path_font)
|
pyglet.font.add_directory(path_font)
|
||||||
Label.default_kwargs["font_name"] = "Century Gothic" # NOQA: Label à un "default_kwargs" avec la metaclass
|
Label.default_kwargs["font_name"] = "Century Gothic"
|
||||||
|
|
||||||
# Créer une nouvelle fenêtre
|
# Créer une nouvelle fenêtre
|
||||||
window = GameWindow(
|
window = GameWindow(
|
||||||
|
@ -21,7 +21,8 @@ window = GameWindow(
|
||||||
option_path=Path("./option.json")
|
option_path=Path("./option.json")
|
||||||
)
|
)
|
||||||
|
|
||||||
try: window.set_icon(pyglet.image.load("./assets/image/icon/icon.png"))
|
# Change l'icône de cette fenêtre
|
||||||
|
try: window.set_icon(pyglet.image.load(path_image / "/icon/icon.png"))
|
||||||
except: pass # NOQA E722
|
except: pass # NOQA E722
|
||||||
|
|
||||||
window.set_minimum_size(720, 480)
|
window.set_minimum_size(720, 480)
|
||||||
|
|
6
setup.py
6
setup.py
|
@ -1,5 +1,7 @@
|
||||||
from cx_Freeze import setup, Executable
|
from cx_Freeze import setup, Executable
|
||||||
|
|
||||||
|
from source.path import path_image, path_assets
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='Bataille Navale',
|
name='Bataille Navale',
|
||||||
description='Bataille Navale',
|
description='Bataille Navale',
|
||||||
|
@ -8,7 +10,7 @@ setup(
|
||||||
|
|
||||||
options={
|
options={
|
||||||
"build_exe": {
|
"build_exe": {
|
||||||
"include_files": ["./assets"],
|
"include_files": [path_assets],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -17,7 +19,7 @@ setup(
|
||||||
executables=[
|
executables=[
|
||||||
Executable(
|
Executable(
|
||||||
"main.pyw",
|
"main.pyw",
|
||||||
icon="./assets/image/icon/icon.ico",
|
icon=path_image / "/icon/icon.ico",
|
||||||
base="win32gui",
|
base="win32gui",
|
||||||
target_name="Bataille Navale.exe",
|
target_name="Bataille Navale.exe",
|
||||||
shortcut_name="Bataille Navale",
|
shortcut_name="Bataille Navale",
|
||||||
|
|
|
@ -3,35 +3,36 @@ from typing import Callable
|
||||||
|
|
||||||
class Listener:
|
class Listener:
|
||||||
"""
|
"""
|
||||||
The Listener can be subclassed to allow the subclass to add, remove and call event easily.
|
Les classes héritant de Listener permettent d'ajouter, retirer et appeler facilement des événements.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
# dictionnaire des événements et de leurs fonctions associées
|
||||||
self._events_listener: dict[str, set[Callable]] = {}
|
self._events_listener: dict[str, set[Callable]] = {}
|
||||||
|
|
||||||
def add_listener(self, name: str, callback: Callable):
|
def add_listener(self, name: str, callback: Callable):
|
||||||
"""
|
"""
|
||||||
Add a function to an event name
|
Ajoute une fonction à un événement
|
||||||
:param name: the name of the event to react
|
:param name: le nom de l'événement
|
||||||
:param callback: the function to call
|
:param callback: la fonction à appeler
|
||||||
"""
|
"""
|
||||||
if name not in self._events_listener: self._events_listener[name] = set()
|
if name not in self._events_listener: self._events_listener[name] = set()
|
||||||
self._events_listener[name].add(callback)
|
self._events_listener[name].add(callback)
|
||||||
|
|
||||||
def remove_listener(self, name: str, callback: Callable):
|
def remove_listener(self, name: str, callback: Callable):
|
||||||
"""
|
"""
|
||||||
Remove a function from an event name
|
Retire une fonction d'un événement
|
||||||
:param name: the event name where to remove the callback
|
:param name: le nom de l'événement
|
||||||
:param callback: the callback function to remove
|
:param callback: la fonction à retirer
|
||||||
"""
|
"""
|
||||||
self._events_listener[name].remove(callback)
|
self._events_listener[name].remove(callback)
|
||||||
|
|
||||||
def trigger_event(self, name: str, *args, **kwargs):
|
def trigger_event(self, name: str, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Call all the callback attached to an event
|
Appelle les fonctions associées à un événement
|
||||||
:param name: the name of the event to call
|
:param name: le nom de l'événement
|
||||||
:param args: the args of the callbacks
|
:param args: les arguments des fonctions
|
||||||
:param kwargs: the kwargs of the callbacks
|
:param kwargs: les arguments à clé des fonctions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# .copy() pour que si le listener supprime un de ses événements, la liste de la boucle de change pas de taille
|
# .copy() pour que si le listener supprime un de ses événements, la liste de la boucle de change pas de taille
|
||||||
|
|
|
@ -3,5 +3,7 @@ from typing import Any
|
||||||
|
|
||||||
|
|
||||||
class Element(ABC):
|
class Element(ABC):
|
||||||
|
default_kwargs: dict[str, Any]
|
||||||
|
|
||||||
def __init_subclass__(cls, **kwargs):
|
def __init_subclass__(cls, **kwargs):
|
||||||
cls.default_kwargs: dict[str, Any] = {} # all subclasses will have their own "default_kwargs" dict
|
cls.default_kwargs = {} # all subclasses will have their own "default_kwargs" dict
|
||||||
|
|
|
@ -16,7 +16,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
class Client(StoppableThread):
|
class Client(StoppableThread):
|
||||||
"""
|
"""
|
||||||
The thread executed on the person who join a room.
|
Ce thread est utilisé pour la personne qui rejoint la salle.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, window: "Window",
|
def __init__(self, window: "Window",
|
||||||
|
@ -39,9 +39,10 @@ class Client(StoppableThread):
|
||||||
try:
|
try:
|
||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as connection:
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as connection:
|
||||||
try:
|
try:
|
||||||
|
# Se connecte à l'opposant
|
||||||
connection.connect((self.ip_address, self.port))
|
connection.connect((self.ip_address, self.port))
|
||||||
except ConnectionRefusedError:
|
except ConnectionRefusedError:
|
||||||
# Appelle l'événement lorsque la connexion échoue
|
# Appelle la fonction prévue lorsque la connexion échoue
|
||||||
if self.on_connexion_refused is not None:
|
if self.on_connexion_refused is not None:
|
||||||
in_pyglet_context(self.on_connexion_refused)
|
in_pyglet_context(self.on_connexion_refused)
|
||||||
return
|
return
|
||||||
|
@ -91,13 +92,14 @@ class Client(StoppableThread):
|
||||||
with open(path_old_save, "r", encoding="utf-8") as file:
|
with open(path_old_save, "r", encoding="utf-8") as file:
|
||||||
save_data = json.load(file)
|
save_data = json.load(file)
|
||||||
|
|
||||||
# paramètres & jeu
|
# paramètres et jeu
|
||||||
|
|
||||||
settings = PacketSettings.from_connection(connection)
|
settings = PacketSettings.from_connection(connection)
|
||||||
PacketUsername(username=self.username).send_data_connection(connection)
|
PacketUsername(username=self.username).send_data_connection(connection)
|
||||||
enemy_username = PacketUsername.from_connection(connection).username
|
enemy_username = PacketUsername.from_connection(connection).username
|
||||||
|
|
||||||
if load_old_save:
|
if load_old_save:
|
||||||
|
# si les joueurs utilise une ancienne sauvegarde, créer la scène du jeu à partir des données
|
||||||
game_scene = in_pyglet_context(
|
game_scene = in_pyglet_context(
|
||||||
self.window.set_scene,
|
self.window.set_scene,
|
||||||
scene.Game.from_json, # depuis le fichier json
|
scene.Game.from_json, # depuis le fichier json
|
||||||
|
@ -109,6 +111,7 @@ class Client(StoppableThread):
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
# s'il n'y a pas de sauvegarde à utiliser, initialise une nouvelle scène
|
||||||
game_scene = in_pyglet_context(
|
game_scene = in_pyglet_context(
|
||||||
self.window.set_scene,
|
self.window.set_scene,
|
||||||
scene.Game,
|
scene.Game,
|
||||||
|
@ -124,6 +127,7 @@ class Client(StoppableThread):
|
||||||
my_turn=not settings.host_start
|
my_turn=not settings.host_start
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# commence la partie réseau du jeu
|
||||||
game_network(
|
game_network(
|
||||||
thread=self,
|
thread=self,
|
||||||
connection=connection,
|
connection=connection,
|
||||||
|
|
|
@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
class Host(StoppableThread):
|
class Host(StoppableThread):
|
||||||
"""
|
"""
|
||||||
The thread executed on the person who create a room.
|
Le thread utilisé lorsqu'un joueur créer une salle
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, window: "Window", port: int, username: str, settings: "PacketSettings", **kw):
|
def __init__(self, window: "Window", port: int, username: str, settings: "PacketSettings", **kw):
|
||||||
|
@ -29,6 +29,7 @@ class Host(StoppableThread):
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
self.port = port
|
self.port = port
|
||||||
|
|
||||||
|
# condition utilisée lorsque l'on attend la décision de charger une partie ou non
|
||||||
self.condition_load = Condition()
|
self.condition_load = Condition()
|
||||||
self.accept_load: bool = False
|
self.accept_load: bool = False
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ class Host(StoppableThread):
|
||||||
|
|
||||||
path_old_save: Optional[Path] = None
|
path_old_save: Optional[Path] = None
|
||||||
|
|
||||||
for file in path_save.iterdir(): # cherche une ancienne sauvegarde correspondant à l'ip de l'adversaire
|
for file in path_save.iterdir(): # cherche une ancienne sauvegarde correspondant à l'IP de l'adversaire
|
||||||
if file.stem.startswith(ip_address):
|
if file.stem.startswith(ip_address):
|
||||||
path_old_save = file
|
path_old_save = file
|
||||||
break
|
break
|
||||||
|
@ -72,7 +73,8 @@ class Host(StoppableThread):
|
||||||
from source.gui.scene import GameLoad
|
from source.gui.scene import GameLoad
|
||||||
in_pyglet_context(self.window.set_scene, GameLoad, path=path_old_save, thread_host=self)
|
in_pyglet_context(self.window.set_scene, GameLoad, path=path_old_save, thread_host=self)
|
||||||
|
|
||||||
with self.condition_load: self.condition_load.wait() # attend que l'utilisateur choisisse l'option
|
# attend que l'utilisateur choisisse l'option
|
||||||
|
with self.condition_load: self.condition_load.wait()
|
||||||
|
|
||||||
PacketLoadOldSave(value=self.accept_load).send_data_connection(connection)
|
PacketLoadOldSave(value=self.accept_load).send_data_connection(connection)
|
||||||
|
|
||||||
|
@ -89,6 +91,7 @@ class Host(StoppableThread):
|
||||||
PacketUsername(username=self.username).send_data_connection(connection)
|
PacketUsername(username=self.username).send_data_connection(connection)
|
||||||
|
|
||||||
if self.accept_load:
|
if self.accept_load:
|
||||||
|
# si une sauvegarde doit être chargée
|
||||||
game_scene = in_pyglet_context(
|
game_scene = in_pyglet_context(
|
||||||
self.window.set_scene,
|
self.window.set_scene,
|
||||||
scene.Game.from_json, # depuis le fichier json
|
scene.Game.from_json, # depuis le fichier json
|
||||||
|
@ -100,6 +103,7 @@ class Host(StoppableThread):
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
# s'il n'y a pas de sauvegarde à charger
|
||||||
game_scene = in_pyglet_context(
|
game_scene = in_pyglet_context(
|
||||||
self.window.set_scene,
|
self.window.set_scene,
|
||||||
scene.Game,
|
scene.Game,
|
||||||
|
@ -115,6 +119,7 @@ class Host(StoppableThread):
|
||||||
my_turn=self.settings.host_start
|
my_turn=self.settings.host_start
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# commence la partie réseau du jeu
|
||||||
game_network(
|
game_network(
|
||||||
thread=self,
|
thread=self,
|
||||||
connection=connection,
|
connection=connection,
|
||||||
|
|
|
@ -9,8 +9,15 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
def handle_error(window: "Window", exception: Exception):
|
def handle_error(window: "Window", exception: Exception):
|
||||||
|
"""
|
||||||
|
Fonction permettant d'afficher le bon message d'erreur du au réseau.
|
||||||
|
:param window: la fenêtre du jeu
|
||||||
|
:param exception: l'erreur qui s'est produite
|
||||||
|
"""
|
||||||
|
|
||||||
message: str = "Erreur :\n"
|
message: str = "Erreur :\n"
|
||||||
|
|
||||||
|
# récupère le message d'erreur selon le type de l'erreur
|
||||||
match type(exception):
|
match type(exception):
|
||||||
case builtins.ConnectionResetError:
|
case builtins.ConnectionResetError:
|
||||||
message += "Perte de connexion avec l'adversaire."
|
message += "Perte de connexion avec l'adversaire."
|
||||||
|
|
|
@ -18,12 +18,13 @@ def game_network(
|
||||||
game_scene: "Game",
|
game_scene: "Game",
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Run the networking to make the game work and react with the other player
|
Partie réseau permettant au jeu de fonctionner et de réagir avec l'autre joueur
|
||||||
:param game_scene: the scene of the game
|
:param game_scene: la scène du jeu
|
||||||
:param thread: the thread where this function is called.
|
:param thread: le thread dans lequel la fonction est appelé
|
||||||
:param connection: the connection with the other player
|
:param connection: la connexion avec l'autre joueur
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# associe le type de packet avec la fonction correspondante
|
||||||
game_methods: dict[Type["Packet"], Callable] = {
|
game_methods: dict[Type["Packet"], Callable] = {
|
||||||
packet.PacketChat: game_scene.network_on_chat,
|
packet.PacketChat: game_scene.network_on_chat,
|
||||||
packet.PacketBoatPlaced: game_scene.network_on_boat_placed,
|
packet.PacketBoatPlaced: game_scene.network_on_boat_placed,
|
||||||
|
@ -35,16 +36,19 @@ def game_network(
|
||||||
}
|
}
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
# récupère le type de packet reçu
|
||||||
data_type = Packet.type_from_connection(connection)
|
data_type = Packet.type_from_connection(connection)
|
||||||
|
|
||||||
if data_type is None:
|
if data_type is None:
|
||||||
if thread.stopped: return # vérifie si le thread n'est pas censé s'arrêter
|
# s'il n'y a pas de donnée reçue, vérifie si le thread devrait s'arrêter, sinon ignore
|
||||||
|
if thread.stopped: return
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# récupère les données du packet
|
||||||
data = data_type.from_connection(connection)
|
data = data_type.from_connection(connection)
|
||||||
|
|
||||||
in_pyglet_context(
|
in_pyglet_context(
|
||||||
game_methods[data_type], data # récupère la methode relié ce type de donnée
|
game_methods[data_type], data # récupère la methode relié à ce type de donnée
|
||||||
) # Appelle la méthode.
|
) # Appelle la méthode.
|
||||||
|
|
||||||
if thread.stopped: return # vérifie si le thread n'est pas censé s'arrêter
|
if thread.stopped: return # vérifie si le thread n'est pas censé s'arrêter
|
||||||
|
|
|
@ -6,5 +6,5 @@ from source.network.packet.abc import SignalPacket
|
||||||
@dataclass
|
@dataclass
|
||||||
class PacketAskSave(SignalPacket):
|
class PacketAskSave(SignalPacket):
|
||||||
"""
|
"""
|
||||||
A packet that is sent when the player wish to save the game.
|
Un packet envoyé quand le joueur souhaite sauvegarder
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -6,5 +6,5 @@ from source.network.packet.abc import SignalPacket
|
||||||
@dataclass
|
@dataclass
|
||||||
class PacketBoatPlaced(SignalPacket):
|
class PacketBoatPlaced(SignalPacket):
|
||||||
"""
|
"""
|
||||||
A packet that signal that all the boat of the player have been placed
|
Un packet signalant que tous les bateaux du joueur ont été placé
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -9,6 +9,9 @@ from source.network.packet.abc import Packet
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PacketBoatsData(Packet):
|
class PacketBoatsData(Packet):
|
||||||
|
"""
|
||||||
|
Un packet contenant les données de la position de tous les bateaux
|
||||||
|
"""
|
||||||
|
|
||||||
boats: np.array = field()
|
boats: np.array = field()
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ from source.type import Point2D
|
||||||
@dataclass
|
@dataclass
|
||||||
class PacketBombPlaced(SimplePacket):
|
class PacketBombPlaced(SimplePacket):
|
||||||
"""
|
"""
|
||||||
A packet that signal that a bomb have been placed on the board
|
Un packet qui signale qu'une bombe à été placé sur la grille
|
||||||
"""
|
"""
|
||||||
|
|
||||||
position: Point2D = field()
|
position: Point2D = field()
|
||||||
|
|
|
@ -9,7 +9,7 @@ from source.type import Point2D
|
||||||
@dataclass
|
@dataclass
|
||||||
class PacketBombState(SimplePacket):
|
class PacketBombState(SimplePacket):
|
||||||
"""
|
"""
|
||||||
A packet that signal how a bomb exploded on the board
|
Un packet qui signale qu'une bombe à explosé sur la grille
|
||||||
"""
|
"""
|
||||||
|
|
||||||
position: Point2D = field()
|
position: Point2D = field()
|
||||||
|
|
|
@ -6,7 +6,7 @@ from source.network.packet.abc import VariableLengthPacket
|
||||||
@dataclass
|
@dataclass
|
||||||
class PacketChat(VariableLengthPacket):
|
class PacketChat(VariableLengthPacket):
|
||||||
"""
|
"""
|
||||||
A packet that represent a message from the chat
|
Un packet qui représente un message du chat
|
||||||
"""
|
"""
|
||||||
|
|
||||||
message: str = field()
|
message: str = field()
|
||||||
|
|
|
@ -7,7 +7,7 @@ from source.network.packet.abc import SimplePacket
|
||||||
@dataclass
|
@dataclass
|
||||||
class PacketHaveSaveBeenFound(SimplePacket):
|
class PacketHaveSaveBeenFound(SimplePacket):
|
||||||
"""
|
"""
|
||||||
A packet that is sent when the player accept or refuse a requested save.
|
Un packet indiquant si le joueur à trouvé un ancien fichier de sauvegarde avec l'opposant
|
||||||
"""
|
"""
|
||||||
|
|
||||||
value: bool = field() # True si requête accepter, sinon False
|
value: bool = field() # True si requête accepter, sinon False
|
||||||
|
|
|
@ -7,7 +7,7 @@ from source.network.packet.abc import SimplePacket
|
||||||
@dataclass
|
@dataclass
|
||||||
class PacketLoadOldSave(SimplePacket):
|
class PacketLoadOldSave(SimplePacket):
|
||||||
"""
|
"""
|
||||||
A packet that is sent when the player accept or refuse a requested save.
|
Un packet qui est envoyé lorsque l'hôte accepte ou refuse de charger une ancienne sauvegarde
|
||||||
"""
|
"""
|
||||||
|
|
||||||
value: bool = field() # True si requête accepter, sinon False
|
value: bool = field() # True si requête accepter, sinon False
|
||||||
|
|
|
@ -6,5 +6,5 @@ from source.network.packet.abc import SignalPacket
|
||||||
@dataclass
|
@dataclass
|
||||||
class PacketQuit(SignalPacket):
|
class PacketQuit(SignalPacket):
|
||||||
"""
|
"""
|
||||||
A packet that is sent when the player wish to quit a game.
|
Un packet envoyé lorsque le joueur souhaite quitter la partie
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -7,7 +7,7 @@ from source.network.packet.abc import SimplePacket
|
||||||
@dataclass
|
@dataclass
|
||||||
class PacketResponseSave(SimplePacket):
|
class PacketResponseSave(SimplePacket):
|
||||||
"""
|
"""
|
||||||
A packet that is sent when the player accept or refuse a requested save.
|
Un packet qui est envoyé lorsque le joueur accepte ou refuse une demande de sauvegarde
|
||||||
"""
|
"""
|
||||||
|
|
||||||
value: bool = field() # True si requête accepter, sinon False
|
value: bool = field() # True si requête accepter, sinon False
|
||||||
|
|
|
@ -7,6 +7,10 @@ from source.network.packet.abc import Packet
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PacketSettings(Packet):
|
class PacketSettings(Packet):
|
||||||
|
"""
|
||||||
|
Un packet contenant tous les paramètres de la partie
|
||||||
|
"""
|
||||||
|
|
||||||
grid_width: int = field()
|
grid_width: int = field()
|
||||||
grid_height: int = field()
|
grid_height: int = field()
|
||||||
host_start: bool = field()
|
host_start: bool = field()
|
||||||
|
|
|
@ -5,6 +5,10 @@ from source.network.packet.abc import VariableLengthPacket
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PacketUsername(VariableLengthPacket):
|
class PacketUsername(VariableLengthPacket):
|
||||||
|
"""
|
||||||
|
Un packet contenant le nom d'utilisateur de l'opposant
|
||||||
|
"""
|
||||||
|
|
||||||
username: str = field()
|
username: str = field()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -9,10 +9,8 @@ T = TypeVar("T", bound="Packet")
|
||||||
|
|
||||||
class Packet(ABC):
|
class Packet(ABC):
|
||||||
"""
|
"""
|
||||||
A packet that can be sent on a socket.
|
Un packet pouvant être envoyé dans un socket.
|
||||||
Multiple subtype of packet can be sent and received in an easier way.
|
Permet aux sous-classes de ce packet d'être envoyé et reçu d'une manière beaucoup plus simple.
|
||||||
|
|
||||||
The to_bytes and from_connection method need to be defined.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
packet_types: set[T] = set()
|
packet_types: set[T] = set()
|
||||||
|
|
|
@ -10,8 +10,8 @@ T = TypeVar("T", bound="SignalPacket")
|
||||||
|
|
||||||
class SignalPacket(Packet, ABC):
|
class SignalPacket(Packet, ABC):
|
||||||
"""
|
"""
|
||||||
A packet that has for only usage to send a signal thanks to the type of the class.
|
Un packet ne contenant aucune donnée.
|
||||||
It does not hold any other data.
|
Permet de réagir à des événements seulement avec le type de la classe.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def to_bytes(self) -> bytes:
|
def to_bytes(self) -> bytes:
|
||||||
|
|
|
@ -11,8 +11,8 @@ T = TypeVar("T", bound="SimplePacket")
|
||||||
|
|
||||||
class SimplePacket(Packet, ABC):
|
class SimplePacket(Packet, ABC):
|
||||||
"""
|
"""
|
||||||
A packet with a simple packet format.
|
Un packet avec un format plus simple.
|
||||||
Only the from_bytes and to_bytes method need to be implemented.
|
Se base sur le "packet_format" pour envoyé et reservoir les données.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
packet_format: str = ">"
|
packet_format: str = ">"
|
||||||
|
@ -21,9 +21,9 @@ class SimplePacket(Packet, ABC):
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def from_bytes(cls, data: bytes) -> T:
|
def from_bytes(cls, data: bytes) -> T:
|
||||||
"""
|
"""
|
||||||
Convert a bytes object into a packet.
|
Convertie un objet bytes en un SimplePacket
|
||||||
:param data: the data to convert into a packet. Should be "packet_size" long.
|
:param data: les données à charger, doit être "packet_size" de long
|
||||||
:return: a packet corresponding to the bytes.
|
:return: un SimplePacket correspondant à ces données
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,7 @@ T = TypeVar("T", bound="VariableLengthPacket")
|
||||||
|
|
||||||
class VariableLengthPacket(Packet, ABC):
|
class VariableLengthPacket(Packet, ABC):
|
||||||
"""
|
"""
|
||||||
A Packet that represent a single value that can be encoded with a variable length.
|
Un packet représentant une seule valeur avec une longueur variable qui peut être encodé, comme une chaîne.
|
||||||
The property "data" and the method "from_bytes" need to be defined.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
packet_format: str = ">I"
|
packet_format: str = ">I"
|
||||||
|
@ -20,6 +19,11 @@ class VariableLengthPacket(Packet, ABC):
|
||||||
@property
|
@property
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def data(self) -> bytes:
|
def data(self) -> bytes:
|
||||||
|
"""
|
||||||
|
Donnée à envoyer sur le réseau
|
||||||
|
:return: la donnée sous la forme d'un objet bytes
|
||||||
|
"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def to_bytes(self) -> bytes:
|
def to_bytes(self) -> bytes:
|
||||||
|
|
|
@ -9,6 +9,10 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
class Option:
|
class Option:
|
||||||
|
"""
|
||||||
|
Cette classe permet de modifier, sauvegarder et charger les options.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, window: "GameWindow",
|
def __init__(self, window: "GameWindow",
|
||||||
volume_ambient: float = 0.1,
|
volume_ambient: float = 0.1,
|
||||||
volume_fx: float = 0.1,
|
volume_fx: float = 0.1,
|
||||||
|
@ -24,7 +28,7 @@ class Option:
|
||||||
self.set_fps_limit(fps_limit)
|
self.set_fps_limit(fps_limit)
|
||||||
self.set_vsync(vsync)
|
self.set_vsync(vsync)
|
||||||
|
|
||||||
# propriété
|
# propriétés
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_volume_ambient() -> float: return media.SoundAmbient.get_volume()
|
def get_volume_ambient() -> float: return media.SoundAmbient.get_volume()
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
from typing import Union, Callable
|
from typing import Union, Callable
|
||||||
|
|
||||||
|
|
||||||
Point2D = tuple[int, int] # a 2D point
|
Point2D = tuple[int, int] # un point 2D
|
||||||
BBox = tuple[int, int, int, int] # a boundary box
|
BBox = tuple[int, int, int, int] # une boîte de collision
|
||||||
ColorRGB = tuple[int, int, int] # a RGB Color
|
ColorRGB = tuple[int, int, int] # une couleur RGB
|
||||||
ColorRGBA = tuple[int, int, int, int] # a RGBA Color
|
ColorRGBA = tuple[int, int, int, int] # une couleur RGBA
|
||||||
|
|
||||||
DistanceFunc = Callable[["BoxWidget"], int] # a function that return a position / distance
|
DistanceFunc = Callable[["BoxWidget"], int] # une fonction renvoyant une position / distance
|
||||||
Distance = Union[int, DistanceFunc] # a position / distance, represented by a number or a function
|
Distance = Union[int, DistanceFunc] # une position / distance sous la forme d'un nombre ou d'une fonction
|
||||||
|
|
|
@ -3,10 +3,10 @@ from source.type import Point2D, BBox
|
||||||
|
|
||||||
def in_bbox(point: Point2D, bbox: BBox) -> bool:
|
def in_bbox(point: Point2D, bbox: BBox) -> bool:
|
||||||
"""
|
"""
|
||||||
Return true if a point is inside a bounding box
|
Indique si un point est dans un rectangle
|
||||||
:param point: the point to check
|
:param point: le point à vérifier
|
||||||
:param bbox: the bbox where to check the point
|
:param bbox: la bbox à vérifier
|
||||||
:return: True if the point is inside the bbox, False otherwise
|
:return: True si le point est dans la bbox, sinon Faux
|
||||||
"""
|
"""
|
||||||
|
|
||||||
point_x, point_y = point
|
point_x, point_y = point
|
||||||
|
|
|
@ -3,17 +3,15 @@ from typing import Callable, Any
|
||||||
|
|
||||||
def dict_filter(filter_func: Callable[[Any, Any], bool], dictionary: dict[Any, Any]) -> dict[Any, Any]:
|
def dict_filter(filter_func: Callable[[Any, Any], bool], dictionary: dict[Any, Any]) -> dict[Any, Any]:
|
||||||
"""
|
"""
|
||||||
Filter a dict object with the filter function given.
|
Filtre les objets d'un dictionnaire avec la fonction de filtre donnée.
|
||||||
:param filter_func: the function to filter with
|
:param filter_func: La fonction utilisée pour le filtre. Reçois l'argument clé et valeur
|
||||||
:param dictionary: the dictionary to filter
|
:param dictionary: Le dictionnaire à filtrer
|
||||||
:return: the filtered dictionary
|
:return: Le dictionnaire filtrer
|
||||||
|
|
||||||
Example :
|
Exemple :
|
||||||
filter_func = lambda key, value: key.startswith("valeur")
|
filter_func = lambda key, value: key.startswith("valeur")
|
||||||
dictionary = {"valeur1": 1, "valeur2": 2, "clé1": None}
|
dictionary = {"valeur1": 1, "valeur2": 2, "clé1": None}
|
||||||
|
-> {"valeur1": 1, "valeur2": 2}
|
||||||
result = {"valeur1": 1, "valeur2": 2}
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -26,16 +24,15 @@ def dict_filter(filter_func: Callable[[Any, Any], bool], dictionary: dict[Any, A
|
||||||
|
|
||||||
def dict_filter_prefix(prefix: str, dictionary: dict[str, Any]) -> dict[str, Any]:
|
def dict_filter_prefix(prefix: str, dictionary: dict[str, Any]) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Take only the keys that start with the prefix, and remove this prefix from the keys.
|
Ne garde que les clés qui commencent avec ce préfixe dans le dictionnaire et retire leur préfixe.
|
||||||
:param prefix: the prefix to use
|
:param prefix: le préfixe à utiliser
|
||||||
:param dictionary: the dictionary to filter
|
:param dictionary: le dictionnaire à filtrer
|
||||||
:return: the dictionary with the prefix
|
:return: le dictionnaire avec le préfixe
|
||||||
|
|
||||||
Example:
|
Exemple :
|
||||||
prefix = "button"
|
prefix = "button"
|
||||||
dictionary = {"button1": 1, "button2": 2, "label1": None}
|
dictionary = {"button1": 1, "button2": 2, "label1": None}
|
||||||
|
-> {"1": 1, "2": 2}
|
||||||
result = {"1": 1, "2": 2}
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -48,10 +45,10 @@ def dict_filter_prefix(prefix: str, dictionary: dict[str, Any]) -> dict[str, Any
|
||||||
|
|
||||||
def dict_add_prefix(prefix: str, dictionary: dict[str, Any]) -> dict[str, Any]:
|
def dict_add_prefix(prefix: str, dictionary: dict[str, Any]) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Add a prefix to every key of the dictionary
|
Ajoute un préfixe à toute les clés d'un dictionnaire
|
||||||
:param prefix: the prefix to add
|
:param prefix: le préfixe à ajouter
|
||||||
:param dictionary: the dictionary to modify
|
:param dictionary: le dictionnaire à modifier
|
||||||
:return: the dictionary with the prefix at the start of the keys
|
:return: le dictionnaire avec le préfixe à chaque clé
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -5,10 +5,10 @@ from source.type import Point2D
|
||||||
|
|
||||||
def copy_array_offset(src: np.array, dst: np.array, offset: Point2D) -> None:
|
def copy_array_offset(src: np.array, dst: np.array, offset: Point2D) -> None:
|
||||||
"""
|
"""
|
||||||
Copy a numpy array into another one with an offset
|
Copie une matrice dans une autre matrice avec un décalage.
|
||||||
:param src: source array
|
:param src: la matrice source
|
||||||
:param dst: destination array
|
:param dst: la matrice de destination
|
||||||
:param offset: the offset where to copy the array
|
:param offset: le décalage avec lequel copier la matrice
|
||||||
"""
|
"""
|
||||||
column, row = offset
|
column, row = offset
|
||||||
width, height = src.shape
|
width, height = src.shape
|
||||||
|
|
|
@ -2,5 +2,10 @@ from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
def path_ctime_str(path: Path):
|
def path_ctime_str(path: Path) -> str:
|
||||||
|
"""
|
||||||
|
Un raccourci permettant d'obtenir la représentation de la date de création d'un fichier
|
||||||
|
:param path: le chemin du fichier
|
||||||
|
:return: la date correspondante sous la forme d'un texte
|
||||||
|
"""
|
||||||
return datetime.fromtimestamp(path.lstat().st_ctime).strftime('%d/%m/%Y %H:%M:%S')
|
return datetime.fromtimestamp(path.lstat().st_ctime).strftime('%d/%m/%Y %H:%M:%S')
|
||||||
|
|
|
@ -7,8 +7,9 @@ import pyglet
|
||||||
|
|
||||||
class StoppableThread(Thread):
|
class StoppableThread(Thread):
|
||||||
"""
|
"""
|
||||||
A thread that can be stopped.
|
Un thread pouvant être arrêté.
|
||||||
The run method need to check for the "self._stop" variable and return manually if it is true.
|
La méthode "run" doit souvent vérifier la variable self.stopped et faire un return manuellement si cette variable
|
||||||
|
est vrai.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -16,17 +17,18 @@ class StoppableThread(Thread):
|
||||||
self.stopped = False
|
self.stopped = False
|
||||||
|
|
||||||
def stop(self) -> None:
|
def stop(self) -> None:
|
||||||
|
# indique que le thread devrait s'arrêter dès que possible
|
||||||
self.stopped = True
|
self.stopped = True
|
||||||
|
|
||||||
|
|
||||||
def in_pyglet_context(func: Callable, *args, **kwargs) -> Any:
|
def in_pyglet_context(func: Callable, *args, **kwargs) -> Any:
|
||||||
"""
|
"""
|
||||||
This function can be call in a thread. It will call the "func" in the pyglet event loop, avoiding
|
Cette fonction doit être appelée dans un thread. Elle appellera une fonction dans la boucle d'événement de pyglet,
|
||||||
some operation that are not allowed outside of the pyglet context, and return its result
|
ce qui permet d'éviter certaines opérations illégales en dehors de ce contexte et renvoie le résultat.
|
||||||
:param func: the function to call in the pyglet context
|
:param func: la fonction à appeler
|
||||||
:param args: the args of the function
|
:param args: les arguments de la fonction
|
||||||
:param kwargs: the kwargs of the function
|
:param kwargs: les arguments à clé de la fonction
|
||||||
:return: the result of the function
|
:return: le résultat de la fonction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
queue = Queue()
|
queue = Queue()
|
||||||
|
|
Loading…
Reference in a new issue