コード例 #1
0
def init(config: 'Configuration') -> None:
    '''
    Do some importing and set-up.
    '''
    log_dotted = label.normalize(_DOTTED, 'init')
    log.start_up(log_dotted, "Initializing Veredi...")

    registration(config)

    log.start_up(log_dotted, "Initialization done.")
コード例 #2
0
def add(system: System) -> SystemId:
    '''
    Helper to take an already created system, and add it into the
    SystemManager's systems. Returns the SystemId assigned by SystemManager.
    '''
    log_dotted = label.normalize(_DOTTED, 'add')
    log.start_up(log_dotted, f"Adding system '{str(system.klass)}'...")

    sid = background.manager.system.add(system)

    log.start_up(log_dotted, f"Added system '{str(system.klass)}' with "
                 f"SystemId: {str(sid)}",
                 log_success=log.SuccessType.SUCCESS)
    return sid
コード例 #3
0
ファイル: options.py プロジェクト: cole-brown/veredi-code
def configuration(rules: label.LabelInput,
                  game_id: Any,
                  path: pathlib.Path = None) -> Configuration:
    '''
    Find config file and parse into the Configuration object for this game.

    `rules` is the Label for the rules type, e.g. 'veredi.rules.d20.pf2'

    `game_id` is the repository identity key for the specific game.

    `path` can be either a directory or the config file path. If `path` is
    None, this looks in the current directory for the first file that matches
    the _CONFIG_FILE_NAME_GLOBS patterns.
    '''
    log_dotted = label.normalize(_DOTTED, 'configuration')
    log.start_up(log_dotted, "Creating Veredi Configuration...")

    # ------------------------------
    # Sanity Checks?
    # ------------------------------
    log.start_up(log_dotted, "Checking Inputs...", path,
                 _CONFIG_FILE_NAME_GLOBS)

    # Normalize rules to a dotted string.
    rules = label.normalize(rules)

    # game_id... dunno much about it until we get a repository for it.

    # ------------------------------
    # Figure out actual config file path from input path.
    # ------------------------------
    log.start_up(log_dotted, "Finding Config File...", path,
                 _CONFIG_FILE_NAME_GLOBS)
    path = _config_path(log_dotted, path)

    # ------------------------------
    # Create Configuration.
    # ------------------------------
    log.start_up(log_dotted, "Creating Configuration...", path,
                 _CONFIG_FILE_NAME_GLOBS)
    config = Configuration(rules, game_id, config_path=path)

    # ------------------------------
    # Done.
    # ------------------------------
    log.start_up(log_dotted,
                 "Done creating Veredi Configuration.",
                 log_success=log.SuccessType.SUCCESS)
    return config
コード例 #4
0
def create(config: Optional[Configuration],
           context: VerediContext,
           system_type: Type[System],
           debug_flags: Optional[DebugFlag] = None) -> SystemId:
    '''
    Helper to create a system. Returns the created system's SystemId.
    '''
    log_dotted = label.normalize(_DOTTED, 'create')
    log.start_up(log_dotted, f"Creating system '{str(system_type.klass)}'...")

    sid = background.manager.system.create(system_type, context)

    log.start_up(log_dotted, f"Created system '{str(system_type.klass)}' with "
                 f"SystemId: {str(sid)}",
                 log_success=log.SuccessType.SUCCESS)
    return sid
コード例 #5
0
ファイル: server.py プロジェクト: cole-brown/veredi-code
def server(
        path: pathlib.Path = None,
        debug_flags: Optional[DebugFlag] = None
) -> Tuple[Configuration, Engine]:
    '''
    Start a Veredi Game Engine, ECS Managers, etc. Everything required to run a
    game server.

    Returns the configuration and the engine in a tuple.
    '''
    log_dotted = label.normalize(_DOTTED, 'server')
    log.start_up(log_dotted, "Creating Veredi Server...")

    # ---
    # Find & parse config file.
    # ---
    log.start_up(log_dotted, "Creating Configuration...")
    config = configuration(path)

    # ---
    # Set up ECS.
    # ---
    log.start_up(log_dotted, "Creating Managers...")
    meeting = managers(config, debug_flags=debug_flags)

    # ---
    # Set game.
    # ---
    log.start_up(log_dotted, "Creating Game...")
    game_engine = engine(config, meeting, debug_flags)

    # ---
    # Set up logging.
    # ---
    # TODO: log?
    # TODO: log_server?
    # TODO: log_client?

    # ---
    # Done.
    # ---
    log.start_up(log_dotted,
                 "Done Creating Veredi Server.",
                 log_success=log.SuccessType.SUCCESS)
    return config, game_engine
コード例 #6
0
def _create_or_add(log_dotted: str, config: Optional[Configuration],
                   context: VerediContext, system_or_type: Union[System,
                                                                 Type[System]],
                   debug_flags: DebugFlag, special_context: bool) -> SystemId:
    '''
    Helper for using SysCreateType to `create`/`add` systems.
    '''
    ctx_str = ('special context' if special_context else 'context')
    sid = None

    # System type to create?
    if issubclass(system_or_type, System):
        log.start_up(
            log_dotted, f"Creating system '{str(system_or_type.klass)}' "
            f"with {ctx_str} {str(context)}...")
        sid = create(config, context, system_or_type, debug_flags)
        log.start_up(log_dotted,
                     f"Created system '{str(system_or_type.klass)}'.",
                     log_success=log.SuccessType.SUCCESS)

    # System already created?
    elif isinstance(system_or_type, System):
        log.start_up(
            log_dotted, f"Adding system '{str(system_or_type.klass)}' "
            f"with {ctx_str} {str(context)}...")
        sid = create(config, context, system_or_type, debug_flags)
        log.start_up(log_dotted,
                     f"Added system '{str(system_or_type.klass)}'.",
                     log_success=log.SuccessType.SUCCESS)

    # Error!
    else:
        msg = "`system_or_type` must be a System instance or System type."
        error = ConfigError(msg,
                            data={
                                'config': config,
                                'context': context,
                                'system_or_type': system_or_type,
                                'debug_flags': debug_flags,
                                'special_context': special_context,
                            })
        raise log.exception(error, msg)

    return sid
コード例 #7
0
ファイル: engine.py プロジェクト: cole-brown/veredi-code
def engine(
    configuration: Configuration,
    meeting: Meeting,
    # Optional Debug Stuff:
    debug_flags: Optional[DebugFlag] = None,
) -> Engine:
    '''
    Create and configure a game engine using the other supplied parameters.
    '''
    log_dotted = label.normalize(_DOTTED, 'engine')
    log.start_up(log_dotted, "Building the Engine...")

    # ---
    # Sanity.
    # ---
    if not configuration:
        msg = "Configuration must be provided."
        error = ConfigError(msg,
                            data={
                                'configuration': str(configuration),
                                'meeting': str(meeting),
                            })
        raise log.exception(error, msg)

    if not meeting:
        # This shouldn't happen - should raise an error before here, right?
        msg = "Managers' Meeting must be provided."
        error = ConfigError(msg,
                            data={
                                'configuration': str(configuration),
                                'meeting': str(meeting),
                            })
        raise log.exception(error, msg)

    # ---
    # Create engine.
    # ---
    log.start_up(log_dotted, "Initializing the Engine...")
    owner = None
    campaign_id = None
    engine = Engine(owner, campaign_id, configuration, meeting, debug_flags)

    log.start_up(log_dotted,
                 "Done building the Engine.",
                 log_success=log.SuccessType.SUCCESS)
    return engine
コード例 #8
0
def many(config: Optional[Configuration],
         context: VerediContext,
         *args: SysCreateType,
         debug_flags: Optional[DebugFlag] = None) -> List[SystemId]:
    '''
    Helper to `create`/`add` many systems.

    See SysCreateType docstr for what it accepts.

    Returns a list of SystemIds.

    If tuple, will use tuple's context, else uses the `context` arg.

    e.g.:
      systems(config, context, SomeSystem) # could just use `create` or add`
      systems(config, context,
              (SomeSystem, different_context)) # uses `different_context`
      systems(config, context,
              (SomeSystem, context_for_SomeSystem), # ignores `context`
              TwoSystem) # uses `context`
    '''
    log_dotted = label.normalize(_DOTTED, 'many')
    log.start_up(log_dotted, f"Creating {len(args)} systems...")

    sids = []
    for each in args:
        sid = None
        system_or_type = None
        system_context = None
        context_unique = False

        if isinstance(each, tuple):
            # Have a special context in tuple - ignore the "default" `context`
            # arg.
            system_or_type = each[0]
            system_context = each[1]
            context_unique = True

        else:
            # Use the normal `context` arg.
            system_or_type = each
            system_context = context
            context_unique = False

        log.start_up(
            log_dotted, f"Processing system '{str(system_or_type.klass)}' for "
            f"adding/creating...")

        # Alrighty - do the thing with the system.
        sid = _create_or_add(log_dotted, config, system_context,
                             system_or_type, debug_flags, context_unique)
        sids.append(sid)

        log.start_up(log_dotted,
                     f"System '{str(system_or_type.klass)}' processed.",
                     log_success=log.SuccessType.SUCCESS)

    log.start_up(log_dotted,
                 f"Created {len(sids)} systems with SystemIds: {str(sids)}",
                 log_success=log.SuccessType.SUCCESS)
    return sids
コード例 #9
0
    def _set_up(self) -> VerediHealth:
        '''
        Sanity checks before loading, and any additional set-up required after
        initialization.

        Raises ConfigError
        '''
        # TODO: Move creation of our repo/serdes here?

        log.start_up(self.dotted, "Configuration set-up...")
        if not self._path:
            log.start_up(self.dotted,
                         "Configuration set-up: No path! Erroring out...",
                         log_success=False)
            raise log.exception(ConfigError,
                                "No path for config data after loading!")

        if not self._codec:
            log.start_up(self.dotted,
                         "Configuration set-up: No Codec! Erroring out...",
                         log_success=False)
            raise log.exception(ConfigError,
                                "No codec for config data after loading!")

        if not self._serdes:
            log.start_up(self.dotted,
                         "Configuration set-up: No Serdes! Erroring out...",
                         log_success=False)
            raise log.exception(ConfigError,
                                "No serdes for config data after loading!")

        if not self._repo:
            log.start_up(self.dotted, "Configuration set-up: No Repository! "
                         "Erroring out...",
                         log_success=False)
            raise log.exception(
                ConfigError, "No repository for config data after loading!")

        log.start_up(self.dotted,
                     "Done setting up Configuration.",
                     log_success=True)
        return VerediHealth.HEALTHY
コード例 #10
0
    def __init__(self,
                 rules: label.LabelInput,
                 game_id: Any,
                 config_path: Optional[pathlib.Path] = None,
                 config_repo: Optional['BaseRepository'] = None,
                 config_serdes: Optional['BaseSerdes'] = None,
                 config_codec: Optional[Codec] = None) -> None:
        '''
        Create a Configuration object for the game's set-up.

        `rules_dotted` is the veredi dotted label of the game's rules type.
          example: 'veredi.rules.d20.pf2.game'

        `game_id` is the Repository id/key/record-name for the game's Saved
        records.

        `config_repo`, `config_serdes`, and `config_codec` are the repository,
        serdes, and codec to use for data about the game's set-up (Definitions
        and Saved records). The game's data (players, items, etc) is delt with
        through DataManager with a different Repository/Serdes/Codec.

        `Config_path` is an optional override of the default_path() used to
        find the general Veredi configuration data.

        Raises LoadError and ConfigError
        '''
        log.start_up(self.dotted, "Creating Configuration...")
        self._define_vars()

        # ---
        # Sanity Check...
        # ---
        preexisting = background.config.link(background.Link.CONFIG)
        if preexisting:
            # Log start-up error...
            msg = ("A Configuration already exists in the background context! "
                   "Two configs cannot be used to initialize Veredi.")
            log.start_up(self.dotted,
                         msg + ' Pre-existing: {}',
                         preexisting,
                         success=False)
            # ...And error out.
            raise background.config.exception(None, msg)

        # ---
        # Params
        # ---
        self._rules = label.normalize(rules)
        self._id = game_id
        log.start_up(
            self.dotted, "Creating Configuration for: "
            f"rules: '{self._rules}', game-id: '{self._id}'...")

        self._path = config_path or default_path()
        log.start_up(self.dotted, "Configuration path (using {}): {}",
                     ('provided' if config_path else 'default'), self._path)

        try:
            # ---
            # NOTE:
            # Config's Repo & Serdes are not the game's repo/serdes. Ours are
            # used for loading the config data itself, and so:
            #   1) Can't rely on config data to configure themselves.
            #   2) Are the type for loading "this file (or data) exactly".
            # ---

            context = ConfigContext(self._path, self.dotted)

            # ---
            # Config Repository
            # ---
            # This will usually be a FileBareRepository created by us, but
            # allow it to be passed in.
            self._repo = config_repo
            if not self._repo:
                self._repo = FileBareRepository(context)
                log.start_up(self.dotted, "  Created config's repo: '{}'",
                             self._repo.dotted)
            else:
                log.start_up(self.dotted, "  Using passed in repo: '{}'",
                             self._repo.dotted)

            # ---
            # Config Serdes
            # ---
            # This will usually be a YamlSerdes created by us, but allow it to
            # be passed in.
            self._serdes = config_serdes
            if not self._serdes:
                self._serdes = YamlSerdes()
                log.start_up(self.dotted, "  Created config's serdes: '{}'",
                             self._serdes.dotted)
            else:
                log.start_up(self.dotted, "  Using passed in serdes: '{}'",
                             self._serdes.dotted)

            # ---
            # Config Codec
            # ---
            # This will usually be a Codec created by us, but allow it to
            # be passed in.
            self._codec = config_codec
            if not self._codec:
                self._codec = Codec()
                log.start_up(self.dotted, "  Created config's codec: '{}'",
                             self._codec.dotted)
            else:
                log.start_up(self.dotted, "  Using passed in codec: '{}'",
                             self._codec.dotted)

            # ---
            # Background
            # ---
            # Do background stuff after repo/serdes so that they cannot try to
            # use us to make stuff from the config we haven't loaded yet.
            log.start_up(self.dotted,
                         "Setting Configuration into background data...")

            # Set ourself into the background.
            background.config.init(self._path, self)
            self._set_background()
            log.start_up(self.dotted,
                         "Configuration set into background data.")

        except Exception as err:
            log.start_up(self.dotted,
                         "Configuration failed to initialize... Erroring out.",
                         log_success=False)
            raise log.exception(
                ConfigError,
                "Found an exception when creating config.") from err

        # ---
        # Finalize: Load & Set-Up Configuration
        # ---
        log.start_up(self.dotted, "Configuration final load, set-up...")
        self._load()
        self._set_up()

        log.start_up(self.dotted,
                     "Done initializing Configuration.",
                     log_success=True)
コード例 #11
0
ファイル: engine.py プロジェクト: cole-brown/veredi-code
def managers(configuration: Configuration,
             time_manager: Optional[TimeManager] = None,
             event_manager: Optional[EventManager] = None,
             component_manager: Optional[ComponentManager] = None,
             entity_manager: Optional[EntityManager] = None,
             system_manager: Optional[SystemManager] = None,
             data_manager: Optional[DataManager] = None,
             identity_manager: Optional[IdentityManager] = None,
             debug_flags: Optional[DebugFlag] = None) -> Meeting:
    '''
    Creates a Meeting of EcsManagers.

    Any/all managers may be provided as arguments. If a manager is not
    provided, one will be created using the `configuration`, which must be
    provided.
    '''
    log_dotted = label.normalize(_DOTTED, 'managers')
    log.start_up(log_dotted, "Creating Meeting of EcsManagers...")

    # ---
    # Sanity.
    # ---
    if not configuration:
        msg = "Configuration must be provided."
        error = ConfigError(msg, data={
            'configuration': str(configuration),
        })
        raise log.exception(error, msg)

    # ---
    # Create Managers.
    # ---
    # Create any managers that weren't passed in.

    # Time
    time = time_manager or TimeManager(debug_flags=debug_flags)
    log.start_up(log_dotted, "Created TimeManager.")

    # Event
    event = event_manager or EventManager(configuration, debug_flags)
    log.start_up(log_dotted, "Created EventManager.")

    # Component
    component = component_manager or ComponentManager(configuration, event,
                                                      debug_flags)
    log.start_up(log_dotted, "Created ComponentManager.")

    # Entity
    entity = entity_manager or EntityManager(configuration, event, component,
                                             debug_flags)
    log.start_up(log_dotted, "Created EntityManager.")

    # System
    system = system_manager or SystemManager(event, debug_flags)
    log.start_up(log_dotted, "Created SystemManager.")

    # Data
    data = data_manager or DataManager(configuration, time, event, component,
                                       debug_flags)
    log.start_up(log_dotted, "Created DataManager.")

    # Identity
    identity = identity_manager or IdentityManager(configuration, time, event,
                                                   entity, debug_flags)
    log.start_up(log_dotted, "Created IdentityManager.")

    # ---
    # Finish up.
    # ---

    # And now we can create the Manager's Meeting itself.
    meeting = Meeting(time, event, component, entity, system, data, identity,
                      debug_flags)
    log.start_up(log_dotted, "Created Meeting of Managers.")

    # Save to background and return.
    mtg_bg_data, mtg_bg_owner = meeting.get_background()
    background.manager.set(meeting.dotted, meeting, mtg_bg_data, mtg_bg_owner)
    log.start_up(log_dotted, "Set managers into background context.")

    log.start_up(
        log_dotted, "Finalize TimeManager's initialization after "
        "Meeting creation...")
    # TimeManager has to delay some initialization until after other managers
    # are created.
    time.finalize_init(data)
    log.start_up(log_dotted, "TimeManager fully initialized.")

    log.start_up(log_dotted,
                 "Done Creating Meeting of EcsManagers.",
                 log_success=log.SuccessType.SUCCESS)
    return meeting
コード例 #12
0
ファイル: options.py プロジェクト: cole-brown/veredi-code
def _config_path(log_dotted: label.DotStr,
                 path: pathlib.Path = None) -> pathlib.Path:
    '''
    Find config file from `path` and parse into the Configuration object for
    the game.

    `path` can be either a directory or the config file path. If `path` is
    None, this looks in the current directory for the first file that matches
    the _CONFIG_FILE_NAME_GLOBS patterns.
    '''
    # ---
    # Default path?
    # ---
    if path:
        log.start_up(log_dotted, "Looking for config in provided path: {}",
                     path)

    else:
        path = pathlib.Path(os.getcwd())
        log.start_up(log_dotted,
                     "Set config path to current working directory: {}", path)

    # ---
    # Sanity checks for path.
    # ---
    if not path.exists():
        msg = "Configuration path doesn't exist."
        error = ConfigError(msg,
                            data={
                                'path': str(path),
                                'exists': path.exists(),
                                'is_file': path.is_file(),
                                'is_dir': path.is_dir(),
                            })
        raise log.exception(error, msg + f" path: {path}")

    if not path.is_dir() and not path.is_file():
        msg = "Configuration path must be a file or directory."
        error = ConfigError(msg,
                            data={
                                'path': str(path),
                                'exists': path.exists(),
                                'is_file': path.is_file(),
                                'is_dir': path.is_dir(),
                            })
        raise log.exception(error, msg + f" path: {path}")

    # ---
    # Get config.
    # ---
    # Already checked that it's either file or dir, so:
    if path.is_dir():
        log.start_up(
            log_dotted, "Path is a directory; look for config file "
            "by glob: {} {}", path, _CONFIG_FILE_NAME_GLOBS)

        # Look for files matching the glob. Claim the first one and ignore any
        # others.
        claim = None
        for glob in _CONFIG_FILE_NAME_GLOBS:
            for match in path.glob(glob):
                if not match.is_file():
                    continue
                claim = match
                log.start_up(
                    log_dotted,
                    "Found config file '{}' by glob '{}' in directory '{}'.",
                    claim,
                    glob,
                    path,
                    _CONFIG_FILE_NAME_GLOBS,
                    log_success=log.SuccessType.SUCCESS)
                break

            if claim:
                break

        # Nothing found? Something wrong?
        if not claim or not claim.exists() or not claim.is_file():
            msg = "No config file found in supplied directory."
            error = ConfigError(msg,
                                data={
                                    'dir': str(path),
                                    'globs': _CONFIG_FILE_NAME_GLOBS,
                                    'claim': claim,
                                })
            raise log.exception(
                error, msg + f" dir: {str(path)}, claim: {str(claim)}")

        # Got a file to claim; set it as our path now.
        path = claim.resolve()
        log.start_up(log_dotted,
                     "Config file path resolved to: {}",
                     path,
                     _CONFIG_FILE_NAME_GLOBS,
                     log_success=log.SuccessType.NEUTRAL)

    # Path is a file. Not much needs done.
    else:
        path = path.resolve()
        log.start_up(log_dotted,
                     "Path is a file; resolved to: {}",
                     path,
                     log_success=log.SuccessType.NEUTRAL)

    log.start_up(log_dotted,
                 "Final path to config file: {}",
                 path,
                 log_success=log.SuccessType.SUCCESS)
    return path