class VehicleTelemetry(object): def __init__(self, avatar): self.avatar = avatar self.logName = None self.saveTextLog = False self.dynamicsLog = None self.dynamicsData = {} self.scenarioName = None self.recordStarted = False self.__physicsDebugInfoEnabled = ENABLE_DEBUG_DYNAMICS_INFO self.__physicsDebugInfo = None self.__completionFlag = None return physicsDebugInfo = property(lambda self: self.__physicsDebugInfo) def enableVehiclePhysicsTelemetry(self, enabled=None): if not self.avatar.inWorld: return else: shouldEnable = enabled if enabled is not None else not self.__physicsDebugInfoEnabled flag = 1 if shouldEnable else 0 self.avatar.base.setDevelopmentFeature( 0, 'toggle_vehicle_debug_info', flag, '') self.__physicsDebugInfoEnabled = shouldEnable return try: DYNAMICS_LOG_DIR = ResMgr.appDirectory() + 'dynamics_log' except AttributeError: DYNAMICS_LOG_DIR = 'dynamics_log' def __checkDynLogDir(self): if not os.path.exists(VehicleTelemetry.DYNAMICS_LOG_DIR): LOG_WARNING('DYNAMICS_LOG_DIR not found, creating ...', VehicleTelemetry.DYNAMICS_LOG_DIR) os.mkdir(VehicleTelemetry.DYNAMICS_LOG_DIR) NAME_DELIMITER = '$' def __generateDynamicsLogName(self): vehicleName = self.avatar.getVehicleAttached().typeDescriptor.name vehicleName = vehicleName.replace(':', VehicleTelemetry.NAME_DELIMITER) timestamp = datetime.datetime.now().strftime('%y%m%d%H%M%S') logName = VehicleTelemetry.NAME_DELIMITER.join( (vehicleName, self.scenarioName, timestamp)) return logName def recordVehicleDynamics(self, scenarioName, cmd, isRapidMode=True, saveTextLog=False): if not self.avatar.inWorld: LOG_WARNING('Avatar.base is not available yet on Avatar client') LOG_CODEPOINT_WARNING() return self.scenarioName = scenarioName self.saveTextLog = saveTextLog self.logName = self.__generateDynamicsLogName() cmd = cmd.strip() zippedArg = zlib.compress(cPickle.dumps((isRapidMode, cmd)), 9) self.__completionFlag = False self.avatar.base.setDevelopmentFeature(0, 'record_vehicle_dynamics', 0, zippedArg) def isSimulationComplete(self): return self.__completionFlag def __openDynamicsLog(self, refTime, refDist): if self.dynamicsLog: self.__closeDynamicsLog() self.logPath = os.path.join(VehicleTelemetry.DYNAMICS_LOG_DIR, self.logName) self.refTime = refTime self.refDist = refDist if self.saveTextLog: self.dynamicsLog = open(self.logPath, 'w') self.__writeHeader() HEADER_TEMPLATE = '# vehicle : {}\n# engine : {}\n# chassis : {}\n# scenario: {}\n# time distance Vz Vx Az Ax X Y Z w wcc yaw pitch roll r health\n' def __writeHeader(self): descr = self.avatar.getVehicleAttached().typeDescriptor header = VehicleTelemetry.HEADER_TEMPLATE.format( descr.name, descr.engine.name, descr.chassis.name, self.scenarioName) self.dynamicsLog.write(header) def __closeDynamicsLog(self): if self.dynamicsLog: self.dynamicsLog.close() self.dynamicsLog = None os.rename(self.logPath, self.logPath + '.log') if self.dynamicsData: dataFileName = '{}.pkl'.format(self.logName) with open( os.path.join(VehicleTelemetry.DYNAMICS_LOG_DIR, dataFileName), 'wb') as dataFile: cPickle.dump(self.dynamicsData, dataFile, protocol=2) self.dynamicsData = {} self.refTime = None self.refDist = None self.recordStarted = False return def __onStop(self): self.__closeDynamicsLog() self.__completionFlag = True LOG_LINE_TEMPLATE = ' '.join( ('{t:8.3f} {dist:8.3f}', '{Vz:8.3f} {Vx:8.3f}', '{Az:8.3f} {Ax:8.3f}', '{X:8.3f} {Y:8.3f} {Z:8.3f}', '{w:8.3f} {wcc:8.3f}', '{yaw:8.3f} {pitch:8.3f} {roll:8.3f}', '{r:8.3f} {health:4d}', '{ltr:8.3f} {rtr:8.3f}', '{ltp:8.3f} {rtp:8.3f}', '{lte:8.3f} {rte:8.3f}', '{hle:8.3f}', '{dhh:8.3f} {dlt:8.3f} {drt:8.3f}', '{hdm:8.3f} {hrc:8.3f}', '{lthp:8.3f} {rthp:8.3f}', '{Vy:8.3f} {Ay:8.3f}', '{ltslp:8.3f} {rtslp:8.3f}', '{ltbf:8.3f} {rtbf:8.3f}', '\n')) def __logDynamics(self, paramNamesMap, snapshots): namesMap = paramNamesMap def getSnapshotValue(snapshot, parameterName, default=0.0): return snapshot[namesMap[parameterName]] if namesMap.has_key( parameterName) else default snapshot = None for snapshot in snapshots: time = snapshot[namesMap['time']] - self.refTime if time < 0: print 'Nt:', snapshot[namesMap['time']], self.refTime dist = snapshot[namesMap['path']] - self.refDist velocity = snapshot[namesMap['vel']] acceleration = snapshot[namesMap['acc']] position = snapshot[namesMap['pos']] pitch = -math.degrees(snapshot[namesMap['dir']][1]) roll = math.degrees(snapshot[namesMap['dir']][2]) yaw = math.degrees(snapshot[namesMap['dir']][0]) angularVelocity = math.degrees(snapshot[namesMap['wel']].y) angularAcceleration = math.degrees(snapshot[namesMap['wac']].y) binormal = (acceleration * velocity).length r = abs(velocity.length**3 / binormal) if abs(binormal) > 0 else 0 r = min(500, r) velocity *= 3.6 acceleration *= 1 / G data = { 't': time, 'dist': dist, 'Vz': velocity.z, 'Vx': velocity.x, 'Az': acceleration.z, 'Ax': acceleration.x, 'X': position.x, 'Y': position.y, 'Z': position.z, 'w': angularVelocity, 'wcc': angularAcceleration, 'yaw': yaw, 'pitch': pitch, 'roll': roll, 'r': r, 'health': int(self.avatar.getVehicleAttached().health), 'ltr': getSnapshotValue(snapshot, 'lTrackReaction'), 'rtr': getSnapshotValue(snapshot, 'rTrackReaction'), 'ltp': getSnapshotValue(snapshot, 'lTrackPressure'), 'rtp': getSnapshotValue(snapshot, 'rTrackPressure'), 'lte': getSnapshotValue(snapshot, 'lTrackEnergy'), 'rte': getSnapshotValue(snapshot, 'rTrackEnergy'), 'hle': getSnapshotValue(snapshot, 'hullEnergy'), 'dhh': getSnapshotValue(snapshot, 'dmg_hh'), 'dlt': getSnapshotValue(snapshot, 'dmg_lt'), 'drt': getSnapshotValue(snapshot, 'dmg_rt'), 'lthp': getSnapshotValue(snapshot, 'lthp'), 'rthp': getSnapshotValue(snapshot, 'rthp'), 'hdm': getSnapshotValue(snapshot, 'hull_dmgmp'), 'hrc': getSnapshotValue(snapshot, 'hull_react'), 'Vy': velocity.y, 'Ay': acceleration.y, 'ltslp': getSnapshotValue(snapshot, 'trackScrolling', default=-20.0), 'rtslp': getSnapshotValue(snapshot, 'trackScrolling', default=-30.0), 'ltbf': getSnapshotValue(snapshot, 'ltbf'), 'rtbf': getSnapshotValue(snapshot, 'rtbf') } for key, value in data.iteritems(): self.dynamicsData.setdefault(key, []).append(value) line = VehicleTelemetry.LOG_LINE_TEMPLATE.format(**data) if self.saveTextLog: self.dynamicsLog.write(line) self.dynamicsLog.flush() return def receivePhysicsDebugInfo(self, info, modifDict): infoDict = cPickle.loads(zlib.decompress(info)) cmd = infoDict['cmd'] if cmd == 'telemetry': nDict = {} for key, value in modifDict.iteritems(): try: index = infoDict['paramNamesMap'][key] nDict[index] = value except Exception: pass temp = [] ind = 0 for inValue in infoDict['snapshots'][0]: mValue = nDict.get(ind, None) if mValue is not None: temp.append(mValue) else: temp.append(inValue) ind += 1 infoDict['snapshots'][0] = temp if self.recordStarted: self.__logDynamics(infoDict['paramNamesMap'], infoDict['snapshots']) self.__physicsDebugInfo = infoDict elif cmd == 'comment': if self.dynamicsLog: line = '#%(text)s\n' % infoDict self.dynamicsLog.write(line) elif cmd == 'openLog': self.recordStarted = True self.__openDynamicsLog(infoDict['time'], infoDict['path']) elif cmd == 'closeLog': self.__closeDynamicsLog() elif cmd == 'stop': self.__onStop() else: LOG_ERROR('Invalid PhysicsDebugInfo has been received:', infoDict) return
class VehicleTelemetry: def __init__(self, avatar): raise avatar is not None or AssertionError self.avatar = avatar self.dynamicsLog = None self.dynamicsLogKey = None self.__physicsDebugInfoEnabled = ENABLE_DEBUG_DYNAMICS_INFO self.__physicsDebugInfo = None self.__completionFlag = None return physicsDebugInfo = property(lambda self: self.__physicsDebugInfo) def enableVehiclePhysicsTelemetry(self, enabled = None): if not self.avatar.inWorld: return else: shouldEnable = enabled if enabled is not None else not self.__physicsDebugInfoEnabled flag = 1 if shouldEnable else 0 self.avatar.base.setDevelopmentFeature('toggle_vehicle_debug_info', flag, '') self.__physicsDebugInfoEnabled = shouldEnable return try: DYNAMICS_LOG_DIR = ResMgr.appDirectory() + 'dynamics_log' except AttributeError: DYNAMICS_LOG_DIR = 'dynamics_log' def __checkDynLogDir(self): if not os.path.exists(VehicleTelemetry.DYNAMICS_LOG_DIR): LOG_WARNING('DYNAMICS_LOG_DIR not found, creating ...', VehicleTelemetry.DYNAMICS_LOG_DIR) os.mkdir(VehicleTelemetry.DYNAMICS_LOG_DIR) def __getScenarioFilePath(self, scenarioName): self.__checkDynLogDir() scenarioPath = os.path.join(VehicleTelemetry.DYNAMICS_LOG_DIR, scenarioName) if not os.path.exists(scenarioPath): LOG_ERROR('SCENARIO file not found:', scenarioPath) return None else: return scenarioPath NAME_DELIMITER = '$' def __generateDynamicsLogName(self, scenarioName): vname = self.avatar.getVehicleAttached().typeDescriptor.name vname = vname.replace(':', VehicleTelemetry.NAME_DELIMITER) sname = scenarioName.split('.', 1)[0] stamp = datetime.datetime.now().strftime('%y%m%d%H%M%S') logName = VehicleTelemetry.NAME_DELIMITER.join((vname, sname, stamp)) return logName def recordVehicleDynamics(self, scenarioName, isRapidMode = True): if not self.avatar.inWorld: LOG_WARNING('Avatar.base is not available yet on Avatar client') LOG_CODEPOINT_WARNING() return cmd = '' scenarioPath = self.__getScenarioFilePath(scenarioName) if not scenarioPath: return scenario = open(scenarioPath, 'r') try: cmd = scenario.read() finally: scenario.close() self.logName = self.__generateDynamicsLogName(scenarioName) cmd = cmd.strip() zippedArg = zlib.compress(cPickle.dumps((isRapidMode, cmd)), 9) self.__completionFlag = False self.avatar.base.setDevelopmentFeature('record_vehicle_dynamics', 0, zippedArg) def isSimulationComplete(self): return self.__completionFlag def __openDynamicsLog(self, key, refTime, refDist): if self.dynamicsLog: self.__closeDynamicsLog() name = VehicleTelemetry.NAME_DELIMITER.join((self.logName, key)) self.logPath = os.path.join(VehicleTelemetry.DYNAMICS_LOG_DIR, name) raise not os.path.exists(self.logPath) or AssertionError self.dynamicsLog = open(self.logPath, 'w') self.refTime = refTime self.refDist = refDist self.__writeHeader(name) HEADER_TMPL = '\n# vehicle : %(Veh)s\n# engine : %(Eng)s\n# chassis : %(Css)s\n# scenario: %(Scn)s\n# section : %(Sec)s\n# physics : %(Phy)s\n# t s Vz Vx Az Ax X Y Z yaw w wcc p r\n'.lstrip('\r\n') def __writeHeader(self, name): descr = self.avatar.getVehicleAttached().typeDescriptor parts = name.split(VehicleTelemetry.NAME_DELIMITER) header = VehicleTelemetry.HEADER_TMPL % {'Veh': descr.name, 'Eng': descr.engine['name'], 'Css': descr.chassis['name'], 'Scn': parts[2], 'Sec': parts[-2], 'Phy': parts[-1]} self.dynamicsLog.write(header) def __closeDynamicsLog(self): if self.dynamicsLog: self.dynamicsLog.close() self.dynamicsLog = None os.rename(self.logPath, self.logPath + '.log') self.refTime = None self.refDist = None return def __onStop(self): self.__closeDynamicsLog() self.__completionFlag = True LOG_TMPL = ' '.join(('%(t)8.3f %(s)8.3f', '%(Vz)8.3f %(Vx)8.3f', '%(Az)8.3f %(Ax)8.3f', '%(X)8.3f %(Y)8.3f %(Z)8.3f', '%(y)8.3f %(w)8.3f %(q)8.3f', '%(p)8.3f %(r)8.3f', '%(h)4d', '%(ltr)8.3f %(rtr)8.3f', '%(ltp)8.3f %(rtp)8.3f', '%(lte)8.3f %(rte)8.3f', '%(hle)8.3f', '%(dhh)8.3f %(dlt)8.3f %(drt)8.3f', '%(hdm)8.3f %(hrc)8.3f', '%(lthp)8.3f %(rthp)8.3f', '%(Vy)8.3f %(Ay)8.3f', '%(ltslp)8.3f %(rtslp)8.3f', '%(ltbf)8.3f %(rtbf)8.3f', '%(roll)8.3f', '\n')) def __logDynamics(self, paramNamesMap, snapshots): nmap = paramNamesMap for sh in snapshots: t = sh[nmap['time']] - self.refTime if t < 0: print 'Nt:', sh[nmap['time']], self.refTime s = sh[nmap['path']] - self.refDist vel = sh[nmap['vel']] acc = sh[nmap['acc']] pos = sh[nmap['pos']] pitch = -math.degrees(sh[nmap['dir']][1]) roll = math.degrees(sh[nmap['dir']][2]) yaw = math.degrees(sh[nmap['dir']][0]) wel = math.degrees(sh[nmap['wel']].y) wcc = math.degrees(sh[nmap['wac']].y) binormal = (acc * vel).length r = abs(vel.length ** 3 / binormal) if abs(binormal) > 0 else 0 r = min(500, r) vel *= 3.6 acc *= 1 / G line = VehicleTelemetry.LOG_TMPL % {'t': t, 's': s, 'Vz': vel.z, 'Vx': vel.x, 'Az': acc.z, 'Ax': acc.x, 'X': pos.x, 'Y': pos.y, 'Z': pos.z, 'y': yaw, 'w': wel, 'q': wcc, 'p': pitch, 'roll': roll, 'r': r, 'h': int(self.avatar.getVehicleAttached().health), 'ltr': sh[nmap['lTrackReaction']] if nmap.has_key('lTrackReaction') else 0.0, 'rtr': sh[nmap['rTrackReaction']] if nmap.has_key('rTrackReaction') else 0.0, 'ltp': sh[nmap['lTrackPressure']] if nmap.has_key('lTrackPressure') else 0.0, 'rtp': sh[nmap['rTrackPressure']] if nmap.has_key('rTrackPressure') else 0.0, 'lte': sh[nmap['lTrackEnergy']] if nmap.has_key('lTrackEnergy') else 0.0, 'rte': sh[nmap['rTrackEnergy']] if nmap.has_key('rTrackEnergy') else 0.0, 'hle': sh[nmap['hullEnergy']] if nmap.has_key('hullEnergy') else 0.0, 'dhh': sh[nmap['dmg_hh']] if nmap.has_key('dmg_hh') else 0.0, 'dlt': sh[nmap['dmg_lt']] if nmap.has_key('dmg_lt') else 0.0, 'drt': sh[nmap['dmg_rt']] if nmap.has_key('dmg_rt') else 0.0, 'lthp': sh[nmap['lthp']] if nmap.has_key('lthp') else 0.0, 'rthp': sh[nmap['rthp']] if nmap.has_key('rthp') else 0.0, 'hdm': sh[nmap['hull_dmgmp']] if nmap.has_key('hull_dmgmp') else 0.0, 'hrc': sh[nmap['hull_react']] if nmap.has_key('hull_react') else 0.0, 'Vy': vel.y, 'Ay': acc.y, 'ltslp': sh[nmap['trackScrolling']][0] if nmap.has_key('trackScrolling') else -20.0, 'rtslp': sh[nmap['trackScrolling']][1] if nmap.has_key('trackScrolling') else -30.0, 'ltbf': sh[nmap['ltbf']] if nmap.has_key('ltbf') else 0.0, 'rtbf': sh[nmap['rtbf']] if nmap.has_key('rtbf') else 0.0} self.dynamicsLog.write(line) self.dynamicsLog.flush() def receivePhysicsDebugInfo(self, info): infoDict = cPickle.loads(zlib.decompress(info)) cmd = infoDict['cmd'] if cmd == 'telemetry': if self.dynamicsLog: self.__logDynamics(infoDict['paramNamesMap'], infoDict['snapshots']) self.__physicsDebugInfo = infoDict elif cmd == 'comment': if self.dynamicsLog: line = '#%(text)s\n' % infoDict self.dynamicsLog.write(line) elif cmd == 'openLog': self.__openDynamicsLog(infoDict['key'], infoDict['time'], infoDict['path']) elif cmd == 'closeLog': self.__closeDynamicsLog() elif cmd == 'stop': self.__onStop() else: LOG_ERROR('Invalid PhysicsDebugInfo has been received:', infoDict)
FOV_MIN = math.radians(10) FOV_MAX = math.radians(160) MOUSE_TOGGLE_KEYS = [Keys.KEY_ESCAPE, Keys.KEY_LEFTMOUSE] SPACE_LOAD_EPS = 0.0001 class CameraTransform(object): matrix = Math.Matrix() def __init__(self, matrix): self.matrix = matrix def apply(self): BigWorld.camera().set(self.matrix) CAMERAS_XML_NAME = ResMgr.appDirectory() + 'offline_mode_cameras.xml' g_cameraTransforms = list() g_curCameraTransform = 0 def _clampCameraTransformIdx(val): val = max(0, val) val = min(len(g_cameraTransforms) - 1, val) return val def _loadCameraTransforms(): rootDS = ResMgr.openSection(CAMERAS_XML_NAME) if rootDS is not None and rootDS['cameras'] is not None: for c in rootDS['cameras'].values(): c = CameraTransform(c.readMatrix('transform')) g_cameraTransforms.append(c)