Further defined the Expansion class
This commit is contained in:
14
players.json
14
players.json
@ -1,14 +1,14 @@
|
||||
{
|
||||
"expansions":
|
||||
{
|
||||
"ShockColar1": {"players": ["Brosef"], "types": ["shock"]},
|
||||
"RobotBarman": {"players": ["Tango", "TRS_MML"], "types": ["drink"]},
|
||||
"ChallengeDB": {"players": ["TRS_MML"], "types": ["challenge"]},
|
||||
"SourCandy": {"players": [], "types": ["food"]}
|
||||
"ShockColar1": {"players": ["Brosef"], "tags": ["shock"]},
|
||||
"RobotBarman": {"players": ["Tango", "TRS_MML"], "tags": ["drink"]},
|
||||
"ChallengeDB": {"players": ["TRS_MML"], "tags": ["challenge"]},
|
||||
"SourCandy": {"players": [], "tags": ["food"]}
|
||||
},
|
||||
"players": {
|
||||
"Brosef": {"flags": [], "expansions": {"exampleExpansion": {"playerOption": 5}}, "games": {"gameID0": 2}},
|
||||
"TRS_MML": {"flags": [], "expansions": {"exampleExpansion": {"playerOption": 5}}, "games": {"gameID0": 1}},
|
||||
"Tango": {"flags": [], "expansions": {"exampleExpansion": {"playerOption": 5}}, "games": {"gameID0": 0}}
|
||||
"Brosef": {"flags": [], "expansions": {"exampleExpansion": {"playerOption": 5}}, "gamesSave": {"gameID0": 2}},
|
||||
"TRS_MML": {"flags": [], "expansions": {"exampleExpansion": {"playerOption": 5}}, "gamesSave": {"gameID0": 1}},
|
||||
"Tango": {"flags": [], "expansions": {"exampleExpansion": {"playerOption": 5}}, "gamesSave": {"gameID0": 0}}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,20 @@
|
||||
class Expansion:
|
||||
def __init__(self, parent, globalConfig):
|
||||
setattr(parent, self.__class__.ID, self)
|
||||
from player_settings import Expansion
|
||||
|
||||
class PlayerExpansion:
|
||||
def __init__(self, player, localConfig):
|
||||
class serialShockers(Expansion):
|
||||
_api = None
|
||||
|
||||
def __init__(self, ID, expansionsManager):
|
||||
super().__init__(ID, expansionsManager)
|
||||
if serialShockers._api is None:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
|
||||
def step(self, action):
|
||||
pass
|
||||
|
||||
def reset(self):
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
@ -13,6 +13,12 @@ _log = logging.getLogger('NoPE-Lib')
|
||||
|
||||
|
||||
class Hook:
|
||||
"""
|
||||
A class that allows the creation of hooks.
|
||||
|
||||
Methods:
|
||||
connect: Connect a slot when the signal is launched.
|
||||
"""
|
||||
def __init__(self):
|
||||
self._slot = []
|
||||
|
||||
@ -21,6 +27,7 @@ class Hook:
|
||||
fct(*args, **kwargs)
|
||||
|
||||
def connect(self, fct):
|
||||
""" Connect a slot when the signal is launched. """
|
||||
self._slot.append(fct)
|
||||
|
||||
|
||||
@ -43,15 +50,21 @@ class PlayersManager:
|
||||
"""
|
||||
defaultPlayerConfig = {"flags": [], "expansions": {}, "games": {}}
|
||||
|
||||
def __init__(self, gameID: str=None, activePlayers: list[str]=None, playersPath: str='../players.json', loggerID: str='PlayersManager'):
|
||||
def __init__(
|
||||
self, gameID: str=None, activePlayers: list[str]=None,
|
||||
playersPath: str='../players.json', loggerID: str='PlayersManager'
|
||||
):
|
||||
"""
|
||||
Initialises a list of players.
|
||||
|
||||
Args:
|
||||
gameID (str): The ID of the game used in the configuration file.
|
||||
activePlayers (list of str): The names of the players that are playing. Defaults to none which includes all players.
|
||||
playersPath (str, optional): The path of the players.json file. Defaults to '../players.json'.
|
||||
loggerID (str, optional): The ID used for logging. Defaults to 'Players'.
|
||||
gameID (str): The ID of the game used in the configuration file.
|
||||
activePlayers (list of str): The names of the players that are playing.
|
||||
Defaults to none which includes all players.
|
||||
playersPath (str, optional): The path of the players.json file.
|
||||
Defaults to '../players.json'.
|
||||
loggerID (str, optional): The ID used for logging. Defaults to
|
||||
'Players'.
|
||||
"""
|
||||
|
||||
# Store the arguments
|
||||
@ -60,7 +73,7 @@ class PlayersManager:
|
||||
# Deal with the path
|
||||
self._playersPath = Path(playersPath)
|
||||
# Get the config file
|
||||
with open(self._playersPath, 'r') as f:
|
||||
with open(self._playersPath, "r", encoding="utf-8") as f:
|
||||
self._cfg = json.load(f)
|
||||
# Create the players
|
||||
activePlayers = activePlayers if activePlayers is not None else self._cfg["players"].keys()
|
||||
@ -89,15 +102,11 @@ class PlayersManager:
|
||||
self.onMadePlayerActive(playerName)
|
||||
return self._player_data[playerName]
|
||||
|
||||
def __setitem__(self, playerName: str, config: dict, makeNewPlayerObject=False):
|
||||
def __setitem__(self, playerName: str, config: dict):
|
||||
"""
|
||||
Replace a player's config with another one.
|
||||
|
||||
Arguments:
|
||||
playerName (str):
|
||||
config (dict):
|
||||
makeNewPlayerObject (bool):
|
||||
"""
|
||||
makeNewPlayerObject = False
|
||||
if makeNewPlayerObject:
|
||||
previousInstance = self._player_data[playerName]
|
||||
self._player_data[playerName] = Player(playerName, self, **config)
|
||||
@ -121,21 +130,29 @@ class PlayersManager:
|
||||
|
||||
@property
|
||||
def config(self):
|
||||
""" Deepcopy of the dictionnary of the config. """
|
||||
return copy.deepcopy(self._cfg)
|
||||
|
||||
@property
|
||||
def gameID(self):
|
||||
""" String of the current game ID. """
|
||||
return self._currentGameID
|
||||
|
||||
@gameID.setter
|
||||
def gameID(self, gameID: str):
|
||||
self._currentGameID = gameID
|
||||
self._player_data = {name: Player(name, self, **cfg) for name, cfg in self._cfg["players"].items()}
|
||||
self._player_data = {
|
||||
name: Player(name, self, **cfg)
|
||||
for name, cfg in self._cfg["players"].items()
|
||||
}
|
||||
|
||||
@gameID.deleter
|
||||
def gameID(self):
|
||||
self._currentGameID = None
|
||||
self._player_data = {name: Player(name, self, **cfg) for name, cfg in self._cfg["players"].items()}
|
||||
self._player_data = {
|
||||
name: Player(name, self, **cfg)
|
||||
for name, cfg in self._cfg["players"].items()
|
||||
}
|
||||
|
||||
def keys(self):
|
||||
""" Iterator of the active players' names """
|
||||
@ -150,8 +167,9 @@ class PlayersManager:
|
||||
return self._player_data.items()
|
||||
|
||||
def save(self):
|
||||
with open(self._playersPath, 'w') as f:
|
||||
self._cfg = json.dump(f, self._cfg)
|
||||
""" Save the config to the disk. """
|
||||
with open(self._playersPath, "w", encoding="utf-8") as f:
|
||||
self._cfg = f.write(json.dump(f, self._cfg))
|
||||
|
||||
|
||||
class Player:
|
||||
@ -165,58 +183,74 @@ class Player:
|
||||
gameState:
|
||||
|
||||
Methods:
|
||||
generateConfig:
|
||||
exportConfig:
|
||||
punish:
|
||||
"""
|
||||
def __init__(self, name: str, manager: PlayersManager, **cfg):
|
||||
self._name = name
|
||||
def __init__(self, playerName: str, manager: PlayersManager, **cfg):
|
||||
self._name = playerName
|
||||
self._manager = manager
|
||||
self._gamesSave = {}
|
||||
for key, val in cfg.items():
|
||||
setattr(self, "_" + key, val)
|
||||
|
||||
def __repr__(self):
|
||||
return f"Player {self._name} has {len(self._flags)} flag(s), {len(self._expansions)} expansions and {len(self._games)} saved game"
|
||||
txt = f"Player {self._name} has "
|
||||
txt += f"{len(self.flags)} flags, "
|
||||
txt += f"{len(self._expansions)} expansions and "
|
||||
txt += f"{len(self._gamesSave)} saved game"
|
||||
return txt
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
""" String representing the name of the player. """
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def flags(self):
|
||||
""" List of the flags associated with the player. """
|
||||
return self._flags
|
||||
|
||||
@flags.setter
|
||||
def flags(self, newFlags):
|
||||
self._flags = newFlags
|
||||
# The container was changed and must be transmited to the manager
|
||||
self._manager[self._name] = self.generateConfig()
|
||||
self._manager[self._name] = self.exportConfig()
|
||||
|
||||
@property
|
||||
def expansionsConfig(self):
|
||||
return self._expansionsConfig
|
||||
def expansions(self):
|
||||
""" Dictionnary of the player's expansion settings. """
|
||||
return self._expansions
|
||||
|
||||
@expansionsConfig.setter
|
||||
@expansions.setter
|
||||
def expansions(self, newExpansions):
|
||||
self._expansionsConfig = newExpansions
|
||||
self._expansions = newExpansions
|
||||
# The container was changed and must be transmited to the manager
|
||||
self._manager[self._name] = self.generateConfig()
|
||||
self._manager[self._name] = self.exportConfig()
|
||||
|
||||
@property
|
||||
def gameSave(self):
|
||||
"""The save for the current game. If no configuration was found None is returned."""
|
||||
return self._games.get(self._manager.gameID)
|
||||
"""
|
||||
The save for the current game. If no configuration was found None
|
||||
is returned.
|
||||
"""
|
||||
return self._gamesSave.get(self._manager.gameID)
|
||||
|
||||
@gameSave.setter
|
||||
def gameSave(self, newGameSave):
|
||||
self._games[self._manager.gameID] = newGameSave
|
||||
self._gamesSave[self._manager.gameID] = newGameSave
|
||||
|
||||
def generateConfig(self):
|
||||
return {"flags": self._flags, "expansions": self._expansions, "games": self._games}
|
||||
def exportConfig(self):
|
||||
""" Export the exact player's configuration. """
|
||||
return {
|
||||
"flags": self._flags,
|
||||
"expansions": self._expansions,
|
||||
"games": self._gamesSave
|
||||
}
|
||||
|
||||
def punish(self, value, preferedExpansion: str=None):
|
||||
do_something = lambda value: value
|
||||
do_something = lambda value, preferedExpansion: value
|
||||
additionalInfos = {
|
||||
"expansionClass": "challengeDB",
|
||||
"expansionID": "challengeDB",
|
||||
"balancedValue": 0.2,
|
||||
"showOnScreen": "Do 100 push-up",
|
||||
"error": None,
|
||||
@ -224,59 +258,10 @@ class Player:
|
||||
}
|
||||
# NOTE Make a result class instead and an error class
|
||||
# TODO Implement a way to choose between the available expansions
|
||||
additionalInfos = do_something(value)
|
||||
additionalInfos = do_something(value, preferedExpansion)
|
||||
return additionalInfos
|
||||
|
||||
|
||||
class Expansion:
|
||||
"""
|
||||
|
||||
Attributes:
|
||||
specs:
|
||||
|
||||
Methods:
|
||||
step:
|
||||
reset:
|
||||
close:
|
||||
|
||||
Signals:
|
||||
onError:
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Intended behavior of the method:
|
||||
Initialise the creation of an expansion
|
||||
Should NEVER use any kind of argument.
|
||||
Raise an error if not available.
|
||||
"""
|
||||
self.onError = Hook()
|
||||
self._specs
|
||||
pass
|
||||
|
||||
@property
|
||||
def specs(self):
|
||||
return self._specs
|
||||
|
||||
@abc.abstractmethod
|
||||
def step(self, action):
|
||||
"""
|
||||
Call close if an error is thrown
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def reset(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def makeSpecs(self):
|
||||
pass
|
||||
|
||||
|
||||
class ExpansionsManager:
|
||||
"""
|
||||
Manager of the availability of the expansions.
|
||||
@ -286,22 +271,31 @@ class ExpansionsManager:
|
||||
Container of the expansions to try making available
|
||||
activeExpansions: dict of Expansion
|
||||
Container of the relevent expansions
|
||||
|
||||
TODO Add an interface to allow the modification of the expansion settings
|
||||
"""
|
||||
defaultExpansionConfig = {"players": (), "types": ()}
|
||||
keysConvert2Tuple = ("players", "types")
|
||||
tags = ["shock", "spice", "sour", "drink", "challenge"]
|
||||
# TODO Add an interface to allow the modification of the expansion settings
|
||||
# (attributed players / types)
|
||||
# TODO Allow to get a list of expansions with a specific tag/player
|
||||
|
||||
def __init__(self, playersManager: PlayersManager, includedExpansions: tuple[str]=None):
|
||||
"""
|
||||
Arguments:
|
||||
tryInclude: bool=False, tryActivate: bool=False
|
||||
"""
|
||||
# Create the attributes
|
||||
self.playersManager = playersManager
|
||||
self._cfg = playersManager.config["expansions"]
|
||||
self._includedExpansions = tuple(includedExpansions) if includedExpansions is not None else ()
|
||||
if includedExpansions is not None:
|
||||
self._includedExpansions = tuple(includedExpansions)
|
||||
else:
|
||||
self._includedExpansions = ()
|
||||
# Convert the required lists into tuples
|
||||
for expansionID in self._cfg["expansions"]:
|
||||
for key in self.keysConvert2Tuple:
|
||||
self._cfg["expansions"][expansionID][key] = tuple(self._cfg["expansions"][expansionID][key])
|
||||
converted = tuple(self._cfg["expansions"][expansionID][key])
|
||||
self._cfg["expansions"][expansionID][key] = converted
|
||||
# Compute the active expansions
|
||||
self._activeExpansions = {}
|
||||
for expansionID in self._listPossiblyValidExpansions():
|
||||
@ -311,8 +305,21 @@ class ExpansionsManager:
|
||||
playersManager.onMadePlayerActive.connect(self._activePlayerAdded)
|
||||
playersManager.onMadePlayerInactive.connect(self._activePlayerRemoved)
|
||||
|
||||
def __getitem__(self, expansionID: str):
|
||||
return self._activeExpansions[expansionID]
|
||||
|
||||
def __len__(self):
|
||||
return len(self._activeExpansions)
|
||||
|
||||
def __iter__(self):
|
||||
return self._activeExpansions.__iter__()
|
||||
|
||||
def __repr__(self):
|
||||
return f"ExpansionsManager has {len(self._activeExpansions)} active expansions"
|
||||
|
||||
@property
|
||||
def includedExpansions(self):
|
||||
""" Dictionnary of the included expansions. """
|
||||
return self._includedExpansions
|
||||
|
||||
@includedExpansions.setter
|
||||
@ -325,26 +332,29 @@ class ExpansionsManager:
|
||||
self._includedExpansions = ()
|
||||
|
||||
@property
|
||||
def activeExpansions(self):
|
||||
return self._activeExpansions
|
||||
def config(self):
|
||||
""" Dictionnary of the expansions' settings. """
|
||||
return self._cfg
|
||||
|
||||
def _getPlayersFillMissing(self, expansionID):
|
||||
return set(self._cfg["expansions"].get(expansionID, {}).get("players", []))
|
||||
|
||||
def _listPossiblyValidExpansions(self):
|
||||
"""
|
||||
List expansions that are included, defined in PDOLib and are available to at least one active player.
|
||||
List expansions that are included, defined in PDOLib and are available
|
||||
to at least one active player.
|
||||
"""
|
||||
activePlayers = set(self.playersManager.keys())
|
||||
possiblyValidExpansions = [
|
||||
expansion for expansion in self._includedExpansions
|
||||
if hasattr(PDOLib, expansion) and not self._getPlayersFillMissing(expansion).isdisjoint(activePlayers)
|
||||
if hasattr(PDOLib, expansion) and
|
||||
not self._getPlayersFillMissing(expansion).isdisjoint(activePlayers)
|
||||
]
|
||||
return possiblyValidExpansions
|
||||
|
||||
def _createExpansion(self, expansionID):
|
||||
try:
|
||||
expansion = getattr(PDOLib, expansionID)()
|
||||
expansion = getattr(PDOLib, expansionID)(expansionID, self)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
@ -374,10 +384,11 @@ class ExpansionsManager:
|
||||
|
||||
def _activePlayerAdded(self, playerName):
|
||||
# Find the expansions that are to be created
|
||||
possibleAddition = set(self._includedExpansions).difference(self.activeExpansions)
|
||||
possibleAddition = set(self._includedExpansions).difference(self._activeExpansions)
|
||||
filteredAddition = [
|
||||
expansionID for expansionID in possibleAddition
|
||||
if hasattr(PDOLib, expansionID) and playerName in self._getPlayersFillMissing(expansionID)
|
||||
if hasattr(PDOLib, expansionID) and
|
||||
playerName in self._getPlayersFillMissing(expansionID)
|
||||
]
|
||||
# Create the expansions
|
||||
for expansionID in filteredAddition:
|
||||
@ -386,7 +397,7 @@ class ExpansionsManager:
|
||||
def _activePlayerRemoved(self, playerName):
|
||||
# Find the expansions that are to be removed
|
||||
filteredRemoval = [
|
||||
expansionID for expansionID in self.activeExpansions
|
||||
expansionID for expansionID in self._activeExpansions
|
||||
if playerName in self._cfg["players"] and len(self._cfg["players"]) == 1
|
||||
]
|
||||
# Close the expansions
|
||||
@ -396,7 +407,7 @@ class ExpansionsManager:
|
||||
def _errorOccured(self, expansionID):
|
||||
self._removeExpansion(expansionID)
|
||||
|
||||
def _expansionPlayersChanged(self, expansionID):
|
||||
def expansionPlayersChanged(self, expansionID):
|
||||
expansionIsActive = expansionID in self._activeExpansions
|
||||
activePlayers = set(self.playersManager.keys())
|
||||
expansionHasNoPlayers = self._getPlayersFillMissing(expansionID).isdisjoint(activePlayers)
|
||||
@ -408,29 +419,106 @@ class ExpansionsManager:
|
||||
|
||||
def initilizeExpansion(self, expansionID: str, suppressError: bool=False):
|
||||
"""
|
||||
Initilise the expansion.
|
||||
Initilise (possibly again) the expansion.
|
||||
|
||||
Arguments:
|
||||
expansionID (str):
|
||||
suppressError (bool):
|
||||
"""
|
||||
if expansionID in self._activeExpansions:
|
||||
self._removeExpansion(expansionID)
|
||||
# Make sure that the expansion is relevent
|
||||
if not suppressError:
|
||||
# Make sure that the expansion is relevent
|
||||
# Verify that creating the expansion was successful
|
||||
pass
|
||||
# Try creating a new instance of the expansion
|
||||
# Update the list of relevent expansions
|
||||
pass
|
||||
# TODO Implement the rest
|
||||
|
||||
|
||||
class Expansion:
|
||||
"""
|
||||
A meta class implementation meant to describe how to interact with any kind
|
||||
of expansions.
|
||||
|
||||
Attributes:
|
||||
players (tuple of str):
|
||||
tags (tuple of flag):
|
||||
|
||||
Methods:
|
||||
step:
|
||||
reset:
|
||||
close:
|
||||
|
||||
Signals:
|
||||
onError:
|
||||
"""
|
||||
|
||||
def __init__(self, ID: str, expansionsManager: ExpansionsManager):
|
||||
"""
|
||||
Initialise the creation of an expansion and raise an error if not
|
||||
available.
|
||||
"""
|
||||
self._ID = ID
|
||||
self._manager = expansionsManager
|
||||
self.onError = Hook()
|
||||
|
||||
@property
|
||||
def players(self):
|
||||
""" Players that have access to this expansion. """
|
||||
return self._manager.config[self._ID]["players"]
|
||||
|
||||
@players.setter
|
||||
def players(self, newPlayers):
|
||||
""" Players that have access to this expansion. """
|
||||
self._manager.config[self._ID]["players"] = tuple(newPlayers)
|
||||
self._manager.expansionPlayersChanged(self._ID)
|
||||
|
||||
@players.deleter
|
||||
def players(self):
|
||||
self._manager.config[self._ID]["players"] = ()
|
||||
self._manager.expansionPlayersChanged(self._ID)
|
||||
|
||||
@property
|
||||
def tags(self):
|
||||
""" Players that have access to this expansion. """
|
||||
return self._manager.config[self._ID]["tags"]
|
||||
|
||||
@tags.setter
|
||||
def tags(self, newPlayers):
|
||||
""" Players that have access to this expansion. """
|
||||
self._manager.config[self._ID]["tags"] = tuple(newPlayers)
|
||||
|
||||
@tags.deleter
|
||||
def tags(self):
|
||||
self._manager.config[self._ID]["tags"] = ()
|
||||
|
||||
@abc.abstractmethod
|
||||
def step(self, action):
|
||||
"""
|
||||
Call close if an error is thrown
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def reset(self):
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def close(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test run to make sure nothing is flagrantly flawed
|
||||
configPath = Path(__file__).parent / "players.json"
|
||||
manager = PlayersManager(playersPath=configPath, gameID="gameID0")
|
||||
pm = PlayersManager(playersPath=configPath, gameID="gameID0")
|
||||
# Iteration
|
||||
for playerName in manager:
|
||||
print(playerName)
|
||||
for name in pm:
|
||||
print(name)
|
||||
# Modification of a players data
|
||||
brosef = manager["Brosef"]
|
||||
brosef = pm["Brosef"]
|
||||
brosef.gameSave = [1]
|
||||
print(manager["Brosef"].gameSave)
|
||||
print(pm["Brosef"].gameSave)
|
||||
brosef.state = ["alive"]
|
||||
# TODO Verify that changing the gameID works as intended
|
||||
Reference in New Issue
Block a user