From 9345b2cc7b18ce8ffacd8b1369c77845bd1c7a25 Mon Sep 17 00:00:00 2001 From: Nick Loose Date: Thu, 10 Mar 2011 19:39:20 +0100 Subject: [PATCH] Can now load named worlds from beta 1.3 Used Godzil's 3ecd8a418f95e73c60890e13e5e09614234ea1df to load from folder and added the ability to save worlds and list all worlds in minecraft/saves/ --- Classes/IJInventoryWindowController.h | 9 +- Classes/IJInventoryWindowController.m | 162 ++++++++-- Classes/IJMinecraftLevel.h | 16 +- Classes/IJMinecraftLevel.m | 53 ++-- English.lproj/MainMenu.xib | 433 ++++++++++---------------- 5 files changed, 345 insertions(+), 328 deletions(-) diff --git a/Classes/IJInventoryWindowController.h b/Classes/IJInventoryWindowController.h index d5aab37..d36bb74 100644 --- a/Classes/IJInventoryWindowController.h +++ b/Classes/IJInventoryWindowController.h @@ -16,9 +16,10 @@ @interface IJInventoryWindowController : NSWindowController { IJMinecraftLevel *level; + IJMinecraftLevel *player; NSArray *inventory; - NSSegmentedControl *worldSelectionControl; + NSPopUpButton *worldSelectionControl; NSTextField *statusTextField; IJInventoryView *inventoryView; @@ -43,10 +44,11 @@ // Document int64_t sessionLockValue; int loadedWorldIndex; - int attemptedLoadWorldIndex; + NSString *loadedWorldFolder; + NSString *attemptedLoadWorldFolder; } -@property (nonatomic, assign) IBOutlet NSSegmentedControl *worldSelectionControl; +@property (nonatomic, assign) IBOutlet NSPopUpButton *worldSelectionControl; @property (nonatomic, assign) IBOutlet NSTextField *statusTextField; @property (nonatomic, assign) IBOutlet IJInventoryView *inventoryView; @property (nonatomic, assign) IBOutlet IJInventoryView *quickView; @@ -56,6 +58,7 @@ @property (nonatomic, retain) NSNumber *worldTime; +- (IBAction)menuSelectWorldFromPath:(id)sender; - (IBAction)menuSelectWorld:(id)sender; - (IBAction)worldSelectionChanged:(id)sender; - (IBAction)updateItemSearchFilter:(id)sender; diff --git a/Classes/IJInventoryWindowController.m b/Classes/IJInventoryWindowController.m index d2eca21..9532844 100644 --- a/Classes/IJInventoryWindowController.m +++ b/Classes/IJInventoryWindowController.m @@ -18,6 +18,8 @@ - (void)saveWorld; - (void)loadWorldAtIndex:(int)worldIndex; - (BOOL)isDocumentEdited; +- (void)loadWorldAtFolder:(NSString *)worldFolder; +- (void)loadWorldSelectionControl; @end @implementation IJInventoryWindowController @@ -30,6 +32,8 @@ - (void)awakeFromNib { + [self loadWorldSelectionControl]; + armorInventory = [[NSMutableArray alloc] init]; quickInventory = [[NSMutableArray alloc] init]; normalInventory = [[NSMutableArray alloc] init]; @@ -50,7 +54,6 @@ [itemTableView setTarget:self]; [itemTableView setDoubleAction:@selector(itemTableViewDoubleClicked:)]; - } - (void)dealloc @@ -72,27 +75,27 @@ { if (returnCode == NSAlertOtherReturn) // Cancel { - [worldSelectionControl setSelectedSegment:loadedWorldIndex-1]; + [worldSelectionControl selectItemWithTitle:[loadedWorldFolder lastPathComponent]]; return; } if (returnCode == NSAlertDefaultReturn) // Save { [self saveWorld]; - [self loadWorldAtIndex:attemptedLoadWorldIndex]; + [self loadWorldAtFolder:attemptedLoadWorldFolder]; } else if (returnCode == NSAlertAlternateReturn) // Don't save { [self setDocumentEdited:NO];// Slightly hacky -- prevent the alert from being put up again. - [self loadWorldAtIndex:attemptedLoadWorldIndex]; + [self loadWorldAtFolder:attemptedLoadWorldFolder]; } } -- (void)loadWorldAtIndex:(int)worldIndex +- (void)loadWorldAtFolder:(NSString *)worldPath { if ([self isDocumentEdited]) { - attemptedLoadWorldIndex = worldIndex; + attemptedLoadWorldFolder = worldPath; NSBeginInformationalAlertSheet(@"Do you want to save the changes you made in this world?", @"Save", @"Don't Save", @"Cancel", self.window, self, @selector(dirtyLoadSheetDidEnd:returnCode:contextInfo:), nil, nil, @"Your changes will be lost if you do not save them."); return; } @@ -113,24 +116,19 @@ [self didChangeValueForKey:@"worldTime"]; statusTextField.stringValue = @"No world loaded."; + + NSString *levelPath = [IJMinecraftLevel pathForLevelDatAtFolder:worldPath]; + NSData *fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:levelPath]]; + + - if (![IJMinecraftLevel worldExistsAtIndex:worldIndex]) - { - NSBeginCriticalAlertSheet(@"No world exists in that slot.", @"Dismiss", nil, nil, self.window, nil, nil, nil, nil, @"Please create a new single player world in this slot using Minecraft and try again."); - return; - } - - sessionLockValue = [IJMinecraftLevel writeToSessionLockAtIndex:worldIndex]; - if (![IJMinecraftLevel checkSessionLockAtIndex:worldIndex value:sessionLockValue]) + sessionLockValue = [IJMinecraftLevel writeToSessionLockAtFolder:worldPath]; + if (![IJMinecraftLevel checkSessionLockAtFolder:worldPath value:sessionLockValue]) { NSBeginCriticalAlertSheet(@"Error loading world.", @"Dismiss", nil, nil, self.window, nil, nil, nil, nil, @"Inside Job was unable obtain the session lock."); return; } - - NSString *levelPath = [IJMinecraftLevel pathForLevelDatAtIndex:worldIndex]; - - NSData *fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:levelPath]]; - + if (!fileData) { // Error loading @@ -140,9 +138,21 @@ [self willChangeValueForKey:@"worldTime"]; - level = [[IJMinecraftLevel nbtContainerWithData:fileData] retain]; - inventory = [[level inventory] retain]; - + /* Now search for first player .dat file (but by default try to load from level.dat */ + + NSString *playerPath = [IJMinecraftLevel pathForLevelDatAtFolder:worldPath]; + NSData *playerFileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:playerPath]]; + if (!fileData) + { + // Error loading + NSBeginCriticalAlertSheet(@"Error loading world.", @"Dismiss", nil, nil, self.window, nil, nil, nil, nil, @"InsideJob was unable to load the level at %@.", levelPath); + return; + } + + level = [[IJMinecraftLevel nbtContainerWithData:fileData] retain]; + player = [[IJMinecraftLevel nbtContainerWithData:playerFileData] retain]; + inventory = [[player inventory] retain]; + [self didChangeValueForKey:@"worldTime"]; // Add placeholder inventory items: @@ -184,22 +194,39 @@ [self setDocumentEdited:NO]; statusTextField.stringValue = @""; - loadedWorldIndex = worldIndex; + + + loadedWorldFolder = [worldPath retain]; + + NSLog(@"%@",loadedWorldFolder); + NSLog(@"%@",worldPath); + + } +- (void)loadWorldAtIndex:(int)worldIndex +{ + NSString *worldPath; + worldPath = [IJMinecraftLevel pathForWorldAtIndex:worldIndex]; + + [self loadWorldAtFolder: worldPath]; +} + + - (void)saveWorld { - int worldIndex = loadedWorldIndex; + NSString *worldPath = loadedWorldFolder; + if (inventory == nil) return; // no world loaded, nothing to save - if (![IJMinecraftLevel checkSessionLockAtIndex:worldIndex value:sessionLockValue]) + if (![IJMinecraftLevel checkSessionLockAtFolder:worldPath value:sessionLockValue]) { NSBeginCriticalAlertSheet(@"Another application has modified this world.", @"Dismiss", nil, nil, self.window, nil, nil, nil, nil, @"The session lock was changed by another application."); return; } - NSString *levelPath = [IJMinecraftLevel pathForLevelDatAtIndex:worldIndex]; + NSString *levelPath = [worldPath stringByAppendingPathComponent:@"level.dat"]; NSMutableArray *newInventory = [NSMutableArray array]; @@ -284,13 +311,90 @@ { int worldIndex = [sender tag]; [self loadWorldAtIndex:worldIndex]; - [worldSelectionControl setSelectedSegment:worldIndex - 1]; + [worldSelectionControl selectItemWithTitle:[loadedWorldFolder lastPathComponent]]; +} + +- (IBAction)menuSelectWorldFromPath:(id)sender +{ + NSInteger openResult; + /* Ask user for world folder path */ + NSOpenPanel *panel = [NSOpenPanel openPanel]; + NSString *worldPath; + + /* Only allow to choose a folder */ + [panel setCanChooseDirectories:YES]; + [panel setCanChooseFiles:NO]; + openResult = [panel runModal]; + + if (openResult == NSOKButton) + { + worldPath = [[panel directoryURL] path]; + + /* Verify for level.dat */ + if (![IJMinecraftLevel worldExistsAtFolder: worldPath]) + { + NSBeginCriticalAlertSheet(@"No world exists in that slot.", @"Dismiss", nil, nil, self.window, nil, nil, nil, nil, @"Please create a new single player world in this slot using Minecraft and try again."); + return; + } + /* Now try to open the world... */ + [self loadWorldAtFolder:[[panel directoryURL] path]]; + [worldSelectionControl addItemWithTitle:[loadedWorldFolder lastPathComponent]]; + [worldSelectionControl selectItemWithTitle:[loadedWorldFolder lastPathComponent]]; + + } } - (IBAction)worldSelectionChanged:(id)sender { - int worldIndex = [worldSelectionControl selectedSegment] + 1; - [self loadWorldAtIndex:worldIndex]; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); + NSString *path = [paths objectAtIndex:0]; + path = [path stringByAppendingPathComponent:@"minecraft"]; + path = [path stringByAppendingPathComponent:@"saves"]; + + + NSString* worldName = [worldSelectionControl titleOfSelectedItem]; + NSString* worldPath = [path stringByAppendingPathComponent:worldName]; + + NSLog(@"loadedWorldFolder: %@",loadedWorldFolder); + NSLog(@"worldName: %@",worldName); + NSLog(@"worldPath: %@",worldPath); + + [self loadWorldAtFolder:worldPath]; +} + +- (void)loadWorldSelectionControl +{ + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); + NSString *path = [paths objectAtIndex:0]; + path = [path stringByAppendingPathComponent:@"minecraft"]; + path = [path stringByAppendingPathComponent:@"saves"]; + + + NSFileManager *filemgr; + NSArray *filelist; + NSError *fileError; + int count; + int i; + + filemgr = [NSFileManager defaultManager]; + + filelist = [filemgr contentsOfDirectoryAtPath:path error:&fileError]; + + count = [filelist count]; + + + [worldSelectionControl removeAllItems]; + for (i = 0; i < count; i++) + { + NSLog (@"%@", [filelist objectAtIndex: i]); + if([IJMinecraftLevel worldExistsAtFolder:[path stringByAppendingPathComponent:[filelist objectAtIndex: i]]]) + [worldSelectionControl addItemWithTitle:[filelist objectAtIndex: i]]; + } + + + + [filemgr release]; + } - (void)saveDocument:(id)sender diff --git a/Classes/IJMinecraftLevel.h b/Classes/IJMinecraftLevel.h index 509a3f3..5c5606f 100644 --- a/Classes/IJMinecraftLevel.h +++ b/Classes/IJMinecraftLevel.h @@ -4,26 +4,28 @@ // // Created by Adam Preble on 10/7/10. // Copyright 2010 Adam Preble. All rights reserved. +// Changes for opening folder Copyright 2011 Manoel Trapier // #import #import "NBTContainer.h" @interface IJMinecraftLevel : NBTContainer { - + } @property (nonatomic, copy) NSArray *inventory; // Array of IJInventoryItem objects. @property (nonatomic, readonly) NBTContainer *worldTimeContainer; + (NSString *)pathForWorldAtIndex:(int)worldIndex; -+ (NSString *)pathForLevelDatAtIndex:(int)worldIndex; -+ (NSString *)pathForSessionLockAtIndex:(int)worldIndex; -+ (BOOL)worldExistsAtIndex:(int)worldIndex; ++ (NSString *)pathForLevelDatAtFolder:(NSString *)worldPath; ++ (NSString *)pathForSessionLockAtFolder:(NSString *)worldPath; -+ (int64_t)writeToSessionLockAtIndex:(int)worldIndex; -+ (BOOL)checkSessionLockAtIndex:(int)worldIndex value:(int64_t)checkValue; ++ (BOOL)worldExistsAtFolder:(NSString *)worldPath; + ++ (int64_t)writeToSessionLockAtFolder:(NSString *)worldPath; ++ (BOOL)checkSessionLockAtFolder:(NSString *)worldPath value:(int64_t)checkValue; -@end +@end \ No newline at end of file diff --git a/Classes/IJMinecraftLevel.m b/Classes/IJMinecraftLevel.m index ed598f9..a22bef4 100644 --- a/Classes/IJMinecraftLevel.m +++ b/Classes/IJMinecraftLevel.m @@ -4,6 +4,7 @@ // // 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" @@ -41,7 +42,7 @@ 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]; @@ -56,7 +57,7 @@ { 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 @@ -64,7 +65,7 @@ NSLog(@"%s Fixing inventory list type; was %d.", __PRETTY_FUNCTION__, inventoryList.listType); inventoryList.listType = NBTTypeCompound; } - + for (IJInventoryItem *invItem in newInventory) { NSArray *listItems = [NSArray arrayWithObjects: @@ -96,20 +97,6 @@ return path; } -+ (NSString *)pathForLevelDatAtIndex:(int)worldIndex -{ - return [[[self class] pathForWorldAtIndex:worldIndex] stringByAppendingPathComponent:@"level.dat"]; -} -+ (NSString *)pathForSessionLockAtIndex:(int)worldIndex -{ - return [[[self class] pathForWorldAtIndex:worldIndex] stringByAppendingPathComponent:@"session.lock"]; -} - -+ (BOOL)worldExistsAtIndex:(int)worldIndex -{ - return [[NSFileManager defaultManager] fileExistsAtPath:[[self class] pathForLevelDatAtIndex:worldIndex]]; -} - + (NSData *)dataWithInt64:(int64_t)v { NSMutableData *data = [NSMutableData data]; @@ -128,31 +115,47 @@ return n; } -+ (int64_t)writeToSessionLockAtIndex:(int)worldIndex +/******************************************************************************/ ++ (NSString *)pathForLevelDatAtFolder:(NSString *)worldPath { - NSString *path = [IJMinecraftLevel pathForSessionLockAtIndex:worldIndex]; + return [worldPath stringByAppendingPathComponent:@"level.dat"]; +} + ++ (NSString *)pathForSessionLockAtFolder:(NSString *)worldPath +{ + return [worldPath stringByAppendingPathComponent:@"session.lock"]; +} + ++ (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)checkSessionLockAtIndex:(int)worldIndex value:(int64_t)checkValue ++ (BOOL)checkSessionLockAtFolder:(NSString *)worldPath value:(int64_t)checkValue { - NSString *path = [IJMinecraftLevel pathForSessionLockAtIndex:worldIndex]; + 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; } diff --git a/English.lproj/MainMenu.xib b/English.lproj/MainMenu.xib index 948cc2a..775864b 100644 --- a/English.lproj/MainMenu.xib +++ b/English.lproj/MainMenu.xib @@ -12,25 +12,25 @@ YES - NSTableColumn - NSSegmentedControl + NSPopUpButtonCell NSNumberFormatter NSScroller NSMenuItem NSMenu NSTextFieldCell NSScrollView + NSPopUpButton NSBox NSImageCell NSSearchField NSTableView NSSearchFieldCell + NSCustomView NSCustomObject - NSSegmentedCell NSView NSWindowTemplate NSTextField - NSCustomView + NSTableColumn YES @@ -205,70 +205,14 @@ World YES - + Open - + o + 1048576 2147483647 - submenuAction: - - Open - - YES - - - World 1 - 1 - 1048576 - 2147483647 - - - 1 - - - - World 2 - 2 - 1048576 - 2147483647 - - - 2 - - - - World 3 - 3 - 1048576 - 2147483647 - - - 3 - - - - World 4 - 4 - 1048576 - 2147483647 - - - 4 - - - - World 5 - 5 - 1048576 - 2147483647 - - - 5 - - - @@ -793,55 +737,6 @@ 0 NO - - - 268 - {{11, 364}, {195, 25}} - - - - YES - - 67239424 - 0 - - LucidaGrande - 13 - 16 - - - - YES - - World 1 - 1 - YES - 0 - - - 2 - 2 - 0 - - - 3 - 3 - 0 - - - 4 - 4 - 0 - - - 5 - 5 - 0 - - - 2 - - 268 @@ -1153,7 +1048,6 @@ {{1, 382}, {190, 15}} - 1 _doScroller: @@ -1170,13 +1064,81 @@ QSAAAEEgAABBmAAAQZgAAA + + + 268 + {{11, 363}, {172, 25}} + + + + YES + + -2080244160 + 2048 + + + -2035269377 + 35 + + + 400 + 75 + + + Item 1 + + 1048576 + 2147483647 + 1 + + + _popUpItemAction: + + + YES + + OtherViews + + YES + + + + Item 2 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Item 3 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + + 2 + YES + YES + 2 + + {{7, 11}, {585, 396}} - + - {{0, 0}, {1440, 878}} + {{0, 0}, {1920, 1178}} {1e+13, 1e+13} MainWindow @@ -1377,22 +1339,6 @@ 593 - - - worldSelectionControl - - - - 603 - - - - worldSelectionChanged: - - - - 604 - value: worldTime @@ -1489,46 +1435,6 @@ 670 - - - menuSelectWorld: - - - - 680 - - - - menuSelectWorld: - - - - 681 - - - - menuSelectWorld: - - - - 682 - - - - menuSelectWorld: - - - - 683 - - - - menuSelectWorld: - - - - 684 - setNextDay: @@ -1585,6 +1491,30 @@ 722 + + + menuSelectWorldFromPath: + + + + 731 + + + + worldSelectionControl + + + + 738 + + + + worldSelectionChanged: + + + + 739 + @@ -1851,8 +1781,6 @@ YES - - @@ -1860,6 +1788,8 @@ + + @@ -1957,20 +1887,6 @@ - - 600 - - - YES - - - - - - 601 - - - 641 @@ -2101,59 +2017,12 @@ YES - + - - 672 - - - YES - - - - - - 673 - - - YES - - - - - - - - - - 679 - - - - - 678 - - - - - 677 - - - - - 676 - - - - - 674 - - - 112 @@ -2265,6 +2134,55 @@ + + 732 + + + YES + + + + + + 733 + + + YES + + + + + + 734 + + + YES + + + + + + + + 735 + + + + + 736 + + + + + 737 + + + + + 730 + + + @@ -2369,10 +2287,6 @@ 597.IBViewBoundsToFrameTransform 598.IBPluginDependency 599.IBPluginDependency - 600.IBPluginDependency - 600.IBViewBoundsToFrameTransform - 601.IBPluginDependency - 601.IBSegmentedControlInspectorSelectedSegmentMetadataKey 641.IBPluginDependency 641.IBViewBoundsToFrameTransform 643.IBPluginDependency @@ -2397,14 +2311,6 @@ 667.IBPluginDependency 669.IBPluginDependency 671.IBPluginDependency - 672.IBPluginDependency - 673.IBEditorWindowLastContentRect - 673.IBPluginDependency - 674.IBPluginDependency - 676.IBPluginDependency - 677.IBPluginDependency - 678.IBPluginDependency - 679.IBPluginDependency 696.IBPluginDependency 701.IBEditorWindowLastContentRect 701.IBPluginDependency @@ -2422,6 +2328,9 @@ 726.IBPluginDependency 727.IBEditorWindowLastContentRect 727.IBPluginDependency + 730.IBPluginDependency + 732.IBPluginDependency + 733.IBPluginDependency 75.IBPluginDependency 75.ImportedFromIB2 81.IBEditorWindowLastContentRect @@ -2547,12 +2456,6 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - - P4AAAL+AAABDiYAAw82AAA - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin AUKcAABDFQAAA @@ -2585,14 +2488,6 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{661, 733}, {127, 103}} - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin {{585, 1083}, {193, 53}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -2610,6 +2505,9 @@ {{778, 1023}, {189, 83}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin {{483, 773}, {178, 63}} com.apple.InterfaceBuilder.CocoaPlugin @@ -2633,7 +2531,7 @@ - 728 + 739 @@ -2658,6 +2556,7 @@ loadInventoryItems: makeSearchFieldFirstResponder: menuSelectWorld: + menuSelectWorldFromPath: saveInventoryItems: setNextDay: setNextMidnight: @@ -2680,6 +2579,7 @@ id id id + id @@ -2691,6 +2591,7 @@ loadInventoryItems: makeSearchFieldFirstResponder: menuSelectWorld: + menuSelectWorldFromPath: saveInventoryItems: setNextDay: setNextMidnight: @@ -2721,6 +2622,10 @@ menuSelectWorld: id + + menuSelectWorldFromPath: + id + saveInventoryItems: id @@ -2771,7 +2676,7 @@ NSTableView IJInventoryView NSTextField - NSSegmentedControl + NSPopUpButton @@ -2814,7 +2719,7 @@ worldSelectionControl - NSSegmentedControl + NSPopUpButton