behaviortreemonitor.py (6564B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\behaviors\debugging\behaviortreemonitor.py 2 from behaviors import behaviortree 3 import logging 4 from behaviors.blackboards import scopes, BlackboardDeletedError 5 from behaviors.composites import Composite 6 from behaviors.debugging.tools import DepthFirstTaskIterator 7 from cluster import SERVICE_BEYONCE 8 import gametime 9 logger = logging.getLogger(__name__) 10 11 class BehaviorTreeMonitor(object): 12 __machoresolve__ = None 13 14 def __init__(self, serviceManager, clientID, itemID): 15 self.serviceManager = serviceManager 16 self.clientID = clientID 17 self.itemID = itemID 18 self.behaviorTree = None 19 self.events = [] 20 self.machoNet = serviceManager.GetService('machoNet') 21 self.taskSeen = [] 22 23 def SendToClient(self, *args, **kwargs): 24 self.machoNet.SinglecastByClientID(self.clientID, 'OnBehaviorDebugUpdate', self.itemID, *args, **kwargs) 25 26 def AttachToBehaviorTree(self, behaviorTree): 27 self.behaviorTree = behaviorTree 28 messenger = self.behaviorTree.GetMessenger() 29 messenger.SubscribeToMessage(behaviortree.MESSAGE_STEP, self.OnTreeStep) 30 messenger.SubscribeToMessage(behaviortree.MESSAGE_RESET, self.OnTreeReset) 31 messenger.SubscribeToMessage(behaviortree.MESSAGE_REQUEST_RESET, self.OnTreeResetRequest) 32 messenger.SubscribeToMessage(behaviortree.MESSAGE_TICK_DONE, self.OnTickDone) 33 messenger.SubscribeToMessage(behaviortree.MESSAGE_BLOCK_RESET, self.OnTreeSetBlockReset) 34 self.serviceManager.RegisterForNotifyEvent(self, 'OnSessionDetach') 35 self.serviceManager.RegisterForNotifyEvent(self, 'OnSessionChanged') 36 37 def DetachFromBehaviorTree(self): 38 if self.behaviorTree is None: 39 return 40 try: 41 messenger = self.behaviorTree.GetMessenger() 42 messenger.UnsubscribeFromMessage(behaviortree.MESSAGE_STEP, self.OnTreeStep) 43 messenger.UnsubscribeFromMessage(behaviortree.MESSAGE_RESET, self.OnTreeReset) 44 messenger.UnsubscribeFromMessage(behaviortree.MESSAGE_REQUEST_RESET, self.OnTreeResetRequest) 45 messenger.UnsubscribeFromMessage(behaviortree.MESSAGE_TICK_DONE, self.OnTickDone) 46 messenger.UnsubscribeFromMessage(behaviortree.MESSAGE_BLOCK_RESET, self.OnTreeSetBlockReset) 47 self.serviceManager.UnregisterForNotifyEvent(self, 'OnSessionDetach') 48 self.serviceManager.UnregisterForNotifyEvent(self, 'OnSessionChanged') 49 except: 50 logger.exception('Problem detaching debugger from the behavior for entity') 51 finally: 52 self.behaviorTree = None 53 54 def OnSessionDetach(self): 55 logger.warn('OnSessionDetach %s', session) 56 if getattr(session, 'clientID', None) == self.clientID: 57 self.DetachFromBehaviorTree() 58 59 def OnSessionChanged(self, isRemote, sess, change): 60 logger.warn('OnSessionChanged %s %s %s', isRemote, sess, change) 61 if getattr(sess, 'clientID', None) == self.clientID and 'solarsystemid' in change: 62 self.DetachFromBehaviorTree() 63 64 def OnTreeReset(self): 65 logger.debug('OnTreeReset') 66 self.events.append((self.GetSimTime(), 'Reset', None)) 67 68 def OnTreeResetRequest(self, requestedBy): 69 logger.debug('OnTreeResetRequest requestedBy=%s', requestedBy) 70 self.events.append((self.GetSimTime(), 'RequestReset', id(requestedBy))) 71 72 def OnTreeSetBlockReset(self, value, task): 73 logger.debug('OnTreeSetBlockReset task=%s is %sblocking', task, '' if value else 'un-') 74 self.events.append((self.GetSimTime(), 'SetBlockReset', (id(task), value))) 75 76 def OnTreeStep(self, task): 77 if task is not None: 78 self.taskSeen.append(task) 79 self.events.append((self.GetSimTime(), 'Step', id(task))) 80 81 def OnTickDone(self, context): 82 if self.behaviorTree is None: 83 return 84 events = self.events 85 self.events = [] 86 taskStatuses = {id(t):t.status.__name__ for t in DepthFirstTaskIterator(self.behaviorTree.GetRootTask())} 87 tasksSeen = [ id(t) for t in self.taskSeen ] 88 del self.taskSeen[:] 89 blackboards = GetBlackboards(context) 90 self.SendToClient(events, taskStatuses, tasksSeen, blackboards) 91 92 def GetTreeDump(self): 93 return DumpTree(self.behaviorTree) 94 95 def GetSimTime(self): 96 return gametime.GetSimTime() 97 98 def MachoResolve(self, session): 99 result = None 100 solarsystemid2 = session.GetSessionVariable('solarsystemid2') 101 if solarsystemid2: 102 result = self.machoNet.GetNodeFromAddress(SERVICE_BEYONCE, session.solarsystemid2) 103 return result 104 105 106 def DumpTree(behaviorTree): 107 taskList = [] 108 rootTask = behaviorTree.GetRootTask() 109 RecursiveDumpTask(taskList, rootTask, 0) 110 return taskList 111 112 113 def RecursiveDumpTask(taskList, task, depth): 114 taskDict = DumpTask(task, depth) 115 taskList.append(taskDict) 116 if issubclass(task.__class__, Composite): 117 subTasks = [] 118 for subTask in task.GetSubTasks(): 119 subTasks.append(id(subTask)) 120 RecursiveDumpTask(taskList, subTask, depth + 1) 121 122 taskDict['subtasks'] = subTasks 123 124 125 def DumpTask(task, depth): 126 return dict(type=task.__class__.__name__, id=id(task), attributes=get_attribute_dict(task), status=task.status.__name__, depth=depth) 127 128 129 def get_attribute_dict(task): 130 if isinstance(task.attributes, dict): 131 if task.attributes: 132 return dict(task.attributes) 133 return {} 134 else: 135 return dict(task.attributes._asdict()) 136 137 138 def GetBlackboards(context): 139 bbm = context.blackboardManager 140 blackboards = {} 141 for scopeType in scopes.ScopeTypes.values(): 142 if scopeType not in scopes.CONTEXT_ID_BY_SCOPE: 143 continue 144 scopeID = context.get(scopes.CONTEXT_ID_BY_SCOPE[scopeType]) 145 if scopeID is not None: 146 scope = scopes.Scope(scopeType, scopeID) 147 try: 148 bb = bbm.GetBlackboard(scope) 149 except BlackboardDeletedError: 150 continue 151 152 channels = [] 153 for channel in bb.GetMessageChannelList(): 154 message = channel.GetLastMessage() 155 if message is None: 156 channels.append((channel.name, None, None)) 157 else: 158 channels.append((channel.name, message.time, message.value)) 159 160 blackboards[scope.scopeType, scope.id] = channels 161 162 return blackboards