예제 #1
0
def __fixActive(acti, lord):
    # filter plugins not present in modInfos - this will disable corrupted too!
    actiFiltered = [x for x in acti
                    if x in bosh.modInfos]  #preserve acti order
    _removed = set(acti) - set(actiFiltered)
    if _removed:  # take note as we may need to rewrite plugins txt
        msg = u'Those mods were present in plugins.txt but were not present ' \
              u'in Data/ directory or were corrupted: ' + _pl(_removed) + u'\n'
        bosh.modInfos.selectedBad = _removed
    else:
        msg = u''
    # again is below needed ? Apparently not with liblo 4 (acti is [Skyrim.esm,
    # Update.esm] on empty plugins.txt) - Keep it cause eventually (when liblo
    # is made to return actual contents of plugins.txt at all times) I may
    # need to correct this here
    addUpdateEsm = False
    if bush.game.fsName == 'Skyrim':
        skyrim = bolt.GPath(u'Skyrim.esm')
        if not skyrim in actiFiltered:
            actiFiltered.insert(0, skyrim)
            msg += u'Skyrim.esm not present in active mods' + u'\n'
        updateEsm = bolt.GPath(u'Update.esm')
        if updateEsm in lord and not updateEsm in actiFiltered:
            msg += (u'Update.esm not present in plugins.txt while present in '
                    u'Data folder') + u'\n'
            addUpdateEsm = True
    dexDict = {mod: index for index, mod in enumerate(lord)}
    # not needed for oblivion, for skyrim liblo will write plugins.txt in order
    # STILL restore for skyrim to warn on LO change
    if usingTxtFile():
        actiSorted = actiFiltered[:]
        actiSorted.sort(key=dexDict.__getitem__)  # all present in lord
        if actiFiltered != actiSorted:  # were mods in an order that disagrees with lord ?
            msg += (u'Plugins.txt order of plugins (%s) differs from current '
                    u'load order (%s)') % (_pl(actiFiltered), _pl(actiSorted))
    else:
        actiSorted = sorted(actiFiltered, key=dexDict.__getitem__)
    if addUpdateEsm:  # insert after the last master (as does liblo)
        actiSorted.insert(_indexFirstEsp(actiSorted), updateEsm)
    # check if we have more than 256 active mods
    if len(actiSorted) > 255:
        msg += u'Plugins.txt contains more than 255 plugins - the following ' \
               u'plugins will be deactivated: '
        bosh.modInfos.selectedExtra = actiSorted[255:]
        msg += _pl(bosh.modInfos.selectedExtra)
    acti[:] = actiSorted[:255]  # chop off extra
    if msg:
        ##: Notify user - maybe backup previous plugin txt ?
        bolt.deprint(u'Invalid Plugin txt corrected' + u'\n' + msg)
        SetActivePlugins(acti, lord, _fixed=True)
        return True  # changes, saved
    return False  # no changes, not saved
예제 #2
0
파일: games.py 프로젝트: Skarfoze/wrye-bash
def _parse_plugins_txt_(path, mod_infos, _star):
    """Parse loadorder.txt and plugins.txt files with or without stars.

    Return two lists which are identical except when _star is True, whereupon
    the second list is the load order while the first the active plugins. In
    all other cases use the first list, which is either the list of active
    mods (when parsing plugins.txt) or the load order (when parsing
    loadorder.txt)
    :type path: bolt.Path
    :type mod_infos: bosh.ModInfos
    :type _star: bool
    :rtype: (list[bolt.Path], list[bolt.Path])
    """
    with path.open('r') as ins:
        #--Load Files
        active, modnames = [], []
        for line in ins:
            # Oblivion/Skyrim saves the plugins.txt file in cp1252 format
            # It wont accept filenames in any other encoding
            modname = _re_plugins_txt_comment.sub('', line).strip()
            if not modname: continue
            # use raw strings below
            is_active = not _star or modname.startswith('*')
            if _star and is_active: modname = modname[1:]
            try:
                test = bolt.decode(modname, encoding='cp1252')
            except UnicodeError:
                bolt.deprint(u'%r failed to properly decode' % modname)
                continue
            if bolt.GPath(test) not in mod_infos:
                # The automatic encoding detector could have returned
                # an encoding it actually wasn't.  Luckily, we
                # have a way to double check: modInfos.data
                for encoding in bolt.encodingOrder:
                    try:
                        test2 = unicode(modname, encoding)
                        if bolt.GPath(test2) not in mod_infos:
                            continue
                        modname = bolt.GPath(test2)
                        break
                    except UnicodeError:
                        pass
                else:
                    modname = bolt.GPath(test)
            else:
                modname = bolt.GPath(test)
            modnames.append(modname)
            if is_active: active.append(modname)
    return active, modnames
예제 #3
0
 def restore_ini(self):
     if self._timestamped_old is self.__unset:
         return  # we did not move bash.ini
     if self._timestamped_old is not None:
         bolt.deprint(u'Restoring bash.ini')
         GPath(self._timestamped_old).copyTo(u'bash.ini')
     elif self._bash_ini_path:
         # remove bash.ini as it is the one from the backup
         bolt.GPath(u'bash.ini').remove()
예제 #4
0
파일: games.py 프로젝트: Skarfoze/wrye-bash
class SkyrimSE(AsteriskGame):

    must_be_active_if_present = (
        bolt.GPath(u'Update.esm'),
        bolt.GPath(u'Dawnguard.esm'),
        bolt.GPath(u'Hearthfires.esm'),
        bolt.GPath(u'Dragonborn.esm'),
    )
    _ccc_filename = u'Skyrim.ccc'

    @property
    def remove_from_plugins_txt(self):
        return {bolt.GPath(u'Skyrim.esm')} | set(
            self.must_be_active_if_present)

    __dlc_spacing = 60  # in seconds

    def _fixed_order_plugins(self):
        """Return the semi fixed plugins after pinning them in correct order by
        timestamping them."""
        # get existing
        add = [self.master_path]
        add.extend(x for x in self.must_be_active_if_present
                   if x in self.mod_infos)
        # rewrite mtimes
        master_mtime = self.mod_infos[self.master_path].mtime
        update = bolt.GPath(u'Update.esm')
        for dlc in add[1:]:
            if dlc == update:
                master_mtime = self.mod_infos[update].mtime
            else:
                master_mtime += self.__dlc_spacing
                dlc_mtime = self.mod_infos[dlc].mtime
                if dlc_mtime != master_mtime:
                    self.mod_infos[dlc].setmtime(master_mtime)
                    bolt.deprint(u'Restamped %s  from %s to %s' %
                                 (dlc, bolt.formatDate(dlc_mtime),
                                  bolt.formatDate(master_mtime)))
        return add
예제 #5
0
def exit_cleanup():
    # Cleanup temp installers directory
    import tempfile
    tmpDir = bolt.GPath(tempfile.tempdir)
    for file_ in tmpDir.list():
        if file_.cs.startswith(u'wryebash_'):
            file_ = tmpDir.join(file_)
            try:
                if file_.isdir():
                    file_.rmtree(safety=file_.stail)
                else:
                    file_.remove()
            except:
                pass
    # make sure to flush the BashBugDump.log
    if _bugdump_handle is not None:
        _bugdump_handle.close()
    if bass.is_restarting:
        cli = cmd_line = bass.sys_argv  # list of cli args
        try:
            if '--uac' in bass.sys_argv:  ##: mostly untested - needs revamp
                import win32api
                if is_standalone:
                    exe = cli[0]
                    cli = cli[1:]
                else:
                    exe = sys.executable
                exe = [u'%s', u'"%s"'][u' ' in exe] % exe
                cli = u' '.join([u'%s', u'"%s"'][u' ' in x] % x for x in cli)
                cmd_line = u'%s %s' % (exe, cli)
                win32api.ShellExecute(0, 'runas', exe, cli, None, True)
                return
            else:
                import subprocess
                cmd_line = (is_standalone and cli) or [sys.executable] + cli
                subprocess.Popen(
                    cmd_line,  # a list, no need to escape spaces
                    close_fds=True)
        except Exception as error:
            print error
            print u'Error Attempting to Restart Wrye Bash!'
            print u'cmd line: %s' % (cmd_line, )
            print
            raise
예제 #6
0
파일: games.py 프로젝트: Skarfoze/wrye-bash
class Fallout4(AsteriskGame):

    must_be_active_if_present = (
        bolt.GPath(u'DLCRobot.esm'),
        bolt.GPath(u'DLCworkshop01.esm'),
        bolt.GPath(u'DLCCoast.esm'),
        bolt.GPath(u'DLCWorkshop02.esm'),
        bolt.GPath(u'DLCWorkshop03.esm'),
        bolt.GPath(u'DLCNukaWorld.esm'),
        bolt.GPath(u'DLCUltraHighResolution.esm'),
    )
    _ccc_filename = u'Fallout4.ccc'

    @property
    def remove_from_plugins_txt(self):
        return {bolt.GPath(u'Fallout4.esm')} | set(
            self.must_be_active_if_present)
예제 #7
0
파일: games.py 프로젝트: Skarfoze/wrye-bash
 def _fixed_order_plugins(self):
     """Return the semi fixed plugins after pinning them in correct order by
     timestamping them."""
     # get existing
     add = [self.master_path]
     add.extend(x for x in self.must_be_active_if_present
                if x in self.mod_infos)
     # rewrite mtimes
     master_mtime = self.mod_infos[self.master_path].mtime
     update = bolt.GPath(u'Update.esm')
     for dlc in add[1:]:
         if dlc == update:
             master_mtime = self.mod_infos[update].mtime
         else:
             master_mtime += self.__dlc_spacing
             dlc_mtime = self.mod_infos[dlc].mtime
             if dlc_mtime != master_mtime:
                 self.mod_infos[dlc].setmtime(master_mtime)
                 bolt.deprint(u'Restamped %s  from %s to %s' %
                              (dlc, bolt.formatDate(dlc_mtime),
                               bolt.formatDate(master_mtime)))
     return add
예제 #8
0
파일: games.py 프로젝트: Skarfoze/wrye-bash
 def remove_from_plugins_txt(self):
     return {bolt.GPath(u'Skyrim.esm')} | set(
         self.must_be_active_if_present)
예제 #9
0
파일: games.py 프로젝트: Skarfoze/wrye-bash
class TextfileGame(Game):

    must_be_active_if_present = (bolt.GPath(u'Update.esm'), )

    def __init__(self, mod_infos, plugins_txt_path, loadorder_txt_path):
        super(TextfileGame, self).__init__(mod_infos, plugins_txt_path)
        self.loadorder_txt_path = loadorder_txt_path
        self.mtime_loadorder_txt = 0
        self.size_loadorder_txt = 0

    def load_order_changed(self):
        # if active changed externally refetch load order to check for desync
        return self.active_changed() or (self.loadorder_txt_path.exists() and (
            (self.size_loadorder_txt, self.mtime_loadorder_txt) !=
            self.loadorder_txt_path.size_mtime()))

    def __update_lo_cache_info(self):
        self.size_loadorder_txt, self.mtime_loadorder_txt = \
            self.loadorder_txt_path.size_mtime()

    @staticmethod
    def _must_update_active(deleted, reordered):
        return deleted or reordered

    def swap(self, old_path, new_path):
        super(TextfileGame, self).swap(old_path, new_path)
        # Save loadorder.txt inside the old (saves) directory
        if self.loadorder_txt_path.exists():
            self.loadorder_txt_path.copyTo(old_path.join(u'loadorder.txt'))
        # Move the new loadorder.txt here for use
        move = new_path.join(u'loadorder.txt')
        if move.exists():
            move.copyTo(self.loadorder_txt_path)
            self.loadorder_txt_path.mtime = time.time(
            )  # update mtime to trigger refresh

    # Abstract overrides ------------------------------------------------------
    def _fetch_load_order(self, cached_load_order, cached_active):
        """Read data from loadorder.txt file. If loadorder.txt does not
        exist create it and try reading plugins.txt so the load order of the
        user is preserved (note it will create the plugins.txt if not
        existing). Additional mods should be added by caller who should
        anyway call _fix_load_order. If cached_active is passed, the relative
        order of mods will be corrected to match their relative order in
        cached_active.
        :type cached_active: tuple[bolt.Path] | list[bolt.Path]"""
        if not self.loadorder_txt_path.exists():
            mods = cached_active or []
            if cached_active is not None and not self.plugins_txt_path.exists(
            ):
                self._write_plugins_txt(cached_active, cached_active)
                bolt.deprint(u'Created %s based on cached info' %
                             self.plugins_txt_path)
            elif cached_active is None and self.plugins_txt_path.exists():
                mods = self._fetch_active_plugins()  # will add Skyrim.esm
            self._persist_load_order(mods, mods)
            bolt.deprint(u'Created %s' % self.loadorder_txt_path)
            return mods
        #--Read file
        _acti, lo = self._parse_modfile(self.loadorder_txt_path)
        # handle desync with plugins txt
        if cached_active is not None:
            cached_active_copy = cached_active[:]
            active_in_lo = [x for x in lo if x in set(cached_active)]
            w = dict((x, i) for i, x in enumerate(lo))
            while active_in_lo:
                for i, (ordered, current) in enumerate(
                        zip(cached_active_copy, active_in_lo)):
                    if ordered != current:
                        for j, x in enumerate(active_in_lo[i:]):
                            if x == ordered: break
                            # x should be above ordered
                            to = w[ordered] + 1 + j
                            # make room
                            w = dict((x, i if i < to else i + 1)
                                     for x, i in w.iteritems())
                            w[x] = to  # bubble them up !
                        active_in_lo.remove(ordered)
                        cached_active_copy = cached_active_copy[i + 1:]
                        active_in_lo = active_in_lo[i:]
                        break
                else:
                    break
            fetched_lo = lo[:]
            lo.sort(key=w.get)
            if lo != fetched_lo:
                self._persist_load_order(lo, lo)
                bolt.deprint(u'Corrected %s (order of mods differed from '
                             u'their order in %s)' %
                             (self.loadorder_txt_path, self.plugins_txt_path))
        self.__update_lo_cache_info()
        return lo

    def _fetch_active_plugins(self):
        acti, _lo = self._parse_plugins_txt()
        if self.master_path in acti:
            acti.remove(self.master_path)
            self._write_plugins_txt(acti, acti)
            bolt.deprint(u'Removed %s from %s' %
                         (self.master_path, self.plugins_txt_path))
        acti.insert(0, self.master_path)
        return acti

    def _persist_load_order(self, lord, active):
        _write_plugins_txt_(self.loadorder_txt_path, lord, lord, _star=False)
        self.__update_lo_cache_info()

    def _persist_active_plugins(self, active,
                                lord):  # must chop off Skyrim.esm
        self._write_plugins_txt(active[1:], active[1:])

    def _persist_if_changed(self, active, lord, previous_active,
                            previous_lord):
        if previous_lord is None or previous_lord != lord:
            self._persist_load_order(lord, active)
        if previous_active is None or previous_active != active:
            self._persist_active_plugins(active, lord)

    # Validation overrides ----------------------------------------------------
    @staticmethod
    def _check_active_order(acti, lord):
        dex_dict = {mod: index for index, mod in enumerate(lord)}
        old = acti[:]
        acti.sort(key=dex_dict.__getitem__)  # all present in lord
        if acti != old:  # active mods order that disagrees with lord ?
            return (u'Active list order of plugins (%s) differs from supplied '
                    u'load order (%s)') % (_pl(old), _pl(acti))
        return u''