Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically find modded loc files, using dlc_load.json #116

Merged
merged 1 commit into from
Nov 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,11 @@ If this system is not configured correctly, you will see some long and cryptic n
```
when using the dashboard.

If you are not using any mods and installed Stellaris in the default location at (`C:/Program Files (x86)/Steam/steamapps/common/Stellaris/` on windows), there is a good chance that everything will work without any additional actions.
If you installed Stellaris in the default location at (`C:/Program Files (x86)/Steam/steamapps/common/Stellaris/` on windows), there is a good chance that everything will work without any additional actions. If your game (or Steam library) is not in the default location, you will need to change the "Stellaris install folder" setting and restart the dashboard.

However, if you use mods that add new names, if you play the game in another language, or if your Stellaris game files (or steam library) are in a different location, you will need to take some manual actions. While the dashboard application itself does not have any kind of localization (yet), you can also change the localization_file_dir to have names rendered in your preferred language.
If you play the game in another language, you can change the "Stellaris language" and restart the dashboard. Note that this setting should be the language code used by the game (ie `l_braz_por`, `l_english`, `l_french`, `l_german`, `l_japanese`, `l_korean`, `l_polish`, `l_russian`, `l_simp_chinese`, `l_spanish`).

In this case, you can fix it like this:
- Make sure there is a single folder containing all required localization files ending in `.yml`, including the files from your stellaris game and from all mods that introduce new names. You might need to collect these files yourself and copy them to a convenient location. The file names you use does not matter, the dashboard will take them all and build one big name mapping.
- Update the `Stellaris localization folder` in the dashboard settings (or edit it in config.yml). Restart the dashboard program.
- Look in the dashboard program for some output like `Loaded 162 localization files from <path-to-your-stellaris>/localisation/english` or similar that matches the number of files you prepared.
If you use mods that add new names, the dashboard *should* automatically find the required files. Note that if you restart change your mod list, any new modded names will not be loaded until you restart the dashboard. If modded names are not working at all, you might need to change your "Stellaris user data folder" setting and restart the dashboard. This should be the folder containing the `dlc_load.json` file as well as the `mod/` folder.

## Colors

Expand Down
105 changes: 86 additions & 19 deletions stellarisdashboard/config.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import dataclasses
import itertools
import json
import logging
import pathlib
import platform
import re
import sys
import traceback
from collections import defaultdict
from typing import List, Dict, Any

import yaml

LOG_LEVELS = {"CRITICAL": logging.CRITICAL, "ERROR": logging.ERROR, "WARNING": logging.WARNING, "INFO": logging.INFO, "DEBUG": logging.DEBUG}
LOG_LEVELS = {
"CRITICAL": logging.CRITICAL,
"ERROR": logging.ERROR,
"WARNING": logging.WARNING,
"INFO": logging.INFO,
"DEBUG": logging.DEBUG,
}

LOG_FORMAT = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
LOG_FORMAT = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")

CONFIG: "Config" = None
logger: logging.Logger = None
Expand All @@ -30,25 +36,29 @@ def initialize_logger():
root_logger.addHandler(stdout_ch)


def _get_default_save_path():
def _get_default_stellaris_user_data_path():
# according to https://stellaris.paradoxwikis.com/Save-game_editing
home = pathlib.Path.home()
if platform.system() == "Windows":
return home / "Documents/Paradox Interactive/Stellaris/save games/"
return home / "Documents/Paradox Interactive/Stellaris/"
elif platform.system() == "Linux":
return home / ".local/share/Paradox Interactive/Stellaris/save games/"
return home / ".local/share/Paradox Interactive/Stellaris/"
else:
return home / "Documents/Paradox Interactive/Stellaris/save games/"
return home / "Documents/Paradox Interactive/Stellaris/"


def _get_default_save_path():
return _get_default_stellaris_user_data_path() / "save games"


def _get_default_localization_file_dir() -> pathlib.Path:
def _get_default_stellaris_install_path():
for p in [
pathlib.Path("C:/Program Files (x86)/Steam/steamapps/common/Stellaris/"),
(pathlib.Path.home() / ".steam/steamapps/common/Stellaris/").absolute(),
(pathlib.Path.home() / ".steam/root/steamapps/common/Stellaris/").absolute(),
]:
p_abs = p / "localisation/english/"
if p_abs.exists():
return p_abs
if p.exists():
return p
return pathlib.Path(__file__).parent


Expand Down Expand Up @@ -163,10 +173,12 @@ def _get_default_base_output_path():

DEFAULT_SETTINGS = dict(
save_file_path=_get_default_save_path(),
stellaris_install_path=_get_default_stellaris_install_path(),
stellaris_user_data_path=_get_default_stellaris_user_data_path(),
stellaris_language="l_english",
mp_username="",
base_output_path=_get_default_base_output_path(),
threads=1,
localization_file_dir=_get_default_localization_file_dir(),
host="127.0.0.1",
port=28053,
polling_interval=0.5,
Expand Down Expand Up @@ -195,8 +207,10 @@ class Config:
"""Stores the settings for the dashboard."""

save_file_path: pathlib.Path = None
stellaris_install_path: pathlib.Path = None
stellaris_user_data_path: pathlib.Path = None
stellaris_language: str = None
mp_username: str = None
localization_file_dir: pathlib.Path = None
base_output_path: pathlib.Path = None
threads: int = None

Expand Down Expand Up @@ -231,7 +245,8 @@ class Config:
PATH_KEYS = {
"base_output_path",
"save_file_path",
"localization_file_dir",
"stellaris_install_path",
"stellaris_user_data_path",
}
BOOL_KEYS = {
"check_version",
Expand Down Expand Up @@ -259,6 +274,7 @@ class Config:
"mp_username",
"save_name_filter",
"log_level",
"stellaris_language",
}
DICT_KEYS = {
"tab_layout",
Expand Down Expand Up @@ -391,20 +407,71 @@ def db_path(self) -> pathlib.Path:
path.mkdir(parents=True)
return path

@property
def game_data_dirs(self):
dlc_load_path = self.stellaris_user_data_path / "dlc_load.json"
try:
with open(dlc_load_path, "r") as f:
dlc_load = json.load(f)
mod_descriptor_paths = [
self.stellaris_user_data_path / relative_mod_descriptor_path
for relative_mod_descriptor_path in dlc_load.get("enabled_mods", [])
]
mod_data_paths = [
_get_mod_data_dir(descriptor_path)
for descriptor_path in mod_descriptor_paths
if descriptor_path.exists()
]
return [self.stellaris_install_path] + [
mod_data_path
for mod_data_path in mod_data_paths
if mod_data_path is not None
]
except Exception as e:
logger.error(f"Failed to read enabled mods {dlc_load_path}")
logger.error(e)
return [self.stellaris_install_path]

@property
def localization_files(self):
YAML_SUFFIXES = ("yaml", "yml")
files = list(
itertools.chain(
self.localization_file_dir.glob("**/*.yaml"),
self.localization_file_dir.glob("**/*.yml"),
path
for path in itertools.chain(
*(
(data_dir / "localisation").glob(f"**/*.{yaml_suffix}")
for data_dir in self.game_data_dirs
for yaml_suffix in YAML_SUFFIXES
)
)
if _localization_file_matches_language(path, self.stellaris_language)
)
logger.info(
f"Loaded {len(files)} localization files from {self.localization_file_dir}"
f"Loaded {len(files)} localization files from {self.game_data_dirs}"
)
return files


def _get_mod_data_dir(mod_descriptor_path: pathlib.Path):
try:
with open(mod_descriptor_path, "r") as f:
for line in f:
match = re.match('^\s*path\s*=\s*"(.*)"\s*$', line)
if match:
return pathlib.Path(match.group(1))
except Exception as e:
logger.error(f"Failed to read mod path from {mod_descriptor_path}")
logger.error(e)
return None


def _localization_file_matches_language(file_path: pathlib.Path, language: str):
with open(file_path, "r") as f:
first_line = f.readline()
match = re.match(f"^\ufeff\s*{language}\s*:\s*$", first_line)
return match is not None


def _apply_existing_settings(config: Config):
settings = dict(DEFAULT_SETTINGS)
settings_file = _get_settings_file_path()
Expand Down
20 changes: 16 additions & 4 deletions stellarisdashboard/dashboard_app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,23 @@ def _bool_to_lowercase(py_bool: bool) -> str:
"name": "Save file path (applies after restart, set to empty to restore default, applies after restart)",
"description": "Where the dashboard will look for new Stellaris save files.",
},
"localization_file_dir": {
"stellaris_user_data_path": {
"type": t_str,
"value": current_values["localization_file_dir"],
"name": "Stellaris localization folder",
"description": "Path where the dashboard will look for Stellaris localization files that define how names are created. Applies after dashboard restart. See README.md for details.",
"value": current_values["stellaris_user_data_path"],
"name": "Stellaris user data folder",
"description": "Where the dashboard will look for user data such as enabled mods. It should contain the dlc_load.json file.",
},
"stellaris_install_path": {
"type": t_str,
"value": current_values["stellaris_install_path"],
"name": "Stellaris install folder",
"description": "Where the dashboard will look for Stellaris game data.",
},
"stellaris_language": {
"type": t_str,
"value": current_values["stellaris_language"],
"name": "Stellaris language",
"description": "The language to use for localizing Stellaris text. In the format l_<language> (for example, l_english)"
},
"mp_username": {
"type": t_str,
Expand Down
Loading