diff --git a/Game Server/Classes/Game/Player.py b/Game Server/Classes/Game/Player.py index 8682682..bb9044b 100644 --- a/Game Server/Classes/Game/Player.py +++ b/Game Server/Classes/Game/Player.py @@ -4,10 +4,11 @@ import random class Player: __id:int __hp:int + __mana:int __name:str __handCards:list - def __init__(self, name:str, hp:int=1000): + def __init__(self, name:str, hp:int=1000, mana:int=0): self.__hp = hp self.__name = name self.__handCards = [] @@ -28,6 +29,13 @@ class Player: def getHand(self) -> list: return self.__handCards + def getMana(self) -> int: + return self.__mana + + def addMana(self, amount) -> int: + self.__mana + amount + return self.__mana + def AddToHand(self, card) -> list: self.__handCards.append(card) return self.__handCards diff --git a/Game Server/Classes/Game/__pycache__/Player.cpython-311.pyc b/Game Server/Classes/Game/__pycache__/Player.cpython-311.pyc new file mode 100644 index 0000000..83afbc8 Binary files /dev/null and b/Game Server/Classes/Game/__pycache__/Player.cpython-311.pyc differ diff --git a/Game Server/Classes/System/GameManager.py b/Game Server/Classes/System/GameManager.py new file mode 100644 index 0000000..69dfe6b --- /dev/null +++ b/Game Server/Classes/System/GameManager.py @@ -0,0 +1,89 @@ +import socket +from Classes.Game.Player import Player + + +class GameManager: + __players:dict + __playingPlayer:Player + __state:str + __round:str + + def __init__(self): + self.__players = {} + self.__playingPlayer = None + self.__state = "waiting" + self.__round = "none" + pass + + # game round management + # this section manages the flow of rounds this should inherit itself + # ============================================================================= + + # this function iterates all + def progressRound(self): + # phases + # - playerPrep => playing player switches, gets a mana point and gets verified + if self.__playingPlayer != None: + for player in self.__players: + if self.__playingPlayer != player: + self.__playingPlayer = player + else: + self.__playingPlayer = next(iter(self.__players)) + # - playerDraw => player draws a card + # - playerPlay => player can place cards and active effects + # - playerEnd => player ends his turn and the code reiterates with the remaining player + pass + + # game state management + # this section mostly only used by the networking and event handling classes + # other parts should never need to interface with this unless really required + # ============================================================================= + def startGame(self): + self.__state = "running" + + print("game starts") + for userAddr in self.__users.keys(): + try: + user = self.__serverWorld.getPlayers[userAddr] + user.addMana(1000) + user.adjustHP(1000) + + payload = { + "event":"startgame", + "mana": user.getMana(), + "hp": user.getHP() + } + + self.send(payload, userAddr) + except Exception as e: + print(f"failed to start game due to error: {e}") + break + # handles notifying all players that the game starts + pass + + def stopGame(self): + # handles notifying all players that the game stops + # handles stoping the game itself and notifies server to stop itself + pass + + # player management + # the network manager will create a player instance + # ============================================================= + + # gets all player known to the game manager and returns them + def getPlayers(self) -> dict: + return self.__players + + # 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.__players[clientAddr] = { + player: player, + socket:socket + } + + # counts participating players and starts the game if enough have joined + if len(self.__players) == 2: + self.startGame() + + return self.__players \ 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 7729d76..38112fc 100644 --- a/Game Server/Classes/System/Network/EventHandler.py +++ b/Game Server/Classes/System/Network/EventHandler.py @@ -1,4 +1,8 @@ import socket +from Classes.Game.Player import Player +from Classes.System.GameManager import GameManager + +from Classes.System.World import World class TCPEventHandler: @@ -8,13 +12,13 @@ class TCPEventHandler: self.__tcpSocket = socket # handles passing of event data to the right functions - def handleTCPEvents(self, event): + def handleTCPEvents(self, event, gameManager:GameManager, address): pass class UDPEventHandler: __udpSocket:socket - def __init__(self, socket:socket): + def __init__(self, socket:socket, gameManager:GameManager): self.__udpSocket = socket def handleUDPEvents(self, event): diff --git a/Game Server/Classes/System/Network/NetworkManger.py b/Game Server/Classes/System/Network/NetworkManger.py index 7c4bedc..38df93a 100644 --- a/Game Server/Classes/System/Network/NetworkManger.py +++ b/Game Server/Classes/System/Network/NetworkManger.py @@ -1,8 +1,11 @@ import json import socket import threading +from Classes.Game.Player import Player +from Classes.System.GameManager import GameManager from Classes.System.Network.EventHandler import UDPEventHandler, TCPEventHandler +from Classes.System.World import World class NetworkManager: @@ -11,24 +14,28 @@ class NetworkManager: __Port:str __BufferSize:int = 1024 __udpSocket:socket - __users:list + __users:dict __eventHandler: UDPEventHandler __UDPClientThread:threading.Thread - - def __init__(self, Addr:str, Port:str): + __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) - self.__udpSocket.bind((self.__Addr, self.__Port)) - - # Starten eines Threads für das Empfangen von UDP-Daten + + 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 incomming udp data + # handles incoming udp data def receive(self): while True: data, address = self.__udpSocket.recvfrom(self.__BufferSize) @@ -40,7 +47,7 @@ class NetworkManager: self.__users[user] = address # Storing new user in dictionary # Process the message and handle accordingly - self.__eventHandler.handleUDPEvents(messageJson) + self.__eventHandler.handleUDPEvents(messageJson, self.__serverWorld) print(f"Received message from {address}: {message}") def broadcast(self, payload:dict): @@ -56,15 +63,14 @@ class NetworkManager: __Port:str __BufferSize:int = 1024 __tcpSocket:socket - __users:list - __eventHandler: TCPEventHandler + __eventHandler: dict __TCPClientThread:threading.Thread + __gameManager:GameManager - def __init__(self, Addr:str, Port:str): + def __init__(self, Addr:str, Port:str, gameManager:GameManager): self.__Addr = Addr self.__Port = int(Port) - - self.__users = {} + self.__gameManager = gameManager self.__eventHandler = {} self.__tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.__tcpSocket.bind((self.__Addr, self.__Port)) @@ -95,16 +101,20 @@ class NetworkManager: data = client_socket.recv(self.__BufferSize) if not data: print(f"Connection with {client_address} closed.") - break # Verbindung geschlossen, Schleife beenden + break message = data.decode() messageJson = json.loads(message) user = messageJson.get("user") + # 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.__users: - self.__users[user] = client_address + if messageJson["event"] == "login": + self.__gameManager.addPlayers(Player(messageJson["username"]), self.__tcpSocket, client_address) + print(f"connected users {len(self.__users)}") - self.__eventHandler[client_address].handleTCPEvents(messageJson) + self.__eventHandler[client_address].handleTCPEvents(messageJson, self.__gameManager, client_address) print(f"Received message from {client_address}: {message}") except socket.error as e: @@ -118,16 +128,20 @@ class NetworkManager: print(f"Error receiving data from {client_address}: {e}") def broadcast(self, payload:dict): - for user_socket in self.__users.values(): - user_socket.send(json.dumps(payload).encode()) + for user in self.__gameManager.getPlayers().values(): + user["socket"].send(json.dumps(payload).encode()) - def send(self, payload:dict, user:str): - if user in self.__users: - self.__users[user].send(json.dumps(payload).encode()) + def send(self, payload: dict, user: str): + players = self.__gameManager.getPlayers() + + 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.") tcp: TCP udp: UDP - def __init__(self, Addr:str, TCPPort:str, UDPPort:str): - self.tcp = self.TCP(Addr, TCPPort) - self.udp = self.UDP(Addr, UDPPort) + 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) 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 783943a..4f106e3 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 ef6db75..7bc686b 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/PlayerManager.py b/Game Server/Classes/System/PlayerManager.py index 297a24a..e149622 100644 --- a/Game Server/Classes/System/PlayerManager.py +++ b/Game Server/Classes/System/PlayerManager.py @@ -1,12 +1,6 @@ import json -from Classes.Objects.Player import Player - class Player: - __users:list - - def __init__(self): - self.__users = [] - + def createUser(self, user:json): self.__users.append(user) @@ -23,12 +17,7 @@ class Player: def getUsers(self) -> list: return self.__users - def getUser(self, user:int) -> (any | None): + def getUser(self, user:int): for user in self.__users: if int(user["id"]) == user: - return user - - def getUser(self, user:str) -> (any | None): - for user in self.__users: - if user["name"] == user: return user \ No newline at end of file diff --git a/Game Server/Classes/System/Server.py b/Game Server/Classes/System/Server.py index f5f4fa6..bc8f7f6 100644 --- a/Game Server/Classes/System/Server.py +++ b/Game Server/Classes/System/Server.py @@ -1,25 +1,32 @@ import json import socket import threading +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 class Server: __address:str __tcpPort:str __udpPort:str - + __world:World + __gameManager:GameManager + networkManager:NetworkManager def __init__(self, address:str, tcpPort:str, udpPort:str): self.__address = address self.__tcpPort = tcpPort self.__udpPort = udpPort + self.__world = World() + self.__gameManager = GameManager() - self.startServer() + self.startServer(self.__gameManager) # handles starting the server and assigning socket values to the local reference - def startServer(self): - self.__networkManager = NetworkManager(self.__address, self.__tcpPort, self.__udpPort) \ No newline at end of file + def startServer(self, gameManager:GameManager): + self.__networkManager = NetworkManager(self.__address, self.__tcpPort, self.__udpPort, gameManager) \ No newline at end of file diff --git a/Game Server/Classes/System/World.py b/Game Server/Classes/System/World.py new file mode 100644 index 0000000..f6b2957 --- /dev/null +++ b/Game Server/Classes/System/World.py @@ -0,0 +1,20 @@ +import socket +from Classes.Game.Player import Player + + +class World: + __players:dict + + def __init__(self): + self.__players = {} + + def getPlayers(self) -> list: + return self.__players + + def addPlayers(self, player:Player, socket:socket, clientAddr) -> list: + self.__players[clientAddr] = { + player: player, + socket:socket + } + + return self.__players \ 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 new file mode 100644 index 0000000..8fa01a3 Binary files /dev/null and b/Game Server/Classes/System/__pycache__/GameManager.cpython-311.pyc differ diff --git a/Game Server/Classes/System/__pycache__/PlayerManager.cpython-311.pyc b/Game Server/Classes/System/__pycache__/PlayerManager.cpython-311.pyc new file mode 100644 index 0000000..b43d1ec Binary files /dev/null and b/Game Server/Classes/System/__pycache__/PlayerManager.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 14462d2..c6001c4 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/Classes/System/__pycache__/World.cpython-311.pyc b/Game Server/Classes/System/__pycache__/World.cpython-311.pyc new file mode 100644 index 0000000..a74158d Binary files /dev/null and b/Game Server/Classes/System/__pycache__/World.cpython-311.pyc differ