@@ -2217,19 +2217,22 @@ def _convert_hud_dds_to_tex(self, base_dir: Path, champion: str, main_bin_path:
22172217 # Hash storage (minimal version of LtMAO hash_helper.Storage)
22182218 class _HashStorage :
22192219 hashtables = {}
2220-
2220+
22212221 @staticmethod
22222222 def read_all_hashes (hashes_dir : Path ):
22232223 """Read all hashes from hashes/ directory."""
22242224 _HashStorage = WizardApp ._HashStorage
22252225 _HashStorage .hashtables = {}
22262226 bin_files = ['hashes.binentries.txt' , 'hashes.binhashes.txt' , 'hashes.bintypes.txt' , 'hashes.binfields.txt' ]
22272227 wad_files = ['hashes.game.txt' , 'hashes.lcu.txt' ]
2228+ print (f"[DEBUG] read_all_hashes called with: { hashes_dir } " )
22282229 for fname in bin_files + wad_files :
22292230 _HashStorage .hashtables [fname ] = {}
22302231 fpath = hashes_dir / fname
22312232 if not fpath .is_file ():
2233+ print (f"[DEBUG] Hash file NOT FOUND: { fpath } " )
22322234 continue
2235+ print (f"[DEBUG] Loading hash file: { fpath } " )
22332236 sep = 16 if fname in wad_files else 8
22342237 with open (fpath , 'r' , encoding = 'utf-8' ) as f :
22352238 for line in f :
@@ -2238,6 +2241,7 @@ def read_all_hashes(hashes_dir: Path):
22382241 key = line [:sep ]
22392242 val = line [sep + 1 :- 1 ]
22402243 _HashStorage .hashtables [fname ][key ] = val
2244+ print (f"[DEBUG] Loaded { len (_HashStorage .hashtables [fname ])} entries from { fname } " )
22412245
22422246 @staticmethod
22432247 def free_all_hashes ():
@@ -3048,7 +3052,16 @@ def _repath_fresh(self, fresh_unpack: Path) -> bool:
30483052 # Load hashes before starting (from AppData, not bundled)
30493053 hashes_dir = self ._hash_dir ()
30503054 self ._set_status ("Loading hash tables..." )
3055+ print (f"[DEBUG] Loading hashtables from: { hashes_dir } " )
3056+ print (f"[DEBUG] hashes_dir exists: { hashes_dir .exists ()} " )
30513057 WizardApp ._HashStorage .read_all_hashes (hashes_dir )
3058+ # Debug: verify hashtables loaded
3059+ print (f"[DEBUG] After read_all_hashes: { len (WizardApp ._HashStorage .hashtables )} keys" )
3060+ for fname , entries in WizardApp ._HashStorage .hashtables .items ():
3061+ print (f"[DEBUG] { fname } : { len (entries )} entries" )
3062+ if 'hashes.bintypes.txt' in WizardApp ._HashStorage .hashtables :
3063+ types_count = len (WizardApp ._HashStorage .hashtables ['hashes.bintypes.txt' ])
3064+ print (f"[DEBUG] bintypes loaded with { types_count } entries" )
30523065
30533066 # Get custom prefix or generate random one
30543067 prefix = self .custom_prefix .get ().strip ()
@@ -3240,7 +3253,21 @@ def _repath_fresh(self, fresh_unpack: Path) -> bool:
32403253 self ._set_status ("Repathing (ignore missing, combine linked)..." )
32413254 try :
32423255 bum .bum (str (output_dir ), ignore_missing = True , combine_linked = True )
3243-
3256+
3257+ # Debug: verify hashtables still exist after bum.bum()
3258+ print (f"[DEBUG] After bum.bum(): hashtables has { len (WizardApp ._HashStorage .hashtables )} keys" )
3259+ if 'hashes.bintypes.txt' in WizardApp ._HashStorage .hashtables :
3260+ print (f"[DEBUG] bintypes still has { len (WizardApp ._HashStorage .hashtables ['hashes.bintypes.txt' ])} entries" )
3261+ else :
3262+ print ("[DEBUG] WARNING: bintypes MISSING after bum.bum()!" )
3263+
3264+ # Separate VFX entries into a separate BIN file in the data folder
3265+ self ._set_status ("Separating VFX entries into separate BIN..." )
3266+ vfx_count = self ._separate_vfx_entries (output_dir , champ )
3267+ if vfx_count > 0 :
3268+ self ._set_status (f"Separated { vfx_count } VFX entries into data folder" )
3269+ print (f"[DEBUG] Separated { vfx_count } VFX entries into data folder" )
3270+
32443271 # Fix HUD paths in repathed BIN files (change .dds to .tex)
32453272 self ._set_status ("Fixing HUD paths in repathed BIN files..." )
32463273 bin_fixed_count = 0
@@ -3318,6 +3345,120 @@ def _repath_fresh(self, fresh_unpack: Path) -> bool:
33183345 WizardApp ._HashStorage .free_all_hashes ()
33193346 return False
33203347
3348+ def _separate_vfx_entries (self , repathed_dir : Path , champ : str ) -> int :
3349+ """
3350+ Separate VFX entries from main BIN (after combine_linked merged everything).
3351+ - VFX entries go to data/{champ}_vfx.bin
3352+ - Non-VFX entries stay in main BIN
3353+ Returns the number of VFX entries separated.
3354+ """
3355+ try :
3356+ print (f"[DEBUG] Separating VFX entries from { repathed_dir } " )
3357+
3358+ # Check hashtables status
3359+ print (f"[DEBUG] Hashtables has { len (WizardApp ._HashStorage .hashtables )} keys" )
3360+ if 'hashes.bintypes.txt' in WizardApp ._HashStorage .hashtables :
3361+ print (f"[DEBUG] hashes.bintypes.txt has { len (WizardApp ._HashStorage .hashtables ['hashes.bintypes.txt' ])} entries" )
3362+ else :
3363+ print ("[DEBUG] hashes.bintypes.txt NOT in hashtables!" )
3364+
3365+ # Build type hash lookup from hashes.bintypes.txt
3366+ bin_type_hashes = {}
3367+ if 'hashes.bintypes.txt' in WizardApp ._HashStorage .hashtables :
3368+ for hex_hash , raw_name in WizardApp ._HashStorage .hashtables ['hashes.bintypes.txt' ].items ():
3369+ bin_type_hashes [raw_name .strip ()] = hex_hash
3370+
3371+ vfx_type_hash = bin_type_hashes .get ('VfxSystemDefinitionData' )
3372+ if not vfx_type_hash :
3373+ print (f"[DEBUG] VfxSystemDefinitionData not found. bin_type_hashes has { len (bin_type_hashes )} entries" )
3374+ if len (bin_type_hashes ) > 0 :
3375+ print (f"[DEBUG] Sample entries: { list (bin_type_hashes .items ())[:3 ]} " )
3376+ return 0
3377+
3378+ print (f"[DEBUG] VfxSystemDefinitionData hash: { vfx_type_hash } " )
3379+
3380+ data_dir = repathed_dir / 'data'
3381+ characters_dir = data_dir / 'characters'
3382+
3383+ # Find ALL skin BINs (in data/characters/*/skins/) - including subfolders like aniviaegg
3384+ all_bin_paths = []
3385+ if characters_dir .exists ():
3386+ for bin_file in characters_dir .rglob ("*.bin" ):
3387+ if self ._is_valid_binary_bin (bin_file ):
3388+ all_bin_paths .append (bin_file )
3389+
3390+ if not all_bin_paths :
3391+ print ("[DEBUG] No skin BINs found in characters folder" )
3392+ return 0
3393+
3394+ print (f"[DEBUG] Found { len (all_bin_paths )} BIN file(s) to process" )
3395+ for bp in all_bin_paths :
3396+ print (f"[DEBUG] - { bp .relative_to (repathed_dir )} " )
3397+
3398+ # Collect ALL VFX entries from ALL BINs, track existing hashes to avoid duplicates
3399+ all_vfx_entries = []
3400+ existing_vfx_hashes = set ()
3401+ total_vfx_count = 0
3402+
3403+ for bin_path in all_bin_paths :
3404+ main_bin = pyRitoFile .bin .BIN ().read (str (bin_path ))
3405+ print (f"[DEBUG] Processing { bin_path .name } : { len (main_bin .entries )} entries" )
3406+
3407+ # Separate VFX from non-VFX
3408+ vfx_entries = []
3409+ non_vfx_entries = []
3410+
3411+ for entry in main_bin .entries :
3412+ if entry .type == vfx_type_hash :
3413+ vfx_entries .append (entry )
3414+ # Only add to combined list if not already seen
3415+ if entry .hash not in existing_vfx_hashes :
3416+ all_vfx_entries .append (entry )
3417+ existing_vfx_hashes .add (entry .hash )
3418+ else :
3419+ non_vfx_entries .append (entry )
3420+
3421+ print (f"[DEBUG] Separated: { len (vfx_entries )} VFX, { len (non_vfx_entries )} non-VFX" )
3422+ total_vfx_count += len (vfx_entries )
3423+
3424+ if vfx_entries :
3425+ # Update this BIN with only non-VFX entries + link to VFX bin
3426+ main_bin .entries = non_vfx_entries
3427+ vfx_bin_name = f"{ champ } _vfx.bin"
3428+ vfx_link_path = f"data/{ vfx_bin_name } "
3429+ if vfx_link_path not in main_bin .links :
3430+ main_bin .links .append (vfx_link_path )
3431+ main_bin .write (str (bin_path ))
3432+ print (f"[DEBUG] Updated { bin_path .name } with { len (non_vfx_entries )} non-VFX entries" )
3433+
3434+ if not all_vfx_entries :
3435+ print ("[DEBUG] No VFX entries found in any BIN" )
3436+ return 0
3437+
3438+ # Create ONE combined VFX BIN in data/ folder
3439+ vfx_bin_name = f"{ champ } _vfx.bin"
3440+ vfx_bin_path = data_dir / vfx_bin_name
3441+ data_dir .mkdir (parents = True , exist_ok = True )
3442+
3443+ vfx_bin = pyRitoFile .bin .BIN (
3444+ signature = 'PROP' ,
3445+ version = 3 ,
3446+ is_patch = False ,
3447+ links = [],
3448+ entries = all_vfx_entries ,
3449+ patches = []
3450+ )
3451+ vfx_bin .write (str (vfx_bin_path ))
3452+ print (f"[DEBUG] Created: data/{ vfx_bin_name } with { len (all_vfx_entries )} unique VFX entries (from { total_vfx_count } total)" )
3453+
3454+ return len (all_vfx_entries )
3455+
3456+ except Exception as e :
3457+ print (f"[DEBUG] Error in _separate_vfx_entries: { e } " )
3458+ import traceback
3459+ traceback .print_exc ()
3460+ return 0
3461+
33213462 def _package_repathed (self ) -> bool :
33223463 try :
33233464 work_root = self ._work_root ()
@@ -5460,8 +5601,7 @@ def _repair_bin_file(self, bin_path: Path, fresh_unpack: Path = None):
54605601 entry .data .append (hb )
54615602 # write back
54625603 b .write (str (bin_path ))
5463-
5464- WizardApp ._HashStorage .free_all_hashes ()
5604+ # NOTE: Don't free hashtables here - caller manages the lifecycle
54655605
54665606 def _pack_wad (self , raw_dir : Path , wad_file : Path ) -> None :
54675607 # Local pack using pyRitoFile.wad (mirrors LtMAO.wad_tool.pack)
0 commit comments