tasks.py (7026B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\behaviors\tasks.py 2 import weakref 3 from collections import defaultdict 4 from behaviors import status 5 from behaviors.blackboards import scopes, BlackboardDeletedError 6 from behaviors.blackboards.scopes import ItemScope 7 from brennivin.itertoolsext import Bundle 8 from ccpProfile import TimedFunction 9 import weakness 10 import logging 11 logger = logging.getLogger(__name__) 12 13 class TaskAttributeMissingError(Exception): 14 pass 15 16 17 class Task(object): 18 __attributes__ = {} 19 20 def __init__(self, attributes = None): 21 self.SetAttributes(attributes or Bundle()) 22 self.status = None 23 self.SetStatusToInvalid() 24 self.exitObserver = None 25 self.context = None 26 self.behaviorTree = None 27 28 def OnEnter(self): 29 self.SetStatusToRunning() 30 31 def OnExit(self): 32 pass 33 34 def Update(self): 35 pass 36 37 def CleanUp(self): 38 self.SetStatusToInvalid() 39 40 def Tick(self, behaviorTree, context): 41 if self.status is status.TaskInvalidStatus: 42 self.SetEnvironment(behaviorTree, context) 43 self.OnEnter() 44 self.Update() 45 self.OnStatusUpdate() 46 47 def NotifyExited(self): 48 if self.exitObserver: 49 self.exitObserver(self) 50 51 def SetExitObserver(self, exitObserver): 52 self.exitObserver = weakness.callable_proxy(exitObserver) 53 54 def Exit(self): 55 self.NotifyExited() 56 self.OnExit() 57 58 def SetAttributes(self, attributes): 59 self.attributes = attributes 60 61 def HasSubTasks(self): 62 return False 63 64 def SetEnvironment(self, behaviorTree, context): 65 self.behaviorTree = weakref.proxy(behaviorTree) 66 self.context = weakref.proxy(context) 67 68 def GetChannelFromAddress(self, address): 69 channel_cache = self.context.task_channel_cache[self] 70 if address in channel_cache: 71 return channel_cache[address] 72 else: 73 channel = scopes.GetChannelFromAddress(self.context, address) 74 channel_cache[address] = channel 75 return channel 76 77 @TimedFunction('behaviors::tasks::Task::GetLastBlackboardValue') 78 def GetLastBlackboardValue(self, address): 79 return self.GetChannelFromAddress(address).GetLastMessageValue() 80 81 def GetLastBlackboardValueWithMaxAge(self, address, maxAge): 82 return self.GetChannelFromAddress(address).GetLastMessageValueWithMaxAge(maxAge) 83 84 @TimedFunction('behaviors::tasks::Task::SendBlackboardValue') 85 def SendBlackboardValue(self, address, value): 86 return self.GetChannelFromAddress(address).SendMessage(value) 87 88 def SubscribeToBlackboard(self, address, handler): 89 self.GetChannelFromAddress(address).AddObserver(handler) 90 91 def UnsubscribeToBlackboard(self, address, handler): 92 try: 93 self.GetChannelFromAddress(address).RemoveObserver(handler) 94 except BlackboardDeletedError: 95 pass 96 97 def GetEventMessenger(self): 98 return self.context.ballpark.eventMessenger 99 100 def SubscribeItem(self, itemID, messageId, handler): 101 self.GetEventMessenger().SubscribeItem(itemID, messageId, handler) 102 103 def UnsubscribeItem(self, itemID, messageId, handler): 104 try: 105 self.GetEventMessenger().UnsubscribeItem(itemID, messageId, handler) 106 except ReferenceError: 107 logger.debug('Unable to unsubscribe from message as behavior is probably dead and context reference is lost. (itemID=%s, messageId=%, handler=%s)', itemID, messageId, handler) 108 109 def SetStatusToInvalid(self): 110 self.status = status.TaskInvalidStatus 111 112 def SetStatusToSuccess(self): 113 self.status = status.TaskSuccessStatus 114 115 def SetStatusToFailed(self): 116 self.status = status.TaskFailureStatus 117 118 def SetStatusToSuspended(self): 119 self.status = status.TaskSuspendedStatus 120 121 def SetStatusToRunning(self): 122 self.status = status.TaskRunningStatus 123 124 def SetStatusToBlocked(self): 125 self.status = status.TaskBlockingStatus 126 127 def IsInvalid(self): 128 return self.status is status.TaskInvalidStatus 129 130 def IsSuspended(self): 131 return self.status == status.TaskSuspendedStatus 132 133 def IsRunning(self): 134 return self.status == status.TaskRunningStatus 135 136 def IsSuccessful(self): 137 return self.status == status.TaskSuccessStatus 138 139 def IsFailed(self): 140 return self.status == status.TaskFailureStatus 141 142 def IsBlocked(self): 143 return self.status == status.TaskBlockingStatus 144 145 def SetStatusToSuccessIfTrueElseToFailed(self, value): 146 if value: 147 self.SetStatusToSuccess() 148 else: 149 self.SetStatusToFailed() 150 151 def GetMessageChannelForItemId(self, itemId, channelAddress): 152 scope = ItemScope(itemId) 153 return self.context.blackboardManager.GetBlackboard(scope).GetMessageChannel(channelAddress) 154 155 def GetMessageChannelForGroupId(self, groupId, channelAddress): 156 scope = scopes.EntityGroupScope(groupId) 157 return self.context.blackboardManager.GetBlackboard(scope).GetMessageChannel(channelAddress) 158 159 def HasAttribute(self, attributeName): 160 return hasattr(self.attributes, attributeName) and getattr(self.attributes, attributeName) is not None 161 162 def GetTaskName(self): 163 return type(self).__name__ 164 165 def GetContextValue(self, valueName): 166 return self.context.task_cache[self].get(valueName) 167 168 def SetContextValue(self, valueName, value): 169 self.context.task_cache[self][valueName] = value 170 171 def HasContextValue(self, valueName): 172 return valueName in self.context.task_cache[self] 173 174 def ResetBlackboardAddressCache(self): 175 self.context.task_channel_cache = defaultdict(dict) 176 177 def OnStatusUpdate(self): 178 self.status.OnUpdated(self) 179 180 181 class BlockingTask(Task): 182 183 def OnEnter(self): 184 self.SetStatusToBlocked() 185 self.behaviorTree.BlockReset(self) 186 187 def OnExit(self): 188 self.behaviorTree.UnblockReset(self) 189 190 191 class MonitorTask(Task): 192 193 @TimedFunction('behaviors::tasks::MonitorTask::OnEnter') 194 def OnEnter(self): 195 item_id = self._get_item_id() 196 if item_id is None: 197 self.SetStatusToFailed() 198 return 199 self.SubscribeItem(self._get_item_id(), self._get_message(), self._self_process_message) 200 self.SetStatusToSuccess() 201 202 def _get_item_id(self): 203 return self.context.myItemId 204 205 def _get_message(self): 206 raise NotImplementedError 207 208 @TimedFunction('behaviors::tasks::MonitorTask::_self_process_message') 209 def _self_process_message(self, *args): 210 if self._can_process_message(*args): 211 self.behaviorTree.RequestReset(requestedBy=self) 212 213 def _can_process_message(self, *args): 214 return True 215 216 def CleanUp(self): 217 if not self.IsInvalid(): 218 self.UnsubscribeItem(self._get_item_id(), self._get_message(), self._self_process_message) 219 self.SetStatusToInvalid()