Skip to content

Commit 53dcdd6

Browse files
authored
Merge pull request #395 from satisfactorymodding/Dev
Update with changes from Dev
2 parents 226adb6 + 065eefc commit 53dcdd6

File tree

110 files changed

+1629
-593
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

110 files changed

+1629
-593
lines changed

.github/workflows/push.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ jobs:
122122
BUILD=build:ci
123123
124124
notify:
125-
name: Notify
125+
name: Build Failure Notifications
126126
runs-on: ubuntu-latest
127127
needs:
128128
- build

antora.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,13 @@ asciidoc:
88
# Custom text replacements. Built-in ones can be found here:
99
# https://github.com/asciidoctor/asciidoctor/blob/917d3800a08a8f283a8d05beb08bb75af1673de5/lib/asciidoctor.rb#L391
1010
attributes:
11+
# Increase max table of content nesting levels from 2 to 3 https://docs.antora.org/antora/latest/page/page-attributes/#access-attributes-from-ui-template
12+
page-toclevels: 3@
13+
# Zero-width joiner (U+200D) to avoid being split across lines
14+
zero-width-join:
1115
# Uses zero-width joiner (U+200D) to avoid being split across lines
12-
cpp: C‍+‍+
16+
cpp: C‍+‍+
17+
# Use backslash without it escaping things in other situations
18+
literal-backslash: \
19+
# To keep paths from breaking across lines
20+
NoBreakBackslash: ‍\‍

cspell.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
"paintable",
8989
"Paks",
9090
"Panakotta",
91+
"Panini",
9192
"passaround",
9293
"Photoshop",
9394
"Quixel",
@@ -109,6 +110,7 @@
109110
"structs",
110111
"subfolder",
111112
"subfolders",
113+
"toclevels",
112114
"Tolgee",
113115
"Treelo",
114116
"uasset",

lychee.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,13 @@ exclude = [
3737
"https://docs.unrealengine.com/",
3838
"https://dev.epicgames.com/",
3939
"^https://www.unrealengine.com/en-US/blog/.*",
40+
"^https://www.epicgames.com/help/.*",
4041
# Times out despite being valid
4142
"https://www.adobe.com/learn/substance-3d-designer/web/the-pbr-guide-part-1",
4243
# Pages often time out and Shouldn't™ ever get deleted anyways
4344
"https://web.archive.org/web/",
4445
# Cloudflare checks this, unlikely to be deleted
45-
"^https://superuser.com/.*",
46-
# Temporarily allow link to 3.10 docs that won't exist till PR is merged. Clean this up as soon as 3.10 is stable.
47-
"https://docs.ficsit.app/satisfactory-modding/v3.10.0/index.html"
46+
"^https://superuser.com/.*"
4847
]
4948

5049
# Exclude these filesystem paths from getting checked.

modules/ROOT/attachments/BeginnersGuide/dependencies/SML.vsconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
3636
"Microsoft.VisualStudio.Component.Graphics.Tools",
3737
"Microsoft.VisualStudio.Component.VC.DiagnosticTools",
38-
"Microsoft.VisualStudio.Component.Windows11SDK.22000",
38+
"Microsoft.VisualStudio.Component.Windows11SDK.26100",
3939
"Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites",
4040
"Microsoft.VisualStudio.Component.DotNetModelBuilder",
4141
"Microsoft.ComponentGroup.Blend",
Lines changed: 228 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,242 @@
1+
# pylint: disable=logging-fstring-interpolation, global-statement, missing-function-docstring, missing-module-docstring, broad-exception-caught
12
import os
3+
import subprocess
24
from pathlib import Path
5+
import shutil
6+
import logging
7+
import sys
38

4-
def convert(filename):
9+
# Full path to vgmstream-cli.exe, usually in your FModel's Output Directory
10+
# Example Path
11+
VGMSTREAM = Path(r"C:/FModel/Output/.data/vgmstream-cli.exe")
512

6-
my_file = open("./txtp/" + filename, "r")
7-
data = my_file.read()
13+
# ==================================================================================================
814

9-
data_into_list = data.replace('\n', ' ').split(" ")
15+
# Logs
16+
MAIN_LOG = "conversion_main.log"
17+
FAILED_LOG = "conversion_errors.log"
1018

19+
# Setup main logging
20+
logging.basicConfig(
21+
level=logging.INFO,
22+
format="%(asctime)s [%(levelname)s] %(message)s",
23+
handlers=[
24+
logging.FileHandler(MAIN_LOG, mode="w", encoding="utf-8"),
25+
logging.StreamHandler(),
26+
],
27+
)
1128

12-
for i in range(len(data_into_list)):
13-
if data_into_list[i].startswith('wem'):
1429

15-
wavname = "./txtp/" + data_into_list[i].split('.')[0] + '.wav'
30+
# Set up subfolders
31+
currentDirectory = Path(os.path.dirname(os.path.abspath(__file__)))
32+
(currentDirectory / "out").mkdir(exist_ok=True)
33+
(currentDirectory / "txtp" / "wem").mkdir(parents=True, exist_ok=True)
1634

17-
if os.path.isfile(wavname):
18-
os.rename(wavname, "./out/" + filename.split('.')[0] + '_' + str(i) + '.wav')
35+
# Check if vgmstream exists
36+
if not VGMSTREAM.exists():
37+
logging.critical(
38+
f"vgmstream-cli.exe not found at {VGMSTREAM}. It should have been downloaded by FModel. Edit the script if necessary to change the path."
39+
)
40+
sys.exit(1)
41+
else:
42+
logging.info(f"Using vgmstream-cli.exe at {VGMSTREAM}")
43+
44+
# Setup failed conversion logging (Will overwrite each run, could be replaced with RotatingFileHandler but needs script changes)
45+
failed_logger = logging.getLogger("failed")
46+
failed_handler = logging.FileHandler(FAILED_LOG, mode="w", encoding="utf-8")
47+
failed_handler.setLevel(logging.ERROR)
48+
failed_logger.addHandler(failed_handler)
49+
failed_logger.propagate = False
50+
51+
# Counters for summary
52+
total_wems = 0
53+
converted_count = 0
54+
skipped_count = 0
55+
failed_count = 0
56+
57+
58+
# Step 1: Convert all .wem files into ./out_temp/wem/ (flat), mapping to digit folders
59+
def wem_to_wav(input_root, temp_root):
60+
global converted_count, skipped_count, failed_count
61+
input_root = Path(input_root)
62+
temp_wem_root = Path(temp_root) / "wem"
63+
64+
# CLEAN temp folder
65+
if temp_wem_root.exists():
66+
shutil.rmtree(temp_wem_root)
67+
temp_wem_root.mkdir(parents=True, exist_ok=True)
68+
69+
wav_filename_to_digit_folder = {}
70+
71+
for folder, _, files in os.walk(input_root):
72+
folder_path = Path(folder)
73+
74+
# If we are in root (txtp/wem) use "root" as folder name
75+
digit_folder = "root" if folder_path == input_root else folder_path.name
76+
77+
for file in files:
78+
ext = Path(file).suffix.lower()
79+
base_name = Path(file).stem
80+
wav_name = base_name + ".wav"
81+
82+
wem_path = folder_path / file
83+
wav_path = temp_wem_root / wav_name
84+
wav_filename_to_digit_folder[wav_name] = digit_folder
85+
86+
final_out_path = Path("out") / digit_folder / wav_name
87+
if wav_path.exists() or final_out_path.exists():
88+
skipped_count += 1
89+
logging.info(f"Skipping existing WAV: {wav_path} or {final_out_path}")
90+
continue
91+
92+
if ext == ".wem":
93+
# Convert wem → wav
94+
logging.info(f"Converting: {wem_path}{wav_path}")
95+
result = subprocess.run(
96+
[str(VGMSTREAM), "-o", str(wav_path), str(wem_path)],
97+
capture_output=True,
98+
text=True,
99+
check=False,
100+
)
101+
if result.returncode != 0 or not wav_path.exists():
102+
failed_count += 1
103+
logging.error(f"Conversion failed for {wem_path}: {result.stderr}")
104+
failed_logger.error(str(wem_path))
105+
else:
106+
converted_count += 1
107+
logging.info(f"Converted {wem_path} successfully")
108+
109+
elif ext == ".wav":
110+
# Copy pre-existing wav into temp for rename step
111+
try:
112+
shutil.copy2(wem_path, wav_path)
113+
skipped_count += 1
114+
logging.info(
115+
f"Using existing WAV instead of converting: {wem_path}{wav_path}"
116+
)
117+
except Exception as e:
118+
failed_count += 1
119+
logging.error(f"Failed to copy existing WAV {wem_path}: {e}")
120+
failed_logger.error(str(wem_path))
121+
return wav_filename_to_digit_folder
122+
123+
124+
# Step 2: Rename .wav files based on .txtp references
125+
def convert(filename, wav_root, out_root, mapping):
126+
wav_root = Path(wav_root)
127+
out_root = Path(out_root)
128+
txtp_path = Path("txtp") / filename
129+
130+
try:
131+
with open(txtp_path, "r", encoding="utf-8") as my_file:
132+
data = my_file.read()
133+
except Exception as e:
134+
logging.error(f"Failed to read {txtp_path}: {e}")
135+
return
136+
137+
tokens = data.replace("\n", " ").split(" ")
138+
139+
for i, token in enumerate(tokens):
140+
if token.startswith("wem"):
141+
wav_file_only = Path(token).stem + ".wav"
142+
wavname = wav_root / wav_file_only
143+
digit_folder = mapping.get(wavname.name, "unknown")
144+
out_folder = out_root / digit_folder
145+
out_folder.mkdir(parents=True, exist_ok=True)
146+
new_name = out_folder / f"{filename.split('.')[0]}_{i}.wav"
147+
148+
if new_name.exists():
149+
logging.info(f"Skipping already renamed WAV: {new_name}")
150+
continue
151+
152+
if wavname.exists():
153+
try:
154+
shutil.move(str(wavname), str(new_name))
155+
logging.info(f"Renamed {wavname}{new_name}")
156+
except Exception as e:
157+
logging.error(f"Failed to rename {wavname}: {e}")
19158
else:
20-
print(wavname + " not found.")
159+
logging.warning(f"{wavname} not found.")
160+
161+
162+
# Step 3: Retry failed conversions
163+
def retry_failed_conversions(temp_wav_root):
164+
global converted_count, failed_count
165+
failed_path = Path(FAILED_LOG)
166+
if not failed_path.exists():
167+
logging.info("No failed conversions to retry.")
168+
return
169+
170+
logging.info("Retrying failed conversions...")
171+
172+
# Read and truncate the failed log for this retry
173+
with open(failed_path, "r+", encoding="utf-8") as f:
174+
failed_files = [line.strip() for line in f.readlines() if line.strip()]
175+
f.seek(0)
176+
f.truncate(0)
177+
178+
new_failures = 0 # counter for files that fail again
179+
180+
for wem_path_str in failed_files:
181+
wem_path = Path(wem_path_str)
182+
wav_name = wem_path.stem + ".wav"
183+
wav_path = temp_wav_root / wav_name
184+
185+
if wav_path.exists():
186+
logging.info(f"Skipping existing WAV: {wav_path}")
187+
continue
188+
189+
logging.info(f"Retrying conversion: {wem_path}{wav_path}")
190+
result = subprocess.run(
191+
[str(VGMSTREAM), "-o", str(wav_path), str(wem_path)],
192+
capture_output=True,
193+
text=True,
194+
check=False,
195+
)
196+
if result.returncode != 0 or not wav_path.exists():
197+
new_failures += 1
198+
logging.error(
199+
f"Conversion failed a 2nd time: {wem_path}. "
200+
"Either the .wem file is corrupt, broken, or there is no .txtp path for that file. "
201+
"Consider a manual approach or ask for help in the Discord."
202+
)
203+
failed_logger.error(str(wem_path))
204+
else:
205+
# Count as converted only if it actually succeeds now
206+
converted_count += 1
207+
logging.info(f"Successfully converted on retry: {wem_path}")
208+
209+
# Update failed_count to reflect files that truly failed after retry
210+
failed_count = new_failures
211+
212+
213+
# Main driver
214+
if __name__ == "__main__":
215+
wem_root = Path("txtp/wem")
216+
wav_temp_root = Path("out_temp") / "wem"
217+
out_root = Path("out")
218+
219+
logging.info("Starting .wem → .wav conversion")
220+
mapping = wem_to_wav(wem_root, Path("out_temp"))
21221

22-
my_file.close()
222+
logging.info("Starting .wav renaming based on .txtp files")
223+
txtp_files = [f for f in Path("txtp").glob("*.txtp")]
224+
for file_path in txtp_files:
225+
convert(file_path.name, wav_temp_root, out_root, mapping)
23226

24-
relevant_path = "./txtp/"
25-
included_extensions = ['txtp']
26-
file_names = [fn for fn in os.listdir(relevant_path)
27-
if any(fn.endswith(ext) for ext in included_extensions)]
227+
# Retry any failed conversions
228+
retry_failed_conversions(wav_temp_root)
28229

230+
# Clean up temp folder
231+
if wav_temp_root.parent.exists():
232+
shutil.rmtree(wav_temp_root.parent)
233+
logging.info(f"Temporary folder {wav_temp_root.parent} deleted")
29234

30-
for file_name in file_names:
31-
convert(file_name)
235+
# Final summary
236+
logging.info("===================================")
237+
logging.info(f"Total .wem files found: {total_wems}")
238+
logging.info(f"Successfully converted: {converted_count}")
239+
logging.info(f"Skipped (already exists): {skipped_count}")
240+
logging.info(f"Failed conversions: {failed_count}")
241+
logging.info("Conversion and renaming complete")
242+
logging.info("===================================")
11.1 KB
172 KB
106 KB
52.9 KB

0 commit comments

Comments
 (0)