Index: src/Cube.mm ================================================================== --- src/Cube.mm +++ src/Cube.mm @@ -66,10 +66,22 @@ sdesc = @""; if (ip == nil) ip = @""; if (passwd == nil) passwd = @""; + + _gameDataIRI = [OFFileManager.defaultManager currentDirectoryIRI]; + _userDataIRI = [OFFileManager.defaultManager currentDirectoryIRI]; + + [OFFileManager.defaultManager + createDirectoryAtIRI:[_userDataIRI + IRIByAppendingPathComponent:@"demos"] + createParents:true]; + [OFFileManager.defaultManager + createDirectoryAtIRI:[_userDataIRI + IRIByAppendingPathComponent:@"savegames"] + createParents:true]; if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | par) < 0) fatal(@"Unable to initialize SDL"); log(@"net"); @@ -116,12 +128,10 @@ log(@"gl"); gl_init(_width, _height); log(@"basetex"); - _gameDataIRI = [OFFileManager.defaultManager currentDirectoryIRI]; - _userDataIRI = [OFFileManager.defaultManager currentDirectoryIRI]; int xs, ys; if (!installtex(2, [_userDataIRI IRIByAppendingPathComponent:@"data/newchars.png"], &xs, &ys, false) || !installtex(3, Index: src/savegamedemo.mm ================================================================== --- src/savegamedemo.mm +++ src/savegamedemo.mm @@ -86,98 +86,112 @@ if (demorecording) stop(); } void -savestate(char *fn) -{ - stop(); - f = gzopen(fn, "wb9"); - if (!f) { - conoutf(@"could not write %s", fn); - return; - } - gzwrite(f, (void *)"CUBESAVE", 8); - gzputc(f, islittleendian); - gzputi(SAVEGAMEVERSION); - gzputi(sizeof(dynent)); +savestate(OFIRI *IRI) +{ @autoreleasepool { + stop(); + f = gzopen([IRI.fileSystemRepresentation + cStringWithEncoding:OFLocale.encoding], + "wb9"); + if (!f) { + conoutf(@"could not write %@", IRI.string); + return; + } + gzwrite(f, (void *)"CUBESAVE", 8); + gzputc(f, islittleendian); + gzputi(SAVEGAMEVERSION); + gzputi(sizeof(dynent)); gzwrite(f, getclientmap().UTF8String, _MAXDEFSTR); - } - gzputi(gamemode); - gzputi(ents.length()); - loopv(ents) gzputc(f, ents[i].spawned); - gzwrite(f, player1, sizeof(dynent)); - dvector &monsters = getmonsters(); - gzputi(monsters.length()); - loopv(monsters) gzwrite(f, monsters[i], sizeof(dynent)); - gzputi(players.length()); - loopv(players) - { - gzput(players[i] == NULL); - gzwrite(f, players[i], sizeof(dynent)); + gzputi(gamemode); + gzputi(ents.length()); + loopv(ents) gzputc(f, ents[i].spawned); + gzwrite(f, player1, sizeof(dynent)); + dvector &monsters = getmonsters(); + gzputi(monsters.length()); + loopv(monsters) gzwrite(f, monsters[i], sizeof(dynent)); + gzputi(players.length()); + loopv(players) + { + gzput(players[i] == NULL); + gzwrite(f, players[i], sizeof(dynent)); + } } } void savegame(OFString *name) { + if (!m_classicsp) { + conoutf(@"can only save classic sp games"); + return; + } + @autoreleasepool { - if (!m_classicsp) { - conoutf(@"can only save classic sp games"); - return; - } - sprintf_sd(fn)("savegames/%s.csgz", name.UTF8String); - savestate(fn); + OFString *path = + [OFString stringWithFormat:@"savegames/%@.csgz", name]; + OFIRI *IRI = [Cube.sharedInstance.userDataIRI + IRIByAppendingPathComponent:path]; + savestate(IRI); stop(); - conoutf(@"wrote %s", fn); + conoutf(@"wrote %@", IRI.string); } } COMMAND(savegame, ARG_1STR) void -loadstate(char *fn) -{ - stop(); - if (multiplayer()) - return; - f = gzopen(fn, "rb9"); - if (!f) { - conoutf(@"could not open %s", fn); - return; - } - - string buf; - gzread(f, buf, 8); - if (strncmp(buf, "CUBESAVE", 8)) - goto out; - if (gzgetc(f) != islittleendian) - goto out; // not supporting save->load accross incompatible - // architectures simpifies things a LOT - if (gzgeti() != SAVEGAMEVERSION || gzgeti() != sizeof(dynent)) - goto out; - string mapname; - gzread(f, mapname, _MAXDEFSTR); - nextmode = gzgeti(); - @autoreleasepool { - // continue below once map has been loaded and client & server - // have updated - changemap(@(mapname)); - } - return; -out: - conoutf(@"aborting: savegame/demo from a different version of cube or " - @"cpu architecture"); - stop(); +loadstate(OFIRI *IRI) +{ + @autoreleasepool { + stop(); + if (multiplayer()) + return; + f = gzopen([IRI.fileSystemRepresentation + cStringWithEncoding:OFLocale.encoding], + "rb9"); + if (!f) { + conoutf(@"could not open %@", IRI.string); + return; + } + + string buf; + gzread(f, buf, 8); + if (strncmp(buf, "CUBESAVE", 8)) + goto out; + if (gzgetc(f) != islittleendian) + goto out; // not supporting save->load accross + // incompatible architectures simpifies things + // a LOT + if (gzgeti() != SAVEGAMEVERSION || gzgeti() != sizeof(dynent)) + goto out; + string mapname; + gzread(f, mapname, _MAXDEFSTR); + nextmode = gzgeti(); + @autoreleasepool { + // continue below once map has been loaded and client & + // server have updated + changemap(@(mapname)); + } + return; + out: + conoutf(@"aborting: savegame/demo from a different version of " + @"cube or cpu architecture"); + stop(); + } } void loadgame(OFString *name) { @autoreleasepool { - sprintf_sd(fn)("savegames/%s.csgz", name.UTF8String); - loadstate(fn); + OFString *path = + [OFString stringWithFormat:@"savegames/%@.csgz", name]; + OFIRI *IRI = [Cube.sharedInstance.userDataIRI + IRIByAppendingPathComponent:path]; + loadstate(IRI); } } COMMAND(loadgame, ARG_1STR) void @@ -247,22 +261,27 @@ OFVector3D dorig; void record(OFString *name) { + if (m_sp) { + conoutf(@"cannot record singleplayer games"); + return; + } + + int cn = getclientnum(); + if (cn < 0) + return; + @autoreleasepool { - if (m_sp) { - conoutf(@"cannot record singleplayer games"); - return; - } - int cn = getclientnum(); - if (cn < 0) - return; - sprintf_sd(fn)("demos/%s.cdgz", name.UTF8String); - savestate(fn); + OFString *path = + [OFString stringWithFormat:@"demos/%@.cdgz", name]; + OFIRI *IRI = [Cube.sharedInstance.userDataIRI + IRIByAppendingPathComponent:path]; + savestate(IRI); gzputi(cn); - conoutf(@"started recording demo to %s", fn); + conoutf(@"started recording demo to %@", IRI.string); demorecording = true; starttime = lastmillis; ddamage = bdamage = 0; } } @@ -313,12 +332,15 @@ void demo(OFString *name) { @autoreleasepool { - sprintf_sd(fn)("demos/%s.cdgz", name.UTF8String); - loadstate(fn); + OFString *path = + [OFString stringWithFormat:@"demos/%@.cdgz", name]; + OFIRI *IRI = [Cube.sharedInstance.userDataIRI + IRIByAppendingPathComponent:path]; + loadstate(IRI); demoloading = true; } } COMMAND(demo, ARG_1STR) Index: src/sound.mm ================================================================== --- src/sound.mm +++ src/sound.mm @@ -252,12 +252,11 @@ IRI.fileSystemRepresentation.UTF8String, FSOUND_LOOP_OFF, 0, 0); #endif if (!samples[n]) { - conoutf(@"failed to load sample: %s", - IRI.string.UTF8String); + conoutf(@"failed to load sample: %@", IRI.string); return; } } #ifdef USE_MIXER