NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

incursionSvc.py (20004B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\incursionSvc.py
      2 import carbonui.fontconst
      3 from carbon.common.script.sys.service import Service
      4 from carbonui.decorative.panelUnderlay import PanelUnderlay
      5 from grouprewards import REWARD_TYPE_ISK
      6 from grouprewards.data import get_immediate_reward_tables
      7 from grouprewards.data import get_max_player_count_from_reward_tables
      8 from grouprewards.data import get_max_reward_from_tables_with_reward_type
      9 from grouprewards.data import get_min_player_count_from_reward_tables
     10 from grouprewards.data import get_reward_for_player_count
     11 from grouprewards.data import is_security_criteria_all
     12 from grouprewards.data import is_security_criteria_high
     13 from grouprewards.data import is_security_criteria_low
     14 import blue
     15 import uthread
     16 import math
     17 import localization
     18 from eve.client.script.parklife.environmentSvc import GetEnvironmentService
     19 from eveservices.xmppchat import GetChatService
     20 from fsdBuiltData.common.soundIDs import GetSoundEventName
     21 from fsdBuiltData.client.environmentTemplates import INCURSION_ENVIRONMENT_TEMPLATE_ID
     22 from talecommon.const import INCURSION_TEMPLATE_CLASSES
     23 from talecommon.const import templateClass
     24 from eve.client.script.ui.control.eveLabel import Label
     25 from eve.client.script.ui.control.eveLabel import EveLabelSmall, EveLabelLarge
     26 import carbonui.const as uiconst
     27 from carbonui.primitives.container import Container
     28 from carbonui.primitives.transform import Transform
     29 from carbonui.graphs.graph import GraphArea
     30 from carbonui.graphs.grid import Grid
     31 from carbonui.graphs.linegraph import LineGraph
     32 from carbonui.util.color import Color
     33 import carbonui.graphs.axislabels as axislabels
     34 import carbonui.graphs.axis as axis
     35 INCURSION_CHAT_WARNING_DELAY = 20
     36 INCURSION_CHAT_CLOSE_DELAY = 120
     37 COLOR_HIGH_SEC = (0.0,
     38  0.65,
     39  0.0,
     40  1.0)
     41 COLOR_LOW_NULL_SEC = (1.0,
     42  0.0,
     43  0.0,
     44  1.0)
     45 INCURSION_ENVIRONMENT_TEMPLATE = 2
     46 
     47 class IncursionSvc(Service):
     48     __guid__ = 'svc.incursion'
     49     __notifyevents__ = ['OnTaleRemove', 'OnSessionChanged', 'OnTaleData']
     50     __startupdependencies__ = ['settings']
     51 
     52     def Run(self, *args):
     53         Service.Run(self, *args)
     54         self.incursionData = None
     55         self.enableSoundOverrides = False
     56         self.stationAudioPlaying = False
     57         self.addStationSoundThreadRunning = False
     58         self.isDisablingHud = False
     59         self.isActivatingHud = False
     60         self.incursionChatInfoByTaleId = {}
     61         self.waitingIncursionChannelTaleID = set()
     62         self.rewardsByID = {}
     63         self.soundUrlByKey = {'hangar': 10004,
     64          const.groupStation: 10007,
     65          const.groupAsteroidBelt: 10003,
     66          'enterSystem': 10005}
     67 
     68     def OnTaleData(self, solarSystemID, data):
     69         for taleData in data.itervalues():
     70             self.SetIncursion(taleData, fadeEffect=False, reason='Entered incursion system')
     71 
     72     def SetIncursion(self, data, fadeEffect = False, reason = None):
     73         if data.templateClassID in INCURSION_TEMPLATE_CLASSES:
     74             self.LogInfo('Starting the incursion UI for tale', data.taleID, '. Reason:', reason)
     75             self.incursionData = data
     76             self.enableSoundOverrides = True
     77             self.JoinIncursionChat(data.taleID)
     78             soundURL = self.GetSoundUrlByKey('enterSystem')
     79             if soundURL is not None:
     80                 sm.GetService('audio').SendUIEvent(soundURL)
     81             if session.stationid is not None:
     82                 self.AddIncursionStationSoundIfApplicable()
     83             sm.GetService('infoPanel').UpdateIncursionsPanel()
     84             GetEnvironmentService().AddSystemEnvironment('incursion', INCURSION_ENVIRONMENT_TEMPLATE_ID)
     85 
     86     def OnTaleRemove(self, taleID, templateClassID, templateID):
     87         if templateClassID not in INCURSION_TEMPLATE_CLASSES:
     88             return
     89         if self.incursionData is None:
     90             return
     91         self.LogInfo('OnTaleRemove', taleID)
     92         self.enableSoundOverrides = False
     93         GetEnvironmentService().RemoveEnvironment('incursion')
     94         self.incursionData = None
     95         sm.GetService('infoPanel').UpdateIncursionsPanel()
     96         self.StartTimeoutOfIncursionChat(taleID)
     97 
     98     def OnSessionChanged(self, isremote, sess, change):
     99         for taleID in self.incursionChatInfoByTaleId:
    100             self.StartTimeoutOfIncursionChat(taleID)
    101 
    102         if 'solarsystemid2' in change:
    103             oldSolarsystem, newSolarsystem = change['solarsystemid2']
    104             if self.incursionData:
    105                 if self.IsSystemInIncursion(oldSolarsystem):
    106                     self.enableSoundOverrides = False
    107                 if self.IsSystemInIncursion(newSolarsystem):
    108                     self.enableSoundOverrides = True
    109                 else:
    110                     self.incursionData = None
    111                 sm.GetService('infoPanel').UpdateIncursionsPanel()
    112         if 'stationid' in change:
    113             self.stationAudioPlaying = False
    114             oldStationID, newStationID = change['stationid']
    115             if newStationID != None:
    116                 self.AddIncursionStationSoundIfApplicable()
    117 
    118     def IsSystemInIncursion(self, solarsystemID):
    119         return self.incursionData is not None and solarsystemID in self.incursionData.incursedSystems
    120 
    121     def GetMusicState(self, solarsystemid):
    122         if self.IsSystemInIncursion(solarsystemid):
    123             if self.incursionData is not None:
    124                 return getattr(self.incursionData, 'musicState', None)
    125 
    126     def _EndTimeoutOfIncursionChat(self, taleID):
    127         if taleID in self.waitingIncursionChannelTaleID:
    128             self.waitingIncursionChannelTaleID.remove(taleID)
    129 
    130     def IsTaleInTheCurrentSystem(self, taleID):
    131         if self.incursionData is not None:
    132             if self.incursionData.taleID == taleID:
    133                 return True
    134         return False
    135 
    136     def IsIncursionActive(self):
    137         if self.incursionData is not None:
    138             return self.incursionData.templateClassID in INCURSION_TEMPLATE_CLASSES
    139         return False
    140 
    141     def GetActiveIncursionData(self):
    142         return self.incursionData
    143 
    144     def TimeoutOfIncursionChat_Thread(self, taleID):
    145         blue.pyos.synchro.SleepWallclock(INCURSION_CHAT_WARNING_DELAY * 1000)
    146         if self.IsTaleInTheCurrentSystem(taleID):
    147             self._EndTimeoutOfIncursionChat(taleID)
    148             return
    149         channelID = self._GetChannelId(taleID)
    150         self._AnnounceChatClosure(channelID)
    151         blue.pyos.synchro.SleepWallclock(INCURSION_CHAT_CLOSE_DELAY * 1000)
    152         if self.IsTaleInTheCurrentSystem(taleID):
    153             self._EndTimeoutOfIncursionChat(taleID)
    154             return
    155         GetChatService().LeaveChannel(channelID)
    156         if taleID in self.incursionChatInfoByTaleId:
    157             del self.incursionChatInfoByTaleId[taleID]
    158         self._EndTimeoutOfIncursionChat(taleID)
    159 
    160     def _GetChannelId(self, taleId):
    161         return self.incursionChatInfoByTaleId[taleId]['incursionType'] + '_' + str(taleId)
    162 
    163     def _AnnounceChatClosure(self, channelID):
    164         window = GetChatService().GetGroupChatWindow(channelID)
    165         if window:
    166             window.Receive(const.ownerSystem, localization.GetByLabel('UI/Incursion/LeaveChat', minutesRemaining=INCURSION_CHAT_CLOSE_DELAY / 60))
    167 
    168     def StartTimeoutOfIncursionChat(self, taleID):
    169         if taleID not in self.waitingIncursionChannelTaleID:
    170             self.waitingIncursionChannelTaleID.add(taleID)
    171             uthread.new(self.TimeoutOfIncursionChat_Thread, taleID).context = 'IncursionSvc::StartTimeoutOfIncursionChat'
    172 
    173     def JoinIncursionChat(self, taleID):
    174         uthread.new(self._JoinIncursionChat, taleID)
    175 
    176     def _JoinIncursionChat(self, taleID):
    177         while not sm.GetService('settings').IsCharSettingsLoaded():
    178             blue.synchro.Yield()
    179 
    180         if not hasattr(self.incursionData, 'hasChat') or not self.incursionData.hasChat:
    181             return
    182         if taleID not in self.incursionChatInfoByTaleId:
    183             self._SetIncursionChatInfo(taleID)
    184             channelID = self._GetChannelId(taleID)
    185             GetChatService().JoinChannel(channelID)
    186             self._PostIncursionChatAnnouncement(channelID)
    187         else:
    188             channelID = self._GetChannelId(taleID)
    189             GetChatService().JoinChannel(channelID)
    190 
    191     def _PostIncursionChatAnnouncement(self, channelID):
    192         retries = 0
    193         while retries < 3:
    194             window = GetChatService().GetGroupChatWindow(channelID)
    195             if window:
    196                 break
    197             blue.synchro.SleepWallclock(1000)
    198             retries += 1
    199 
    200         if not window or not self.incursionData.chatAnnouncementMessageId:
    201             return
    202         if self._IsConstellationIncursion():
    203             constellationName = cfg.evelocations.Get(session.constellationid).name
    204             message = localization.GetByMessageID(self.incursionData.chatAnnouncementMessageId, constellationName=constellationName)
    205         elif self._IsSpreadingIncursion():
    206             message = localization.GetByMessageID(self.incursionData.chatAnnouncementMessageId)
    207         else:
    208             return
    209         window.Receive(const.ownerSystem, message)
    210 
    211     def _SetIncursionChatInfo(self, taleID):
    212         self.incursionChatInfoByTaleId[taleID] = {'constellationId': session.constellationid,
    213          'distributionNameId': self.incursionData.templateNameID}
    214         self.incursionChatInfoByTaleId[taleID]['incursionType'] = ''
    215         if self._IsConstellationIncursion():
    216             self.incursionChatInfoByTaleId[taleID]['incursionType'] = 'incursion'
    217         elif self._IsSpreadingIncursion():
    218             self.incursionChatInfoByTaleId[taleID]['incursionType'] = 'spreadingIncursion'
    219 
    220     def _IsConstellationIncursion(self):
    221         return self.incursionData.templateClassID == templateClass.incursion
    222 
    223     def _IsSpreadingIncursion(self):
    224         return self.incursionData.templateClassID == templateClass.spreadingIncursion
    225 
    226     def GetConstellationNameFromTaleIDForIncursionChat(self, taleID):
    227         if taleID in self.incursionChatInfoByTaleId and self.incursionChatInfoByTaleId[taleID]['constellationId']:
    228             return cfg.evelocations.Get(self.incursionChatInfoByTaleId[taleID]['constellationId']).name
    229         return ''
    230 
    231     def GetDistributionName(self, taleId):
    232         distributionNameId = self.incursionChatInfoByTaleId.get(taleId, None)['distributionNameId']
    233         if distributionNameId:
    234             return localization.GetByMessageID(distributionNameId)
    235         return localization.GetByLabel('UI/Generic/Unknown')
    236 
    237     def GetDelayedRewards(self, rewardGroupID):
    238         return self.GetDelayedRewardsByGroupIDs([rewardGroupID]).get(rewardGroupID)
    239 
    240     def GetDelayedRewardsByGroupIDs(self, rewardGroupIDs):
    241         rewardGroupIDs.sort()
    242         rewardsByRewardGroupID = sm.RemoteSvc('rewardMgr').GetDelayedRewardsByGroupIDs(tuple(rewardGroupIDs))
    243         return rewardsByRewardGroupID
    244 
    245     def DoRewardChart(self, rewardID, parent):
    246 
    247         def GetRewardData():
    248             maxRewardValue = 0
    249             minPlayerCount = 0
    250             maxPlayerCount = 0
    251             allSecurityBandTable = None
    252             lowSecurityBandTable = None
    253             highSecurityBandTable = None
    254             rewardTables = get_immediate_reward_tables(rewardID)
    255             for rewardTable in rewardTables:
    256                 if not rewardTables:
    257                     continue
    258                 if is_security_criteria_all(rewardTable):
    259                     maxRewardValue = get_max_reward_from_tables_with_reward_type(rewardTables, REWARD_TYPE_ISK)
    260                     minPlayerCount = get_min_player_count_from_reward_tables(rewardTables)
    261                     maxPlayerCount = get_max_player_count_from_reward_tables(rewardTables)
    262                     allSecurityBandTable = rewardTables[0]
    263                     break
    264                 if is_security_criteria_high(rewardTable):
    265                     highSecurityBandTable = rewardTable
    266                 elif is_security_criteria_low(rewardTable):
    267                     lowSecurityBandTable = rewardTable
    268                 else:
    269                     continue
    270                 maxRewardValue = max(maxRewardValue, get_max_reward_from_tables_with_reward_type(rewardTables, REWARD_TYPE_ISK))
    271                 minPlayerCount = min(minPlayerCount, get_min_player_count_from_reward_tables(rewardTables))
    272                 maxPlayerCount = max(maxPlayerCount, get_max_player_count_from_reward_tables(rewardTables))
    273 
    274             scale = 1.0 / maxRewardValue
    275             majorTick = (maxPlayerCount - minPlayerCount) / 4
    276             majorTick = 1 if majorTick < 2 else majorTick
    277             data1 = []
    278             data2 = [] if allSecurityBandTable is None else None
    279             labels = []
    280             for x in xrange(minPlayerCount, maxPlayerCount + 1):
    281                 if allSecurityBandTable is not None:
    282                     quantity = get_reward_for_player_count(allSecurityBandTable, x) * scale
    283                     data1.append(quantity)
    284                 else:
    285                     quantityHigh = get_reward_for_player_count(highSecurityBandTable, x) * scale
    286                     quantityLow = get_reward_for_player_count(lowSecurityBandTable, x) * scale
    287                     data1.append(quantityHigh)
    288                     data2.append(quantityLow)
    289                 labels.append(x)
    290 
    291             return (data1,
    292              data2,
    293              labels,
    294              majorTick)
    295 
    296         valuesHigh, valuesLow, players, majorTick = GetRewardData()
    297         axisValues = (0.0, 0.5, 1.0)
    298         main = PanelUnderlay(parent=parent, align=uiconst.TOALL, bgColor=Color.GetGrayRGBA(0.0, 0.25))
    299 
    300         def valueFilter(x):
    301             if x not in axisValues:
    302                 return ''
    303             return str(x)
    304 
    305         def playerFilter(x):
    306             if x % majorTick != 0:
    307                 return ''
    308             return str(int(x))
    309 
    310         verticalAxis = axis.AutoTicksAxis((0.0, 1.0), tickCount=5, margins=(0.01, 0.01), labelFormat=valueFilter)
    311         horizontalAxis = axis.CategoryAxis(players, labelFormat=playerFilter)
    312         EveLabelLarge(parent=main, align=uiconst.TOTOP, padTop=6, padBottom=0, text='<center>%s</center>' % localization.GetByLabel('UI/Incursion/Reward/Title'))
    313         EveLabelSmall(parent=main, align=uiconst.TOBOTTOM, width=120, padBottom=6, text='<center>%s</center>' % localization.GetByLabel('UI/Incursion/Reward/NumberPilots'))
    314         axislabels.AxisLabels(parent=main, align=uiconst.TORIGHT, width=24, axis=verticalAxis, orientation=axis.AxisOrientation.VERTICAL, minFactor=1.0, maxFactor=0.0, padBottom=17, padTop=7)
    315         axislabels.AxisLabels(parent=main, align=uiconst.TOBOTTOM, height=24, axis=horizontalAxis, orientation=axis.AxisOrientation.HORIZONTAL, textAlignment=uiconst.CENTER, padLeft=24)
    316         sideTransform = Transform(name='myTransform', parent=main, align=uiconst.TOLEFT, width=24, rotationCenter=(0.5, 0.5), rotation=math.pi / 2)
    317         EveLabelSmall(name='myLabel', parent=sideTransform, width=120, align=uiconst.CENTER, text='<center>%s</center>' % localization.GetByLabel('UI/Incursion/Reward/PayoutMultiplier'))
    318         legendContainer = Container(name='container', parent=main, height=14, align=uiconst.TOTOP)
    319         graphArea = GraphArea(name='graph', parent=main, align=uiconst.TOALL, bgColor=Color.GetGrayRGBA(0.2, 0.5))
    320         graphArea.AddAxis(axis.AxisOrientation.HORIZONTAL, horizontalAxis, 0.0, 1.0)
    321         graphArea.AddAxis(axis.AxisOrientation.VERTICAL, verticalAxis, 1.0, 0.0)
    322         Grid(parent=graphArea, axis=verticalAxis, orientation=axis.AxisOrientation.VERTICAL, color=Color.GetGrayRGBA(1.0, 0.4))
    323 
    324         def _createLegend(items, legendParent):
    325             container = legendParent
    326             for item, text in items:
    327                 item.height = 10
    328                 item.width = 10
    329                 item.align = uiconst.TOLEFT
    330                 item.padding = (6, 1, 2, 3)
    331                 item.SetParent(container)
    332                 Label(parent=container, align=uiconst.TOLEFT, text=text, color=(1.0, 1.0, 1.0, 0.5), fontsize=carbonui.fontconst.EVE_SMALL_FONTSIZE)
    333 
    334         def _lineGraph(color, values):
    335             ranges = []
    336             i0 = 0
    337             while i0 < len(values) - 1:
    338                 val0 = values[i0]
    339                 repeatRange = [i0, i0]
    340                 i1 = i0 + 1
    341                 while i1 < len(values):
    342                     val1 = values[i1]
    343                     if val1 != val0:
    344                         break
    345                     else:
    346                         repeatRange[1] = i1
    347                     i1 += 1
    348 
    349                 i0 = i1
    350                 if repeatRange[0] != repeatRange[1]:
    351                     ranges.append(repeatRange)
    352 
    353             dataPoints = range(len(values))
    354             valuesPruned = values[:]
    355             ranges.reverse()
    356             for i0, i1 in ranges:
    357                 valuesPruned = valuesPruned[:i0 + 1] + valuesPruned[i1:]
    358                 dataPoints = dataPoints[:i0 + 1] + dataPoints[i1:]
    359 
    360             return LineGraph(parent=graphArea, categoryAxis=horizontalAxis, valueAxis=verticalAxis, values=valuesPruned, lineColor=color, lineWidth=1, dataPoints=dataPoints)
    361 
    362         l0 = _lineGraph(COLOR_HIGH_SEC, valuesHigh)
    363         label1 = localization.GetByLabel('UI/Common/Ratio')
    364         if valuesLow is not None:
    365             label1 = localization.GetByLabel('UI/Common/HighSec')
    366         legendItems = [(l0.GetLegendItem(), label1)]
    367         if valuesLow is not None:
    368             l1 = _lineGraph(COLOR_LOW_NULL_SEC, valuesLow)
    369             legendItems.append((l1.GetLegendItem(), localization.GetByLabel('UI/Common/LowNullSec')))
    370         _createLegend(legendItems, legendContainer)
    371 
    372     def GetSoundUrlByKey(self, key):
    373         if self.enableSoundOverrides == False:
    374             return
    375         soundID = self.soundUrlByKey.get(key, None)
    376         if soundID is not None:
    377             soundUrl = GetSoundEventName(soundID)
    378             if soundUrl is None:
    379                 self.LogError('Unable to find a sound for key', key, 'and soundID', soundID)
    380         else:
    381             soundUrl = None
    382         return soundUrl
    383 
    384     def AddIncursionStationSoundIfApplicable(self):
    385         if not self.addStationSoundThreadRunning and self.enableSoundOverrides:
    386             self.addStationSoundThreadRunning = True
    387             uthread.new(self.AddIncursionStationSoundIfApplicableThread).context = 'incursionSvc::AddIncursionStationSoundIfApplicableThread'
    388 
    389     def AddIncursionStationSoundIfApplicableThread(self):
    390         count = 0
    391         success = False
    392         while success == False and count < 60:
    393             blue.synchro.SleepWallclock(1000)
    394             count += 1
    395             if session.stationid is None:
    396                 success = True
    397                 break
    398             try:
    399                 if not self.stationAudioPlaying:
    400                     activeScene = sm.GetService('sceneManager').GetRegisteredScene('hangar')
    401                     stringToMatch = 'invisible_sound_locator_'
    402                     soundLocator = FindSoundLocatorThatStartsWith(activeScene, stringToMatch)
    403                     addedSound = self.GetSoundUrlByKey('hangar')
    404                     if addedSound is not None and soundLocator is not None:
    405                         ReplaceHangarSound(soundLocator, addedSound)
    406                         self.stationAudioPlaying = True
    407                         success = True
    408             except:
    409                 self.LogInfo('Could not add incursion station sound trying again in 1 second')
    410 
    411         if success == False:
    412             self.LogError('Incursion station audio could not be added after 60 tries')
    413         self.addStationSoundThreadRunning = False
    414 
    415 
    416 def FindSoundLocatorThatStartsWith(scene, startingString):
    417     for transform in scene.objects:
    418         if transform.name.startswith(startingString):
    419             return transform
    420 
    421 
    422 def ReplaceHangarSound(soundLocator, soundEvent):
    423     if not soundLocator.observers:
    424         return
    425     for objects in soundLocator.observers:
    426         objects.observer.SendEvent('fade_out')
    427 
    428     soundLocator.observers[0].observer.SendEvent(soundEvent[6:])