merged rework -> master
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
import json
|
||||
import socket
|
||||
import time
|
||||
from Classes.Game.Player import Player
|
||||
|
||||
|
||||
class GameManager:
|
||||
__players:dict
|
||||
__playingPlayer:Player
|
||||
__state:str
|
||||
__round:str
|
||||
__cards:list
|
||||
|
||||
def __init__(self, logger):
|
||||
self.__players = {}
|
||||
self.__playingPlayer = None
|
||||
self.__state = "waiting"
|
||||
self.__round = "none"
|
||||
self.logger = logger
|
||||
self.__cards = []
|
||||
pass
|
||||
|
||||
def getLogger(self):
|
||||
return self.logger
|
||||
|
||||
# card management
|
||||
def spawnCard(self, card, owner, x, y):
|
||||
# self.logger.info("spawning card")
|
||||
|
||||
self.__cards.append(card)
|
||||
|
||||
payload = {
|
||||
"event":"PlacedCard",
|
||||
"owner": owner,
|
||||
"card": card,
|
||||
"x": x,
|
||||
"y": y,
|
||||
}
|
||||
|
||||
for userAddr in self.__players.keys():
|
||||
try:
|
||||
self.logger.info(f"send to client {self.__players[userAddr]['player'].getID() != owner}")
|
||||
if self.__players[userAddr]["player"].getID() != owner:
|
||||
self.__players[userAddr]["socket"].send(json.dumps(payload).encode())
|
||||
except:
|
||||
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, tcpSocket: socket):
|
||||
self.__state = "running"
|
||||
|
||||
players = list(self.__players.values())
|
||||
|
||||
print("game starts")
|
||||
self.logger.info("game manager is starting the game")
|
||||
for userAddr, player_data in self.__players.items():
|
||||
try:
|
||||
user = player_data["player"]
|
||||
user.addMana(1000)
|
||||
user.adjustHP(1000)
|
||||
user.shuffleDeck()
|
||||
cards = self.__players[userAddr]["deck"]
|
||||
user.setHand(cards[:5])
|
||||
|
||||
# iterates until the enemy player is not anymore equal to current player
|
||||
enemy = next(player_data["player"] for player_data in players if player_data["player"] != user)
|
||||
|
||||
payload = {
|
||||
"event": "startgame",
|
||||
"player": {
|
||||
"mana": user.getMana(),
|
||||
"hp": user.getHP(),
|
||||
"hand": user.getHand()
|
||||
},
|
||||
"enemy": {
|
||||
"id": enemy.getID(),
|
||||
"name": enemy.getName(),
|
||||
"hp": enemy.getHP(),
|
||||
},
|
||||
}
|
||||
|
||||
print(f"user {player_data["socket"]}")
|
||||
player_data["socket"].send(json.dumps(payload).encode())
|
||||
except Exception as e:
|
||||
self.logger.error(f"failed to start game due to error: {e}")
|
||||
break
|
||||
|
||||
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, deck) -> dict:
|
||||
|
||||
self.logger.info(f"creating user with id: {player.getID}")
|
||||
self.__players[clientAddr] = {
|
||||
"player": player,
|
||||
"deck": deck,
|
||||
"socket":socket
|
||||
}
|
||||
self.logger.info(f"new length of user dictionary: {len(self.__players)}")
|
||||
|
||||
payload = {
|
||||
"event":"loginresponse",
|
||||
"status": "success",
|
||||
"id": player.getID(),
|
||||
"name": player.getName()
|
||||
}
|
||||
|
||||
socket.send(json.dumps(payload).encode())
|
||||
|
||||
|
||||
# counts participating players and starts the game if enough have joined
|
||||
if len(self.__players) >= 2:
|
||||
time.sleep(1)
|
||||
self.logger.info("2 players have join game starts")
|
||||
self.startGame()
|
||||
|
||||
return self.__players
|
||||
|
||||
def removePlayers(self, clientAddr):
|
||||
self.logger.info(f"removing player with address '{clientAddr}' from players database")
|
||||
del self.__players[clientAddr]
|
||||
@@ -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)
|
||||
@@ -0,0 +1,45 @@
|
||||
import socket
|
||||
from Classes.Game.Player import Player
|
||||
from Classes.System.GameManager import GameManager
|
||||
|
||||
from Classes.System.World import World
|
||||
|
||||
|
||||
class TCPEventHandler:
|
||||
__tcpSocket:socket
|
||||
|
||||
def __init__(self, socket:socket):
|
||||
self.__tcpSocket = socket
|
||||
|
||||
# handles passing of event data to the right functions
|
||||
def handleTCPEvents(self, event, gameManager:GameManager, address):
|
||||
gameManager.getLogger().info(f"incommingevent {event}")
|
||||
if event["event"] == "PlaceCard":
|
||||
gameManager.getLogger().info(f"player {event['user']} attempted to place card {event['card']}")
|
||||
for playerKey in gameManager.getPlayers().keys():
|
||||
player = gameManager.getPlayers()[playerKey]
|
||||
if int(event["user"]) != player["player"].getID():
|
||||
payload = {
|
||||
"event":"cardPlaced",
|
||||
"card": {
|
||||
"card":event["card"],
|
||||
"owner": event["user"],
|
||||
"x": event["x"],
|
||||
"y": event["y"]
|
||||
}
|
||||
}
|
||||
player["socket"].send(payload)
|
||||
pass
|
||||
elif event["event"] == "MoveCard":
|
||||
pass
|
||||
elif event["event"] == "RemoveCard":
|
||||
pass
|
||||
elif event["event"] == "AttackCard":
|
||||
pass
|
||||
elif event["event"] == "AttackPlayer":
|
||||
pass
|
||||
elif event["event"] == "ActivateEffectCard":
|
||||
pass
|
||||
elif event["event"] == "ActivateMonsterCard":
|
||||
pass
|
||||
pass
|
||||
@@ -0,0 +1,145 @@
|
||||
import json
|
||||
import signal
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
from Classes.Game.Player import Player
|
||||
from Classes.System.GameManager import GameManager
|
||||
|
||||
from Classes.System.Network.EventHandler import TCPEventHandler
|
||||
from Classes.System.World import World
|
||||
|
||||
class NetworkManager:
|
||||
class TCP:
|
||||
__Addr:str
|
||||
__Port:str
|
||||
__BufferSize:int = 1024
|
||||
__tcpSocket:socket
|
||||
__eventHandler: dict
|
||||
__users: dict
|
||||
__TCPClientThread:threading.Thread
|
||||
__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()
|
||||
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:
|
||||
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:
|
||||
self.__gameManager.getLogger().info(f"Connection with {client_address} closed.")
|
||||
break
|
||||
|
||||
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.getLogger().info("user logging in")
|
||||
self.__gameManager.getLogger().info("task passed off to gameManager")
|
||||
user = self.__gameManager.addPlayers(Player(messageJson["username"], messageJson["deck"]), client_socket, client_address, messageJson["deck"])
|
||||
self.__gameManager.getLogger().info(f"connected users {len(self.__gameManager.getPlayers())}")
|
||||
|
||||
self.__gameManager.getLogger().info(f"confirming login for user")
|
||||
self.send({
|
||||
"event": "loginresponse",
|
||||
"status": "success",
|
||||
"username": user[client_address]["player"].getName(),
|
||||
"id": user[client_address]["player"].getID(),
|
||||
}, client_address)
|
||||
|
||||
self.__eventHandler[client_address].handleTCPEvents(messageJson, self.__gameManager, client_address)
|
||||
self.__gameManager.getLogger().info(f"Received message from {client_address}: {message}")
|
||||
|
||||
except socket.error as e:
|
||||
|
||||
if e.errno == 10054:
|
||||
self.__gameManager.getLogger().error(f"Connection with {client_address} forcibly closed by remote host.")
|
||||
players = self.__gameManager.getPlayers()
|
||||
self.__gameManager.removePlayers(client_address)
|
||||
self.__gameManager.getLogger().info(f"new player length {len(players)}")
|
||||
break
|
||||
|
||||
self.__gameManager.getLogger().error(f"Socket error receiving data from {client_address}: {e}")
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
self.__gameManager.getLogger().error(f"JSON decoding error receiving data from {client_address}: {e}")
|
||||
|
||||
# except Exception as e:
|
||||
# self.__gameManager.getLogger().error(f"UknownError receiving data from {client_address} due to error: {e}")
|
||||
|
||||
def broadcast(self, payload:dict):
|
||||
for user in self.__gameManager.getPlayers().values():
|
||||
user["socket"].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:
|
||||
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)
|
||||
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)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
import json
|
||||
class Player:
|
||||
|
||||
def createUser(self, user:json):
|
||||
self.__users.append(user)
|
||||
|
||||
def createUser(self, user:json):
|
||||
if self.getUser(user["username"]) == None:
|
||||
self.__users.append(Player(user["username"]))
|
||||
|
||||
def removeUser(self, user:int):
|
||||
self.__users.remove(user)
|
||||
|
||||
def removeUser(self, user:str):
|
||||
self.__users.remove(user)
|
||||
|
||||
def getUsers(self) -> list:
|
||||
return self.__users
|
||||
|
||||
def getUser(self, user:int):
|
||||
for user in self.__users:
|
||||
if int(user["id"]) == user:
|
||||
return user
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
|
||||
from Classes.Game.Player import Player
|
||||
|
||||
|
||||
class QueueManager:
|
||||
__queue:list
|
||||
|
||||
def __init__(self):
|
||||
self.__queue = []
|
||||
|
||||
def getQueue(self) -> list:
|
||||
return self.__queue
|
||||
|
||||
def addToQueue(self, user) -> list:
|
||||
if self.isInQueue(user["id"]):
|
||||
self.__queue.append(user)
|
||||
return self.__queue
|
||||
|
||||
def removeFromQueue(self, player:Player) -> list:
|
||||
self.__queue.remove(player)
|
||||
return self.__queue
|
||||
|
||||
def isInQueue(self, user:int) -> bool:
|
||||
for user in self.__queue:
|
||||
if int(user["id"]) == user:
|
||||
return True
|
||||
return False
|
||||
|
||||
def isInQueue(self, user:str) -> bool:
|
||||
for user in self.__queue:
|
||||
if user["username"] == user:
|
||||
return True
|
||||
return False
|
||||
@@ -0,0 +1,40 @@
|
||||
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
|
||||
from Classes.System.Logger import Logger
|
||||
|
||||
class Server:
|
||||
|
||||
__address:str
|
||||
__tcpPort:str
|
||||
__udpPort:str
|
||||
__world:World
|
||||
__gameManager:GameManager
|
||||
|
||||
networkManager:NetworkManager
|
||||
|
||||
def __init__(self, address:str, tcpPort:str, udpPort:str, logger:Logger):
|
||||
self.__address = address
|
||||
self.__tcpPort = tcpPort
|
||||
self.__udpPort = udpPort
|
||||
self.__world = World()
|
||||
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.logger.info("starting up network manager")
|
||||
self.__networkManager = NetworkManager(self.__address, self.__tcpPort, self.__udpPort, gameManager)
|
||||
|
||||
def getNetworkManager(self) -> NetworkManager:
|
||||
return self.__networkManager
|
||||
@@ -0,0 +1,6 @@
|
||||
import os
|
||||
|
||||
|
||||
class PathUtil:
|
||||
def getAbsolutePathTo(notAbsolutPath:str) -> str:
|
||||
return os.path.abspath("OLD_Server/" + notAbsolutPath)
|
||||
@@ -0,0 +1,11 @@
|
||||
import random
|
||||
import string
|
||||
|
||||
|
||||
class StringUtils:
|
||||
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
|
||||
@@ -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
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user