Esempio n. 1
0
class TutorialLoader(object):
    lobbyContext = dependency.descriptor(ILobbyContext)

    def __init__(self):
        super(TutorialLoader, self).__init__()
        self.__loggedDBIDs = set()
        self.__afterBattle = False
        self.__tutorial = None
        self.__dispatcher = None
        self.__restoreID = None
        self.__settings = _settings.createSettingsCollection()
        self.__hintsManager = None
        self.__listener = None
        return

    def init(self):
        """
        Initialization of tutorial loader.
        """
        self.__listener = AppLoaderListener()
        self.__listener.start(weakref.proxy(self))

    def fini(self):
        """
        Tutorial loader finalizes work: stops training process, saving state,
        # if tutorial is running.
        """
        if self.__listener is not None:
            self.__listener.stop()
        if self.__hintsManager is not None:
            self.__hintsManager.stop()
        if self.__dispatcher is not None:
            self.__dispatcher.stop()
        if self.__tutorial is not None:
            self.__tutorial.onStopped -= self.__onTutorialStopped
            self.__tutorial.stop()
        self.__loggedDBIDs.clear()
        self.__settings.clear()
        return

    @property
    def tutorial(self):
        return self.__tutorial

    @property
    def tutorialID(self):
        result = ''
        if self.__tutorial is not None:
            result = self.__tutorial.getID()
        return result

    @property
    def isRunning(self):
        result = False
        if self.__tutorial is not None:
            result = not self.__tutorial.isStopped()
        return result

    def isTutorialStopped(self):
        result = True
        if self.__tutorial is not None:
            result = self.__tutorial.isStopped()
        return result

    def run(self, settingsID, state=None):
        """
        Try to run tutorial.
        
        :param settingsID: string containing settings ID of required tutorial.
        :param state: dict(
                reloadIfRun : bool - just reload tutorial if it's running,
                afterBattle : bool - tutorial should load scenario that is played
                    when player left battle,
                initialChapter : str - name of initial chapter,
                restoreIfRun: bool - current tutorial will be started again
                    if required tutorial stop.
                globalFlags : dict(GLOBAL_FLAG.* : bool,)
            )
        :return: True if tutorial has started, otherwise - False.
        """
        settings = self.__settings.getSettings(settingsID)
        if settings is None:
            LOG_ERROR('Can not find settings', settingsID)
            return False
        else:
            if state is None:
                state = {}
            reloadIfRun = state.pop('reloadIfRun', False)
            restoreIfRun = state.pop('restoreIfRun', False)
            isStopForced = state.pop('isStopForced', False)
            if self.__tutorial is not None and not self.__tutorial.isStopped():
                isCurrent = self.__tutorial.getID() == settings.id
                if reloadIfRun and isCurrent:
                    if isStopForced:
                        self.__doStop()
                    else:
                        GlobalStorage.setFlags(state.get('globalFlags', {}))
                        self.__tutorial.invalidateFlags()
                        return True
                elif restoreIfRun and not isCurrent:
                    self.__restoreID = self.__tutorial.getID()
                    self.__doStop()
                else:
                    LOG_ERROR('Tutorial already is running',
                              self.__tutorial.getID())
                    return False
            state.setdefault('isAfterBattle', self.__afterBattle)
            state.setdefault('restart', True)
            state['byRequest'] = True
            result = self.__doRun(settings, state)
            if not result:
                self.__restoreID = None
            return result

    def stop(self, restore=True):
        self.__doStop()
        self.__doStopHints()
        if restore:
            self.__doRestore()
        else:
            self.__restoreID = None
        return

    def refuse(self):
        if self.__tutorial is not None:
            self.__tutorial.refuse()
        return

    def goToLobby(self):
        databaseID = account_helpers.getAccountDatabaseID()
        raise databaseID or AssertionError(
            'Acoount database ID is not defined')
        isFirstStart = databaseID not in self.__loggedDBIDs
        self.__loggedDBIDs.add(databaseID)
        state = {
            'isFirstStart': isFirstStart,
            'isAfterBattle': self.__afterBattle
        }
        self.__setDispatcher(_LOBBY_DISPATCHER)
        self.__restoreID = _SETTINGS.QUESTS.id
        self.__doAutoRun((_SETTINGS.OFFBATTLE, _SETTINGS.QUESTS), state)
        self.__hintsManager = HintsManager()
        self.__hintsManager.start()

    def stopOnceOnlyHint(self, itemID):
        if self.__hintsManager is not None:
            self.__hintsManager.stopOnceOnlyHint(itemID)
        return

    def leaveLobby(self):
        self.stop(restore=False)

    def goToBattleLoading(self):
        self.__afterBattle = True
        self.__doClear()
        self.__doAutoRun((_SETTINGS.BATTLE_V2, _SETTINGS.BATTLE_QUESTS),
                         {'canResolveChapterOnStart': False})

    def goToBattle(self):
        if self.__tutorial is not None:
            self.__tutorial.startBattle()
        return

    def leaveBattle(self):
        self.stop(restore=False)

    def goToLogin(self):
        self.__afterBattle = False
        self.__doClear()

    def __doAutoRun(self, seq, state):
        for settings in seq:
            if self.__doRun(settings, state):
                return

    def __doRun(self, settings, state):
        if not settings.enabled:
            return False
        else:
            reqs = _settings.createTutorialElement(settings.reqs)
            if not reqs.isEnabled():
                return False
            descriptor = loadDescriptorData(settings, settings.exParsers)
            if descriptor is None:
                LOG_ERROR('Descriptor is not valid. Tutorial is not available',
                          settings)
                return False
            cache = _cache.TutorialCache(BigWorld.player().name)
            cache.read()
            cache.setSpace(settings.space)
            if state.get('byRequest', False):
                cache.setRefused(False)
            runCtx = RunCtx(cache, **state)
            reqs.prepare(runCtx)
            if not reqs.process(descriptor, runCtx):
                return False
            self.__doStop()
            if self.__dispatcher is None:
                self.__setDispatcher(settings.dispatcher)
            tutorial = core.Tutorial(settings, descriptor)
            result = tutorial.run(weakref.proxy(self.__dispatcher), runCtx)
            if result:
                self.__tutorial = tutorial
                self.__tutorial.onStopped += self.__onTutorialStopped
            return result

    def __doStop(self):
        if self.__tutorial is not None:
            self.__tutorial.onStopped -= self.__onTutorialStopped
            self.__tutorial.stop()
            self.__tutorial = None
        return

    def __doStopHints(self):
        if self.__hintsManager is not None:
            self.__hintsManager.stop()
        return

    def __doClear(self):
        self.__restoreID = None
        self.__doStop()
        self.__doStopHints()
        if self.__dispatcher is not None:
            self.__dispatcher.stop()
            self.__dispatcher = None
        return

    def __doRestore(self):
        if self.__restoreID is not None:
            settingsID, self.__restoreID = self.__restoreID, None
            LOG_DEBUG('Restore tutorial', settingsID)
            self.run(settingsID)
        return

    def __setDispatcher(self, settings):
        if self.__dispatcher is not None:
            self.__dispatcher.stop()
            self.__dispatcher = None
        self.__dispatcher = _settings.createTutorialElement(settings)
        self.__dispatcher.start(weakref.proxy(self))
        return

    def __onTutorialStopped(self):
        """
        Listener for event Tutorial.onStopped.
        """
        self.__doRestore()
class TutorialLoader(object):
    lobbyContext = dependency.descriptor(ILobbyContext)

    def __init__(self):
        super(TutorialLoader, self).__init__()
        self.__loggedDBIDs = set()
        self.__afterBattle = False
        self.__tutorial = None
        self.__dispatcher = None
        self.__restoreID = None
        self.__settings = _settings.createSettingsCollection()
        self.__hintsManager = None
        self.__listener = None
        return

    def init(self):
        self.__listener = AppLoaderListener()
        self.__listener.start(weakref.proxy(self))

    def fini(self):
        if self.__listener is not None:
            self.__listener.stop()
        if self.__hintsManager is not None:
            self.__hintsManager.stop()
        if self.__dispatcher is not None:
            self.__dispatcher.stop()
        if self.__tutorial is not None:
            self.__tutorial.onStopped -= self.__onTutorialStopped
            self.__tutorial.stop()
        self.__loggedDBIDs.clear()
        self.__settings.clear()
        return

    @property
    def tutorial(self):
        return self.__tutorial

    @property
    def tutorialID(self):
        result = ''
        if self.__tutorial is not None:
            result = self.__tutorial.getID()
        return result

    @property
    def isRunning(self):
        result = False
        if self.__tutorial is not None:
            result = not self.__tutorial.isStopped()
        return result

    def isTutorialStopped(self):
        result = True
        if self.__tutorial is not None:
            result = self.__tutorial.isStopped()
        return result

    def run(self, settingsID, state=None):
        settings = self.__settings.getSettings(settingsID)
        if settings is None:
            LOG_ERROR('Can not find settings', settingsID)
            return False
        else:
            if state is None:
                state = {}
            reloadIfRun = state.pop('reloadIfRun', False)
            restoreIfRun = state.pop('restoreIfRun', False)
            isStopForced = state.pop('isStopForced', False)
            if self.__tutorial is not None and not self.__tutorial.isStopped():
                isCurrent = self.__tutorial.getID() == settings.id
                if reloadIfRun and isCurrent:
                    if isStopForced:
                        self.__doStop()
                    else:
                        GlobalStorage.setFlags(state.get('globalFlags', {}))
                        LOG_DEBUG('invalidateFlags from TutorialLoader.run')
                        self.__tutorial.invalidateFlags()
                        return True
                elif restoreIfRun and not isCurrent:
                    self.__restoreID = self.__tutorial.getID()
                    self.__doStop()
                else:
                    LOG_ERROR('Tutorial already is running',
                              self.__tutorial.getID())
                    return False
            state.setdefault('isAfterBattle', self.__afterBattle)
            state.setdefault('restart', True)
            state['byRequest'] = True
            result = self.__doRun(settings, state)
            if not result:
                self.__restoreID = None
            return result

    def stop(self, restore=True):
        self.__doStop()
        self.__doStopHints()
        if restore:
            self.__doRestore()
        else:
            self.__restoreID = None
        return

    def refuse(self):
        if self.__tutorial is not None:
            self.__tutorial.refuse()
        return

    def goToLobby(self):
        databaseID = account_helpers.getAccountDatabaseID()
        if not databaseID:
            raise SoftException('Acoount database ID is not defined')
        isFirstStart = databaseID not in self.__loggedDBIDs
        self.__loggedDBIDs.add(databaseID)
        state = {
            'isFirstStart': isFirstStart,
            'isAfterBattle': self.__afterBattle
        }
        self.__setDispatcher(_LOBBY_DISPATCHER)
        self.__restoreID = _SETTINGS.QUESTS.id
        bootcampController = dependency.instance(IBootcampController)
        isInBootcampAccount = bootcampController.isInBootcampAccount()
        if isInBootcampAccount:
            selectedSettings = self.__doAutoRun(
                (_SETTINGS.OFFBATTLE, _SETTINGS.QUESTS,
                 _SETTINGS.BOOTCAMP_LOBBY), state)
        else:
            selectedSettings = None
        if selectedSettings is None or selectedSettings.hintsEnabled:
            self.__hintsManager = HintsManager()
            self.__hintsManager.start()
        return

    def stopOnceOnlyHint(self, itemID):
        if self.__hintsManager is not None:
            self.__hintsManager.stopOnceOnlyHint(itemID)
        return

    def leaveLobby(self):
        self.stop(restore=False)

    def goToBattleLoading(self):
        self.__afterBattle = True
        self.__doClear()
        self.__doAutoRun((_SETTINGS.BATTLE_V2, _SETTINGS.BATTLE_QUESTS),
                         {'canResolveChapterOnStart': False})

    def goToBattle(self):
        if self.__tutorial is not None:
            self.__tutorial.startBattle()
        return

    def leaveBattle(self):
        self.stop(restore=False)

    def goToLogin(self):
        self.__afterBattle = False
        self.__doClear()

    def __doAutoRun(self, seq, state):
        for settings in seq:
            if self.__doRun(settings, state):
                return settings

        return None

    def __doRun(self, settings, state):
        if not settings.enabled:
            return False
        else:
            reqs = _settings.createTutorialElement(settings.reqs)
            if not reqs.isEnabled():
                return False
            descriptor = loadDescriptorData(settings, settings.exParsers)
            if descriptor is None:
                LOG_ERROR('Descriptor is not valid. Tutorial is not available',
                          settings)
                return False
            cache = _cache.TutorialCache(BigWorld.player().name)
            cache.read()
            cache.setSpace(settings.space, ioEnabled=settings.cacheEnabled)
            if state.get('byRequest', False):
                cache.setRefused(False)
            runCtx = RunCtx(cache, **state)
            reqs.prepare(runCtx)
            if not reqs.process(descriptor, runCtx):
                return False
            self.__doStop()
            if self.__dispatcher is None:
                self.__setDispatcher(settings.dispatcher)
            self.__tutorial = core.Tutorial(settings, descriptor)
            self.__tutorial.onStopped += self.__onTutorialStopped
            result = self.__tutorial.run(weakref.proxy(self.__dispatcher),
                                         runCtx)
            if not result:
                self.__tutorial.onStopped -= self.__onTutorialStopped
                self.__tutorial = None
            return result

    def __doStop(self):
        if self.__tutorial is not None:
            self.__tutorial.onStopped -= self.__onTutorialStopped
            self.__tutorial.stop()
            self.__tutorial = None
        return

    def __doStopHints(self):
        if self.__hintsManager is not None:
            self.__hintsManager.stop()
            self.__hintsManager = None
        return

    def __doClear(self):
        self.__restoreID = None
        self.__doStop()
        self.__doStopHints()
        if self.__dispatcher is not None:
            self.__dispatcher.stop()
            self.__dispatcher = None
        return

    def __doRestore(self):
        if self.__restoreID is not None:
            settingsID, self.__restoreID = self.__restoreID, None
            LOG_DEBUG('Restore tutorial', settingsID)
            self.run(settingsID)
        return

    def __setDispatcher(self, settings):
        if self.__dispatcher is not None:
            self.__dispatcher.stop()
            self.__dispatcher = None
        self.__dispatcher = _settings.createTutorialElement(settings)
        self.__dispatcher.start(weakref.proxy(self))
        return

    def __onTutorialStopped(self):
        self.__doRestore()