bountySvc.py (13178B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\bountySvc.py 2 import blue 3 import uthread 4 import telemetry 5 import localization 6 from carbon.common.script.sys.service import Service 7 from eve.common.lib import appConst as const, killRightTracker 8 from eve.common.script.sys import idCheckers 9 from eve.common.script.util import bountyUtil 10 from eveexceptions import UserError 11 from globalConfig.getFunctions import IsPlayerBountyHidden 12 from caching.memoize import Memoize 13 from player_messaging.client.ui_message import prompt_player_fsd_dialog 14 15 class BountyService(Service): 16 __guid__ = 'svc.bountySvc' 17 __startupdependencies__ = ['machoNet'] 18 __notifyevents__ = ['DoBallsAdded', 19 'OnKillRightCreated', 20 'OnKillRightUsed', 21 'OnKillRightActivated', 22 'OnGlobalConfigChanged', 23 'OnKillRightForYouSold', 24 'OnSessionReset'] 25 DISABLE_BOUNTY_KEY = 'isDynamicBountiesAndKillRightsDisabled' 26 27 def __init__(self): 28 super(BountyService, self).__init__() 29 self.bounties = {} 30 self.cacheTime = 5 * const.MIN 31 self.myKillRights = None 32 self.killRightTracker = None 33 34 def Run(self, *args, **kwargs): 35 Service.Run(self, *args, **kwargs) 36 config = self.machoNet.GetGlobalConfig() 37 self._SetDisabledStatus(config) 38 self.Reset() 39 40 def Reset(self): 41 self.bounties = {} 42 self.myKillRights = None 43 self.killRightTracker = killRightTracker.KillRightTracker(self.FetchKillRightsFromServer, blue.os.GetWallclockTime, 5 * const.MIN) 44 45 def OnSessionReset(self): 46 self.GetMyBounties.clear_memoized() 47 self.Reset() 48 49 def _SetDisabledStatus(self, config): 50 self.isDisabled = int(config.get(self.DISABLE_BOUNTY_KEY, 0)) 51 52 def OnGlobalConfigChanged(self, config): 53 self._SetDisabledStatus(config) 54 55 def GetBounty(self, *ownerIDs): 56 if IsPlayerBountyHidden(self.machoNet): 57 return 0 58 ownerIDs = [ ownerID for ownerID in ownerIDs if ownerID is not None ] 59 self.FetchBounties(ownerIDs) 60 return sum((self.bounties[ownerID][0].bounty for ownerID in ownerIDs)) 61 62 def GetBountyFromCache(self, ownerID): 63 return self.bounties[ownerID][0].bounty 64 65 def GetBounties(self, *ownerIDs): 66 if IsPlayerBountyHidden(self.machoNet): 67 return {} 68 ownerIDs = [ ownerID for ownerID in ownerIDs if ownerID is not None ] 69 self.FetchBounties(ownerIDs) 70 return {ownerID:self.bounties[ownerID][0].bounty for ownerID in ownerIDs} 71 72 def AddToBounty(self, ownerID, amount): 73 newBounty = sm.ProxySvc('bountyProxy').AddToBounty(ownerID, amount) 74 bountyUtil.CacheBounties(self.bounties, [newBounty]) 75 self.GetMyBounties.clear_memoized() 76 77 def CanHaveBounty(self, slimItem): 78 if IsPlayerBountyHidden(self.machoNet): 79 return False 80 try: 81 categoryID = slimItem.categoryID 82 except AttributeError: 83 return False 84 85 if categoryID == const.categoryShip and slimItem.charID is not None: 86 return True 87 if categoryID == const.categoryStarbase: 88 return True 89 return False 90 91 def QuickHasBounty(self, slimItem): 92 if not self.CanHaveBounty(slimItem): 93 return False 94 for ownerID in (slimItem.charID, slimItem.corpID, slimItem.allianceID): 95 try: 96 bounty = self.bounties[ownerID][0].bounty 97 except KeyError: 98 bounty = 0 99 100 if bounty > 0: 101 return True 102 103 return False 104 105 def QuickHasKillRight(self, slimItem): 106 if getattr(slimItem, 'charID', None) is None: 107 return False 108 if self.killRightTracker.GetKillRightsFromCache(slimItem.charID): 109 return True 110 for killRight in self.GetMyKillRights(): 111 if killRight.fromID == session.charid and killRight.toID == slimItem.charID: 112 return True 113 114 return False 115 116 def FetchBounties(self, targetIDs): 117 bountiesToUpdate = {targetID for targetID in targetIDs if self.IsObsolete(targetID)} 118 self.LogInfo('FetchBounties - Got', len(bountiesToUpdate), 'that are not cached or expired') 119 if bountiesToUpdate: 120 bounties = [ bounty for targetID, bounty in self.GetBountiesFromServer(bountiesToUpdate) ] 121 bountyUtil.CacheBounties(self.bounties, bounties) 122 123 def IsObsolete(self, targetID, useTime = None): 124 if useTime is None: 125 useTime = blue.os.GetWallclockTime() 126 try: 127 return blue.os.GetWallclockTime() > self.bounties[targetID][1] + self.cacheTime 128 except KeyError: 129 return True 130 131 def GetBountiesFromServer(self, targetIDs): 132 return sm.ProxySvc('bountyProxy').GetBounties(targetIDs) 133 134 def DoBallsAdded(self, slimItems, *args, **kwargs): 135 uthread.pool('BountySvc::DoBallsAdded', self._DoBallsAdded, slimItems) 136 137 def OnKillRightCreated(self, killRightID, fromID, toID, expiryTime): 138 self.InvalidateGetMyKillRights() 139 140 def OnKillRightUsed(self, killRightID, toID): 141 try: 142 del self.killRightTracker.killRightsByToID[toID] 143 except KeyError: 144 pass 145 146 self.InvalidateGetMyKillRights() 147 148 def OnKillRightActivated(self): 149 prompt_player_fsd_dialog('CustomNotify', {'notify': localization.GetByLabel('UI/CharacterSheet/CharacterSheetWindow/KilLRightActivated')}) 150 151 def OnKillRightForYouSold(self, killRightID): 152 self.InvalidateGetMyKillRights() 153 sm.ScatterEvent('OnKillRightSold', killRightID) 154 155 @telemetry.ZONE_METHOD 156 def _DoBallsAdded(self, slimItems): 157 if self.isDisabled: 158 return 159 ownersToQuery = set() 160 charIDs = set() 161 validItemIDs = set() 162 for ball, slim in slimItems: 163 if slim.categoryID not in (const.categoryShip, const.categoryStarbase): 164 continue 165 if slim.charID is not None and idCheckers.IsOwner(slim.charID): 166 charIDs.add(slim.charID) 167 if slim.corpID is not None and idCheckers.IsOwner(slim.corpID): 168 ownersToQuery.add(slim.corpID) 169 validItemIDs.add(slim.itemID) 170 if slim.allianceID is not None and idCheckers.IsOwner(slim.allianceID): 171 ownersToQuery.add(slim.allianceID) 172 validItemIDs.add(slim.itemID) 173 174 self.LogInfo('_DoBallsAdded fetching possible bounties for', len(validItemIDs), 'entities with', len(ownersToQuery), 'seperate owners') 175 if ownersToQuery or charIDs: 176 self.FetchBountiesAndKillRightsFromServer(charIDs, ownersToQuery) 177 sm.ChainEvent('ProcessBountyInfoUpdated', validItemIDs) 178 179 def GetTopPilotBounties(self, page = 0): 180 return self.GetTopBounties(sm.ProxySvc('bountyProxy').GetTopPilotBounties, page) 181 182 def GetTopCorpBounties(self, page = 0): 183 return self.GetTopBounties(sm.ProxySvc('bountyProxy').GetTopCorpBounties, page) 184 185 def GetTopAllianceBounties(self, page = 0): 186 return self.GetTopBounties(sm.ProxySvc('bountyProxy').GetTopAllianceBounties, page) 187 188 def GetTopBounties(self, fetcher, page): 189 newBounties, lastFetchingTime = fetcher(page) 190 bountiesToCache = [ bounty for bounty in newBounties if self.IsObsolete(bounty.targetID, lastFetchingTime) ] 191 self.LogInfo('GetTopBounties::Got', len(newBounties), 'but caching', len(bountiesToCache)) 192 bountyUtil.CacheBounties(self.bounties, bountiesToCache) 193 return sorted(newBounties, key=lambda x: x.bounty, reverse=True) 194 195 def GetTopPilotBountyHunters(self, page = 0): 196 return sm.ProxySvc('bountyProxy').GetTopPilotBountyHunters(page)[0] 197 198 def GetTopCorporationBountyHunters(self, page = 0): 199 return sm.ProxySvc('bountyProxy').GetTopCorporationBountyHunters(page)[0] 200 201 def GetTopAllianceBountyHunters(self, page = 0): 202 return sm.ProxySvc('bountyProxy').GetTopAllianceBountyHunters(page)[0] 203 204 @Memoize 205 def GetMyBounties(self): 206 return sm.ProxySvc('bountyProxy').GetMyBounties() 207 208 def GMReimburseBounties(self): 209 sm.ProxySvc('bountyProxy').GMReimburseBounties() 210 211 def GMClearBountyCache(self): 212 objectCaching = sm.GetService('objectCaching') 213 for entry in objectCaching.cachedMethodCalls.keys(): 214 if entry[0] == 'bountyProxy': 215 objectCaching.InvalidateCachedMethodCall(*entry) 216 217 sm.ProxySvc('bountyProxy').GMClearBountyCache() 218 219 def SearchBounties(self, targetID): 220 if idCheckers.IsCharacter(targetID): 221 fetcher = sm.ProxySvc('bountyProxy').SearchCharBounties 222 elif idCheckers.IsCorporation(targetID): 223 fetcher = sm.ProxySvc('bountyProxy').SearchCorpBounties 224 elif idCheckers.IsAlliance(targetID): 225 fetcher = sm.ProxySvc('bountyProxy').SearchAllianceBounties 226 bountyAndRank = fetcher(targetID) 227 bountyUtil.CacheBounties(self.bounties, [ bounty for rank, bounty in bountyAndRank ]) 228 return bountyAndRank 229 230 def CancelSellKillRight(self, killRightID, toID): 231 sm.ProxySvc('bountyProxy').CancelSellKillRight(killRightID, toID) 232 self.killRightTracker.OnKillRightRemoved(toID, killRightID) 233 self.InvalidateGetMyKillRights() 234 sm.ScatterEvent('OnKillRightSellCancel', killRightID) 235 236 def SellKillRight(self, killRightID, price, restrictedTo = None): 237 killRights = sm.ProxySvc('bountyProxy').SellKillRight(killRightID, price, restrictedTo) 238 if killRights is not None: 239 for killRight in killRights: 240 self.killRightTracker.OnKillRightAdded(killRight) 241 242 self.InvalidateGetMyKillRights() 243 244 def GetMyKillRights(self): 245 if self.myKillRights is not None: 246 return self.myKillRights 247 else: 248 killRights = sm.ProxySvc('bountyProxy').GetMyKillRights() 249 self.myKillRights = killRights 250 return killRights 251 252 def GetKillRights(self, toIDs): 253 toIDs = [ toID for toID in toIDs if toID is not None and idCheckers.IsCharacter(toID) and idCheckers.IsOwner(toID) ] 254 validIDs = [session.charid, session.corpid] 255 if session.allianceid is not None: 256 validIDs.append(session.allianceid) 257 return self.killRightTracker.GetKillRights(toIDs, *validIDs) 258 259 def FetchKillRightsFromServer(self, toIDs): 260 self.LogInfo('Fetching', len(toIDs), 'kill rights from the server') 261 return sm.ProxySvc('bountyProxy').GetKillRightsOnCharacters(toIDs) 262 263 def FetchBountiesAndKillRightsFromServer(self, charIDs, ownerIDs): 264 bountiesToFetch = {ownerID for ownerID in ownerIDs if self.IsObsolete(ownerID)} 265 killRightsToFetch = self.killRightTracker.GetInvalidKillRights(charIDs) 266 self.LogInfo('FetchBountiesAndKillRightsFromServer - fetching', len(bountiesToFetch), 'for bounties and', len(killRightsToFetch), 'for killRights') 267 if not (bountiesToFetch or killRightsToFetch): 268 self.LogInfo('FetchBountiesAndKillRightsFromServer - Bailing out because nothing to fetch') 269 return 270 myKillRights, (bounties, killRights) = uthread.parallel([(self.GetMyKillRights, ()), (sm.ProxySvc('bountyProxy').GetBountiesAndKillRights, (bountiesToFetch, killRightsToFetch))]) 271 bountyUtil.CacheBounties(self.bounties, [ bounty for targetID, bounty in bounties ]) 272 self.killRightTracker.CacheKillRights(killRights, killRightsToFetch) 273 274 def ClearAllKillRightData(self): 275 self.killRightTracker.killRightsByToID.clear() 276 self.InvalidateGetMyKillRights() 277 278 def GetBestKillRight(self, toID): 279 for killRight in self.GetMyKillRights(): 280 if killRight.fromID == session.charid and killRight.toID == toID: 281 return (killRight.killRightID, None) 282 283 killRights = self.GetKillRights([toID]) 284 if not killRights: 285 return (None, None) 286 killRight = min(killRights, key=lambda x: x.price) 287 return (killRight.killRightID, killRight.price) 288 289 def BuyKillRight(self, killRightID, toID, shipID, price): 290 try: 291 sm.RemoteSvc('killRightMgr').BuyKillRight(killRightID, price) 292 except UserError as e: 293 if e.msg in ('NoValidKillRight', 'KillRightExpired', 'KillRightNotForSale'): 294 self.killRightTracker.OnKillRightRemoved(toID, killRightID) 295 sm.ChainEvent('ProcessBountyInfoUpdated', [shipID]) 296 raise 297 298 def ActivateKillRight(self, killRightID, toID, shipID): 299 try: 300 sm.RemoteSvc('killRightMgr').ActivateKillRight(killRightID) 301 except UserError as e: 302 if e.msg in ('NoValidKillRight', 'KillRightExpired'): 303 self.killRightTracker.OnKillRightRemoved(toID, killRightID) 304 self.InvalidateGetMyKillRights() 305 sm.ChainEvent('ProcessBountyInfoUpdated', [shipID]) 306 raise 307 308 def InvalidateGetMyKillRights(self): 309 self.myKillRights = None 310 sm.GetService('objectCaching').InvalidateCachedMethodCall('bountyProxy', 'GetMyKillRights')