mac docu fixes, mac launcher backport from sauer, etc

git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@3372 e016b1c5-ed68-44aa-a2f7-31cac88cffde
This commit is contained in:
core-code
2008-11-01 17:11:55 +00:00
parent baf375b83c
commit fe13d43a59
13 changed files with 655 additions and 356 deletions
+88 -30
View File
@@ -1,30 +1,88 @@
{
IBClasses = (
{CLASS = ConsoleView; LANGUAGE = ObjC; SUPERCLASS = NSView; },
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
ACTIONS = {
helpAction = id;
multiplayerAction = id;
playAction = id;
playMap = id;
playRpg = id;
};
CLASS = Launcher;
LANGUAGE = ObjC;
OUTLETS = {
console = ConsoleView;
keys = NSArrayController;
maps = NSArrayController;
multiplayer = NSButton;
resolutions = NSPopUpButton;
view1 = NSView;
view2 = NSView;
view3 = NSView;
window = NSWindow;
};
SUPERCLASS = NSObject;
}
);
IBVersion = 1;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBClasses</key>
<array>
<dict>
<key>ACTIONS</key>
<dict>
<key>helpAction</key>
<string>id</string>
<key>multiplayerAction</key>
<string>id</string>
<key>openUserdir</key>
<string>id</string>
<key>playAction</key>
<string>id</string>
<key>playMap</key>
<string>id</string>
<key>playRpg</key>
<string>id</string>
<key>showForum</key>
<string>id</string>
</dict>
<key>CLASS</key>
<string>Launcher</string>
<key>LANGUAGE</key>
<string>ObjC</string>
<key>OUTLETS</key>
<dict>
<key>console</key>
<string>ConsoleView</string>
<key>keys</key>
<string>NSArrayController</string>
<key>maps</key>
<string>NSArrayController</string>
<key>multiplayer</key>
<string>NSButton</string>
<key>prog</key>
<string>NSProgressIndicator</string>
<key>resolutions</key>
<string>NSPopUpButton</string>
<key>stencil</key>
<string>NSButton</string>
<key>tabs</key>
<string>NSTabView</string>
<key>view1</key>
<string>NSView</string>
<key>view2</key>
<string>NSView</string>
<key>view3</key>
<string>NSView</string>
<key>view4</key>
<string>NSView</string>
<key>view5</key>
<string>NSView</string>
<key>window</key>
<string>NSWindow</string>
</dict>
<key>SUPERCLASS</key>
<string>NSObject</string>
</dict>
<dict>
<key>ACTIONS</key>
<dict>
<key></key>
<string>id</string>
</dict>
<key>CLASS</key>
<string>FirstResponder</string>
<key>LANGUAGE</key>
<string>ObjC</string>
<key>SUPERCLASS</key>
<string>NSObject</string>
</dict>
<dict>
<key>CLASS</key>
<string>ConsoleView</string>
<key>LANGUAGE</key>
<string>ObjC</string>
<key>SUPERCLASS</key>
<string>NSView</string>
</dict>
</array>
<key>IBVersion</key>
<string>1</string>
</dict>
</plist>
+12 -20
View File
@@ -1,32 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>363 148 569 391 0 0 1920 1178 </string>
<key>IBEditorPositions</key>
<dict>
<key>208</key>
<string>709 615 502 340 0 0 1920 1178 </string>
<key>213</key>
<string>709 615 502 340 0 0 1920 1178 </string>
<key>264</key>
<string>709 615 502 340 0 0 1920 1178 </string>
<key>29</key>
<string>149 405 230 44 0 0 1920 1178 </string>
</dict>
<key>IBFramework Version</key>
<string>446.1</string>
<key>IBLockedObjects</key>
<array/>
<string>672</string>
<key>IBLastKnownRelativeProjectPath</key>
<string>../actioncube.xcodeproj</string>
<key>IBOldestOS</key>
<integer>5</integer>
<key>IBOpenObjects</key>
<array>
<integer>264</integer>
<integer>213</integer>
<integer>208</integer>
<integer>336</integer>
<integer>240</integer>
<integer>21</integer>
<integer>213</integer>
</array>
<key>IBSystem Version</key>
<string>8P2137</string>
<string>9F33</string>
<key>targetFramework</key>
<string>IBCocoaFramework</string>
</dict>
</plist>
Binary file not shown.
+26 -12
View File
@@ -3,24 +3,38 @@
@class ConsoleView;
@interface Launcher : NSObject {
IBOutlet NSWindow *window;
IBOutlet NSView *view1;
IBOutlet NSView *view2;
IBOutlet NSView *view3;
IBOutlet NSWindow *window;
IBOutlet NSArrayController *maps;
IBOutlet NSArrayController *keys;
//able to leave these disconnected
IBOutlet NSView *view1; //Main
IBOutlet NSView *view2; //Maps
IBOutlet NSView *view3; //Keys
IBOutlet NSView *view4; //Server
IBOutlet NSProgressIndicator *prog; //while scanning maps - it's there if you want to wire it up
IBOutlet NSArrayController *maps;
IBOutlet NSArrayController *keys;
IBOutlet NSPopUpButton *resolutions;
IBOutlet NSButton *multiplayer;
IBOutlet ConsoleView *console;
IBOutlet NSButton *stencil;
IBOutlet NSButton *multiplayer;
IBOutlet ConsoleView *console;
@private
NSMutableDictionary *toolBarItems;
pid_t server;
NSMutableDictionary *toolBarItems;
pid_t server;
NSMutableDictionary *fileRoles;
BOOL forcename;
}
- (IBAction)playAction:(id)sender;
- (IBAction)multiplayerAction:(id)sender;
- (IBAction)helpAction:(id)sender;
@end
- (IBAction)playRpg:(id)sender;
- (IBAction)playMap:(id)sender;
- (IBAction)openUserdir:(id)sender;
@end
+453 -271
View File
@@ -1,35 +1,70 @@
#import "Launcher.h"
#import "ConsoleView.h"
#include <stdlib.h>
#include <unistd.h> /* unlink */
#include <util.h> /* forkpty */
#include <unistd.h> /* _exit() */
#include <util.h> /* forkpty() */
// User default keys
#define dkVERSION @"version"
#define dkFULLSCREEN @"fullscreen"
#define dkFSAA @"fsaa"
#define dkRESOLUTION @"resolution"
#define dkADVANCEDOPTS @"advancedOptions"
#define dkSERVEROPTS @"server_options"
#define dkDESCRIPTION @"server_description"
#define dkPASSWORD @"server_password"
#define dkMAXCLIENTS @"server_maxclients"
#define kMaxDisplays 16
// unless you want strings with "(null)" in them :-/
@interface NSUserDefaults(Extras)
- (NSString*)nonNullStringForKey:(NSString*)key;
@end
//If you make a MOD then please change this, the bundle indentifier, the file extensions (.ogz, .dmo), and the url registration.
#define kSAUERBRATEN @"assaultcube"
@implementation NSUserDefaults(Extras)
- (NSString*)nonNullStringForKey:(NSString*)key {
NSString *result = [self stringForKey:key];
return (result?result:@"");
//tab names, i.e. image names (text is localised)
#define tkMAIN @"Main"
#define tkMAPS @"Maps"
#define tkKEYS @"Keys"
#define tkSERVER @"Server"
@interface NSString(Extras)
@end
@implementation NSString(Extras)
- (NSString*)expand {
NSMutableString *str = [NSMutableString string];
[str setString:self];
[str replaceOccurrencesOfString:@":s" withString:kSAUERBRATEN options:0 range:NSMakeRange(0, [str length])];
return str;
}
@end
@interface NSUserDefaults(Extras) // unless you want strings with "(null)" in them :-/
- (NSString*)nonNullStringForKey:(NSString*)key;
@end
@implementation NSUserDefaults(Extras)
- (NSString*)nonNullStringForKey:(NSString*)key {
NSString *result = [self stringForKey:key];
return (result ? result : @"");
}
@end
@interface Map : NSObject {
NSString *path;
BOOL demo, user;
}
@end
@implementation Map
- (id)initWithPath:(NSString*)aPath
- (id)initWithPath:(NSString*)aPath user:(BOOL)aUser demo:(BOOL)aDemo
{
if((self = [super init]))
{
path = [[aPath stringByDeletingPathExtension] retain];
user = aUser;
demo = aDemo;
}
return self;
}
- (void)dealloc
@@ -37,26 +72,42 @@
[path release];
[super dealloc];
}
- (NSString*)path { return path; }
- (NSString*)path { return (demo ? [NSString stringWithFormat:@"-xdemo \"%@\"", path] : path); } // minor hack
- (NSString*)name { return [path lastPathComponent]; }
- (NSImage*)image { return [[NSImage alloc] initWithContentsOfFile:[path stringByAppendingString:@".jpg"]]; }
- (NSImage*)image
{
NSImage *image = [[NSImage alloc] initWithContentsOfFile:[path stringByAppendingString:@".jpg"]];
if(!image && demo) image = [NSImage imageNamed:tkMAIN];
if(!image) image = [NSImage imageNamed:@"Nomap"];
return image;
}
- (NSString*)text
{
NSString *text = [NSString alloc];
NSError *error;
return [[NSString alloc] initWithContentsOfFile:[path stringByAppendingString:@".txt"] encoding:NSASCIIStringEncoding error:&error];
if([text respondsToSelector:@selector(initWithContentsOfFile:encoding:error:)])
text = [text initWithContentsOfFile:[path stringByAppendingString:@".txt"] encoding:NSASCIIStringEncoding error:&error];
else
text = [text initWithContentsOfFile:[path stringByAppendingString:@".txt"]]; //deprecated in 10.4
if(!text) text = (demo)?@"Recorded demo data":@"";
return text;
}
- (void)setText:(NSString*)text { } // wtf? - damn textfield believes it's editable
- (NSString*)tickIfExists:(NSString*)ext
{
unichar tickCh = 0x2713;
return [[NSFileManager defaultManager] fileExistsAtPath:[path stringByAppendingString:ext]] ? [NSString stringWithCharacters:&tickCh length:1] : @"";
return ([[NSFileManager defaultManager] fileExistsAtPath:[path stringByAppendingString:ext]] ? [NSString stringWithCharacters:&tickCh length:1] : @"");
}
- (NSString*)hasImage { return [self tickIfExists:@".jpg"]; }
- (NSString*)hasText { return [self tickIfExists:@".txt"]; }
- (NSString*)hasCfg { return [self tickIfExists:@".cfg"]; }
- (NSString*)user {
unichar tickCh = 0x2713;
return (user ? [NSString stringWithCharacters:&tickCh length:1] : @"");
}
@end
static int numberForKey(CFDictionaryRef desc, CFStringRef key)
{
CFNumberRef value;
@@ -67,19 +118,15 @@ static int numberForKey(CFDictionaryRef desc, CFStringRef key)
return num;
}
@implementation Launcher
@interface Launcher(ToolBar)
@end
@implementation Launcher(ToolBar)
- (void)switchViews:(NSToolbarItem *)item
{
NSView *prefsView;
switch([item tag])
{
case 1: prefsView = view1; break;
case 2: prefsView = view2; break;
case 3: prefsView = view3; break;
//extend as see fit...
default: return;
}
NSView *views[] = {view1, view2, view3, view4};
NSView *prefsView = views[[item tag]-1];
//to stop flicker, we make a temp blank view.
NSView *tempView = [[NSView alloc] initWithFrame:[[window contentView] frame]];
@@ -94,39 +141,38 @@ static int numberForKey(CFDictionaryRef desc, CFStringRef key)
//set the frame to newFrame and animate it.
[window setFrame:newFrame display:YES animate:YES];
//set the main content view to the new view we have picked through the if structure above.
//set the main content view to the new view we have picked through.
[window setContentView:prefsView];
[window setContentMinSize:[prefsView bounds].size];
}
- (NSToolbarItem*)addToolBarItem:(NSString*)name
{
int n = [toolBarItems count] + 1;
NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:[NSString stringWithFormat:@"%0d", n]];
[item setTag:n];
[item setTarget:self];
[item setAction:@selector(switchViews:)];
[toolBarItems setObject:item forKey:[item itemIdentifier]];
[item setLabel:NSLocalizedString(name, @"")];
[item setImage:[NSImage imageNamed:name]];
[item release];
return item;
}
- (void)initViews
- (void)initToolBar
{
toolBarItems = [[NSMutableDictionary alloc] init];
NSToolbarItem *first = [self addToolBarItem:@"Main"];
[self addToolBarItem:@"Keys"];
[self addToolBarItem:@"Server"];
NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:NSToolbarFlexibleSpaceItemIdentifier];
[toolBarItems setObject:item forKey:[item itemIdentifier]];
[item release];
[[self addToolBarItem:@"Help"] setAction:@selector(helpAction:)];
NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"PreferencePanes"];
NSEnumerator *e = [[self toolbarDefaultItemIdentifiers:nil] objectEnumerator];
NSString *identifier;
while(identifier = [e nextObject])
{
NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:identifier];
int tag = [identifier intValue];
NSString *name = identifier;
SEL action = @selector(displayHelp:);
id target = self;
if(tag) {
NSString *names[] = {tkMAIN, tkMAPS, tkKEYS, tkSERVER};
name = names[tag-1];
action = @selector(switchViews:);
target = self;
}
[item setTag:tag];
[item setTarget:target];
[item setAction:action];
[item setLabel:NSLocalizedString(name, @"")];
[item setImage:[NSImage imageNamed:name]];
[toolBarItems setObject:item forKey:identifier];
[item release];
}
NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@""];
[toolbar setDelegate:self];
[toolbar setAllowsUserCustomization:NO];
[toolbar setAutosavesConfiguration:NO];
@@ -134,14 +180,14 @@ static int numberForKey(CFDictionaryRef desc, CFStringRef key)
[toolbar release];
if([window respondsToSelector:@selector(setShowsToolbarButton:)]) [window setShowsToolbarButton:NO]; //10.4+
//Make it select the first by default
//select the first by default
NSToolbarItem *first = [toolBarItems objectForKey:[[self toolbarDefaultItemIdentifiers:nil] objectAtIndex:0]];
[toolbar setSelectedItemIdentifier:[first itemIdentifier]];
[self switchViews:first];
}
/*
* toolbar delegate methods
*/
#pragma mark toolbar delegate methods
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
{
return [toolBarItems objectForKey:itemIdentifier];
@@ -152,19 +198,58 @@ static int numberForKey(CFDictionaryRef desc, CFStringRef key)
return [self toolbarDefaultItemIdentifiers:theToolbar];
}
- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)theToolbar
- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
{
return [NSArray arrayWithObjects:@"1", @"2", @"3", NSToolbarFlexibleSpaceItemIdentifier, @"5", nil];
NSMutableArray *array = (NSMutableArray *)[self toolbarSelectableItemIdentifiers:toolbar];
[array addObject:NSToolbarFlexibleSpaceItemIdentifier];
[array addObject:@"Help"];
return array;
}
- (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar {
return [NSArray arrayWithObjects:@"1", @"2", @"3", nil];
- (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar
{
NSMutableArray *array = [NSMutableArray array];
NSView *views[] = {view1, view2, view3, view4};
int i;
for(i = 0; i < sizeof(views)/sizeof(NSView*); i++) if(views[i]) [array addObject:[NSString stringWithFormat:@"%d", i+1]];
return array;
}
- (void)displayHelp:(id)sender
{
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/help/README.html"];
if (![[NSWorkspace sharedWorkspace] openFile:path])
NSLog(@"Warning: [[NSWorkspace sharedWorkspace] openFile:path] failed");
}
@end
@implementation Launcher
/* directory where the executable lives */
+ (NSString *)cwd
{
return [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents/gamedata"];
}
/* directory where user files are kept - typically /Users/<name>/Application Support/sauerbraten */
+ (NSString*)userdir
{
FSRef folder;
NSString *path = nil;
if(FSFindFolder(kUserDomain, kApplicationSupportFolderType, NO, &folder) == noErr) {
CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &folder);
path = [(NSURL *)url path];
CFRelease(url);
path = [path stringByAppendingPathComponent:kSAUERBRATEN];
NSFileManager *fm = [NSFileManager defaultManager];
if(![fm fileExistsAtPath:path]) [fm createDirectoryAtPath:path attributes:nil]; //ensure it exists
}
return path;
}
- (void)addResolutionsForDisplay:(CGDirectDisplayID)dspy
{
@@ -190,63 +275,51 @@ static int numberForKey(CFDictionaryRef desc, CFStringRef key)
for (i = 0; i < numDisplays; i++)
[self addResolutionsForDisplay:display[i]];
}
[resolutions selectItemAtIndex: [[NSUserDefaults standardUserDefaults] integerForKey:@"resolution"]];
}
/* directory where the executable lives */
-(NSString *)cwd
{
return [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"assaultcube"];
[resolutions selectItemAtIndex: [[NSUserDefaults standardUserDefaults] integerForKey:dkRESOLUTION]];
}
/* build key array from config data */
-(NSArray *)getKeys:(NSDictionary *)dict
{
NSMutableArray *arr = [[NSMutableArray alloc] init];
NSMutableArray *arr = [NSMutableArray array];
NSEnumerator *e = [dict keyEnumerator];
NSString *key;
while ((key = [e nextObject]))
{
NSString *trig;
if([key hasPrefix:@"editbind"])
trig = [key substringFromIndex:9];
else if([key hasPrefix:@"bind"])
trig = [key substringFromIndex:5];
else
continue;
int pos = [key rangeOfString:@"bind."].location;
if(pos == NSNotFound || pos > 5) continue;
[arr addObject:[NSDictionary dictionaryWithObjectsAndKeys: //keys used in nib
trig, @"key",
[key hasPrefix:@"editbind"]?@"edit":@"", @"mode",
[key substringFromIndex:pos+5], @"key",
[key substringToIndex:pos], @"mode",
[dict objectForKey:key], @"action",
nil]];
}
return arr;
}
/*
* extract a dictionary from the config files containing:
* - name, gamma strings
* - name, team, gamma strings
* - bind/editbind '.' key strings
*/
-(NSDictionary *)readConfigFiles
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:@"" forKey:@"name"]; //ensure these entries are never nil
[dict setObject:@"" forKey:@"team"];
NSString *files[] = {@"config.cfg", @"autoexec.cfg"};
int i;
for(i = 0; i < sizeof(files)/sizeof(NSString*); i++)
{
NSString *file = [[self cwd] stringByAppendingPathComponent:files[i]];
NSString *file = [Launcher userdir];
file = [file stringByAppendingPathComponent:files[i]];
NSArray *lines = [[NSString stringWithContentsOfFile:file] componentsSeparatedByString:@"\n"];
if(i==0 && !lines) // ugh - special case when first run...
{
file = [[self cwd] stringByAppendingPathComponent:@"config/defaults.cfg"];
file = [[Launcher cwd] stringByAppendingPathComponent:@"config/defaults.cfg"];
lines = [[NSString stringWithContentsOfFile:file] componentsSeparatedByString:@"\n"];
}
@@ -257,6 +330,7 @@ static int numberForKey(CFDictionaryRef desc, CFStringRef key)
NSRange r; // more flexible to do this manually rather than via NSScanner...
int j = 0;
while(j < [line length] && [line characterAtIndex:j] <= ' ') j++; //skip white
if(j != 0) continue; // shouldn't be indented
r.location = j;
while(j < [line length] && [line characterAtIndex:j] > ' ') j++; //until white
r.length = j - r.location;
@@ -273,139 +347,28 @@ static int numberForKey(CFDictionaryRef desc, CFStringRef key)
while(j < [line length] && [line characterAtIndex:j] > ' ') j++; //until white
r.length = j - r.location;
}
if(r.location+r.length >= [line length]) continue; //missing value
NSString *value = [line substringWithRange:r];
while(j < [line length] && [line characterAtIndex:j] <= ' ') j++; //skip white
NSString *remainder = [line substringFromIndex:j];
if([type isEqual:@"name"] || [type isEqual:@"gamma"])
if([type isEqual:@"name"] || [type isEqual:@"team"] || [type isEqual:@"gamma"])
[dict setObject:value forKey:type];
else if([type isEqual:@"bind"] || [type isEqual:@"editbind"])
else if([type isEqual:@"bind"] || [type isEqual:@"editbind"] || [type isEqual:@"specbind"])
[dict setObject:remainder forKey:[NSString stringWithFormat:@"%@.%@", type,value]];
}
}
return dict;
}
-(void)updateAutoexecFile:(NSDictionary *)updates
{
NSString *file = [[self cwd] stringByAppendingPathComponent:@"config/autoexec.cfg"];
//build the data
NSString *result = nil;
NSArray *lines = [[NSString stringWithContentsOfFile:file] componentsSeparatedByString:@"\n"];
if(lines)
{
NSString *line;
NSEnumerator *e = [lines objectEnumerator];
while(line = [e nextObject])
{
NSScanner *scanner = [NSScanner scannerWithString:line];
NSString *type;
if([scanner scanCharactersFromSet:[NSCharacterSet letterCharacterSet] intoString:&type])
if([updates objectForKey:type]) continue; //skip things declared in updates
result = (result) ? [NSString stringWithFormat:@"%@\n%@", result, line] : line;
}
}
NSEnumerator *e = [updates keyEnumerator];
NSString *type;
while(type = [e nextObject])
{
id value = [updates objectForKey:type];
if([type isEqual:@"name"]) value = [NSString stringWithFormat:@"\"%@\"", value];
NSString *line = [NSString stringWithFormat:@"%@ %@", type, value];
result = (result) ? [NSString stringWithFormat:@"%@\n%@", result, line] : line;
}
//backup
NSFileManager *fm = [NSFileManager defaultManager];
NSString *backupfile = nil;
if([fm fileExistsAtPath:file])
{
backupfile = [file stringByAppendingString:@".bak"];
if(![fm movePath:file toPath:backupfile handler:nil]) return; //can't create backup
}
//write the new file
if(![fm createFileAtPath:file contents:[result dataUsingEncoding:NSASCIIStringEncoding] attributes:nil]) return; //can't create new file
//remove the backup
if(backupfile) [fm removeFileAtPath:backupfile handler:nil];
}
- (void)serverTerminated
{
if(server==-1) return;
- (void)killServer {
if(server > 0) kill(server, SIGKILL); //@WARNING - you do NOT want a 0 or -1 to be accidentally sent a kill!
server = -1;
[multiplayer setTitle:@"Start"];
[multiplayer setTitle:NSLocalizedString(@"Start", @"")];
[console appendText:@"\n \n"];
}
- (void)setServerActive:(BOOL)start
{
if((server==-1) != start) return;
if(!start)
{ //STOP
//damn server, terminate isn't good enough for you - die, die, die...
if((server!=-1) && (server!=0)) kill(server, SIGKILL); //@WARNING - you do not want a 0 or -1 to be accidentally sent a kill!
[self serverTerminated];
}
else
{ //START
NSString *cwd = [self cwd];
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSArray *opts = [[defs nonNullStringForKey:@"server_options"] componentsSeparatedByString:@" "];
const char *childCwd = [cwd fileSystemRepresentation];
const char *childPath = [[cwd stringByAppendingPathComponent:@"actioncube.app/Contents/MacOS/actioncube"] fileSystemRepresentation];
const char **args = (const char**)malloc(sizeof(char*)*([opts count] + 3 + 3)); //3 = {path, -d, NULL}, and +3 again for optional settings...
int i, fdm, argc = 0;
args[argc++] = childPath;
args[argc++] = "-d";
for(i = 0; i < [opts count]; i++)
{
NSString *opt = [opts objectAtIndex:i];
if([opt length] == 0) continue; //skip empty
args[argc++] = [opt UTF8String];
}
NSString *desc = [[NSUserDefaults standardUserDefaults] nonNullStringForKey:@"server_description"];
if (![desc isEqualToString:@""]) args[argc++] = [[NSString stringWithFormat:@"-n%@", desc] UTF8String];
NSString *pass = [[NSUserDefaults standardUserDefaults] nonNullStringForKey:@"server_password"];
if (![pass isEqualToString:@""]) args[argc++] = [[NSString stringWithFormat:@"-x%@", pass] UTF8String];
int clients = [[NSUserDefaults standardUserDefaults] integerForKey:@"server_maxclients"];
if (clients > 0) args[argc++] = [[NSString stringWithFormat:@"-c%d", clients] UTF8String];
args[argc++] = NULL;
switch ( (server = forkpty(&fdm, NULL, NULL, NULL)) ) // forkpty so we can reliably grab SDL console
{
case -1:
[console appendLine:@"Error - can't launch server"];
[self serverTerminated];
break;
case 0: // child
chdir(childCwd);
execv(childPath, (char*const*)args);
fprintf(stderr, "Error - can't launch server\n");
_exit(0);
default: // parent
free(args);
//fprintf(stderr, "fdm=%d\n", slave_name, fdm);
[multiplayer setTitle:@"Stop"];
NSFileHandle *taskOutput = [[NSFileHandle alloc] initWithFileDescriptor:fdm];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(serverDataAvailable:) name:NSFileHandleReadCompletionNotification object:taskOutput];
[taskOutput readInBackgroundAndNotify];
break;
}
}
}
- (void)serverDataAvailable:(NSNotification *)note
{
NSFileHandle *taskOutput = [note object];
@@ -413,7 +376,7 @@ static int numberForKey(CFDictionaryRef desc, CFStringRef key)
if (data && [data length])
{
NSString *text = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSString *text = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
[console appendText:text];
[text release];
[taskOutput readInBackgroundAndNotify]; //wait for more data
@@ -423,105 +386,324 @@ static int numberForKey(CFDictionaryRef desc, CFStringRef key)
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:self name:NSFileHandleReadCompletionNotification object:taskOutput];
close([taskOutput fileDescriptor]);
[self setServerActive:NO];
[self killServer];
}
}
- (BOOL)playFile
- (BOOL)launchGame:(NSArray *)args {
NSString *cwd = [Launcher cwd];
NSString *exe = [[NSBundle bundleWithPath:[cwd stringByAppendingPathComponent:[@":s.app" expand]]] executablePath];
BOOL okay = YES;
if([args containsObject:@"-d"])
{
if(server != -1) return NO; // server is already running
const char **argv = (const char**)malloc(sizeof(char*)*([args count] + 2)); //{path, <args>, NULL};
argv[0] = [exe fileSystemRepresentation];
argv[[args count]+1] = NULL;
int i;
for(i = 0; i < [args count]; i++) argv[i+1] = [[args objectAtIndex:i] UTF8String];
int fdm;
NSString *fail = [NSLocalizedString(@"ServerAlertMesg", nil) expand];
switch ( (server = forkpty(&fdm, NULL, NULL, NULL)) ) // forkpty so we can reliably grab SDL console
{
case -1:
[console appendLine:fail];
[self killServer];
okay = NO;
break;
case 0: // child
chdir([cwd fileSystemRepresentation]);
if(execv([exe fileSystemRepresentation], (char*const*)argv) == -1) fprintf(stderr, "%s\n", [fail UTF8String]);
_exit(0);
default: // parent
[multiplayer setTitle:NSLocalizedString(@"Stop", @"")];
NSFileHandle *taskOutput = [[NSFileHandle alloc] initWithFileDescriptor:fdm];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(serverDataAvailable:) name:NSFileHandleReadCompletionNotification object:taskOutput];
[taskOutput readInBackgroundAndNotify];
break;
}
free(argv);
}
else
{
NS_DURING
NSTask *task = [[NSTask alloc] init];
[task setCurrentDirectoryPath:cwd];
[task setLaunchPath:exe];
[task setArguments:args];
[task setEnvironment:[NSDictionary dictionaryWithObjectsAndKeys:
@"1", @"SDL_SINGLEDISPLAY",
@"1", @"SDL_ENABLEAPPEVENTS", nil
]]; // makes Command-H, Command-M and Command-Q work at least when not in fullscreen
[task launch];
if(server == -1) [NSApp terminate:self]; //if there is a server then don't exit!
NS_HANDLER
//NSLog(@"%@", localException);
NSBeginCriticalAlertSheet(
[NSLocalizedString(@"ClientAlertTitle", @"") expand] , nil, nil, nil,
window, nil, nil, nil, nil,
[NSLocalizedString(@"ClientAlertMesg", @"") expand]);
okay = NO;
NS_ENDHANDLER
}
return okay;
}
/*
* nil will just launch the fps game
* "-rpg" will launch the rpg demo
* "-x.." will launch and run commands
* otherwise we are specifying a map to play
*/
- (BOOL)playFile:(id)filename
{
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSArray *res = [[resolutions titleOfSelectedItem] componentsSeparatedByString:@" x "];
NSMutableArray *args = [[NSMutableArray alloc] init];
NSString *cwd = [self cwd];
NSMutableArray *args = [NSMutableArray array];
//suppose could use this to update gamma and keys too, but can't be bothered...
[self updateAutoexecFile:[NSDictionary dictionaryWithObjectsAndKeys:
[defs nonNullStringForKey:@"name"], @"name",
nil]];
[args addObject:[NSString stringWithFormat:@"-w%@", [res objectAtIndex:0]]];
[args addObject:[NSString stringWithFormat:@"-h%@", [res objectAtIndex:1]]];
[args addObject:@"-z32"];
[args addObject:@"-z32"]; //otherwise seems to have a fondness to use -z16 which looks crap
if([defs integerForKey:@"fullscreen"] == 0) [args addObject:@"-t"];
[args addObject:[NSString stringWithFormat:@"-a%d", [defs integerForKey:@"fsaa"]]];
[args addObject:[NSString stringWithFormat:@"-f%d", [defs integerForKey:@"shader"]]];
if([defs integerForKey:dkFULLSCREEN] == 0) [args addObject:@"-t"];
[args addObject:[NSString stringWithFormat:@"-a%d", [defs integerForKey:dkFSAA]]];
if ([stencil state] == NSOnState) [args addObject:@"-z8"];
NSString *adv = [defs nonNullStringForKey:@"advancedOptions"];
if(![adv isEqual:@""]) [args addObjectsFromArray:[adv componentsSeparatedByString:@" "]];
[args addObject:[NSString stringWithFormat:@"--home=%@", [Launcher userdir]]];
NSMutableArray *cmds = [NSMutableArray array];
if(forcename) [cmds addObject:[NSString stringWithFormat:@"name \"%@\"", NSUserName()]];
NSTask *task = [[NSTask alloc] init];
[task setCurrentDirectoryPath:cwd];
[task setLaunchPath:[cwd stringByAppendingPathComponent:@"actioncube.app/Contents/MacOS/actioncube"]];
[task setArguments:args];
[task setEnvironment:[NSDictionary dictionaryWithObjectsAndKeys:
@"1", @"SDL_SINGLEDISPLAY",
@"1", @"SDL_ENABLEAPPEVENTS", nil
]]; // makes Command-H, Command-M and Command-Q work at least when not in fullscreen
[args release];
BOOL okay = YES;
NS_DURING
[task launch];
if(server==-1) [NSApp terminate:self]; //if there is a server then don't exit!
NS_HANDLER
//NSLog(@"%@", localException);
NSBeginCriticalAlertSheet(
@"Can't start AssaultCube", nil, nil, nil,
window, nil, nil, nil, nil,
@"Please move the directory containing AssaultCube to a path that doesn't contain weird characters or start AssaultCube manually.");
okay = NO;
NS_ENDHANDLER
return okay;
if(filename)
{
if([filename isEqual:@"-rpg"]) {
[cmds removeAllObjects]; // rpg current doesn't require name/team
[args addObject:@"-grpg"]; //demo the rpg game
} else if([filename hasPrefix:@"-x"])
[cmds addObject:[filename substringFromIndex:2]];
else
[args addObject:[NSString stringWithFormat:@"-l%@", filename]];
}
if([cmds count] > 0)
{
NSString *script = [cmds objectAtIndex:0];
int i;
for(i = 1; i < [cmds count]; i++) script = [NSString stringWithFormat:@"%@;%@", script, [cmds objectAtIndex:i]];
[args addObject:[NSString stringWithFormat:@"-x%@", script]];
}
NSEnumerator *e = [[[defs nonNullStringForKey:dkADVANCEDOPTS] componentsSeparatedByString:@" "] objectEnumerator];
NSString *opt;
while(opt = [e nextObject]) if([opt length] != 0) [args addObject:opt]; //skip empty ones
return [self launchGame:args];
}
- (void)scanMaps:(id)obj //@note threaded!
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i;
for(i = 0; i < 2; i++)
{
NSString *dir = (i==0) ? [Launcher cwd] : [Launcher userdir];
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtPath:dir];
NSString *file;
while(file = [enumerator nextObject])
{
NSString *role = [fileRoles objectForKey:[file pathExtension]];
if(role)
{
Map *map = [[Map alloc] initWithPath:[dir stringByAppendingPathComponent:file] user:(i==1) demo:[role isEqual:@"Viewer"]];
[maps performSelectorOnMainThread:@selector(addObject:) withObject:map waitUntilDone:NO];
}
}
}
[prog performSelectorOnMainThread:@selector(stopAnimation:) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void)initMaps
{
[prog startAnimation:nil];
[maps removeObjects:[maps arrangedObjects]];
[NSThread detachNewThreadSelector: @selector(scanMaps:) toTarget:self withObject:nil];
}
- (void)awakeFromNib
{
[self initViews];
//generate some pretty icons if they are missing
NSRect region = NSMakeRect(0, 0, 64, 64);
NSImage *image = [NSImage imageNamed:tkMAIN];
if(!image) {
image = [[NSImage imageNamed:@"NSApplicationIcon"] copy];
[image setSize:region.size];
[image setName:tkMAIN]; //one less image to include
}
[self initToolBar];
[window setBackgroundColor:[NSColor colorWithDeviceRed:0.90 green:0.90 blue:0.90 alpha:1.0]]; //Apples 'mercury' crayon color
//from the plist we determine that dmo->Viewer, and ogz->Editor
fileRoles = [[NSMutableDictionary dictionary] retain];
NSEnumerator *types = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDocumentTypes"] objectEnumerator];
NSDictionary *type;
while((type = [types nextObject])) {
NSString *role = [type objectForKey:@"CFBundleTypeRole"];
NSEnumerator *exts = [[type objectForKey:@"CFBundleTypeExtensions"] objectEnumerator];
NSString *ext;
while((ext = [exts nextObject])) [fileRoles setObject:role forKey:ext];
}
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSFileManager *fm = [NSFileManager defaultManager];
NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
NSString *version = [defs stringForKey:dkVERSION];
if(!version || ![version isEqual:appVersion])
{
NSLog(@"Upgraded Version...");
//need to flush lurking config files - they're automatically generated, so no big deal...
NSString *dir = [Launcher userdir];
[fm removeFileAtPath:[dir stringByAppendingPathComponent:@"init.cfg"] handler:nil];
[fm removeFileAtPath:[dir stringByAppendingPathComponent:@"config.cfg"] handler:nil];
}
[defs setObject:appVersion forKey:dkVERSION];
NSDictionary *dict = [self readConfigFiles];
[keys addObjects:[self getKeys:dict]];
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
if([[defs nonNullStringForKey:@"name"] isEqual:@""])
{
NSString *name = [dict objectForKey:@"name"];
if([name isEqual:@""] || [name isEqual:@"unnamed"]) name = NSUserName();
[defs setValue:name forKey:@"name"];
}
//encourage people not to remain unnamed
NSString *name = [dict objectForKey:@"name"];
forcename = (!name || [name isEqual:@""] || [name isEqual:@"unnamed"]);
[self initMaps];
[self initResolutions];
server = -1;
[window setDelegate:self]; // so can catch the window close
[NSApp setDelegate:self]; //so can catch the double-click & dropped files
[NSApp setDelegate:self]; //so can catch the double-click, dropped files, termination
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(getUrl:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
}
-(void)windowWillClose:(NSNotification *)notification
#pragma mark -
#pragma mark application delegate
- (void)applicationDidFinishLaunching:(NSNotification *)note {
NSFileManager *fm = [NSFileManager defaultManager];
NSString *dir = [Launcher cwd];
if(![fm fileExistsAtPath:dir])
NSBeginCriticalAlertSheet(
[NSLocalizedString(@"InitAlertTitle", @"") expand], nil, nil, nil,
window, self, nil, nil, nil,
[NSLocalizedString(@"InitAlertMesg", @"") expand]);
}
-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
return YES;
}
- (void)applicationWillTerminate: (NSNotification *)note {
[self killServer];
}
//we register 'ogz' and 'dmo' as doc types
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
[self setServerActive:NO];
[NSApp terminate:self];
NSString *role = [fileRoles objectForKey:[filename pathExtension]];
if(!role) return NO;
BOOL demo = [role isEqual:@"Viewer"];
filename = [filename stringByDeletingPathExtension]; //chop off extension
int i;
for(i = 0; i < 2; i++) {
NSString *pkg = (i == 0) ? [Launcher cwd] : [Launcher userdir];
if(!demo) pkg = [pkg stringByAppendingPathComponent:@"packages"];
if([filename hasPrefix:pkg])
return [self playFile:(demo ? [NSString stringWithFormat:@"-xdemo \"%@\"", filename] : filename)];
}
NSBeginCriticalAlertSheet(
[NSLocalizedString(@"FileAlertMesg", @"") expand], NSLocalizedString(@"Ok", @""), NSLocalizedString(@"Cancel", @""), nil,
window, self, @selector(openPackageFolder:returnCode:contextInfo:), nil, nil,
[NSLocalizedString(@"FileAlertMesg", @"") expand]);
return NO;
}
/*
* Interface actions
*/
- (void)openPackageFolder:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
if(returnCode == 0) return;
[self openUserdir:nil];
}
//we register 'sauerbraten' as a url scheme
- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
NSURL *url = [NSURL URLWithString:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]];
if(!url) return;
[self playFile:[NSString stringWithFormat:@"-xconnect %@", [url host]]];
}
#pragma mark interface actions
- (IBAction)multiplayerAction:(id)sender
{
[window makeFirstResponder:window]; //ensure fields are exited and committed
[self setServerActive:(server==-1)];
if(server != -1)
{
[self killServer];
}
else
{
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSMutableArray *args = [NSMutableArray arrayWithObject:@"-d"];
NSEnumerator *e = [[[defs nonNullStringForKey:dkSERVEROPTS] componentsSeparatedByString:@" "] objectEnumerator];
NSString *opt;
while(opt = [e nextObject]) if([opt length] != 0) [args addObject:opt]; //skip empty ones
NSString *desc = [defs nonNullStringForKey:dkDESCRIPTION];
if (![desc isEqual:@""]) [args addObject:[NSString stringWithFormat:@"-n%@", desc]];
NSString *pass = [defs nonNullStringForKey:dkPASSWORD];
if (![pass isEqual:@""]) [args addObject:[NSString stringWithFormat:@"-p%@", pass]];
int clients = [defs integerForKey:dkMAXCLIENTS];
if (clients > 0) [args addObject:[NSString stringWithFormat:@"-c%d", clients]];
[args addObject:[NSString stringWithFormat:@"-q%@", [Launcher userdir]]];
[self launchGame:args];
}
}
- (IBAction)playAction:(id)sender
{
[window makeFirstResponder:window]; //ensure fields are exited and committed
[self playFile];
[self playFile:nil];
}
- (IBAction)helpAction:(id)sender
{
NSString *file = [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"README.html"];
[[NSWorkspace sharedWorkspace] openURL:[NSURL fileURLWithPath:file]];
- (IBAction)playRpg:(id)sender
{
[self playFile:@"-rpg"];
}
@end
- (IBAction)playMap:(id)sender
{
NSArray *sel = [maps selectedObjects];
if(sel && [sel count] > 0) [self playFile:[[sel objectAtIndex:0] path]];
}
- (IBAction)openUserdir:(id)sender
{
[[NSWorkspace sharedWorkspace] openFile:[Launcher userdir]];
}
@end
+2 -2
View File
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>actioncube</string>
<string>assaultcube</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
@@ -45,6 +45,7 @@
B96D0D590920970C00B6C936 /* Launcher.m in Sources */ = {isa = PBXBuildFile; fileRef = B96D0D580920970C00B6C936 /* Launcher.m */; };
B96D0D630920971300B6C936 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = B96D0D5A0920971300B6C936 /* MainMenu.nib */; };
B96D0D6D0920976E00B6C936 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B96D0D6C0920976E00B6C936 /* main.m */; };
B975E7F40EBCC3A200880D5D /* map.icns in Resources */ = {isa = PBXBuildFile; fileRef = B975E7F30EBCC3A200880D5D /* map.icns */; };
B98944640EA68F70003CC623 /* shadow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B98944630EA68F70003CC623 /* shadow.cpp */; };
B9FA3B420DD9E6C900581F8D /* worldrender.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B9FA3B090DD9E6C900581F8D /* worldrender.cpp */; };
B9FA3B430DD9E6C900581F8D /* editing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B9FA3B0A0DD9E6C900581F8D /* editing.cpp */; };
@@ -154,12 +155,13 @@
B2F67ED704C74A3F00A80002 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
B92DC0F909D08CF9008219BD /* SDL_image.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL_image.framework; path = /Library/Frameworks/SDL_image.framework; sourceTree = "<absolute>"; };
B92DC0FB09D08CF9008219BD /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = /Library/Frameworks/SDL.framework; sourceTree = "<absolute>"; };
B94198CB09207E810029DAD1 /* actioncube.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = actioncube.app; sourceTree = BUILT_PRODUCTS_DIR; };
B94198CB09207E810029DAD1 /* assaultcube.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = assaultcube.app; sourceTree = BUILT_PRODUCTS_DIR; };
B96D0D4C092096F200B6C936 /* launcher.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = launcher.app; sourceTree = BUILT_PRODUCTS_DIR; };
B96D0D570920970C00B6C936 /* Launcher.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Launcher.h; sourceTree = "<group>"; };
B96D0D580920970C00B6C936 /* Launcher.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Launcher.m; sourceTree = "<group>"; };
B96D0D5B0920971300B6C936 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; };
B96D0D6C0920976E00B6C936 /* main.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
B975E7F30EBCC3A200880D5D /* map.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = map.icns; sourceTree = "<group>"; };
B98944630EA68F70003CC623 /* shadow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shadow.cpp; sourceTree = "<group>"; };
B9CACA12092099DF00A13F04 /* launcher-Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = "launcher-Info.plist"; sourceTree = "<group>"; };
B9FA3B090DD9E6C900581F8D /* worldrender.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = worldrender.cpp; sourceTree = "<group>"; };
@@ -292,7 +294,7 @@
19C28FACFE9D520D11CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
B94198CB09207E810029DAD1 /* actioncube.app */,
B94198CB09207E810029DAD1 /* assaultcube.app */,
B96D0D4C092096F200B6C936 /* launcher.app */,
);
name = Products;
@@ -327,6 +329,7 @@
B96D0D5A0920971300B6C936 /* MainMenu.nib */,
089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
665CDD4A0AFE7FBD0030D605 /* actioncube.icns */,
B975E7F30EBCC3A200880D5D /* map.icns */,
66899EA80C14887F00927C34 /* Help.tiff */,
66899EA90C14887F00927C34 /* Keys.gif */,
66899EAA0C14887F00927C34 /* Main.gif */,
@@ -485,9 +488,9 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
B941988A09207E810029DAD1 /* actioncube */ = {
B941988A09207E810029DAD1 /* assaultcube */ = {
isa = PBXNativeTarget;
buildConfigurationList = B94198C609207E810029DAD1 /* Build configuration list for PBXNativeTarget "actioncube" */;
buildConfigurationList = B94198C609207E810029DAD1 /* Build configuration list for PBXNativeTarget "assaultcube" */;
buildPhases = (
B941988B09207E810029DAD1 /* Headers */,
B94198A409207E810029DAD1 /* Resources */,
@@ -500,10 +503,10 @@
dependencies = (
B96D0D790920980E00B6C936 /* PBXTargetDependency */,
);
name = actioncube;
name = assaultcube;
productInstallPath = "$(HOME)/Applications";
productName = sauerbraten;
productReference = B94198CB09207E810029DAD1 /* actioncube.app */;
productReference = B94198CB09207E810029DAD1 /* assaultcube.app */;
productType = "com.apple.product-type.application";
};
B96D0D4B092096F200B6C936 /* launcher */ = {
@@ -533,9 +536,9 @@
hasScannedForEncodings = 1;
mainGroup = 29B97314FDCFA39411CA2CEA /* sauerbraten */;
projectDirPath = "";
projectRoot = ..;
projectRoot = "";
targets = (
B941988A09207E810029DAD1 /* actioncube */,
B941988A09207E810029DAD1 /* assaultcube */,
B96D0D4B092096F200B6C936 /* launcher */,
);
};
@@ -562,6 +565,7 @@
66899EB90C14898500927C34 /* Server.gif in Resources */,
B90357B509D09B9D002C9DC7 /* InfoPlist.strings in Resources */,
665CDFD20AFE90F30030D605 /* actioncube.icns in Resources */,
B975E7F40EBCC3A200880D5D /* map.icns in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -579,7 +583,7 @@
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
shellScript = "echo $TARGET_BUILD_DIR\ncd $TARGET_BUILD_DIR\n\n#make the directory which our disk image will be made of\nmkdir AssaultCube\nmkdir AssaultCube/assaultcube\n\n#copy sauerbraten there\n/Developer/Tools/CpMac -r $TARGET_BUILD_DIR/actioncube.app AssaultCube/assaultcube\n/Developer/Tools/CpMac -r $TARGET_BUILD_DIR/launcher.app AssaultCube/\nmv AssaultCube/launcher.app AssaultCube/AssaultCube.app\nstrip -u -r $TARGET_BUILD_DIR/AssaultCube/assaultcube/actioncube.app/Contents/MacOS/actioncube -o $TARGET_BUILD_DIR/AssaultCube/assaultcube/actioncube.app/Contents/MacOS/actioncube_stripped\nmv $TARGET_BUILD_DIR/AssaultCube/assaultcube/actioncube.app/Contents/MacOS/actioncube $TARGET_BUILD_DIR/actioncube_nonstripped\nmv $TARGET_BUILD_DIR/AssaultCube/assaultcube/actioncube.app/Contents/MacOS/actioncube_stripped $TARGET_BUILD_DIR/AssaultCube/assaultcube/actioncube.app/Contents/MacOS/actioncube\ncp $SRCROOT/../../README.html $TARGET_BUILD_DIR/AssaultCube/\n\n#install all frameworks into app bundle\nmkdir AssaultCube/assaultcube/actioncube.app/Contents/Frameworks\nfor framework in SDL.framework SDL_image.framework Ogg.framework Vorbis.framework\ndo\n\tif [ -d $LOCAL_LIBRARY_DIR/Frameworks/$framework/ ] \n\tthen\t\n\t\t/Developer/Tools/CpMac -r $LOCAL_LIBRARY_DIR/Frameworks/$framework/ AssaultCube/assaultcube/actioncube.app/Contents/Frameworks\n\t\trm -rf AssaultCube/assaultcube/actioncube.app/Contents/Frameworks/$framework/Versions/A/Headers\n\telse\n\t\texit 1\n\tfi\ndone\n\n#copy readme and data and remove unneccesary stuff\n/Developer/Tools/CpMac -r $SRCROOT/../../docs AssaultCube/\n/Developer/Tools/CpMac -r $SRCROOT/../../bot AssaultCube/assaultcube/\n/Developer/Tools/CpMac -r $SRCROOT/../../config AssaultCube/assaultcube/\n/Developer/Tools/CpMac -r $SRCROOT/../../packages AssaultCube/assaultcube/\nrm -rf AssaultCube/docs/CVS/\nrm -rf AssaultCube/docs/*/CVS/\nrm -rf AssaultCube/docs/*/*/CVS/\nrm -f AssaultCube/docs/.DS_Store\nrm -f AssaultCube/docs/*/.DS_Store\nrm -f AssaultCube/docs/*/*/.DS_Store\nrm -rf AssaultCube/assaultcube/packages/CVS/\nrm -rf AssaultCube/assaultcube/packages/*/CVS/\nrm -rf AssaultCube/assaultcube/packages/*/*/CVS/\nrm -f AssaultCube/assaultcube/packages/.DS_Store\nrm -f AssaultCube/assaultcube/packages/*/.DS_Store\nrm -f AssaultCube/assaultcube/packages/*/*/.DS_Store\nrm -rf AssaultCube/assaultcube/config/CVS/\nrm -f AssaultCube/assaultcube/config/.DS_Store\nrm -rf AssaultCube/assaultcube/bot/CVS/\nrm -rf AssaultCube/assaultcube/bot/*/CVS/\nrm -f AssaultCube/assaultcube/bot/.DS_Store\nrm -f AssaultCube/assaultcube/bot/*/.DS_Store\nrm -rf AssaultCube/assaultcube/data/CVS/\nrm -rf AssaultCube/assaultcube/data/*/CVS/\nrm -f AssaultCube/assaultcube/data/.DS_Store\nrm -f AssaultCube/assaultcube/data/*/.DS_Store\n\n#finally make a disk image out of the stuff\nhdiutil create -srcfolder AssaultCube AssaultCube.dmg\nhdiutil internet-enable -yes AssaultCube.dmg\n\n#cleanup\nrm -r AssaultCube";
shellScript = "echo $TARGET_BUILD_DIR\ncd $TARGET_BUILD_DIR\n\n#ensure old package is gone\nrm -f assaultcube.dmg\n\n#make the directory which our disk image will be made of\n#use /tmp as a destination because copying ourself (xcode folder) whilst compling causes the dog to chase its tail\nACPKG=`mktemp -d /tmp/acpkg.XXXXXX` || exit 1\n\n#leave indicator of where temp directory is in case things break\nln -sf $ACPKG $TARGET_BUILD_DIR/acpkg\n\n#copy launcher\n/Developer/Tools/CpMac -r $TARGET_BUILD_DIR/launcher.app $ACPKG/AssaultCube.app\n\nHELPDIR=$ACPKG/AssaultCube.app/Contents/Resources/help/\nGAMEDIR=$ACPKG/AssaultCube.app/Contents/gamedata\nmkdir $GAMEDIR\nmkdir $HELPDIR\n\n#copy assaultcube\n/Developer/Tools/CpMac -r $TARGET_BUILD_DIR/assaultcube.app $GAMEDIR/\nstrip -u -r $GAMEDIR/assaultcube.app/Contents/MacOS/assaultcube\n\n#install all frameworks into app bundle\nmkdir $GAMEDIR/assaultcube.app/Contents/Frameworks\nfor framework in SDL.framework SDL_image.framework Ogg.framework Vorbis.framework\ndo\n\tif [ -d $LOCAL_LIBRARY_DIR/Frameworks/$framework/ ] \n\tthen\t\n\t\t/Developer/Tools/CpMac -r $LOCAL_LIBRARY_DIR/Frameworks/$framework/ $GAMEDIR/assaultcube.app/Contents/Frameworks\n\t\trm -rf $GAMEDIR/assaultcube.app/Contents/Frameworks/$framework/Versions/A/Headers\n\telse\n\t\texit 1\n\tfi\ndone\n\n\n#copy readme and data and remove unneccesary stuff\n/Developer/Tools/CpMac -r $SRCROOT/../../README.html $HELPDIR/\n/Developer/Tools/CpMac -r $SRCROOT/../../docs $HELPDIR/\n/Developer/Tools/CpMac -r $SRCROOT/../../bot $GAMEDIR/\n/Developer/Tools/CpMac -r $SRCROOT/../../config $GAMEDIR/\n/Developer/Tools/CpMac -r $SRCROOT/../../screenshots $GAMEDIR/\n/Developer/Tools/CpMac -r $SRCROOT/../../mods $GAMEDIR/\n/Developer/Tools/CpMac -r $SRCROOT/../../packages $GAMEDIR/\n/Developer/Tools/CpMac -r $SRCROOT/../../source $ACPKG/sourcecode\nfind -d $ACPKG -name \"CVS\" -exec rm -rf {} \\;\nfind $ACPKG -name \".DS_Store\" -exec rm -f {} \\;\nrm -rf $ACPKG/sourcecode/xcode/build\n\n#add alias to readme\n/usr/bin/osascript <<EOT\ntell application \"Finder\"\nset macSrcPath to POSIX file \"$HELPDIR/README.html\" as text\nset macDestPath to POSIX file \"$ACPKG\" as text\nmake new alias file to file macSrcPath at folder macDestPath\nend tell\nEOT\n\n#finally make a disk image out of the stuff\nhdiutil create -srcfolder $ACPKG -volname assaultcube assaultcube.dmg\nhdiutil internet-enable -yes assaultcube.dmg\n\n#cleanup\nrm -rf $ACPKG";
};
/* End PBXShellScriptBuildPhase section */
@@ -696,7 +700,7 @@
);
INFOPLIST_FILE = "actioncube-Info.plist";
OTHER_LDFLAGS = "-lz";
PRODUCT_NAME = actioncube;
PRODUCT_NAME = assaultcube;
};
name = Debug;
};
@@ -712,7 +716,7 @@
);
INFOPLIST_FILE = "actioncube-Info.plist";
OTHER_LDFLAGS = "-lz";
PRODUCT_NAME = actioncube;
PRODUCT_NAME = assaultcube;
};
name = Release;
};
@@ -731,7 +735,7 @@
);
INFOPLIST_FILE = "actioncube-Info.plist";
OTHER_LDFLAGS = "-lz";
PRODUCT_NAME = actioncube;
PRODUCT_NAME = assaultcube;
};
name = "Release-Deployment";
};
@@ -889,7 +893,7 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
B94198C609207E810029DAD1 /* Build configuration list for PBXNativeTarget "actioncube" */ = {
B94198C609207E810029DAD1 /* Build configuration list for PBXNativeTarget "assaultcube" */ = {
isa = XCConfigurationList;
buildConfigurations = (
B94198C709207E810029DAD1 /* Debug */,
+36 -1
View File
@@ -1,7 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>dmo</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>map.icns</string>
<key>CFBundleTypeName</key>
<string>AssaultCube demo</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSTypeIsPackage</key>
<false/>
<key>NSPersistentStoreTypeKey</key>
<string>Binary</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>cgz</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>map.icns</string>
<key>CFBundleTypeName</key>
<string>AssaultCube map</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSTypeIsPackage</key>
<false/>
<key>NSPersistentStoreTypeKey</key>
<string>Binary</string>
</dict>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
+15 -3
View File
@@ -1,8 +1,8 @@
#import <Cocoa/Cocoa.h>
#define _MAXDEFSTR 260
#define MAXSTRLEN 260
inline char *s_strncpy(char *d, const char *s, size_t m) { strncpy(d,s,m); d[m-1] = 0; return d; };
inline char *s_strcat(char *d, const char *s) { size_t n = strlen(d); return s_strncpy(d+n,s,_MAXDEFSTR-n); };
inline char *s_strcat(char *d, const char *s) { size_t n = strlen(d); return s_strncpy(d+n,s,MAXSTRLEN-n); };
void mac_pasteconsole(char *commandbuf)
{
@@ -13,4 +13,16 @@ void mac_pasteconsole(char *commandbuf)
if (contents != nil)
s_strcat(commandbuf, [contents lossyCString]);
}
}
}
/*
* 0x1030 = 10.3
* 0x1040 = 10.4
* 0x1050 = 10.5
*/
int mac_osversion()
{
SInt32 MacVersion;
Gestalt(gestaltSystemVersion, &MacVersion);
return MacVersion;
}
Binary file not shown.