LCOV - code coverage report
Current view: top level - Core - OOSystemDescriptionManager.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 24 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOPlanetDescriptionManager.h
       4             : 
       5             : Singleton class responsible for planet description data.
       6             : 
       7             : Oolite
       8             : Copyright (C) 2004-2013 Giles C Williams and contributors
       9             : 
      10             : This program is free software; you can redistribute it and/or
      11             : modify it under the terms of the GNU General Public License
      12             : as published by the Free Software Foundation; either version 2
      13             : of the License, or (at your option) any later version.
      14             : 
      15             : This program is distributed in the hope that it will be useful,
      16             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             : GNU General Public License for more details.
      19             : 
      20             : You should have received a copy of the GNU General Public License
      21             : along with this program; if not, write to the Free Software
      22             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
      23             : MA 02110-1301, USA.
      24             : 
      25             : */
      26             : 
      27             : #import "OOSystemDescriptionManager.h"
      28             : #import "OOStringParsing.h"
      29             : #import "OOCollectionExtractors.h"
      30             : #import "OOTypes.h"
      31             : #import "PlayerEntity.h"
      32             : #import "Universe.h"
      33             : #import "ResourceManager.h"
      34             : 
      35             : // character sequence which can't be in property name, system key or layer
      36             : // and is highly unlikely to be in a manifest identifier
      37           0 : static NSString * const kOOScriptedChangeJoiner = @"~|~";
      38             : 
      39             : // likely maximum number of planetinfo properties to be applied to a system
      40             : // just for efficiency - no harm in exceeding it
      41           0 : #define OO_LIKELY_PROPERTIES_PER_SYSTEM 50
      42             : 
      43             : @interface OOSystemDescriptionManager (OOPrivate)
      44           0 : - (void) setProperties:(NSDictionary *)properties inDescription:(OOSystemDescriptionEntry *)desc;
      45           0 : - (NSDictionary *) calculatePropertiesForSystemKey:(NSString *)key;
      46           0 : - (void) updateCacheEntry:(NSUInteger)i;
      47           0 : - (void) updateCacheEntry:(NSUInteger)i forProperty:(NSString *)property;
      48           0 : - (id) getProperty:(NSString *)property forSystemKey:(NSString *)key withUniversal:(BOOL)universal;
      49             : /* some planetinfo properties have two ways to specify
      50             :  * need to get the one with higher layer (if they're both at the same layer,
      51             :  * go with property1) */
      52           0 : - (id) getProperty:(NSString *)property1 orProperty:(NSString *)property2 forSystemKey:(NSString *)key withUniversal:(BOOL)universal;
      53             : 
      54           0 : - (void) saveScriptedChangeToProperty:(NSString *)property forSystemKey:(NSString *)key andLayer:(OOSystemLayer)layer toValue:(id)value fromManifest:(NSString *)manifest;
      55             : 
      56             : @end
      57             : 
      58           0 : static NSString *kOOSystemLayerProperty = @"layer";
      59             : 
      60             : @implementation OOSystemDescriptionManager
      61             : 
      62           0 : - (id) init
      63             : {
      64             :         self = [super init];
      65             :         if (self != nil)
      66             :         {
      67             :                 universalProperties = [[NSMutableDictionary alloc] initWithCapacity:OO_LIKELY_PROPERTIES_PER_SYSTEM];
      68             :                 interstellarSpace = [[OOSystemDescriptionEntry alloc] init];
      69             :                 // assume specific interstellar settings are rare
      70             :                 systemDescriptions = [[NSMutableDictionary alloc] initWithCapacity:OO_SYSTEM_CACHE_LENGTH+20];
      71             :                 for (NSUInteger i=0;i<OO_SYSTEM_CACHE_LENGTH;i++)
      72             :                 {
      73             :                         propertyCache[i] = [[NSMutableDictionary alloc] initWithCapacity:OO_LIKELY_PROPERTIES_PER_SYSTEM];
      74             :                         // hub count of 24 is considerably higher than occurs in
      75             :                         // standard planetinfo
      76             :                         neighbourCache[i] = [[NSMutableArray alloc] initWithCapacity:24];
      77             :                 }
      78             :                 propertiesInUse = [[NSMutableSet alloc] initWithCapacity:OO_LIKELY_PROPERTIES_PER_SYSTEM];
      79             :                 scriptedChanges = [[NSMutableDictionary alloc] initWithCapacity:64];
      80             :         }
      81             :         return self;
      82             : }
      83             : 
      84           0 : - (void) dealloc
      85             : {
      86             :         DESTROY(universalProperties);
      87             :         DESTROY(interstellarSpace);
      88             :         DESTROY(systemDescriptions);
      89             :         for (NSUInteger i=0;i<OO_SYSTEM_CACHE_LENGTH;i++)
      90             :         {
      91             :                 DESTROY(propertyCache[i]);
      92             :                 DESTROY(neighbourCache[i]);
      93             :         }
      94             :         DESTROY(propertiesInUse);
      95             :         DESTROY(scriptedChanges);
      96             :         [super dealloc];
      97             : }
      98             : 
      99             : 
     100             : - (void) buildRouteCache
     101             : {
     102             :         NSUInteger i,j,k,jIndex,kIndex;
     103             :         // firstly, cache all coordinates
     104             :         for (i=0;i<OO_SYSTEM_CACHE_LENGTH;i++)
     105             :         {
     106             :                 coordinatesCache[i] = PointFromString([propertyCache[i] oo_stringForKey:@"coordinates"]);
     107             :         }
     108             :         // now for each system find its neighbours
     109             :         for (i=0;i<OO_GALAXIES_AVAILABLE;i++)
     110             :         {
     111             :                 // one galaxy at a time
     112             :                 for (j=0;j<OO_SYSTEMS_PER_GALAXY;j++)
     113             :                 {
     114             :                         jIndex = j+(i*OO_SYSTEMS_PER_GALAXY);
     115             :                         for (k=j+1;k<OO_SYSTEMS_PER_GALAXY;k++)
     116             :                         {
     117             :                                 kIndex = k+(i*OO_SYSTEMS_PER_GALAXY);
     118             :                                 if (distanceBetweenPlanetPositions(coordinatesCache[jIndex].x,coordinatesCache[jIndex].y,coordinatesCache[kIndex].x,coordinatesCache[kIndex].y) <= MAX_JUMP_RANGE)
     119             :                                 {
     120             :                                         // arrays are of system number only
     121             :                                         [neighbourCache[jIndex] addObject:[NSNumber numberWithUnsignedInteger:k]];
     122             :                                         [neighbourCache[kIndex] addObject:[NSNumber numberWithUnsignedInteger:j]];
     123             :                                 }
     124             :                         }
     125             :                 }
     126             :         }
     127             : 
     128             : }
     129             : 
     130             : 
     131             : - (void) setUniversalProperties:(NSDictionary *)properties
     132             : {
     133             :         [universalProperties addEntriesFromDictionary:properties];
     134             :         [propertiesInUse addObjectsFromArray:[properties allKeys]];
     135             :         for (NSUInteger i = 0; i<OO_SYSTEM_CACHE_LENGTH; i++)
     136             :         {
     137             :                 [self updateCacheEntry:i];
     138             :         }
     139             : }
     140             : 
     141             : 
     142             : - (void) setInterstellarProperties:(NSDictionary *)properties
     143             : {
     144             :         [self setProperties:properties inDescription:interstellarSpace];
     145             : }
     146             : 
     147             : 
     148             : - (void) setProperties:(NSDictionary *)properties forSystemKey:(NSString *)key
     149             : {
     150             :         OOSystemDescriptionEntry *desc = [systemDescriptions objectForKey:key];
     151             :         if (desc == nil)
     152             :         {
     153             :                 // create it
     154             :                 desc = [[[OOSystemDescriptionEntry alloc] init] autorelease];
     155             :                 [systemDescriptions setObject:desc forKey:key];
     156             :         }
     157             :         [self setProperties:properties inDescription:desc];
     158             :         [propertiesInUse addObjectsFromArray:[properties allKeys]];
     159             : 
     160             :         NSArray  *tokens = ScanTokensFromString(key);
     161             :         if ([tokens count] == 2 && [tokens oo_unsignedIntegerAtIndex:0] < OO_GALAXIES_AVAILABLE && [tokens oo_unsignedIntegerAtIndex:1] < OO_SYSTEMS_PER_GALAXY)
     162             :         {
     163             :                 OOGalaxyID g = [tokens oo_unsignedIntegerAtIndex:0];
     164             :                 OOSystemID s = [tokens oo_unsignedIntegerAtIndex:1];
     165             :                 NSUInteger index = (g * OO_SYSTEMS_PER_GALAXY) + s;
     166             :                 if (index >= OO_SYSTEM_CACHE_LENGTH)
     167             :                 {
     168             :                         OOLog(@"system.description.error",@"'%@' is an invalid system key. This is an internal error. Please report it.",key);
     169             :                 }
     170             :                 else
     171             :                 {
     172             :                         [self updateCacheEntry:index];
     173             :                 }
     174             :         }
     175             : }
     176             : 
     177             : 
     178             : - (void) setProperty:(NSString *)property forSystemKey:(NSString *)key andLayer:(OOSystemLayer)layer toValue:(id)value fromManifest:(NSString *)manifest
     179             : {
     180             :         OOSystemDescriptionEntry *desc = [systemDescriptions objectForKey:key];
     181             :         if (desc == nil)
     182             :         {
     183             :                 // create it
     184             :                 desc = [[[OOSystemDescriptionEntry alloc] init] autorelease];
     185             :                 [systemDescriptions setObject:desc forKey:key];
     186             :         }
     187             :         [desc setProperty:property forLayer:layer toValue:value];
     188             :         [propertiesInUse addObject:property];
     189             : 
     190             :         NSArray  *tokens = ScanTokensFromString(key);
     191             :         if ([tokens count] == 2 && [tokens oo_unsignedIntegerAtIndex:0] < OO_GALAXIES_AVAILABLE && [tokens oo_unsignedIntegerAtIndex:1] < OO_SYSTEMS_PER_GALAXY)
     192             :         {
     193             :                 [self saveScriptedChangeToProperty:property forSystemKey:key andLayer:layer toValue:value fromManifest:manifest];
     194             :         
     195             :                 OOGalaxyID g = [tokens oo_unsignedIntegerAtIndex:0];
     196             :                 OOSystemID s = [tokens oo_unsignedIntegerAtIndex:1];
     197             :                 NSUInteger index = (g * OO_SYSTEMS_PER_GALAXY) + s;
     198             :                 if (index >= OO_SYSTEM_CACHE_LENGTH)
     199             :                 {
     200             :                         OOLog(@"system.description.error",@"'%@' is an invalid system key. This is an internal error. Please report it.",key);
     201             :                 }
     202             :                 else
     203             :                 {
     204             :                         [self updateCacheEntry:index forProperty:property];
     205             :                 }
     206             :         }
     207             :         // for interstellar updates, save but don't update cache
     208             :         else if ([tokens count] == 4 && [tokens oo_unsignedIntegerAtIndex:1] < OO_GALAXIES_AVAILABLE && [tokens oo_unsignedIntegerAtIndex:2] < OO_SYSTEMS_PER_GALAXY && [tokens oo_unsignedIntegerAtIndex:3] < OO_SYSTEMS_PER_GALAXY)
     209             :         {
     210             :                 [self saveScriptedChangeToProperty:property forSystemKey:key andLayer:layer toValue:value fromManifest:manifest];
     211             :         }
     212             : }
     213             : 
     214             : 
     215           0 : - (void) saveScriptedChangeToProperty:(NSString *)property forSystemKey:(NSString *)key andLayer:(OOSystemLayer)layer toValue:(id)value fromManifest:(NSString *)manifest
     216             : {
     217             :         // if OXP doesn't have a manifest, cancel saving the change
     218             :         if (manifest == nil)
     219             :         {
     220             :                 return;
     221             :         }
     222             : //      OOLog(@"saving change",@"%@ %@ %@ %d",manifest,key,property,layer);
     223             :         NSArray *overrideKey = [NSArray arrayWithObjects:manifest,key,property,[[NSNumber numberWithInt:layer] stringValue],nil];
     224             :         // Obj-C copes with NSArray keys to dictionaries fine, but the
     225             :         // plist format doesn't, so they can't be saved.
     226             :         NSString *overrideKeyStr = [overrideKey componentsJoinedByString:kOOScriptedChangeJoiner];
     227             :         if (value != nil)
     228             :         {
     229             :                 [scriptedChanges setObject:value forKey:overrideKeyStr];
     230             :         }
     231             :         else
     232             :         {
     233             :                 [scriptedChanges removeObjectForKey:overrideKeyStr];
     234             :         }
     235             : }
     236             : 
     237             : 
     238             : - (void) importScriptedChanges:(NSDictionary *)scripted
     239             : {
     240             :         NSArray *key = nil;
     241             :         NSString *keyStr = nil;
     242             :         NSString *manifest = nil;
     243             :         foreachkey(keyStr, scripted)
     244             :         {
     245             :                 key = [keyStr componentsSeparatedByString:kOOScriptedChangeJoiner];
     246             :                 if ([key count] == 4)
     247             :                 {
     248             :                         manifest = [key oo_stringAtIndex:0];
     249             :                         if ([ResourceManager manifestForIdentifier:manifest] != nil)
     250             :                         {
     251             : //                              OOLog(@"importing",@"%@ -> %@",keyStr,[scripted objectForKey:keyStr]);
     252             :                                 [self setProperty:[key oo_stringAtIndex:2]
     253             :                                          forSystemKey:[key oo_stringAtIndex:1]
     254             :                                                  andLayer:[key oo_intAtIndex:3]
     255             :                                                   toValue:[scripted objectForKey:keyStr]
     256             :                                          fromManifest:manifest];
     257             :                                 // and doing this set stores it into the manager's copy
     258             :                                 // of scripted changes
     259             :                                 // this means in theory we could import more than one
     260             :                         }
     261             :                         // else OXP not installed, do not load
     262             :                 }
     263             :                 else
     264             :                 {
     265             :                         OOLog(@"systemManager.import",@"Key '%@' has unexpected format - skipping",keyStr);
     266             :                 }
     267             :         }
     268             : 
     269             : }
     270             : 
     271             : 
     272             : // import of the old local_planetinfo_overrides dictionary
     273             : - (void) importLegacyScriptedChanges:(NSDictionary *)scripted
     274             : {
     275             :         NSString *systemKey = nil;
     276             :         NSString *propertyKey = nil;
     277             :         NSString *defaultManifest = @"org.oolite.oolite";
     278             :         
     279             :         foreachkey(systemKey,scripted)
     280             :         {
     281             :                 NSDictionary *legacyChanges = [scripted oo_dictionaryForKey:systemKey];
     282             :                 if ([legacyChanges objectForKey:@"sun_gone_nova"] != nil)
     283             :                 {
     284             :                         // then this is a change to import even if we don't know
     285             :                         // if the OXP is still installed
     286             :                         foreachkey (propertyKey, legacyChanges)
     287             :                         {
     288             :                                 [self setProperty:propertyKey
     289             :                                          forSystemKey:systemKey
     290             :                                                  andLayer:OO_LAYER_OXP_DYNAMIC
     291             :                                                   toValue:[legacyChanges objectForKey:propertyKey]
     292             :                                          fromManifest:defaultManifest];
     293             :                         }
     294             :                         /* Fix for older savegames not having a larger sun radius
     295             :                          * property set from the Nova mission. */
     296             :                         id sr = [self getProperty:@"sun_radius" forSystemKey:systemKey];
     297             :                         float sr_num = [sr floatValue];
     298             :                         if (sr_num < 600000) {
     299             :                                 // fix sun radius values
     300             :                                 [self setProperty:@"sun_radius"
     301             :                                          forSystemKey:systemKey
     302             :                                                  andLayer:OO_LAYER_OXP_DYNAMIC
     303             :                                                   toValue:[NSNumber numberWithFloat:sr_num+600000.0f]
     304             :                                          fromManifest:defaultManifest];
     305             :                         }
     306             :                 }
     307             :         }
     308             : 
     309             : }
     310             : 
     311             : 
     312             : - (NSDictionary *) exportScriptedChanges
     313             : {
     314             :         return [[scriptedChanges copy] autorelease];
     315             : }
     316             : 
     317             : 
     318             : - (NSDictionary *) getPropertiesForCurrentSystem
     319             : {
     320             :         OOSystemID s = [UNIVERSE currentSystemID];
     321             :         if (s >= 0)
     322             :         {
     323             :                 NSUInteger index = ([PLAYER galaxyNumber] * OO_SYSTEMS_PER_GALAXY) + s;
     324             :                 if (index >= OO_SYSTEM_CACHE_LENGTH)
     325             :                 {
     326             :                         OOLog(@"system.description.error",@"'%lu' is an invalid system index for the current system. This is an internal error. Please report it.",index);
     327             :                         return [NSDictionary dictionary];
     328             :                 }
     329             :                 return propertyCache[index];
     330             :         }
     331             :         else
     332             :         {
     333             :                 OOLog(@"system.description.error", @"%@", @"getPropertiesForCurrentSystem called while player in interstellar space. This is an internal error. Please report it.");
     334             :                 // this shouldn't be called for interstellar space
     335             :                 return [NSDictionary dictionary];
     336             :         }
     337             : }
     338             : 
     339             : 
     340             : - (NSDictionary *) getPropertiesForSystemKey:(NSString *)key
     341             : {
     342             :         NSArray  *tokens = ScanTokensFromString(key);
     343             :         if ([tokens count] == 2 && [tokens oo_unsignedIntegerAtIndex:0] < OO_GALAXIES_AVAILABLE && [tokens oo_unsignedIntegerAtIndex:1] < OO_SYSTEMS_PER_GALAXY)
     344             :         {
     345             :                 OOGalaxyID g = [tokens oo_unsignedIntegerAtIndex:0];
     346             :                 OOSystemID s = [tokens oo_unsignedIntegerAtIndex:1];
     347             :                 NSUInteger index = (g * OO_SYSTEMS_PER_GALAXY) + s;
     348             :                 if (index >= OO_SYSTEM_CACHE_LENGTH)
     349             :                 {
     350             :                         OOLog(@"system.description.error",@"'%@' is an invalid system key. This is an internal error. Please report it.",key);
     351             :                         return [NSDictionary dictionary];
     352             :                 }
     353             :                 return propertyCache[index];
     354             :         }
     355             :         // interstellar spaces aren't cached
     356             :         return [self calculatePropertiesForSystemKey:key];
     357             : }
     358             : 
     359             : 
     360             : - (NSDictionary *) getPropertiesForSystem:(OOSystemID)s inGalaxy:(OOGalaxyID)g
     361             : {
     362             :         NSUInteger index = (g * OO_SYSTEMS_PER_GALAXY) + s;
     363             :         if (index >= OO_SYSTEM_CACHE_LENGTH)
     364             :         {
     365             :                 OOLog(@"system.description.error",@"'%u, %u' is an invalid system. This is an internal error. Please report it.",g,s);
     366             :                 return [NSDictionary dictionary];
     367             :         }
     368             :         return propertyCache[index];
     369             : }
     370             : 
     371             : 
     372             : - (id) getProperty:(NSString *)property forSystemKey:(NSString *)key
     373             : {
     374             :         return [self getProperty:property forSystemKey:key withUniversal:YES];
     375             : }
     376             : 
     377             : - (id) getProperty:(NSString *)property forSystem:(OOSystemID)s inGalaxy:(OOGalaxyID)g
     378             : {
     379             :         if (s < 0)
     380             :         {
     381             :                 OOLog(@"system.description.error",@"'%d %d' is an invalid system key. This is an internal error. Please report it.",g,s);
     382             :                 return nil;
     383             :         }
     384             :         NSUInteger index = (g * OO_SYSTEMS_PER_GALAXY) + s;
     385             :         if (index >= OO_SYSTEM_CACHE_LENGTH)
     386             :         {
     387             :                 OOLog(@"system.description.error",@"'%d %d' is an invalid system key. This is an internal error. Please report it.",g,s);
     388             :                 return nil;
     389             :         }
     390             :         return [propertyCache[index] objectForKey:property];
     391             : }
     392             : 
     393             : 
     394           0 : - (id) getProperty:(NSString *)property forSystemKey:(NSString *)key withUniversal:(BOOL)universal
     395             : {
     396             :         OOSystemDescriptionEntry *desc = nil;
     397             :         if (EXPECT_NOT([key isEqualToString:@"interstellar"]))
     398             :         {
     399             :                 desc = interstellarSpace;
     400             :         }
     401             :         else
     402             :         {
     403             :                 desc = [systemDescriptions objectForKey:key];
     404             :         }
     405             :         if (desc == nil)
     406             :         {
     407             :                 return nil;
     408             :         }
     409             :         id result = nil;
     410             :         result = [desc getProperty:property forLayer:OO_LAYER_OXP_PRIORITY];
     411             :         if (result == nil)
     412             :         {
     413             :                 result = [desc getProperty:property forLayer:OO_LAYER_OXP_DYNAMIC];
     414             :         }
     415             :         if (result == nil)
     416             :         {
     417             :                 result = [desc getProperty:property forLayer:OO_LAYER_OXP_STATIC];
     418             :         }
     419             :         if (result == nil && universal)
     420             :         {
     421             :                 result = [universalProperties objectForKey:property];
     422             :         }
     423             :         if (result == nil)
     424             :         {
     425             :                 result = [desc getProperty:property forLayer:OO_LAYER_CORE];
     426             :         }
     427             :         return result;
     428             : }
     429             : 
     430             : 
     431           0 : - (id) getProperty:(NSString *)property1 orProperty:(NSString *)property2 forSystemKey:(NSString *)key withUniversal:(BOOL)universal
     432             : {
     433             :         OOSystemDescriptionEntry *desc = [systemDescriptions objectForKey:key];
     434             :         if (desc == nil)
     435             :         {
     436             :                 return nil;
     437             :         }
     438             :         id result = nil;
     439             :         result = [desc getProperty:property1 forLayer:OO_LAYER_OXP_PRIORITY];
     440             :         if (result == nil)
     441             :         {
     442             :                 result = [desc getProperty:property2 forLayer:OO_LAYER_OXP_PRIORITY];
     443             :         }
     444             :         if (result == nil)
     445             :         {
     446             :                 result = [desc getProperty:property1 forLayer:OO_LAYER_OXP_DYNAMIC];
     447             :         }
     448             :         if (result == nil)
     449             :         {
     450             :                 result = [desc getProperty:property2 forLayer:OO_LAYER_OXP_DYNAMIC];
     451             :         }
     452             :         if (result == nil)
     453             :         {
     454             :                 result = [desc getProperty:property1 forLayer:OO_LAYER_OXP_STATIC];
     455             :         }
     456             :         if (result == nil)
     457             :         {
     458             :                 result = [desc getProperty:property2 forLayer:OO_LAYER_OXP_STATIC];
     459             :         }
     460             :         if (universal)
     461             :         {
     462             :                 if (result == nil)
     463             :                 {
     464             :                         result = [universalProperties objectForKey:property1];
     465             :                 }
     466             :                 if (result == nil)
     467             :                 {
     468             :                         result = [universalProperties objectForKey:property2];
     469             :                 }
     470             :         }
     471             :         if (result == nil)
     472             :         {
     473             :                 result = [desc getProperty:property1 forLayer:OO_LAYER_CORE];
     474             :         }
     475             :         if (result == nil)
     476             :         {
     477             :                 result = [desc getProperty:property2 forLayer:OO_LAYER_CORE];
     478             :         }
     479             :         return result;
     480             : }
     481             : 
     482             : 
     483           0 : - (void) setProperties:(NSDictionary *)properties inDescription:(OOSystemDescriptionEntry *)desc
     484             : {
     485             :         OOSystemLayer layer = [properties oo_unsignedIntForKey:kOOSystemLayerProperty defaultValue:OO_LAYER_OXP_STATIC];
     486             :         if (layer > OO_LAYER_OXP_PRIORITY)
     487             :         {
     488             :                 OOLog(@"system.description.error",@"Layer %u is not a valid layer number in system information.",layer);
     489             :                 layer = OO_LAYER_OXP_PRIORITY;
     490             :         }
     491             :         NSString *key = nil;
     492             :         foreachkey(key, properties)
     493             :         {
     494             :                 if (![key isEqualToString:kOOSystemLayerProperty])
     495             :                 {
     496             :                         [propertiesInUse addObject:key];
     497             :                         [desc setProperty:key forLayer:layer toValue:[properties objectForKey:key]];
     498             :                 }
     499             :         }
     500             : }
     501             : 
     502             : 
     503           0 : - (NSDictionary *) calculatePropertiesForSystemKey:(NSString *)key
     504             : {
     505             :         NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:OO_LIKELY_PROPERTIES_PER_SYSTEM];
     506             :         NSString *property = nil;
     507             :         id val = nil;
     508             :         BOOL interstellar = [key hasPrefix:@"interstellar:"];
     509             :         foreach (property, propertiesInUse)
     510             :         {
     511             :                 // don't use universal properties on interstellar specific regions
     512             :                 val = [self getProperty:property forSystemKey:key withUniversal:!interstellar];
     513             : 
     514             :                 if (val != nil)
     515             :                 {
     516             :                         [dict setObject:val forKey:property];
     517             :                 }
     518             :                 else if (interstellar)
     519             :                 {
     520             :                         // interstellar is always overridden by specific regions
     521             :                         // universal properties for interstellar get picked up here
     522             :                         val = [self getProperty:property forSystemKey:@"interstellar"];
     523             :                         if (val != nil)
     524             :                         {
     525             :                                 [dict setObject:val forKey:property];
     526             :                         }
     527             :                 }
     528             :         }
     529             :         return dict;
     530             : }
     531             : 
     532             : 
     533           0 : - (void) updateCacheEntry:(NSUInteger)i
     534             : {
     535             :         NSAssert(i < OO_SYSTEM_CACHE_LENGTH,@"Invalid cache entry number");
     536             :         NSString *key = [NSString stringWithFormat:@"%lu %lu",i/OO_SYSTEMS_PER_GALAXY,i%OO_SYSTEMS_PER_GALAXY];
     537             :         NSDictionary *current = [self calculatePropertiesForSystemKey:key];
     538             : 
     539             :         [propertyCache[i] removeAllObjects];
     540             :         [propertyCache[i] addEntriesFromDictionary:current];
     541             : }
     542             : 
     543             : 
     544           0 : - (void) updateCacheEntry:(NSUInteger)i forProperty:(NSString *)property
     545             : {
     546             :         NSAssert(i < OO_SYSTEM_CACHE_LENGTH,@"Invalid cache entry number");
     547             :         NSString *key = [NSString stringWithFormat:@"%lu %lu",i/OO_SYSTEMS_PER_GALAXY,i%OO_SYSTEMS_PER_GALAXY];
     548             :         id current = [self getProperty:property forSystemKey:key];
     549             :         if (current == nil)
     550             :         {
     551             :                 [propertyCache[i] removeObjectForKey:property];
     552             :         }
     553             :         else
     554             :         {
     555             :                 [propertyCache[i] setObject:current forKey:property];
     556             :         }
     557             : }
     558             : 
     559             : 
     560             : - (NSPoint) getCoordinatesForSystem:(OOSystemID)s inGalaxy:(OOGalaxyID)g
     561             : {
     562             :         if (s < 0)
     563             :         {
     564             :                 OOLog(@"system.description.error",@"'%d %d' is an invalid system key. This is an internal error. Please report it.",g,s);
     565             :                 return (NSPoint){0,0};
     566             :         }
     567             :         NSUInteger index = (g * OO_SYSTEMS_PER_GALAXY) + s;
     568             :         if (index >= OO_SYSTEM_CACHE_LENGTH)
     569             :         {
     570             :                 OOLog(@"system.description.error",@"'%d %d' is an invalid system key. This is an internal error. Please report it.",g,s);
     571             :                 return (NSPoint){0,0};
     572             :         }
     573             :         return coordinatesCache[index];
     574             : }
     575             : 
     576             : 
     577             : - (NSArray *) getNeighbourIDsForSystem:(OOSystemID)s inGalaxy:(OOGalaxyID)g
     578             : {
     579             :         if (s < 0)
     580             :         {
     581             :                 OOLog(@"system.description.error",@"'%d %d' is an invalid system key. This is an internal error. Please report it.",g,s);
     582             :                 return nil;
     583             :         }
     584             :         NSUInteger index = (g * OO_SYSTEMS_PER_GALAXY) + s;
     585             :         if (index >= OO_SYSTEM_CACHE_LENGTH)
     586             :         {
     587             :                 OOLog(@"system.description.error",@"'%d %d' is an invalid system key. This is an internal error. Please report it.",g,s);
     588             :                 return nil;
     589             :         }
     590             : 
     591             :         return neighbourCache[index];
     592             : }
     593             : 
     594             : 
     595             : - (Random_Seed) getRandomSeedForCurrentSystem
     596             : {
     597             :         if ([UNIVERSE currentSystemID] < 0)
     598             :         {
     599             :                 return kNilRandomSeed;
     600             :         }
     601             :         else
     602             :         {
     603             :                 OOSystemID s = [UNIVERSE currentSystemID];
     604             :                 NSUInteger index = ([PLAYER galaxyNumber] * OO_SYSTEMS_PER_GALAXY) + s;
     605             :                 if (index >= OO_SYSTEM_CACHE_LENGTH)
     606             :                 {
     607             :                         OOLog(@"system.description.error",@"'%lu' is an invalid system index for the current system. This is an internal error. Please report it.",(unsigned long)index);
     608             :                         return kNilRandomSeed;
     609             :                 }
     610             :                 return RandomSeedFromString([propertyCache[index] oo_stringForKey:@"random_seed"]);
     611             :         }
     612             : }
     613             : 
     614             : 
     615             : - (Random_Seed) getRandomSeedForSystem:(OOSystemID)s inGalaxy:(OOGalaxyID)g
     616             : {
     617             :         if (s < 0)
     618             :         {
     619             :                 OOLog(@"system.description.error",@"'%d %d' is an invalid system key. This is an internal error. Please report it.",g,s);
     620             :                 return kNilRandomSeed;
     621             :         }
     622             :         NSUInteger index = (g * OO_SYSTEMS_PER_GALAXY) + s;
     623             :         if (index >= OO_SYSTEM_CACHE_LENGTH)
     624             :         {
     625             :                 OOLog(@"system.description.error",@"'%d %d' is an invalid system key. This is an internal error. Please report it.",g,s);
     626             :                 return kNilRandomSeed;
     627             :         }
     628             :         return RandomSeedFromString([propertyCache[index] oo_stringForKey:@"random_seed"]);
     629             : }
     630             : 
     631             : 
     632             : @end
     633             : 
     634             : 
     635             : @interface OOSystemDescriptionEntry (OOPrivate)
     636           0 : - (id) validateProperty:(NSString *)property withValue:(id)value;
     637             : @end
     638             : 
     639             : @implementation OOSystemDescriptionEntry 
     640             : 
     641           0 : - (id) init
     642             : {
     643             :         self = [super init];
     644             :         if (self != nil)
     645             :         {
     646             :                 for (NSUInteger i=0;i<OO_SYSTEM_LAYERS;i++)
     647             :                 {
     648             :                         layers[i] = [[NSMutableDictionary alloc] initWithCapacity:OO_LIKELY_PROPERTIES_PER_SYSTEM];
     649             :                 }
     650             :         }
     651             :         return self;
     652             : }
     653             : 
     654             : 
     655           0 : - (void) dealloc
     656             : {
     657             :         for (NSUInteger i=0;i<OO_SYSTEM_LAYERS;i++)
     658             :         {
     659             :                 DESTROY(layers[i]);
     660             :         }
     661             :         [super dealloc];
     662             : }
     663             : 
     664             : 
     665             : - (void) setProperty:(NSString *)property forLayer:(OOSystemLayer)layer toValue:(id)value
     666             : {
     667             :         if (value == nil)
     668             :         {
     669             :                 [layers[layer] removeObjectForKey:property];
     670             :         }
     671             :         else
     672             :         {
     673             :                 // validate type of object for certain properties
     674             :                 value = [self validateProperty:property withValue:value];
     675             :                 // if it's nil now, validation failed and could not be recovered
     676             :                 // so don't actually set anything
     677             :                 if (value != nil)
     678             :                 {
     679             :                         [layers[layer] setObject:value forKey:property];
     680             :                 }
     681             :         }
     682             : }
     683             : 
     684             : 
     685             : - (id) getProperty:(NSString *)property forLayer:(OOSystemLayer)layer
     686             : {
     687             :         return [layers[layer] objectForKey:property];
     688             : }
     689             : 
     690             : 
     691             : /* Mostly the rest of the game gets a system dictionary from
     692             :  * [UNIVERSE currentSystemData] or similar, which means that it uses
     693             :  * safe methods like oo_stringForKey: - a few things use a direct call
     694             :  * to getProperty for various reasons, so need some type validation
     695             :  * here instead. */
     696           0 : - (id) validateProperty:(NSString *)property withValue:(id)value
     697             : {
     698             :         if ([property isEqualToString:@"coordinates"])
     699             :         {
     700             :                 // must be a string with two numbers in it
     701             :                 // TODO: convert two element arrays
     702             :                 if (![value isKindOfClass:[NSString class]])
     703             :                 {
     704             :                         OOLog(@"system.description.error",@"'%@' is not a valid format for coordinates",value);
     705             :                         return nil;
     706             :                 }
     707             :                 NSArray         *tokens = ScanTokensFromString((NSString *)value);
     708             :                 if ([tokens count] != 2)
     709             :                 {
     710             :                         OOLog(@"system.description.error",@"'%@' is not a valid format for coordinates (must have exactly two numbers)",value);
     711             :                         return nil;
     712             :                 }
     713             :         } 
     714             :         else if ([property isEqualToString:@"radius"] || [property isEqualToString:@"government"]) 
     715             :         { 
     716             :                 // read in a context which expects a string, but it's a string representation of a number
     717             :                 if (![value isKindOfClass:[NSString class]])
     718             :                 {
     719             :                         if ([value isKindOfClass:[NSNumber class]])
     720             :                         {
     721             :                                 return [value stringValue];
     722             :                         }
     723             :                         else
     724             :                         {
     725             :                                 OOLog(@"system.description.error",@"'%@' is not a valid value for '%@' (string required)",value,property);
     726             :                                 return nil;
     727             :                         }
     728             :                 }
     729             :         }
     730             :         else if ([property isEqualToString:@"inhabitant"] || [property isEqualToString:@"inhabitants"] || [property isEqualToString:@"name"] ) 
     731             :         {
     732             :                 // read in a context which expects a string
     733             :                 if (![value isKindOfClass:[NSString class]])
     734             :                 {
     735             :                         OOLog(@"system.description.error",@"'%@' is not a valid value for '%@' (string required)",value,property);
     736             :                         return nil;
     737             :                 }
     738             :         }
     739             : 
     740             :         return value;
     741             : }
     742             : 
     743             : @end

Generated by: LCOV version 1.14