Skip to content

Commit

Permalink
309.1 Bug fixes for 309 [2021/06/09] [Infernio]
Browse files Browse the repository at this point in the history
This release fixes a few critical bugs and regressions that made their
way into 309.
  • Loading branch information
Infernio committed Jun 9, 2021
2 parents 820a0d4 + b079657 commit 2fa32e6
Show file tree
Hide file tree
Showing 17 changed files with 142 additions and 52 deletions.
5 changes: 3 additions & 2 deletions Mopy/Docs/Wrye Bash Advanced Readme.html
Expand Up @@ -8647,7 +8647,8 @@ <h3 class="clearfb" id="tools-checker">Plugin Checker <a class="back2top" href="
<li>Plugins with delinquent masters, i.e. masters that load after their
dependent plugins</li>
<li>Plugins with unknown header versions</li>
<li>For SSE and games based on it, plugins with Form Version <=43</li>
<li>For SSE and games based on it, plugins with Form Version &lt;44</li>
<li>For SSE and games based on it, weapon records with Form Version &lt;44</li>
<li>Cleaning information retrieved from LOOT</li>
<li>Deleted references</li>
<li>Deleted navmeshes</li>
Expand Down Expand Up @@ -8929,7 +8930,7 @@ <h3 id="international-format">Translator File Format <a class="back2top" href="#
</div>

<div id="footer">
<div id="version">Wrye Bash v309</div>
<div id="version">Wrye Bash v309.1</div>
<a href="Wrye Bash General Readme.html">General</a>&#160;&#x2726;&#160;Advanced&#160;&#x2726;&#160;<a href="Wrye Bash Technical Readme.html">Technical</a>&#160;&#x2726;&#160;<a href="Wrye Bash Version History.html">Versions</a>
<div id="oldie">Javascript disabled, menu and slideshows nonfunctional.</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion Mopy/Docs/Wrye Bash General Readme.html
Expand Up @@ -1999,7 +1999,7 @@ <h2 id="advanced">Advanced Readme Topics <a class="back2top" href="#contents">Ba
</div>

<div id="footer">
<div id="version">Wrye Bash v309</div>
<div id="version">Wrye Bash v309.1</div>
General&#160;&#x2726;&#160;<a href="Wrye Bash Advanced Readme.html">Advanced</a>&#160;&#x2726;&#160;<a href="Wrye Bash Technical Readme.html">Technical</a>&#160;&#x2726;&#160;<a href="Wrye Bash Version History.html">Versions</a>
<div id="oldie">Javascript disabled, menu and slideshows nonfunctional.</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion Mopy/Docs/Wrye Bash Technical Readme.html
Expand Up @@ -1193,7 +1193,7 @@ <h3 id="trusted-binaries-structure">Structure</h3>
</div>

<div id="footer">
<div id="version">Wrye Bash v309</div>
<div id="version">Wrye Bash v309.1</div>
<a href="Wrye Bash General Readme.html">General</a>&#160;&#x2726;&#160;<a href="Wrye Bash Advanced Readme.html">Advanced</a>&#160;&#x2726;&#160;Technical&#160;&#x2726;&#160;<a href="Wrye Bash Version History.html">Versions</a>
<div id="oldie">Javascript disabled, menu and slideshows nonfunctional.</div>
</div>
Expand Down
8 changes: 6 additions & 2 deletions Mopy/Docs/Wrye Bash Version History.html
Expand Up @@ -35,7 +35,11 @@

<p class="history-veranc">All versions by Wrye unless otherwise noted.

<h3>309 Python 3 preparation, pt. 2 [2021/05/21] [Infernio, Lojack, Utumno]</h3>
<h3>309.1 Bug fixes for 309 [2021/06/09] [Infernio]</h3>
<p>This release fixes a few critical bugs and regressions that made
their way into 309.</p>

<h3>309 Python 3 preparation, pt. 2 [2021/06/01] [Infernio, Lojack, Utumno]</h3>
<ul>
<li><a href="https://github.com/wrye-bash/wrye-bash/issues/597">#597</a>: Convert settings to VDATA3 [Infernio]</li>
<li><a href="https://github.com/wrye-bash/wrye-bash/issues/594">#594</a>: Support extracting .fomod files [Infernio]</li>
Expand Down Expand Up @@ -4304,7 +4308,7 @@ <h3>0.01 [2006/04/13]</h3>
</div>

<div id="footer">
<div id="version">Wrye Bash v309</div>
<div id="version">Wrye Bash v309.1</div>
<a href="Wrye Bash General Readme.html">General</a>&#160;&#x2726;&#160;<a href="Wrye Bash Advanced Readme.html">Advanced</a>&#160;&#x2726;&#160;<a href="Wrye Bash Technical Readme.html">Technical</a>&#160;&#x2726;&#160;Versions
<div id="oldie">Javascript disabled, menu and slideshows nonfunctional.</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions Mopy/Wrye Bash Debug.bat
Expand Up @@ -64,8 +64,8 @@ SET PYTHON=%PYPATH%pythonw.exe
:FOUNDPYTHON
ECHO Found Python at '%PYTHON%'
ECHO Found Python at '%PYTHON%' >%OUTFILE%
ECHO Launching Wrye Bash 309 in debug mode
ECHO Launching Wrye Bash 309 in debug mode >>%OUTFILE%
ECHO Launching Wrye Bash 309.1 in debug mode
ECHO Launching Wrye Bash 309.1 in debug mode >>%OUTFILE%
:: Line below won't do due to us redirecting stdout/err inside bash.py
SET PYTHONIOENCODING=UTF8
:: The following line checks if %OUTFILE% is writeable to determine if there is
Expand Down
10 changes: 6 additions & 4 deletions Mopy/bash/basher/saves_links.py
Expand Up @@ -902,7 +902,8 @@ def Execute(self):
for npc in modFile.tops[b'NPC_'].getActiveRecords():
fid = mapToOrdered(short_mapper(npc.fid), None)
if not fid: continue
npc_info[fid] = (npc.eid, npc.level, npc.calcMin, npc.calcMax, npc.flags.pcLevelOffset)
npc_info[fid] = (npc.eid, npc.level_offset, npc.calcMin,
npc.calcMax, npc.flags.pcLevelOffset)
#--Loop over savefiles
subProgress = SubProgress(progress,0.4,1.0,len(self.selected))
message = _(u'NPCs Releveled:')
Expand All @@ -918,17 +919,18 @@ def Execute(self):
enumerate(records):
orderedRecId = mapToOrdered(recId,None)
if recType_ != 35 or recId == 7 or orderedRecId not in npc_info: continue
(eid,level,calcMin,calcMax,pcLevelOffset) = npc_info[orderedRecId]
(eid, level_offset, calcMin, calcMax,
pcLevelOffset) = npc_info[orderedRecId]
npc = bosh._saves.SreNPC(recFlags, data_)
acbs = npc.acbs
if acbs and (
(acbs.level != level) or
(acbs.level_offset != level_offset) or
(acbs.calcMin != calcMin) or
(acbs.calcMax != calcMax) or
(acbs.flags.pcLevelOffset != pcLevelOffset)
):
acbs.flags.pcLevelOffset = pcLevelOffset
acbs.level = level
acbs.level_offset = level_offset
acbs.calcMin = calcMin
acbs.calcMax = calcMax
(recId,recType_,recFlags,version,data_) = saveFile.records[recNum]
Expand Down
2 changes: 1 addition & 1 deletion Mopy/bash/bass.py
Expand Up @@ -29,7 +29,7 @@

# The name of the locale we ended up with after localize.setup_locale()
active_locale = None
AppVersion = u'309' # must represent a valid float
AppVersion = u'309.1' # must represent a valid float
is_standalone = False # whether or not we're on standalone

#--Global dictionaries - do _not_ reassign !
Expand Down
7 changes: 5 additions & 2 deletions Mopy/bash/bolt.py
Expand Up @@ -239,8 +239,11 @@ def conv_obj(o, conv_enc=u'utf-8', __list_types=frozenset((list, set, tuple))):
by trying the specified encoding first, then falling back on the regular
'guess and try' logic."""
if isinstance(o, dict):
return type(o)(((conv_obj(k, conv_enc), conv_obj(v, conv_enc))
for k, v in o.iteritems()))
new_dict = o.copy()
new_dict.clear()
new_dict.update(((conv_obj(k, conv_enc), conv_obj(v, conv_enc))
for k, v in o.iteritems()))
return new_dict
elif type(o) in __list_types:
return type(o)(conv_obj(e, conv_enc) for e in o)
elif isinstance(o, bytes):
Expand Down
22 changes: 13 additions & 9 deletions Mopy/bash/bosh/_saves.py
Expand Up @@ -65,7 +65,7 @@ class SreNPC(object):

class ACBS(object):
__slots__ = (u'flags', u'baseSpell', u'fatigue', u'barterGold',
u'level', u'calcMin', u'calcMax')
u'level_offset', u'calcMin', u'calcMax')

def __init__(self, sre_flags=0, data_=None):
for attr in self.__slots__:
Expand All @@ -76,8 +76,8 @@ def getDefault(self,attr):
"""Returns a default version. Only supports acbs."""
assert attr == u'acbs'
acbs = SreNPC.ACBS()
(acbs.flags, acbs.baseSpell, acbs.fatigue, acbs.barterGold, acbs.level,
acbs.calcMin, acbs.calcMax) = (0,0,0,0,1,0,0)
(acbs.flags, acbs.baseSpell, acbs.fatigue, acbs.barterGold,
acbs.level_offset, acbs.calcMin, acbs.calcMax) = (0,0,0,0,1,0,0)
acbs.flags = MreRecord.type_class[b'NPC_']._flags(acbs.flags)
return acbs

Expand All @@ -94,7 +94,8 @@ def _unpack(fmt, fmt_siz):
if sr_flags.acbs:
acbs = self.acbs = SreNPC.ACBS()
(acbs.flags, acbs.baseSpell, acbs.fatigue, acbs.barterGold,
acbs.level, acbs.calcMin, acbs.calcMax) = _unpack(u'=I3Hh2H', 16)
acbs.level_offset, acbs.calcMin,
acbs.calcMax) = _unpack(u'=I3Hh2H', 16)
acbs.flags = MreRecord.type_class[b'NPC_']._flags(acbs.flags)
if sr_flags.factions:
num = unpack_short(ins)
Expand All @@ -120,7 +121,7 @@ def getFlags(self):
for attr in SreNPC.__slots__:
if attr != u'unused2':
setattr(sr_flags, attr, getattr(self, attr) is not None)
return int(sr_flags)
return sr_flags.dump()

def getData(self):
"""Returns self.data."""
Expand All @@ -136,8 +137,9 @@ def _pack(fmt, *args):
#--Acbs
if self.acbs is not None:
acbs = self.acbs
_pack(u'=I3Hh2H',int(acbs.flags), acbs.baseSpell, acbs.fatigue,
acbs.barterGold, acbs.level, acbs.calcMin, acbs.calcMax)
_pack(u'=I3Hh2H', acbs.flags.dump(), acbs.baseSpell, acbs.fatigue,
acbs.barterGold, acbs.level_offset, acbs.calcMin,
acbs.calcMax)
#--Factions
if self.factions is not None:
pack_short(out, len(self.factions))
Expand Down Expand Up @@ -376,10 +378,12 @@ def _pack(fmt, *args):
_pack(u'I',fidsPos)
out.seek(fidsPos)
_pack(u'I',len(self.fids))
self.fids.tofile(out)
# PY3: self.fids.tofile(out)
out.write(self.fids.tostring())
#--Worldspaces
_pack(u'I',len(self.worldSpaces))
self.worldSpaces.tofile(out)
# PY3: self.worldSpaces.tofile(out)
out.write(self.worldSpaces.tostring())
#--Done
progress(1.0,_(u'Writing complete.'))

Expand Down
25 changes: 13 additions & 12 deletions Mopy/bash/bosh/faces.py
Expand Up @@ -45,7 +45,7 @@ class PCFace(object):
__slots__ = (
u'face_masters', u'eid', u'pcName', u'race', u'gender', u'eye',
u'hair', u'hairLength', u'hairRed', u'hairBlue', u'hairGreen',
u'unused3', u'fggs_p', u'fgga_p', u'fgts_p', u'level',
u'unused3', u'fggs_p', u'fgga_p', u'fgts_p', u'level_offset',
u'attributes', u'skills', u'health', u'unused2', u'baseSpell',
u'fatigue', u'iclass', u'factions', u'modifiers', u'spells')

Expand All @@ -55,7 +55,8 @@ def __init__(self):
self.fggs_p = self.fgts_p = b'\x00'*4*50
self.fgga_p = b'\x00'*4*30
self.unused2 = null2
self.health = self.unused3 = self.baseSpell = self.fatigue = self.level = 0
self.health = self.unused3 = self.baseSpell = self.fatigue = 0
self.level_offset = 0
self.skills = self.attributes = self.iclass = None
self.factions = []
self.modifiers = []
Expand Down Expand Up @@ -132,9 +133,9 @@ def save_getCreatedFaces(saveFile,targetid=None):
face.face_masters = saveFile._masters
for a in (u'eid', u'race', u'eye', u'hair', u'hairLength',
u'hairRed', u'hairBlue', u'hairGreen', u'unused3',
u'fggs_p', u'fgga_p', u'fgts_p', u'level', u'skills',
u'health', u'unused2', u'baseSpell', u'fatigue',
u'attributes', u'iclass'):
u'fggs_p', u'fgga_p', u'fgts_p', u'level_offset',
u'skills', u'health', u'unused2', u'baseSpell',
u'fatigue', u'attributes', u'iclass'):
setattr(face, a, getattr(npc, a))
face.gender = (0,1)[npc.flags.female]
face.pcName = npc.full
Expand All @@ -153,7 +154,7 @@ def save_getChangedNpc(saveFile,fid,face=None):
npc = SreNPC(recFlags,data)
if npc.acbs:
face.gender = npc.acbs.flags.female
face.level = npc.acbs.level
face.level_offset = npc.acbs.level_offset
face.baseSpell = npc.acbs.baseSpell
face.fatigue = npc.acbs.fatigue
for a in (u'attributes', u'skills', u'health', u'unused2'):
Expand Down Expand Up @@ -267,7 +268,7 @@ def save_setCreatedFace(saveFile,targetid,face):
npc = SreNPC(recFlags,data)
if not npc.acbs: npc.acbs = npc.getDefault(u'acbs')
npc.acbs.flags.female = face.gender
npc.acbs.level = face.level
npc.acbs.level_offset = face.level_offset
npc.acbs.baseSpell = face.baseSpell
npc.acbs.fatigue = face.fatigue
npc.modifiers = face.modifiers[:]
Expand Down Expand Up @@ -360,7 +361,7 @@ def buffPackRef(oldFid,doPack=True):
npc.acbs.flags.female = face.gender
#--Stats
if pcf_flags.stats and npc.acbs:
npc.acbs.level = face.level
npc.acbs.level_offset = face.level_offset
npc.acbs.baseSpell = face.baseSpell
npc.acbs.fatigue = face.fatigue
npc.attributes = face.attributes
Expand Down Expand Up @@ -424,9 +425,9 @@ def mod_getFaces(modInfo):
face.face_masters = modFile.augmented_masters()
for a in (u'eid', u'race', u'eye', u'hair', u'hairLength',
u'hairRed', u'hairBlue', u'hairGreen', u'unused3',
u'fggs_p', u'fgga_p', u'fgts_p', u'level', u'skills',
u'health', u'unused2', u'baseSpell', u'fatigue',
u'attributes', u'iclass'):
u'fggs_p', u'fgga_p', u'fgts_p', u'level_offset',
u'skills', u'health', u'unused2', u'baseSpell',
u'fatigue', u'attributes', u'iclass'):
npc_val = getattr(npc, a)
if isinstance(npc_val, tuple): # Hacky check for FormIDs
npc_val = short_mapper(npc_val)
Expand Down Expand Up @@ -494,7 +495,7 @@ def mod_addFace(modInfo,face):
npc.fgga_p = face.fgga_p
npc.fgts_p = face.fgts_p
#--Stats
npc.level_offset = face.level
npc.level_offset = face.level_offset
npc.baseSpell = face.baseSpell
npc.fatigue = face.fatigue
if face.skills: npc.skills = face.skills
Expand Down
39 changes: 30 additions & 9 deletions Mopy/bash/bosh/loot_conditions.py
Expand Up @@ -152,8 +152,11 @@ def _fn_active(path_or_regex):
if is_regex(path_or_regex):
# Regex means we have to look at each active plugin - plugins can
# obviously only be in Data, no need to process the path here
file_regex = re.compile(path_or_regex)
return any(file_regex.match(x.s) for x in cached_active_tuple())
matches_regex = re.compile(path_or_regex).match
for p in cached_active_tuple():
if matches_regex(p.s):
return True
return False
else:
return cached_is_active(GPath(path_or_regex))

Expand Down Expand Up @@ -182,9 +185,12 @@ def _fn_file(path_or_regex):
# to check every step of the way
final_sep = path_or_regex.rfind(u'/')
# Note that we don't have to error check here due to the +1 offset
file_regex = re.compile(path_or_regex[final_sep + 1:])
matches_regex = re.compile(path_or_regex[final_sep + 1:]).match
parent_dir = _process_path(path_or_regex[:final_sep + 1])
return any(file_regex.match(f) for f in _iter_dir(parent_dir))
for f in _iter_dir(parent_dir):
if matches_regex(f):
return True
return False
else:
return _process_path(path_or_regex).exists()

Expand All @@ -207,20 +213,32 @@ def _fn_many(path_regex):
:param path_regex: The regex to check."""
# Same idea as in _fn_file
final_sep = path_regex.rfind(u'/')
file_regex = re.compile(path_regex[final_sep + 1:])
matches_regex = re.compile(path_regex[final_sep + 1:]).match
parent_dir = _process_path(path_regex[:final_sep + 1])
# Check if we have more than one matching file
return len([x for x in _iter_dir(parent_dir) if file_regex.match(x.s)]) > 1
matching_count = 0
for f in _iter_dir(parent_dir):
if matches_regex(f):
matching_count += 1
if matching_count > 1:
return True
return False

def _fn_many_active(path_regex):
# type: (unicode) -> bool
"""Takes a regex. Returns True iff more than 1 active plugin matches the
specified regex.
:param path_regex: The regex to check."""
file_regex = re.compile(path_regex)
matches_regex = re.compile(path_regex).match
# Check if we have more than one matching active plugin
return len([x for x in cached_active_tuple() if file_regex.match(x.s)]) > 1
matching_count = 0
for p in cached_active_tuple():
if matches_regex(p.s):
matching_count += 1
if matching_count > 1:
return True
return False

##: Maybe tweak the implementation to match LOOT's by adding some params to
# env.get_file_version?
Expand Down Expand Up @@ -313,7 +331,10 @@ def is_regex(string_to_check):
for the details.
:param string_to_check: The string to check for regex characters."""
return any(x in string_to_check for x in u':\\*?|')
for regex_char in r':\*?|':
if regex_char in string_to_check:
return True
return False

def _process_path(file_path):
# type: (unicode) -> Path
Expand Down

0 comments on commit 2fa32e6

Please sign in to comment.