behaviortree.py (4194B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\behaviors\behaviortree.py 2 from collections import deque 3 import gametime 4 from ccpProfile import TimedFunction 5 import logging 6 import signals 7 from eveexceptions.exceptionEater import ExceptionEater 8 logger = logging.getLogger(__name__) 9 TICK_END_MARKER = None 10 MESSAGE_REQUEST_RESET = 'OnRequestReset' 11 MESSAGE_STEP = 'OnStep' 12 MESSAGE_RESET = 'OnReset' 13 MESSAGE_TICK_DONE = 'OnTickDone' 14 MESSAGE_BLOCK_RESET = 'OnBlockReset' 15 16 class UnrecoverableBehaviorError(Exception): 17 pass 18 19 20 class BehaviorTree(object): 21 22 def __init__(self, behaviorId = None, scopeType = None): 23 self.behaviorId = behaviorId 24 self.scopeType = scopeType 25 self._tasks = deque() 26 self._rootTask = None 27 self._isResetRequested = False 28 self._isResetBlocked = False 29 self._messenger = signals.Messenger() 30 31 def Release(self): 32 with ExceptionEater('CleanUp behavior tree'): 33 if self._rootTask is not None: 34 self._rootTask.CleanUp() 35 logger.debug('Cleaned up behaviors for behaviortree') 36 self._rootTask = None 37 self._messenger = None 38 39 def StartRootTask(self, rootTask): 40 self._rootTask = rootTask 41 rootTask.SetExitObserver(self.OnRootTaskTerminated) 42 self.StartTask(rootTask) 43 44 def AddEndMarker(self): 45 self._tasks.append(TICK_END_MARKER) 46 47 def StartTask(self, task): 48 self._tasks.appendleft(task) 49 50 def StartTaskNextTick(self, task): 51 self._tasks.append(task) 52 53 def GetTaskList(self): 54 return list(self._tasks) 55 56 def GetRootTask(self): 57 return self._rootTask 58 59 @TimedFunction('behaviors::behaviortree::BehaviorTree::Tick') 60 def Tick(self, context): 61 startTime = gametime.GetWallclockTimeNow() 62 self.ProcessResetRequest() 63 self.AddEndMarker() 64 while self.Step(context): 65 pass 66 67 self.SendMessage(MESSAGE_TICK_DONE, context) 68 updateTime = gametime.GetWallclockTimeNow() - startTime 69 context.statistics.update(updateTime) 70 71 @TimedFunction('behaviors::behaviortree::BehaviorTree::Step') 72 def Step(self, context): 73 task = self._tasks.popleft() 74 moreTasks = True 75 if task is TICK_END_MARKER: 76 moreTasks = False 77 else: 78 task.Tick(self, context) 79 context.statistics.add_tick() 80 self.SendMessage(MESSAGE_STEP, task=task) 81 return moreTasks 82 83 def BlockReset(self, blockingTask): 84 self._SetBlockReset(True, blockingTask) 85 86 def UnblockReset(self, blockingTask): 87 self._SetBlockReset(False, blockingTask) 88 89 def _SetBlockReset(self, isBlocking, blockingTask): 90 self.SendMessage(MESSAGE_BLOCK_RESET, isBlocking, blockingTask) 91 self._isResetBlocked = isBlocking 92 93 def RequestReset(self, requestedBy = None): 94 logger.debug("requested reset for behavior=%s by task=%s name='%s'", self.behaviorId, requestedBy.__class__.__name__, getattr(getattr(requestedBy, 'attributes', None), 'name', None)) 95 self._isResetRequested = True 96 self.SendMessage(MESSAGE_REQUEST_RESET, requestedBy=requestedBy) 97 self._UpdateStatistics(requestedBy) 98 99 def _UpdateStatistics(self, requestedBy): 100 self.GetRootTask().context.statistics.update_request_reset(requestedBy) 101 102 @TimedFunction('behaviors::behaviortree::BehaviorTree::Reset') 103 def Reset(self): 104 self._tasks.clear() 105 self._rootTask.CleanUp() 106 self.StartTask(self._rootTask) 107 self.SendMessage(MESSAGE_RESET) 108 109 def ProcessResetRequest(self): 110 if self._isResetRequested and not self._isResetBlocked: 111 self._isResetRequested = False 112 self.Reset() 113 114 def HasResetRequest(self): 115 return self._isResetRequested 116 117 def OnRootTaskTerminated(self, rootTask): 118 self.RequestReset(requestedBy=rootTask) 119 120 def GetMessenger(self): 121 return self._messenger 122 123 def SendMessage(self, messageName, *args, **kwargs): 124 self._messenger.SendMessage(messageName, *args, **kwargs) 125 126 def GetBehaviorId(self): 127 return self.behaviorId