hoi4dev 0.1.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hoi4dev-0.1.0.3/LICENSE +19 -0
- hoi4dev-0.1.0.3/PKG-INFO +212 -0
- hoi4dev-0.1.0.3/README.md +193 -0
- hoi4dev-0.1.0.3/pyproject.toml +3 -0
- hoi4dev-0.1.0.3/setup.cfg +4 -0
- hoi4dev-0.1.0.3/setup.py +41 -0
- hoi4dev-0.1.0.3/src/hoi4dev/__init__.py +22 -0
- hoi4dev-0.1.0.3/src/hoi4dev/achievements/__init__.py +43 -0
- hoi4dev-0.1.0.3/src/hoi4dev/bops/__init__.py +61 -0
- hoi4dev-0.1.0.3/src/hoi4dev/characters/__init__.py +154 -0
- hoi4dev-0.1.0.3/src/hoi4dev/countries/__init__.py +100 -0
- hoi4dev-0.1.0.3/src/hoi4dev/decisions/__init__.py +69 -0
- hoi4dev-0.1.0.3/src/hoi4dev/diplomacy/__init__.py +23 -0
- hoi4dev-0.1.0.3/src/hoi4dev/divisions/__init__.py +101 -0
- hoi4dev-0.1.0.3/src/hoi4dev/equipments/__init__.py +399 -0
- hoi4dev-0.1.0.3/src/hoi4dev/events/__init__.py +296 -0
- hoi4dev-0.1.0.3/src/hoi4dev/focuses/__init__.py +193 -0
- hoi4dev-0.1.0.3/src/hoi4dev/ideas/__init__.py +94 -0
- hoi4dev-0.1.0.3/src/hoi4dev/ideologies/__init__.py +5 -0
- hoi4dev-0.1.0.3/src/hoi4dev/init/__init__.py +115 -0
- hoi4dev-0.1.0.3/src/hoi4dev/intelligence_agencies/__init__.py +48 -0
- hoi4dev-0.1.0.3/src/hoi4dev/maps/__init__.py +10 -0
- hoi4dev-0.1.0.3/src/hoi4dev/maps/map2graph.py +177 -0
- hoi4dev-0.1.0.3/src/hoi4dev/maps/map2img.py +258 -0
- hoi4dev-0.1.0.3/src/hoi4dev/maps/state_stats.py +143 -0
- hoi4dev-0.1.0.3/src/hoi4dev/modifiers/__init__.py +37 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/buildings.json +65 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/config.json +40 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/copy.json +203 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/equipmentdesigner.json +34 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/equipmentdesigner_window.json +43 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/equipmentdesigner_window_special.json +13 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/manpower.json +17 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/paths.json +5 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/portraits.json +116 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/resources.json +134 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/super_event.json +86 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/super_event_gfx.json +16 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/super_event_gui.json +16 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/super_event_localisation_desc.json +8 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/super_event_localisation_mark.json +8 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/super_event_localisation_name.json +8 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/configs/term_table.json +1 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/Super_Event_Close_Button.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/Super_Event_Underlay.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/Super_Event_Window.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/advisor_template.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/country_event_template.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/defaults/X.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/defaults/default_achievement.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/defaults/default_bop.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/defaults/default_equipment.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/defaults/default_event.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/defaults/default_flag.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/defaults/default_focus.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/defaults/default_idea.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/defaults/default_intel_agency.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/defaults/default_modifier.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/imgs/defaults/default_portrait.dds +0 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/localisations/empty_l_braz_por.yml +1 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/localisations/empty_l_english.yml +1 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/localisations/empty_l_french.yml +1 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/localisations/empty_l_german.yml +1 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/localisations/empty_l_japanese.yml +1 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/localisations/empty_l_polish.yml +1 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/localisations/empty_l_russian.yml +1 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/localisations/empty_l_simp_chinese.yml +1 -0
- hoi4dev-0.1.0.3/src/hoi4dev/resources/localisations/empty_l_spanish.yml +1 -0
- hoi4dev-0.1.0.3/src/hoi4dev/technologies/__init__.py +146 -0
- hoi4dev-0.1.0.3/src/hoi4dev/traits/__init__.py +24 -0
- hoi4dev-0.1.0.3/src/hoi4dev/translation/__init__.py +41 -0
- hoi4dev-0.1.0.3/src/hoi4dev/translation/llm.py +41 -0
- hoi4dev-0.1.0.3/src/hoi4dev/translation/lm.py +61 -0
- hoi4dev-0.1.0.3/src/hoi4dev/translation/manual.py +16 -0
- hoi4dev-0.1.0.3/src/hoi4dev/utils/__init__.py +7 -0
- hoi4dev-0.1.0.3/src/hoi4dev/utils/ccl.py +395 -0
- hoi4dev-0.1.0.3/src/hoi4dev/utils/config.py +104 -0
- hoi4dev-0.1.0.3/src/hoi4dev/utils/date.py +16 -0
- hoi4dev-0.1.0.3/src/hoi4dev/utils/gui.py +20 -0
- hoi4dev-0.1.0.3/src/hoi4dev/utils/img.py +339 -0
- hoi4dev-0.1.0.3/src/hoi4dev/utils/locs.py +146 -0
- hoi4dev-0.1.0.3/src/hoi4dev/utils/utils.py +13 -0
- hoi4dev-0.1.0.3/src/hoi4dev.egg-info/PKG-INFO +212 -0
- hoi4dev-0.1.0.3/src/hoi4dev.egg-info/SOURCES.txt +85 -0
- hoi4dev-0.1.0.3/src/hoi4dev.egg-info/dependency_links.txt +1 -0
- hoi4dev-0.1.0.3/src/hoi4dev.egg-info/entry_points.txt +2 -0
- hoi4dev-0.1.0.3/src/hoi4dev.egg-info/top_level.txt +1 -0
hoi4dev-0.1.0.3/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2018 The Python Packaging Authority
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
hoi4dev-0.1.0.3/PKG-INFO
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: hoi4dev
|
|
3
|
+
Version: 0.1.0.3
|
|
4
|
+
Summary: HOI4DEV: Hearts of Iron IV Development Tools
|
|
5
|
+
Home-page: https://github.com/Magolor/
|
|
6
|
+
Author: Magolor
|
|
7
|
+
Author-email: magolorcz@gmail.com
|
|
8
|
+
Project-URL: Author, https://github.com/Magolor/
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Requires-Python: >=3.9, <4
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
|
|
20
|
+
# HOI4DEV
|
|
21
|
+
|
|
22
|
+
**Warning: This package is currently underdeveloped and does not guarantee any consistency.**
|
|
23
|
+
|
|
24
|
+
**Tutorial Coming Soon...**
|
|
25
|
+
|
|
26
|
+
**Compatible with HOI4 Version**:
|
|
27
|
+
|
|
28
|
+
### Configuration
|
|
29
|
+
|
|
30
|
+
After installation, you need to setup the config to start working for a specific mod project. By default, `init_config()` creates a config at `~/.hoi4dev/config.json`, you can setup the paths manually.
|
|
31
|
+
|
|
32
|
+
On MacOS:
|
|
33
|
+
```bash
|
|
34
|
+
{
|
|
35
|
+
"HOI4_GAME_PATH": "/Users/<YOUR_USER_NAME_HERE>/Library/Application Support/Steam/steamapps/common/Hearts of Iron IV",
|
|
36
|
+
"HOI4_MODS_PATH": "/Users/<YOUR_USER_NAME_HERE>/Documents/Paradox Interactive/Hearts of Iron IV/mod",
|
|
37
|
+
"HOI4_MODS_COPY_PATH": "/Users/<YOUR_USER_NAME_HERE>/Documents/Paradox Interactive/Hearts of Iron IV/mod",
|
|
38
|
+
"CURRENT_MOD_PATH": "/Users/<YOUR_USER_NAME_HERE>/Documents/Paradox Interactive/Hearts of Iron IV/mod/<YOUR_MOD_NAME>"
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
On Windows:
|
|
43
|
+
```bash
|
|
44
|
+
{
|
|
45
|
+
"HOI4_GAME_PATH": "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Hearts of Iron IV",
|
|
46
|
+
"HOI4_MODS_PATH": "C:\\Program Files (x86)\\Steam\\steamapps\\workshop\\content\\394360",
|
|
47
|
+
"HOI4_MODS_COPY_PATH": "C:\\Users\\<YOUR_USER_NAME_HERE>\\Documents\\Paradox Interactive\\Hearts of Iron IV\\mod",
|
|
48
|
+
"CURRENT_MOD_PATH": "C:\\Program Files (x86)\\Steam\\steamapps\\workshop\\content\\394360\\<YOUR_MOD_NAME>"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The `HOI4_MODS_COPY_PATH` is usually useless, but sometimes it may be required if your user name contains Chinese or other non-UTF-8 characters. Though, it is still worth warning that **This package is known to malfunction if you are running on Windows with non-UTF-8 characters. May be fixed in the future.**
|
|
53
|
+
|
|
54
|
+
## Basic Features
|
|
55
|
+
|
|
56
|
+
### CCL (Clausewitz scripting language) and JSON conversion
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from hoi4dev import *
|
|
60
|
+
# Load JSON file
|
|
61
|
+
A = LoadJson("xxx.json")
|
|
62
|
+
|
|
63
|
+
# Convert JSON to CCL
|
|
64
|
+
with open("xxx.txt", "w") as f:
|
|
65
|
+
f.write(Dict2CCL(A) + "\n")
|
|
66
|
+
|
|
67
|
+
# Load CCL file
|
|
68
|
+
with open("ccl.txt", "r") as f:
|
|
69
|
+
A_ccl = f.read()
|
|
70
|
+
|
|
71
|
+
# Convert CCL to JSON
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Image conversion
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from hoi4dev import *
|
|
79
|
+
|
|
80
|
+
# Load a png
|
|
81
|
+
a = ImageLoad("xxx.png")
|
|
82
|
+
|
|
83
|
+
# Zoom & auto-Crop to target size
|
|
84
|
+
A = ImageZoom(a, w=512, h=512)
|
|
85
|
+
|
|
86
|
+
# Save Image:
|
|
87
|
+
ImageSave(A, "xxx.dds") # automatically compress dds with dxt5
|
|
88
|
+
ImageSave(A, "xxx.tga") # automatically flip tga for flags
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Find your COMPILED mod
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
# Use `F` to find your COMPILED mod files
|
|
95
|
+
path_to_your_mod = F("")
|
|
96
|
+
# Add a thumbnail manually
|
|
97
|
+
CopyFile("thumbnail.png", F("thumbnail.png"))
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Conversion between YML localisation and TXT files
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
AddLocalisation("xxx.txt", scope="ABC", translate=False)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
In the txt file, use `[<LANGUAGE_ABBREVIATION>.<KEY>]`, use `@` to copy the `scope`
|
|
107
|
+
For example, consider the following `txt` file, under "ABC" scope:
|
|
108
|
+
```
|
|
109
|
+
[en.key01]
|
|
110
|
+
test1
|
|
111
|
+
test2
|
|
112
|
+
[zh.@key01]
|
|
113
|
+
|
|
114
|
+
中文测例1
|
|
115
|
+
中文测例2
|
|
116
|
+
[zh.key01]
|
|
117
|
+
中文测例3
|
|
118
|
+
中文测例4
|
|
119
|
+
```
|
|
120
|
+
It will be converted to:
|
|
121
|
+
```yml
|
|
122
|
+
l_english:
|
|
123
|
+
"key01":0 "test1\ntest2"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```yml
|
|
127
|
+
l_simp_chinese:
|
|
128
|
+
"ABC_key01":0 "中文测例1\n中文测例2"
|
|
129
|
+
"key01":0 "中文测例3\n中文测例4"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Currently `translate` supports either a local translation model or a Large Language Model, but it requires additonal setups (e.g., huggingface `transformer` or `openai`).
|
|
133
|
+
|
|
134
|
+
Instead of conversion to YML, you can also convert to JSON using:
|
|
135
|
+
```python
|
|
136
|
+
ReadTxtLocs("xxx.txt", scope="ABC")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
For example, the above text file will be parsed as `{'key01: {'en': 'test1\ntest2', 'zh': '中文测例3\n中文测例4'}, 'ABC_key01': {'zh': '中文测例1\n中文测例2'}}`.
|
|
140
|
+
|
|
141
|
+
### Conversion of dates
|
|
142
|
+
|
|
143
|
+
Want to know how many days you need to set in `on_actions` for the event to happen at a specific date? Or you need to number of weeks for a focus?
|
|
144
|
+
```python
|
|
145
|
+
get_num_days("1001.06.01", "1001.12.01") // 7 # 26 weeks
|
|
146
|
+
|
|
147
|
+
get_end_date("1002.12.01", 1298) # 1006.06.21
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Actually, when adding events, `hoi4dev` allows you to automatically set the dates in `on_actions`. We will specify how to use that in the `events` tutorial (Coming Soon).
|
|
151
|
+
|
|
152
|
+
## Advanced Features
|
|
153
|
+
|
|
154
|
+
See example scripts in `example_scripts/`. Those scripts may not all able to run as they lack project resource files, but can be useful to help you understand the `hoi4dev` mechanism and classical workflows. For example, consider example scripts in `PIHC_v_0_2_1_2024_10_06/`
|
|
155
|
+
|
|
156
|
+
On the one hand, there are some useful little tools that can be created using `hoi4dev` in `scripts/*/`:
|
|
157
|
+
|
|
158
|
+
For example `scripts/states_editor/szj.py` shows how you can batch change the owner of certain states by converting all state history files to JSON, modifying them, and save them back.
|
|
159
|
+
|
|
160
|
+
`scripts/add_kitin_state_group_gui.py` batch creates a map GUI gfxs (results are in `scripts/region_gui/`). This rely on preprocessed map information by `scripts/C01_build_the_map.py`.
|
|
161
|
+
|
|
162
|
+
`scripts/adv_gen/script.py` and `scripts/mil_gen/script.py` allow you generate a huge amount of political advisors and military generals with a single `.csv` file. You can create Chinese translation if all your mod developers are from Chinese, for example.
|
|
163
|
+
|
|
164
|
+
...
|
|
165
|
+
|
|
166
|
+
On the other hand, scripts starting with `scripts/CXX_....` demonstrates how a regular mod workflow runs. `v0.2.1.py` is the main thread, generating a mod from scratch (not able to run here due to lack of project resource files).
|
|
167
|
+
|
|
168
|
+
## Demos
|
|
169
|
+
|
|
170
|
+
We plan to share an end-to-end mod project built with the package in the near future. Stay tuned.
|
|
171
|
+
|
|
172
|
+
## Frequent Issues
|
|
173
|
+
|
|
174
|
+
### Windows Computer with non-UTF-8 characters / pyheaven running error with JSON files
|
|
175
|
+
|
|
176
|
+
**This package is known to malfunction if you are running on Windows with non-UTF-8 characters. May be fixed in the future.**
|
|
177
|
+
|
|
178
|
+
This error is usually occurred when operating JSON files containing Chinese. The error occurred due to version difference of `jsonlines`.
|
|
179
|
+
|
|
180
|
+
Therefore, you may try to modify the dependency `pyheaven`:
|
|
181
|
+
```python
|
|
182
|
+
# In pyheaven/serialize_utils/py 3
|
|
183
|
+
def SaveJson(obj, path, backend:Literal['json','jsonl','demjson','simplejson','jsonpickle']='json', indent:Optional[int]=None, append:bool=False, *args, **kwargs):
|
|
184
|
+
"""Save an object as json (or jsonl) file.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
obj: The object to be saved.
|
|
188
|
+
path: The save path.
|
|
189
|
+
backend (str): Specify backend for saving an object in json format. Please refer to function `BUILTIN_JSON_BACKENDS()` for built-in backends.
|
|
190
|
+
indent (int/None): The `indent` argument for saving in json format, only works if backend is not "jsonl".
|
|
191
|
+
append (bool): If True, use "a" mode instead of "w" mode, only works if backend is "jsonl".
|
|
192
|
+
Returns:
|
|
193
|
+
None
|
|
194
|
+
"""
|
|
195
|
+
assert (backend in BUILTIN_JSON_BACKENDS()), (f"backend not found! Supported backends: {BUILTIN_JSON_BACKENDS()}")
|
|
196
|
+
CreateFile(path); path = p2s(path)
|
|
197
|
+
if backend=='jsonl':
|
|
198
|
+
assert (indent is None), ("'jsonl' format does not support parameter 'indent'!")
|
|
199
|
+
with jsonlines.open(path, "a" if append else "w", encoding='utf-8', errors='ignore') as f:
|
|
200
|
+
for data in obj:
|
|
201
|
+
f.write(data)
|
|
202
|
+
else:
|
|
203
|
+
assert (append is False), ("'json' format does not support parameter 'append'!")
|
|
204
|
+
module = globals()[backend]
|
|
205
|
+
with open(path, "w", encoding='utf-8', errors='ignore') as f:
|
|
206
|
+
if backend in ['json','simplejson']:
|
|
207
|
+
module.dump(obj, f, indent=indent, *args, **kwargs)
|
|
208
|
+
else:
|
|
209
|
+
f.write(module.dumps(obj, indent=indent, *args, **kwargs))
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Remove or add `encoding='utf-8', errors='ignore'` depending on your error may solve this issue. You may also want to change `LoadJson` function in the same file. (If you find any convenient fix to this error, feel free to contact me or create a new issue to update `pyheaven`).
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# HOI4DEV
|
|
2
|
+
|
|
3
|
+
**Warning: This package is currently underdeveloped and does not guarantee any consistency.**
|
|
4
|
+
|
|
5
|
+
**Tutorial Coming Soon...**
|
|
6
|
+
|
|
7
|
+
**Compatible with HOI4 Version**:
|
|
8
|
+
|
|
9
|
+
### Configuration
|
|
10
|
+
|
|
11
|
+
After installation, you need to setup the config to start working for a specific mod project. By default, `init_config()` creates a config at `~/.hoi4dev/config.json`, you can setup the paths manually.
|
|
12
|
+
|
|
13
|
+
On MacOS:
|
|
14
|
+
```bash
|
|
15
|
+
{
|
|
16
|
+
"HOI4_GAME_PATH": "/Users/<YOUR_USER_NAME_HERE>/Library/Application Support/Steam/steamapps/common/Hearts of Iron IV",
|
|
17
|
+
"HOI4_MODS_PATH": "/Users/<YOUR_USER_NAME_HERE>/Documents/Paradox Interactive/Hearts of Iron IV/mod",
|
|
18
|
+
"HOI4_MODS_COPY_PATH": "/Users/<YOUR_USER_NAME_HERE>/Documents/Paradox Interactive/Hearts of Iron IV/mod",
|
|
19
|
+
"CURRENT_MOD_PATH": "/Users/<YOUR_USER_NAME_HERE>/Documents/Paradox Interactive/Hearts of Iron IV/mod/<YOUR_MOD_NAME>"
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
On Windows:
|
|
24
|
+
```bash
|
|
25
|
+
{
|
|
26
|
+
"HOI4_GAME_PATH": "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Hearts of Iron IV",
|
|
27
|
+
"HOI4_MODS_PATH": "C:\\Program Files (x86)\\Steam\\steamapps\\workshop\\content\\394360",
|
|
28
|
+
"HOI4_MODS_COPY_PATH": "C:\\Users\\<YOUR_USER_NAME_HERE>\\Documents\\Paradox Interactive\\Hearts of Iron IV\\mod",
|
|
29
|
+
"CURRENT_MOD_PATH": "C:\\Program Files (x86)\\Steam\\steamapps\\workshop\\content\\394360\\<YOUR_MOD_NAME>"
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The `HOI4_MODS_COPY_PATH` is usually useless, but sometimes it may be required if your user name contains Chinese or other non-UTF-8 characters. Though, it is still worth warning that **This package is known to malfunction if you are running on Windows with non-UTF-8 characters. May be fixed in the future.**
|
|
34
|
+
|
|
35
|
+
## Basic Features
|
|
36
|
+
|
|
37
|
+
### CCL (Clausewitz scripting language) and JSON conversion
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from hoi4dev import *
|
|
41
|
+
# Load JSON file
|
|
42
|
+
A = LoadJson("xxx.json")
|
|
43
|
+
|
|
44
|
+
# Convert JSON to CCL
|
|
45
|
+
with open("xxx.txt", "w") as f:
|
|
46
|
+
f.write(Dict2CCL(A) + "\n")
|
|
47
|
+
|
|
48
|
+
# Load CCL file
|
|
49
|
+
with open("ccl.txt", "r") as f:
|
|
50
|
+
A_ccl = f.read()
|
|
51
|
+
|
|
52
|
+
# Convert CCL to JSON
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Image conversion
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from hoi4dev import *
|
|
60
|
+
|
|
61
|
+
# Load a png
|
|
62
|
+
a = ImageLoad("xxx.png")
|
|
63
|
+
|
|
64
|
+
# Zoom & auto-Crop to target size
|
|
65
|
+
A = ImageZoom(a, w=512, h=512)
|
|
66
|
+
|
|
67
|
+
# Save Image:
|
|
68
|
+
ImageSave(A, "xxx.dds") # automatically compress dds with dxt5
|
|
69
|
+
ImageSave(A, "xxx.tga") # automatically flip tga for flags
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Find your COMPILED mod
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
# Use `F` to find your COMPILED mod files
|
|
76
|
+
path_to_your_mod = F("")
|
|
77
|
+
# Add a thumbnail manually
|
|
78
|
+
CopyFile("thumbnail.png", F("thumbnail.png"))
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Conversion between YML localisation and TXT files
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
AddLocalisation("xxx.txt", scope="ABC", translate=False)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
In the txt file, use `[<LANGUAGE_ABBREVIATION>.<KEY>]`, use `@` to copy the `scope`
|
|
88
|
+
For example, consider the following `txt` file, under "ABC" scope:
|
|
89
|
+
```
|
|
90
|
+
[en.key01]
|
|
91
|
+
test1
|
|
92
|
+
test2
|
|
93
|
+
[zh.@key01]
|
|
94
|
+
|
|
95
|
+
中文测例1
|
|
96
|
+
中文测例2
|
|
97
|
+
[zh.key01]
|
|
98
|
+
中文测例3
|
|
99
|
+
中文测例4
|
|
100
|
+
```
|
|
101
|
+
It will be converted to:
|
|
102
|
+
```yml
|
|
103
|
+
l_english:
|
|
104
|
+
"key01":0 "test1\ntest2"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```yml
|
|
108
|
+
l_simp_chinese:
|
|
109
|
+
"ABC_key01":0 "中文测例1\n中文测例2"
|
|
110
|
+
"key01":0 "中文测例3\n中文测例4"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Currently `translate` supports either a local translation model or a Large Language Model, but it requires additonal setups (e.g., huggingface `transformer` or `openai`).
|
|
114
|
+
|
|
115
|
+
Instead of conversion to YML, you can also convert to JSON using:
|
|
116
|
+
```python
|
|
117
|
+
ReadTxtLocs("xxx.txt", scope="ABC")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
For example, the above text file will be parsed as `{'key01: {'en': 'test1\ntest2', 'zh': '中文测例3\n中文测例4'}, 'ABC_key01': {'zh': '中文测例1\n中文测例2'}}`.
|
|
121
|
+
|
|
122
|
+
### Conversion of dates
|
|
123
|
+
|
|
124
|
+
Want to know how many days you need to set in `on_actions` for the event to happen at a specific date? Or you need to number of weeks for a focus?
|
|
125
|
+
```python
|
|
126
|
+
get_num_days("1001.06.01", "1001.12.01") // 7 # 26 weeks
|
|
127
|
+
|
|
128
|
+
get_end_date("1002.12.01", 1298) # 1006.06.21
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Actually, when adding events, `hoi4dev` allows you to automatically set the dates in `on_actions`. We will specify how to use that in the `events` tutorial (Coming Soon).
|
|
132
|
+
|
|
133
|
+
## Advanced Features
|
|
134
|
+
|
|
135
|
+
See example scripts in `example_scripts/`. Those scripts may not all able to run as they lack project resource files, but can be useful to help you understand the `hoi4dev` mechanism and classical workflows. For example, consider example scripts in `PIHC_v_0_2_1_2024_10_06/`
|
|
136
|
+
|
|
137
|
+
On the one hand, there are some useful little tools that can be created using `hoi4dev` in `scripts/*/`:
|
|
138
|
+
|
|
139
|
+
For example `scripts/states_editor/szj.py` shows how you can batch change the owner of certain states by converting all state history files to JSON, modifying them, and save them back.
|
|
140
|
+
|
|
141
|
+
`scripts/add_kitin_state_group_gui.py` batch creates a map GUI gfxs (results are in `scripts/region_gui/`). This rely on preprocessed map information by `scripts/C01_build_the_map.py`.
|
|
142
|
+
|
|
143
|
+
`scripts/adv_gen/script.py` and `scripts/mil_gen/script.py` allow you generate a huge amount of political advisors and military generals with a single `.csv` file. You can create Chinese translation if all your mod developers are from Chinese, for example.
|
|
144
|
+
|
|
145
|
+
...
|
|
146
|
+
|
|
147
|
+
On the other hand, scripts starting with `scripts/CXX_....` demonstrates how a regular mod workflow runs. `v0.2.1.py` is the main thread, generating a mod from scratch (not able to run here due to lack of project resource files).
|
|
148
|
+
|
|
149
|
+
## Demos
|
|
150
|
+
|
|
151
|
+
We plan to share an end-to-end mod project built with the package in the near future. Stay tuned.
|
|
152
|
+
|
|
153
|
+
## Frequent Issues
|
|
154
|
+
|
|
155
|
+
### Windows Computer with non-UTF-8 characters / pyheaven running error with JSON files
|
|
156
|
+
|
|
157
|
+
**This package is known to malfunction if you are running on Windows with non-UTF-8 characters. May be fixed in the future.**
|
|
158
|
+
|
|
159
|
+
This error is usually occurred when operating JSON files containing Chinese. The error occurred due to version difference of `jsonlines`.
|
|
160
|
+
|
|
161
|
+
Therefore, you may try to modify the dependency `pyheaven`:
|
|
162
|
+
```python
|
|
163
|
+
# In pyheaven/serialize_utils/py 3
|
|
164
|
+
def SaveJson(obj, path, backend:Literal['json','jsonl','demjson','simplejson','jsonpickle']='json', indent:Optional[int]=None, append:bool=False, *args, **kwargs):
|
|
165
|
+
"""Save an object as json (or jsonl) file.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
obj: The object to be saved.
|
|
169
|
+
path: The save path.
|
|
170
|
+
backend (str): Specify backend for saving an object in json format. Please refer to function `BUILTIN_JSON_BACKENDS()` for built-in backends.
|
|
171
|
+
indent (int/None): The `indent` argument for saving in json format, only works if backend is not "jsonl".
|
|
172
|
+
append (bool): If True, use "a" mode instead of "w" mode, only works if backend is "jsonl".
|
|
173
|
+
Returns:
|
|
174
|
+
None
|
|
175
|
+
"""
|
|
176
|
+
assert (backend in BUILTIN_JSON_BACKENDS()), (f"backend not found! Supported backends: {BUILTIN_JSON_BACKENDS()}")
|
|
177
|
+
CreateFile(path); path = p2s(path)
|
|
178
|
+
if backend=='jsonl':
|
|
179
|
+
assert (indent is None), ("'jsonl' format does not support parameter 'indent'!")
|
|
180
|
+
with jsonlines.open(path, "a" if append else "w", encoding='utf-8', errors='ignore') as f:
|
|
181
|
+
for data in obj:
|
|
182
|
+
f.write(data)
|
|
183
|
+
else:
|
|
184
|
+
assert (append is False), ("'json' format does not support parameter 'append'!")
|
|
185
|
+
module = globals()[backend]
|
|
186
|
+
with open(path, "w", encoding='utf-8', errors='ignore') as f:
|
|
187
|
+
if backend in ['json','simplejson']:
|
|
188
|
+
module.dump(obj, f, indent=indent, *args, **kwargs)
|
|
189
|
+
else:
|
|
190
|
+
f.write(module.dumps(obj, indent=indent, *args, **kwargs))
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Remove or add `encoding='utf-8', errors='ignore'` depending on your error may solve this issue. You may also want to change `LoadJson` function in the same file. (If you find any convenient fix to this error, feel free to contact me or create a new issue to update `pyheaven`).
|
hoi4dev-0.1.0.3/setup.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
import pathlib
|
|
4
|
+
here = pathlib.Path(__file__).parent.resolve()
|
|
5
|
+
version = '0.1.0.3'
|
|
6
|
+
short_description = "HOI4DEV: Hearts of Iron IV Development Tools"
|
|
7
|
+
long_description = (here / "README.md").read_text(encoding="utf-8")
|
|
8
|
+
|
|
9
|
+
print(f"Installing HOI4DEV version: {version}.")
|
|
10
|
+
setup(
|
|
11
|
+
name = "hoi4dev",
|
|
12
|
+
version = version,
|
|
13
|
+
author = "Magolor",
|
|
14
|
+
author_email = "magolorcz@gmail.com",
|
|
15
|
+
description = short_description,
|
|
16
|
+
long_description = long_description,
|
|
17
|
+
long_description_content_type="text/markdown",
|
|
18
|
+
url = "https://github.com/Magolor/",
|
|
19
|
+
project_urls={
|
|
20
|
+
"Author":"https://github.com/Magolor/",
|
|
21
|
+
},
|
|
22
|
+
python_requires=">=3.9, <4",
|
|
23
|
+
packages=find_packages(),
|
|
24
|
+
package_dir={"":"src"},
|
|
25
|
+
entry_points = '''
|
|
26
|
+
[console_scripts]
|
|
27
|
+
hoi4dev=hoi4dev.cli:cli
|
|
28
|
+
''',
|
|
29
|
+
classifiers = [
|
|
30
|
+
"Development Status :: 3 - Alpha",
|
|
31
|
+
"Intended Audience :: Developers",
|
|
32
|
+
"Topic :: Software Development :: Build Tools",
|
|
33
|
+
"License :: OSI Approved :: MIT License",
|
|
34
|
+
"Programming Language :: Python :: 3",
|
|
35
|
+
"Operating System :: MacOS :: MacOS X",
|
|
36
|
+
"Operating System :: Microsoft :: Windows",
|
|
37
|
+
],
|
|
38
|
+
package_data={
|
|
39
|
+
'hoi4dev': ['resources/**/*'],
|
|
40
|
+
}
|
|
41
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from .utils import *
|
|
2
|
+
from .translation import *
|
|
3
|
+
from .init import *
|
|
4
|
+
from .maps import *
|
|
5
|
+
from .ideologies import *
|
|
6
|
+
from .ideas import *
|
|
7
|
+
from .modifiers import *
|
|
8
|
+
from .traits import *
|
|
9
|
+
from .countries import *
|
|
10
|
+
from .diplomacy import *
|
|
11
|
+
from .characters import *
|
|
12
|
+
from .equipments import *
|
|
13
|
+
from .technologies import *
|
|
14
|
+
from .divisions import *
|
|
15
|
+
from .decisions import *
|
|
16
|
+
from .focuses import *
|
|
17
|
+
from .events import *
|
|
18
|
+
from .bops import *
|
|
19
|
+
from .intelligence_agencies import *
|
|
20
|
+
from .achievements import *
|
|
21
|
+
|
|
22
|
+
__version__ = "0.1.0.3"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from ..utils import *
|
|
2
|
+
from ..translation import AddLocalisation
|
|
3
|
+
|
|
4
|
+
def AddAchievement(unique_id, path, translate=True):
|
|
5
|
+
'''
|
|
6
|
+
Add an achievement to the mod.
|
|
7
|
+
Args:
|
|
8
|
+
unique_id: str. The unique id of your entire mod.
|
|
9
|
+
path: str. The path of the resource files of the achievement. The resources should include the achievement icon, the achievement definition and the localisation.
|
|
10
|
+
translate: bool. Whether to translate the localisation of the achievement.
|
|
11
|
+
Return:
|
|
12
|
+
None
|
|
13
|
+
'''
|
|
14
|
+
tag = path.strip('/').split('/')[-1].upper()
|
|
15
|
+
file_name = f"custom_achievements_{unique_id}.json"
|
|
16
|
+
info = LoadJson(pjoin(path,"info.json"))
|
|
17
|
+
name = info.pop('name', None)
|
|
18
|
+
|
|
19
|
+
# Add idea localisation
|
|
20
|
+
AddLocalisation(pjoin(path,"locs.txt"), scope=f"ACHIEVEMENT_{tag}", translate=translate)
|
|
21
|
+
|
|
22
|
+
# Initialize achievement definition
|
|
23
|
+
Edit(F(pjoin("data","common","achievements",file_name)), {'unique_id': unique_id, f"ACHIEVEMENT_{tag}": info}, clear=False)
|
|
24
|
+
|
|
25
|
+
# Add achievement icons
|
|
26
|
+
scales = get_mod_config('img_scales'); w, h = scales['achievement']
|
|
27
|
+
icon = ImageFind(pjoin(path,"default"))
|
|
28
|
+
if icon is None:
|
|
29
|
+
icon = ImageFind(F(pjoin("hoi4dev_settings", "imgs", "defaults", "default_achievement")), find_default=False)
|
|
30
|
+
assert (icon is not None), "The default achievement icon is not found!"
|
|
31
|
+
icon = ImageZoom(icon, w=w, h=h)
|
|
32
|
+
ImageSave(icon, F(pjoin("gfx","achievements",f"ACHIEVEMENT_{tag}")), format='dds')
|
|
33
|
+
|
|
34
|
+
grey_icon = icon.clone()
|
|
35
|
+
grey_icon.type = "grayscale"
|
|
36
|
+
ImageSave(grey_icon, F(pjoin("gfx","achievements",f"ACHIEVEMENT_{tag}_grey")), format='dds')
|
|
37
|
+
|
|
38
|
+
not_eligible_icon = icon.clone()
|
|
39
|
+
X = ImageFind(F(pjoin("hoi4dev_settings", "imgs", "defaults", "X")), find_default=False)
|
|
40
|
+
X = ImageZoom(X, w=int(w*0.9), h=int(h*0.9))
|
|
41
|
+
assert (icon is not None), "The default achievement not eligible icon is not found!"
|
|
42
|
+
not_eligible_icon.composite(X, gravity='center')
|
|
43
|
+
ImageSave(not_eligible_icon, F(pjoin("gfx","achievements",f"ACHIEVEMENT_{tag}_not_eligible")), format='dds')
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from ..utils import *
|
|
2
|
+
from ..translation import AddLocalisation
|
|
3
|
+
|
|
4
|
+
def AddBoP(path, translate=True):
|
|
5
|
+
'''
|
|
6
|
+
Add a balance of power to the mod.
|
|
7
|
+
Args:
|
|
8
|
+
path: str. The path of the resource files of the bop. The resources should include the left side icon, right side icon, the bop definition and the localisation.
|
|
9
|
+
translate: bool. Whether to translate the localisation of the bop.
|
|
10
|
+
Return:
|
|
11
|
+
None
|
|
12
|
+
It is recommended to use 'sides' to define the sides of the bop, which is a dictionary mapping from the side name to the side. 'left' and 'right' are reserved for the left and right side of the bop.
|
|
13
|
+
Any side definition using 'side' instead of 'sides' will NOT be processed by this function.
|
|
14
|
+
'''
|
|
15
|
+
tag = path.strip('/').split('/')[-1].upper()
|
|
16
|
+
info = merge_dicts([{
|
|
17
|
+
'left_side': f'BOP_{tag}_LEFT_SIDE',
|
|
18
|
+
'right_side': f'BOP_{tag}_RIGHT_SIDE',
|
|
19
|
+
'initial_value': 0.0,
|
|
20
|
+
},LoadJson(pjoin(path,"info.json"))])
|
|
21
|
+
name = info.pop('name', None)
|
|
22
|
+
sides = info.pop('sides', list())
|
|
23
|
+
modifiers = info.pop('modifiers', list())
|
|
24
|
+
for s in sides:
|
|
25
|
+
S = s.upper()
|
|
26
|
+
sides[s] = merge_dicts([{
|
|
27
|
+
'id': f'BOP_{tag}_{S}_SIDE',
|
|
28
|
+
'icon': f'GFX_BOP_{tag}_{S}_SIDE',
|
|
29
|
+
},sides[s]])
|
|
30
|
+
for i, key in enumerate(dup_gen('range')):
|
|
31
|
+
if key in sides[s]:
|
|
32
|
+
sides[s][key] = merge_dicts([{
|
|
33
|
+
'id': f'BOP_{tag}_{S}_SIDE_r{i}',
|
|
34
|
+
},sides[s][key]])
|
|
35
|
+
else:
|
|
36
|
+
break
|
|
37
|
+
for s in sides:
|
|
38
|
+
info[find_dup('side', info)] = sides[s]
|
|
39
|
+
|
|
40
|
+
# Add bop localisation
|
|
41
|
+
AddLocalisation(pjoin(path,"locs.txt"), scope=f"BOP_{tag}", translate=translate)
|
|
42
|
+
|
|
43
|
+
# Initialize bop definition
|
|
44
|
+
Edit(F(pjoin("data","common","bop",f"BOP_{tag}.json")), {f"BOP_{tag}": info})
|
|
45
|
+
|
|
46
|
+
# Add bop modifiers
|
|
47
|
+
if modifiers: Edit(F(pjoin("data","common","modifiers",f"BOP_{tag}.json")), modifiers)
|
|
48
|
+
|
|
49
|
+
# Add bop icons
|
|
50
|
+
scales = get_mod_config('img_scales'); w, h = scales['bop']
|
|
51
|
+
sprites = []
|
|
52
|
+
for s in sides:
|
|
53
|
+
S = s.upper()
|
|
54
|
+
icon = ImageFind(pjoin(path,"icons",s))
|
|
55
|
+
if icon is None:
|
|
56
|
+
icon = ImageFind(F(pjoin("hoi4dev_settings", "imgs", "default_bop")), find_default=False)
|
|
57
|
+
assert (icon is not None), "The default balance of power icon is not found!"
|
|
58
|
+
icon = ImageZoom(icon, w=w, h=h)
|
|
59
|
+
ImageSave(icon, F(pjoin("gfx","interface","bop",f"BOP_{tag}_{S}_SIDE")), format='dds')
|
|
60
|
+
sprites.append({'spriteType': {"name": f"GFX_BOP_{tag}_{S}_SIDE", "texturefile": pjoin("gfx","interface","bop",f"BOP_{tag}_{S}_SIDE.dds")}})
|
|
61
|
+
Edit(F(pjoin("data","interface","bop",f"BOP_{tag}.json")), {'spriteTypes': merge_dicts(sprites,d=True)})
|