class _PythonTimer(_TimerComponent): __slots__ = ('_timeInterval', '_startTime', '_finishTime', '__weakref__') def __init__(self, panel, typeID, viewID, totalTime): super(_PythonTimer, self).__init__(panel, typeID, viewID, totalTime) self._timeInterval = TimeInterval(1.0, self, '_tick') self._startTime = BigWorld.serverTime() if totalTime: self._finishTime = self._startTime + totalTime else: self._finishTime = 0 def clear(self): self._timeInterval.stop() super(_PythonTimer, self).clear() def _startTick(self): if self._totalTime: timeLeft = max(0, self._finishTime - BigWorld.serverTime()) if timeLeft: self._panel.as_setTimeSnapshotS(self._typeID, self._totalTime, timeLeft) self._timeInterval.start() def _stopTick(self): self._timeInterval.stop() def _tick(self): timeLeft = self._finishTime - BigWorld.serverTime() if timeLeft >= 0: self._panel.as_setTimeSnapshotS(self._typeID, self._totalTime, timeLeft) else: self.hide()
class PythonTimer(TimerComponent): __slots__ = ('_timeInterval', '__weakref__') def __init__(self, panel, typeID, viewID, totalTime): super(PythonTimer, self).__init__(panel, typeID, viewID, totalTime) self._timeInterval = TimeInterval(1.0, self, '_tick') def clear(self): self._timeInterval.stop() super(PythonTimer, self).clear() def _startTick(self): if self._totalTime: timeLeft = max(0, self._finishTime - BigWorld.serverTime()) if timeLeft: self._setViewSnapshot(timeLeft) self._timeInterval.start() def _stopTick(self): self._timeInterval.stop() def _tick(self): timeLeft = self._finishTime - BigWorld.serverTime() if timeLeft >= 0: self._setViewSnapshot(timeLeft) else: self.hide() def _setViewSnapshot(self, timeLeft): raise NotImplementedError
class _DistancePlugin(IPlugin): __slots__ = ('__weakref__', '_interval', '_distance') def __init__(self, parentObj): super(_DistancePlugin, self).__init__(parentObj) self._interval = None self._distance = 0 return def start(self): self._interval = TimeInterval(_TARGET_UPDATE_INTERVAL, self, '_update') ctrl = g_sessionProvider.shared.crosshair raise ctrl is not None or AssertionError('Crosshair controller is not found') ctrl.onCrosshairViewChanged += self._onCrosshairViewChanged return def stop(self): if self._interval is not None: self._interval.stop() self._interval = None ctrl = g_sessionProvider.shared.crosshair if ctrl is not None: ctrl.onCrosshairViewChanged -= self._onCrosshairViewChanged return def _update(self): raise NotImplementedError def _onCrosshairViewChanged(self, viewID): raise NotImplementedError
class _DistancePlugin(CrosshairPlugin): __slots__ = ('_interval', '_distance') def __init__(self, parentObj): super(_DistancePlugin, self).__init__(parentObj) self._interval = None self._distance = 0 return def start(self): self._interval = TimeInterval(_TARGET_UPDATE_INTERVAL, self, '_update') ctrl = self.sessionProvider.shared.crosshair ctrl.onCrosshairViewChanged += self._onCrosshairViewChanged def stop(self): if self._interval is not None: self._interval.stop() self._interval = None ctrl = self.sessionProvider.shared.crosshair if ctrl is not None: ctrl.onCrosshairViewChanged -= self._onCrosshairViewChanged return def _update(self): raise NotImplementedError def _onCrosshairViewChanged(self, viewID): raise NotImplementedError
class PythonTimer(TimerComponent): __slots__ = ('_timeInterval', '__weakref__') def __init__(self, viewObject, typeID, viewID, totalTime, finishTime, startTime=None, interval=1.0, secondInRow=False, **kwargs): super(PythonTimer, self).__init__(viewObject, typeID, viewID, totalTime, finishTime, startTime, secondInRow=secondInRow, **kwargs) self._timeInterval = TimeInterval(interval, self, '_tick') def clear(self): self._timeInterval.stop() super(PythonTimer, self).clear() def _startTick(self): if self._totalTime: timeLeft = max(0, self._finishTime - BigWorld.serverTime()) if timeLeft: self._setViewSnapshot(timeLeft) self._timeInterval.restart() def _stopTick(self): self._timeInterval.stop() def _tick(self): timeLeft = self._finishTime - BigWorld.serverTime() if timeLeft >= 0: self._setViewSnapshot(timeLeft) else: self.hide() def _setViewSnapshot(self, timeLeft): raise NotImplementedError
class DebugController(IViewComponentsController): """Controller for the debug panel. This class starts internal update cycle and updates debug panel. In order to collect lagging info from near vehicles, these vehicle's ids should be provided from outside using special methods. """ statsCollector = dependency.descriptor(IStatisticsCollector) def __init__(self): super(DebugController, self).__init__() self._debugPanelUI = None self._timeInterval = None return def getControllerID(self): return BATTLE_CTRL_ID.DEBUG def startControl(self): self._timeInterval = TimeInterval(_UPDATE_INTERVAL, self, '_update') self._timeInterval.start() def stopControl(self): self._timeInterval.stop() self._timeInterval = None self.clearViewComponents() return def setViewComponents(self, debugPanelUI): raise isinstance(debugPanelUI, IDebugPanel) or AssertionError self._debugPanelUI = debugPanelUI def clearViewComponents(self): self._debugPanelUI = None return def _update(self): replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isPlaying and not replayCtrl.isBattleSimulation and replayCtrl.fps > 0: fps = BigWorld.getFPS()[1] fpsReplay = int(replayCtrl.fps) ping = replayCtrl.ping isLaggingNow = replayCtrl.isLaggingNow else: fpsReplay = -1 isLaggingNow = BigWorld.statLagDetected() ping = BigWorld.statPing() fps = BigWorld.getFPS()[1] self.statsCollector.update() if replayCtrl.isRecording: replayCtrl.setFpsPingLag(fps, ping, isLaggingNow) try: ping = int(ping) fps = int(fps) except (ValueError, OverflowError): return if self._debugPanelUI is not None: self._debugPanelUI.updateDebugInfo(int(ping), int(fps), isLaggingNow, fpsReplay=fpsReplay) return
class DebugController(IViewComponentsController): """Controller for the debug panel. This class starts internal update cycle and updates debug panel. In order to collect lagging info from near vehicles, these vehicle's ids should be provided from outside using special methods. """ def __init__(self): super(DebugController, self).__init__() self._debugPanelUI = None self._timeInterval = None return def getControllerID(self): return BATTLE_CTRL_ID.DEBUG def startControl(self): self._timeInterval = TimeInterval(_UPDATE_INTERVAL, self, '_update') self._timeInterval.start() def stopControl(self): self._timeInterval.stop() self._timeInterval = None self._debugPanelUI = None return def setViewComponents(self, debugPanelUI): raise isinstance(debugPanelUI, IDebugPanel) or AssertionError self._debugPanelUI = debugPanelUI def clearViewComponents(self): self._debugPanelUI = None return def _update(self): replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isPlaying and replayCtrl.fps > 0: fps = BigWorld.getFPS()[1] fpsReplay = int(replayCtrl.fps) ping = replayCtrl.ping isLaggingNow = replayCtrl.isLaggingNow else: fpsReplay = -1 isLaggingNow = BigWorld.statLagDetected() ping = BigWorld.statPing() fps = BigWorld.getFPS()[1] g_statistics.update() if replayCtrl.isRecording: replayCtrl.setFpsPingLag(fps, ping, isLaggingNow) try: ping = int(ping) fps = int(fps) except (ValueError, OverflowError): return if self._debugPanelUI is not None: self._debugPanelUI.updateDebugInfo(int(ping), int(fps), isLaggingNow, fpsReplay=fpsReplay) return
class DebugPanel(UIInterface): __UPDATE_INTERVAL = 0.01 def __init__(self, parentUI): UIInterface.__init__(self) self.__ui = parentUI self.__timeInterval = None self.__performanceStats = _PerformanceStats() self.__performanceStats.populateUI(parentUI) def start(self): self.__timeInterval = TimeInterval(self.__UPDATE_INTERVAL, self, '_DebugPanel__update') self.__timeInterval.start() self.__update() def destroy(self): self.__performanceStats.disposeUI() self.__performanceStats = None self.__timeInterval.stop() def __update(self): player = BigWorld.player() if player is None or not hasattr(player, 'playerVehicleID'): return fps = 0 recordedFps = -1 ping = 0 isLaggingNow = False replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isPlaying and replayCtrl.fps > 0: fps = BigWorld.getFPS()[1] recordedFps = replayCtrl.fps ping = replayCtrl.ping isLaggingNow = replayCtrl.isLaggingNow else: isLaggingNow = player.filter.isLaggingNow if not isLaggingNow: for v in BigWorld.entities.values(): if _isVehicleEntity(v): if not v.isPlayer: if v.isAlive() and isinstance(v.filter, BigWorld.WGVehicleFilter) and v.filter.isLaggingNow: isLaggingNow = True break ping = min(BigWorld.LatencyInfo().value[3] * 1000, 999) if ping < 999: ping = max(1, ping - 500.0 * constants.SERVER_TICK_LENGTH) fpsInfo = BigWorld.getFPS() from helpers.statistics import g_statistics g_statistics.update(fpsInfo, ping, isLaggingNow) fps = fpsInfo[1] if replayCtrl.isRecording: replayCtrl.setFpsPingLag(fps, ping, isLaggingNow) try: self.__performanceStats.updateDebugInfo(int(fps), int(ping), isLaggingNow, int(recordedFps)) except: pass
class DebugController(IViewComponentsController): statsCollector = dependency.descriptor(IStatisticsCollector) def __init__(self): super(DebugController, self).__init__() self._debugPanelUI = None self._timeInterval = None return def getControllerID(self): return BATTLE_CTRL_ID.DEBUG def startControl(self): self._timeInterval = TimeInterval(_UPDATE_INTERVAL, self, '_update') self._timeInterval.start() def stopControl(self): self._timeInterval.stop() self._timeInterval = None self.clearViewComponents() return def setViewComponents(self, debugPanelUI): self._debugPanelUI = debugPanelUI def clearViewComponents(self): self._debugPanelUI = None return def _update(self): replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isPlaying and not replayCtrl.isBattleSimulation and replayCtrl.fps > 0 or replayCtrl.isServerSideReplay: fps = BigWorld.getFPS()[1] fpsReplay = int(replayCtrl.fps) ping = replayCtrl.ping isLaggingNow = replayCtrl.isLaggingNow else: fpsReplay = -1 isLaggingNow = BigWorld.statLagDetected() ping = BigWorld.statPing() fps = BigWorld.getFPS()[1] self.statsCollector.update() if replayCtrl.isRecording: replayCtrl.setFpsPingLag(fps, ping, isLaggingNow) try: ping = int(ping) fps = int(fps) except (ValueError, OverflowError): return if self._debugPanelUI is not None: self._debugPanelUI.updateDebugInfo(ping, fps, isLaggingNow, fpsReplay=fpsReplay) return
class TimerReload(object): def __init__(self): self.strTime = '' self.section = 'damageLog/timeReload/' self.currentTime = 0 self.finishTime = 0 self.data = None self.timerReloadAttacker = None def reset(self): self.strTime = '' self.section = 'damageLog/timeReload/' self.currentTime = 0 self.finishTime = 0 self.data = None if (self.timerReloadAttacker is not None) and self.timerReloadAttacker.isStarted: self.timerReloadAttacker.stop() def afterTimerReload(self): self.strTime = '' if (self.timerReloadAttacker is not None) and self.timerReloadAttacker.isStarted: self.timerReloadAttacker.stop() as_event('ON_TIMER_RELOAD') def currentTimeReload(self): self.data['timer'] = self.finishTime - BigWorld.serverTime() timeTextAfterReload = float(config.get(self.section + 'timeTextAfterReload')) if self.data['timer'] > 0: macroes = getValueMacroes(self.section, self.data) self.strTime = parser(config.get(self.section + 'formatTimer'), macroes) else: self.timerReloadAttacker.stop() if timeTextAfterReload > 0: self.timerReloadAttacker = TimeInterval(timeTextAfterReload, self, 'afterTimerReload') macroes = getValueMacroes(self.section, self.data) self.strTime = parser(config.get(self.section + 'formatTimerAfterReload'), macroes) self.timerReloadAttacker.start() else: self.strTime = '' as_event('ON_TIMER_RELOAD') def output(self): if (data.data['attackReasonID'] == 0) and (data.data['timer'] > 0): self.data = data.data.copy() macroes = getValueMacroes(self.section, self.data) self.strTime = parser(config.get(self.section + 'formatTimer'), macroes) as_event('ON_TIMER_RELOAD') self.finishTime = self.data['timer'] + BigWorld.serverTime() if (self.timerReloadAttacker is not None) and (self.timerReloadAttacker.isStarted): self.timerReloadAttacker.stop() self.timerReloadAttacker = TimeInterval(0.1, self, 'currentTimeReload') self.timerReloadAttacker.start()
class _PythonUpdater(_ComponentUpdater): """ This updater is used only in REPLAYS. It will use internal timer to tick every 0.05 second. This solution is necessary to display actual timeLeft, states, etc correctly during replay's timeWarp, rewind, start/stop, etc. """ __slots__ = ('_timeInterval', '_startTime', '_finishTime', '__weakref__') def __init__(self, parentObj, totalTime, timeLeft, siegeState, engineState, isSmooth): super(_PythonUpdater, self).__init__(parentObj, totalTime, timeLeft, siegeState, engineState, isSmooth) self._timeInterval = TimeInterval(0.05, self, '_tick') self._startTime = BigWorld.serverTime() self._finishTime = self._startTime + timeLeft def clear(self): self._timeInterval.stop() super(_PythonUpdater, self).clear() def _startTick(self): if self._siegeState in VEHICLE_SIEGE_STATE.SWITCHING: timeLeft = max(0, self._finishTime - BigWorld.serverTime()) if timeLeft: self._updateSnapshot(timeLeft) self._timeInterval.start() else: self._updateSnapshot(self._timeLeft) self._isSmooth = False def _stopTick(self): self._timeInterval.stop() def _tick(self): timeLeft = self._finishTime - BigWorld.serverTime() if timeLeft >= 0 and self._engineState != 'destroyed': self._updateSnapshot(timeLeft) def _updateSnapshot(self, timeLeft): self._parentObj.as_switchSiegeStateSnapshotS(self._totalTime, timeLeft, self._siegeState, self._engineState, self._isSmooth)
class _PythonUpdater(_ComponentUpdater): __slots__ = ('_timeInterval', '_startTime', '_finishTime', '__weakref__') def __init__(self, parentObj, totalTime, timeLeft, siegeState, engineState, isSmooth): super(_PythonUpdater, self).__init__(parentObj, totalTime, timeLeft, siegeState, engineState, isSmooth) self._timeInterval = TimeInterval(0.05, self, '_tick') self._startTime = BigWorld.serverTime() self._finishTime = self._startTime + timeLeft def clear(self): self._timeInterval.stop() super(_PythonUpdater, self).clear() def _startTick(self): if self._siegeState in VEHICLE_SIEGE_STATE.SWITCHING and not self._staticMode: timeLeft = max(0, self._finishTime - BigWorld.serverTime()) if timeLeft: self._updateSnapshot(timeLeft) self._timeInterval.start() else: self._updateSnapshot(self._timeLeft) self._isSmooth = False def _stopTick(self): self._timeInterval.stop() def _tick(self): if self._staticMode: return timeLeft = self._finishTime - BigWorld.serverTime() if timeLeft >= 0 and self._engineState != 'destroyed': self._updateSnapshot(timeLeft) def _updateSnapshot(self, timeLeft): if self._staticMode: self._parentObj.as_setAutoSiegeModeStateS(self._siegeState, self._engineState) else: self._parentObj.as_switchSiegeStateSnapshotS( self._totalTime, timeLeft, self._siegeState, self._engineState, self._isSmooth)
class TimeTrackState(RepairState): __slots__ = ('_timer', '_nextTime', '__weakref__') def __init__(self, pointIndex, stateID, *actions): super(TimeTrackState, self).__init__(pointIndex, stateID, *actions) self._timer = None self._nextTime = 0 return def destroy(self): self._destroyTimer() super(TimeTrackState, self).destroy() def setAction(self, action, nextActionTime): if action in self._actions: self._recreateTimer(nextActionTime) self._updateTime() else: self._destroyTimer() def _getTimeLeft(self): return max(0, round(self._nextTime - BigWorld.serverTime())) def _updateTime(self): self._ctrl.onTimerUpdated(self._pointIndex, self._stateID, self._getTimeLeft()) def _createTimer(self, nextActionTime): self._nextTime = nextActionTime self._timer = TimeInterval(1, self, '_updateTime') self._timer.start() def _destroyTimer(self): if self._timer is not None: self._timer.stop() self._timer = None return def _recreateTimer(self, nextActionTime): self._destroyTimer() self._createTimer(nextActionTime)
class VehicleStateController(IBattleController): def __init__(self): super(VehicleStateController, self).__init__() self.__eManager = Event.EventManager() self.onVehicleStateUpdated = Event.Event(self.__eManager) self.onVehicleControlling = Event.Event(self.__eManager) self.onPostMortemSwitched = Event.Event(self.__eManager) self.onRespawnBaseMoving = Event.Event(self.__eManager) self.__cachedStateValues = {} self.__waitingTI = TimeInterval(VEHICLE_WAINING_INTERVAL, self, '_waiting') self.__vehicleID = 0 self.__updater = None self.__isRqToSwitch = False self.__isInPostmortem = False self.__needInvalidate = False return def getControllerID(self): return BATTLE_CTRL_ID.OBSERVED_VEHICLE_STATE def startControl(self): pass def stopControl(self): if self.__waitingTI is not None: self.__waitingTI.stop() self.__waitingTI = None if self.__updater is not None: self.__updater.clear() self.__updater = None self.__vehicleID = 0 self.__isRqToSwitch = False self.__isInPostmortem = False self.__eManager.clear() self.__cachedStateValues.clear() return @property def isInPostmortem(self): return self.__isInPostmortem def setPlayerVehicle(self, vehicleID): self.notifyStateChanged(VEHICLE_VIEW_STATE.PLAYER_INFO, vehicleID) self.__vehicleID = vehicleID self.__updater = _VehicleUpdater(self, self.__vehicleID) self.__waitingTI.start() def getControllingVehicle(self): vehicle = None if self.__vehicleID: vehicle = BigWorld.entity(self.__vehicleID) return vehicle def getControllingVehicleID(self): return self.__vehicleID def notifyStateChanged(self, stateID, value): if stateID == VEHICLE_VIEW_STATE.DEVICES: self.__cachedStateValues.setdefault(stateID, []) self.__cachedStateValues[stateID].append(value) else: self.__cachedStateValues[stateID] = value self.onVehicleStateUpdated(stateID, value) def getStateValue(self, stateID): return self.__cachedStateValues[stateID] if stateID in self.__cachedStateValues else None def refreshVehicleStateValue(self, stateID): if stateID in self.__cachedStateValues: self.onVehicleStateUpdated(stateID, self.__cachedStateValues[stateID]) def invalidate(self, state, value, vehicleID=0): if vehicleID != 0 and vehicleID != self.__vehicleID: return else: isStateChangeHandled = False if self.__isRqToSwitch and self.__waitingTI.isStarted(): self._waiting() if self.__updater is not None: isStateChangeHandled = self.__updater.handleStateChange(state, value) if not isStateChangeHandled: self.notifyStateChanged(state, value) return def switchToPostmortem(self, noRespawnPossible, respawnAvailable): self.__isRqToSwitch = False if avatar_getter.getPlayerVehicleID() == self.__vehicleID: if self.__updater is not None: self.__updater.stop() self.__updater.updateOnce() self.__isInPostmortem = True self.onPostMortemSwitched(noRespawnPossible, respawnAvailable) return def switchToOther(self, vehicleID): if vehicleID is None: self.notifyStateChanged(VEHICLE_VIEW_STATE.SWITCHING, 0) self.__needInvalidate = True return elif self.__vehicleID == vehicleID and not self.__needInvalidate: return else: self.__needInvalidate = False self.notifyStateChanged(VEHICLE_VIEW_STATE.SWITCHING, vehicleID) self.__waitingTI.stop() if self.__updater: self.__updater.stop() self.__vehicleID = vehicleID self.__isRqToSwitch = True self.notifyStateChanged(VEHICLE_VIEW_STATE.PLAYER_INFO, self.__vehicleID) self.__cachedStateValues.clear() self.__waitingTI.start() return def movingToRespawn(self): self.__isInPostmortem = False self.notifyStateChanged(VEHICLE_VIEW_STATE.SWITCHING, 0) self.onRespawnBaseMoving() self.__cachedStateValues.clear() def _waiting(self): vehicle = BigWorld.entity(self.__vehicleID) if vehicle is not None and vehicle.isStarted: self.__waitingTI.stop() self._setup(vehicle) return def _setup(self, vehicle): if self.__updater is not None: self.__updater = self.__updater.switch(self.__vehicleID) if self.__isRqToSwitch: nationID = vehicle.typeDescriptor.type.id[0] notifications = avatar_getter.getSoundNotifications() if notifications is not None: notifications.clear() SoundGroups.g_instance.soundModes.setCurrentNation(nations.NAMES[nationID]) self.onVehicleControlling(vehicle) if self.__updater is not None: self.__updater.start() return
class _VehicleUpdater(object): def __init__(self, vehCtrl, vehicleID): super(_VehicleUpdater, self).__init__() self.__isAlive = True self.__handlers = None self.__ctrl = weakref.proxy(vehCtrl) self.__vehicleID = vehicleID self.__updateTI = None self._setUpHandlers() return def handleStateChange(self, state, value): isStateHandled = False for handler in self.__handlers: isStateHandled |= handler.handleStateChange(state, value) return isStateHandled def switch(self, vehicleID): self.clear() self.__vehicleID = vehicleID self._setUpHandlers() return self def start(self): if self.__updateTI is None: self.__updateTI = TimeInterval(VEHICLE_UPDATE_INTERVAL, self, '_update') self.__updateTI.start() return def stop(self): if self.__updateTI is not None: self.__updateTI.stop() self.__updateTI = None return def clear(self): self.stop() if self.__handlers is not None: for handler in self.__handlers: handler.clear() self.__handlers = None self.__vehicleID = None self.__isAlive = True return def updateOnce(self): self._update() def notifyStateChanged(self, state, value): self.__ctrl.notifyStateChanged(state, value) def _update(self): states = [] vehicle = BigWorld.entity(self.__vehicleID) if vehicle is not None and vehicle.isStarted: if not vehicle.isAlive() and self.__isAlive: self.__isAlive = False if vehicle.health > 0 and not vehicle.isCrewActive: states.append((VEHICLE_VIEW_STATE.CREW_DEACTIVATED, 0)) else: states.append((VEHICLE_VIEW_STATE.DESTROYED, 0)) for handler in self.__handlers: newStates = handler(vehicle) states.extend(newStates) for item in states: self.notifyStateChanged(*item) return def _setUpHandlers(self): vehicle = BigWorld.entity(self.__vehicleID) if vehicle is not None: isPlayerVehicle = vehicle.isPlayerVehicle if isPlayerVehicle: if not vehicle.isAlive(): self.__handlers = (_SpeedStateHandler(self, True),) else: self.__handlers = (_SpeedStateHandler(self, True),) else: self.__handlers = (_HealthStateHandler(self), _SpeedStateHandler(self, False)) return
class VehicleStateController(object): def __init__(self): super(VehicleStateController, self).__init__() self.__eManager = Event.EventManager() self.onVehicleStateUpdated = Event.Event(self.__eManager) self.onVehicleControlling = Event.Event(self.__eManager) self.onPostMortemSwitched = Event.Event(self.__eManager) self.onRespawnBaseMoving = Event.Event(self.__eManager) self.__waitingTI = TimeInterval(VEHICLE_WAINING_INTERVAL, self, '_waiting') self.__updateTI = TimeInterval(VEHICLE_UPDATE_INTERVAL, self, '_update') self.__vehicleID = 0 self.__updater = _PlayerVehicleUpdater() self.__isRqToSwitch = False def clear(self): if self.__waitingTI: self.__waitingTI.stop() self.__waitingTI = None if self.__updateTI: self.__updateTI.stop() self.__updateTI = None self.__vehicleID = 0 self.__isRqToSwitch = False self.__updater = None self.__eManager.clear() def setPlayerVehicle(self, vehicleID): self.onVehicleStateUpdated(VEHICLE_VIEW_STATE.PLAYER_INFO, vehicleID) self.__vehicleID = vehicleID self.__waitingTI.start() def getControllingVehicle(self): vehicle = None if self.__vehicleID: vehicle = BigWorld.entity(self.__vehicleID) return vehicle def invalidate(self, state, value): if state == VEHICLE_VIEW_STATE.DESTROYED: self.__updateTI.stop() self.onVehicleStateUpdated(state, value) def switchToPostmortem(self): self.__isRqToSwitch = False if avatar_getter.getPlayerVehicleID() == self.__vehicleID: self.__waitingTI.stop() self.__updateTI.stop() self.onPostMortemSwitched() def switchToAnother(self, vehicleID): if self.__vehicleID == vehicleID or vehicleID is None: return self.onVehicleStateUpdated(VEHICLE_VIEW_STATE.SWITCHING, self.__vehicleID) if self.__updater: self.__updater.clear() self.__waitingTI.stop() self.__updateTI.stop() self.__vehicleID = vehicleID self.__isRqToSwitch = True self.onVehicleStateUpdated(VEHICLE_VIEW_STATE.PLAYER_INFO, self.__vehicleID) self.__waitingTI.start() def movingToRespawn(self): self.onVehicleStateUpdated(VEHICLE_VIEW_STATE.SWITCHING, 0) self.onRespawnBaseMoving() def _waiting(self): vehicle = BigWorld.entity(self.__vehicleID) if vehicle is not None: self.__waitingTI.stop() self._setup(vehicle) def _update(self): states = self.__updater.update(self.__vehicleID, self.__updateTI) if states is not None: for item in states: self.onVehicleStateUpdated(*item) def _setup(self, vehicle): self.__updater = self.__updater.switch(vehicle.isPlayer) if self.__isRqToSwitch: nationID = vehicle.typeDescriptor.type.id[0] notifications = avatar_getter.getSoundNotifications() if notifications: notifications.clear() SoundGroups.g_instance.soundModes.setCurrentNation( nations.NAMES[nationID]) self.onVehicleControlling(vehicle) if not vehicle.isAlive(): self.onVehicleStateUpdated(VEHICLE_VIEW_STATE.DESTROYED, None) else: self.__updateTI.start()
class VehicleStateController(IBattleController): """ Class of controller that tracks specified vehicle on arena. At any time there is only one instance of this class. When player's own vehicle is destroyed, controller can track other vehicles on player's team. The main goal of the controller to combine all knowledge about vehicle state changes and to notify subscribers about that through appropriate events. The controller declares public interface to know about changes. Triggers call these method to notify the controller about specific changes that occur outside client. Also there is a list of changes that are triggered directly by the controller via the updater. The updater tracks those parameters on which there are no outside triggers or when required to control triggering frequency. """ def __init__(self): """ Constructor. Initializes internal variables. """ super(VehicleStateController, self).__init__() self.__eManager = Event.EventManager() self.onVehicleStateUpdated = Event.Event(self.__eManager) self.onVehicleControlling = Event.Event(self.__eManager) self.onPostMortemSwitched = Event.Event(self.__eManager) self.onRespawnBaseMoving = Event.Event(self.__eManager) self.__cachedStateValues = {} self.__waitingTI = TimeInterval(VEHICLE_WAINING_INTERVAL, self, '_waiting') self.__vehicleID = 0 self.__updater = None self.__isRqToSwitch = False self.__isInPostmortem = False return def getControllerID(self): return BATTLE_CTRL_ID.OBSERVED_VEHICLE_STATE def startControl(self): pass def stopControl(self): """ Clears internal variables and stops timers. :return: """ if self.__waitingTI is not None: self.__waitingTI.stop() self.__waitingTI = None if self.__updater is not None: self.__updater.clear() self.__updater = None self.__vehicleID = 0 self.__isRqToSwitch = False self.__isInPostmortem = False self.__eManager.clear() self.__cachedStateValues.clear() return @property def isInPostmortem(self): return self.__isInPostmortem def setPlayerVehicle(self, vehicleID): """ Sets ID of player's own vehicle. :param vehicleID: ID of vehicle entity """ self.notifyStateChanged(VEHICLE_VIEW_STATE.PLAYER_INFO, vehicleID) self.__vehicleID = vehicleID self.__updater = _VehicleUpdater(self, self.__vehicleID) self.__waitingTI.start() def getControllingVehicle(self): """ Gets entity of vehicle that is controlling. :return: entity of vehicle or None """ vehicle = None if self.__vehicleID: vehicle = BigWorld.entity(self.__vehicleID) return vehicle def getControllingVehicleID(self): return self.__vehicleID def notifyStateChanged(self, stateID, value): """ Store the specified state value, and raise the event :param stateID: id for state, listed within VEHICLE_VIEW_STATE :param value: state value """ if stateID == VEHICLE_VIEW_STATE.DEVICES: self.__cachedStateValues.setdefault(stateID, []) self.__cachedStateValues[stateID].append(value) else: self.__cachedStateValues[stateID] = value self.onVehicleStateUpdated(stateID, value) def getStateValue(self, stateID): """ Returns the last value for the the desired state :param stateID: id of state, listed within VEHICLE_VIEW_STATE :return: None or state value """ if stateID in self.__cachedStateValues: return self.__cachedStateValues[stateID] else: return None def refreshVehicleStateValue(self, stateID): """ Re-calls Update on the cached value of the vehicle state, nothing if not cached :param stateID: id of state, listed within VEHICLE_VIEW_STATE """ if stateID in self.__cachedStateValues: self.onVehicleStateUpdated(stateID, self.__cachedStateValues[stateID]) def invalidate(self, state, value, vehicleID = 0): """ Invalidates vehicle sates. The method should be invoked by vehicle state change trigger. :param state: A state listed within VEHICLE_VIEW_STATE :param value: New state value :param vehicleID: ID of vehicle for which the given state is changed. """ if vehicleID != 0 and vehicleID != self.__vehicleID: return else: isStateChangeHandled = False if self.__isRqToSwitch and self.__waitingTI.isStarted(): self._waiting() if self.__updater is not None: isStateChangeHandled = self.__updater.handleStateChange(state, value) if not isStateChangeHandled: self.notifyStateChanged(state, value) return def switchToPostmortem(self, noRespawnPossible, respawnAvailable): """ Switches to postmortem mode. :param leave: """ self.__isRqToSwitch = False if avatar_getter.getPlayerVehicleID() == self.__vehicleID: if self.__updater is not None: self.__updater.stop() self.__updater.updateOnce() self.__isInPostmortem = True self.onPostMortemSwitched(noRespawnPossible, respawnAvailable) return def switchToOther(self, vehicleID): """ Switches to another vehicle. :param vehicleID: ID of a new vehicle to be tracked. """ if self.__vehicleID == vehicleID or vehicleID is None: return else: self.notifyStateChanged(VEHICLE_VIEW_STATE.SWITCHING, vehicleID) self.__waitingTI.stop() if self.__updater: self.__updater.stop() self.__vehicleID = vehicleID self.__isRqToSwitch = True self.notifyStateChanged(VEHICLE_VIEW_STATE.PLAYER_INFO, self.__vehicleID) self.__cachedStateValues.clear() self.__waitingTI.start() return def movingToRespawn(self): """ Emits the appropriate event and state change event. The method should be called when the vehicle is moved to respawn. :return: """ self.__isInPostmortem = False self.notifyStateChanged(VEHICLE_VIEW_STATE.SWITCHING, 0) self.onRespawnBaseMoving() self.__cachedStateValues.clear() def _waiting(self): """ Callback to be invoked when the waiting timer is elapsed. Starts the updater when the avatar has been switched to the required vehicle. """ vehicle = BigWorld.entity(self.__vehicleID) if vehicle is not None and vehicle.isStarted: self.__waitingTI.stop() self._setup(vehicle) return def _setup(self, vehicle): """ Set up the updater and other properties :param vehicle: Vehicle entity. """ if self.__updater is not None: self.__updater = self.__updater.switch(self.__vehicleID) if self.__isRqToSwitch: nationID = vehicle.typeDescriptor.type.id[0] notifications = avatar_getter.getSoundNotifications() if notifications is not None: notifications.clear() SoundGroups.g_instance.soundModes.setCurrentNation(nations.NAMES[nationID]) self.onVehicleControlling(vehicle) if self.__updater is not None: self.__updater.start() return
class _VehicleUpdater(object): """ The class implements logic for tracking changes of vehicle parameters in equal time intervals. It encapsulates different algorithms of tracking based on vehicle type. The inner logic is based on the custom state handlers (classes derived from _StateHandler). """ def __init__(self, vehCtrl, vehicleID): """ Constructor. Initializes internal variables. :param vehCtrl: Reference to vehicle state controller owning this updater. :param vehicleID: Unique identifier of vehicle to be tracked """ super(_VehicleUpdater, self).__init__() self.__isAlive = True self.__handlers = None self.__ctrl = weakref.proxy(vehCtrl) self.__vehicleID = vehicleID self.__updateTI = None self._setUpHandlers() return def handleStateChange(self, state, value): """ Represents a hook to catch states changes before the vehicle state controller propagates them to subscribers. Redirects the call to each handler to perform required logic. :param state: A state listed within VEHICLE_VIEW_STATE :param value: State value :return: True if any handler returns True. Otherwise - False. """ isStateHandled = False for handler in self.__handlers: isStateHandled |= handler.handleStateChange(state, value) return isStateHandled def switch(self, vehicleID): """ Switches the updater to another vehicle: reset internal states and handlers. :param vehicleID: Unique identifier of a new vehicle that will be tracked """ self.clear() self.__vehicleID = vehicleID self._setUpHandlers() return self def start(self): """ Sets up and starts the timer to invalidate handlers. """ if self.__updateTI is None: self.__updateTI = TimeInterval(VEHICLE_UPDATE_INTERVAL, self, '_update') self.__updateTI.start() return def stop(self): """ Stops and clears running timer (if any). """ if self.__updateTI is not None: self.__updateTI.stop() self.__updateTI = None return def clear(self): """ Clears internal variables and stops timer. """ self.stop() if self.__handlers is not None: for handler in self.__handlers: handler.clear() self.__handlers = None self.__vehicleID = None self.__isAlive = True return def updateOnce(self): """ Invokes this routine to singe update of information about vehicle if it is needed. For example, player's vehicle is destroyed, we need to update modules and crew states, set max speed. """ raise self.__updateTI is None or not self.__updateTI.isStarted() or AssertionError('Updater is started') self._update() return def notifyStateChanged(self, state, value): """ The helper method to provide handler ability to notify subscribers about changes of vehicle's states through the vehicle state controller. :param state: A state listed within VEHICLE_VIEW_STATE :param value: State value. """ self.__ctrl.notifyStateChanged(state, value) def _update(self): """ Callback on timer tick event. Initiates invalidation of all handlers, get all states changes and redirects them to the vehicle state controller by emitting appropriate events. """ states = [] vehicle = BigWorld.entity(self.__vehicleID) if vehicle is not None and vehicle.isStarted: if not vehicle.isAlive() and self.__isAlive: self.__isAlive = False if vehicle.health > 0 and not vehicle.isCrewActive: states.append((VEHICLE_VIEW_STATE.CREW_DEACTIVATED, 0)) else: states.append((VEHICLE_VIEW_STATE.DESTROYED, 0)) for handler in self.__handlers: newStates = handler(vehicle) states.extend(newStates) for item in states: self.notifyStateChanged(*item) return def _setUpHandlers(self): """ Determines a list of handlers based on vehicle type and sets up them. """ vehicle = BigWorld.entity(self.__vehicleID) if vehicle is not None: isPlayerVehicle = vehicle.isPlayerVehicle if isPlayerVehicle: if not vehicle.isAlive(): self.__handlers = (_SpeedStateHandler(self, True),) else: self.__handlers = (_SpeedStateHandler(self, True), _RpmStateHandler(self, vehicle), _EngineStateHandler(self, vehicle)) else: self.__handlers = (_HealthStateHandler(self), _SpeedStateHandler(self, False), _RpmStateHandler(self, vehicle), _EngineStateHandler(self, vehicle)) return
class VehicleStateController(IBattleController): """ Class of controller that tracks specified vehicle on arena. At any time there is only one instance of this class. When player's own vehicle is destroyed, controller can track other vehicles on player's team. The main goal of the controller to combine all knowledge about vehicle state changes and to notify subscribers about that through appropriate events. The controller declares public interface to know about changes. Triggers call these method to notify the controller about specific changes that occur outside client. Also there is a list of changes that are triggered directly by the controller via the updater. The updater tracks those parameters on which there are no outside triggers or when required to control triggering frequency. """ def __init__(self): """ Constructor. Initializes internal variables. """ super(VehicleStateController, self).__init__() self.__eManager = Event.EventManager() self.onVehicleStateUpdated = Event.Event(self.__eManager) self.onVehicleControlling = Event.Event(self.__eManager) self.onPostMortemSwitched = Event.Event(self.__eManager) self.onRespawnBaseMoving = Event.Event(self.__eManager) self.__cachedStateValues = {} self.__waitingTI = TimeInterval(VEHICLE_WAINING_INTERVAL, self, '_waiting') self.__vehicleID = 0 self.__updater = None self.__isRqToSwitch = False self.__isInPostmortem = False return def getControllerID(self): return BATTLE_CTRL_ID.OBSERVED_VEHICLE_STATE def startControl(self): pass def stopControl(self): """ Clears internal variables and stops timers. :return: """ if self.__waitingTI is not None: self.__waitingTI.stop() self.__waitingTI = None if self.__updater is not None: self.__updater.clear() self.__updater = None self.__vehicleID = 0 self.__isRqToSwitch = False self.__isInPostmortem = False self.__eManager.clear() self.__cachedStateValues.clear() return @property def isInPostmortem(self): return self.__isInPostmortem def setPlayerVehicle(self, vehicleID): """ Sets ID of player's own vehicle. :param vehicleID: ID of vehicle entity """ self.notifyStateChanged(VEHICLE_VIEW_STATE.PLAYER_INFO, vehicleID) self.__vehicleID = vehicleID self.__updater = _VehicleUpdater(self, self.__vehicleID) self.__waitingTI.start() def getControllingVehicle(self): """ Gets entity of vehicle that is controlling. :return: entity of vehicle or None """ vehicle = None if self.__vehicleID: vehicle = BigWorld.entity(self.__vehicleID) return vehicle def notifyStateChanged(self, stateID, value): """ Store the specified state value, and raise the event :param stateID: id for state, listed within VEHICLE_VIEW_STATE :param value: state value """ self.__cachedStateValues[stateID] = value self.onVehicleStateUpdated(stateID, value) def getStateValue(self, stateID): """ Returns the last value for the the desired state :param stateID: id of state, listed within VEHICLE_VIEW_STATE :return: None or state value """ if stateID in self.__cachedStateValues: return self.__cachedStateValues[stateID] else: return None return None def invalidate(self, state, value, vehicleID = 0): """ Invalidates vehicle sates. The method should be invoked by vehicle state change trigger. :param state: A state listed within VEHICLE_VIEW_STATE :param value: New state value :param vehicleID: ID of vehicle for which the given state is changed. """ if vehicleID != 0 and vehicleID != self.__vehicleID: return else: isStateChangeHandled = False if self.__updater is not None: isStateChangeHandled = self.__updater.handleStateChange(state, value) if not isStateChangeHandled: self.notifyStateChanged(state, value) return def switchToPostmortem(self): """ Switches to postmortem mode. """ self.__isRqToSwitch = False if avatar_getter.getPlayerVehicleID() == self.__vehicleID: self.__waitingTI.stop() if self.__updater is not None: self.__updater.stop() self.__isInPostmortem = True self.onPostMortemSwitched() return def switchToOther(self, vehicleID): """ Switches to another vehicle. :param vehicleID: ID of a new vehicle to be tracked. """ if self.__vehicleID == vehicleID or vehicleID is None: return else: self.notifyStateChanged(VEHICLE_VIEW_STATE.SWITCHING, vehicleID) self.__waitingTI.stop() if self.__updater: self.__updater.stop() self.__vehicleID = vehicleID self.__isRqToSwitch = True self.notifyStateChanged(VEHICLE_VIEW_STATE.PLAYER_INFO, self.__vehicleID) self.__waitingTI.start() return def movingToRespawn(self): """ Emits the appropriate event and state change event. The method should be called when the vehicle is moved to respawn. :return: """ self.notifyStateChanged(VEHICLE_VIEW_STATE.SWITCHING, 0) self.onRespawnBaseMoving() def _waiting(self): """ Callback to be invoked when the waiting timer is elapsed. Starts the updater when the avatar has been switched to the required vehicle. """ vehicle = BigWorld.entity(self.__vehicleID) if vehicle is not None: self.__waitingTI.stop() self._setup(vehicle) return def _setup(self, vehicle): """ Set up the updater and other properties :param vehicle: Vehicle entity. """ if self.__updater is not None: self.__updater = self.__updater.switch(self.__vehicleID) if self.__isRqToSwitch: nationID = vehicle.typeDescriptor.type.id[0] notifications = avatar_getter.getSoundNotifications() if notifications is not None: notifications.clear() SoundGroups.g_instance.soundModes.setCurrentNation(nations.NAMES[nationID]) self.onVehicleControlling(vehicle) if not vehicle.isAlive(): self.notifyStateChanged(VEHICLE_VIEW_STATE.DESTROYED, None) elif self.__updater is not None: self.__updater.start() return
class DebugController(IViewComponentsController): """Controller for the debug panel. This class starts internal update cycle and updates debug panel. In order to collect lagging info from near vehicles, these vehicle's ids should be provided from outside using special methods. """ def __init__(self): super(DebugController, self).__init__() self._debugPanelUI = None self._timeInterval = None self._visibleVehicles = set() return def getControllerID(self): return BATTLE_CTRL_ID.DEBUG def startControl(self): self._timeInterval = TimeInterval(_UPDATE_INTERVAL, self, '_update') self._timeInterval.start() def stopControl(self): self._timeInterval.stop() self._timeInterval = None self._debugPanelUI = None self._visibleVehicles = set() return def setViewComponents(self, debugPanelUI): raise isinstance(debugPanelUI, IDebugPanel) or AssertionError self._debugPanelUI = debugPanelUI def clearViewComponents(self): self._debugPanelUI = None return def startVehicleVisual(self, vehicleID): if avatar_getter.getPlayerVehicleID() != vehicleID: self._visibleVehicles.add(vehicleID) def stopVehicleVisual(self, vehicleID): self._visibleVehicles.discard(vehicleID) def _update(self): replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isPlaying and replayCtrl.fps > 0: fps = BigWorld.getFPS()[1] fpsReplay = int(replayCtrl.fps) ping = replayCtrl.ping isLaggingNow = replayCtrl.isLaggingNow else: fpsReplay = -1 player = BigWorld.player() isLaggingNow = player.filter.isLaggingNow if player is not None else False if not isLaggingNow: for vehicleID in self._visibleVehicles: vehicle = BigWorld.entities[vehicleID] if vehicle is not None and vehicle.isAlive(): try: if vehicle.filter.isLagginNow: isLaggingNow = True break except AttributeError: pass avgLatency = BigWorld.LatencyInfo().value[3] if avgLatency: ping = min(avgLatency * 1000, 999) if ping < 999: ping = max(1, ping - 500.0 * constants.SERVER_TICK_LENGTH) else: ping = 999 fpsInfo = BigWorld.getFPS() g_statistics.update(fpsInfo, ping, isLaggingNow) fps = fpsInfo[1] if replayCtrl.isRecording: replayCtrl.setFpsPingLag(fps, ping, isLaggingNow) if self._debugPanelUI is not None: self._debugPanelUI.updateDebugInfo(int(ping), int(fps), isLaggingNow, fpsReplay=fpsReplay) return
class VehicleStateController(IBattleController): def __init__(self): super(VehicleStateController, self).__init__() self.__eManager = Event.EventManager() self.onVehicleStateUpdated = Event.Event(self.__eManager) self.onVehicleControlling = Event.Event(self.__eManager) self.onPostMortemSwitched = Event.Event(self.__eManager) self.onRespawnBaseMoving = Event.Event(self.__eManager) self.onEquipmentComponentUpdated = Event.ContextEvent(self.__eManager) self.__cachedStateValues = {} self.__cachedRepairingCallbackID = None self.__waitingTI = TimeInterval(VEHICLE_WAINING_INTERVAL, self, '_waiting') self.__vehicleID = 0 self.__updater = None self.__isRqToSwitch = False self.__isInPostmortem = False self.__needInvalidate = False return def getControllerID(self): return BATTLE_CTRL_ID.OBSERVED_VEHICLE_STATE def startControl(self, *_): pass def stopControl(self): if self.__waitingTI is not None: self.__waitingTI.stop() self.__waitingTI = None if self.__updater is not None: self.__updater.clear() self.__updater = None self.__vehicleID = 0 self.__isRqToSwitch = False self.__isInPostmortem = False self.__eManager.clear() self.__cachedStateValues.clear() if self.__cachedRepairingCallbackID: BigWorld.cancelCallback(self.__cachedRepairingCallbackID) return @property def isInPostmortem(self): return self.__isInPostmortem def setPlayerVehicle(self, vehicleID): self.notifyStateChanged(VEHICLE_VIEW_STATE.PLAYER_INFO, vehicleID) self.__vehicleID = vehicleID self.__updater = _VehicleUpdater(self, self.__vehicleID) self.__waitingTI.restart() def getControllingVehicle(self): vehicle = None if self.__vehicleID: vehicle = BigWorld.entity(self.__vehicleID) return vehicle def getControllingVehicleID(self): return self.__vehicleID def notifyStateChanged(self, stateID, value): if stateID == VEHICLE_VIEW_STATE.DEVICES: self.__cachedStateValues.setdefault(stateID, {}) deviceName = value[0] cachedRepairingDeviceName = first(self.__cachedStateValues.get(VEHICLE_VIEW_STATE.REPAIRING, ())) if cachedRepairingDeviceName == deviceName and value[2] == DEVICE_STATE_NORMAL: self.__cachedStateValues.pop(VEHICLE_VIEW_STATE.REPAIRING) self.__cachedStateValues[stateID][deviceName] = value else: if stateID == VEHICLE_VIEW_STATE.REPAIRING: if self.__cachedRepairingCallbackID: BigWorld.cancelCallback(self.__cachedRepairingCallbackID) BigWorld.callback(value[2], partial(self.__cachedRepairingCallback, value)) self.__cachedStateValues[stateID] = value self.onVehicleStateUpdated(stateID, value) def __cachedRepairingCallback(self, value): self.__cachedRepairingCallbackID = None if self.__cachedStateValues.get(VEHICLE_VIEW_STATE.REPAIRING) == value: self.__cachedStateValues.pop(VEHICLE_VIEW_STATE.REPAIRING) return def getStateValue(self, stateID): if stateID in self.__cachedStateValues: if stateID == VEHICLE_VIEW_STATE.DEVICES: value = self.__cachedStateValues[stateID].values() else: value = self.__cachedStateValues[stateID] return value else: return None def refreshVehicleStateValue(self, stateID): if stateID in self.__cachedStateValues: self.onVehicleStateUpdated(stateID, self.__cachedStateValues[stateID]) def invalidate(self, state, value, vehicleID=0): if vehicleID != 0 and vehicleID != self.__vehicleID: return else: isStateChangeHandled = False if self.__isRqToSwitch and self.__waitingTI.isStarted(): self._waiting() if self.__updater is not None: isStateChangeHandled = self.__updater.handleStateChange(state, value) if not isStateChangeHandled: self.notifyStateChanged(state, value) return def switchToPostmortem(self, noRespawnPossible, respawnAvailable): self.__isRqToSwitch = False if avatar_getter.getPlayerVehicleID() == self.__vehicleID: if self.__updater is not None: self.__updater.stop() self.__updater.updateOnce() self.__isInPostmortem = True self.onPostMortemSwitched(noRespawnPossible, respawnAvailable) return def switchToOther(self, vehicleID): if vehicleID is None: self.notifyStateChanged(VEHICLE_VIEW_STATE.SWITCHING, 0) self.__needInvalidate = True return elif self.__vehicleID == vehicleID and not self.__needInvalidate: return else: self.__needInvalidate = False self.notifyStateChanged(VEHICLE_VIEW_STATE.SWITCHING, vehicleID) self.__waitingTI.stop() if self.__updater: self.__updater.stop() self.__vehicleID = vehicleID self.__isRqToSwitch = True self.notifyStateChanged(VEHICLE_VIEW_STATE.PLAYER_INFO, self.__vehicleID) self.__cachedStateValues.clear() self.__waitingTI.start() return def refreshObserverVehicleVisual(self): vehicle = self.getControllingVehicle() if vehicle is not None: self.onVehicleControlling(vehicle) return def movingToRespawn(self): self.__isInPostmortem = False self.notifyStateChanged(VEHICLE_VIEW_STATE.SWITCHING, 0) self.onRespawnBaseMoving() self.__cachedStateValues.clear() def _waiting(self): vehicle = BigWorld.entity(self.__vehicleID) if vehicle is not None and vehicle.isStarted: self.__waitingTI.stop() self._setup(vehicle) return def _setup(self, vehicle): if self.__updater is not None: self.__updater = self.__updater.switch(self.__vehicleID) if self.__isRqToSwitch: nationID = vehicle.typeDescriptor.type.id[0] notifications = avatar_getter.getSoundNotifications() if notifications is not None: notifications.clear() SoundGroups.g_instance.soundModes.setCurrentNation(nations.NAMES[nationID]) self.onVehicleControlling(vehicle) if VEHICLE_VIEW_STATE.DUAL_GUN_STATE_UPDATED in self.__cachedStateValues.keys(): self.onVehicleStateUpdated(VEHICLE_VIEW_STATE.DUAL_GUN_STATE_UPDATED, self.getStateValue(VEHICLE_VIEW_STATE.DUAL_GUN_STATE_UPDATED)) if self.__updater is not None: self.__updater.start() return
class IndicatorManager(object): def __init__(self, config): self.__config = config self.__panels = [] self.__isSetHandler = False self.__visible = False self.__crosshairPosition = [0, 0] self.__onShoot = None self.__onShot = None self.__onShotResult = None self.__intervalHandlers = Event() self.__eventHandlers = Event() self.__keyHandlers = {} interval = config['common']['updateInterval'] self.__timeInterval = TimeInterval(interval, self, 'onWatchStats') g_eventBus.addListener(events.AppLifeCycleEvent.INITIALIZED, self.onAppInitialized) g_eventBus.addListener(events.AppLifeCycleEvent.DESTROYED, self.onAppDestroyed) appLoader = dependency.instance(IAppLoader) appLoader.onGUISpaceEntered += self.onGUISpaceEntered appLoader.onGUISpaceLeft += self.onGUISpaceLeft g_statsCollector.eventHandlers.clear() def initPanel(self): _logger.info('initPanel') self.addHandler() g_statsCollector.eventHandlers += self.onEvent g_statsCollector.start() g_statsCollector.updateArenaInfo() clientStatus = g_statsCollector.clientStatus self.__panels = [] self.__keyHandlers = {} for paneldef in self.__config.get('panelDefs', []): if paneldef['channel'] == 'indicator': panel = StatsIndicator(paneldef, clientStatus) if 'events' in paneldef: self.__eventHandlers += panel.onEvent else: self.__intervalHandlers += panel.update if 'toggleKey' in paneldef['style']: keyName = paneldef['style']['toggleKey'] keyId = getattr(Keys, keyName) if keyId not in self.__keyHandlers: self.__keyHandlers[keyId] = Event() self.__keyHandlers[keyId] += panel.toggle elif paneldef['channel'] == 'status': panel = StatsLogger(paneldef, clientStatus) self.__intervalHandlers += panel.update elif paneldef['channel'] == 'event': panel = EventLogger(paneldef, clientStatus) self.__eventHandlers += panel.onEvent self.__panels.append(panel) session = dependency.instance(IBattleSessionProvider) ctrl = session.shared.crosshair self.changeView(ctrl.getViewID()) self.updateScreenPosition() self.updateCrosshairPosition() def finiPanel(self): _logger.info('finiPanel') self.stopIntervalTimer() self.invisiblePanel() self.removeHandler() for panel in self.__panels: if isinstance(panel, EventLogger): _logger.info('del EventLogger.onEvent') g_statsCollector.eventHandlers -= panel.onEvent self.__panels = [] self.__keyHandlers = {} def addHandler(self): if self.__isSetHandler: return self.__isSetHandler = True arena = BigWorld.player().arena arena.onPeriodChange += self.onArenaPeriodChange session = dependency.instance(IBattleSessionProvider) ctl = session.shared.vehicleState ctl.onVehicleStateUpdated += self.onVehicleStateUpdated ctl = session.shared.crosshair ctl.onCrosshairViewChanged += self.onCrosshairViewChanged ctl.onCrosshairPositionChanged += self.onCrosshairPositionChanged self.__crosshairPosition = list(ctl.getScaledPosition()) g_guiResetters.add(self.onScreenResolutionChanged) g_keyEventHandlers.add(self.__handleKeyEvent) def removeHandler(self): if not self.__isSetHandler: return self.__isSetHandler = False player = BigWorld.player() if player: arena = player.arena if arena: arena.onPeriodChange -= self.onArenaPeriodChange session = dependency.instance(IBattleSessionProvider) ctl = session.shared.vehicleState if ctl: ctl.onVehicleStateUpdated -= self.onVehicleStateUpdated ctl = session.shared.crosshair if ctl: ctl.onCrosshairViewChanged -= self.onCrosshairViewChanged ctl.onCrosshairPositionChanged -= self.onCrosshairPositionChanged g_guiResetters.remove(self.onScreenResolutionChanged) g_keyEventHandlers.remove(self.__handleKeyEvent) def visiblePanel(self): if self.__visible: return self.__visible = True _logger.info('panel.start') for panel in self.__panels: panel.start() def invisiblePanel(self): if not self.__visible: return self.__visible = False _logger.info('panel.stop') for panel in self.__panels: panel.stop() def startIntervalTimer(self): if not self.__timeInterval.isStarted(): _logger.info('TimeInterval: start') self.__timeInterval.start() def stopIntervalTimer(self): if self.__timeInterval.isStarted(): _logger.info('TimeInterval: stop') self.__timeInterval.stop() def changeView(self, viewID): _logger.debug('changeView: %s', CROSSHAIR_VIEW_SYMBOL[viewID]) for panel in self.__panels: panel.changeView(viewID) def updateScreenPosition(self): width, height = GUI.screenResolution() _logger.debug('updateScreenPosition: (%d, %d)', width, height) for panel in self.__panels: panel.updateScreenPosition(width, height) def updateCrosshairPosition(self): x, y = self.__crosshairPosition _logger.debug('updateCrosshairPosition: (%d, %d)', x, y) for panel in self.__panels: _logger.debug('updateCrosshairPosition: call panel: "%s"', panel.name) panel.updateCrosshairPosition(x, y) def onAppInitialized(self, event): if event.ns != APP_NAME_SPACE.SF_BATTLE: return _logger.info('AppLifeCycleEvent.INITIALIZED: SF_BATTLE') #self.initPanel() def onAppDestroyed(self, event): if event.ns != APP_NAME_SPACE.SF_BATTLE: return _logger.info('AppLifeCycleEvent.DESTROYED: SF_BATTLE') self.finiPanel() def onGUISpaceEntered(self, spaceID): if spaceID != GuiGlobalSpaceID.BATTLE: return _logger.info('onGUISpaceEnterd: %s', GUI_GLOBAL_SPACE_SYMBOL[spaceID]) self.initPanel() def onGUISpaceLeft(self, spaceID): if spaceID != GuiGlobalSpaceID.BATTLE: return _logger.info('onGUISpaceLeft: %s', GUI_GLOBAL_SPACE_SYMBOL[spaceID]) self.finiPanel() def onArenaPeriodChange(self, period, periodEndTime, periodLength, periodAdditionalInfo): _logger.info('onArenaPeriodChange: %s', ARENA_PERIOD_SYMBOL[period]) if period == ARENA_PERIOD.PREBATTLE: self.visiblePanel() elif period == ARENA_PERIOD.BATTLE: self.visiblePanel() self.startIntervalTimer() elif period == ARENA_PERIOD.AFTERBATTLE: self.stopIntervalTimer() self.invisiblePanel() def onVehicleStateUpdated(self, stateID, value): if stateID == VEHICLE_VIEW_STATE.DESTROYED: _logger.info('onVehicleStateUpdated: VEHICLE_VIEW_STATE.DESTROYED') self.stopIntervalTimer() self.invisiblePanel() def onScreenResolutionChanged(self): width, height = GUI.screenResolution() _logger.debug('onScreenResolutionChanged: (%d, %d)', width, height) for panel in self.__panels: panel.updateScreenPosition(width, height) def onCrosshairViewChanged(self, viewID): _logger.debug('crosshairViewChanged: %s', CROSSHAIR_VIEW_SYMBOL[viewID]) self.changeView(viewID) def onCrosshairPositionChanged(self, x, y): _logger.debug('onCrosshairPositionChanged: (%d, %d)', x, y) self.__crosshairPosition = [x, y] for panel in self.__panels: panel.updateCrosshairPosition(x, y) def onWatchStats(self): BigWorld.callback(0, partial(self.__intervalHandlers)) def onEvent(self, reason): BigWorld.callback(0, partial(self.__eventHandlers, reason)) def __handleKeyEvent(self, event): if event.isKeyDown() and not event.isRepeatedEvent(): handlers = self.__keyHandlers.get(event.key, None) if handlers is not None: handlers() return True return False
class _EngineStateHandler(_StateHandler): """ The class provides logic to track engine state changes and vehicle movement changes. All logic is based on changes of the current gear. """ __slots__ = ('__weakref__', '__gear', '__vehMoveAnimTimer', '__engineStartAnimTimer') def __init__(self, updater, vehicle): """ Constructor. Initializes internal variables based on vehicle state. :param updater: An instance of _VehicleUpdater class, that creates this handler. :param vehicle: Vehicle to be tracked. :return: """ super(_EngineStateHandler, self).__init__(updater) self.__gear = vehicle.appearance.gear if vehicle is not None else _STOPPED_ENGINE_GEAR self.__vehMoveAnimTimer = TimeInterval(_VEHICLE_ANIM_DURATION, self, '_stopVehMoveAnim') self.__engineStartAnimTimer = TimeInterval(_VEHICLE_ANIM_DURATION, self, '_stopEngineStartAnim') return def clear(self): """ Resets internal variables. """ self.__gear = _STOPPED_ENGINE_GEAR self._stopVehMoveAnim() self._stopEngineStartAnim() def _invalidate(self, vehicle): """ The method determines whether one of the following events has occurred and exposes the appropriate state change to the updater: 1. Vehicle starts moving. 2. Engine is started. By these events, appropriate animations are run on UI. To stop animations appropriate state change event is sent in _VEHICLE_ANIM_DURATION time. Note that animation duration depends on sound effect (track length). But right now there is no way to determine effect duration. Therefore for all vehicles the same constant is used. :param vehicle: A reference to the tracked vehicle(BW entity). :return: The state change if any. Otherwise an empty list. """ states = [] gear = vehicle.appearance.gear if self.__gear != gear: if not self.__gear and gear > 0: if not self.__vehMoveAnimTimer.isStarted(): states.append((VEHICLE_VIEW_STATE.VEHICLE_MOVEMENT_STATE, True)) self.__vehMoveAnimTimer.start() elif self.__gear == _STOPPED_ENGINE_GEAR and gear >= 0: if not self.__engineStartAnimTimer.isStarted(): states.append((VEHICLE_VIEW_STATE.VEHICLE_ENGINE_STATE, True)) self.__engineStartAnimTimer.start() elif self.__gear > 0 and not self.__gear: pass elif self.__gear >= 0 and gear == _STOPPED_ENGINE_GEAR: pass self.__gear = gear return states def _stopVehMoveAnim(self): """ Stops 'vehicle start' animation by sending the appropriate event. """ if self.__vehMoveAnimTimer.isStarted(): self.__vehMoveAnimTimer.stop() self.notifyStateChanged(VEHICLE_VIEW_STATE.VEHICLE_MOVEMENT_STATE, False) def _stopEngineStartAnim(self): """ Stops 'engine start' animation by sending the appropriate event. """ if self.__engineStartAnimTimer.isStarted(): self.__engineStartAnimTimer.stop() self.notifyStateChanged(VEHICLE_VIEW_STATE.VEHICLE_ENGINE_STATE, False)
class VehicleStateController(object): def __init__(self): super(VehicleStateController, self).__init__() self.__eManager = Event.EventManager() self.onVehicleStateUpdated = Event.Event(self.__eManager) self.onVehicleControlling = Event.Event(self.__eManager) self.onPostMortemSwitched = Event.Event(self.__eManager) self.onRespawnBaseMoving = Event.Event(self.__eManager) self.__waitingTI = TimeInterval(VEHICLE_WAINING_INTERVAL, self, '_waiting') self.__updateTI = TimeInterval(VEHICLE_UPDATE_INTERVAL, self, '_update') self.__vehicleID = 0 self.__updater = _PlayerVehicleUpdater() self.__isRqToSwitch = False def clear(self): if self.__waitingTI: self.__waitingTI.stop() self.__waitingTI = None if self.__updateTI: self.__updateTI.stop() self.__updateTI = None self.__vehicleID = 0 self.__isRqToSwitch = False self.__updater = None self.__eManager.clear() return def setPlayerVehicle(self, vehicleID): self.onVehicleStateUpdated(VEHICLE_VIEW_STATE.PLAYER_INFO, vehicleID) self.__vehicleID = vehicleID self.__waitingTI.start() def getControllingVehicle(self): vehicle = None if self.__vehicleID: vehicle = BigWorld.entity(self.__vehicleID) return vehicle def invalidate(self, state, value): if state == VEHICLE_VIEW_STATE.DESTROYED: self.__updateTI.stop() self.onVehicleStateUpdated(state, value) def switchToPostmortem(self): self.__isRqToSwitch = False if avatar_getter.getPlayerVehicleID() == self.__vehicleID: self.__waitingTI.stop() self.__updateTI.stop() self.onPostMortemSwitched() def switchToAnother(self, vehicleID): if self.__vehicleID == vehicleID or vehicleID is None: return else: if self.__updater: self.__updater.clear() self.__waitingTI.stop() self.__updateTI.stop() self.__vehicleID = vehicleID self.__isRqToSwitch = True self.onVehicleStateUpdated(VEHICLE_VIEW_STATE.PLAYER_INFO, self.__vehicleID) self.__waitingTI.start() return def _waiting(self): vehicle = BigWorld.entity(self.__vehicleID) if vehicle is not None: self.__waitingTI.stop() self._setup(vehicle) return def _update(self): states = self.__updater.update(self.__vehicleID, self.__updateTI) if states is not None: for item in states: self.onVehicleStateUpdated(*item) return def _setup(self, vehicle): self.__updater = self.__updater.switch(vehicle.isPlayer) if self.__isRqToSwitch: nationID = vehicle.typeDescriptor.type.id[0] notifications = avatar_getter.getSoundNotifications() if notifications: notifications.clear() SoundGroups.g_instance.soundModes.setCurrentNation(nations.NAMES[nationID]) self.onVehicleControlling(vehicle) if not vehicle.isAlive(): self.onVehicleStateUpdated(VEHICLE_VIEW_STATE.DESTROYED, None) else: self.__updateTI.start() return
class DamageLog(object): def __init__(self): self.msgNoAlt = [] self.msgAlt = [] self.isDownAlt = False self.lastHit = '' self.currentTime = '' self.isAlive = True self.oldHealth = None self.maxHealth = None self.lineFire = -1 self.totalFireDmg = 0 self.lineFireOld = -1 self.numberFire = 0 self.timerLastHit = None self.timerReloadAttacker = None self.copyMacros = {} self.macros = { 'number': 0, 'critical-hit': '', 'vehicle': '', 'name': '', 'vtype': '', 'clan': '', 'c:costShell': 'do_not_know', 'dmg-kind': '', 'c:dmg-kind': '', 'c:vtype': '', 'type-shell': '', 'costShell': 'do_not_know', 'dmg': '', 'timer': 0, 'c:team-dmg': '', 'c:hit-effects': '', 'comp-name': '', 'level': '', 'clanicon': '', 'clannb': '', 'marksOnGun': '', 'squad-num': None, 'dmg-ratio': '', 'hit-effects': '', 'team-dmg': '', 'c:type-shell': '', 'splash-hit': '' } self.data = { 'attackReasonID': 0, 'n': 0, 'maxHitEffectCode': -1, 'isFire': False, 'splash-hit': 'no-splash', 'compName': 'do_not_know', 'dmg': 0 } self.config = {} def reset(self): self.msgNoAlt = [] self.msgAlt = [] self.isDownAlt = False self.lastHit = '' self.currentTime = '' self.isAlive = True self.oldHealth = None self.maxHealth = None self.lineFire = -1 self.totalFireDmg = 0 self.lineFireOld = -1 self.numberFire = 0 if (self.timerLastHit is not None) and (self.timerLastHit.isStarted): self.timerLastHit.stop() if (self.timerReloadAttacker is not None) and (self.timerReloadAttacker.isStarted): self.timerReloadAttacker.stop() self.copyMacros = {} self.macros = { 'number': 0, 'critical-hit': '', 'vehicle': '', 'name': '', 'vtype': '', 'clan': '', 'c:costShell': 'do_not_know', 'dmg-kind': '', 'c:dmg-kind': '', 'c:vtype': '', 'type-shell': '', 'costShell': 'do_not_know', 'dmg': '', 'timer': 0, 'c:team-dmg': '', 'c:hit-effects': '', 'comp-name': '', 'level': '', 'clanicon': '', 'clannb': '', 'marksOnGun': '', 'squad-num': None, 'dmg-ratio': '', 'hit-effects': '', 'team-dmg': '', 'c:type-shell': '', 'splash-hit': '' } self.data = { 'attackReasonID': 0, 'n': 0, 'maxHitEffectCode': -1, 'isFire': False, 'splash-hit': 'no-splash', 'compName': 'do_not_know', 'dmg': 0 } self.config = {} def parser(self, strHTML, fire=False): old_strHTML = '' while old_strHTML != strHTML: old_strHTML = strHTML if fire: for s in MACROS_NAME: strHTML = strHTML.replace('{{' + s + '}}', str(self.copyMacros[s])) else: for s in MACROS_NAME: strHTML = strHTML.replace('{{' + s + '}}', str(self.macros[s])) return strHTML def addStringLog(self): if self.data['attackReasonID'] == 1: if self.lineFireOld > -1: if self.lineFire > -1: self.lineFireOld = self.lineFire self.msgNoAlt[self.lineFireOld] = self.parser( config.get('damageLog/log/formatHistory'), True) self.msgAlt[self.lineFireOld] = self.parser( config.get('damageLog/log/formatHistoryAlt'), True) if self.lineFire == -1: self.lineFireOld = self.lineFire else: self.copyMacros = self.macros.copy() self.msgNoAlt.insert( 0, self.parser(config.get('damageLog/log/formatHistory'))) self.msgAlt.insert( 0, self.parser(config.get('damageLog/log/formatHistoryAlt'))) self.lineFireOld = self.lineFire else: self.msgNoAlt.insert( 0, self.parser(config.get('damageLog/log/formatHistory'))) self.msgAlt.insert( 0, self.parser(config.get('damageLog/log/formatHistoryAlt'))) self.numberFire += 1 as_event('ON_HIT') def hideLastHit(self): self.lastHit = '' self.timerLastHit.stop() as_event('ON_LAST_HIT') def updateLastHit(self): timeDisplayLastHit = float( config.get('damageLog/lastHit/timeDisplayLastHit')) self.lastHit = self.parser( config.get('damageLog/lastHit/formatLastHit')) #, True) if self.lastHit: if (self.timerLastHit is not None) and (self.timerLastHit.isStarted): self.timerLastHit.stop() self.timerLastHit = TimeInterval(timeDisplayLastHit, self, 'hideLastHit') self.timerLastHit.start() as_event('ON_LAST_HIT') def afterTimerReload(self): self.currentTime = '' self.timerReloadAttacker.stop() as_event('ON_TIMER_RELOAD') def currentTimeReload(self): self.macros['timer'] = round(self.finishTime - BigWorld.serverTime(), 1) self.config['timeTextAfterReload'] = float( config.get('damageLog/timeReload/timeTextAfterReload')) if self.macros['timer'] > 0: self.currentTime = self.parser( config.get('damageLog/timeReload/formatTimer')) else: self.timerReloadAttacker.stop() if self.config['timeTextAfterReload'] > 0: self.timerReloadAttacker = TimeInterval( self.config['timeTextAfterReload'], self, 'afterTimerReload') self.currentTime = self.parser( config.get('damageLog/timeReload/formatTimerAfterReload')) self.timerReloadAttacker.start() else: self.currentTime = '' as_event('ON_TIMER_RELOAD') def timeReload(self): reload_orig = self.data['typeDescriptor'].gun['reloadTime'] crew = 0.94 if self.data['typeDescriptor'].miscAttrs[ 'crewLevelIncrease'] != 0 else 1 if (self.data['typeDescriptor'].gun['clip'][0] == 1) and ( self.data['typeDescriptor'].miscAttrs['gunReloadTimeFactor'] != 0): rammer = self.data['typeDescriptor'].miscAttrs[ 'gunReloadTimeFactor'] else: rammer = 1 self.macros['timer'] = round(reload_orig * crew * rammer, 1) self.currentTime = self.parser( config.get('damageLog/timeReload/formatTimer')) as_event('ON_TIMER_RELOAD') self.finishTime = self.macros['timer'] + BigWorld.serverTime() if (self.timerReloadAttacker is not None) and (self.timerReloadAttacker.isStarted): self.timerReloadAttacker.stop() self.timerReloadAttacker = TimeInterval(0.1, self, 'currentTimeReload') self.timerReloadAttacker.start() def readyConfig(self, section): self.config['vehicleClass'] = keyLower(config.get(section + 'vtype')) self.config['colorShell'] = keyLower( config.get(section + 'c:costShell')) self.config['costShell'] = keyLower(config.get(section + 'costShell')) self.config['color_type_hit'] = keyLower( keyLower(config.get(section + 'c:dmg-kind'))) self.config['colorVehicleClass'] = keyLower( config.get(section + 'c:vtype')) self.config['type_hit'] = keyLower(config.get(section + 'dmg-kind')) self.config['c:team-dmg'] = keyLower(config.get(section + 'c:team-dmg')) self.config['team-dmg'] = keyLower(config.get(section + 'team-dmg')) self.config['compNames'] = keyLower(config.get(section + 'comp-name')) self.config['splash-hit'] = keyLower(config.get(section + 'splash-hit')) if self.data['maxHitEffectCode'] == 5: self.config['critical-hit'] = config.get(section + 'critical-hit/critical') else: self.config['critical-hit'] = config.get( section + 'critical-hit/no-critical') self.config['showHitNoDamage'] = config.get(section + 'showHitNoDamage') self.config['hitEffect'] = keyLower(config.get(section + 'hit-effects')) self.config['colorHitEffect'] = keyLower( config.get(section + 'c:hit-effects')) self.config['type-shell'] = keyLower(config.get(section + 'type-shell')) self.config['c:type-shell'] = keyLower( config.get(section + 'c:type-shell')) def setMacros(self): self.macros['c:team-dmg'] = self.config['c:team-dmg'].get( self.data['team-dmg'], '') self.macros['team-dmg'] = self.config['team-dmg'].get( self.data['team-dmg'], '') self.macros['vtype'] = self.config['vehicleClass'].get( self.data['attackerVehicleType'], 'not_vehicle') self.macros['c:costShell'] = self.config['colorShell'].get( self.data['costShell']) self.macros['costShell'] = self.config['costShell'].get( self.data['costShell']) self.macros['c:dmg-kind'] = self.config['color_type_hit'].get( ATTACK_REASONS[self.data['attackReasonID']]) self.macros['dmg-kind'] = self.config['type_hit'].get( ATTACK_REASONS[self.data['attackReasonID']], 'reason: %s' % self.data['attackReasonID']) self.macros['c:vtype'] = self.config['colorVehicleClass'].get( self.data['attackerVehicleType'], 'not_vehicle') self.macros['comp-name'] = self.config['compNames'].get( self.data['compName'], '') self.macros['splash-hit'] = self.config['splash-hit'].get( self.data['splash-hit'], '') self.macros['critical-hit'] = self.config['critical-hit'] self.macros['type-shell'] = self.config['type-shell'].get( self.data['shellKind'], '') self.macros['c:type-shell'] = self.config['c:type-shell'].get( self.data['shellKind'], '') self.macros['c:hit-effects'] = self.config['colorHitEffect'].get( self.data['HIT_EFFECT_CODE']) self.macros['hit-effects'] = self.config['hitEffect'][ self.data['HIT_EFFECT_CODE']] self.macros['dmg'] = self.data['dmg'] self.macros['dmg-ratio'] = self.data['dmg-ratio'] def groupDamageFire(self): if self.data['attackReasonID'] == 1 and config.get( 'damageLog/log/groupDamagesFromFire'): if (self.lineFire == -1) and (self.lineFireOld == -1): self.lineFire = 0 self.data['n'] += 1 else: self.copyMacros['dmg'] += self.data['dmg'] self.copyMacros['dmg-ratio'] += self.data['dmg-ratio'] else: if (self.config['showHitNoDamage']) or (self.data['isDamage']): self.data['n'] += 1 if self.lineFire > -1: self.lineFire += 1 def updateData(self): player = BigWorld.player() self.data['dmg-ratio'] = self.data['dmg'] * 100 // self.maxHealth if self.data['attackerID'] != 0: attacker = player.arena.vehicles.get(self.data['attackerID']) entity = BigWorld.entity(self.data['attackerID']) statXVM = _stat.players.get(self.data['attackerID']) self.data['team-dmg'] = 'do_not_know' if attacker['team'] != player.team: self.data['team-dmg'] = 'enemy-dmg' elif attacker['name'] == player.name: self.data['team-dmg'] = 'player' else: self.data['team-dmg'] = 'ally-dmg' self.data['typeDescriptor'] = attacker['vehicleType'] self.data['vehCD'] = attacker['vehicleType'].type.compactDescr self.data['attackerVehicleType'] = list( attacker['vehicleType'].type.tags.intersection( VEHICLE_CLASSES))[0].lower() self.data['shortUserString'] = self.data[ 'typeDescriptor'].type.shortUserString self.data['name'] = attacker['name'] self.data['clanAbbrev'] = attacker['clanAbbrev'] self.data['level'] = self.data['typeDescriptor'].level self.data['clanicon'] = _stat.getClanIcon(self.data['attackerID']) if (statXVM is not None) and (statXVM.squadnum > 0): self.data['squadnum'] = statXVM.squadnum else: self.data['squadnum'] = '' if entity is not None: self.data['marksOnGun'] = '_' + str( entity.publicInfo['marksOnGun']) else: self.data['marksOnGun'] = '' else: self.data['team-dmg'] = 'do_not_know' self.data['typeDescriptor'] = None self.data['vehCD'] = None self.data['attackerVehicleType'] = '' self.data['shortUserString'] = '' self.data['name'] = '' self.data['clanAbbrev'] = '' self.data['level'] = '' self.data['clanicon'] = '' self.data['squadnum'] = '' self.data['marksOnGun'] = '' self.updateMacros() def updateMacros(self): self.readyConfig('damageLog/log/') self.groupDamageFire() self.config['marksOnGun'] = config.get('texts/marksOnGun') if self.data['isFire'] and (self.data['attackReasonID'] == 1): self.macros['dmg'] = self.copyMacros['dmg'] else: self.macros['dmg'] = self.data['dmg'] self.macros['number'] = '{:0>2}'.format(self.data['n']) self.macros['vehicle'] = self.data['shortUserString'] self.macros['name'] = self.data['name'] self.macros['clannb'] = self.data['clanAbbrev'] self.macros['clan'] = '[' + self.data[ 'clanAbbrev'] + ']' if self.data['clanAbbrev'] else '' self.macros['level'] = self.data['level'] self.macros['clanicon'] = self.data.get('clanicon', '') self.macros['marksOnGun'] = self.config['marksOnGun'].get( self.data['marksOnGun'], '') self.macros['squad-num'] = self.data['squadnum'] self.setMacros() if self.config['showHitNoDamage']: self.addStringLog() elif self.data['isDamage']: self.addStringLog() self.readyConfig('damageLog/lastHit/') self.setMacros() if self.data['isFire'] and (self.data['attackReasonID'] == 1): self.macros['dmg'] = self.copyMacros['dmg'] if self.config['showHitNoDamage']: self.updateLastHit() elif self.data['isDamage']: self.updateLastHit() if (self.data['attackReasonID'] == 0) and (self.data['attackerID'] != 0): self.readyConfig('damageLog/timeReload/') self.setMacros() self.timeReload() if self.data['attackReasonID'] == 1 and config.get( 'damageLog/log/groupDamagesFromFire'): self.data['isFire'] = True if self.lineFireOld == -1: self.data['isFire'] = False def typeShell(self, effectsIndex): if (self.data['attackerID'] == 0) or (self.data['attackReasonID'] not in [0, 100]): self.data['costShell'] = 'do_not_know' self.data['shellKind'] = 'not_shell' return player = BigWorld.player() attacker = player.arena.vehicles.get(self.data['attackerID']) self.data['costShell'] = 'do_not_know' for shell in attacker['vehicleType'].gun['shots']: if effectsIndex == shell['shell']['effectsIndex']: self.data['shellKind'] = str(shell['shell']['kind']).lower() xmlPath = ITEM_DEFS_PATH + 'vehicles/' + nations.NAMES[ shell['shell']['id'][0]] + '/components/shells.xml' for name, subsection in ResMgr.openSection(xmlPath).items(): if name != 'icons': xmlCtx = (None, xmlPath + '/' + name) if _xml.readInt(xmlCtx, subsection, 'id', 0, 65535) == shell['shell']['id'][1]: price = _xml.readPrice(xmlCtx, subsection, 'price') self.data['costShell'] = 'gold-shell' if price[ 1] else 'silver-shell' break ResMgr.purge(xmlPath, True) break def showDamageFromShot(self, vehicle, attackerID, points, effectsIndex, damageFactor): if vehicle.isPlayerVehicle and self.isAlive: self.isAlive = vehicle.health > 0 self.data['isDamage'] = damageFactor > 0 maxHitEffectCode, decodedPoints = DamageFromShotDecoder.decodeHitPoints( points, vehicle.typeDescriptor) self.data['compName'] = decodedPoints[ 0].componentName if decodedPoints else 'do_not_know' self.data['maxHitEffectCode'] = maxHitEffectCode self.data['attackReasonID'] = 0 self.data['attackerID'] = attackerID self.data['isDamage'] = damageFactor > 0 self.data['splash-hit'] = 'no-splash' if (effectsIndex == 24) or (effectsIndex == 25): self.data['attackReasonID'] = effectsIndex self.typeShell(effectsIndex) if (maxHitEffectCode < 4): self.data['HIT_EFFECT_CODE'] = HIT_EFFECT_CODES[ maxHitEffectCode] self.data['dmg'] = 0 self.updateData() elif (maxHitEffectCode == 5) and (damageFactor == 0): self.data['HIT_EFFECT_CODE'] = 'armor_pierced_no_damage' self.data['dmg'] = 0 self.updateData() elif maxHitEffectCode == 4: self.data['HIT_EFFECT_CODE'] = 'armor_pierced' def showDamageFromExplosion(self, vehicle, attackerID, center, effectsIndex, damageFactor): if vehicle.isPlayerVehicle and self.isAlive: self.isAlive = vehicle.health > 0 self.data['isDamage'] = damageFactor > 0 # log('damageFactor = %s' % damageFactor) self.data['splash-hit'] = 'splash' self.data['attackerID'] = attackerID if (effectsIndex == 24) or (effectsIndex == 25): self.data['attackReasonID'] = effectsIndex self.typeShell(effectsIndex) if (damageFactor == 0): self.data['HIT_EFFECT_CODE'] = 'armor_pierced_no_damage' self.data['dmg'] = 0 self.updateData() def onHealthChanged(self, vehicle, newHealth, attackerID, attackReasonID): if vehicle.isPlayerVehicle: if (attackReasonID != 0) or (self.data['attackReasonID'] not in [24, 25]): # [24, 25, 100]): self.data['attackReasonID'] = attackReasonID self.data['isDamage'] = True if (attackReasonID != 0): # and (attackReasonID != 100): self.data['costShell'] = 'do_not_know' self.data['shellKind'] = 'not_shell' self.data['attackerID'] = attackerID self.data['dmg'] = self.oldHealth - newHealth self.oldHealth = newHealth self.data['HIT_EFFECT_CODE'] = 'armor_pierced' self.updateData()
class _EngineStateHandler(_StateHandler): """ The class provides logic to track engine state changes and vehicle movement changes. All logic is based on changes of the current gear. """ __slots__ = ('__weakref__', '__gear', '__vehMoveAnimTimer', '__engineStartAnimTimer') def __init__(self, updater, vehicle): """ Constructor. Initializes internal variables based on vehicle state. :param updater: An instance of _VehicleUpdater class, that creates this handler. :param vehicle: Vehicle to be tracked. :return: """ super(_EngineStateHandler, self).__init__(updater) if vehicle is not None and vehicle.appearance is not None: self.__gear = vehicle.appearance.gear else: self.__gear = _STOPPED_ENGINE_GEAR self.__vehMoveAnimTimer = TimeInterval(_VEHICLE_ANIM_DURATION, self, '_stopVehMoveAnim') self.__engineStartAnimTimer = TimeInterval(_VEHICLE_ANIM_DURATION, self, '_stopEngineStartAnim') return def clear(self): """ Resets internal variables. """ self.__gear = _STOPPED_ENGINE_GEAR self._stopVehMoveAnim() self._stopEngineStartAnim() def _invalidate(self, vehicle): """ The method determines whether one of the following events has occurred and exposes the appropriate state change to the updater: 1. Vehicle starts moving. 2. Engine is started. By these events, appropriate animations are run on UI. To stop animations appropriate state change event is sent in _VEHICLE_ANIM_DURATION time. Note that animation duration depends on sound effect (track length). But right now there is no way to determine effect duration. Therefore for all vehicles the same constant is used. :param vehicle: A reference to the tracked vehicle(BW entity). :return: The state change if any. Otherwise an empty list. """ states = [] if vehicle.appearance is not None: gear = vehicle.appearance.gear if self.__gear != gear: if not self.__gear and gear > 0: if not self.__vehMoveAnimTimer.isStarted(): states.append((VEHICLE_VIEW_STATE.VEHICLE_MOVEMENT_STATE, True)) self.__vehMoveAnimTimer.start() elif self.__gear == _STOPPED_ENGINE_GEAR and gear >= 0: if not self.__engineStartAnimTimer.isStarted(): states.append((VEHICLE_VIEW_STATE.VEHICLE_ENGINE_STATE, True)) self.__engineStartAnimTimer.start() elif self.__gear > 0 and not self.__gear: pass elif self.__gear >= 0 and gear == _STOPPED_ENGINE_GEAR: pass self.__gear = gear return states def _stopVehMoveAnim(self): """ Stops 'vehicle start' animation by sending the appropriate event. """ if self.__vehMoveAnimTimer.isStarted(): self.__vehMoveAnimTimer.stop() self.notifyStateChanged(VEHICLE_VIEW_STATE.VEHICLE_MOVEMENT_STATE, False) def _stopEngineStartAnim(self): """ Stops 'engine start' animation by sending the appropriate event. """ if self.__engineStartAnimTimer.isStarted(): self.__engineStartAnimTimer.stop() self.notifyStateChanged(VEHICLE_VIEW_STATE.VEHICLE_ENGINE_STATE, False)
class DebugPanel(UIInterface): __UPDATE_INTERVAL = 0.01 def __init__(self, parentUI): UIInterface.__init__(self) self.__ui = parentUI self.__timeInterval = None self.__performanceStats = _PerformanceStats() self.__performanceStats.populateUI(parentUI) return def start(self): self.__timeInterval = TimeInterval(self.__UPDATE_INTERVAL, self, '_DebugPanel__update') self.__timeInterval.start() self.__update() def destroy(self): self.__performanceStats.disposeUI() self.__performanceStats = None self.__timeInterval.stop() return def __update(self): player = BigWorld.player() if player is None or not hasattr(player, 'playerVehicleID'): return else: fps = 0 recordedFps = -1 ping = 0 isLaggingNow = False replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isPlaying and replayCtrl.fps > 0: fps = BigWorld.getFPS()[1] recordedFps = replayCtrl.fps ping = replayCtrl.ping isLaggingNow = replayCtrl.isLaggingNow else: isLaggingNow = player.filter.isLaggingNow if not isLaggingNow: for v in BigWorld.entities.values(): if _isVehicleEntity(v): if not v.isPlayer: if v.isAlive() and isinstance(v.filter, BigWorld.WGVehicleFilter) and v.filter.isLaggingNow: isLaggingNow = True break ping = min(BigWorld.LatencyInfo().value[3] * 1000, 999) if ping < 999: ping = max(1, ping - 500.0 * constants.SERVER_TICK_LENGTH) fpsInfo = BigWorld.getFPS() from helpers.statistics import g_statistics g_statistics.update(fpsInfo, ping, isLaggingNow) fps = fpsInfo[1] if replayCtrl.isRecording: replayCtrl.setFpsPingLag(fps, ping, isLaggingNow) try: self.__performanceStats.updateDebugInfo(int(fps), int(ping), isLaggingNow, int(recordedFps)) except: pass return
class _VehicleUpdater(object): """ The class implements logic for tracking changes of vehicle parameters in equal time intervals. It encapsulates different algorithms of tracking based on vehicle type. The inner logic is based on the custom state handlers (classes derived from _StateHandler). """ def __init__(self, vehCtrl, vehicleID): """ Constructor. Initializes internal variables. :param vehCtrl: Reference to vehicle state controller owning this updater. :param vehicleID: Unique identifier of vehicle to be tracked """ super(_VehicleUpdater, self).__init__() self.__isAlive = True self.__handlers = None self.__ctrl = weakref.proxy(vehCtrl) self.__vehicleID = vehicleID self.__updateTI = None self._setUpHandlers() return def handleStateChange(self, state, value): """ Represents a hook to catch states changes before the vehicle state controller propagates them to subscribers. Redirects the call to each handler to perform required logic. :param state: A state listed within VEHICLE_VIEW_STATE :param value: State value :return: True if any handler returns True. Otherwise - False. """ isStateHandled = False for handler in self.__handlers: isStateHandled |= handler.handleStateChange(state, value) return isStateHandled def switch(self, vehicleID): """ Switches the updater to another vehicle: reset internal states and handlers. :param vehicleID: Unique identifier of a new vehicle that will be tracked """ self.clear() self.__vehicleID = vehicleID self._setUpHandlers() return self def start(self): """ Sets up and starts the timer to invalidate handlers. """ if self.__updateTI is None: self.__updateTI = TimeInterval(VEHICLE_UPDATE_INTERVAL, self, '_update') self.__updateTI.start() return def stop(self): """ Stops and clears running timer (if any). """ if self.__updateTI is not None: self.__updateTI.stop() self.__updateTI = None return def clear(self): """ Clears internal variables and stops timer. """ self.stop() if self.__handlers is not None: for handler in self.__handlers: handler.clear() self.__handlers = None self.__vehicleID = None return def notifyStateChanged(self, state, value): """ The helper method to provide handler ability to notify subscribers about changes of vehicle's states through the vehicle state controller. :param state: A state listed within VEHICLE_VIEW_STATE :param value: State value. """ self.__ctrl.notifyStateChanged(state, value) def _update(self): """ Callback on timer tick event. Initiates invalidation of all handlers, get all states changes and redirects them to the vehicle state controller by emitting appropriate events. """ states = [] vehicle = BigWorld.entity(self.__vehicleID) if vehicle is not None and vehicle.isStarted: if not vehicle.isAlive() and self.__isAlive: self.__isAlive = False states.append((VEHICLE_VIEW_STATE.DESTROYED, None)) for handler in self.__handlers: newStates = handler(vehicle) states.extend(newStates) for item in states: self.notifyStateChanged(*item) return def _setUpHandlers(self): """ Determines a list of handlers based on vehicle type and sets up them. """ vehicle = BigWorld.entity(self.__vehicleID) if vehicle is not None: isPlayerVehicle = vehicle.isPlayerVehicle if isPlayerVehicle: self.__handlers = (_SpeedStateHandler(self, True), _RpmStateHandler(self, vehicle), _EngineStateHandler(self, vehicle)) else: self.__handlers = (_HealthStateHandler(self), _SpeedStateHandler(self, False), _RpmStateHandler(self, vehicle), _EngineStateHandler(self, vehicle)) return
class BaseMarkerController(IArenaVehiclesController): _UPDATE_TICK_LENGTH = 0.01 def __init__(self): super(BaseMarkerController, self).__init__() self.onTickUpdate = Event.Event() self._gui = None self._attachGUIToMarkersCallback = {} self._markers = {} self._updateTI = None self._globalVisibility = True return def init(self): _logger.debug('BaseMarkerController.init') self._gui = MarkerGUIProvider(self.getPluginID()) g_eventBus.addListener(events.GameEvent.GUI_VISIBILITY, self._handleGUIVisibility, scope=EVENT_BUS_SCOPE.BATTLE) @property def allMarkers(self): return self._markers.values() @property def allMarkersID(self): return self._markers.keys() def getPluginID(self): raise NotImplementedError def createMarker(self, matrix, markerType, clazz=AreaMarker, bitMask=0): markerData = MarkerParamsFactory.getMarkerParams( matrix, markerType, bitMask) return clazz(markerData) def addMarker(self, marker): markerID = marker.markerID if markerID in self._markers: _logger.error('Marker with Id=%s exists already', markerID) marker.clear() return None else: self._attachGUIToMarkersCallback[markerID] = BigWorld.callback( 0, partial(self._attachGUIToMarkers, markerID)) self._checkGlobalVisibilityForMarker(marker) self._markers[markerID] = marker self.checkStartTimer() return markerID def setMarkerMatrix(self, markerID, matrix): marker = self._markers.get(markerID, None) if marker: marker.setMatrix(matrix) return def removeMarker(self, markerID): if markerID not in self._markers: return else: if markerID in self._attachGUIToMarkersCallback: BigWorld.cancelCallback( self._attachGUIToMarkersCallback[markerID]) self._attachGUIToMarkersCallback.pop(markerID) else: self._markers[markerID].detachGUI() self._markers[markerID].clear() self._markers.pop(markerID, None) return def removeAllMarkers(self): for markerID in self._markers: if markerID in self._attachGUIToMarkersCallback: BigWorld.cancelCallback( self._attachGUIToMarkersCallback[markerID]) self._attachGUIToMarkersCallback.pop(markerID) else: self._markers[markerID].detachGUI() self._markers[markerID].clear() self._markers.clear() def showMarkers(self, unblock=True): if not self._globalVisibility: return for markerID in self._markers.iterkeys(): self.showMarkersById(markerID, unblock) self.checkStartTimer() def hideMarkers(self, block=True): for marker in self._markers.values(): marker.setVisible(False) if block: marker.blockChangVisibility = True if self._updateTI is not None: self._updateTI.stop() return def showMarkersById(self, markerID, unblock=True): player = BigWorld.player() marker = self._markers.get(markerID, None) if marker: if unblock: marker.blockChangVisibility = False if not self._globalVisibility: return if marker.isEmpty(): return conditionDistance = marker.disappearingRadius if conditionDistance > 0: distanceToArea = BaseMarkerController.getDistanceToArea( marker, player) hide = conditionDistance < distanceToArea if marker.reverseDisappearing else conditionDistance > distanceToArea if hide: marker.setVisible(False) return marker.setVisible(True) self.checkStartTimer() return def hideMarkersById(self, markerID, block=True): if markerID in self._markers.keys(): marker = self._markers[markerID] marker.setVisible(False) if block: marker.blockChangVisibility = True def getMarkerById(self, markerID): return self._markers.get(markerID) @staticmethod def getDistanceToArea(marker, player): absDistance = (marker.getMarkerPosition() - player.getOwnVehiclePosition()).length distanceToArea = max(0, absDistance - marker.areaRadius) return distanceToArea def start(self): if self._gui is None: return else: if self._updateTI: self._updateTI.stop() for markerID in self._markers.iterkeys(): if markerID not in self._attachGUIToMarkersCallback: self._attachGUIToMarkersCallback[ markerID] = BigWorld.callback( 0.0, partial(self._attachGUIToMarkers, markerID=markerID)) self._updateTI = TimeInterval(self._UPDATE_TICK_LENGTH, self, '_tickUpdate') self._updateTI.start() return def checkStartTimer(self): if self._markers and self._updateTI and not self._updateTI.isStarted(): self.start() def stop(self): if self._updateTI is not None: self._updateTI.stop() self._updateTI = None self._clear() return def checkStopTimer(self): if not self._markers and self._updateTI and self._updateTI.isStarted(): self._updateTI.stop() def _tickUpdate(self): self.onTickUpdate() self.checkStopTimer() def _clear(self): g_eventBus.removeListener(events.GameEvent.GUI_VISIBILITY, self._handleGUIVisibility, scope=EVENT_BUS_SCOPE.BATTLE) self.removeAllMarkers() self._gui = None return def _attachGUIToMarkers(self, markerID): self._attachGUIToMarkersCallback[markerID] = None if self._gui and markerID in self._markers: marker = self._markers[markerID] if self._checkInitedPlugin(marker): self._attachGUIToMarkersCallback.pop(markerID) self._markers[markerID].attachGUI(self._gui) return self._attachGUIToMarkersCallback[markerID] = BigWorld.callback( 0, partial(self._attachGUIToMarkers, markerID)) return def _handleGUIVisibility(self, event): self._globalVisibility = event.ctx['visible'] if self._globalVisibility: self.showMarkers(unblock=False) else: self.hideMarkers(block=False) def _checkInitedPlugin(self, marker): if marker.hasMarker2D() and self._gui.getMarkers2DPlugin() is None: return False else: return False if marker.hasMinimap( ) and self._gui.getMinimapPlugin() is None else True def _checkGlobalVisibilityForMarker(self, marker): if not self._globalVisibility: marker.setVisible(False)