Skip to content

Commit

Permalink
Basically done with config changes
Browse files Browse the repository at this point in the history
  • Loading branch information
monkeyman192 committed Dec 21, 2024
1 parent 9f51bf3 commit 5fbea14
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 24 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ It is designed to make it very easy to create libraries for any game or applicat

*pyMHF* contains a number of important features to make creatting a modding library as easy as possible:

## Using *pyMHF*

*pyMHF* has a number of command line arguments to make running it easier. The main way to run *pyMHF* is by calling it like so:

`python -m pymhf run <module>`

Where `<module>` can either be the name of any library using *pyMHF*, the absolute or relative path to a folder which contains a `pyproject.toml` file (this method is often used for local development of libraries), or even the absolute or relative path to a single-file mod.

*pyMHF* also has a `config` mode which allows you to override the default values which are provided by the `pymhf.toml` file as part of a library.

This configuration is done by running

`python -m pymhf config <module>`

For all possible options, see `pymhf --help`.

### Simple hooking

To create a hook, the following pieces of information are required:
Expand Down
71 changes: 58 additions & 13 deletions docs/settings.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,79 @@
# pyMHF settings file [OBSOLETE]
# Configuring `pymhf`

**TODO: Update these settings**
The way that `pymhf` is configured is by way of settings in [toml](https://toml.io/en/) format.
These can be provided in one of two ways, depending on whether you are providing them as part of a library, or as part of a single-file mod.

*pyMHF* contains a file called `pymhf.cfg` which (currently) must be situated within the root directory of the modding library (cf. [here](../writing_libraries.md))
This file has a number of properties in different sections. Some are required and others are not:
For a library, the settings MUST be provided in a `pymhf.toml` file within the root directory of the library (ie. not the top level, but the named directory which contains all the files relevant to the library, cf. [here](../writing_libraries.md))
For a single-file mod, the settings are provided in the inline metadata (see [here](../single_file_mods.md))

## `binary` section:
## Configuration sections and values

In the following we shall name the sections as how they must be typed in the `pymhf.toml` file. To use these in the inline metadata for a single-file mod, simply prepend `tool.` to the section name.

### `pymhf` section:

This section handles properties which relate to the game or program that the library will be for.

- **path**: The full path of the binary to be run.
- **exe**: Either the absolute path to the binary being run, or the name of the exe which is being run by steam.

- **steam_guid** [Optional]: If the game is run through steam, this should set to the Steam App ID. This can be found by right clicking on the game in your library and selecting "Properties...". The value can be found under the "Updates" option on the left.

- **mod_dir**: The full path to the directory containing the mods to be run.
- **required_assemblies**: [Optional]: A list of assemblies that are required to be loaded by the binary at `path` for the game to be considered "loaded". For now, if this is provided, it will also be the binary within which offsets are found relative to, however this will be relaxed in the future as better functionality regarding this is developed.

- **hash**: The `SHA1` hash of the exe. This is used to ensure that the binary matches what is expected by the library exactly.
- **start_paused**: [Optional] - default `True`: Whether or not to start the binary paused. Some programs do no like being started paused, however, if you can start paused it is preferred so that all hooks are created before any code is executed, ensuring no potential detours to be run are missed.

- **steam_guid** [optional]: If the game is run through steam, this should set to the Steam App ID. This can be found by right clicking on the game in your library and selecting "Properties...". The value can be found under the "Updates" option on the left.
- **default_mod_save_dir**: [Can use magic path] The path to the directory within which mod saves are to be placed. If this is not an absolute path and instead a "magic" path, `MOD_SAVES` will be appended to the magic path for the final path.

- **required_assemblies**: [optional]: A list of assemblies that are required to be loaded by the binary at `path` for the game to be considered "loaded". For now, if this is provided, it will also be the binary within which offsets are found relative to, however this will be relaxed in the future as better functionality regarding this is developed.
- **internal_mod_dir**: [Optional] [Can use magic path] [Library only] The path to the directory which contains the mods to be run by the library.

## `pymhf` section:
### `pymhf.logging` section:

- **default_log_dir** [Can use magic path] The path to save the logs under. If not an absolute path, a subdirectory called `LOGS` will be created under this directory.

- **log_level**: Whether to log at the standard level (`INFO`), or more in-depth (`DEBUG`).

## `gui` section:
- **window_name_override**: A string to override the default log window name. Note: This has some limitation currently such as only ascii characters being supported. This will be fixed some time in the future.

### `pymhf.gui` section:

This section related to properties specifically for the GUI which is auto-generated.

- **shown**: Whether or not to show the GUI (`True` or `False`).

- **scale**: The scale of the GUI. For some high-resolution monitors the GUI may end up scaled down when running from within a process, so sometimes this may need to be set to 1.5 for the GUI to look correct.

- **log_window_name_override** The text to display at the top of the log window.

## Magic path variables

`pymhf` has a few "magic" path variables which can be used to make setting up configs more generic and flexible.

To use the "name" versions of the magic strings, they must be surrounded by braces (ie. `{EXE_DIR}`) as part of the path.

These path variables get resolved as part of a path, so we can provide a path like so `{EXE_PATH}/../MyMods` to place things in a folder called `MyMods` in the parent directory of the location of the main binary.

### `EXE_DIR`

This is the absolute path to directory which contains the main binary being run.

### `USER_DIR` / `~`

This is a directory within your user folder. This will often look something like `C:/Users/<username>/pymhf/<plugin name>`. For a single-file mod there is no `plugin name` so the folder will just be the `pymhf` folder.

### `CURR_DIR` / `.`

The current working directory, ie. the directory the single-file mod or modding library is located in. For the modding library it will be the main directory of the project which contains the `pymhf.toml` file.


## Local-only variables and sections

The above configuration settings are the defaults as set by the library or single-file mod. However, there are some settings which will need to be configured before running any libraries since the location of mod folders will very for each user.

## `pymhf.local_config` section:

These settings are set by calling `pymhf --config <libraryname>` or on first run of `pymhf <libraryname>`.

- **mod_dir**: [Can use magic path] [Library only] The path to the directory which contains the mods to be run by the library.

- **mod_save_dir**: [Can use magic path] [Overrides `default_mod_save_dir`] The path to the directory within which mod saves are to be placed. If this is not an absolute path and instead a "magic" path, `MOD_SAVES` will be appended to the magic path for the final path.

- **log_dir** [Can use magic path] [Overrides `default_log_dir`] The path to save the logs under. If not an absolute path, a subdirectory called `LOGS` will be created under this directory.
23 changes: 17 additions & 6 deletions pymhf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import os.path as op
import shutil
import subprocess
from importlib.metadata import PackageNotFoundError, entry_points, version
from typing import Optional

Expand Down Expand Up @@ -98,6 +99,13 @@ def run():
)

config_parser = command_parser.add_parser("config")
config_parser.add_argument(
"-o",
"--open",
action="store_true",
default=False,
help="Open the directory the local config is stored at.",
)
config_parser.add_argument(
"plugin_name",
help=(
Expand All @@ -112,7 +120,7 @@ def run():

plugin_name: str = args.plugin_name
command = args._command
is_config_mode: bool = (command == "config")
is_config_mode: bool = command == "config"
standalone = False
local = False

Expand Down Expand Up @@ -210,7 +218,7 @@ def run():
initial_config = True

if initial_config:
local_config = {"pymhf": {"local_config": {}}}
local_config = {"local_config": {}}
if not has_tkinter:
print(
"tkinter cannot be found. Please ensure it's installed as part of your python install.\n"
Expand All @@ -230,7 +238,7 @@ def run():
if (
mod_folder := get_folder("Select folder where mods are located", MOD_DIR_Q, has_tkinter)
) is not None:
local_config["pymhf"]["local_config"]["mod_dir"] = mod_folder
local_config["local_config"]["mod_dir"] = mod_folder
else:
return None

Expand All @@ -239,15 +247,18 @@ def run():
os.remove(config_progress_file)
initial_config = False
elif is_config_mode:
if args.open:
print(f"Opening {cfg_folder!r} and exiting")
subprocess.call(f'explorer "{cfg_folder}"')
return
local_config = read_pymhf_settings(dst)
pymhf_settings = local_config["pymhf"]["local_config"]
pymhf_settings = local_config["local_config"]
keep_going = True
if has_tkinter:
root = Tk()
root.withdraw()
while keep_going:
config_choice = CONFIG_SELECT_Q.ask()
print(config_choice)
if config_choice == CFG_OPT_BIN_PATH:
if (exe_path := EXE_PATH_Q.ask()) is not None:
pymhf_settings["exe_path"] = exe_path
Expand Down Expand Up @@ -292,7 +303,7 @@ def run():
keep_going = CONTINUE_CONFIGURING_Q.ask()
if keep_going is None:
return
local_config["pymhf"]["local_config"] = pymhf_settings
local_config["local_config"] = pymhf_settings
write_pymhf_settings(local_config, dst)

if not RUN_GAME.ask():
Expand Down
6 changes: 3 additions & 3 deletions pymhf/injected.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@
if _internal.BINARY_PATH:
_binary_dir = op.dirname(_internal.BINARY_PATH)

internal_mod_folder = _internal.CONFIG.get("local_config", {}).get("internal_mod_dir")
internal_mod_folder = _internal.CONFIG.get("internal_mod_dir")
internal_mod_folder = canonicalize_setting(internal_mod_folder, "pymhf", _module_path, _binary_dir)
mod_folder = _internal.CONFIG.get("local_config", {}).get("mod_dir")
mod_folder = _internal.CONFIG.get("mod_dir")

mod_folder = canonicalize_setting(mod_folder, "pymhf", _module_path, _binary_dir)

Expand Down Expand Up @@ -234,7 +234,7 @@ def top_globals(limit: Optional[int] = 10):
_loaded_mods, _loaded_hooks = mod_manager.load_mod_folder(mod_folder)
else:
logging.warning(
"""You have not configured the `binary.mod_dir` variable in the pymhf.toml file.
"""You have not configured the `mod_dir` variable in the pymhf.toml file.
Please do so so that you can load mods."""
)
except Exception:
Expand Down
2 changes: 1 addition & 1 deletion pymhf/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def load_module(plugin_name: str, module_path: str):
"""Load the module."""
local_cfg_file = op.join(APPDATA_DIR, "pymhf", plugin_name, "pymhf.local.toml")
if op.exists(local_cfg_file):
local_cfg = read_pymhf_settings(local_cfg_file)
local_cfg = read_pymhf_settings(local_cfg_file).get("local_config", {})
else:
local_cfg = {}
module_cfg_file = op.join(module_path, "pymhf.toml")
Expand Down
5 changes: 4 additions & 1 deletion pymhf/utils/parse_toml.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,8 @@ def read_pymhf_settings(fpath: str, standalone: bool = False) -> dict:


def write_pymhf_settings(settings: dict, fpath: str):
"""Write the pymhf settings to disk as a toml file.
This will automatically add the `pymhf` top section.
"""
with open(fpath, "w") as f:
tomlkit.dump(settings, f)
tomlkit.dump({"pymhf": settings}, f)

0 comments on commit 5fbea14

Please sign in to comment.