Use one autorelease pool per frame

This way, nowhere else autorelease pools need to be managed.

FossilOrigin-Name: 489124a92fd2a7e6d543b58ce50e454f2cb1647c81b4ba637d6c252404012ddd
This commit is contained in:
Jonathan Schleifer 2025-03-16 10:11:39 +00:00
parent a67b134eb2
commit 875c395ce1
22 changed files with 1262 additions and 1443 deletions

View file

@ -21,262 +21,275 @@ VARP(minmillis, 0, 5, 1000);
- (void)applicationDidFinishLaunching:(OFNotification *)notification - (void)applicationDidFinishLaunching:(OFNotification *)notification
{ {
bool dedicated, windowed; @autoreleasepool {
int par = 0, uprate = 0, maxcl = 4; bool dedicated, windowed;
OFString *__autoreleasing sdesc, *__autoreleasing ip; int par = 0, uprate = 0, maxcl = 4;
OFString *__autoreleasing master, *__autoreleasing passwd; OFString *__autoreleasing sdesc, *__autoreleasing ip;
OFString *__autoreleasing master, *__autoreleasing passwd;
processInitQueue(); processInitQueue();
#define log(s) conoutf(@"init: %@", s) #define log(s) conoutf(@"init: %@", s)
log(@"sdl"); log(@"sdl");
const OFOptionsParserOption options[] = { { 'd', @"dedicated", 0, const OFOptionsParserOption options[] = {
&dedicated, NULL }, { 'd', @"dedicated", 0, &dedicated, NULL },
{ 't', @"window", 0, &windowed, NULL }, { 't', @"window", 0, &windowed, NULL },
{ 'w', @"width", 1, NULL, NULL }, { 'w', @"width", 1, NULL, NULL },
{ 'h', @"height", 1, NULL, NULL }, { 'h', @"height", 1, NULL, NULL },
{ 'u', @"upload-rate", 1, NULL, NULL }, { 'u', @"upload-rate", 1, NULL, NULL },
{ 'n', @"server-desc", 1, NULL, &sdesc }, { 'n', @"server-desc", 1, NULL, &sdesc },
{ 'i', @"ip", 1, NULL, &ip }, { 'i', @"ip", 1, NULL, &ip },
{ 'm', @"master", 1, NULL, &master }, { 'm', @"master", 1, NULL, &master },
{ 'p', @"password", 1, NULL, &passwd }, { 'p', @"password", 1, NULL, &passwd },
{ 'c', @"max-clients", 1, NULL, NULL }, { 'c', @"max-clients", 1, NULL, NULL },
{ '\0', nil, 0, NULL, NULL } }; { '\0', nil, 0, NULL, NULL }
OFOptionsParser *optionsParser = };
[OFOptionsParser parserWithOptions:options]; OFOptionsParser *optionsParser =
OFUnichar option; [OFOptionsParser parserWithOptions:options];
while ((option = [optionsParser nextOption]) != '\0') { OFUnichar option;
switch (option) { while ((option = [optionsParser nextOption]) != '\0') {
case 'w': switch (option) {
_width = optionsParser.argument.intValue; case 'w':
break; _width = optionsParser.argument.intValue;
case 'h': break;
_height = optionsParser.argument.intValue; case 'h':
break; _height = optionsParser.argument.intValue;
case 'u': break;
uprate = optionsParser.argument.intValue; case 'u':
break; uprate = optionsParser.argument.intValue;
case 'c': break;
maxcl = optionsParser.argument.intValue; case 'c':
break; maxcl = optionsParser.argument.intValue;
case ':': break;
case '=': case ':':
case '?': case '=':
conoutf(@"unknown commandline option"); case '?':
[OFApplication terminateWithStatus:1]; conoutf(@"unknown commandline option");
[OFApplication terminateWithStatus:1];
}
} }
if (sdesc == nil)
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");
initPlayers();
log(@"net");
if (enet_initialize() < 0)
fatal(@"Unable to initialise network module");
initclient();
// never returns if dedicated
initserver(dedicated, uprate, sdesc, ip, master, passwd, maxcl);
log(@"world");
empty_world(7, true);
log(@"video: sdl");
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
fatal(@"Unable to initialize SDL Video");
if (_width == 0 || _height == 0) {
SDL_DisplayMode mode;
if (SDL_GetDesktopDisplayMode(0, &mode) == 0) {
_width = mode.w;
_height = mode.h;
} else {
_width = 1920;
_height = 1080;
}
}
log(@"video: mode");
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
if ((_window = SDL_CreateWindow("cube engine",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
_width, _height,
SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL |
(!windowed ? SDL_WINDOW_FULLSCREEN : 0))) ==
NULL ||
SDL_GL_CreateContext(_window) == NULL)
fatal(@"Unable to create OpenGL screen");
log(@"video: misc");
SDL_SetWindowGrab(_window, SDL_TRUE);
SDL_SetRelativeMouseMode(SDL_TRUE);
SDL_ShowCursor(0);
log(@"gl");
gl_init(_width, _height);
log(@"basetex");
int xs, ys;
if (!installtex(2,
[_gameDataIRI
IRIByAppendingPathComponent:@"data/newchars.png"],
&xs, &ys, false) ||
!installtex(3,
[_gameDataIRI IRIByAppendingPathComponent:
@"data/martin/base.png"],
&xs, &ys, false) ||
!installtex(6,
[_gameDataIRI IRIByAppendingPathComponent:
@"data/martin/ball1.png"],
&xs, &ys, false) ||
!installtex(7,
[_gameDataIRI IRIByAppendingPathComponent:
@"data/martin/smoke.png"],
&xs, &ys, false) ||
!installtex(8,
[_gameDataIRI IRIByAppendingPathComponent:
@"data/martin/ball2.png"],
&xs, &ys, false) ||
!installtex(9,
[_gameDataIRI IRIByAppendingPathComponent:
@"data/martin/ball3.png"],
&xs, &ys, false) ||
!installtex(4,
[_gameDataIRI
IRIByAppendingPathComponent:@"data/explosion.jpg"],
&xs, &ys, false) ||
!installtex(5,
[_gameDataIRI
IRIByAppendingPathComponent:@"data/items.png"],
&xs, &ys, false) ||
!installtex(1,
[_gameDataIRI
IRIByAppendingPathComponent:@"data/crosshair.png"],
&xs, &ys, false))
fatal(@"could not find core textures (hint: run cube "
@"from the parent of the bin directory)");
log(@"sound");
initsound();
log(@"cfg");
newmenu(@"frags\tpj\tping\tteam\tname");
newmenu(@"ping\tplr\tserver");
exec(@"data/keymap.cfg");
exec(@"data/menus.cfg");
exec(@"data/prefabs.cfg");
exec(@"data/sounds.cfg");
exec(@"servers.cfg");
if (!execfile([_userDataIRI
IRIByAppendingPathComponent:@"config.cfg"]))
execfile([_gameDataIRI
IRIByAppendingPathComponent:@"data/defaults.cfg"]);
exec(@"autoexec.cfg");
log(@"localconnect");
localconnect();
// if this map is changed, also change depthcorrect()
changemap(@"metl3");
log(@"mainloop");
} }
if (sdesc == nil)
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");
initPlayers();
log(@"net");
if (enet_initialize() < 0)
fatal(@"Unable to initialise network module");
initclient();
// never returns if dedicated
initserver(dedicated, uprate, sdesc, ip, master, passwd, maxcl);
log(@"world");
empty_world(7, true);
log(@"video: sdl");
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
fatal(@"Unable to initialize SDL Video");
if (_width == 0 || _height == 0) {
SDL_DisplayMode mode;
if (SDL_GetDesktopDisplayMode(0, &mode) == 0) {
_width = mode.w;
_height = mode.h;
} else {
_width = 1920;
_height = 1080;
}
}
log(@"video: mode");
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
if ((_window = SDL_CreateWindow("cube engine", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, _width, _height,
SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL |
(!windowed ? SDL_WINDOW_FULLSCREEN : 0))) == NULL ||
SDL_GL_CreateContext(_window) == NULL)
fatal(@"Unable to create OpenGL screen");
log(@"video: misc");
SDL_SetWindowGrab(_window, SDL_TRUE);
SDL_SetRelativeMouseMode(SDL_TRUE);
SDL_ShowCursor(0);
log(@"gl");
gl_init(_width, _height);
log(@"basetex");
int xs, ys;
if (!installtex(2,
[_gameDataIRI IRIByAppendingPathComponent:@"data/newchars.png"],
&xs, &ys, false) ||
!installtex(3,
[_gameDataIRI
IRIByAppendingPathComponent:@"data/martin/base.png"],
&xs, &ys, false) ||
!installtex(6,
[_gameDataIRI
IRIByAppendingPathComponent:@"data/martin/ball1.png"],
&xs, &ys, false) ||
!installtex(7,
[_gameDataIRI
IRIByAppendingPathComponent:@"data/martin/smoke.png"],
&xs, &ys, false) ||
!installtex(8,
[_gameDataIRI
IRIByAppendingPathComponent:@"data/martin/ball2.png"],
&xs, &ys, false) ||
!installtex(9,
[_gameDataIRI
IRIByAppendingPathComponent:@"data/martin/ball3.png"],
&xs, &ys, false) ||
!installtex(4,
[_gameDataIRI
IRIByAppendingPathComponent:@"data/explosion.jpg"],
&xs, &ys, false) ||
!installtex(5,
[_gameDataIRI IRIByAppendingPathComponent:@"data/items.png"],
&xs, &ys, false) ||
!installtex(1,
[_gameDataIRI
IRIByAppendingPathComponent:@"data/crosshair.png"],
&xs, &ys, false))
fatal(@"could not find core textures (hint: run cube from the "
@"parent of the bin directory)");
log(@"sound");
initsound();
log(@"cfg");
newmenu(@"frags\tpj\tping\tteam\tname");
newmenu(@"ping\tplr\tserver");
exec(@"data/keymap.cfg");
exec(@"data/menus.cfg");
exec(@"data/prefabs.cfg");
exec(@"data/sounds.cfg");
exec(@"servers.cfg");
if (!execfile([_userDataIRI IRIByAppendingPathComponent:@"config.cfg"]))
execfile([_gameDataIRI
IRIByAppendingPathComponent:@"data/defaults.cfg"]);
exec(@"autoexec.cfg");
log(@"localconnect");
localconnect();
// if this map is changed, also change depthcorrect()
changemap(@"metl3");
log(@"mainloop");
int ignore = 5;
OFDate *past = [OFDate date]; OFDate *past = [OFDate date];
int ignore = 5;
for (;;) { for (;;) {
[OFRunLoop.mainRunLoop runUntilDate:past]; @autoreleasepool {
[OFRunLoop.mainRunLoop runUntilDate:past];
int millis = SDL_GetTicks() * gamespeed / 100; int millis = SDL_GetTicks() * gamespeed / 100;
if (millis - lastmillis > 200) if (millis - lastmillis > 200)
lastmillis = millis - 200; lastmillis = millis - 200;
else if (millis - lastmillis < 1) else if (millis - lastmillis < 1)
lastmillis = millis - 1; lastmillis = millis - 1;
if (millis - lastmillis < minmillis) if (millis - lastmillis < minmillis)
SDL_Delay(minmillis - (millis - lastmillis)); SDL_Delay(minmillis - (millis - lastmillis));
cleardlights(); cleardlights();
updateworld(millis); updateworld(millis);
if (!demoplayback) if (!demoplayback)
serverslice((int)time(NULL), 0); serverslice((int)time(NULL), 0);
static float fps = 30.0f; static float fps = 30.0f;
fps = (1000.0f / curtime + fps * 50) / 51; fps = (1000.0f / curtime + fps * 50) / 51;
computeraytable(player1.o.x, player1.o.y); computeraytable(player1.o.x, player1.o.y);
readdepth(_width, _height); readdepth(_width, _height);
SDL_GL_SwapWindow(_window); SDL_GL_SwapWindow(_window);
extern void updatevol(); extern void updatevol();
updatevol(); updatevol();
// cheap hack to get rid of initial sparklies, even when
// triple buffering etc.
if (_framesInMap++ < 5) {
player1.yaw += 5;
gl_drawframe(_width, _height, fps);
player1.yaw -= 5;
}
// cheap hack to get rid of initial sparklies, even when triple
// buffering etc.
if (_framesInMap++ < 5) {
player1.yaw += 5;
gl_drawframe(_width, _height, fps); gl_drawframe(_width, _height, fps);
player1.yaw -= 5;
}
gl_drawframe(_width, _height, fps); SDL_Event event;
int lasttype = 0, lastbut = 0;
SDL_Event event; while (SDL_PollEvent(&event)) {
int lasttype = 0, lastbut = 0; switch (event.type) {
while (SDL_PollEvent(&event)) { case SDL_QUIT:
switch (event.type) { [self quit];
case SDL_QUIT: break;
[self quit]; case SDL_KEYDOWN:
break; case SDL_KEYUP:
case SDL_KEYDOWN: if (_repeatsKeys ||
case SDL_KEYUP: event.key.repeat == 0)
if (_repeatsKeys || event.key.repeat == 0) keypress(event.key.keysym.sym,
keypress(event.key.keysym.sym, event.key.state ==
event.key.state == SDL_PRESSED); SDL_PRESSED);
break; break;
case SDL_TEXTINPUT: case SDL_TEXTINPUT:
@autoreleasepool {
input(@(event.text.text)); input(@(event.text.text));
}
break;
case SDL_MOUSEMOTION:
if (ignore) {
ignore--;
break; break;
} case SDL_MOUSEMOTION:
mousemove(event.motion.xrel, event.motion.yrel); if (ignore) {
break; ignore--;
case SDL_MOUSEBUTTONDOWN: break;
case SDL_MOUSEBUTTONUP: }
if (lasttype == event.type && mousemove(event.motion.xrel,
lastbut == event.button.button) event.motion.yrel);
// why?? get event twice without it
break; break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
if (lasttype == event.type &&
lastbut == event.button.button)
// why?? get event twice without
// it
break;
keypress(-event.button.button, keypress(-event.button.button,
event.button.state != 0); event.button.state != 0);
lasttype = event.type; lasttype = event.type;
lastbut = event.button.button; lastbut = event.button.button;
break; break;
}
} }
} }
} }
[self quit];
} }
- (void)applicationWillTerminate:(OFNotification *)notification - (void)applicationWillTerminate:(OFNotification *)notification
@ -323,16 +336,12 @@ VARP(minmillis, 0, 5, 1000);
endianswap(dest, 3, _width); endianswap(dest, 3, _width);
} }
@autoreleasepool { OFString *path = [OFString
OFString *path = [OFString stringWithFormat:@"screenshots/screenshot_%d.bmp",
stringWithFormat: lastmillis];
@"screenshots/screenshot_%d.bmp", SDL_SaveBMP(temp,
lastmillis]; [_userDataIRI IRIByAppendingPathComponent:path]
SDL_SaveBMP(temp, .fileSystemRepresentation.UTF8String);
[_userDataIRI
IRIByAppendingPathComponent:path]
.fileSystemRepresentation.UTF8String);
}
SDL_FreeSurface(temp); SDL_FreeSurface(temp);
} }

View file

@ -54,60 +54,57 @@ snap(int sn, float f)
- (bool)loadWithIRI:(OFIRI *)IRI - (bool)loadWithIRI:(OFIRI *)IRI
{ {
@autoreleasepool { OFSeekableStream *stream;
OFSeekableStream *stream; @try {
@try { stream = (OFSeekableStream *)[[OFIRIHandler handlerForIRI:IRI]
stream = (OFSeekableStream *)[[OFIRIHandler openItemAtIRI:IRI
handlerForIRI:IRI] openItemAtIRI:IRI mode:@"r"]; mode:@"r"];
} @catch (id e) { } @catch (id e) {
return false; return false;
}
if (![stream isKindOfClass:OFSeekableStream.class])
return false;
md2_header header;
[stream readIntoBuffer:&header exactLength:sizeof(md2_header)];
endianswap(
&header, sizeof(int), sizeof(md2_header) / sizeof(int));
if (header.magic != 844121161 || header.version != 8)
return false;
_frames = new char[header.frameSize * header.numFrames];
if (_frames == NULL)
return false;
[stream seekToOffset:header.offsetFrames whence:OFSeekSet];
[stream readIntoBuffer:_frames
exactLength:header.frameSize * header.numFrames];
for (int i = 0; i < header.numFrames; ++i)
endianswap(
_frames + i * header.frameSize, sizeof(float), 6);
_glCommands = new int[header.numGlCommands];
if (_glCommands == NULL)
return false;
[stream seekToOffset:header.offsetGlCommands whence:OFSeekSet];
[stream readIntoBuffer:_glCommands
exactLength:header.numGlCommands * sizeof(int)];
endianswap(_glCommands, sizeof(int), header.numGlCommands);
_numFrames = header.numFrames;
_numGlCommands = header.numGlCommands;
_frameSize = header.frameSize;
_numTriangles = header.numTriangles;
_numVerts = header.numVertices;
[stream close];
_mverts = new OFVector3D *[_numFrames];
loopj(_numFrames) _mverts[j] = NULL;
return true;
} }
if (![stream isKindOfClass:OFSeekableStream.class])
return false;
md2_header header;
[stream readIntoBuffer:&header exactLength:sizeof(md2_header)];
endianswap(&header, sizeof(int), sizeof(md2_header) / sizeof(int));
if (header.magic != 844121161 || header.version != 8)
return false;
_frames = new char[header.frameSize * header.numFrames];
if (_frames == NULL)
return false;
[stream seekToOffset:header.offsetFrames whence:OFSeekSet];
[stream readIntoBuffer:_frames
exactLength:header.frameSize * header.numFrames];
for (int i = 0; i < header.numFrames; ++i)
endianswap(_frames + i * header.frameSize, sizeof(float), 6);
_glCommands = new int[header.numGlCommands];
if (_glCommands == NULL)
return false;
[stream seekToOffset:header.offsetGlCommands whence:OFSeekSet];
[stream readIntoBuffer:_glCommands
exactLength:header.numGlCommands * sizeof(int)];
endianswap(_glCommands, sizeof(int), header.numGlCommands);
_numFrames = header.numFrames;
_numGlCommands = header.numGlCommands;
_frameSize = header.frameSize;
_numTriangles = header.numTriangles;
_numVerts = header.numVertices;
[stream close];
_mverts = new OFVector3D *[_numFrames];
loopj(_numFrames) _mverts[j] = NULL;
return true;
} }
- (void)scaleWithFrame:(int)frame scale:(float)scale snap:(int)sn - (void)scaleWithFrame:(int)frame scale:(float)scale snap:(int)sn

View file

@ -63,28 +63,24 @@ throttle()
void void
newname(OFString *name) newname(OFString *name)
{ {
@autoreleasepool { c2sinit = false;
c2sinit = false;
if (name.length > 16) if (name.length > 16)
name = [name substringToIndex:16]; name = [name substringToIndex:16];
player1.name = name; player1.name = name;
}
} }
COMMANDN(name, newname, ARG_1STR) COMMANDN(name, newname, ARG_1STR)
void void
newteam(OFString *name) newteam(OFString *name)
{ {
@autoreleasepool { c2sinit = false;
c2sinit = false;
if (name.length > 5) if (name.length > 5)
name = [name substringToIndex:5]; name = [name substringToIndex:5];
player1.team = name; player1.team = name;
}
} }
COMMANDN(team, newteam, ARG_1STR) COMMANDN(team, newteam, ARG_1STR)
@ -103,12 +99,9 @@ connects(OFString *servername)
conoutf(@"attempting to connect to %@", servername); conoutf(@"attempting to connect to %@", servername);
ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT }; ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT };
@autoreleasepool { if (enet_address_set_host(&address, servername.UTF8String) < 0) {
if (enet_address_set_host(&address, servername.UTF8String) < conoutf(@"could not resolve server %@", servername);
0) { return;
conoutf(@"could not resolve server %@", servername);
return;
}
} }
clienthost = enet_host_create(NULL, 1, rate, rate); clienthost = enet_host_create(NULL, 1, rate, rate);
@ -287,99 +280,94 @@ sendpackettoserv(void *packet)
void void
c2sinfo(DynamicEntity *d) c2sinfo(DynamicEntity *d)
{ {
@autoreleasepool { if (clientnum < 0)
if (clientnum < 0) return; // we haven't had a welcome message from the server yet
return; // we haven't had a welcome message from the if (lastmillis - lastupdate < 40)
// server yet return; // don't update faster than 25fps
if (lastmillis - lastupdate < 40) ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, 0);
return; // don't update faster than 25fps uchar *start = packet->data;
ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, 0); uchar *p = start + 2;
uchar *start = packet->data; bool serveriteminitdone = false;
uchar *p = start + 2; // suggest server to change map
bool serveriteminitdone = false; if (toservermap.length > 0) {
if (toservermap.length > 0) // suggest server to change map // do this exclusively as map change may invalidate rest of
{ // do this exclusively as map change may invalidate rest of // update
// update packet->flags = ENET_PACKET_FLAG_RELIABLE;
packet->flags = ENET_PACKET_FLAG_RELIABLE; putint(p, SV_MAPCHANGE);
putint(p, SV_MAPCHANGE); sendstring(toservermap, p);
sendstring(toservermap, p); toservermap = @"";
toservermap = @""; putint(p, nextmode);
putint(p, nextmode); } else {
} else { putint(p, SV_POS);
putint(p, SV_POS); putint(p, clientnum);
putint(p, clientnum); // quantize coordinates to 1/16th of a cube, between 1 and 3
// quantize coordinates to 1/16th of a cube, between 1 // bytes
// and 3 bytes putint(p, (int)(d.o.x * DMF));
putint(p, (int)(d.o.x * DMF)); putint(p, (int)(d.o.y * DMF));
putint(p, (int)(d.o.y * DMF)); putint(p, (int)(d.o.z * DMF));
putint(p, (int)(d.o.z * DMF)); putint(p, (int)(d.yaw * DAF));
putint(p, (int)(d.yaw * DAF)); putint(p, (int)(d.pitch * DAF));
putint(p, (int)(d.pitch * DAF)); putint(p, (int)(d.roll * DAF));
putint(p, (int)(d.roll * DAF)); // quantize to 1/100, almost always 1 byte
// quantize to 1/100, almost always 1 byte putint(p, (int)(d.vel.x * DVF));
putint(p, (int)(d.vel.x * DVF)); putint(p, (int)(d.vel.y * DVF));
putint(p, (int)(d.vel.y * DVF)); putint(p, (int)(d.vel.z * DVF));
putint(p, (int)(d.vel.z * DVF)); // pack rest in 1 byte: strafe:2, move:2, onfloor:1, state:3
// pack rest in 1 byte: strafe:2, move:2, onfloor:1, putint(p,
// state:3 (d.strafe & 3) | ((d.move & 3) << 2) |
putint(p, (((int)d.onfloor) << 4) |
(d.strafe & 3) | ((d.move & 3) << 2) | ((editmode ? CS_EDITING : d.state) << 5));
(((int)d.onfloor) << 4) |
((editmode ? CS_EDITING : d.state) << 5));
if (senditemstoserver) { if (senditemstoserver) {
packet->flags = ENET_PACKET_FLAG_RELIABLE; packet->flags = ENET_PACKET_FLAG_RELIABLE;
putint(p, SV_ITEMLIST); putint(p, SV_ITEMLIST);
if (!m_noitems) if (!m_noitems)
putitems(p); putitems(p);
putint(p, -1); putint(p, -1);
senditemstoserver = false; senditemstoserver = false;
serveriteminitdone = true; serveriteminitdone = true;
} }
// player chat, not flood protected for now // player chat, not flood protected for now
if (ctext.length > 0) { if (ctext.length > 0) {
packet->flags = ENET_PACKET_FLAG_RELIABLE; packet->flags = ENET_PACKET_FLAG_RELIABLE;
putint(p, SV_TEXT); putint(p, SV_TEXT);
sendstring(ctext, p); sendstring(ctext, p);
ctext = @""; ctext = @"";
} }
// tell other clients who I am // tell other clients who I am
if (!c2sinit) { if (!c2sinit) {
packet->flags = ENET_PACKET_FLAG_RELIABLE; packet->flags = ENET_PACKET_FLAG_RELIABLE;
c2sinit = true; c2sinit = true;
putint(p, SV_INITC2S); putint(p, SV_INITC2S);
sendstring(player1.name, p); sendstring(player1.name, p);
sendstring(player1.team, p); sendstring(player1.team, p);
putint(p, player1.lifesequence); putint(p, player1.lifesequence);
} }
for (OFData *msg in messages) { for (OFData *msg in messages) {
// send messages collected during the previous // send messages collected during the previous frames
// frames if (*(int *)[msg itemAtIndex:1])
if (*(int *)[msg itemAtIndex:1]) packet->flags = ENET_PACKET_FLAG_RELIABLE;
packet->flags = loopi(*(int *)[msg itemAtIndex:0])
ENET_PACKET_FLAG_RELIABLE; putint(p, *(int *)[msg itemAtIndex:i + 2]);
loopi(*(int *)[msg itemAtIndex:0]) }
putint(p, *(int *)[msg itemAtIndex:i + 2]); [messages removeAllObjects];
} if (lastmillis - lastping > 250) {
[messages removeAllObjects]; putint(p, SV_PING);
if (lastmillis - lastping > 250) { putint(p, lastmillis);
putint(p, SV_PING); lastping = lastmillis;
putint(p, lastmillis);
lastping = lastmillis;
}
} }
*(ushort *)start = ENET_HOST_TO_NET_16(p - start);
enet_packet_resize(packet, p - start);
incomingdemodata(start, p - start, true);
if (clienthost) {
enet_host_broadcast(clienthost, 0, packet);
enet_host_flush(clienthost);
} else
localclienttoserver(packet);
lastupdate = lastmillis;
if (serveriteminitdone)
loadgamerest(); // hack
} }
*(ushort *)start = ENET_HOST_TO_NET_16(p - start);
enet_packet_resize(packet, p - start);
incomingdemodata(start, p - start, true);
if (clienthost) {
enet_host_broadcast(clienthost, 0, packet);
enet_host_flush(clienthost);
} else
localclienttoserver(packet);
lastupdate = lastmillis;
if (serveriteminitdone)
loadgamerest(); // hack
} }
void void

View file

@ -107,21 +107,19 @@ static OFMutableArray<OFString *> *scoreLines;
void void
renderscore(DynamicEntity *d) renderscore(DynamicEntity *d)
{ {
@autoreleasepool { OFString *lag = [OFString stringWithFormat:@"%d", d.plag];
OFString *lag = [OFString stringWithFormat:@"%d", d.plag]; OFString *name = [OFString stringWithFormat:@"(%@)", d.name];
OFString *name = [OFString stringWithFormat:@"(%@)", d.name]; OFString *line =
OFString *line = [OFString stringWithFormat:@"%d\t%@\t%d\t%@\t%@", d.frags,
[OFString stringWithFormat:@"%d\t%@\t%d\t%@\t%@", d.frags, (d.state == CS_LAGGED ? @"LAG" : lag), d.ping, d.team,
(d.state == CS_LAGGED ? @"LAG" : lag), d.ping, (d.state == CS_DEAD ? name : d.name)];
d.team, (d.state == CS_DEAD ? name : d.name)];
if (scoreLines == nil) if (scoreLines == nil)
scoreLines = [[OFMutableArray alloc] init]; scoreLines = [[OFMutableArray alloc] init];
[scoreLines addObject:line]; [scoreLines addObject:line];
menumanual(0, scoreLines.count - 1, line); menumanual(0, scoreLines.count - 1, line);
}
} }
static const int maxTeams = 4; static const int maxTeams = 4;
@ -132,20 +130,18 @@ static size_t teamsUsed;
void void
addteamscore(DynamicEntity *d) addteamscore(DynamicEntity *d)
{ {
@autoreleasepool { for (size_t i = 0; i < teamsUsed; i++) {
for (size_t i = 0; i < teamsUsed; i++) { if ([teamName[i] isEqual:d.team]) {
if ([teamName[i] isEqual:d.team]) { teamScore[i] += d.frags;
teamScore[i] += d.frags;
return;
}
}
if (teamsUsed == maxTeams)
return; return;
}
teamName[teamsUsed] = d.team;
teamScore[teamsUsed++] = d.frags;
} }
if (teamsUsed == maxTeams)
return;
teamName[teamsUsed] = d.team;
teamScore[teamsUsed++] = d.frags;
} }
void void
@ -172,9 +168,7 @@ renderscores()
[teamScores appendFormat:@"[ %@: %d ]", teamName[j], [teamScores appendFormat:@"[ %@: %d ]", teamName[j],
teamScore[j]]; teamScore[j]];
menumanual(0, scoreLines.count, @""); menumanual(0, scoreLines.count, @"");
@autoreleasepool { menumanual(0, scoreLines.count + 1, teamScores);
menumanual(0, scoreLines.count + 1, teamScores);
}
} }
} }
@ -183,38 +177,36 @@ renderscores()
void void
sendmap(OFString *mapname) sendmap(OFString *mapname)
{ {
@autoreleasepool { if (mapname.length > 0)
if (mapname.length > 0) save_world(mapname);
save_world(mapname); changemap(mapname);
changemap(mapname); mapname = getclientmap();
mapname = getclientmap(); OFData *mapdata = readmap(mapname);
OFData *mapdata = readmap(mapname); if (mapdata == nil)
if (mapdata == nil) return;
return; ENetPacket *packet = enet_packet_create(
ENetPacket *packet = enet_packet_create( NULL, MAXTRANS + mapdata.count, ENET_PACKET_FLAG_RELIABLE);
NULL, MAXTRANS + mapdata.count, ENET_PACKET_FLAG_RELIABLE); uchar *start = packet->data;
uchar *start = packet->data; uchar *p = start + 2;
uchar *p = start + 2; putint(p, SV_SENDMAP);
putint(p, SV_SENDMAP); sendstring(mapname, p);
sendstring(mapname, p); putint(p, mapdata.count);
putint(p, mapdata.count); if (65535 - (p - start) < mapdata.count) {
if (65535 - (p - start) < mapdata.count) { conoutf(@"map %@ is too large to send", mapname);
conoutf(@"map %@ is too large to send", mapname); enet_packet_destroy(packet);
enet_packet_destroy(packet); return;
return;
}
memcpy(p, mapdata.items, mapdata.count);
p += mapdata.count;
*(ushort *)start = ENET_HOST_TO_NET_16(p - start);
enet_packet_resize(packet, p - start);
sendpackettoserv(packet);
conoutf(@"sending map %@ to server...", mapname);
OFString *msg =
[OFString stringWithFormat:@"[map %@ uploaded to server, "
@"\"getmap\" to receive it]",
mapname];
toserver(msg);
} }
memcpy(p, mapdata.items, mapdata.count);
p += mapdata.count;
*(ushort *)start = ENET_HOST_TO_NET_16(p - start);
enet_packet_resize(packet, p - start);
sendpackettoserv(packet);
conoutf(@"sending map %@ to server...", mapname);
OFString *msg =
[OFString stringWithFormat:@"[map %@ uploaded to server, "
@"\"getmap\" to receive it]",
mapname];
toserver(msg);
} }
void void

View file

@ -95,15 +95,12 @@ localservertoclient(uchar *buf, int len)
// map // map
toservermap = getclientmap(); toservermap = getclientmap();
sgetstr(); sgetstr();
@autoreleasepool { if (text[0] &&
if (text[0] && strcmp(text, clientpassword.UTF8String)) {
strcmp(text, clientpassword.UTF8String)) { conoutf(@"you need to set the correct password "
conoutf(@"you need to set the correct " @"to join this server!");
@"password " disconnect();
@"to join this server!"); return;
disconnect();
return;
}
} }
if (getint(p) == 1) if (getint(p) == 1)
conoutf(@"server is FULL, disconnecting.."); conoutf(@"server is FULL, disconnecting..");
@ -150,9 +147,7 @@ localservertoclient(uchar *buf, int len)
case SV_MAPCHANGE: case SV_MAPCHANGE:
sgetstr(); sgetstr();
@autoreleasepool { changemapserv(@(text), getint(p));
changemapserv(@(text), getint(p));
}
mapchanged = true; mapchanged = true;
break; break;
@ -378,12 +373,10 @@ localservertoclient(uchar *buf, int len)
conoutf(@"received map \"%s\" from server, reloading..", conoutf(@"received map \"%s\" from server, reloading..",
text); text);
int mapsize = getint(p); int mapsize = getint(p);
@autoreleasepool { OFString *string = @(text);
OFString *string = @(text); writemap(string, mapsize, p);
writemap(string, mapsize, p); p += mapsize;
p += mapsize; changemapserv(string, gamemode);
changemapserv(string, gamemode);
}
break; break;
} }

View file

@ -123,16 +123,13 @@ parseexp(char *&p, int right)
} }
char *s = strndup(word, p - word - 1); char *s = strndup(word, p - word - 1);
if (left == '(') { if (left == '(') {
@autoreleasepool { OFString *t;
OFString *t; @try {
@try { t = [OFString stringWithFormat:@"%d", execute(@(s))];
t = [OFString } @finally {
stringWithFormat:@"%d", execute(@(s))]; free(s);
} @finally {
free(s);
}
s = strdup(t.UTF8String);
} }
s = strdup(t.UTF8String);
} }
return s; return s;
} }
@ -164,19 +161,16 @@ parseword(char *&p)
return strndup(word, p - word); return strndup(word, p - word);
} }
// find value of ident referenced with $ in exp
OFString * OFString *
lookup(OFString *n) // find value of ident referenced with $ in exp lookup(OFString *n)
{ {
@autoreleasepool { __kindof Identifier *identifier = identifiers[[n substringFromIndex:1]];
__kindof Identifier *identifier =
identifiers[[n substringFromIndex:1]];
if ([identifier isKindOfClass:Variable.class]) { if ([identifier isKindOfClass:Variable.class]) {
return [OFString return [OFString stringWithFormat:@"%d", *[identifier storage]];
stringWithFormat:@"%d", *[identifier storage]]; } else if ([identifier isKindOfClass:Alias.class])
} else if ([identifier isKindOfClass:Alias.class]) return [identifier action];
return [identifier action];
}
conoutf(@"unknown alias lookup: %@", [n substringFromIndex:1]); conoutf(@"unknown alias lookup: %@", [n substringFromIndex:1]);
return n; return n;
@ -234,57 +228,55 @@ executeIdentifier(__kindof Identifier *identifier,
int int
execute(OFString *string, bool isDown) execute(OFString *string, bool isDown)
{ {
@autoreleasepool { std::unique_ptr<char> copy(strdup(string.UTF8String));
std::unique_ptr<char> copy(strdup(string.UTF8String)); char *p = copy.get();
char *p = copy.get(); const int MAXWORDS = 25; // limit, remove
const int MAXWORDS = 25; // limit, remove OFString *w[MAXWORDS];
OFString *w[MAXWORDS]; int val = 0;
int val = 0; for (bool cont = true; cont;) {
for (bool cont = true; cont;) { // for each ; seperated statement
// for each ; seperated statement int numargs = MAXWORDS;
int numargs = MAXWORDS; loopi(MAXWORDS)
loopi(MAXWORDS) {
{ // collect all argument values
// collect all argument values w[i] = @"";
w[i] = @""; if (i > numargs)
if (i > numargs)
continue;
// parse and evaluate exps
char *s = parseword(p);
if (!s) {
numargs = i;
s = strdup("");
}
@try {
if (*s == '$')
// substitute variables
w[i] = lookup(@(s));
else
w[i] = @(s);
} @finally {
free(s);
}
}
p += strcspn(p, ";\n\0");
// more statements if this isn't the end of the string
cont = *p++ != 0;
OFString *c = w[0];
// strip irc-style command prefix
if ([c hasPrefix:@"/"]) {
c = [c substringFromIndex:1];
w[0] = c;
}
// empty statement
if (c.length == 0)
continue; continue;
// parse and evaluate exps
val = executeIdentifier(identifiers[c], char *s = parseword(p);
[OFArray arrayWithObjects:w count:numargs], isDown); if (!s) {
numargs = i;
s = strdup("");
}
@try {
if (*s == '$')
// substitute variables
w[i] = lookup(@(s));
else
w[i] = @(s);
} @finally {
free(s);
}
} }
return val; p += strcspn(p, ";\n\0");
// more statements if this isn't the end of the string
cont = *p++ != 0;
OFString *c = w[0];
// strip irc-style command prefix
if ([c hasPrefix:@"/"]) {
c = [c substringFromIndex:1];
w[0] = c;
}
// empty statement
if (c.length == 0)
continue;
val = executeIdentifier(identifiers[c],
[OFArray arrayWithObjects:w count:numargs], isDown);
} }
return val;
} }
// tab-completion of all identifiers // tab-completion of all identifiers
@ -300,64 +292,57 @@ resetcomplete()
void void
complete(OFMutableString *s) complete(OFMutableString *s)
{ {
@autoreleasepool { if (![s hasPrefix:@"/"])
if (![s hasPrefix:@"/"]) [s insertString:@"/" atIndex:0];
[s insertString:@"/" atIndex:0];
if (s.length == 1) if (s.length == 1)
return; return;
if (!completesize) { if (!completesize) {
completesize = s.length - 1; completesize = s.length - 1;
completeidx = 0; completeidx = 0;
}
__block int idx = 0;
[identifiers enumerateKeysAndObjectsUsingBlock:^(
OFString *name, Identifier *identifier, bool *stop) {
if (strncmp(identifier.name.UTF8String,
s.UTF8String + 1, completesize) == 0 &&
idx++ == completeidx)
[s replaceCharactersInRange:OFMakeRange(
1, s.length - 1)
withString:identifier.name];
}];
completeidx++;
if (completeidx >= idx)
completeidx = 0;
} }
__block int idx = 0;
[identifiers enumerateKeysAndObjectsUsingBlock:^(
OFString *name, Identifier *identifier, bool *stop) {
if (strncmp(identifier.name.UTF8String, s.UTF8String + 1,
completesize) == 0 &&
idx++ == completeidx)
[s replaceCharactersInRange:OFMakeRange(1, s.length - 1)
withString:identifier.name];
}];
completeidx++;
if (completeidx >= idx)
completeidx = 0;
} }
bool bool
execfile(OFIRI *cfgfile) execfile(OFIRI *cfgfile)
{ {
@autoreleasepool { OFString *command;
OFString *command; @try {
@try { command = [OFString stringWithContentsOfIRI:cfgfile];
command = [OFString stringWithContentsOfIRI:cfgfile]; } @catch (OFOpenItemFailedException *e) {
} @catch (OFOpenItemFailedException *e) { return false;
return false; } @catch (OFReadFailedException *e) {
} @catch (OFReadFailedException *e) { return false;
return false;
}
execute(command);
return true;
} }
execute(command);
return true;
} }
void void
exec(OFString *cfgfile) exec(OFString *cfgfile)
{ {
@autoreleasepool { if (!execfile([Cube.sharedInstance.userDataIRI
if (!execfile([Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:cfgfile]) &&
IRIByAppendingPathComponent:cfgfile]) && !execfile([Cube.sharedInstance.gameDataIRI
!execfile([Cube.sharedInstance.gameDataIRI IRIByAppendingPathComponent:cfgfile]))
IRIByAppendingPathComponent:cfgfile])) conoutf(@"could not read \"%@\"", cfgfile);
conoutf(@"could not read \"%@\"", cfgfile);
}
} }
void void
@ -418,9 +403,7 @@ COMMAND(writecfg, ARG_NONE)
void void
intset(OFString *name, int v) intset(OFString *name, int v)
{ {
@autoreleasepool { alias(name, [OFString stringWithFormat:@"%d", v]);
alias(name, [OFString stringWithFormat:@"%d", v]);
}
} }
void void
@ -432,14 +415,12 @@ ifthen(OFString *cond, OFString *thenp, OFString *elsep)
void void
loopa(OFString *times, OFString *body) loopa(OFString *times, OFString *body)
{ {
@autoreleasepool { int t = times.cube_intValue;
int t = times.cube_intValue;
loopi(t) loopi(t)
{ {
intset(@"i", i); intset(@"i", i);
execute(body); execute(body);
}
} }
} }
@ -472,32 +453,28 @@ concatword(OFString *s)
int int
listlen(OFString *a_) listlen(OFString *a_)
{ {
@autoreleasepool { const char *a = a_.UTF8String;
const char *a = a_.UTF8String;
if (!*a) if (!*a)
return 0; return 0;
int n = 0; int n = 0;
while (*a) while (*a)
if (*a++ == ' ') if (*a++ == ' ')
n++; n++;
return n + 1; return n + 1;
}
} }
void void
at(OFString *s_, OFString *pos) at(OFString *s_, OFString *pos)
{ {
@autoreleasepool { int n = pos.cube_intValue;
int n = pos.cube_intValue; std::unique_ptr<char> copy(strdup(s_.UTF8String));
std::unique_ptr<char> copy(strdup(s_.UTF8String)); char *s = copy.get();
char *s = copy.get(); loopi(n) s += strspn(s += strcspn(s, " \0"), " ");
loopi(n) s += strspn(s += strcspn(s, " \0"), " "); s[strcspn(s, " \0")] = 0;
s[strcspn(s, " \0")] = 0; concat(@(s));
concat(@(s));
}
} }
COMMANDN(loop, loopa, ARG_2STR) COMMANDN(loop, loopa, ARG_2STR)

View file

@ -83,22 +83,20 @@ conline(OFString *sf, bool highlight) // add a line to the console buffer
void void
conoutf(OFConstantString *format, ...) conoutf(OFConstantString *format, ...)
{ {
@autoreleasepool { va_list arguments;
va_list arguments; va_start(arguments, format);
va_start(arguments, format);
OFString *string = [[OFString alloc] initWithFormat:format OFString *string = [[OFString alloc] initWithFormat:format
arguments:arguments]; arguments:arguments];
va_end(arguments); va_end(arguments);
int n = 0; int n = 0;
while (string.length > WORDWRAP) { while (string.length > WORDWRAP) {
conline([string substringToIndex:WORDWRAP], n++ != 0); conline([string substringToIndex:WORDWRAP], n++ != 0);
string = [string substringFromIndex:WORDWRAP]; string = [string substringFromIndex:WORDWRAP];
}
conline(string, n != 0);
} }
conline(string, n != 0);
} }
// render buffer taking into account time & scrolling // render buffer taking into account time & scrolling
@ -181,19 +179,15 @@ COMMAND(saycommand, ARG_VARI)
void void
mapmsg(OFString *s) mapmsg(OFString *s)
{ {
@autoreleasepool { memset(hdr.maptitle, '\0', sizeof(hdr.maptitle));
memset(hdr.maptitle, '\0', sizeof(hdr.maptitle)); strncpy(hdr.maptitle, s.UTF8String, 127);
strncpy(hdr.maptitle, s.UTF8String, 127);
}
} }
COMMAND(mapmsg, ARG_1STR) COMMAND(mapmsg, ARG_1STR)
void void
pasteconsole() pasteconsole()
{ {
@autoreleasepool { [commandbuf appendString:@(SDL_GetClipboardText())];
[commandbuf appendString:@(SDL_GetClipboardText())];
}
} }
static OFMutableArray<OFString *> *vhistory; static OFMutableArray<OFString *> *vhistory;
@ -262,21 +256,17 @@ keypress(int code, bool isDown)
} else { } else {
if (code == SDLK_RETURN) { if (code == SDLK_RETURN) {
if (commandbuf.length > 0) { if (commandbuf.length > 0) {
@autoreleasepool { if (vhistory == nil)
if (vhistory == nil) vhistory =
vhistory = [[OFMutableArray alloc]
[[OFMutableArray init];
alloc] init];
if (vhistory.count == 0 || if (vhistory.count == 0 ||
![vhistory.lastObject ![vhistory.lastObject
isEqual:commandbuf]) { isEqual:commandbuf]) {
// cap this? // cap this?
[vhistory [vhistory addObject:[commandbuf
addObject: copy]];
[commandbuf
copy]];
}
} }
histpos = vhistory.count; histpos = vhistory.count;
if ([commandbuf hasPrefix:@"/"]) if ([commandbuf hasPrefix:@"/"])

View file

@ -604,11 +604,9 @@ void
newent(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4) newent(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4)
{ {
EDITSEL; EDITSEL;
@autoreleasepool { newentity(sel.x, sel.y, (int)player1.o.z, what,
newentity(sel.x, sel.y, (int)player1.o.z, what, [a1 cube_intValueWithBase:0], [a2 cube_intValueWithBase:0],
[a1 cube_intValueWithBase:0], [a2 cube_intValueWithBase:0], [a3 cube_intValueWithBase:0], [a4 cube_intValueWithBase:0]);
[a3 cube_intValueWithBase:0], [a4 cube_intValueWithBase:0]);
}
} }
COMMANDN(select, selectpos, ARG_4INT) COMMANDN(select, selectpos, ARG_4INT)

View file

@ -42,15 +42,10 @@ renderentities()
MapModelInfo *mmi = getmminfo(e.attr2); MapModelInfo *mmi = getmminfo(e.attr2);
if (mmi == nil) if (mmi == nil)
continue; continue;
@autoreleasepool { rendermodel(mmi.name, 0, 1, e.attr4, (float)mmi.rad,
rendermodel(mmi.name, 0, 1, e.attr4, e.x, (float)S(e.x, e.y)->floor + mmi.zoff + e.attr3,
(float)mmi.rad, e.x, e.y, (float)((e.attr1 + 7) - (e.attr1 + 7) % 15), 0,
(float)S(e.x, e.y)->floor + mmi.zoff + false, 1.0f, 10.0f, mmi.snap);
e.attr3,
e.y,
(float)((e.attr1 + 7) - (e.attr1 + 7) % 15),
0, false, 1.0f, 10.0f, mmi.snap);
}
} else { } else {
if (OUTBORD(e.x, e.y)) if (OUTBORD(e.x, e.y))
continue; continue;

View file

@ -43,53 +43,50 @@ void refreshservers();
bool bool
rendermenu() rendermenu()
{ {
@autoreleasepool { if (vmenu < 0) {
if (vmenu < 0) { [menuStack removeAllObjects];
[menuStack removeAllObjects]; return false;
return false;
}
if (vmenu == 1)
refreshservers();
Menu *m = menus[vmenu];
OFString *title;
if (vmenu > 1)
title =
[OFString stringWithFormat:@"[ %@ menu ]", m.name];
else
title = m.name;
int mdisp = m.items.count;
int w = 0;
loopi(mdisp)
{
int x = text_width(m.items[i].text);
if (x > w)
w = x;
}
int tw = text_width(title);
if (tw > w)
w = tw;
int step = FONTH / 4 * 5;
int h = (mdisp + 2) * step;
int y = (VIRTH - h) / 2;
int x = (VIRTW - w) / 2;
blendbox(x - FONTH / 2 * 3, y - FONTH, x + w + FONTH / 2 * 3,
y + h + FONTH, true);
draw_text(title, x, y, 2);
y += FONTH * 2;
if (vmenu) {
int bh = y + m.menusel * step;
blendbox(x - FONTH, bh - 10, x + w + FONTH,
bh + FONTH + 10, false);
}
loopj(mdisp)
{
draw_text(m.items[j].text, x, y, 2);
y += step;
}
return true;
} }
if (vmenu == 1)
refreshservers();
Menu *m = menus[vmenu];
OFString *title;
if (vmenu > 1)
title = [OFString stringWithFormat:@"[ %@ menu ]", m.name];
else
title = m.name;
int mdisp = m.items.count;
int w = 0;
loopi(mdisp)
{
int x = text_width(m.items[i].text);
if (x > w)
w = x;
}
int tw = text_width(title);
if (tw > w)
w = tw;
int step = FONTH / 4 * 5;
int h = (mdisp + 2) * step;
int y = (VIRTH - h) / 2;
int x = (VIRTW - w) / 2;
blendbox(x - FONTH / 2 * 3, y - FONTH, x + w + FONTH / 2 * 3,
y + h + FONTH, true);
draw_text(title, x, y, 2);
y += FONTH * 2;
if (vmenu) {
int bh = y + m.menusel * step;
blendbox(
x - FONTH, bh - 10, x + w + FONTH, bh + FONTH + 10, false);
}
loopj(mdisp)
{
draw_text(m.items[j].text, x, y, 2);
y += step;
}
return true;
} }
void void
@ -154,11 +151,8 @@ menukey(int code, bool isdown)
} else { } else {
if (code == SDLK_RETURN || code == -2) { if (code == SDLK_RETURN || code == -2) {
OFString *action = menus[vmenu].items[menusel].action; OFString *action = menus[vmenu].items[menusel].action;
if (vmenu == 1) { if (vmenu == 1)
@autoreleasepool { connects(getservername(menusel));
connects(getservername(menusel));
}
}
if (menuStack == nil) if (menuStack == nil)
menuStack = [[OFMutableArray alloc] init]; menuStack = [[OFMutableArray alloc] init];

View file

@ -203,34 +203,31 @@ renderents() // show sparkly thingies for map entities in edit mode
void void
loadsky(OFString *basename) loadsky(OFString *basename)
{ {
@autoreleasepool { static OFString *lastsky = @"";
static OFString *lastsky = @"";
basename = [basename stringByReplacingOccurrencesOfString:@"\\" basename = [basename stringByReplacingOccurrencesOfString:@"\\"
withString:@"/"]; withString:@"/"];
if ([lastsky isEqual:basename]) if ([lastsky isEqual:basename])
return; return;
static const OFString *side[] = { @"ft", @"bk", @"lf", @"rt", static const OFString *side[] = { @"ft", @"bk", @"lf", @"rt", @"dn",
@"dn", @"up" }; @"up" };
int texnum = 14; int texnum = 14;
loopi(6) loopi(6)
{ {
OFString *path = OFString *path = [OFString
[OFString stringWithFormat:@"packages/%@_%@.jpg", stringWithFormat:@"packages/%@_%@.jpg", basename, side[i]];
basename, side[i]];
int xs, ys; int xs, ys;
if (!installtex(texnum + i, if (!installtex(texnum + i,
[Cube.sharedInstance.gameDataIRI [Cube.sharedInstance.gameDataIRI
IRIByAppendingPathComponent:path], IRIByAppendingPathComponent:path],
&xs, &ys, true)) &xs, &ys, true))
conoutf(@"could not load sky textures"); conoutf(@"could not load sky textures");
}
lastsky = basename;
} }
lastsky = basename;
} }
COMMAND(loadsky, ARG_1STR) COMMAND(loadsky, ARG_1STR)
@ -367,17 +364,15 @@ gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwater)
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
@autoreleasepool { OFString *command = getcurcommand();
OFString *command = getcurcommand(); OFString *player = playerincrosshair();
OFString *player = playerincrosshair();
if (command) if (command)
draw_textf(@"> %@_", 20, 1570, 2, command); draw_textf(@"> %@_", 20, 1570, 2, command);
else if (closeent.length > 0) else if (closeent.length > 0)
draw_text(closeent, 20, 1570, 2); draw_text(closeent, 20, 1570, 2);
else if (player != nil) else if (player != nil)
draw_text(player, 20, 1570, 2); draw_text(player, 20, 1570, 2);
}
renderscores(); renderscores();
if (!rendermenu()) { if (!rendermenu()) {

View file

@ -78,40 +78,37 @@ cleangl()
bool bool
installtex(int tnum, OFIRI *IRI, int *xs, int *ys, bool clamp) installtex(int tnum, OFIRI *IRI, int *xs, int *ys, bool clamp)
{ {
@autoreleasepool { SDL_Surface *s = IMG_Load(IRI.fileSystemRepresentation.UTF8String);
SDL_Surface *s = if (s == NULL) {
IMG_Load(IRI.fileSystemRepresentation.UTF8String); conoutf(@"couldn't load texture %@", IRI.string);
if (s == NULL) { return false;
conoutf(@"couldn't load texture %@", IRI.string); }
if (s->format->BitsPerPixel != 24) {
SDL_PixelFormat *format =
SDL_AllocFormat(SDL_PIXELFORMAT_RGB24);
if (format == NULL) {
conoutf(@"texture cannot be converted to 24bpp: %@",
IRI.string);
return false; return false;
} }
if (s->format->BitsPerPixel != 24) { @try {
SDL_PixelFormat *format = SDL_Surface *converted =
SDL_AllocFormat(SDL_PIXELFORMAT_RGB24); SDL_ConvertSurface(s, format, 0);
if (format == NULL) { if (converted == NULL) {
conoutf( conoutf(@"texture cannot be converted "
@"texture cannot be converted to 24bpp: %@", @"to 24bpp: %@",
IRI.string); IRI.string);
return false; return false;
} }
@try { SDL_FreeSurface(s);
SDL_Surface *converted = s = converted;
SDL_ConvertSurface(s, format, 0); } @finally {
if (converted == NULL) { SDL_FreeFormat(format);
conoutf(@"texture cannot be converted "
@"to 24bpp: %@",
IRI.string);
return false;
}
SDL_FreeSurface(s);
s = converted;
} @finally {
SDL_FreeFormat(format);
}
} }
}
#if 0 #if 0
loopi(s->w * s->h * 3) loopi(s->w * s->h * 3)
@ -120,46 +117,44 @@ installtex(int tnum, OFIRI *IRI, int *xs, int *ys, bool clamp)
*p = 255 - *p; *p = 255 - *p;
} }
#endif #endif
glBindTexture(GL_TEXTURE_2D, tnum); glBindTexture(GL_TEXTURE_2D, tnum);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT); clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT); clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
glTexParameteri( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // NEAREST);
GL_LINEAR_MIPMAP_LINEAR); // NEAREST); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
*xs = s->w; *xs = s->w;
*ys = s->h; *ys = s->h;
while (*xs > glmaxtexsize || *ys > glmaxtexsize) { while (*xs > glmaxtexsize || *ys > glmaxtexsize) {
*xs /= 2; *xs /= 2;
*ys /= 2; *ys /= 2;
}
void *scaledimg = s->pixels;
if (*xs != s->w) {
conoutf(@"warning: quality loss: scaling %@",
IRI.string); // for voodoo cards under linux
scaledimg = OFAllocMemory(1, *xs * *ys * 3);
gluScaleImage(GL_RGB, s->w, s->h, GL_UNSIGNED_BYTE,
s->pixels, *xs, *ys, GL_UNSIGNED_BYTE, scaledimg);
}
if (gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, *xs, *ys, GL_RGB,
GL_UNSIGNED_BYTE, scaledimg))
fatal(@"could not build mipmaps");
if (*xs != s->w)
free(scaledimg);
SDL_FreeSurface(s);
return true;
} }
void *scaledimg = s->pixels;
if (*xs != s->w) {
conoutf(@"warning: quality loss: scaling %@",
IRI.string); // for voodoo cards under linux
scaledimg = OFAllocMemory(1, *xs * *ys * 3);
gluScaleImage(GL_RGB, s->w, s->h, GL_UNSIGNED_BYTE, s->pixels,
*xs, *ys, GL_UNSIGNED_BYTE, scaledimg);
}
if (gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, *xs, *ys, GL_RGB,
GL_UNSIGNED_BYTE, scaledimg))
fatal(@"could not build mipmaps");
if (*xs != s->w)
free(scaledimg);
SDL_FreeSurface(s);
return true;
} }
// management of texture slots // management of texture slots
@ -197,17 +192,14 @@ COMMAND(texturereset, ARG_NONE)
void void
texture(OFString *aframe, OFString *name) texture(OFString *aframe, OFString *name)
{ {
@autoreleasepool { int num = curtexnum++, frame = aframe.cube_intValue;
int num = curtexnum++, frame = aframe.cube_intValue;
if (num < 0 || num >= 256 || frame < 0 || frame >= MAXFRAMES) if (num < 0 || num >= 256 || frame < 0 || frame >= MAXFRAMES)
return; return;
mapping[num][frame] = 1; mapping[num][frame] = 1;
mapname[num][frame] = mapname[num][frame] = [name stringByReplacingOccurrencesOfString:@"\\"
[name stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
withString:@"/"];
}
} }
COMMAND(texture, ARG_2STR) COMMAND(texture, ARG_2STR)
@ -243,22 +235,20 @@ lookuptexture(int tex, int *xs, int *ys)
int tnum = curtex + FIRSTTEX; int tnum = curtex + FIRSTTEX;
texname[curtex] = mapname[tex][frame]; texname[curtex] = mapname[tex][frame];
@autoreleasepool { OFString *path =
OFString *path = [OFString stringWithFormat:@"packages/%@", texname[curtex]];
[OFString stringWithFormat:@"packages/%@", texname[curtex]];
if (installtex(tnum, if (installtex(tnum,
[Cube.sharedInstance.gameDataIRI [Cube.sharedInstance.gameDataIRI
IRIByAppendingPathComponent:path], IRIByAppendingPathComponent:path],
xs, ys, false)) { xs, ys, false)) {
mapping[tex][frame] = tnum; mapping[tex][frame] = tnum;
texx[curtex] = *xs; texx[curtex] = *xs;
texy[curtex] = *ys; texy[curtex] = *ys;
curtex++; curtex++;
return tnum; return tnum;
} else { } else {
return mapping[tex][frame] = FIRSTTEX; // temp fix return mapping[tex][frame] = FIRSTTEX; // temp fix
}
} }
} }

View file

@ -16,52 +16,42 @@ void
delayedload(MD2 *m) delayedload(MD2 *m)
{ {
if (!m.loaded) { if (!m.loaded) {
@autoreleasepool { OFString *path = [OFString
OFString *path = [OFString stringWithFormat:@"packages/models/%@", m.loadname];
stringWithFormat:@"packages/models/%@", m.loadname]; OFIRI *baseIRI = [Cube.sharedInstance.gameDataIRI
OFIRI *baseIRI = [Cube.sharedInstance.gameDataIRI IRIByAppendingPathComponent:path];
IRIByAppendingPathComponent:path];
OFIRI *IRI1 = OFIRI *IRI1 = [baseIRI IRIByAppendingPathComponent:@"tris.md2"];
[baseIRI IRIByAppendingPathComponent:@"tris.md2"]; if (![m loadWithIRI:IRI1])
if (![m loadWithIRI:IRI1]) fatal(@"loadmodel: ", IRI1.string);
fatal(@"loadmodel: ", IRI1.string);
OFIRI *IRI2 = OFIRI *IRI2 = [baseIRI IRIByAppendingPathComponent:@"skin.jpg"];
[baseIRI IRIByAppendingPathComponent:@"skin.jpg"]; int xs, ys;
int xs, ys; installtex(FIRSTMDL + m.mdlnum, IRI2, &xs, &ys, false);
installtex(FIRSTMDL + m.mdlnum, IRI2, &xs, &ys, false); m.loaded = true;
m.loaded = true;
}
} }
} }
MD2 * MD2 *
loadmodel(OFString *name) loadmodel(OFString *name)
{ {
@autoreleasepool { static int modelnum = 0;
static int modelnum = 0;
MD2 *m = mdllookup[name];
if (m != nil)
return m;
m = [[MD2 alloc] init];
m.mdlnum = modelnum++;
m.mmi = [[MapModelInfo alloc] initWithRad:2
h:2
zoff:0
snap:0
name:@""];
m.loadname = name;
if (mdllookup == nil)
mdllookup = [[OFMutableDictionary alloc] init];
mdllookup[name] = m;
MD2 *m = mdllookup[name];
if (m != nil)
return m; return m;
}
m = [[MD2 alloc] init];
m.mdlnum = modelnum++;
m.mmi = [[MapModelInfo alloc] initWithRad:2 h:2 zoff:0 snap:0 name:@""];
m.loadname = name;
if (mdllookup == nil)
mdllookup = [[OFMutableDictionary alloc] init];
mdllookup[name] = m;
return m;
} }
void void

View file

@ -102,114 +102,106 @@ short char_coords[96][4] = {
int int
text_width(OFString *string) text_width(OFString *string)
{ {
@autoreleasepool { const char *str = string.UTF8String;
const char *str = string.UTF8String; size_t len = string.UTF8StringLength;
size_t len = string.UTF8StringLength;
int x = 0; int x = 0;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
int c = str[i]; int c = str[i];
if (c == '\t') { if (c == '\t') {
x = (x + PIXELTAB) / PIXELTAB * PIXELTAB; x = (x + PIXELTAB) / PIXELTAB * PIXELTAB;
continue; continue;
}
if (c == '\f')
continue;
if (c == ' ') {
x += FONTH / 2;
continue;
}
c -= 33;
if (c < 0 || c >= 95)
continue;
int in_width = char_coords[c][2] - char_coords[c][0];
x += in_width + 1;
} }
return x; if (c == '\f')
continue;
if (c == ' ') {
x += FONTH / 2;
continue;
}
c -= 33;
if (c < 0 || c >= 95)
continue;
int in_width = char_coords[c][2] - char_coords[c][0];
x += in_width + 1;
} }
return x;
} }
void void
draw_textf(OFConstantString *format, int left, int top, int gl_num, ...) draw_textf(OFConstantString *format, int left, int top, int gl_num, ...)
{ {
@autoreleasepool { va_list arguments;
va_list arguments; va_start(arguments, gl_num);
va_start(arguments, gl_num); OFString *str = [[OFString alloc] initWithFormat:format
OFString *str = [[OFString alloc] initWithFormat:format arguments:arguments];
arguments:arguments]; va_end(arguments);
va_end(arguments); draw_text(str, left, top, gl_num);
draw_text(str, left, top, gl_num);
}
} }
void void
draw_text(OFString *string, int left, int top, int gl_num) draw_text(OFString *string, int left, int top, int gl_num)
{ {
@autoreleasepool { glBlendFunc(GL_ONE, GL_ONE);
glBlendFunc(GL_ONE, GL_ONE); glBindTexture(GL_TEXTURE_2D, gl_num);
glBindTexture(GL_TEXTURE_2D, gl_num); glColor3ub(255, 255, 255);
glColor3ub(255, 255, 255);
int x = left; int x = left;
int y = top; int y = top;
int i; int i;
float in_left, in_top, in_right, in_bottom; float in_left, in_top, in_right, in_bottom;
int in_width, in_height; int in_width, in_height;
const char *str = string.UTF8String; const char *str = string.UTF8String;
size_t len = string.UTF8StringLength; size_t len = string.UTF8StringLength;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
int c = str[i]; int c = str[i];
if (c == '\t') { if (c == '\t') {
x = (x - left + PIXELTAB) / PIXELTAB * x = (x - left + PIXELTAB) / PIXELTAB * PIXELTAB + left;
PIXELTAB + continue;
left;
continue;
}
if (c == '\f') {
glColor3ub(64, 255, 128);
continue;
}
if (c == ' ') {
x += FONTH / 2;
continue;
}
c -= 33;
if (c < 0 || c >= 95)
continue;
in_left = ((float)char_coords[c][0]) / 512.0f;
in_top = ((float)char_coords[c][1] + 2) / 512.0f;
in_right = ((float)char_coords[c][2]) / 512.0f;
in_bottom = ((float)char_coords[c][3] - 2) / 512.0f;
in_width = char_coords[c][2] - char_coords[c][0];
in_height = char_coords[c][3] - char_coords[c][1];
glBegin(GL_QUADS);
glTexCoord2f(in_left, in_top);
glVertex2i(x, y);
glTexCoord2f(in_right, in_top);
glVertex2i(x + in_width, y);
glTexCoord2f(in_right, in_bottom);
glVertex2i(x + in_width, y + in_height);
glTexCoord2f(in_left, in_bottom);
glVertex2i(x, y + in_height);
glEnd();
xtraverts += 4;
x += in_width + 1;
} }
if (c == '\f') {
glColor3ub(64, 255, 128);
continue;
}
if (c == ' ') {
x += FONTH / 2;
continue;
}
c -= 33;
if (c < 0 || c >= 95)
continue;
in_left = ((float)char_coords[c][0]) / 512.0f;
in_top = ((float)char_coords[c][1] + 2) / 512.0f;
in_right = ((float)char_coords[c][2]) / 512.0f;
in_bottom = ((float)char_coords[c][3] - 2) / 512.0f;
in_width = char_coords[c][2] - char_coords[c][0];
in_height = char_coords[c][3] - char_coords[c][1];
glBegin(GL_QUADS);
glTexCoord2f(in_left, in_top);
glVertex2i(x, y);
glTexCoord2f(in_right, in_top);
glVertex2i(x + in_width, y);
glTexCoord2f(in_right, in_bottom);
glVertex2i(x + in_width, y + in_height);
glTexCoord2f(in_left, in_bottom);
glVertex2i(x, y + in_height);
glEnd();
xtraverts += 4;
x += in_width + 1;
} }
} }

View file

@ -91,40 +91,38 @@ stopifrecording()
void void
savestate(OFIRI *IRI) savestate(OFIRI *IRI)
{ {
@autoreleasepool { stop();
stop(); f = gzopen([IRI.fileSystemRepresentation
f = gzopen([IRI.fileSystemRepresentation cStringWithEncoding:OFLocale.encoding],
cStringWithEncoding:OFLocale.encoding], "wb9");
"wb9"); if (!f) {
if (!f) { conoutf(@"could not write %@", IRI.string);
conoutf(@"could not write %@", IRI.string); return;
return; }
} gzwrite(f, (void *)"CUBESAVE", 8);
gzwrite(f, (void *)"CUBESAVE", 8); gzputc(f, islittleendian);
gzputc(f, islittleendian); gzputi(SAVEGAMEVERSION);
gzputi(SAVEGAMEVERSION); OFData *data = [player1 dataBySerializing];
OFData *data = [player1 dataBySerializing]; gzputi(data.count);
gzputi(data.count); char map[_MAXDEFSTR] = { 0 };
char map[_MAXDEFSTR] = { 0 }; memcpy(map, getclientmap().UTF8String,
memcpy(map, getclientmap().UTF8String, min(getclientmap().UTF8StringLength, _MAXDEFSTR - 1));
min(getclientmap().UTF8StringLength, _MAXDEFSTR - 1)); gzwrite(f, map, _MAXDEFSTR);
gzwrite(f, map, _MAXDEFSTR); gzputi(gamemode);
gzputi(gamemode); gzputi(ents.length());
gzputi(ents.length()); loopv(ents) gzputc(f, ents[i].spawned);
loopv(ents) gzputc(f, ents[i].spawned); gzwrite(f, data.items, data.count);
OFArray<DynamicEntity *> *monsters = getmonsters();
gzputi(monsters.count);
for (DynamicEntity *monster in monsters) {
data = [monster dataBySerializing];
gzwrite(f, data.items, data.count);
}
gzputi(players.count);
for (id player in players) {
gzput(player == [OFNull null]);
data = [player dataBySerializing];
gzwrite(f, data.items, data.count); gzwrite(f, data.items, data.count);
OFArray<DynamicEntity *> *monsters = getmonsters();
gzputi(monsters.count);
for (DynamicEntity *monster in monsters) {
data = [monster dataBySerializing];
gzwrite(f, data.items, data.count);
}
gzputi(players.count);
for (id player in players) {
gzput(player == [OFNull null]);
data = [player dataBySerializing];
gzwrite(f, data.items, data.count);
}
} }
} }
@ -136,70 +134,60 @@ savegame(OFString *name)
return; return;
} }
@autoreleasepool { OFString *path = [OFString stringWithFormat:@"savegames/%@.csgz", name];
OFString *path = OFIRI *IRI =
[OFString stringWithFormat:@"savegames/%@.csgz", name]; [Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:path];
OFIRI *IRI = [Cube.sharedInstance.userDataIRI savestate(IRI);
IRIByAppendingPathComponent:path]; stop();
savestate(IRI); conoutf(@"wrote %@", IRI.string);
stop();
conoutf(@"wrote %@", IRI.string);
}
} }
COMMAND(savegame, ARG_1STR) COMMAND(savegame, ARG_1STR)
void void
loadstate(OFIRI *IRI) loadstate(OFIRI *IRI)
{ {
@autoreleasepool { stop();
stop(); if (multiplayer())
if (multiplayer()) return;
return; f = gzopen([IRI.fileSystemRepresentation
f = gzopen([IRI.fileSystemRepresentation cStringWithEncoding:OFLocale.encoding],
cStringWithEncoding:OFLocale.encoding], "rb9");
"rb9"); if (!f) {
if (!f) { conoutf(@"could not open %@", IRI.string);
conoutf(@"could not open %@", IRI.string);
return;
}
char mapname[_MAXDEFSTR] = { 0 };
char buf[8];
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() != DynamicEntity.serializedSize)
goto out;
gzread(f, mapname, _MAXDEFSTR);
nextmode = gzgeti();
@autoreleasepool {
// continue below once map has been loaded and client &
// server have updated
changemap(@(mapname));
}
return; return;
out:
conoutf(@"aborting: savegame/demo from a different version of "
@"cube or cpu architecture");
stop();
} }
char mapname[_MAXDEFSTR] = { 0 };
char buf[8];
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() != DynamicEntity.serializedSize)
goto out;
gzread(f, mapname, _MAXDEFSTR);
nextmode = gzgeti();
// 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 void
loadgame(OFString *name) loadgame(OFString *name)
{ {
@autoreleasepool { OFString *path = [OFString stringWithFormat:@"savegames/%@.csgz", name];
OFString *path = OFIRI *IRI =
[OFString stringWithFormat:@"savegames/%@.csgz", name]; [Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:path];
OFIRI *IRI = [Cube.sharedInstance.userDataIRI loadstate(IRI);
IRIByAppendingPathComponent:path];
loadstate(IRI);
}
} }
COMMAND(loadgame, ARG_1STR) COMMAND(loadgame, ARG_1STR)
@ -286,18 +274,15 @@ record(OFString *name)
if (cn < 0) if (cn < 0)
return; return;
@autoreleasepool { OFString *path = [OFString stringWithFormat:@"demos/%@.cdgz", name];
OFString *path = OFIRI *IRI =
[OFString stringWithFormat:@"demos/%@.cdgz", name]; [Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:path];
OFIRI *IRI = [Cube.sharedInstance.userDataIRI savestate(IRI);
IRIByAppendingPathComponent:path]; gzputi(cn);
savestate(IRI); conoutf(@"started recording demo to %@", IRI.string);
gzputi(cn); demorecording = true;
conoutf(@"started recording demo to %@", IRI.string); starttime = lastmillis;
demorecording = true; ddamage = bdamage = 0;
starttime = lastmillis;
ddamage = bdamage = 0;
}
} }
COMMAND(record, ARG_1STR) COMMAND(record, ARG_1STR)
@ -348,14 +333,11 @@ incomingdemodata(uchar *buf, int len, bool extras)
void void
demo(OFString *name) demo(OFString *name)
{ {
@autoreleasepool { OFString *path = [OFString stringWithFormat:@"demos/%@.cdgz", name];
OFString *path = OFIRI *IRI =
[OFString stringWithFormat:@"demos/%@.cdgz", name]; [Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:path];
OFIRI *IRI = [Cube.sharedInstance.userDataIRI loadstate(IRI);
IRIByAppendingPathComponent:path]; demoloading = true;
loadstate(IRI);
demoloading = true;
}
} }
COMMAND(demo, ARG_1STR) COMMAND(demo, ARG_1STR)

View file

@ -173,13 +173,10 @@ vote(OFString *map, int reqmode, int sender)
if (yes == 1 && no == 0) if (yes == 1 && no == 0)
return true; // single player return true; // single player
@autoreleasepool { OFString *msg = [OFString
OFString *msg = stringWithFormat:@"%@ suggests %@ on map %@ (set map to vote)",
[OFString stringWithFormat: clients[sender].name, modestr(reqmode), map];
@"%@ suggests %@ on map %@ (set map to vote)", sendservmsg(msg);
clients[sender].name, modestr(reqmode), map];
sendservmsg(msg);
}
if (yes / (float)(yes + no) <= 0.5f) if (yes / (float)(yes + no) <= 0.5f)
return false; return false;
@ -215,9 +212,7 @@ process(ENetPacket *packet, int sender) // sender may be -1
case SV_INITC2S: case SV_INITC2S:
sgetstr(); sgetstr();
@autoreleasepool { clients[cn].name = @(text);
clients[cn].name = @(text);
}
sgetstr(); sgetstr();
getint(p); getint(p);
break; break;
@ -227,19 +222,15 @@ process(ENetPacket *packet, int sender) // sender may be -1
int reqmode = getint(p); int reqmode = getint(p);
if (reqmode < 0) if (reqmode < 0)
reqmode = 0; reqmode = 0;
@autoreleasepool { if (smapname.length > 0 && !mapreload &&
if (smapname.length > 0 && !mapreload && !vote(@(text), reqmode, sender))
!vote(@(text), reqmode, sender)) return;
return;
}
mapreload = false; mapreload = false;
mode = reqmode; mode = reqmode;
minremain = mode & 1 ? 15 : 10; minremain = mode & 1 ? 15 : 10;
mapend = lastsec + minremain * 60; mapend = lastsec + minremain * 60;
interm = 0; interm = 0;
@autoreleasepool { smapname = @(text);
smapname = @(text);
}
resetitems(); resetitems();
sender = -1; sender = -1;
break; break;
@ -284,9 +275,7 @@ process(ENetPacket *packet, int sender) // sender may be -1
case SV_SENDMAP: { case SV_SENDMAP: {
sgetstr(); sgetstr();
int mapsize = getint(p); int mapsize = getint(p);
@autoreleasepool { sendmaps(sender, @(text), mapsize, p);
sendmaps(sender, @(text), mapsize, p);
}
return; return;
} }
@ -329,9 +318,7 @@ send_welcome(int n)
putint(p, SV_INITS2C); putint(p, SV_INITS2C);
putint(p, n); putint(p, n);
putint(p, PROTOCOL_VERSION); putint(p, PROTOCOL_VERSION);
@autoreleasepool { putint(p, *smapname.UTF8String);
putint(p, *smapname.UTF8String);
}
sendstring(serverpassword, p); sendstring(serverpassword, p);
putint(p, clients.count > maxclients); putint(p, clients.count > maxclients);
if (smapname.length > 0) { if (smapname.length > 0) {
@ -493,13 +480,10 @@ serverslice(int seconds,
c.peer = event.peer; c.peer = event.peer;
c.peer->data = (void *)(clients.count - 1); c.peer->data = (void *)(clients.count - 1);
char hn[1024]; char hn[1024];
@autoreleasepool { c.hostname = (enet_address_get_host(
c.hostname = &c.peer->address, hn, sizeof(hn)) == 0
(enet_address_get_host( ? @(hn)
&c.peer->address, hn, sizeof(hn)) == 0 : @"localhost");
? @(hn)
: @"localhost");
}
[OFStdOut [OFStdOut
writeFormat:@"client connected (%@)\n", c.hostname]; writeFormat:@"client connected (%@)\n", c.hostname];
send_welcome(lastconnect = clients.count - 1); send_welcome(lastconnect = clients.count - 1);
@ -566,11 +550,9 @@ initserver(bool dedicated, int uprate, OFString *sdesc, OFString *ip,
if ((isdedicated = dedicated)) { if ((isdedicated = dedicated)) {
ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT }; ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT };
@autoreleasepool { if (ip.length > 0 &&
if (ip.length > 0 && enet_address_set_host(&address, ip.UTF8String) < 0)
enet_address_set_host(&address, ip.UTF8String) < 0) printf("WARNING: server ip not resolved");
printf("WARNING: server ip not resolved");
}
serverhost = enet_host_create(&address, MAXCLIENTS, 0, uprate); serverhost = enet_host_create(&address, MAXCLIENTS, 0, uprate);
if (!serverhost) if (!serverhost)
fatal(@"could not create server host\n"); fatal(@"could not create server host\n");
@ -589,6 +571,9 @@ initserver(bool dedicated, int uprate, OFString *sdesc, OFString *ip,
atexit(cleanupserver); atexit(cleanupserver);
atexit(enet_deinitialize); atexit(enet_deinitialize);
for (;;) for (;;)
serverslice(/*enet_time_get_sec()*/ time(NULL), 5); @autoreleasepool {
serverslice(
/*enet_time_get_sec()*/ time(NULL), 5);
}
} }
} }

View file

@ -180,17 +180,14 @@ getservername(int n)
void void
addserver(OFString *servername) addserver(OFString *servername)
{ {
@autoreleasepool { for (ServerInfo *si in servers)
for (ServerInfo *si in servers) if ([si.name isEqual:servername])
if ([si.name isEqual:servername]) return;
return;
if (servers == nil) if (servers == nil)
servers = [[OFMutableArray alloc] init]; servers = [[OFMutableArray alloc] init];
[servers [servers addObject:[[ServerInfo alloc] initWithName:servername]];
addObject:[[ServerInfo alloc] initWithName:servername]];
}
} }
void void
@ -260,13 +257,9 @@ checkpings()
si.numplayers = getint(p); si.numplayers = getint(p);
si.minremain = getint(p); si.minremain = getint(p);
sgetstr(); sgetstr();
@autoreleasepool { si.map = @(text);
si.map = @(text);
}
sgetstr(); sgetstr();
@autoreleasepool { si.sdesc = @(text);
si.sdesc = @(text);
}
break; break;
} }
} }
@ -306,10 +299,8 @@ refreshservers()
si.name]; si.name];
// cut off too long server descriptions // cut off too long server descriptions
@autoreleasepool { if (si.full.length > 50)
if (si.full.length > 50) si.full = [si.full substringToIndex:50];
si.full = [si.full substringToIndex:50];
}
menumanual(1, i, si.full); menumanual(1, i, si.full);
@ -348,9 +339,7 @@ updatefrommaster()
conoutf(@"master server not replying"); conoutf(@"master server not replying");
else { else {
[servers removeAllObjects]; [servers removeAllObjects];
@autoreleasepool { execute(@((char *)reply));
execute(@((char *)reply));
}
} }
servermenu(); servermenu();
} }
@ -366,9 +355,7 @@ writeservercfg()
if (!f) if (!f)
return; return;
fprintf(f, "// servers connected to are added here automatically\n\n"); fprintf(f, "// servers connected to are added here automatically\n\n");
@autoreleasepool { for (ServerInfo *si in servers.reversedArray)
for (ServerInfo *si in servers.reversedArray) fprintf(f, "addserver %s\n", si.name.UTF8String);
fprintf(f, "addserver %s\n", si.name.UTF8String);
}
fclose(f); fclose(f);
} }

View file

@ -10,9 +10,7 @@ httpgetsend(ENetAddress &ad, OFString *hostname, OFString *req, OFString *ref,
{ {
if (ad.host == ENET_HOST_ANY) { if (ad.host == ENET_HOST_ANY) {
[OFStdOut writeFormat:@"looking up %@...\n", hostname]; [OFStdOut writeFormat:@"looking up %@...\n", hostname];
@autoreleasepool { enet_address_set_host(&ad, hostname.UTF8String);
enet_address_set_host(&ad, hostname.UTF8String);
}
if (ad.host == ENET_HOST_ANY) if (ad.host == ENET_HOST_ANY)
return; return;
} }
@ -79,13 +77,10 @@ updatemasterserver(int seconds)
{ {
// send alive signal to masterserver every hour of uptime // send alive signal to masterserver every hour of uptime
if (seconds > updmaster) { if (seconds > updmaster) {
@autoreleasepool { OFString *path = [OFString
OFString *path = [OFString stringWithFormat:@"%@register.do?action=add", masterpath];
stringWithFormat:@"%@register.do?action=add", httpgetsend(masterserver, masterbase, path, @"cubeserver",
masterpath]; @"Cube Server");
httpgetsend(masterserver, masterbase, path,
@"cubeserver", @"Cube Server");
}
masterrep[0] = 0; masterrep[0] = 0;
masterb.data = masterrep; masterb.data = masterrep;
masterb.dataLength = MAXTRANS - 1; masterb.dataLength = MAXTRANS - 1;
@ -105,12 +100,10 @@ checkmasterreply()
uchar * uchar *
retrieveservers(uchar *buf, int buflen) retrieveservers(uchar *buf, int buflen)
{ {
@autoreleasepool { OFString *path =
OFString *path = [OFString [OFString stringWithFormat:@"%@retrieve.do?item=list", masterpath];
stringWithFormat:@"%@retrieve.do?item=list", masterpath]; httpgetsend(
httpgetsend(masterserver, masterbase, path, @"cubeserver", masterserver, masterbase, path, @"cubeserver", @"Cube Server");
@"Cube Server");
}
ENetBuffer eb; ENetBuffer eb;
buf[0] = 0; buf[0] = 0;
eb.data = buf; eb.data = buf;
@ -160,23 +153,20 @@ serverms(int mode, int numplayers, int minremain, OFString *smapname,
void void
servermsinit(OFString *master_, OFString *sdesc, bool listen) servermsinit(OFString *master_, OFString *sdesc, bool listen)
{ {
@autoreleasepool { const char *master = master_.UTF8String;
const char *master = master_.UTF8String; const char *mid = strstr(master, "/");
const char *mid = strstr(master, "/"); if (!mid)
if (!mid) mid = master;
mid = master; masterpath = @(mid);
masterpath = @(mid); masterbase = [[OFString alloc] initWithUTF8String:master
masterbase = [[OFString alloc] initWithUTF8String:master length:mid - master];
length:mid - master]; serverdesc = sdesc;
serverdesc = sdesc;
if (listen) { if (listen) {
ENetAddress address = { ENET_HOST_ANY, ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
CUBE_SERVINFO_PORT }; pongsock =
pongsock = enet_socket_create( enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, &address);
ENET_SOCKET_TYPE_DATAGRAM, &address); if (pongsock == ENET_SOCKET_NULL)
if (pongsock == ENET_SOCKET_NULL) fatal(@"could not create server info socket\n");
fatal(@"could not create server info socket\n");
}
} }
} }

View file

@ -45,14 +45,12 @@ getint(uchar *&p)
void void
sendstring(OFString *t_, uchar *&p) sendstring(OFString *t_, uchar *&p)
{ {
@autoreleasepool { const char *t = t_.UTF8String;
const char *t = t_.UTF8String;
for (size_t i = 0; i < _MAXDEFSTR && *t != '\0'; i++) for (size_t i = 0; i < _MAXDEFSTR && *t != '\0'; i++)
putint(p, *t++); putint(p, *t++);
putint(p, 0); putint(p, 0);
}
} }
static const OFString *modenames[] = { static const OFString *modenames[] = {

View file

@ -87,43 +87,37 @@ music(OFString *name)
return; return;
stopsound(); stopsound();
if (soundvol && musicvol) { if (soundvol && musicvol) {
@autoreleasepool { name = [name stringByReplacingOccurrencesOfString:@"\\"
name = [name stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
withString:@"/"]; OFString *path =
OFString *path = [OFString stringWithFormat:@"packages/%@", name];
[OFString stringWithFormat:@"packages/%@", name]; OFIRI *IRI = [Cube.sharedInstance.gameDataIRI
OFIRI *IRI = [Cube.sharedInstance.gameDataIRI IRIByAppendingPathComponent:path];
IRIByAppendingPathComponent:path];
#ifdef USE_MIXER #ifdef USE_MIXER
if ((mod = Mix_LoadMUS( if ((mod = Mix_LoadMUS(
IRI.fileSystemRepresentation.UTF8String)) != IRI.fileSystemRepresentation.UTF8String)) != NULL) {
NULL) { Mix_PlayMusic(mod, -1);
Mix_PlayMusic(mod, -1); Mix_VolumeMusic((musicvol * MAXVOL) / 255);
Mix_VolumeMusic((musicvol * MAXVOL) / 255);
}
#else
if ((mod = FMUSIC_LoadSong(
IRI.fileSystemRepresentation.UTF8String)) !=
NULL) {
FMUSIC_PlaySong(mod);
FMUSIC_SetMasterVolume(mod, musicvol);
} else if (stream = FSOUND_Stream_Open(
IRI.fileSystemRepresentation.UTF8String,
FSOUND_LOOP_NORMAL, 0, 0)) {
int chan =
FSOUND_Stream_Play(FSOUND_FREE, stream);
if (chan >= 0) {
FSOUND_SetVolume(
chan, (musicvol * MAXVOL) / 255);
FSOUND_SetPaused(chan, false);
}
} else {
conoutf(
@"could not play music: %@", IRI.string);
}
#endif
} }
#else
if ((mod = FMUSIC_LoadSong(
IRI.fileSystemRepresentation.UTF8String)) != NULL) {
FMUSIC_PlaySong(mod);
FMUSIC_SetMasterVolume(mod, musicvol);
} else if (stream = FSOUND_Stream_Open(
IRI.fileSystemRepresentation.UTF8String,
FSOUND_LOOP_NORMAL, 0, 0)) {
int chan = FSOUND_Stream_Play(FSOUND_FREE, stream);
if (chan >= 0) {
FSOUND_SetVolume(
chan, (musicvol * MAXVOL) / 255);
FSOUND_SetPaused(chan, false);
}
} else {
conoutf(@"could not play music: %@", IRI.string);
}
#endif
} }
} }
COMMAND(music, ARG_1STR) COMMAND(music, ARG_1STR)

View file

@ -67,13 +67,11 @@ trigger(int tag, int type, bool savegame)
if (!savegame && type != 3) if (!savegame && type != 3)
playsound(S_RUMBLE); playsound(S_RUMBLE);
@autoreleasepool { OFString *aliasname =
OFString *aliasname = [OFString stringWithFormat:@"level_trigger_%d", tag];
[OFString stringWithFormat:@"level_trigger_%d", tag];
if (identexists(aliasname)) if (identexists(aliasname))
execute(aliasname); execute(aliasname);
}
if (type == 2) if (type == 2)
endsp(false); endsp(false);
@ -306,9 +304,7 @@ delent()
return; return;
} }
int t = ents[e].type; int t = ents[e].type;
@autoreleasepool { conoutf(@"%@ entity deleted", entnames[t]);
conoutf(@"%@ entity deleted", entnames[t]);
}
ents[e].type = NOTUSED; ents[e].type = NOTUSED;
addmsg(1, 10, SV_EDITENT, e, NOTUSED, 0, 0, 0, 0, 0, 0, 0); addmsg(1, 10, SV_EDITENT, e, NOTUSED, 0, 0, 0, 0, 0, 0, 0);
if (t == LIGHT) if (t == LIGHT)
@ -318,11 +314,9 @@ delent()
int int
findtype(OFString *what) findtype(OFString *what)
{ {
@autoreleasepool { loopi(MAXENTTYPES) if ([what isEqual:entnames[i]]) return i;
loopi(MAXENTTYPES) if ([what isEqual:entnames[i]]) return i; conoutf(@"unknown entity type \"%@\"", what);
conoutf(@"unknown entity type \"%@\"", what); return NOTUSED;
return NOTUSED;
}
} }
entity * entity *

View file

@ -14,30 +14,27 @@ static OFString *cgzname, *bakname, *pcfname, *mcfname;
static void static void
setnames(OFString *name) setnames(OFString *name)
{ {
@autoreleasepool { OFCharacterSet *cs =
OFCharacterSet *cs = [OFCharacterSet characterSetWithCharactersInString:@"/\\"];
[OFCharacterSet characterSetWithCharactersInString:@"/\\"]; OFRange range = [name rangeOfCharacterFromSet:cs];
OFRange range = [name rangeOfCharacterFromSet:cs]; OFString *pakname, *mapname;
OFString *pakname, *mapname;
if (range.location != OFNotFound) { if (range.location != OFNotFound) {
pakname = [name substringToIndex:range.location]; pakname = [name substringToIndex:range.location];
mapname = [name substringFromIndex:range.location + 1]; mapname = [name substringFromIndex:range.location + 1];
} else { } else {
pakname = @"base"; pakname = @"base";
mapname = name; mapname = name;
}
cgzname = [[OFString alloc]
initWithFormat:@"packages/%@/%@.cgz", pakname, mapname];
bakname =
[[OFString alloc] initWithFormat:@"packages/%@/%@_%d.BAK",
pakname, mapname, lastmillis];
pcfname = [[OFString alloc]
initWithFormat:@"packages/%@/package.cfg", pakname];
mcfname = [[OFString alloc]
initWithFormat:@"packages/%@/%@.cfg", pakname, mapname];
} }
cgzname = [[OFString alloc]
initWithFormat:@"packages/%@/%@.cgz", pakname, mapname];
bakname = [[OFString alloc] initWithFormat:@"packages/%@/%@_%d.BAK",
pakname, mapname, lastmillis];
pcfname = [[OFString alloc]
initWithFormat:@"packages/%@/package.cfg", pakname];
mcfname = [[OFString alloc]
initWithFormat:@"packages/%@/%@.cfg", pakname, mapname];
} }
// the optimize routines below are here to reduce the detrimental effects of // the optimize routines below are here to reduce the detrimental effects of
@ -160,38 +157,37 @@ readmap(OFString *mname)
void void
save_world(OFString *mname) save_world(OFString *mname)
{ {
@autoreleasepool { resettagareas(); // wouldn't be able to reproduce tagged areas
resettagareas(); // wouldn't be able to reproduce tagged areas // otherwise
// otherwise voptimize();
voptimize(); toptimize();
toptimize(); if (mname.length == 0)
if (mname.length == 0) mname = getclientmap();
mname = getclientmap(); setnames(mname);
setnames(mname); backup(cgzname, bakname);
backup(cgzname, bakname); gzFile f =
gzFile f = gzopen( gzopen([cgzname cStringWithEncoding:OFLocale.encoding], "wb9");
[cgzname cStringWithEncoding:OFLocale.encoding], "wb9"); if (!f) {
if (!f) { conoutf(@"could not write map to %@", cgzname);
conoutf(@"could not write map to %@", cgzname); return;
return; }
hdr.version = MAPVERSION;
hdr.numents = 0;
loopv(ents) if (ents[i].type != NOTUSED) hdr.numents++;
header tmp = hdr;
endianswap(&tmp.version, sizeof(int), 4);
endianswap(&tmp.waterlevel, sizeof(int), 16);
gzwrite(f, &tmp, sizeof(header));
loopv(ents)
{
if (ents[i].type != NOTUSED) {
entity tmp = ents[i];
endianswap(&tmp, sizeof(short), 4);
gzwrite(f, &tmp, sizeof(persistent_entity));
} }
hdr.version = MAPVERSION; }
hdr.numents = 0; sqr *t = NULL;
loopv(ents) if (ents[i].type != NOTUSED) hdr.numents++; int sc = 0;
header tmp = hdr;
endianswap(&tmp.version, sizeof(int), 4);
endianswap(&tmp.waterlevel, sizeof(int), 16);
gzwrite(f, &tmp, sizeof(header));
loopv(ents)
{
if (ents[i].type != NOTUSED) {
entity tmp = ents[i];
endianswap(&tmp, sizeof(short), 4);
gzwrite(f, &tmp, sizeof(persistent_entity));
}
}
sqr *t = NULL;
int sc = 0;
#define spurge \ #define spurge \
while (sc) { \ while (sc) { \
gzputc(f, 255); \ gzputc(f, 255); \
@ -203,50 +199,49 @@ save_world(OFString *mname)
sc = 0; \ sc = 0; \
} \ } \
} }
loopk(cubicsize) loopk(cubicsize)
{ {
sqr *s = &world[k]; sqr *s = &world[k];
#define c(f) (s->f == t->f) #define c(f) (s->f == t->f)
// 4 types of blocks, to compress a bit: // 4 types of blocks, to compress a bit:
// 255 (2): same as previous block + count // 255 (2): same as previous block + count
// 254 (3): same as previous, except light // deprecated // 254 (3): same as previous, except light // deprecated
// SOLID (5) // SOLID (5)
// anything else (9) // anything else (9)
if (SOLID(s)) { if (SOLID(s)) {
if (t && c(type) && c(wtex) && c(vdelta)) { if (t && c(type) && c(wtex) && c(vdelta)) {
sc++; sc++;
} else {
spurge;
gzputc(f, s->type);
gzputc(f, s->wtex);
gzputc(f, s->vdelta);
}
} else { } else {
if (t && c(type) && c(floor) && c(ceil) && spurge;
c(ctex) && c(ftex) && c(utex) && c(wtex) && gzputc(f, s->type);
c(vdelta) && c(tag)) { gzputc(f, s->wtex);
sc++; gzputc(f, s->vdelta);
} else { }
spurge; } else {
gzputc(f, s->type); if (t && c(type) && c(floor) && c(ceil) && c(ctex) &&
gzputc(f, s->floor); c(ftex) && c(utex) && c(wtex) && c(vdelta) &&
gzputc(f, s->ceil); c(tag)) {
gzputc(f, s->wtex); sc++;
gzputc(f, s->ftex); } else {
gzputc(f, s->ctex); spurge;
gzputc(f, s->vdelta); gzputc(f, s->type);
gzputc(f, s->utex); gzputc(f, s->floor);
gzputc(f, s->tag); gzputc(f, s->ceil);
} gzputc(f, s->wtex);
gzputc(f, s->ftex);
gzputc(f, s->ctex);
gzputc(f, s->vdelta);
gzputc(f, s->utex);
gzputc(f, s->tag);
} }
t = s;
} }
spurge; t = s;
gzclose(f);
conoutf(@"wrote map file %@", cgzname);
settagareas();
} }
spurge;
gzclose(f);
conoutf(@"wrote map file %@", cgzname);
settagareas();
} }
COMMANDN(savemap, save_world, ARG_1STR) COMMANDN(savemap, save_world, ARG_1STR)
@ -254,142 +249,136 @@ void
load_world(OFString *mname) // still supports all map formats that have existed load_world(OFString *mname) // still supports all map formats that have existed
// since the earliest cube betas! // since the earliest cube betas!
{ {
@autoreleasepool { stopifrecording();
stopifrecording(); cleardlights();
cleardlights(); pruneundos();
pruneundos(); setnames(mname);
setnames(mname); gzFile f =
gzFile f = gzopen( gzopen([cgzname cStringWithEncoding:OFLocale.encoding], "rb9");
[cgzname cStringWithEncoding:OFLocale.encoding], "rb9"); if (!f) {
if (!f) { conoutf(@"could not read map %@", cgzname);
conoutf(@"could not read map %@", cgzname); return;
return;
}
gzread(f, &hdr, sizeof(header) - sizeof(int) * 16);
endianswap(&hdr.version, sizeof(int), 4);
if (strncmp(hdr.head, "CUBE", 4) != 0)
fatal(@"while reading map: header malformatted");
if (hdr.version > MAPVERSION)
fatal(@"this map requires a newer version of cube");
if (sfactor < SMALLEST_FACTOR || sfactor > LARGEST_FACTOR)
fatal(@"illegal map size");
if (hdr.version >= 4) {
gzread(f, &hdr.waterlevel, sizeof(int) * 16);
endianswap(&hdr.waterlevel, sizeof(int), 16);
} else {
hdr.waterlevel = -100000;
}
ents.setsize(0);
loopi(hdr.numents)
{
entity &e = ents.add();
gzread(f, &e, sizeof(persistent_entity));
endianswap(&e, sizeof(short), 4);
e.spawned = false;
if (e.type == LIGHT) {
if (!e.attr2)
e.attr2 =
255; // needed for MAPVERSION<=2
if (e.attr1 > 32)
e.attr1 = 32; // 12_03 and below
}
}
free(world);
setupworld(hdr.sfactor);
char texuse[256];
loopi(256) texuse[i] = 0;
sqr *t = NULL;
loopk(cubicsize)
{
sqr *s = &world[k];
int type = gzgetc(f);
switch (type) {
case 255: {
int n = gzgetc(f);
for (int i = 0; i < n; i++, k++)
memcpy(&world[k], t, sizeof(sqr));
k--;
break;
}
case 254: // only in MAPVERSION<=2
{
memcpy(s, t, sizeof(sqr));
s->r = s->g = s->b = gzgetc(f);
gzgetc(f);
break;
}
case SOLID: {
s->type = SOLID;
s->wtex = gzgetc(f);
s->vdelta = gzgetc(f);
if (hdr.version <= 2) {
gzgetc(f);
gzgetc(f);
}
s->ftex = DEFAULT_FLOOR;
s->ctex = DEFAULT_CEIL;
s->utex = s->wtex;
s->tag = 0;
s->floor = 0;
s->ceil = 16;
break;
}
default: {
if (type < 0 || type >= MAXTYPE) {
OFString *t = [OFString
stringWithFormat:@"%d @ %d", type,
k];
fatal(@"while reading map: type out of "
@"range: ",
t);
}
s->type = type;
s->floor = gzgetc(f);
s->ceil = gzgetc(f);
if (s->floor >= s->ceil)
s->floor = s->ceil - 1; // for pre 12_13
s->wtex = gzgetc(f);
s->ftex = gzgetc(f);
s->ctex = gzgetc(f);
if (hdr.version <= 2) {
gzgetc(f);
gzgetc(f);
}
s->vdelta = gzgetc(f);
s->utex =
(hdr.version >= 2) ? gzgetc(f) : s->wtex;
s->tag = (hdr.version >= 5) ? gzgetc(f) : 0;
s->type = type;
}
}
s->defer = 0;
t = s;
texuse[s->wtex] = 1;
if (!SOLID(s))
texuse[s->utex] = texuse[s->ftex] =
texuse[s->ctex] = 1;
}
gzclose(f);
calclight();
settagareas();
int xs, ys;
loopi(256) if (texuse) lookuptexture(i, &xs, &ys);
conoutf(@"read map %@ (%d milliseconds)", cgzname,
SDL_GetTicks() - lastmillis);
conoutf(@"%s", hdr.maptitle);
startmap(mname);
loopl(256)
{
// can this be done smarter?
OFString *aliasname =
[OFString stringWithFormat:@"level_trigger_%d", l];
if (identexists(aliasname))
alias(aliasname, @"");
}
OFIRI *gameDataIRI = Cube.sharedInstance.gameDataIRI;
execfile([gameDataIRI IRIByAppendingPathComponent:
@"data/default_map_settings.cfg"]);
execfile([gameDataIRI IRIByAppendingPathComponent:pcfname]);
execfile([gameDataIRI IRIByAppendingPathComponent:mcfname]);
} }
gzread(f, &hdr, sizeof(header) - sizeof(int) * 16);
endianswap(&hdr.version, sizeof(int), 4);
if (strncmp(hdr.head, "CUBE", 4) != 0)
fatal(@"while reading map: header malformatted");
if (hdr.version > MAPVERSION)
fatal(@"this map requires a newer version of cube");
if (sfactor < SMALLEST_FACTOR || sfactor > LARGEST_FACTOR)
fatal(@"illegal map size");
if (hdr.version >= 4) {
gzread(f, &hdr.waterlevel, sizeof(int) * 16);
endianswap(&hdr.waterlevel, sizeof(int), 16);
} else {
hdr.waterlevel = -100000;
}
ents.setsize(0);
loopi(hdr.numents)
{
entity &e = ents.add();
gzread(f, &e, sizeof(persistent_entity));
endianswap(&e, sizeof(short), 4);
e.spawned = false;
if (e.type == LIGHT) {
if (!e.attr2)
e.attr2 = 255; // needed for MAPVERSION<=2
if (e.attr1 > 32)
e.attr1 = 32; // 12_03 and below
}
}
free(world);
setupworld(hdr.sfactor);
char texuse[256];
loopi(256) texuse[i] = 0;
sqr *t = NULL;
loopk(cubicsize)
{
sqr *s = &world[k];
int type = gzgetc(f);
switch (type) {
case 255: {
int n = gzgetc(f);
for (int i = 0; i < n; i++, k++)
memcpy(&world[k], t, sizeof(sqr));
k--;
break;
}
case 254: // only in MAPVERSION<=2
{
memcpy(s, t, sizeof(sqr));
s->r = s->g = s->b = gzgetc(f);
gzgetc(f);
break;
}
case SOLID: {
s->type = SOLID;
s->wtex = gzgetc(f);
s->vdelta = gzgetc(f);
if (hdr.version <= 2) {
gzgetc(f);
gzgetc(f);
}
s->ftex = DEFAULT_FLOOR;
s->ctex = DEFAULT_CEIL;
s->utex = s->wtex;
s->tag = 0;
s->floor = 0;
s->ceil = 16;
break;
}
default: {
if (type < 0 || type >= MAXTYPE) {
OFString *t = [OFString
stringWithFormat:@"%d @ %d", type, k];
fatal(@"while reading map: type out of "
@"range: ",
t);
}
s->type = type;
s->floor = gzgetc(f);
s->ceil = gzgetc(f);
if (s->floor >= s->ceil)
s->floor = s->ceil - 1; // for pre 12_13
s->wtex = gzgetc(f);
s->ftex = gzgetc(f);
s->ctex = gzgetc(f);
if (hdr.version <= 2) {
gzgetc(f);
gzgetc(f);
}
s->vdelta = gzgetc(f);
s->utex = (hdr.version >= 2) ? gzgetc(f) : s->wtex;
s->tag = (hdr.version >= 5) ? gzgetc(f) : 0;
s->type = type;
}
}
s->defer = 0;
t = s;
texuse[s->wtex] = 1;
if (!SOLID(s))
texuse[s->utex] = texuse[s->ftex] = texuse[s->ctex] = 1;
}
gzclose(f);
calclight();
settagareas();
int xs, ys;
loopi(256) if (texuse) lookuptexture(i, &xs, &ys);
conoutf(@"read map %@ (%d milliseconds)", cgzname,
SDL_GetTicks() - lastmillis);
conoutf(@"%s", hdr.maptitle);
startmap(mname);
loopl(256)
{
// can this be done smarter?
OFString *aliasname =
[OFString stringWithFormat:@"level_trigger_%d", l];
if (identexists(aliasname))
alias(aliasname, @"");
}
OFIRI *gameDataIRI = Cube.sharedInstance.gameDataIRI;
execfile([gameDataIRI
IRIByAppendingPathComponent:@"data/default_map_settings.cfg"]);
execfile([gameDataIRI IRIByAppendingPathComponent:pcfname]);
execfile([gameDataIRI IRIByAppendingPathComponent:mcfname]);
} }