Skip to content

Commit

Permalink
Merge pull request #20 from Friends-of-Monika/dev
Browse files Browse the repository at this point in the history
Release 0.3.1
  • Loading branch information
dreamscached committed Oct 21, 2022
2 parents a4e1c50 + b2d9e84 commit 42d62dc
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 58 deletions.
62 changes: 61 additions & 1 deletion doc/CUSTOMIZING.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,64 @@ inherit values from another (B), then one more config (C) would inherit values
from A and have values both from A and from B.

Only omitted values are replaced, in case some value is present in the child
config it will never be replaced.
config it will never be replaced.

### Overriding

Continuing to counter issues with default config customization, in patch 0.3.1
two more important parameters have been introduced with one of them being
`Override =`.

With `Override`, you can replace existing config by its ID or path (relative to
config directory, see example below) *entirely*, combined with `Inherit` (see
above) you could could use it to alter just a part of existing config without
a need to copy it entirely.

#### Existing config

```ini
[Presence]
ID = MyAwesomeConfig

[Activity]
State = Having fun at [loc_prompt]
```

#### Overriding config

```ini
[Presence]
Override = MyAwesomeConfig

[Activity]
State = Spending time together at [loc_prompt]
```

Sometimes however, if an existing config has no ID assigned and you don't want
to edit it, you can use a path (relative to config directory) instead:

```ini
[Presence]
# Full path would be game/Submods/Discord Presence Submod/config/default/...
# but you only need part AFTER config/, without a leading slash (/)
Override = default/configs/default.conf
```

### Disabling

Another parameter introduced in 0.3.1 is `Disable =`, which if set to `True`
will disable the config and prevent it from being chosen. This however does not
affect inheriting and overriding and you can still use it as a base for other
configs or override some other config and disable it.

For example, if there is a default config you want to disable, you'd create
another config and use `Override` like this:

```ini
[Presence]
Override = default/configs/some-config-to-disable.conf
Disable = True
```

This config will replace a config you specified in `Override` and disable it,
making it never be chosen.
150 changes: 95 additions & 55 deletions mod/config.rpy
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ init 90 python in _fom_presence_config:
ui_message_report="Could not load some presence configs, see log/submod_log.log."
)

_ERROR_CONFIG_OVERRIDE = error.Error(
log_message_report="Presence config {0} overrides nonexistent config ID: {1}.",
ui_message_report="Could not load some presence configs, see log/submod_log.log."
)

_WARNING_CONFIG_CLASH = error.Error(
log_message_report="Config from file {0} has conflicting name with some other config: {1}.",
ui_message_report="There were some warnings during loading some of the presence configs, see log/submod_log.log.",
Expand Down Expand Up @@ -324,6 +329,8 @@ init 90 python in _fom_presence_config:
self.dynamic = parser.get_value("Presence", "Dynamic", _parse_bool, True)
self.id = parser.get_value("Presence", "ID", str, None)
self.inherit_id = parser.get_value("Presence", "Inherit", str, None)
self.override_id = parser.get_value("Presence", "Override", str, None)
self.disable = parser.get_value("Presence", "Disable", _parse_bool, False)

self.app_id = parser.get_value("Client", "ApplicationID", int)

Expand All @@ -339,7 +346,7 @@ init 90 python in _fom_presence_config:
self.stop_ts = parser.get_value("Timestamps", "End", _parse_ts_supplier, _none_supplier)

self._activity = None
self._inherit_applied = False
self._file = None

@staticmethod
def from_file(path):
Expand All @@ -358,28 +365,33 @@ init 90 python in _fom_presence_config:
c = configparser.ConfigParser()
with _open_with_encoding(path, "r", encoding="utf-8") as f:
c.readfp(f, path.replace("\\", "/").split("/")[:-1])
return Config(_ParserWrapper(c))

def inherit(self, config, force=False):
config = Config(_ParserWrapper(c))
config._file = path
return config

@property
def file(self):
"""
Returns path to file this config was loaded from.
OUT:
str:
Path to config file.
"""

return self._file

def copy_from(self, config):
"""
Copies values from another config (only omitted, None or
_none_supplier values) over to this config. Unless force parameter
is set to True, does nothing on next call.
_none_supplier values) over to this config.
IN:
config -> Config:
Config to copy values from. Inherit method is not called,
inheritance is not done recursively by this method, users
should care about this themselves.
force -> bool, default False:
If True, skips inheritance status checks and applies values
over again.
Config to copy values from.
"""

if self._inherit_applied and not force:
return

if self.app_id is None:
self.app_id = config.app_id
if self.details is _none_supplier:
Expand All @@ -399,23 +411,6 @@ init 90 python in _fom_presence_config:
if self.stop_ts is _none_supplier:
self.stop_ts = config.stop_ts

self._inherit_applied = True

@property
def inherited(self):
"""
Returns inheritance status flag value.
OUT:
True:
If this config has inherited from other config.
False:
If this config has not inherited from another config.
"""

return self._inherit_applied

def to_activity(self):
"""
Creates Activity instance from the values stored in Config.
Expand Down Expand Up @@ -469,8 +464,11 @@ init 90 python in _fom_presence_config:
error context. Reported errors are not resolved on successful loads.
"""

del _configs[:]
_config_id_map.clear()
configs = dict()
id_map = dict()

inherited = set()
overridden = set()

for _dir, _, files in os.walk(_config_dir):
for _file in files:
Expand All @@ -481,46 +479,88 @@ init 90 python in _fom_presence_config:
):
continue

_file = os.path.join(_dir, _file)
rel_file = _file[len(_config_dir) + 1:]

try:
_file = os.path.join(_dir, _file)
config = Config.from_file(_file)
if config.condition is not None:
eval(config.condition, dict(), store.__dict__)

_configs.append((_file, config))
if config.id is not None:
if config.id in _config_id_map:
_WARNING_CONFIG_CLASH.report(_file[len(_config_dir) + 1:], config.id)
_config_id_map[config.id] = config
config._file = rel_file
except Exception as e:
_ERROR_CONFIG_LOADING.report(_file[len(_config_dir) + 1:], e)
_ERROR_CONFIG_LOADING.report(file_rel, e)
continue

configs[rel_file] = config
if config.id is None:
config.id = rel_file

ov = id_map.get(config.id)
if ov is not None:
_WARNING_CONFIG_CLASH.report(rel_file, config.id)

id_map[config.id] = config
id_map[rel_file] = config

# Once configs are loaded, we now copy inherited values.
def inherit(config):
# Prevent loops and infinite recursions.
if config.inherited:
if config in inherited:
return True

if config.inherit_id is not None:
parent = _config_id_map.get(config.inherit_id)
parent = id_map.get(config.inherit_id)
if parent is None:
_ERROR_CONFIG_INHERITANCE.report(_file[len(_config_dir) + 1:], config.inherit_id)
_ERROR_CONFIG_INHERITANCE.report(config.file, config.inherit_id)
return False

# Inheritance is done recursively.
if not inherit(parent):
return False
config.inherit(parent)
config.copy_from(parent)

# Add to list of applied inheritances.
inherited.add(config)
return True

def override(config):
# Prevent loops and infinite recursions.
if config in overridden:
return True

if config.override_id is not None:
ov = id_map.get(config.override_id)
if ov is None:
_ERROR_CONFIG_OVERRIDE.report(config.file, config.override_id)
return False

if not override(ov):
return False

remove_config(ov)
config.id = ov.id
id_map[ov.id] = config

overridden.add(config)
return True

idx = 0
while idx < len(_configs):
_file, config = _configs[idx]
if not inherit(config):
del _configs[idx]
else:
idx += 1
def remove_config(config):
del configs[config.file]
if config.id is not None:
del id_map[config.id]

for rel_file, config in list(configs.items()):
if rel_file not in configs:
continue

if not (inherit(config) and override(config)):
remove_config(config)
continue

del _configs[:]
_config_id_map.clear()

_configs.extend(list(configs.items()))
_config_id_map.update(id_map)

# Sort configs on reload to save precious time on every loop.
_configs.sort(key=lambda it: it[1].priority, reverse=True)
Expand All @@ -537,7 +577,7 @@ init 90 python in _fom_presence_config:
"""

for _file, conf in _configs:
if conf.condition is not None:
if not conf.disable and conf.condition is not None:
try:
if bool(eval(conf.condition, dict(), store.__dict__)):
return conf
Expand Down
5 changes: 3 additions & 2 deletions mod/header.rpy
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ init -990 python in mas_submod_utils:
author="Friends of Monika",
name="Discord Presence Submod",
description="Show everyone who's the person you're spending your time with~",
version="0.3.0",
version="0.3.1",
settings_pane="fom_presence_settings_pane",
version_updates={
"friends_of_monika_discord_presence_submod_v0_0_1": "friends_of_monika_discord_presence_submod_v0_0_2",
Expand All @@ -18,7 +18,8 @@ init -990 python in mas_submod_utils:
"friends_of_monika_discord_presence_submod_v0_0_4": "friends_of_monika_discord_presence_submod_v0_1_2",
"friends_of_monika_discord_presence_submod_v0_1_2": "friends_of_monika_discord_presence_submod_v0_2_0",
"friends_of_monika_discord_presence_submod_v0_2_0": "friends_of_monika_discord_presence_submod_v0_2_1",
"friends_of_monika_discord_presence_submod_v0_2_1": "friends_of_monika_discord_presence_submod_v0_3_0"
"friends_of_monika_discord_presence_submod_v0_2_1": "friends_of_monika_discord_presence_submod_v0_3_0",
"friends_of_monika_discord_presence_submod_v0_3_0": "friends_of_monika_discord_presence_submod_v0_3_1"
}
)

Expand Down
3 changes: 3 additions & 0 deletions mod/updates.rpy
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,7 @@ label friends_of_monika_discord_presence_submod_v0_2_1(version="v0_2_1"):
return

label friends_of_monika_discord_presence_submod_v0_3_0(version="v0_3_0"):
return

label friends_of_monika_discord_presence_submod_v0_3_1(version="v0_3_1"):
return

0 comments on commit 42d62dc

Please sign in to comment.