diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..dbb72d1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.ignoreWords": [ + "posx" + ] +} \ No newline at end of file diff --git a/Game Server/Classes/System/GameManager.py b/Game Server/Classes/System/GameManager.py index db684b7..9347fc2 100644 --- a/Game Server/Classes/System/GameManager.py +++ b/Game Server/Classes/System/GameManager.py @@ -9,13 +9,17 @@ class GameManager: __state:str __round:str - def __init__(self): + def __init__(self, logger): self.__players = {} self.__playingPlayer = None self.__state = "waiting" self.__round = "none" + self.logger = logger pass + def getLogger(self): + return self.logger + # game round management # this section manages the flow of rounds this should inherit itself # ============================================================================= @@ -83,13 +87,17 @@ class GameManager: # creates a player and handles counting all players and if conditions met starting the game # returns the new dict in which the new player now is added def addPlayers(self, player:Player, socket:socket, clientAddr) -> dict: + + self.__gameManager.getLogger().info(f"creating user with id: {player.getID}") self.__players[clientAddr] = { player: player, socket:socket } + self.__gameManager.getLogger().info(f"new length of user dictionary: {len(self.__players)}") # counts participating players and starts the game if enough have joined if len(self.__players) == 2: + self.__gameManager.getLogger().info("2 players have join game starts") self.startGame(socket) return self.__players \ No newline at end of file diff --git a/Game Server/Classes/System/Logger.py b/Game Server/Classes/System/Logger.py new file mode 100644 index 0000000..b548160 --- /dev/null +++ b/Game Server/Classes/System/Logger.py @@ -0,0 +1,18 @@ +import logging + + +class Logger: + def __init__(self, filename): + logging.basicConfig(filename=filename, + filemode='a', + format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s', + datefmt='%H:%M:%S', + level=logging.DEBUG) + + def info(self, message): + print(message) + logging.info(message) + + def error(self, message): + print(message) + logging.error(message) \ No newline at end of file diff --git a/Game Server/Classes/System/Network/EventHandler.py b/Game Server/Classes/System/Network/EventHandler.py index 38112fc..a9cd090 100644 --- a/Game Server/Classes/System/Network/EventHandler.py +++ b/Game Server/Classes/System/Network/EventHandler.py @@ -13,15 +13,7 @@ class TCPEventHandler: # handles passing of event data to the right functions def handleTCPEvents(self, event, gameManager:GameManager, address): - pass - -class UDPEventHandler: - __udpSocket:socket - - def __init__(self, socket:socket, gameManager:GameManager): - self.__udpSocket = socket - - def handleUDPEvents(self, event): + gameManager.getLogger().info(f"incommingevent {event}") if event["event"] == "PlaceCard": pass elif event["event"] == "MoveCard": @@ -35,4 +27,5 @@ class UDPEventHandler: elif event["event"] == "ActivateEffectCard": pass elif event["event"] == "ActivateMonsterCard": - pass \ No newline at end of file + pass + pass \ No newline at end of file diff --git a/Game Server/Classes/System/Network/NetworkManger.py b/Game Server/Classes/System/Network/NetworkManger.py index abc7626..9cb2b78 100644 --- a/Game Server/Classes/System/Network/NetworkManger.py +++ b/Game Server/Classes/System/Network/NetworkManger.py @@ -1,4 +1,5 @@ import json +import signal import socket import sys import threading @@ -9,56 +10,6 @@ from Classes.System.Network.EventHandler import UDPEventHandler, TCPEventHandler from Classes.System.World import World class NetworkManager: - -#class UDP: -# __Addr:str -# __Port:str -# __BufferSize:int = 1024 -# __udpSocket:socket -# __users:dict -# __eventHandler: UDPEventHandler -# __UDPClientThread:threading.Thread -# __gameManager:GameManager -# -# def __init__(self, Addr:str, Port:str, gameManager:GameManager): -# self.__Addr = Addr -# self.__Port = int(Port) -# self.__gameManager = gameManager -# self.__users = {} -# self.__eventHandler = {} -# self.__udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -# -# try: -# self.__udpSocket.bind((self.__Addr, self.__Port)) -# except OSError as e: -# print(f"Error binding UDP socket: {e}") -# -# self.__UDPClientThread = threading.Thread(target=self.receive) -# self.__UDPClientThread.start() -# -# # handles incoming udp data -# def receive(self): -# while True: -# data, address = self.__udpSocket.recvfrom(self.__BufferSize) -# message = data.decode() -# messageJson = json.loads(message) -# user = messageJson.get("user") -# -# if user not in self.__users: -# self.__users[user] = address # Storing new user in dictionary -# -# # Process the message and handle accordingly -# self.__eventHandler.handleUDPEvents(messageJson, self.__serverWorld) -# print(f"Received message from {address}: {message}") -# -# def broadcast(self, payload:dict): -# for user_address in self.__users.values(): -# self.__udpSocket.sendto(json.dumps(payload).encode(), user_address) -# -# def send(self, payload:dict, user:str): -# if user in self.__users: -# self.__udpSocket.sendto(json.dumps(payload).encode(), self.__users[user]) -# class TCP: __Addr:str __Port:str @@ -70,65 +21,96 @@ class NetworkManager: __gameManager:GameManager def __init__(self, Addr:str, Port:str, gameManager:GameManager): + gameManager.getLogger().info("starting up network manager") + self.running = True self.__Addr = Addr self.__Port = int(Port) self.__gameManager = gameManager self.__eventHandler = {} + + gameManager.getLogger().info("starting up tcp server") self.__tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.__tcpSocket.bind((self.__Addr, self.__Port)) self.__tcpSocket.listen() + gameManager.getLogger().info("starting up thread for client socket accepting") self.__TCPClientThread = threading.Thread(target=self.accept_connections) + self.__TCPClientThread.daemon = True self.__TCPClientThread.start() def accept_connections(self): while self.running: try: client_tcp_socket, client_address = self.__tcpSocket.accept() - print(f"Connected with {client_address}") + self.__gameManager.getLogger().info(f"Connected with {client_address}") self.__gameManager.getPlayers()[client_address] = client_tcp_socket self.__eventHandler[client_address] = TCPEventHandler(client_tcp_socket) + client_handler_thread = threading.Thread( target=self.receive, args=(client_tcp_socket, client_address) ) + + self.__gameManager.getLogger().info(f"starting client handler thread for client at address {client_address}") + client_handler_thread.daemon = True client_handler_thread.start() + except Exception as e: - print(f"tcp socket failed to accept connection due to error: {e}") + self.__gameManager.getLogger().error(f"tcp socket failed to accept connection due to error: {e}") pass + client_handler_thread.join() def receive(self, client_socket, client_address): while self.running: try: data = client_socket.recv(self.__BufferSize) if not data: - print(f"Connection with {client_address} closed.") + self.__gameManager.getLogger().info(f"Connection with {client_address} closed.") break - message = data.decode() - messageJson = json.loads(message) - user = messageJson.get("user") + try: + + message = data.decode() + messageJson = json.loads(message) + self.__gameManager.getLogger().info(f"decoded message {messageJson}") + user = messageJson.get("user") + self.__gameManager.getLogger().info(f"user in message {user}") + + except Exception as ex: + self.__gameManager.getLogger().info(f"decoding incoming packet failed due to exception: {ex}") # creates a user and counts how many currently are connected to the server # if enough users for a round are connected the server has to start the game if user not in self.__gameManager.getPlayers(): if messageJson["event"] == "login": - self.__gameManager.addPlayers(Player(messageJson["username"], messageJson["deck"]), client_socket, client_address) - print(f"connected users {len(self.__gameManager.getPlayers())}") + self.logger.__gameManager.getLogger().info("user logging in") + self.logger.__gameManager.getLogger().info("task passed off to gameManager") + user = self.__gameManager.addPlayers(Player(messageJson["username"], messageJson["deck"]), client_socket, client_address) + self.__gameManager.getLogger().info(f"connected users {len(self.__gameManager.getPlayers())}") + + self.__gameManager.getLogger().info(f"confirming login for user") + self.send({ + "event":"loginresponse", + "id": user["player"].getID(), + }) self.__eventHandler[client_address].handleTCPEvents(messageJson, self.__gameManager, client_address) - print(f"Received message from {client_address}: {message}") + self.__gameManager.getLogger().info(f"Received message from {client_address}: {message}") except socket.error as e: + if e.errno == 10054: - print(f"Connection with {client_address} forcibly closed by remote host.") + self.__gameManager.getLogger().error(f"Connection with {client_address} forcibly closed by remote host.") break - print(f"Socket error receiving data from {client_address}: {e}") + + self.__gameManager.getLogger().error(f"Socket error receiving data from {client_address}: {e}") + except json.JSONDecodeError as e: - print(f"JSON decoding error receiving data from {client_address}: {e}") + self.__gameManager.getLogger().error(f"JSON decoding error receiving data from {client_address}: {e}") + except Exception as e: - print(f"Error receiving data from {client_address}: {e}") + self.__gameManager.getLogger().error(f"Error receiving data from {client_address}: {e}") def broadcast(self, payload:dict): for user in self.__gameManager.getPlayers().values(): @@ -140,11 +122,19 @@ class NetworkManager: if user in players and "socket" in players[user]: players[user]["socket"].send(json.dumps(payload).encode()) else: - print(f"user '{user}' or socket was not found 'socket' failed to send data.") + self.__gameManager.getLogger().error(f"user '{user}' or socket was not found 'socket' failed to send data.") + + def stop(self): + self.__TCPClientThread.join() # Wait for the thread to finish before exiting tcp: TCP # udp: UDP def __init__(self, Addr:str, TCPPort:str, UDPPort:str, gameManager:GameManager): self.tcp = self.TCP(Addr, TCPPort, gameManager) - # self.udp = self.UDP(Addr, UDPPort, gameManager) \ No newline at end of file + signal.signal(signal.SIGINT, self.handle_interrupt) # Register the signal handler + + def handle_interrupt(self, signum, frame): + self.__gameManager.getLogger().info("Received keyboard interrupt. Stopping the server.") + self.tcp().stop() + sys.exit(0) \ No newline at end of file diff --git a/Game Server/Classes/System/Network/__pycache__/EventHandler.cpython-311.pyc b/Game Server/Classes/System/Network/__pycache__/EventHandler.cpython-311.pyc index a715b7a..207f795 100644 Binary files a/Game Server/Classes/System/Network/__pycache__/EventHandler.cpython-311.pyc and b/Game Server/Classes/System/Network/__pycache__/EventHandler.cpython-311.pyc differ diff --git a/Game Server/Classes/System/Network/__pycache__/NetworkManger.cpython-311.pyc b/Game Server/Classes/System/Network/__pycache__/NetworkManger.cpython-311.pyc index 7d5188f..769b27d 100644 Binary files a/Game Server/Classes/System/Network/__pycache__/NetworkManger.cpython-311.pyc and b/Game Server/Classes/System/Network/__pycache__/NetworkManger.cpython-311.pyc differ diff --git a/Game Server/Classes/System/Server.py b/Game Server/Classes/System/Server.py index bc8f7f6..c3485db 100644 --- a/Game Server/Classes/System/Server.py +++ b/Game Server/Classes/System/Server.py @@ -6,6 +6,7 @@ from Classes.System.GameManager import GameManager from Classes.System.Network.NetworkManger import NetworkManager from Classes.System.PlayerManager import Player from Classes.System.World import World +from Classes.System.Logger import Logger class Server: @@ -17,16 +18,23 @@ class Server: networkManager:NetworkManager - def __init__(self, address:str, tcpPort:str, udpPort:str): + def __init__(self, address:str, tcpPort:str, udpPort:str, logger:Logger): self.__address = address self.__tcpPort = tcpPort self.__udpPort = udpPort self.__world = World() - self.__gameManager = GameManager() + self.logger = logger - + self.logger.info("starting up game manager") + self.__gameManager = GameManager(logger) + + self.logger.info("preparing to start server") self.startServer(self.__gameManager) # handles starting the server and assigning socket values to the local reference def startServer(self, gameManager:GameManager): - self.__networkManager = NetworkManager(self.__address, self.__tcpPort, self.__udpPort, gameManager) \ No newline at end of file + self.logger.info("starting up network manager") + self.__networkManager = NetworkManager(self.__address, self.__tcpPort, self.__udpPort, gameManager) + + def getNetworkManager(self) -> NetworkManager: + return self.__networkManager \ No newline at end of file diff --git a/Game Server/Classes/System/__pycache__/GameManager.cpython-311.pyc b/Game Server/Classes/System/__pycache__/GameManager.cpython-311.pyc index 1e24e1d..52b6cf3 100644 Binary files a/Game Server/Classes/System/__pycache__/GameManager.cpython-311.pyc and b/Game Server/Classes/System/__pycache__/GameManager.cpython-311.pyc differ diff --git a/Game Server/Classes/System/__pycache__/Logger.cpython-311.pyc b/Game Server/Classes/System/__pycache__/Logger.cpython-311.pyc new file mode 100644 index 0000000..c04e139 Binary files /dev/null and b/Game Server/Classes/System/__pycache__/Logger.cpython-311.pyc differ diff --git a/Game Server/Classes/System/__pycache__/Server.cpython-311.pyc b/Game Server/Classes/System/__pycache__/Server.cpython-311.pyc index f6841be..9c11ea7 100644 Binary files a/Game Server/Classes/System/__pycache__/Server.cpython-311.pyc and b/Game Server/Classes/System/__pycache__/Server.cpython-311.pyc differ diff --git a/Game Server/index.py b/Game Server/index.py index d93b9d6..d06c09f 100644 --- a/Game Server/index.py +++ b/Game Server/index.py @@ -1,7 +1,18 @@ +import logging import os +import random +import string import sys from Classes.System.Server import Server +from Classes.System.Logger import Logger + +def get_random_string(length) -> str: + # choose from all lowercase letter + letters = string.ascii_lowercase + result_str = ''.join(random.choice(letters) for i in range(length)) + print("Random string of length", length, "is:", result_str) + return result_str def main(): # retrieves host data from environment @@ -9,9 +20,11 @@ def main(): TCPPORT = "54322" UDPPORT = "54323" - Server(HOST, TCPPORT, UDPPORT) + logger = Logger("log/"+get_random_string(8)+".log") + logger.info("starting up server") + server = Server(HOST, TCPPORT, UDPPORT, logging) + server.getNetworkManager().tcp.stop() sys.exit(0) - if __name__ == "__main__": main() \ No newline at end of file diff --git a/Game_Client/Classes/Game/Events/PlaceCard.py b/Game_Client/Classes/Game/Events/PlaceCard.py index ec7e1e8..c5729ca 100644 --- a/Game_Client/Classes/Game/Events/PlaceCard.py +++ b/Game_Client/Classes/Game/Events/PlaceCard.py @@ -28,7 +28,7 @@ def CardPlaced(world:World, card:int, type:str, owner:str, pos:pygame.Vector2, i world.spawnSpellCard(f"Assets/Cards/{card}/", pos, inputHandler, owner) pass elif type == "TrapCard": - world.spawmTrapCard(f"Assets/Cards/{card}/", pos, inputHandler, owner) + world.spawnTrapCard(f"Assets/Cards/{card}/", pos, inputHandler, owner) pass pass diff --git a/Game_Client/Classes/System/App.py b/Game_Client/Classes/System/App.py index ae5093b..caaf0ab 100644 --- a/Game_Client/Classes/System/App.py +++ b/Game_Client/Classes/System/App.py @@ -116,9 +116,11 @@ class App: mouse_pos = pygame.Vector2(mouse_x, mouse_y) if event.button == 1: # Wenn linke Maustaste losgelassen wird for card in self.__world.getCards(): + # card.setState("placed") + # TODO: send place card event to server + # resets the currently selected card in order to prevent it getting moved try: card.setDragging(False) - card.setState("placed") # TODO: send place card event to server # resets the currently selected card in order to prevent it getting moved PlaceCard(self.__tcpClient, card) # tells the server that the player placed this card