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];
467 foreach (subentity, [entity subEntityEnumerator])
469 [
self dumpEntity:subentity withState:state parentVisible:visible];
472 if ([entity isPlayer])
474 NSUInteger i,
count = [entity dialMaxMissiles];
475 for (i = 0; i <
count; i++)
477 subentity = [entity missileForPylon:i];
478 if (subentity !=
nil) [
self dumpEntity:subentity withState:state parentVisible:NO];
482 if ([entity isPlanet])
487 PlanetEntity *atmosphere = [entity atmosphere];
488 if (atmosphere !=
nil)
490 [
self dumpEntity:atmosphere withState:state parentVisible:visible];
494 if ([entity isWormhole])
496 NSDictionary *shipInfo =
nil;
497 foreach (shipInfo, [entity shipsInTransit])
499 ShipEntity *ship = [shipInfo objectForKey:@"ship"];
500 [
self dumpEntity:ship withState:state parentVisible:NO];
507- (void) dumpMemoryStatistics
509 OOLog(
@"debug.memStats",
@"%@",
@"Memory statistics:");
514 NSMutableDictionary *textureRefCounts = [NSMutableDictionary dictionaryWithCapacity:[allTextures count]];
517 foreach (tex, allTextures)
520 [textureRefCounts setObject:[NSNumber numberWithUnsignedInteger:[tex retainCount] - 1] forKey:[NSValue valueWithNonretainedObject:tex]];
523 size_t totalSize = 0;
525 [
self writeMemStat:@"Entitites:"];
528 NSArray *entities = [UNIVERSE entityList];
532 .visibleEntityTextures = [NSMutableSet set],
533 .seenEntities = [NSMutableSet set]
537 foreach (entity, entities)
539 [
self dumpEntity:entity withState:&entityDumpState parentVisible:YES];
541 foreach (entity, [
PLAYER scannedWormholes])
543 [
self dumpEntity:entity withState:&entityDumpState parentVisible:YES];
547 [
self writeMemStat:@"Total entity size (excluding %u entities not accounted for): %@ (%@ entity objects, %@ drawables)",
548 gLiveEntityCount - entityDumpState.seenCount,
549 SizeString(entityDumpState.totalEntityObjSize + entityDumpState.totalDrawableSize),
550 SizeString(entityDumpState.totalEntityObjSize),
551 SizeString(entityDumpState.totalDrawableSize)];
552 totalSize += entityDumpState.totalEntityObjSize + entityDumpState.totalDrawableSize;
559 foreach (tex, allTextures)
561 if ([textures indexOfObject:tex] == NSNotFound)
563 [textures addObject:tex];
567 size_t totalTextureObjSize = 0;
568 size_t totalTextureDataSize = 0;
569 size_t visibleTextureDataSize = 0;
571 [
self writeMemStat:@"Textures:"];
574 foreach (tex, textures)
576 size_t objSize = [tex oo_objectSize];
579#if OOTEXTURE_RELOADABLE
580 NSString *byteCountSuffix =
@"";
582 NSString *byteCountSuffix =
@" (* 2)";
585 NSString *usage =
@"";
588 visibleTextureDataSize += dataSize;
589 usage =
@", visible";
596 unsigned refCount = [textureRefCounts oo_unsignedIntForKey:[NSValue valueWithNonretainedObject:tex]];
598 [
self writeMemStat:@"%@: [%u refs%@] %@%@",
602 SizeString(objSize + dataSize),
605 totalTextureDataSize += dataSize;
606 totalTextureObjSize += objSize;
608 totalSize += totalTextureObjSize + totalTextureDataSize;
612#if !OOTEXTURE_RELOADABLE
613 totalTextureDataSize *= 2;
615 [
self writeMemStat:@"Total texture size: %@ (%@ object overhead, %@ data, %@ visible texture data)",
616 SizeString(totalTextureObjSize + totalTextureDataSize),
617 SizeString(totalTextureObjSize),
618 SizeString(totalTextureDataSize),
619 SizeString(visibleTextureDataSize)];
621 totalSize += [
self dumpJSMemoryStatistics];
623 [
self writeMemStat:@"Total: %@", SizeString(totalSize)];
629- (size_t) dumpJSMemoryStatistics
633 JSRuntime *runtime = JS_GetRuntime(context);
634 size_t jsSize = JS_GetGCParameter(runtime, JSGC_BYTES);
635 size_t jsMax = JS_GetGCParameter(runtime, JSGC_MAX_BYTES);
636 uint32_t jsGCCount = JS_GetGCParameter(runtime, JSGC_NUMBER);
640 [
self writeMemStat:@"JavaScript heap: %@ (limit %@, %u collections to date)", SizeString(jsSize), SizeString(jsMax), jsGCCount];
645- (void) setTCPIgnoresDroppedPackets:(BOOL)flag
647 if (_TCPIgnoresDroppedPackets != flag)
649 OOLog(
@"debugMonitor.TCPSettings",
@"The TCP console will %@ TCP packets.",
650 (flag ?
@"try to stay connected, ignoring dropped" :
@"disconnect if an error affects"));
652 _TCPIgnoresDroppedPackets = flag;
656- (BOOL) TCPIgnoresDroppedPackets
658 return _TCPIgnoresDroppedPackets;
662- (void) setUsingPlugInController:(BOOL)flag
664 _usingPlugInController = flag;
668- (BOOL) usingPlugInController
670 return _usingPlugInController;
674- (NSString *)sourceCodeForFile:(in NSString *)filePath line:(in
unsigned)line
676 id linesForFile =
nil;
678 linesForFile = [_sourceFiles objectForKey:filePath];
680 if (linesForFile ==
nil)
682 linesForFile = [
self loadSourceFile:filePath];
683 if (linesForFile ==
nil) linesForFile = [NSArray arrayWithObject:[NSString stringWithFormat:@"<Can't load file %@>", filePath]];
685 if (_sourceFiles ==
nil) _sourceFiles = [[NSMutableDictionary alloc] init];
686 [_sourceFiles setObject:linesForFile forKey:filePath];
689 if ([linesForFile
count] < line || line == 0)
return @"<line out of range!>";
691 return [linesForFile objectAtIndex:line - 1];
695- (void)disconnectDebugger:(in
id<OODebuggerInterface>)debugger
696 message:(in NSString *)message
698 if (debugger ==
nil)
return;
700 if (debugger == _debugger)
702 [
self disconnectDebuggerWithMessage:message];
706 OOLog(
@"debugMonitor.disconnect.ignored",
@"Attempt to disconnect debugger %@, which is not current debugger; ignoring.", debugger);
712- (void) applicationWillTerminate
714 [[NSNotificationCenter defaultCenter] postNotificationName:NSApplicationWillTerminateNotification object:nil];
719- (void)applicationWillTerminate:(NSNotification *)notification
721 if (_configOverrides !=
nil)
723 [[NSUserDefaults standardUserDefaults] setObject:_configOverrides forKey:@"debug-settings-override"];
726 [
self disconnectDebuggerWithMessage:@"Oolite is terminating."];
733@implementation OODebugMonitor (Private)
742 static NSString *path =
nil;
750 NSDictionary *jsProps = [NSDictionary dictionaryWithObjectsAndKeys:
752 JSSpecialFunctionsObjectWrapper(context), @"special",
761 JS_DefineProperty(context, global,
"debugConsole", [
self oo_jsValueInContext:context], NULL, NULL, JSPROP_ENUMERATE);
768- (void) javaScriptEngineWillReset:(NSNotification *)notification
777- (void)disconnectDebuggerWithMessage:(NSString *)message
781 [_debugger disconnectDebugMonitor:self message:message];
783 @catch (NSException *exception)
785 OOLog(
@"debugMonitor.debuggerConnection.exception",
@"Exception while attempting to disconnect debugger: %@ -- %@", [exception name], [exception reason]);
788 id debugger = _debugger;
796 NSMutableDictionary *result =
nil;
798 result = [NSMutableDictionary dictionary];
799 if (_configFromOXPs !=
nil) [result addEntriesFromDictionary:_configFromOXPs];
800 if (_configOverrides !=
nil) [result addEntriesFromDictionary:_configOverrides];
806- (NSArray *)loadSourceFile:(NSString *)filePath
808 NSString *contents =
nil;
809 NSArray *lines =
nil;
811 if (filePath ==
nil)
return nil;
813 contents = [NSString stringWithContentsOfUnicodeFile:filePath];
814 if (contents ==
nil)
return nil;
819 lines = [contents componentsSeparatedByString:@"\n"];
824- (NSMutableDictionary *)normalizeConfigDictionary:(NSDictionary *)dictionary
826 NSMutableDictionary *result =
nil;
830 result = [NSMutableDictionary dictionaryWithCapacity:[dictionary count]];
833 value = [dictionary objectForKey:key];
834 value = [
self normalizeConfigValue:value forKey:key];
836 if (key !=
nil && value !=
nil) [result setObject:value forKey:key];
843- (id)normalizeConfigValue:(
id)value forKey:(NSString *)key
850 if ([key hasSuffix:
@"-color"] || [key hasSuffix:
@"-colour"])
855 else if ([key hasPrefix:
@"show-console"])
858 value = [NSNumber numberWithBool:boolValue];
867 context:(in JSContext *)context
868 error:(in JSErrorReport *)errorReport
869 stackSkip:(in
unsigned)stackSkip
870 showingLocation:(in BOOL)showLocation
871 withMessage:(in NSString *)message
873 NSString *colorKey =
nil;
874 NSString *prefix =
nil;
875 NSString *filePath =
nil;
876 NSString *sourceLine =
nil;
877 NSString *scriptLine =
nil;
878 NSMutableString *formattedMessage =
nil;
879 NSRange emphasisRange;
880 NSString *showKey =
nil;
882 if (_debugger ==
nil)
return;
884 if (errorReport->flags & JSREPORT_WARNING)
886 colorKey =
@"warning";
889 else if (errorReport->flags & JSREPORT_EXCEPTION)
891 colorKey =
@"exception";
892 prefix =
@"Exception";
900 if (errorReport->flags & JSREPORT_STRICT)
902 prefix = [prefix stringByAppendingString:@" (strict mode)"];
906 emphasisRange = NSMakeRange(0, [prefix length] + 1);
908 formattedMessage = [NSMutableString stringWithFormat:@"%@: %@", prefix, message];
915 scriptLine = [[thisScript weakRefUnderlyingObject] displayName];
916 [thisScript release];
918 if (scriptLine !=
nil)
920 [formattedMessage appendFormat:@"\n Active script: %@", scriptLine];
923 if (showLocation && stackSkip == 0)
926 if (errorReport->filename != NULL) filePath = [NSString stringWithUTF8String:errorReport->filename];
927 if ([filePath length] != 0)
929 [formattedMessage appendFormat:@"\n %@, line %u", [filePath lastPathComponent], errorReport->lineno];
932 sourceLine = [
self sourceCodeForFile:filePath line:errorReport->lineno];
933 if (sourceLine !=
nil)
935 [formattedMessage appendFormat:@":\n %@", sourceLine];
940 [
self appendJSConsoleLine:formattedMessage
942 emphasisRange:emphasisRange];
944 if (errorReport->flags & JSREPORT_WARNING) showKey =
@"show-console-on-warning";
945 else showKey =
@"show-console-on-error";
948 [
self showJSConsole];
954 context:(in JSContext *)context
955 logMessage:(in NSString *)message
956 ofClass:(in NSString *)messageClass
958 [
self appendJSConsoleLine:message colorKey:@"log"];
961 [
self showJSConsole];
966- (jsval)oo_jsValueInContext:(JSContext *)context
980 if (_jsSelf != NULL)
return OBJECT_TO_JSVAL(_jsSelf);
981 else return JSVAL_NULL;
987@implementation OODebugMonitor (Singleton)
996+ (id)allocWithZone:(NSZone *)inZone