Skip to content

Commit

Permalink
parser: improve repeat bank handling and add options
Browse files Browse the repository at this point in the history
  • Loading branch information
bnnm committed Nov 10, 2024
1 parent e457018 commit 1c68281
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 9 deletions.
10 changes: 10 additions & 0 deletions doc/WWISER.md
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,16 @@ Since only the bank version is needed, you can use `00000000 00000000 XXXXXXXX 0

Note that devs could instead encrypt the whole `.bnk` using standard encryption like AES, this is unrelated to Wwise and not covered by this program.

## LOADING REPEATED BANKS
By default *wwiser* allows loading the same bank ID+lang in different dirs multiple times, or the same bank in the same dir with different names (same bank in the same dir is ignored). Real *Wwise* games probably don't do that, plus the engine should ignore repeated IDs, but *wwiser* has some leniency for usability or odd games.

The most notable case is game updates, where newer `.bnk` may be put in a separate dir or `.pck`. Manually loading newer banks is time consuming, so when loading multiple dirs *wwiser* just accepts everything. This works fine when dumping contents or wwnames (dupes are taken into account), but affects TXTP generation.

Repeated banks may have the same IDs but different contents. For example a *music-switch* object in v1.0 may have 10 cases (10 `.txtp`), while v1.1 has 12 cases (12 `.txtp`), but the other way around could be possible. *wwiser* can only use either v1.0 or v1.1, but can't guess which *music-switch* is the newer/better one.

By default it favors bigger banks first (usually v1.1) while still allowing both. This can be overridden to ignore repeated banks (first only, last only, biggest, etc) for fine tuning. In comple cases you may need to experiment and see if other mores make more `.txtp`. There is nothing stopping tricky devs of reusing a bank ID with completely different contents though, so use with care.


## KNOWN ISSUES
Bank format may change a bit between major Wwise SDK versions, adding new features or moving fields around. *wwiser* should handle almost all but there are bugs left:
- earliest versions used in *Shadowrun (X360)* and *Too Human (X360)* partially supported
Expand Down
4 changes: 2 additions & 2 deletions wwiser/parser/wio.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ def skip(self, bytes):
def current(self):
return self.file.tell()

#def size(self):
# return self.size
def get_size(self):
return self.size

def guess_endian32(self, offset):
current = self.file.tell()
Expand Down
98 changes: 93 additions & 5 deletions wwiser/parser/wparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3795,6 +3795,26 @@ def parse_chunk(obj):
# #############################################################################

class Parser(object):
# when loading multiple banks
MULTIBANK_AUTO = 'auto'
MULTIBANK_MANUAL = 'manual-all'
MULTIBANK_FIRST = 'first'
MULTIBANK_LAST = 'last'
MULTIBANK_BIGGEST = 'biggest'
MULTIBANK_BIGGEST_LAST = 'biggest+last'
MULTIBANK_SMALLEST = 'smallest'

#MULTIBANK_NEWEST = 6 # latest timestamp (useful?)
MULTIBANK_MODES = [
MULTIBANK_AUTO,
MULTIBANK_MANUAL,
MULTIBANK_FIRST,
MULTIBANK_LAST,
MULTIBANK_BIGGEST,
MULTIBANK_BIGGEST_LAST,
MULTIBANK_SMALLEST,
]

def __init__(self):
#self._ignore_version = ignore_version
self._banks = {}
Expand Down Expand Up @@ -3958,28 +3978,96 @@ def _process(self, r, filename):
if self._names:
bank.set_names(self._names)

self._banks[filename] = bank
root = bank.get_root()
sid = root.get_id()
lang = root.get_lang()
size = r.get_size()

self._banks[filename] = (bank, sid, lang, size)
return None

def get_banks(self, mode=None):
if not mode:
mode = self.MULTIBANK_AUTO

if mode not in self.MULTIBANK_MODES:
logging.warning("parser: WARNING, unknown repeat mode '%s'" % (mode))

# as loaded (MULTIBANK_ALLOW_MANUAL)
items = self._banks.values()

done = {}
banks = []
for bank, version, lang, size in items:

key = (version, lang)
if key not in done:
# not a dupe = always include
done[key] = (bank, size)
banks.append(bank)
continue

# handle dupe
old_bank, old_size = done.get(key)
index = banks.index(old_bank)


# allow as loaded
if mode == self.MULTIBANK_MANUAL:
banks.append(bank)

# allow, bigger first
if mode == self.MULTIBANK_AUTO:
if size > old_size:
banks.insert(index, bank) #before
else:
banks.append(bank) #after (tail)

# ignore current
if mode == self.MULTIBANK_FIRST:
pass

# overwrite old
if mode == self.MULTIBANK_LAST:
banks[index] = bank
done[key] = (bank, size)

# favor bigger
if mode == self.MULTIBANK_BIGGEST:
if size > old_size:
banks[index] = bank #overwrite
done[key] = (bank, size)

# favor bigger, or last (same size = overwrite)
# (generally useless except when fine-tuning which clone banks are preferred, for -fc + multiple updates)
if mode == self.MULTIBANK_BIGGEST_LAST:
if size >= old_size:
banks[index] = bank #overwrite
done[key] = (bank, size)

# favor smaller
if mode == self.MULTIBANK_SMALLEST:
if size < old_size:
banks[index] = bank #overwrite
done[key] = (bank, size)

def get_banks(self):
banks = list(self._banks.values())
return banks

def get_filenames(self):
return list(self._banks.keys())

def set_names(self, names):
self._names = names
for bank in self._banks.values():
for items in self._banks.values():
bank = items[0]
bank.set_names(names)

#def set_ignore_version(self, value):
# self._ignore_version = value

def unload_bank(self, filename):
if filename not in self._banks:
logging.warn("parser: can't unload " + filename)
logging.warning("parser: can't unload " + filename)
return

logging.info("parser: unloading " + filename)
Expand Down
3 changes: 2 additions & 1 deletion wwiser/wcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def _parse_init(self):
p.add_argument('-vp', '--viewer-port', help="Set the viewer port", metavar='PORT', default=wview.DEFAULT_PORT)
#p.add_argument('-iv', '--ignore-version', help="Ignore bank version check", action='store_true')
p.add_argument('-sl', '--save-lst', help="Clean wwnames.txt and include missing hashnames\n(needs dump set)", action='store_true')
p.add_argument('-br', '--bank-repeat', help="Override repeated banks handling:\n manual / first / last / smallest / biggest / biggest+last")

p = parser.add_argument_group('txtp options')
p.add_argument('-g', '--txtp', help="Generate TXTP", action='store_true')
Expand Down Expand Up @@ -268,7 +269,7 @@ def _execute(self, args, filenames):
parser = wparser.Parser()
#parser.set_ignore_version(args.ignore_version)
parser.parse_banks(filenames)
banks = parser.get_banks()
banks = parser.get_banks(args.bank_repeat)


# load names
Expand Down
14 changes: 13 additions & 1 deletion wwiser/wgui.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,15 @@ def _setup_options(self):
frame.grid_columnconfigure(0, minsize=80) #weight 2 = x2 of others
row = 0

cmb = self._cmb('bank_repeat', frame, 'Repeats:', 'How different banks with same ID + language (such as updates) are handled')
cmb[0].grid(row=row, column=0, sticky=tk.E)
cmb[1].grid(row=row, column=1, sticky=tk.W)
cmb[2].grid(row=row, column=2, sticky=tk.W)

items = self._fields["bank_repeat"]
items['values'] = [''] + wparser.Parser.MULTIBANK_MODES #self.parser.MULTIBANK_MODES

row += 1

cmb = self._cmb('txtp_lang', frame, 'Language:', 'Current language (select when loading multiple localized banks or set to SFX to skip all localized banks)')
cmb[0].grid(row=row, column=0, sticky=tk.E)
Expand Down Expand Up @@ -855,8 +864,11 @@ def _process(self, **args):
#raise

def _process_main(self, make_txtp=False, make_tags=False, make_clean=False):
repeat_mode = self._get_list('bank_repeat')
if repeat_mode: #TODO: better way to handle
repeat_mode = repeat_mode[0]

banks = self.parser.get_banks()
banks = self.parser.get_banks(repeat_mode)
if not banks:
messagebox.showerror('Error', 'Load one or more banks')
return
Expand Down

0 comments on commit 1c68281

Please sign in to comment.