Skip to content

Commit 94d5968

Browse files
committed
Added printed information for loading exported changes and saving crop changes to the file | release v2.7.0
1 parent 76803c3 commit 94d5968

3 files changed

Lines changed: 263 additions & 2 deletions

File tree

main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ def get_resource_path(relative_path: str) -> str:
440440
continue
441441

442442
# Create crop editor window (it handles its own event loop)
443-
create_crop_editor_window(database_file_path, database_cursor)
443+
create_crop_editor_window(database_file_path, database_cursor, str(user_save_changes_path))
444444

445445
# Handle Set Swapper functionality
446446
if event == "-SET_SWAPPER-":

src/crop_editor.py

Lines changed: 163 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import FreeSimpleGUI as sg
3535
from pathlib import Path
3636
from typing import Dict, List, Optional, Tuple
37+
import json
3738

3839

3940
class ArtCropData:
@@ -229,16 +230,168 @@ def filter_crops_by_art_id(
229230
return [entry for entry in crop_data if art_id.zfill(6) in entry.path]
230231

231232

233+
def extract_art_id_from_path(path: str) -> Optional[str]:
234+
"""
235+
Extract ArtId from a crop path.
236+
Path format: Assets/Core/CardArt/001000/001155_AIF
237+
238+
Args:
239+
path: The crop entry path
240+
241+
Returns:
242+
ArtId as string, or None if not found
243+
"""
244+
try:
245+
# Split the path and look for the numeric part
246+
parts = path.split("/")
247+
art_id = parts[-1].split("_")[0].lstrip("0")
248+
return art_id
249+
except Exception as e:
250+
print(f"Error extracting ArtId from path {path}: {e}")
251+
return None
252+
253+
254+
def save_crop_change_to_json(entry: ArtCropData, changes_file_path: str) -> bool:
255+
"""
256+
Save crop change to the changes.json file based on ArtId.
257+
258+
Args:
259+
entry: The crop entry that was modified
260+
changes_file_path: Path to the changes.json file
261+
262+
Returns:
263+
True if successful, False otherwise
264+
"""
265+
try:
266+
# Extract ArtId from path
267+
art_id = extract_art_id_from_path(entry.path)
268+
if not art_id:
269+
print(f"Could not extract ArtId from path: {entry.path}")
270+
return False
271+
272+
# Load existing changes
273+
if os.path.exists(changes_file_path):
274+
with open(changes_file_path, "r") as f:
275+
changes_data = json.load(f)
276+
else:
277+
changes_data = {}
278+
279+
# Initialize crops structure if not exists
280+
if "crops" not in changes_data:
281+
changes_data["crops"] = {}
282+
283+
# Store crop change under ArtId
284+
if art_id not in changes_data["crops"]:
285+
changes_data["crops"][art_id] = []
286+
287+
# Create crop entry dict
288+
crop_dict = {
289+
"path": entry.path,
290+
"format": entry.format_type,
291+
"x": entry.x,
292+
"y": entry.y,
293+
"z": entry.z,
294+
"w": entry.w,
295+
"generated": entry.generated,
296+
}
297+
298+
# Check if this crop already exists (by path and format)
299+
existing_crops = changes_data["crops"][art_id]
300+
existing_index = None
301+
for i, crop in enumerate(existing_crops):
302+
if crop["path"] == entry.path and crop["format"] == entry.format_type:
303+
existing_index = i
304+
break
305+
306+
if existing_index is not None:
307+
# Update existing
308+
existing_crops[existing_index] = crop_dict
309+
else:
310+
# Add new
311+
existing_crops.append(crop_dict)
312+
313+
# Save back to file
314+
with open(changes_file_path, "w") as f:
315+
json.dump(changes_data, f, indent=4)
316+
317+
return True
318+
319+
except Exception as e:
320+
print(f"Error saving crop change to JSON: {e}")
321+
return False
322+
323+
324+
def remove_crop_change_from_json(entry: ArtCropData, changes_file_path: str) -> bool:
325+
"""
326+
Remove crop change from the changes.json file.
327+
328+
Args:
329+
entry: The crop entry to remove
330+
changes_file_path: Path to the changes.json file
331+
332+
Returns:
333+
True if successful, False otherwise
334+
"""
335+
try:
336+
# Extract ArtId from path
337+
art_id = extract_art_id_from_path(entry.path)
338+
if not art_id:
339+
return False
340+
341+
# Load existing changes
342+
if not os.path.exists(changes_file_path):
343+
return True # Nothing to remove
344+
345+
with open(changes_file_path, "r") as f:
346+
changes_data = json.load(f)
347+
348+
# Check if crops section exists
349+
if "crops" not in changes_data or art_id not in changes_data["crops"]:
350+
return True # Nothing to remove
351+
352+
# Remove the matching crop entry
353+
changes_data["crops"][art_id] = [
354+
crop
355+
for crop in changes_data["crops"][art_id]
356+
if not (crop["path"] == entry.path and crop["format"] == entry.format_type)
357+
]
358+
359+
# Clean up empty entries
360+
if not changes_data["crops"][art_id]:
361+
del changes_data["crops"][art_id]
362+
363+
if not changes_data["crops"]:
364+
del changes_data["crops"]
365+
366+
# Save back to file
367+
with open(changes_file_path, "w") as f:
368+
json.dump(changes_data, f, indent=4)
369+
370+
return True
371+
372+
except Exception as e:
373+
print(f"Error removing crop change from JSON: {e}")
374+
return False
375+
376+
232377
def create_crop_editor_window(
233-
database_file_path: str, database_cursor: sqlite3.Cursor
378+
database_file_path: str,
379+
database_cursor: sqlite3.Cursor,
380+
changes_file_path: str = None,
234381
) -> None:
235382
"""
236383
Create and display the crop editor window.
237384
238385
Args:
239386
database_file_path: Path to the Raw_CardDatabase file
240387
database_cursor: SQLite cursor for querying card data
388+
changes_file_path: Path to the changes.json file (optional)
241389
"""
390+
# Set default changes file path if not provided
391+
if changes_file_path is None:
392+
user_config_directory = Path.home() / ".mtga_swapper"
393+
changes_file_path = str(user_config_directory / "changes.json")
394+
242395
# Determine the crop database path
243396
db_dir = os.path.dirname(database_file_path)
244397
crop_db_path = None
@@ -453,6 +606,9 @@ def load_entry_to_edit(entry: ArtCropData):
453606

454607
# Update in the database (without committing yet)
455608
if update_crop_entry(crop_cursor, entry, commit=False):
609+
# Save to changes.json
610+
save_crop_change_to_json(entry, changes_file_path)
611+
456612
# Update the display
457613
update_crop_table(filtered_crops)
458614

@@ -588,6 +744,9 @@ def load_entry_to_edit(entry: ArtCropData):
588744
new_entry.to_tuple(),
589745
)
590746

747+
# Save to changes.json
748+
save_crop_change_to_json(new_entry, changes_file_path)
749+
591750
# Add to our data structures
592751
crop_data.append(new_entry)
593752
filtered_crops.append(new_entry)
@@ -650,6 +809,9 @@ def load_entry_to_edit(entry: ArtCropData):
650809
(entry.path, entry.format_type),
651810
)
652811

812+
# Remove from changes.json
813+
remove_crop_change_from_json(entry, changes_file_path)
814+
653815
# Remove from our data structures
654816
crop_data.remove(entry)
655817
filtered_crops.remove(entry)

src/load_preset.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,81 @@
66
import shutil
77

88

9+
def apply_crop_changes(crop_changes: dict, asset_bundle_path: str) -> None:
10+
"""
11+
Apply crop changes from the changes.json file to the Art Crop Database.
12+
13+
Args:
14+
crop_changes: Dictionary of crop changes keyed by ArtId
15+
asset_bundle_path: Path to the MTGA asset bundle directory
16+
"""
17+
try:
18+
# Find the Raw_ArtCropDatabase file
19+
crop_db_path = None
20+
raw_path = Path(asset_bundle_path).parent / "Raw"
21+
for file in os.listdir(raw_path):
22+
if file.startswith("Raw_ArtCropDatabase") and file.endswith(".mtga"):
23+
crop_db_path = os.path.join(raw_path, file)
24+
break
25+
26+
if not crop_db_path or not os.path.exists(crop_db_path):
27+
print(
28+
"Warning: Could not find Raw_ArtCropDatabase file, skipping crop changes"
29+
)
30+
return
31+
32+
# Connect to the crop database
33+
conn = sqlite3.connect(crop_db_path)
34+
cursor = conn.cursor()
35+
36+
# Apply each crop change
37+
for art_id, crops in crop_changes.items():
38+
for crop in crops:
39+
try:
40+
path = crop["path"]
41+
format_type = crop["format"]
42+
x = crop["x"]
43+
y = crop["y"]
44+
z = crop["z"]
45+
w = crop["w"]
46+
generated = crop["generated"]
47+
48+
# Check if entry exists
49+
cursor.execute(
50+
"SELECT COUNT(*) FROM Crops WHERE Path = ? AND Format = ?",
51+
(path, format_type),
52+
)
53+
exists = cursor.fetchone()[0] > 0
54+
55+
if exists:
56+
# Update existing entry
57+
cursor.execute(
58+
"UPDATE Crops SET X = ?, Y = ?, Z = ?, W = ?, Generated = ? WHERE Path = ? AND Format = ?",
59+
(x, y, z, w, generated, path, format_type),
60+
)
61+
else:
62+
# Insert new entry
63+
cursor.execute(
64+
"INSERT INTO Crops (Path, Format, X, Y, Z, W, Generated) VALUES (?, ?, ?, ?, ?, ?, ?)",
65+
(path, format_type, x, y, z, w, generated),
66+
)
67+
68+
print(
69+
f"Applied crop change for ArtId {art_id}: {path} ({format_type})"
70+
)
71+
72+
except Exception as e:
73+
print(f"Error applying crop change for ArtId {art_id}: {e}")
74+
75+
# Commit all changes
76+
conn.commit()
77+
conn.close()
78+
print(f"Successfully applied {len(crop_changes)} crop change(s)")
79+
80+
except Exception as e:
81+
print(f"Error applying crop changes: {e}")
82+
83+
984
def save_grp_id_info(
1085
grp_id: list[str],
1186
user_save_changes_path: str,
@@ -90,12 +165,25 @@ def change_grp_id(
90165
list(json_manual.values()) + [grp_id],
91166
)
92167
else:
168+
print(f"Loading changes from: {change_path}")
93169
with open(change_path, "r") as changes_file:
94170
changes_data = json.load(changes_file)
95171
changes_file.close()
172+
173+
# Handle crop changes if present
174+
crop_changes = changes_data.pop("crops", None)
175+
if crop_changes and asset_bundle_path:
176+
print(f"Found {len(crop_changes)} ArtId(s) with crop changes")
177+
apply_crop_changes(crop_changes, asset_bundle_path)
178+
elif crop_changes:
179+
print(
180+
"Warning: Crop changes found but asset_bundle_path not provided, skipping crop changes"
181+
)
182+
96183
available_backups = Path.home() / "MTGA_Swapper_Backups"
97184
backups = list(available_backups.glob("MOD_*.mtga"))
98185
backups.sort(key=os.path.getmtime)
186+
restored_count = 0
99187
for art in backups:
100188
matching_files = [
101189
filename
@@ -108,6 +196,13 @@ def change_grp_id(
108196
art,
109197
os.path.join(asset_bundle_path, matching_files[0]),
110198
)
199+
restored_count += 1
200+
if restored_count > 0:
201+
print(f"Restored {restored_count} backup file(s)")
202+
203+
card_count = len(changes_data)
204+
total_localizations = 0
205+
print(f"Applying changes to {card_count} card(s)...")
111206
for grp_id, new_values in changes_data.items():
112207

113208
localizations = new_values.pop("Localizations_enUS", None)
@@ -122,8 +217,12 @@ def change_grp_id(
122217
f"UPDATE Localizations_enUS SET Loc = ? WHERE LocId = ?",
123218
[(text, loc_id) for loc_id, text in localizations.items()],
124219
)
220+
total_localizations += len(localizations)
125221

126222
connection.commit()
223+
if total_localizations > 0:
224+
print(f"Updated {total_localizations} localization(s)")
225+
print("Changes applied successfully!")
127226

128227

129228
def save_loc_id_info(

0 commit comments

Comments
 (0)