419 size_t totalDrawableSize;
423- (void) dumpEntity:(
id)entity withState:(
EntityDumpState *)state parentVisible:(BOOL)parentVisible
425 if ([state->
seenEntities containsObject:entity] || entity ==
nil)
return;
426 [state->seenEntities addObject:entity];
430 size_t entitySize = [entity oo_objectSize];
431 size_t drawableSize = 0;
438 BOOL visible = parentVisible && [entity isVisible];
440 NSSet *textures = [entity allTextures];
443 [state->entityTextures unionSet:textures];
444 if (visible) [state->visibleEntityTextures unionSet:textures];
447 NSString *extra =
@"";
450 extra = [extra stringByAppendingString:@", visible"];
453 if (drawableSize != 0)
455 extra = [extra stringByAppendingFormat:@", drawable: %@", SizeString(drawableSize)];
458 [
self writeMemStat:@"%@: %@%@", [entity shortDescription], SizeString(entitySize), extra];
466 NSEnumerator *subEnum =
nil;
468 for (subEnum = [entity subEntityEnumerator]; (subentity = [subEnum nextObject]); )
470 [
self dumpEntity:subentity withState:state parentVisible:visible];
473 if ([entity isPlayer])
475 NSUInteger i,
count = [entity dialMaxMissiles];
476 for (i = 0; i <
count; i++)
478 subentity = [entity missileForPylon:i];
479 if (subentity !=
nil) [
self dumpEntity:subentity withState:state parentVisible:NO];
483 if ([entity isPlanet])
489 if (atmosphere !=
nil)
491 [
self dumpEntity:atmosphere withState:state parentVisible:visible];
495 if ([entity isWormhole])
497 NSEnumerator *shipEnum =
nil;
498 NSDictionary *shipInfo =
nil;
499 for (shipEnum = [[entity shipsInTransit] objectEnumerator]; (shipInfo = [shipEnum nextObject]); )
501 ShipEntity *ship = [shipInfo objectForKey:@"ship"];
502 [
self dumpEntity:ship withState:state parentVisible:NO];
509- (void) dumpMemoryStatistics
511 OOLog(
@"debug.memStats",
@"%@",
@"Memory statistics:");
516 NSMutableDictionary *textureRefCounts = [NSMutableDictionary dictionaryWithCapacity:[allTextures count]];
519 NSEnumerator *texEnum =
nil;
520 for (texEnum = [allTextures objectEnumerator]; (tex = [texEnum nextObject]); )
523 [textureRefCounts setObject:[NSNumber numberWithUnsignedInteger:[tex retainCount] - 1] forKey:[NSValue valueWithNonretainedObject:tex]];
526 size_t totalSize = 0;
528 [
self writeMemStat:@"Entitites:"];
531 NSArray *entities = [UNIVERSE entityList];
534 .entityTextures = [NSMutableSet set],
535 .visibleEntityTextures = [NSMutableSet set],
536 .seenEntities = [NSMutableSet set]
540 NSEnumerator *entityEnum =
nil;
541 for (entityEnum = [entities objectEnumerator]; (entity = [entityEnum nextObject]); )
543 [
self dumpEntity:entity withState:&entityDumpState parentVisible:YES];
545 for (entityEnum = [[
PLAYER scannedWormholes] objectEnumerator]; (entity = [entityEnum nextObject]); )
547 [
self dumpEntity:entity withState:&entityDumpState parentVisible:YES];
551 [
self writeMemStat:@"Total entity size (excluding %u entities not accounted for): %@ (%@ entity objects, %@ drawables)",
552 gLiveEntityCount - entityDumpState.seenCount,
553 SizeString(entityDumpState.totalEntityObjSize + entityDumpState.totalDrawableSize),
554 SizeString(entityDumpState.totalEntityObjSize),
555 SizeString(entityDumpState.totalDrawableSize)];
556 totalSize += entityDumpState.totalEntityObjSize + entityDumpState.totalDrawableSize;
563 for (texEnum = [allTextures objectEnumerator]; (tex = [texEnum nextObject]); )
565 if ([textures indexOfObject:tex] == NSNotFound)
567 [textures addObject:tex];
571 size_t totalTextureObjSize = 0;
572 size_t totalTextureDataSize = 0;
573 size_t visibleTextureDataSize = 0;
575 [
self writeMemStat:@"Textures:"];
578 for (texEnum = [textures objectEnumerator]; (tex = [texEnum nextObject]); )
580 size_t objSize = [tex oo_objectSize];
583#if OOTEXTURE_RELOADABLE
584 NSString *byteCountSuffix =
@"";
586 NSString *byteCountSuffix =
@" (* 2)";
589 NSString *usage =
@"";
592 visibleTextureDataSize += dataSize;
593 usage =
@", visible";
600 unsigned refCount = [textureRefCounts oo_unsignedIntForKey:[NSValue valueWithNonretainedObject:tex]];
602 [
self writeMemStat:@"%@: [%u refs%@] %@%@",
606 SizeString(objSize + dataSize),
609 totalTextureDataSize += dataSize;
610 totalTextureObjSize += objSize;
612 totalSize += totalTextureObjSize + totalTextureDataSize;
616#if !OOTEXTURE_RELOADABLE
617 totalTextureDataSize *= 2;
619 [
self writeMemStat:@"Total texture size: %@ (%@ object overhead, %@ data, %@ visible texture data)",
620 SizeString(totalTextureObjSize + totalTextureDataSize),
621 SizeString(totalTextureObjSize),
622 SizeString(totalTextureDataSize),
623 SizeString(visibleTextureDataSize)];
625 totalSize += [
self dumpJSMemoryStatistics];
627 [
self writeMemStat:@"Total: %@", SizeString(totalSize)];
633- (size_t) dumpJSMemoryStatistics
637 JSRuntime *runtime = JS_GetRuntime(context);
638 size_t jsSize = JS_GetGCParameter(runtime, JSGC_BYTES);
639 size_t jsMax = JS_GetGCParameter(runtime, JSGC_MAX_BYTES);
640 uint32_t jsGCCount = JS_GetGCParameter(runtime, JSGC_NUMBER);
644 [
self writeMemStat:@"JavaScript heap: %@ (limit %@, %u collections to date)", SizeString(jsSize), SizeString(jsMax), jsGCCount];
649- (void) setTCPIgnoresDroppedPackets:(BOOL)flag
651 if (_TCPIgnoresDroppedPackets != flag)
653 OOLog(
@"debugMonitor.TCPSettings",
@"The TCP console will %@ TCP packets.",
654 (flag ?
@"try to stay connected, ignoring dropped" :
@"disconnect if an error affects"));
656 _TCPIgnoresDroppedPackets = flag;
660- (BOOL) TCPIgnoresDroppedPackets
662 return _TCPIgnoresDroppedPackets;
666- (void) setUsingPlugInController:(BOOL)flag
668 _usingPlugInController = flag;
672- (BOOL) usingPlugInController
674 return _usingPlugInController;
678- (NSString *)sourceCodeForFile:(in NSString *)filePath line:(in
unsigned)line
680 id linesForFile =
nil;
682 linesForFile = [_sourceFiles objectForKey:filePath];
684 if (linesForFile ==
nil)
686 linesForFile = [
self loadSourceFile:filePath];
687 if (linesForFile ==
nil) linesForFile = [NSArray arrayWithObject:[NSString stringWithFormat:@"<Can't load file %@>", filePath]];
689 if (_sourceFiles ==
nil) _sourceFiles = [[NSMutableDictionary alloc] init];
690 [_sourceFiles setObject:linesForFile forKey:filePath];
693 if ([linesForFile
count] < line || line == 0)
return @"<line out of range!>";
695 return [linesForFile objectAtIndex:line - 1];
699- (void)disconnectDebugger:(in
id<OODebuggerInterface>)debugger
700 message:(in NSString *)message
702 if (debugger ==
nil)
return;
704 if (debugger == _debugger)
706 [
self disconnectDebuggerWithMessage:message];
710 OOLog(
@"debugMonitor.disconnect.ignored",
@"Attempt to disconnect debugger %@, which is not current debugger; ignoring.", debugger);
716- (void) applicationWillTerminate
718 [[NSNotificationCenter defaultCenter] postNotificationName:NSApplicationWillTerminateNotification object:nil];
723- (void)applicationWillTerminate:(NSNotification *)notification
725 if (_configOverrides !=
nil)
727 [[NSUserDefaults standardUserDefaults] setObject:_configOverrides forKey:@"debug-settings-override"];
730 [
self disconnectDebuggerWithMessage:@"Oolite is terminating."];
737@implementation OODebugMonitor (Private)
746 static NSString *path =
nil;
754 NSDictionary *jsProps = [NSDictionary dictionaryWithObjectsAndKeys:
756 JSSpecialFunctionsObjectWrapper(context), @"special",
765 JS_DefineProperty(context, global,
"debugConsole", [
self oo_jsValueInContext:context], NULL, NULL, JSPROP_ENUMERATE);
772- (void) javaScriptEngineWillReset:(NSNotification *)notification
781- (void)disconnectDebuggerWithMessage:(NSString *)message
785 [_debugger disconnectDebugMonitor:self message:message];
787 @catch (NSException *exception)
789 OOLog(
@"debugMonitor.debuggerConnection.exception",
@"Exception while attempting to disconnect debugger: %@ -- %@", [exception name], [exception reason]);
792 id debugger = _debugger;
800 NSMutableDictionary *result =
nil;
802 result = [NSMutableDictionary dictionary];
803 if (_configFromOXPs !=
nil) [result addEntriesFromDictionary:_configFromOXPs];
804 if (_configOverrides !=
nil) [result addEntriesFromDictionary:_configOverrides];
810- (NSArray *)loadSourceFile:(NSString *)filePath
812 NSString *contents =
nil;
813 NSArray *lines =
nil;
815 if (filePath ==
nil)
return nil;
817 contents = [NSString stringWithContentsOfUnicodeFile:filePath];
818 if (contents ==
nil)
return nil;
823 lines = [contents componentsSeparatedByString:@"\n"];
828- (NSMutableDictionary *)normalizeConfigDictionary:(NSDictionary *)dictionary
830 NSMutableDictionary *result =
nil;
831 NSEnumerator *keyEnum =
nil;
835 result = [NSMutableDictionary dictionaryWithCapacity:[dictionary count]];
836 for (keyEnum = [dictionary keyEnumerator]; (key = [keyEnum nextObject]); )
838 value = [dictionary objectForKey:key];
839 value = [
self normalizeConfigValue:value forKey:key];
841 if (key !=
nil && value !=
nil) [result setObject:value forKey:key];
848- (id)normalizeConfigValue:(
id)value forKey:(NSString *)key
855 if ([key hasSuffix:
@"-color"] || [key hasSuffix:
@"-colour"])
860 else if ([key hasPrefix:
@"show-console"])
863 value = [NSNumber numberWithBool:boolValue];
872 context:(in JSContext *)context
873 error:(in JSErrorReport *)errorReport
874 stackSkip:(in
unsigned)stackSkip
875 showingLocation:(in BOOL)showLocation
876 withMessage:(in NSString *)message
878 NSString *colorKey =
nil;
879 NSString *prefix =
nil;
880 NSString *filePath =
nil;
881 NSString *sourceLine =
nil;
882 NSString *scriptLine =
nil;
883 NSMutableString *formattedMessage =
nil;
884 NSRange emphasisRange;
885 NSString *showKey =
nil;
887 if (_debugger ==
nil)
return;
889 if (errorReport->flags & JSREPORT_WARNING)
891 colorKey =
@"warning";
894 else if (errorReport->flags & JSREPORT_EXCEPTION)
896 colorKey =
@"exception";
897 prefix =
@"Exception";
905 if (errorReport->flags & JSREPORT_STRICT)
907 prefix = [prefix stringByAppendingString:@" (strict mode)"];
911 emphasisRange = NSMakeRange(0, [prefix length] + 1);
913 formattedMessage = [NSMutableString stringWithFormat:@"%@: %@", prefix, message];
920 scriptLine = [[thisScript weakRefUnderlyingObject] displayName];
921 [thisScript release];
923 if (scriptLine !=
nil)
925 [formattedMessage appendFormat:@"\n Active script: %@", scriptLine];
928 if (showLocation && stackSkip == 0)
931 if (errorReport->filename != NULL) filePath = [NSString stringWithUTF8String:errorReport->filename];
932 if ([filePath length] != 0)
934 [formattedMessage appendFormat:@"\n %@, line %u", [filePath lastPathComponent], errorReport->lineno];
937 sourceLine = [
self sourceCodeForFile:filePath line:errorReport->lineno];
938 if (sourceLine !=
nil)
940 [formattedMessage appendFormat:@":\n %@", sourceLine];
945 [
self appendJSConsoleLine:formattedMessage
947 emphasisRange:emphasisRange];
949 if (errorReport->flags & JSREPORT_WARNING) showKey =
@"show-console-on-warning";
950 else showKey =
@"show-console-on-error";
953 [
self showJSConsole];
959 context:(in JSContext *)context
960 logMessage:(in NSString *)message
961 ofClass:(in NSString *)messageClass
963 [
self appendJSConsoleLine:message colorKey:@"log"];
966 [
self showJSConsole];
971- (jsval)oo_jsValueInContext:(JSContext *)context
985 if (_jsSelf != NULL)
return OBJECT_TO_JSVAL(_jsSelf);
986 else return JSVAL_NULL;
992@implementation OODebugMonitor (Singleton)
1001+ (id)allocWithZone:(NSZone *)inZone