123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- //
- // IJMinecraftLevel.m
- // InsideJob
- //
- // Created by Adam Preble on 10/7/10.
- // Copyright 2010 Adam Preble. All rights reserved.
- // Changes for opening folder Copyright 2011 Manoel Trapier
- //
- #import "IJMinecraftLevel.h"
- #import "IJInventoryItem.h"
- @implementation IJMinecraftLevel
- - (NBTContainer *)containerWithName:(NSString *)theName inArray:(NSArray *)array
- {
- for (NBTContainer *container in array)
- {
- if ([container.name isEqual:theName])
- return container;
- }
- return nil;
- }
- - (NBTContainer *)inventoryList
- {
- // Inventory is found in:
- // - compound "Data"
- // - compound "Player"
- // - list "Inventory"
- // *
- // SMP Player have not the same structure, there is no "DATA" compound, nor "player"
- NBTContainer *playerCompound;
- NBTContainer *dataCompound = [self childNamed:@"Data"];
- if (dataCompound != nil)
- {
- playerCompound = [dataCompound childNamed:@"Player"];
- }
- else
- {
- NSLog(@"Player file is from a SMP file, not level.dat one");
- playerCompound = self;
- }
-
- NBTContainer *inventoryList = [playerCompound childNamed:@"Inventory"];
- // TODO: Check for error conditions here.
- return inventoryList;
- }
- - (NSArray *)inventory
- {
- NSMutableArray *output = [NSMutableArray array];
- for (NSArray *listItems in [self inventoryList].children)
- {
- IJInventoryItem *invItem = [[IJInventoryItem alloc] init];
-
- invItem.itemId = [[self containerWithName:@"id" inArray:listItems].numberValue shortValue];
- invItem.count = [[self containerWithName:@"Count" inArray:listItems].numberValue unsignedCharValue];
- invItem.damage = [[self containerWithName:@"Damage" inArray:listItems].numberValue shortValue];
- invItem.slot = [[self containerWithName:@"Slot" inArray:listItems].numberValue unsignedCharValue];
- [output addObject:invItem];
- [invItem release];
- }
- return output;
- }
- - (void)setInventory:(NSArray *)newInventory
- {
- NSMutableArray *newChildren = [NSMutableArray array];
- NBTContainer *inventoryList = [self inventoryList];
-
- if (inventoryList.listType != NBTTypeCompound)
- {
- // There appears to be a bug in the way Minecraft writes empty inventory lists; it appears to
- // set the list type to 'byte', so we will correct it here.
- NSLog(@"%s Fixing inventory list type; was %d.", __PRETTY_FUNCTION__, inventoryList.listType);
- inventoryList.listType = NBTTypeCompound;
- }
-
- for (IJInventoryItem *invItem in newInventory)
- {
- NSArray *listItems = [NSArray arrayWithObjects:
- [NBTContainer containerWithName:@"id" type:NBTTypeShort numberValue:[NSNumber numberWithShort:invItem.itemId]],
- [NBTContainer containerWithName:@"Damage" type:NBTTypeShort numberValue:[NSNumber numberWithShort:invItem.damage]],
- [NBTContainer containerWithName:@"Count" type:NBTTypeByte numberValue:[NSNumber numberWithShort:invItem.count]],
- [NBTContainer containerWithName:@"Slot" type:NBTTypeByte numberValue:[NSNumber numberWithShort:invItem.slot]],
- nil];
- [newChildren addObject:listItems];
- }
- inventoryList.children = newChildren;
- }
- - (NBTContainer *)worldTimeContainer
- {
- return [[self childNamed:@"Data"] childNamed:@"Time"];
- }
- #pragma mark -
- #pragma mark Helpers
- + (NSString *)pathForWorldAtIndex:(int)worldIndex
- {
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
- NSString *path = [paths objectAtIndex:0];
- path = [path stringByAppendingPathComponent:@"minecraft"];
- path = [path stringByAppendingPathComponent:@"saves"];
- path = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"World%d", worldIndex]];
- return path;
- }
- + (NSData *)dataWithInt64:(int64_t)v
- {
- NSMutableData *data = [NSMutableData data];
- uint32_t v0 = htonl(v >> 32);
- uint32_t v1 = htonl(v);
- [data appendBytes:&v0 length:4];
- [data appendBytes:&v1 length:4];
- return data;
- }
- + (int64_t)int64FromData:(NSData *)data
- {
- uint8_t *bytes = (uint8_t *)[data bytes];
- uint64_t n = ntohl(*((uint32_t *)(bytes + 0)));
- n <<= 32;
- n += ntohl(*((uint32_t *)(bytes + 4)));
- return n;
- }
- /******************************************************************************/
- + (NSString *)pathForLevelDatAtFolder:(NSString *)worldPath
- {
- return [worldPath stringByAppendingPathComponent:@"level.dat"];
- }
- + (NSString *)pathForSessionLockAtFolder:(NSString *)worldPath
- {
- return [worldPath stringByAppendingPathComponent:@"session.lock"];
- }
- + (NSString *)pathForPlayer:(NSString *)loadedPlayer withWorld:(NSString *)worldPath;
- {
- /* loadedPlayer == nil, we use level.dat, or else we use the name */
- if (loadedPlayer == nil)
- return [self pathForLevelDatAtFolder:worldPath];
-
- return [[[worldPath stringByAppendingPathComponent:@"players"] stringByAppendingPathComponent:loadedPlayer] stringByAppendingPathExtension:@".dat"];
- }
- + (BOOL)worldExistsAtFolder:(NSString *)worldPath
- {
- return [[NSFileManager defaultManager] fileExistsAtPath:[[self class] pathForLevelDatAtFolder:worldPath]];
- }
- + (int64_t)writeToSessionLockAtFolder:(NSString *)worldPath
- {
- NSString *path = [IJMinecraftLevel pathForSessionLockAtFolder:worldPath];
- NSDate *now = [NSDate date];
- NSTimeInterval interval = [now timeIntervalSince1970];
- int64_t milliseconds = (int64_t)(interval * 1000.0);
- // write as number of milliseconds
-
- NSData *data = [IJMinecraftLevel dataWithInt64:milliseconds];
- [data writeToFile:path atomically:YES];
-
- return milliseconds;
- }
- + (BOOL)checkSessionLockAtFolder:(NSString *)worldPath value:(int64_t)checkValue
- {
- NSString *path = [IJMinecraftLevel pathForSessionLockAtFolder:worldPath];
- NSData *data = [NSData dataWithContentsOfFile:path];
-
- if (!data)
- {
- NSLog(@"Failed to read session lock at %@", path);
- return NO;
- }
-
- int64_t milliseconds = [IJMinecraftLevel int64FromData:data];
- return checkValue == milliseconds;
- }
- @end
|