IJMinecraftLevel.m 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. //
  2. // IJMinecraftLevel.m
  3. // InsideJob
  4. //
  5. // Created by Adam Preble on 10/7/10.
  6. // Copyright 2010 Adam Preble. All rights reserved.
  7. //
  8. #import "IJMinecraftLevel.h"
  9. #import "IJInventoryItem.h"
  10. @implementation IJMinecraftLevel
  11. - (NBTContainer *)containerWithName:(NSString *)theName inArray:(NSArray *)array
  12. {
  13. for (NBTContainer *container in array)
  14. {
  15. if ([container.name isEqual:theName])
  16. return container;
  17. }
  18. return nil;
  19. }
  20. - (NBTContainer *)inventoryList
  21. {
  22. // Inventory is found in:
  23. // - compound "Data"
  24. // - compound "Player"
  25. // - list "Inventory"
  26. // *
  27. NBTContainer *dataCompound = [self childNamed:@"Data"];
  28. NBTContainer *playerCompound = [dataCompound childNamed:@"Player"];
  29. NBTContainer *inventoryList = [playerCompound childNamed:@"Inventory"];
  30. // TODO: Check for error conditions here.
  31. return inventoryList;
  32. }
  33. - (NSArray *)inventory
  34. {
  35. NSMutableArray *output = [NSMutableArray array];
  36. for (NSArray *listItems in [self inventoryList].children)
  37. {
  38. IJInventoryItem *invItem = [[IJInventoryItem alloc] init];
  39. invItem.itemId = [[self containerWithName:@"id" inArray:listItems].numberValue shortValue];
  40. invItem.count = [[self containerWithName:@"Count" inArray:listItems].numberValue unsignedCharValue];
  41. invItem.damage = [[self containerWithName:@"Damage" inArray:listItems].numberValue shortValue];
  42. invItem.slot = [[self containerWithName:@"Slot" inArray:listItems].numberValue unsignedCharValue];
  43. [output addObject:invItem];
  44. [invItem release];
  45. }
  46. return output;
  47. }
  48. - (void)setInventory:(NSArray *)newInventory
  49. {
  50. NSMutableArray *newChildren = [NSMutableArray array];
  51. NBTContainer *inventoryList = [self inventoryList];
  52. for (IJInventoryItem *invItem in newInventory)
  53. {
  54. NSArray *listItems = [NSArray arrayWithObjects:
  55. [NBTContainer containerWithName:@"id" type:NBTTypeShort numberValue:[NSNumber numberWithShort:invItem.itemId]],
  56. [NBTContainer containerWithName:@"Damage" type:NBTTypeShort numberValue:[NSNumber numberWithShort:invItem.damage]],
  57. [NBTContainer containerWithName:@"Count" type:NBTTypeByte numberValue:[NSNumber numberWithShort:invItem.count]],
  58. [NBTContainer containerWithName:@"Slot" type:NBTTypeByte numberValue:[NSNumber numberWithShort:invItem.slot]],
  59. nil];
  60. [newChildren addObject:listItems];
  61. }
  62. inventoryList.children = newChildren;
  63. }
  64. - (NBTContainer *)worldTimeContainer
  65. {
  66. return [[self childNamed:@"Data"] childNamed:@"Time"];
  67. }
  68. #pragma mark -
  69. #pragma mark Helpers
  70. + (NSString *)pathForWorldAtIndex:(int)worldIndex
  71. {
  72. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
  73. NSString *path = [paths objectAtIndex:0];
  74. path = [path stringByAppendingPathComponent:@"minecraft"];
  75. path = [path stringByAppendingPathComponent:@"saves"];
  76. path = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"World%d", worldIndex]];
  77. return path;
  78. }
  79. + (NSString *)pathForLevelDatAtIndex:(int)worldIndex
  80. {
  81. return [[[self class] pathForWorldAtIndex:worldIndex] stringByAppendingPathComponent:@"level.dat"];
  82. }
  83. + (NSString *)pathForSessionLockAtIndex:(int)worldIndex
  84. {
  85. return [[[self class] pathForWorldAtIndex:worldIndex] stringByAppendingPathComponent:@"session.lock"];
  86. }
  87. + (BOOL)worldExistsAtIndex:(int)worldIndex
  88. {
  89. return [[NSFileManager defaultManager] fileExistsAtPath:[[self class] pathForLevelDatAtIndex:worldIndex]];
  90. }
  91. + (NSData *)dataWithInt64:(int64_t)v
  92. {
  93. NSMutableData *data = [NSMutableData data];
  94. uint32_t v0 = htonl(v >> 32);
  95. uint32_t v1 = htonl(v);
  96. [data appendBytes:&v0 length:4];
  97. [data appendBytes:&v1 length:4];
  98. return data;
  99. }
  100. + (int64_t)int64FromData:(NSData *)data
  101. {
  102. uint8_t *bytes = (uint8_t *)[data bytes];
  103. uint64_t n = ntohl(*((uint32_t *)(bytes + 0)));
  104. n <<= 32;
  105. n += ntohl(*((uint32_t *)(bytes + 4)));
  106. return n;
  107. }
  108. + (int64_t)writeToSessionLockAtIndex:(int)worldIndex
  109. {
  110. NSString *path = [IJMinecraftLevel pathForSessionLockAtIndex:worldIndex];
  111. NSDate *now = [NSDate date];
  112. NSTimeInterval interval = [now timeIntervalSince1970];
  113. int64_t milliseconds = (int64_t)(interval * 1000.0);
  114. // write as number of milliseconds
  115. NSData *data = [IJMinecraftLevel dataWithInt64:milliseconds];
  116. [data writeToFile:path atomically:YES];
  117. return milliseconds;
  118. }
  119. + (BOOL)checkSessionLockAtIndex:(int)worldIndex value:(int64_t)checkValue
  120. {
  121. NSString *path = [IJMinecraftLevel pathForSessionLockAtIndex:worldIndex];
  122. NSData *data = [NSData dataWithContentsOfFile:path];
  123. if (!data)
  124. {
  125. NSLog(@"Failed to read session lock at %@", path);
  126. return NO;
  127. }
  128. int64_t milliseconds = [IJMinecraftLevel int64FromData:data];
  129. return checkValue == milliseconds;
  130. }
  131. @end