Use one autorelease pool per frame
This way, nowhere else autorelease pools need to be managed. FossilOrigin-Name: 489124a92fd2a7e6d543b58ce50e454f2cb1647c81b4ba637d6c252404012ddd
This commit is contained in:
parent
a67b134eb2
commit
875c395ce1
22 changed files with 1262 additions and 1443 deletions
493
src/Cube.mm
493
src/Cube.mm
|
@ -21,262 +21,275 @@ VARP(minmillis, 0, 5, 1000);
|
|||
|
||||
- (void)applicationDidFinishLaunching:(OFNotification *)notification
|
||||
{
|
||||
bool dedicated, windowed;
|
||||
int par = 0, uprate = 0, maxcl = 4;
|
||||
OFString *__autoreleasing sdesc, *__autoreleasing ip;
|
||||
OFString *__autoreleasing master, *__autoreleasing passwd;
|
||||
@autoreleasepool {
|
||||
bool dedicated, windowed;
|
||||
int par = 0, uprate = 0, maxcl = 4;
|
||||
OFString *__autoreleasing sdesc, *__autoreleasing ip;
|
||||
OFString *__autoreleasing master, *__autoreleasing passwd;
|
||||
|
||||
processInitQueue();
|
||||
processInitQueue();
|
||||
|
||||
#define log(s) conoutf(@"init: %@", s)
|
||||
log(@"sdl");
|
||||
log(@"sdl");
|
||||
|
||||
const OFOptionsParserOption options[] = { { 'd', @"dedicated", 0,
|
||||
&dedicated, NULL },
|
||||
{ 't', @"window", 0, &windowed, NULL },
|
||||
{ 'w', @"width", 1, NULL, NULL },
|
||||
{ 'h', @"height", 1, NULL, NULL },
|
||||
{ 'u', @"upload-rate", 1, NULL, NULL },
|
||||
{ 'n', @"server-desc", 1, NULL, &sdesc },
|
||||
{ 'i', @"ip", 1, NULL, &ip },
|
||||
{ 'm', @"master", 1, NULL, &master },
|
||||
{ 'p', @"password", 1, NULL, &passwd },
|
||||
{ 'c', @"max-clients", 1, NULL, NULL },
|
||||
{ '\0', nil, 0, NULL, NULL } };
|
||||
OFOptionsParser *optionsParser =
|
||||
[OFOptionsParser parserWithOptions:options];
|
||||
OFUnichar option;
|
||||
while ((option = [optionsParser nextOption]) != '\0') {
|
||||
switch (option) {
|
||||
case 'w':
|
||||
_width = optionsParser.argument.intValue;
|
||||
break;
|
||||
case 'h':
|
||||
_height = optionsParser.argument.intValue;
|
||||
break;
|
||||
case 'u':
|
||||
uprate = optionsParser.argument.intValue;
|
||||
break;
|
||||
case 'c':
|
||||
maxcl = optionsParser.argument.intValue;
|
||||
break;
|
||||
case ':':
|
||||
case '=':
|
||||
case '?':
|
||||
conoutf(@"unknown commandline option");
|
||||
[OFApplication terminateWithStatus:1];
|
||||
const OFOptionsParserOption options[] = {
|
||||
{ 'd', @"dedicated", 0, &dedicated, NULL },
|
||||
{ 't', @"window", 0, &windowed, NULL },
|
||||
{ 'w', @"width", 1, NULL, NULL },
|
||||
{ 'h', @"height", 1, NULL, NULL },
|
||||
{ 'u', @"upload-rate", 1, NULL, NULL },
|
||||
{ 'n', @"server-desc", 1, NULL, &sdesc },
|
||||
{ 'i', @"ip", 1, NULL, &ip },
|
||||
{ 'm', @"master", 1, NULL, &master },
|
||||
{ 'p', @"password", 1, NULL, &passwd },
|
||||
{ 'c', @"max-clients", 1, NULL, NULL },
|
||||
{ '\0', nil, 0, NULL, NULL }
|
||||
};
|
||||
OFOptionsParser *optionsParser =
|
||||
[OFOptionsParser parserWithOptions:options];
|
||||
OFUnichar option;
|
||||
while ((option = [optionsParser nextOption]) != '\0') {
|
||||
switch (option) {
|
||||
case 'w':
|
||||
_width = optionsParser.argument.intValue;
|
||||
break;
|
||||
case 'h':
|
||||
_height = optionsParser.argument.intValue;
|
||||
break;
|
||||
case 'u':
|
||||
uprate = optionsParser.argument.intValue;
|
||||
break;
|
||||
case 'c':
|
||||
maxcl = optionsParser.argument.intValue;
|
||||
break;
|
||||
case ':':
|
||||
case '=':
|
||||
case '?':
|
||||
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];
|
||||
int ignore = 5;
|
||||
for (;;) {
|
||||
[OFRunLoop.mainRunLoop runUntilDate:past];
|
||||
@autoreleasepool {
|
||||
[OFRunLoop.mainRunLoop runUntilDate:past];
|
||||
|
||||
int millis = SDL_GetTicks() * gamespeed / 100;
|
||||
if (millis - lastmillis > 200)
|
||||
lastmillis = millis - 200;
|
||||
else if (millis - lastmillis < 1)
|
||||
lastmillis = millis - 1;
|
||||
if (millis - lastmillis < minmillis)
|
||||
SDL_Delay(minmillis - (millis - lastmillis));
|
||||
int millis = SDL_GetTicks() * gamespeed / 100;
|
||||
if (millis - lastmillis > 200)
|
||||
lastmillis = millis - 200;
|
||||
else if (millis - lastmillis < 1)
|
||||
lastmillis = millis - 1;
|
||||
if (millis - lastmillis < minmillis)
|
||||
SDL_Delay(minmillis - (millis - lastmillis));
|
||||
|
||||
cleardlights();
|
||||
updateworld(millis);
|
||||
cleardlights();
|
||||
updateworld(millis);
|
||||
|
||||
if (!demoplayback)
|
||||
serverslice((int)time(NULL), 0);
|
||||
if (!demoplayback)
|
||||
serverslice((int)time(NULL), 0);
|
||||
|
||||
static float fps = 30.0f;
|
||||
fps = (1000.0f / curtime + fps * 50) / 51;
|
||||
static float fps = 30.0f;
|
||||
fps = (1000.0f / curtime + fps * 50) / 51;
|
||||
|
||||
computeraytable(player1.o.x, player1.o.y);
|
||||
readdepth(_width, _height);
|
||||
SDL_GL_SwapWindow(_window);
|
||||
extern void updatevol();
|
||||
updatevol();
|
||||
computeraytable(player1.o.x, player1.o.y);
|
||||
readdepth(_width, _height);
|
||||
SDL_GL_SwapWindow(_window);
|
||||
extern void 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);
|
||||
player1.yaw -= 5;
|
||||
}
|
||||
|
||||
gl_drawframe(_width, _height, fps);
|
||||
|
||||
SDL_Event event;
|
||||
int lasttype = 0, lastbut = 0;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
[self quit];
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
if (_repeatsKeys || event.key.repeat == 0)
|
||||
keypress(event.key.keysym.sym,
|
||||
event.key.state == SDL_PRESSED);
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
@autoreleasepool {
|
||||
SDL_Event event;
|
||||
int lasttype = 0, lastbut = 0;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
[self quit];
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
if (_repeatsKeys ||
|
||||
event.key.repeat == 0)
|
||||
keypress(event.key.keysym.sym,
|
||||
event.key.state ==
|
||||
SDL_PRESSED);
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
input(@(event.text.text));
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
if (ignore) {
|
||||
ignore--;
|
||||
break;
|
||||
}
|
||||
mousemove(event.motion.xrel, event.motion.yrel);
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (lasttype == event.type &&
|
||||
lastbut == event.button.button)
|
||||
// why?? get event twice without it
|
||||
case SDL_MOUSEMOTION:
|
||||
if (ignore) {
|
||||
ignore--;
|
||||
break;
|
||||
}
|
||||
mousemove(event.motion.xrel,
|
||||
event.motion.yrel);
|
||||
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,
|
||||
event.button.state != 0);
|
||||
lasttype = event.type;
|
||||
lastbut = event.button.button;
|
||||
break;
|
||||
keypress(-event.button.button,
|
||||
event.button.state != 0);
|
||||
lasttype = event.type;
|
||||
lastbut = event.button.button;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[self quit];
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(OFNotification *)notification
|
||||
|
@ -323,16 +336,12 @@ VARP(minmillis, 0, 5, 1000);
|
|||
endianswap(dest, 3, _width);
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
OFString *path = [OFString
|
||||
stringWithFormat:
|
||||
@"screenshots/screenshot_%d.bmp",
|
||||
lastmillis];
|
||||
SDL_SaveBMP(temp,
|
||||
[_userDataIRI
|
||||
IRIByAppendingPathComponent:path]
|
||||
.fileSystemRepresentation.UTF8String);
|
||||
}
|
||||
OFString *path = [OFString
|
||||
stringWithFormat:@"screenshots/screenshot_%d.bmp",
|
||||
lastmillis];
|
||||
SDL_SaveBMP(temp,
|
||||
[_userDataIRI IRIByAppendingPathComponent:path]
|
||||
.fileSystemRepresentation.UTF8String);
|
||||
SDL_FreeSurface(temp);
|
||||
}
|
||||
|
||||
|
|
103
src/MD2.mm
103
src/MD2.mm
|
@ -54,60 +54,57 @@ snap(int sn, float f)
|
|||
|
||||
- (bool)loadWithIRI:(OFIRI *)IRI
|
||||
{
|
||||
@autoreleasepool {
|
||||
OFSeekableStream *stream;
|
||||
@try {
|
||||
stream = (OFSeekableStream *)[[OFIRIHandler
|
||||
handlerForIRI:IRI] openItemAtIRI:IRI mode:@"r"];
|
||||
} @catch (id e) {
|
||||
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;
|
||||
OFSeekableStream *stream;
|
||||
@try {
|
||||
stream = (OFSeekableStream *)[[OFIRIHandler handlerForIRI:IRI]
|
||||
openItemAtIRI:IRI
|
||||
mode:@"r"];
|
||||
} @catch (id e) {
|
||||
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;
|
||||
}
|
||||
|
||||
- (void)scaleWithFrame:(int)frame scale:(float)scale snap:(int)sn
|
||||
|
|
204
src/client.mm
204
src/client.mm
|
@ -63,28 +63,24 @@ throttle()
|
|||
void
|
||||
newname(OFString *name)
|
||||
{
|
||||
@autoreleasepool {
|
||||
c2sinit = false;
|
||||
c2sinit = false;
|
||||
|
||||
if (name.length > 16)
|
||||
name = [name substringToIndex:16];
|
||||
if (name.length > 16)
|
||||
name = [name substringToIndex:16];
|
||||
|
||||
player1.name = name;
|
||||
}
|
||||
player1.name = name;
|
||||
}
|
||||
COMMANDN(name, newname, ARG_1STR)
|
||||
|
||||
void
|
||||
newteam(OFString *name)
|
||||
{
|
||||
@autoreleasepool {
|
||||
c2sinit = false;
|
||||
c2sinit = false;
|
||||
|
||||
if (name.length > 5)
|
||||
name = [name substringToIndex:5];
|
||||
if (name.length > 5)
|
||||
name = [name substringToIndex:5];
|
||||
|
||||
player1.team = name;
|
||||
}
|
||||
player1.team = name;
|
||||
}
|
||||
COMMANDN(team, newteam, ARG_1STR)
|
||||
|
||||
|
@ -103,12 +99,9 @@ connects(OFString *servername)
|
|||
|
||||
conoutf(@"attempting to connect to %@", servername);
|
||||
ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT };
|
||||
@autoreleasepool {
|
||||
if (enet_address_set_host(&address, servername.UTF8String) <
|
||||
0) {
|
||||
conoutf(@"could not resolve server %@", servername);
|
||||
return;
|
||||
}
|
||||
if (enet_address_set_host(&address, servername.UTF8String) < 0) {
|
||||
conoutf(@"could not resolve server %@", servername);
|
||||
return;
|
||||
}
|
||||
|
||||
clienthost = enet_host_create(NULL, 1, rate, rate);
|
||||
|
@ -287,99 +280,94 @@ sendpackettoserv(void *packet)
|
|||
void
|
||||
c2sinfo(DynamicEntity *d)
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (clientnum < 0)
|
||||
return; // we haven't had a welcome message from the
|
||||
// server yet
|
||||
if (lastmillis - lastupdate < 40)
|
||||
return; // don't update faster than 25fps
|
||||
ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, 0);
|
||||
uchar *start = packet->data;
|
||||
uchar *p = start + 2;
|
||||
bool serveriteminitdone = false;
|
||||
if (toservermap.length > 0) // suggest server to change map
|
||||
{ // do this exclusively as map change may invalidate rest of
|
||||
// update
|
||||
packet->flags = ENET_PACKET_FLAG_RELIABLE;
|
||||
putint(p, SV_MAPCHANGE);
|
||||
sendstring(toservermap, p);
|
||||
toservermap = @"";
|
||||
putint(p, nextmode);
|
||||
} else {
|
||||
putint(p, SV_POS);
|
||||
putint(p, clientnum);
|
||||
// quantize coordinates to 1/16th of a cube, between 1
|
||||
// and 3 bytes
|
||||
putint(p, (int)(d.o.x * DMF));
|
||||
putint(p, (int)(d.o.y * DMF));
|
||||
putint(p, (int)(d.o.z * DMF));
|
||||
putint(p, (int)(d.yaw * DAF));
|
||||
putint(p, (int)(d.pitch * DAF));
|
||||
putint(p, (int)(d.roll * DAF));
|
||||
// quantize to 1/100, almost always 1 byte
|
||||
putint(p, (int)(d.vel.x * DVF));
|
||||
putint(p, (int)(d.vel.y * DVF));
|
||||
putint(p, (int)(d.vel.z * DVF));
|
||||
// pack rest in 1 byte: strafe:2, move:2, onfloor:1,
|
||||
// state:3
|
||||
putint(p,
|
||||
(d.strafe & 3) | ((d.move & 3) << 2) |
|
||||
(((int)d.onfloor) << 4) |
|
||||
((editmode ? CS_EDITING : d.state) << 5));
|
||||
if (clientnum < 0)
|
||||
return; // we haven't had a welcome message from the server yet
|
||||
if (lastmillis - lastupdate < 40)
|
||||
return; // don't update faster than 25fps
|
||||
ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, 0);
|
||||
uchar *start = packet->data;
|
||||
uchar *p = start + 2;
|
||||
bool serveriteminitdone = false;
|
||||
// suggest server to change map
|
||||
if (toservermap.length > 0) {
|
||||
// do this exclusively as map change may invalidate rest of
|
||||
// update
|
||||
packet->flags = ENET_PACKET_FLAG_RELIABLE;
|
||||
putint(p, SV_MAPCHANGE);
|
||||
sendstring(toservermap, p);
|
||||
toservermap = @"";
|
||||
putint(p, nextmode);
|
||||
} else {
|
||||
putint(p, SV_POS);
|
||||
putint(p, clientnum);
|
||||
// quantize coordinates to 1/16th of a cube, between 1 and 3
|
||||
// bytes
|
||||
putint(p, (int)(d.o.x * DMF));
|
||||
putint(p, (int)(d.o.y * DMF));
|
||||
putint(p, (int)(d.o.z * DMF));
|
||||
putint(p, (int)(d.yaw * DAF));
|
||||
putint(p, (int)(d.pitch * DAF));
|
||||
putint(p, (int)(d.roll * DAF));
|
||||
// quantize to 1/100, almost always 1 byte
|
||||
putint(p, (int)(d.vel.x * DVF));
|
||||
putint(p, (int)(d.vel.y * DVF));
|
||||
putint(p, (int)(d.vel.z * DVF));
|
||||
// pack rest in 1 byte: strafe:2, move:2, onfloor:1, state:3
|
||||
putint(p,
|
||||
(d.strafe & 3) | ((d.move & 3) << 2) |
|
||||
(((int)d.onfloor) << 4) |
|
||||
((editmode ? CS_EDITING : d.state) << 5));
|
||||
|
||||
if (senditemstoserver) {
|
||||
packet->flags = ENET_PACKET_FLAG_RELIABLE;
|
||||
putint(p, SV_ITEMLIST);
|
||||
if (!m_noitems)
|
||||
putitems(p);
|
||||
putint(p, -1);
|
||||
senditemstoserver = false;
|
||||
serveriteminitdone = true;
|
||||
}
|
||||
// player chat, not flood protected for now
|
||||
if (ctext.length > 0) {
|
||||
packet->flags = ENET_PACKET_FLAG_RELIABLE;
|
||||
putint(p, SV_TEXT);
|
||||
sendstring(ctext, p);
|
||||
ctext = @"";
|
||||
}
|
||||
// tell other clients who I am
|
||||
if (!c2sinit) {
|
||||
packet->flags = ENET_PACKET_FLAG_RELIABLE;
|
||||
c2sinit = true;
|
||||
putint(p, SV_INITC2S);
|
||||
sendstring(player1.name, p);
|
||||
sendstring(player1.team, p);
|
||||
putint(p, player1.lifesequence);
|
||||
}
|
||||
for (OFData *msg in messages) {
|
||||
// send messages collected during the previous
|
||||
// frames
|
||||
if (*(int *)[msg itemAtIndex:1])
|
||||
packet->flags =
|
||||
ENET_PACKET_FLAG_RELIABLE;
|
||||
loopi(*(int *)[msg itemAtIndex:0])
|
||||
putint(p, *(int *)[msg itemAtIndex:i + 2]);
|
||||
}
|
||||
[messages removeAllObjects];
|
||||
if (lastmillis - lastping > 250) {
|
||||
putint(p, SV_PING);
|
||||
putint(p, lastmillis);
|
||||
lastping = lastmillis;
|
||||
}
|
||||
if (senditemstoserver) {
|
||||
packet->flags = ENET_PACKET_FLAG_RELIABLE;
|
||||
putint(p, SV_ITEMLIST);
|
||||
if (!m_noitems)
|
||||
putitems(p);
|
||||
putint(p, -1);
|
||||
senditemstoserver = false;
|
||||
serveriteminitdone = true;
|
||||
}
|
||||
// player chat, not flood protected for now
|
||||
if (ctext.length > 0) {
|
||||
packet->flags = ENET_PACKET_FLAG_RELIABLE;
|
||||
putint(p, SV_TEXT);
|
||||
sendstring(ctext, p);
|
||||
ctext = @"";
|
||||
}
|
||||
// tell other clients who I am
|
||||
if (!c2sinit) {
|
||||
packet->flags = ENET_PACKET_FLAG_RELIABLE;
|
||||
c2sinit = true;
|
||||
putint(p, SV_INITC2S);
|
||||
sendstring(player1.name, p);
|
||||
sendstring(player1.team, p);
|
||||
putint(p, player1.lifesequence);
|
||||
}
|
||||
for (OFData *msg in messages) {
|
||||
// send messages collected during the previous frames
|
||||
if (*(int *)[msg itemAtIndex:1])
|
||||
packet->flags = ENET_PACKET_FLAG_RELIABLE;
|
||||
loopi(*(int *)[msg itemAtIndex:0])
|
||||
putint(p, *(int *)[msg itemAtIndex:i + 2]);
|
||||
}
|
||||
[messages removeAllObjects];
|
||||
if (lastmillis - lastping > 250) {
|
||||
putint(p, SV_PING);
|
||||
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
|
||||
|
|
|
@ -107,21 +107,19 @@ static OFMutableArray<OFString *> *scoreLines;
|
|||
void
|
||||
renderscore(DynamicEntity *d)
|
||||
{
|
||||
@autoreleasepool {
|
||||
OFString *lag = [OFString stringWithFormat:@"%d", d.plag];
|
||||
OFString *name = [OFString stringWithFormat:@"(%@)", d.name];
|
||||
OFString *line =
|
||||
[OFString stringWithFormat:@"%d\t%@\t%d\t%@\t%@", d.frags,
|
||||
(d.state == CS_LAGGED ? @"LAG" : lag), d.ping,
|
||||
d.team, (d.state == CS_DEAD ? name : d.name)];
|
||||
OFString *lag = [OFString stringWithFormat:@"%d", d.plag];
|
||||
OFString *name = [OFString stringWithFormat:@"(%@)", d.name];
|
||||
OFString *line =
|
||||
[OFString stringWithFormat:@"%d\t%@\t%d\t%@\t%@", d.frags,
|
||||
(d.state == CS_LAGGED ? @"LAG" : lag), d.ping, d.team,
|
||||
(d.state == CS_DEAD ? name : d.name)];
|
||||
|
||||
if (scoreLines == nil)
|
||||
scoreLines = [[OFMutableArray alloc] init];
|
||||
if (scoreLines == nil)
|
||||
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;
|
||||
|
@ -132,20 +130,18 @@ static size_t teamsUsed;
|
|||
void
|
||||
addteamscore(DynamicEntity *d)
|
||||
{
|
||||
@autoreleasepool {
|
||||
for (size_t i = 0; i < teamsUsed; i++) {
|
||||
if ([teamName[i] isEqual:d.team]) {
|
||||
teamScore[i] += d.frags;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (teamsUsed == maxTeams)
|
||||
for (size_t i = 0; i < teamsUsed; i++) {
|
||||
if ([teamName[i] isEqual:d.team]) {
|
||||
teamScore[i] += d.frags;
|
||||
return;
|
||||
|
||||
teamName[teamsUsed] = d.team;
|
||||
teamScore[teamsUsed++] = d.frags;
|
||||
}
|
||||
}
|
||||
|
||||
if (teamsUsed == maxTeams)
|
||||
return;
|
||||
|
||||
teamName[teamsUsed] = d.team;
|
||||
teamScore[teamsUsed++] = d.frags;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -172,9 +168,7 @@ renderscores()
|
|||
[teamScores appendFormat:@"[ %@: %d ]", teamName[j],
|
||||
teamScore[j]];
|
||||
menumanual(0, scoreLines.count, @"");
|
||||
@autoreleasepool {
|
||||
menumanual(0, scoreLines.count + 1, teamScores);
|
||||
}
|
||||
menumanual(0, scoreLines.count + 1, teamScores);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,38 +177,36 @@ renderscores()
|
|||
void
|
||||
sendmap(OFString *mapname)
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (mapname.length > 0)
|
||||
save_world(mapname);
|
||||
changemap(mapname);
|
||||
mapname = getclientmap();
|
||||
OFData *mapdata = readmap(mapname);
|
||||
if (mapdata == nil)
|
||||
return;
|
||||
ENetPacket *packet = enet_packet_create(
|
||||
NULL, MAXTRANS + mapdata.count, ENET_PACKET_FLAG_RELIABLE);
|
||||
uchar *start = packet->data;
|
||||
uchar *p = start + 2;
|
||||
putint(p, SV_SENDMAP);
|
||||
sendstring(mapname, p);
|
||||
putint(p, mapdata.count);
|
||||
if (65535 - (p - start) < mapdata.count) {
|
||||
conoutf(@"map %@ is too large to send", mapname);
|
||||
enet_packet_destroy(packet);
|
||||
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);
|
||||
if (mapname.length > 0)
|
||||
save_world(mapname);
|
||||
changemap(mapname);
|
||||
mapname = getclientmap();
|
||||
OFData *mapdata = readmap(mapname);
|
||||
if (mapdata == nil)
|
||||
return;
|
||||
ENetPacket *packet = enet_packet_create(
|
||||
NULL, MAXTRANS + mapdata.count, ENET_PACKET_FLAG_RELIABLE);
|
||||
uchar *start = packet->data;
|
||||
uchar *p = start + 2;
|
||||
putint(p, SV_SENDMAP);
|
||||
sendstring(mapname, p);
|
||||
putint(p, mapdata.count);
|
||||
if (65535 - (p - start) < mapdata.count) {
|
||||
conoutf(@"map %@ is too large to send", mapname);
|
||||
enet_packet_destroy(packet);
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -95,15 +95,12 @@ localservertoclient(uchar *buf, int len)
|
|||
// map
|
||||
toservermap = getclientmap();
|
||||
sgetstr();
|
||||
@autoreleasepool {
|
||||
if (text[0] &&
|
||||
strcmp(text, clientpassword.UTF8String)) {
|
||||
conoutf(@"you need to set the correct "
|
||||
@"password "
|
||||
@"to join this server!");
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
if (text[0] &&
|
||||
strcmp(text, clientpassword.UTF8String)) {
|
||||
conoutf(@"you need to set the correct password "
|
||||
@"to join this server!");
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
if (getint(p) == 1)
|
||||
conoutf(@"server is FULL, disconnecting..");
|
||||
|
@ -150,9 +147,7 @@ localservertoclient(uchar *buf, int len)
|
|||
|
||||
case SV_MAPCHANGE:
|
||||
sgetstr();
|
||||
@autoreleasepool {
|
||||
changemapserv(@(text), getint(p));
|
||||
}
|
||||
changemapserv(@(text), getint(p));
|
||||
mapchanged = true;
|
||||
break;
|
||||
|
||||
|
@ -378,12 +373,10 @@ localservertoclient(uchar *buf, int len)
|
|||
conoutf(@"received map \"%s\" from server, reloading..",
|
||||
text);
|
||||
int mapsize = getint(p);
|
||||
@autoreleasepool {
|
||||
OFString *string = @(text);
|
||||
writemap(string, mapsize, p);
|
||||
p += mapsize;
|
||||
changemapserv(string, gamemode);
|
||||
}
|
||||
OFString *string = @(text);
|
||||
writemap(string, mapsize, p);
|
||||
p += mapsize;
|
||||
changemapserv(string, gamemode);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
253
src/commands.mm
253
src/commands.mm
|
@ -123,16 +123,13 @@ parseexp(char *&p, int right)
|
|||
}
|
||||
char *s = strndup(word, p - word - 1);
|
||||
if (left == '(') {
|
||||
@autoreleasepool {
|
||||
OFString *t;
|
||||
@try {
|
||||
t = [OFString
|
||||
stringWithFormat:@"%d", execute(@(s))];
|
||||
} @finally {
|
||||
free(s);
|
||||
}
|
||||
s = strdup(t.UTF8String);
|
||||
OFString *t;
|
||||
@try {
|
||||
t = [OFString stringWithFormat:@"%d", execute(@(s))];
|
||||
} @finally {
|
||||
free(s);
|
||||
}
|
||||
s = strdup(t.UTF8String);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
@ -164,19 +161,16 @@ parseword(char *&p)
|
|||
return strndup(word, p - word);
|
||||
}
|
||||
|
||||
// find value of ident referenced with $ in exp
|
||||
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]) {
|
||||
return [OFString
|
||||
stringWithFormat:@"%d", *[identifier storage]];
|
||||
} else if ([identifier isKindOfClass:Alias.class])
|
||||
return [identifier action];
|
||||
}
|
||||
if ([identifier isKindOfClass:Variable.class]) {
|
||||
return [OFString stringWithFormat:@"%d", *[identifier storage]];
|
||||
} else if ([identifier isKindOfClass:Alias.class])
|
||||
return [identifier action];
|
||||
|
||||
conoutf(@"unknown alias lookup: %@", [n substringFromIndex:1]);
|
||||
return n;
|
||||
|
@ -234,57 +228,55 @@ executeIdentifier(__kindof Identifier *identifier,
|
|||
int
|
||||
execute(OFString *string, bool isDown)
|
||||
{
|
||||
@autoreleasepool {
|
||||
std::unique_ptr<char> copy(strdup(string.UTF8String));
|
||||
char *p = copy.get();
|
||||
const int MAXWORDS = 25; // limit, remove
|
||||
OFString *w[MAXWORDS];
|
||||
int val = 0;
|
||||
for (bool cont = true; cont;) {
|
||||
// for each ; seperated statement
|
||||
int numargs = MAXWORDS;
|
||||
loopi(MAXWORDS)
|
||||
{
|
||||
// collect all argument values
|
||||
w[i] = @"";
|
||||
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)
|
||||
std::unique_ptr<char> copy(strdup(string.UTF8String));
|
||||
char *p = copy.get();
|
||||
const int MAXWORDS = 25; // limit, remove
|
||||
OFString *w[MAXWORDS];
|
||||
int val = 0;
|
||||
for (bool cont = true; cont;) {
|
||||
// for each ; seperated statement
|
||||
int numargs = MAXWORDS;
|
||||
loopi(MAXWORDS)
|
||||
{
|
||||
// collect all argument values
|
||||
w[i] = @"";
|
||||
if (i > numargs)
|
||||
continue;
|
||||
|
||||
val = executeIdentifier(identifiers[c],
|
||||
[OFArray arrayWithObjects:w count:numargs], isDown);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -300,64 +292,57 @@ resetcomplete()
|
|||
void
|
||||
complete(OFMutableString *s)
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (![s hasPrefix:@"/"])
|
||||
[s insertString:@"/" atIndex:0];
|
||||
if (![s hasPrefix:@"/"])
|
||||
[s insertString:@"/" atIndex:0];
|
||||
|
||||
if (s.length == 1)
|
||||
return;
|
||||
if (s.length == 1)
|
||||
return;
|
||||
|
||||
if (!completesize) {
|
||||
completesize = s.length - 1;
|
||||
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;
|
||||
if (!completesize) {
|
||||
completesize = s.length - 1;
|
||||
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
|
||||
execfile(OFIRI *cfgfile)
|
||||
{
|
||||
@autoreleasepool {
|
||||
OFString *command;
|
||||
@try {
|
||||
command = [OFString stringWithContentsOfIRI:cfgfile];
|
||||
} @catch (OFOpenItemFailedException *e) {
|
||||
return false;
|
||||
} @catch (OFReadFailedException *e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
execute(command);
|
||||
return true;
|
||||
OFString *command;
|
||||
@try {
|
||||
command = [OFString stringWithContentsOfIRI:cfgfile];
|
||||
} @catch (OFOpenItemFailedException *e) {
|
||||
return false;
|
||||
} @catch (OFReadFailedException *e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
execute(command);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
exec(OFString *cfgfile)
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (!execfile([Cube.sharedInstance.userDataIRI
|
||||
IRIByAppendingPathComponent:cfgfile]) &&
|
||||
!execfile([Cube.sharedInstance.gameDataIRI
|
||||
IRIByAppendingPathComponent:cfgfile]))
|
||||
conoutf(@"could not read \"%@\"", cfgfile);
|
||||
}
|
||||
if (!execfile([Cube.sharedInstance.userDataIRI
|
||||
IRIByAppendingPathComponent:cfgfile]) &&
|
||||
!execfile([Cube.sharedInstance.gameDataIRI
|
||||
IRIByAppendingPathComponent:cfgfile]))
|
||||
conoutf(@"could not read \"%@\"", cfgfile);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -418,9 +403,7 @@ COMMAND(writecfg, ARG_NONE)
|
|||
void
|
||||
intset(OFString *name, int v)
|
||||
{
|
||||
@autoreleasepool {
|
||||
alias(name, [OFString stringWithFormat:@"%d", v]);
|
||||
}
|
||||
alias(name, [OFString stringWithFormat:@"%d", v]);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -432,14 +415,12 @@ ifthen(OFString *cond, OFString *thenp, OFString *elsep)
|
|||
void
|
||||
loopa(OFString *times, OFString *body)
|
||||
{
|
||||
@autoreleasepool {
|
||||
int t = times.cube_intValue;
|
||||
int t = times.cube_intValue;
|
||||
|
||||
loopi(t)
|
||||
{
|
||||
intset(@"i", i);
|
||||
execute(body);
|
||||
}
|
||||
loopi(t)
|
||||
{
|
||||
intset(@"i", i);
|
||||
execute(body);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,32 +453,28 @@ concatword(OFString *s)
|
|||
int
|
||||
listlen(OFString *a_)
|
||||
{
|
||||
@autoreleasepool {
|
||||
const char *a = a_.UTF8String;
|
||||
const char *a = a_.UTF8String;
|
||||
|
||||
if (!*a)
|
||||
return 0;
|
||||
if (!*a)
|
||||
return 0;
|
||||
|
||||
int n = 0;
|
||||
while (*a)
|
||||
if (*a++ == ' ')
|
||||
n++;
|
||||
int n = 0;
|
||||
while (*a)
|
||||
if (*a++ == ' ')
|
||||
n++;
|
||||
|
||||
return n + 1;
|
||||
}
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
void
|
||||
at(OFString *s_, OFString *pos)
|
||||
{
|
||||
@autoreleasepool {
|
||||
int n = pos.cube_intValue;
|
||||
std::unique_ptr<char> copy(strdup(s_.UTF8String));
|
||||
char *s = copy.get();
|
||||
loopi(n) s += strspn(s += strcspn(s, " \0"), " ");
|
||||
s[strcspn(s, " \0")] = 0;
|
||||
concat(@(s));
|
||||
}
|
||||
int n = pos.cube_intValue;
|
||||
std::unique_ptr<char> copy(strdup(s_.UTF8String));
|
||||
char *s = copy.get();
|
||||
loopi(n) s += strspn(s += strcspn(s, " \0"), " ");
|
||||
s[strcspn(s, " \0")] = 0;
|
||||
concat(@(s));
|
||||
}
|
||||
|
||||
COMMANDN(loop, loopa, ARG_2STR)
|
||||
|
|
|
@ -83,22 +83,20 @@ conline(OFString *sf, bool highlight) // add a line to the console buffer
|
|||
void
|
||||
conoutf(OFConstantString *format, ...)
|
||||
{
|
||||
@autoreleasepool {
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
|
||||
OFString *string = [[OFString alloc] initWithFormat:format
|
||||
arguments:arguments];
|
||||
OFString *string = [[OFString alloc] initWithFormat:format
|
||||
arguments:arguments];
|
||||
|
||||
va_end(arguments);
|
||||
va_end(arguments);
|
||||
|
||||
int n = 0;
|
||||
while (string.length > WORDWRAP) {
|
||||
conline([string substringToIndex:WORDWRAP], n++ != 0);
|
||||
string = [string substringFromIndex:WORDWRAP];
|
||||
}
|
||||
conline(string, n != 0);
|
||||
int n = 0;
|
||||
while (string.length > WORDWRAP) {
|
||||
conline([string substringToIndex:WORDWRAP], n++ != 0);
|
||||
string = [string substringFromIndex:WORDWRAP];
|
||||
}
|
||||
conline(string, n != 0);
|
||||
}
|
||||
|
||||
// render buffer taking into account time & scrolling
|
||||
|
@ -181,19 +179,15 @@ COMMAND(saycommand, ARG_VARI)
|
|||
void
|
||||
mapmsg(OFString *s)
|
||||
{
|
||||
@autoreleasepool {
|
||||
memset(hdr.maptitle, '\0', sizeof(hdr.maptitle));
|
||||
strncpy(hdr.maptitle, s.UTF8String, 127);
|
||||
}
|
||||
memset(hdr.maptitle, '\0', sizeof(hdr.maptitle));
|
||||
strncpy(hdr.maptitle, s.UTF8String, 127);
|
||||
}
|
||||
COMMAND(mapmsg, ARG_1STR)
|
||||
|
||||
void
|
||||
pasteconsole()
|
||||
{
|
||||
@autoreleasepool {
|
||||
[commandbuf appendString:@(SDL_GetClipboardText())];
|
||||
}
|
||||
[commandbuf appendString:@(SDL_GetClipboardText())];
|
||||
}
|
||||
|
||||
static OFMutableArray<OFString *> *vhistory;
|
||||
|
@ -262,21 +256,17 @@ keypress(int code, bool isDown)
|
|||
} else {
|
||||
if (code == SDLK_RETURN) {
|
||||
if (commandbuf.length > 0) {
|
||||
@autoreleasepool {
|
||||
if (vhistory == nil)
|
||||
vhistory =
|
||||
[[OFMutableArray
|
||||
alloc] init];
|
||||
if (vhistory == nil)
|
||||
vhistory =
|
||||
[[OFMutableArray alloc]
|
||||
init];
|
||||
|
||||
if (vhistory.count == 0 ||
|
||||
![vhistory.lastObject
|
||||
isEqual:commandbuf]) {
|
||||
// cap this?
|
||||
[vhistory
|
||||
addObject:
|
||||
[commandbuf
|
||||
copy]];
|
||||
}
|
||||
if (vhistory.count == 0 ||
|
||||
![vhistory.lastObject
|
||||
isEqual:commandbuf]) {
|
||||
// cap this?
|
||||
[vhistory addObject:[commandbuf
|
||||
copy]];
|
||||
}
|
||||
histpos = vhistory.count;
|
||||
if ([commandbuf hasPrefix:@"/"])
|
||||
|
|
|
@ -604,11 +604,9 @@ void
|
|||
newent(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4)
|
||||
{
|
||||
EDITSEL;
|
||||
@autoreleasepool {
|
||||
newentity(sel.x, sel.y, (int)player1.o.z, what,
|
||||
[a1 cube_intValueWithBase:0], [a2 cube_intValueWithBase:0],
|
||||
[a3 cube_intValueWithBase:0], [a4 cube_intValueWithBase:0]);
|
||||
}
|
||||
newentity(sel.x, sel.y, (int)player1.o.z, what,
|
||||
[a1 cube_intValueWithBase:0], [a2 cube_intValueWithBase:0],
|
||||
[a3 cube_intValueWithBase:0], [a4 cube_intValueWithBase:0]);
|
||||
}
|
||||
|
||||
COMMANDN(select, selectpos, ARG_4INT)
|
||||
|
|
|
@ -42,15 +42,10 @@ renderentities()
|
|||
MapModelInfo *mmi = getmminfo(e.attr2);
|
||||
if (mmi == nil)
|
||||
continue;
|
||||
@autoreleasepool {
|
||||
rendermodel(mmi.name, 0, 1, e.attr4,
|
||||
(float)mmi.rad, e.x,
|
||||
(float)S(e.x, e.y)->floor + mmi.zoff +
|
||||
e.attr3,
|
||||
e.y,
|
||||
(float)((e.attr1 + 7) - (e.attr1 + 7) % 15),
|
||||
0, false, 1.0f, 10.0f, mmi.snap);
|
||||
}
|
||||
rendermodel(mmi.name, 0, 1, e.attr4, (float)mmi.rad,
|
||||
e.x, (float)S(e.x, e.y)->floor + mmi.zoff + e.attr3,
|
||||
e.y, (float)((e.attr1 + 7) - (e.attr1 + 7) % 15), 0,
|
||||
false, 1.0f, 10.0f, mmi.snap);
|
||||
} else {
|
||||
if (OUTBORD(e.x, e.y))
|
||||
continue;
|
||||
|
|
96
src/menus.mm
96
src/menus.mm
|
@ -43,53 +43,50 @@ void refreshservers();
|
|||
bool
|
||||
rendermenu()
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (vmenu < 0) {
|
||||
[menuStack removeAllObjects];
|
||||
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 < 0) {
|
||||
[menuStack removeAllObjects];
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -154,11 +151,8 @@ menukey(int code, bool isdown)
|
|||
} else {
|
||||
if (code == SDLK_RETURN || code == -2) {
|
||||
OFString *action = menus[vmenu].items[menusel].action;
|
||||
if (vmenu == 1) {
|
||||
@autoreleasepool {
|
||||
connects(getservername(menusel));
|
||||
}
|
||||
}
|
||||
if (vmenu == 1)
|
||||
connects(getservername(menusel));
|
||||
|
||||
if (menuStack == nil)
|
||||
menuStack = [[OFMutableArray alloc] init];
|
||||
|
|
|
@ -203,34 +203,31 @@ renderents() // show sparkly thingies for map entities in edit mode
|
|||
void
|
||||
loadsky(OFString *basename)
|
||||
{
|
||||
@autoreleasepool {
|
||||
static OFString *lastsky = @"";
|
||||
static OFString *lastsky = @"";
|
||||
|
||||
basename = [basename stringByReplacingOccurrencesOfString:@"\\"
|
||||
withString:@"/"];
|
||||
basename = [basename stringByReplacingOccurrencesOfString:@"\\"
|
||||
withString:@"/"];
|
||||
|
||||
if ([lastsky isEqual:basename])
|
||||
return;
|
||||
if ([lastsky isEqual:basename])
|
||||
return;
|
||||
|
||||
static const OFString *side[] = { @"ft", @"bk", @"lf", @"rt",
|
||||
@"dn", @"up" };
|
||||
int texnum = 14;
|
||||
loopi(6)
|
||||
{
|
||||
OFString *path =
|
||||
[OFString stringWithFormat:@"packages/%@_%@.jpg",
|
||||
basename, side[i]];
|
||||
static const OFString *side[] = { @"ft", @"bk", @"lf", @"rt", @"dn",
|
||||
@"up" };
|
||||
int texnum = 14;
|
||||
loopi(6)
|
||||
{
|
||||
OFString *path = [OFString
|
||||
stringWithFormat:@"packages/%@_%@.jpg", basename, side[i]];
|
||||
|
||||
int xs, ys;
|
||||
if (!installtex(texnum + i,
|
||||
[Cube.sharedInstance.gameDataIRI
|
||||
IRIByAppendingPathComponent:path],
|
||||
&xs, &ys, true))
|
||||
conoutf(@"could not load sky textures");
|
||||
}
|
||||
|
||||
lastsky = basename;
|
||||
int xs, ys;
|
||||
if (!installtex(texnum + i,
|
||||
[Cube.sharedInstance.gameDataIRI
|
||||
IRIByAppendingPathComponent:path],
|
||||
&xs, &ys, true))
|
||||
conoutf(@"could not load sky textures");
|
||||
}
|
||||
|
||||
lastsky = basename;
|
||||
}
|
||||
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);
|
||||
|
||||
@autoreleasepool {
|
||||
OFString *command = getcurcommand();
|
||||
OFString *player = playerincrosshair();
|
||||
OFString *command = getcurcommand();
|
||||
OFString *player = playerincrosshair();
|
||||
|
||||
if (command)
|
||||
draw_textf(@"> %@_", 20, 1570, 2, command);
|
||||
else if (closeent.length > 0)
|
||||
draw_text(closeent, 20, 1570, 2);
|
||||
else if (player != nil)
|
||||
draw_text(player, 20, 1570, 2);
|
||||
}
|
||||
if (command)
|
||||
draw_textf(@"> %@_", 20, 1570, 2, command);
|
||||
else if (closeent.length > 0)
|
||||
draw_text(closeent, 20, 1570, 2);
|
||||
else if (player != nil)
|
||||
draw_text(player, 20, 1570, 2);
|
||||
|
||||
renderscores();
|
||||
if (!rendermenu()) {
|
||||
|
|
166
src/rendergl.mm
166
src/rendergl.mm
|
@ -78,40 +78,37 @@ cleangl()
|
|||
bool
|
||||
installtex(int tnum, OFIRI *IRI, int *xs, int *ys, bool clamp)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_Surface *s =
|
||||
IMG_Load(IRI.fileSystemRepresentation.UTF8String);
|
||||
if (s == NULL) {
|
||||
conoutf(@"couldn't load texture %@", IRI.string);
|
||||
SDL_Surface *s = IMG_Load(IRI.fileSystemRepresentation.UTF8String);
|
||||
if (s == NULL) {
|
||||
conoutf(@"couldn't load texture %@", IRI.string);
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (s->format->BitsPerPixel != 24) {
|
||||
SDL_PixelFormat *format =
|
||||
SDL_AllocFormat(SDL_PIXELFORMAT_RGB24);
|
||||
if (format == NULL) {
|
||||
conoutf(
|
||||
@"texture cannot be converted to 24bpp: %@",
|
||||
@try {
|
||||
SDL_Surface *converted =
|
||||
SDL_ConvertSurface(s, format, 0);
|
||||
if (converted == NULL) {
|
||||
conoutf(@"texture cannot be converted "
|
||||
@"to 24bpp: %@",
|
||||
IRI.string);
|
||||
return false;
|
||||
}
|
||||
|
||||
@try {
|
||||
SDL_Surface *converted =
|
||||
SDL_ConvertSurface(s, format, 0);
|
||||
if (converted == NULL) {
|
||||
conoutf(@"texture cannot be converted "
|
||||
@"to 24bpp: %@",
|
||||
IRI.string);
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_FreeSurface(s);
|
||||
s = converted;
|
||||
} @finally {
|
||||
SDL_FreeFormat(format);
|
||||
}
|
||||
SDL_FreeSurface(s);
|
||||
s = converted;
|
||||
} @finally {
|
||||
SDL_FreeFormat(format);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
loopi(s->w * s->h * 3)
|
||||
|
@ -120,46 +117,44 @@ installtex(int tnum, OFIRI *IRI, int *xs, int *ys, bool clamp)
|
|||
*p = 255 - *p;
|
||||
}
|
||||
#endif
|
||||
glBindTexture(GL_TEXTURE_2D, tnum);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
|
||||
clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
|
||||
clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
glTexParameteri(
|
||||
GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_LINEAR); // NEAREST);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glBindTexture(GL_TEXTURE_2D, tnum);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
|
||||
clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
|
||||
clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_LINEAR); // NEAREST);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
*xs = s->w;
|
||||
*ys = s->h;
|
||||
while (*xs > glmaxtexsize || *ys > glmaxtexsize) {
|
||||
*xs /= 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;
|
||||
*xs = s->w;
|
||||
*ys = s->h;
|
||||
while (*xs > glmaxtexsize || *ys > glmaxtexsize) {
|
||||
*xs /= 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;
|
||||
}
|
||||
|
||||
// management of texture slots
|
||||
|
@ -197,17 +192,14 @@ COMMAND(texturereset, ARG_NONE)
|
|||
void
|
||||
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)
|
||||
return;
|
||||
if (num < 0 || num >= 256 || frame < 0 || frame >= MAXFRAMES)
|
||||
return;
|
||||
|
||||
mapping[num][frame] = 1;
|
||||
mapname[num][frame] =
|
||||
[name stringByReplacingOccurrencesOfString:@"\\"
|
||||
withString:@"/"];
|
||||
}
|
||||
mapping[num][frame] = 1;
|
||||
mapname[num][frame] = [name stringByReplacingOccurrencesOfString:@"\\"
|
||||
withString:@"/"];
|
||||
}
|
||||
COMMAND(texture, ARG_2STR)
|
||||
|
||||
|
@ -243,22 +235,20 @@ lookuptexture(int tex, int *xs, int *ys)
|
|||
int tnum = curtex + FIRSTTEX;
|
||||
texname[curtex] = mapname[tex][frame];
|
||||
|
||||
@autoreleasepool {
|
||||
OFString *path =
|
||||
[OFString stringWithFormat:@"packages/%@", texname[curtex]];
|
||||
OFString *path =
|
||||
[OFString stringWithFormat:@"packages/%@", texname[curtex]];
|
||||
|
||||
if (installtex(tnum,
|
||||
[Cube.sharedInstance.gameDataIRI
|
||||
IRIByAppendingPathComponent:path],
|
||||
xs, ys, false)) {
|
||||
mapping[tex][frame] = tnum;
|
||||
texx[curtex] = *xs;
|
||||
texy[curtex] = *ys;
|
||||
curtex++;
|
||||
return tnum;
|
||||
} else {
|
||||
return mapping[tex][frame] = FIRSTTEX; // temp fix
|
||||
}
|
||||
if (installtex(tnum,
|
||||
[Cube.sharedInstance.gameDataIRI
|
||||
IRIByAppendingPathComponent:path],
|
||||
xs, ys, false)) {
|
||||
mapping[tex][frame] = tnum;
|
||||
texx[curtex] = *xs;
|
||||
texy[curtex] = *ys;
|
||||
curtex++;
|
||||
return tnum;
|
||||
} else {
|
||||
return mapping[tex][frame] = FIRSTTEX; // temp fix
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,52 +16,42 @@ void
|
|||
delayedload(MD2 *m)
|
||||
{
|
||||
if (!m.loaded) {
|
||||
@autoreleasepool {
|
||||
OFString *path = [OFString
|
||||
stringWithFormat:@"packages/models/%@", m.loadname];
|
||||
OFIRI *baseIRI = [Cube.sharedInstance.gameDataIRI
|
||||
IRIByAppendingPathComponent:path];
|
||||
OFString *path = [OFString
|
||||
stringWithFormat:@"packages/models/%@", m.loadname];
|
||||
OFIRI *baseIRI = [Cube.sharedInstance.gameDataIRI
|
||||
IRIByAppendingPathComponent:path];
|
||||
|
||||
OFIRI *IRI1 =
|
||||
[baseIRI IRIByAppendingPathComponent:@"tris.md2"];
|
||||
if (![m loadWithIRI:IRI1])
|
||||
fatal(@"loadmodel: ", IRI1.string);
|
||||
OFIRI *IRI1 = [baseIRI IRIByAppendingPathComponent:@"tris.md2"];
|
||||
if (![m loadWithIRI:IRI1])
|
||||
fatal(@"loadmodel: ", IRI1.string);
|
||||
|
||||
OFIRI *IRI2 =
|
||||
[baseIRI IRIByAppendingPathComponent:@"skin.jpg"];
|
||||
int xs, ys;
|
||||
installtex(FIRSTMDL + m.mdlnum, IRI2, &xs, &ys, false);
|
||||
m.loaded = true;
|
||||
}
|
||||
OFIRI *IRI2 = [baseIRI IRIByAppendingPathComponent:@"skin.jpg"];
|
||||
int xs, ys;
|
||||
installtex(FIRSTMDL + m.mdlnum, IRI2, &xs, &ys, false);
|
||||
m.loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
MD2 *
|
||||
loadmodel(OFString *name)
|
||||
{
|
||||
@autoreleasepool {
|
||||
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;
|
||||
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;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -102,114 +102,106 @@ short char_coords[96][4] = {
|
|||
int
|
||||
text_width(OFString *string)
|
||||
{
|
||||
@autoreleasepool {
|
||||
const char *str = string.UTF8String;
|
||||
size_t len = string.UTF8StringLength;
|
||||
const char *str = string.UTF8String;
|
||||
size_t len = string.UTF8StringLength;
|
||||
|
||||
int x = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
int c = str[i];
|
||||
if (c == '\t') {
|
||||
x = (x + PIXELTAB) / PIXELTAB * PIXELTAB;
|
||||
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;
|
||||
int x = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
int c = str[i];
|
||||
if (c == '\t') {
|
||||
x = (x + PIXELTAB) / PIXELTAB * PIXELTAB;
|
||||
continue;
|
||||
}
|
||||
|
||||
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
|
||||
draw_textf(OFConstantString *format, int left, int top, int gl_num, ...)
|
||||
{
|
||||
@autoreleasepool {
|
||||
va_list arguments;
|
||||
va_start(arguments, gl_num);
|
||||
OFString *str = [[OFString alloc] initWithFormat:format
|
||||
arguments:arguments];
|
||||
va_end(arguments);
|
||||
draw_text(str, left, top, gl_num);
|
||||
}
|
||||
va_list arguments;
|
||||
va_start(arguments, gl_num);
|
||||
OFString *str = [[OFString alloc] initWithFormat:format
|
||||
arguments:arguments];
|
||||
va_end(arguments);
|
||||
draw_text(str, left, top, gl_num);
|
||||
}
|
||||
|
||||
void
|
||||
draw_text(OFString *string, int left, int top, int gl_num)
|
||||
{
|
||||
@autoreleasepool {
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
glBindTexture(GL_TEXTURE_2D, gl_num);
|
||||
glColor3ub(255, 255, 255);
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
glBindTexture(GL_TEXTURE_2D, gl_num);
|
||||
glColor3ub(255, 255, 255);
|
||||
|
||||
int x = left;
|
||||
int y = top;
|
||||
int x = left;
|
||||
int y = top;
|
||||
|
||||
int i;
|
||||
float in_left, in_top, in_right, in_bottom;
|
||||
int in_width, in_height;
|
||||
int i;
|
||||
float in_left, in_top, in_right, in_bottom;
|
||||
int in_width, in_height;
|
||||
|
||||
const char *str = string.UTF8String;
|
||||
size_t len = string.UTF8StringLength;
|
||||
for (i = 0; i < len; i++) {
|
||||
int c = str[i];
|
||||
const char *str = string.UTF8String;
|
||||
size_t len = string.UTF8StringLength;
|
||||
for (i = 0; i < len; i++) {
|
||||
int c = str[i];
|
||||
|
||||
if (c == '\t') {
|
||||
x = (x - left + PIXELTAB) / PIXELTAB *
|
||||
PIXELTAB +
|
||||
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 == '\t') {
|
||||
x = (x - left + PIXELTAB) / PIXELTAB * PIXELTAB + 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -91,40 +91,38 @@ stopifrecording()
|
|||
void
|
||||
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);
|
||||
OFData *data = [player1 dataBySerializing];
|
||||
gzputi(data.count);
|
||||
char map[_MAXDEFSTR] = { 0 };
|
||||
memcpy(map, getclientmap().UTF8String,
|
||||
min(getclientmap().UTF8StringLength, _MAXDEFSTR - 1));
|
||||
gzwrite(f, map, _MAXDEFSTR);
|
||||
gzputi(gamemode);
|
||||
gzputi(ents.length());
|
||||
loopv(ents) gzputc(f, ents[i].spawned);
|
||||
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);
|
||||
OFData *data = [player1 dataBySerializing];
|
||||
gzputi(data.count);
|
||||
char map[_MAXDEFSTR] = { 0 };
|
||||
memcpy(map, getclientmap().UTF8String,
|
||||
min(getclientmap().UTF8StringLength, _MAXDEFSTR - 1));
|
||||
gzwrite(f, map, _MAXDEFSTR);
|
||||
gzputi(gamemode);
|
||||
gzputi(ents.length());
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
OFString *path =
|
||||
[OFString stringWithFormat:@"savegames/%@.csgz", name];
|
||||
OFIRI *IRI = [Cube.sharedInstance.userDataIRI
|
||||
IRIByAppendingPathComponent:path];
|
||||
savestate(IRI);
|
||||
stop();
|
||||
conoutf(@"wrote %@", IRI.string);
|
||||
}
|
||||
OFString *path = [OFString stringWithFormat:@"savegames/%@.csgz", name];
|
||||
OFIRI *IRI =
|
||||
[Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:path];
|
||||
savestate(IRI);
|
||||
stop();
|
||||
conoutf(@"wrote %@", IRI.string);
|
||||
}
|
||||
COMMAND(savegame, ARG_1STR)
|
||||
|
||||
void
|
||||
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;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
stop();
|
||||
if (multiplayer())
|
||||
return;
|
||||
f = gzopen([IRI.fileSystemRepresentation
|
||||
cStringWithEncoding:OFLocale.encoding],
|
||||
"rb9");
|
||||
if (!f) {
|
||||
conoutf(@"could not open %@", IRI.string);
|
||||
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
|
||||
loadgame(OFString *name)
|
||||
{
|
||||
@autoreleasepool {
|
||||
OFString *path =
|
||||
[OFString stringWithFormat:@"savegames/%@.csgz", name];
|
||||
OFIRI *IRI = [Cube.sharedInstance.userDataIRI
|
||||
IRIByAppendingPathComponent:path];
|
||||
loadstate(IRI);
|
||||
}
|
||||
OFString *path = [OFString stringWithFormat:@"savegames/%@.csgz", name];
|
||||
OFIRI *IRI =
|
||||
[Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:path];
|
||||
loadstate(IRI);
|
||||
}
|
||||
COMMAND(loadgame, ARG_1STR)
|
||||
|
||||
|
@ -286,18 +274,15 @@ record(OFString *name)
|
|||
if (cn < 0)
|
||||
return;
|
||||
|
||||
@autoreleasepool {
|
||||
OFString *path =
|
||||
[OFString stringWithFormat:@"demos/%@.cdgz", name];
|
||||
OFIRI *IRI = [Cube.sharedInstance.userDataIRI
|
||||
IRIByAppendingPathComponent:path];
|
||||
savestate(IRI);
|
||||
gzputi(cn);
|
||||
conoutf(@"started recording demo to %@", IRI.string);
|
||||
demorecording = true;
|
||||
starttime = lastmillis;
|
||||
ddamage = bdamage = 0;
|
||||
}
|
||||
OFString *path = [OFString stringWithFormat:@"demos/%@.cdgz", name];
|
||||
OFIRI *IRI =
|
||||
[Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:path];
|
||||
savestate(IRI);
|
||||
gzputi(cn);
|
||||
conoutf(@"started recording demo to %@", IRI.string);
|
||||
demorecording = true;
|
||||
starttime = lastmillis;
|
||||
ddamage = bdamage = 0;
|
||||
}
|
||||
COMMAND(record, ARG_1STR)
|
||||
|
||||
|
@ -348,14 +333,11 @@ incomingdemodata(uchar *buf, int len, bool extras)
|
|||
void
|
||||
demo(OFString *name)
|
||||
{
|
||||
@autoreleasepool {
|
||||
OFString *path =
|
||||
[OFString stringWithFormat:@"demos/%@.cdgz", name];
|
||||
OFIRI *IRI = [Cube.sharedInstance.userDataIRI
|
||||
IRIByAppendingPathComponent:path];
|
||||
loadstate(IRI);
|
||||
demoloading = true;
|
||||
}
|
||||
OFString *path = [OFString stringWithFormat:@"demos/%@.cdgz", name];
|
||||
OFIRI *IRI =
|
||||
[Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:path];
|
||||
loadstate(IRI);
|
||||
demoloading = true;
|
||||
}
|
||||
COMMAND(demo, ARG_1STR)
|
||||
|
||||
|
|
|
@ -173,13 +173,10 @@ vote(OFString *map, int reqmode, int sender)
|
|||
if (yes == 1 && no == 0)
|
||||
return true; // single player
|
||||
|
||||
@autoreleasepool {
|
||||
OFString *msg =
|
||||
[OFString stringWithFormat:
|
||||
@"%@ suggests %@ on map %@ (set map to vote)",
|
||||
clients[sender].name, modestr(reqmode), map];
|
||||
sendservmsg(msg);
|
||||
}
|
||||
OFString *msg = [OFString
|
||||
stringWithFormat:@"%@ suggests %@ on map %@ (set map to vote)",
|
||||
clients[sender].name, modestr(reqmode), map];
|
||||
sendservmsg(msg);
|
||||
|
||||
if (yes / (float)(yes + no) <= 0.5f)
|
||||
return false;
|
||||
|
@ -215,9 +212,7 @@ process(ENetPacket *packet, int sender) // sender may be -1
|
|||
|
||||
case SV_INITC2S:
|
||||
sgetstr();
|
||||
@autoreleasepool {
|
||||
clients[cn].name = @(text);
|
||||
}
|
||||
clients[cn].name = @(text);
|
||||
sgetstr();
|
||||
getint(p);
|
||||
break;
|
||||
|
@ -227,19 +222,15 @@ process(ENetPacket *packet, int sender) // sender may be -1
|
|||
int reqmode = getint(p);
|
||||
if (reqmode < 0)
|
||||
reqmode = 0;
|
||||
@autoreleasepool {
|
||||
if (smapname.length > 0 && !mapreload &&
|
||||
!vote(@(text), reqmode, sender))
|
||||
return;
|
||||
}
|
||||
if (smapname.length > 0 && !mapreload &&
|
||||
!vote(@(text), reqmode, sender))
|
||||
return;
|
||||
mapreload = false;
|
||||
mode = reqmode;
|
||||
minremain = mode & 1 ? 15 : 10;
|
||||
mapend = lastsec + minremain * 60;
|
||||
interm = 0;
|
||||
@autoreleasepool {
|
||||
smapname = @(text);
|
||||
}
|
||||
smapname = @(text);
|
||||
resetitems();
|
||||
sender = -1;
|
||||
break;
|
||||
|
@ -284,9 +275,7 @@ process(ENetPacket *packet, int sender) // sender may be -1
|
|||
case SV_SENDMAP: {
|
||||
sgetstr();
|
||||
int mapsize = getint(p);
|
||||
@autoreleasepool {
|
||||
sendmaps(sender, @(text), mapsize, p);
|
||||
}
|
||||
sendmaps(sender, @(text), mapsize, p);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -329,9 +318,7 @@ send_welcome(int n)
|
|||
putint(p, SV_INITS2C);
|
||||
putint(p, n);
|
||||
putint(p, PROTOCOL_VERSION);
|
||||
@autoreleasepool {
|
||||
putint(p, *smapname.UTF8String);
|
||||
}
|
||||
putint(p, *smapname.UTF8String);
|
||||
sendstring(serverpassword, p);
|
||||
putint(p, clients.count > maxclients);
|
||||
if (smapname.length > 0) {
|
||||
|
@ -493,13 +480,10 @@ serverslice(int seconds,
|
|||
c.peer = event.peer;
|
||||
c.peer->data = (void *)(clients.count - 1);
|
||||
char hn[1024];
|
||||
@autoreleasepool {
|
||||
c.hostname =
|
||||
(enet_address_get_host(
|
||||
&c.peer->address, hn, sizeof(hn)) == 0
|
||||
? @(hn)
|
||||
: @"localhost");
|
||||
}
|
||||
c.hostname = (enet_address_get_host(
|
||||
&c.peer->address, hn, sizeof(hn)) == 0
|
||||
? @(hn)
|
||||
: @"localhost");
|
||||
[OFStdOut
|
||||
writeFormat:@"client connected (%@)\n", c.hostname];
|
||||
send_welcome(lastconnect = clients.count - 1);
|
||||
|
@ -566,11 +550,9 @@ initserver(bool dedicated, int uprate, OFString *sdesc, OFString *ip,
|
|||
|
||||
if ((isdedicated = dedicated)) {
|
||||
ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT };
|
||||
@autoreleasepool {
|
||||
if (ip.length > 0 &&
|
||||
enet_address_set_host(&address, ip.UTF8String) < 0)
|
||||
printf("WARNING: server ip not resolved");
|
||||
}
|
||||
if (ip.length > 0 &&
|
||||
enet_address_set_host(&address, ip.UTF8String) < 0)
|
||||
printf("WARNING: server ip not resolved");
|
||||
serverhost = enet_host_create(&address, MAXCLIENTS, 0, uprate);
|
||||
if (!serverhost)
|
||||
fatal(@"could not create server host\n");
|
||||
|
@ -589,6 +571,9 @@ initserver(bool dedicated, int uprate, OFString *sdesc, OFString *ip,
|
|||
atexit(cleanupserver);
|
||||
atexit(enet_deinitialize);
|
||||
for (;;)
|
||||
serverslice(/*enet_time_get_sec()*/ time(NULL), 5);
|
||||
@autoreleasepool {
|
||||
serverslice(
|
||||
/*enet_time_get_sec()*/ time(NULL), 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,17 +180,14 @@ getservername(int n)
|
|||
void
|
||||
addserver(OFString *servername)
|
||||
{
|
||||
@autoreleasepool {
|
||||
for (ServerInfo *si in servers)
|
||||
if ([si.name isEqual:servername])
|
||||
return;
|
||||
for (ServerInfo *si in servers)
|
||||
if ([si.name isEqual:servername])
|
||||
return;
|
||||
|
||||
if (servers == nil)
|
||||
servers = [[OFMutableArray alloc] init];
|
||||
if (servers == nil)
|
||||
servers = [[OFMutableArray alloc] init];
|
||||
|
||||
[servers
|
||||
addObject:[[ServerInfo alloc] initWithName:servername]];
|
||||
}
|
||||
[servers addObject:[[ServerInfo alloc] initWithName:servername]];
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -260,13 +257,9 @@ checkpings()
|
|||
si.numplayers = getint(p);
|
||||
si.minremain = getint(p);
|
||||
sgetstr();
|
||||
@autoreleasepool {
|
||||
si.map = @(text);
|
||||
}
|
||||
si.map = @(text);
|
||||
sgetstr();
|
||||
@autoreleasepool {
|
||||
si.sdesc = @(text);
|
||||
}
|
||||
si.sdesc = @(text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -306,10 +299,8 @@ refreshservers()
|
|||
si.name];
|
||||
|
||||
// cut off too long server descriptions
|
||||
@autoreleasepool {
|
||||
if (si.full.length > 50)
|
||||
si.full = [si.full substringToIndex:50];
|
||||
}
|
||||
if (si.full.length > 50)
|
||||
si.full = [si.full substringToIndex:50];
|
||||
|
||||
menumanual(1, i, si.full);
|
||||
|
||||
|
@ -348,9 +339,7 @@ updatefrommaster()
|
|||
conoutf(@"master server not replying");
|
||||
else {
|
||||
[servers removeAllObjects];
|
||||
@autoreleasepool {
|
||||
execute(@((char *)reply));
|
||||
}
|
||||
execute(@((char *)reply));
|
||||
}
|
||||
servermenu();
|
||||
}
|
||||
|
@ -366,9 +355,7 @@ writeservercfg()
|
|||
if (!f)
|
||||
return;
|
||||
fprintf(f, "// servers connected to are added here automatically\n\n");
|
||||
@autoreleasepool {
|
||||
for (ServerInfo *si in servers.reversedArray)
|
||||
fprintf(f, "addserver %s\n", si.name.UTF8String);
|
||||
}
|
||||
for (ServerInfo *si in servers.reversedArray)
|
||||
fprintf(f, "addserver %s\n", si.name.UTF8String);
|
||||
fclose(f);
|
||||
}
|
||||
|
|
|
@ -10,9 +10,7 @@ httpgetsend(ENetAddress &ad, OFString *hostname, OFString *req, OFString *ref,
|
|||
{
|
||||
if (ad.host == ENET_HOST_ANY) {
|
||||
[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)
|
||||
return;
|
||||
}
|
||||
|
@ -79,13 +77,10 @@ updatemasterserver(int seconds)
|
|||
{
|
||||
// send alive signal to masterserver every hour of uptime
|
||||
if (seconds > updmaster) {
|
||||
@autoreleasepool {
|
||||
OFString *path = [OFString
|
||||
stringWithFormat:@"%@register.do?action=add",
|
||||
masterpath];
|
||||
httpgetsend(masterserver, masterbase, path,
|
||||
@"cubeserver", @"Cube Server");
|
||||
}
|
||||
OFString *path = [OFString
|
||||
stringWithFormat:@"%@register.do?action=add", masterpath];
|
||||
httpgetsend(masterserver, masterbase, path, @"cubeserver",
|
||||
@"Cube Server");
|
||||
masterrep[0] = 0;
|
||||
masterb.data = masterrep;
|
||||
masterb.dataLength = MAXTRANS - 1;
|
||||
|
@ -105,12 +100,10 @@ checkmasterreply()
|
|||
uchar *
|
||||
retrieveservers(uchar *buf, int buflen)
|
||||
{
|
||||
@autoreleasepool {
|
||||
OFString *path = [OFString
|
||||
stringWithFormat:@"%@retrieve.do?item=list", masterpath];
|
||||
httpgetsend(masterserver, masterbase, path, @"cubeserver",
|
||||
@"Cube Server");
|
||||
}
|
||||
OFString *path =
|
||||
[OFString stringWithFormat:@"%@retrieve.do?item=list", masterpath];
|
||||
httpgetsend(
|
||||
masterserver, masterbase, path, @"cubeserver", @"Cube Server");
|
||||
ENetBuffer eb;
|
||||
buf[0] = 0;
|
||||
eb.data = buf;
|
||||
|
@ -160,23 +153,20 @@ serverms(int mode, int numplayers, int minremain, OFString *smapname,
|
|||
void
|
||||
servermsinit(OFString *master_, OFString *sdesc, bool listen)
|
||||
{
|
||||
@autoreleasepool {
|
||||
const char *master = master_.UTF8String;
|
||||
const char *mid = strstr(master, "/");
|
||||
if (!mid)
|
||||
mid = master;
|
||||
masterpath = @(mid);
|
||||
masterbase = [[OFString alloc] initWithUTF8String:master
|
||||
length:mid - master];
|
||||
serverdesc = sdesc;
|
||||
const char *master = master_.UTF8String;
|
||||
const char *mid = strstr(master, "/");
|
||||
if (!mid)
|
||||
mid = master;
|
||||
masterpath = @(mid);
|
||||
masterbase = [[OFString alloc] initWithUTF8String:master
|
||||
length:mid - master];
|
||||
serverdesc = sdesc;
|
||||
|
||||
if (listen) {
|
||||
ENetAddress address = { ENET_HOST_ANY,
|
||||
CUBE_SERVINFO_PORT };
|
||||
pongsock = enet_socket_create(
|
||||
ENET_SOCKET_TYPE_DATAGRAM, &address);
|
||||
if (pongsock == ENET_SOCKET_NULL)
|
||||
fatal(@"could not create server info socket\n");
|
||||
}
|
||||
if (listen) {
|
||||
ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
|
||||
pongsock =
|
||||
enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, &address);
|
||||
if (pongsock == ENET_SOCKET_NULL)
|
||||
fatal(@"could not create server info socket\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,14 +45,12 @@ getint(uchar *&p)
|
|||
void
|
||||
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++)
|
||||
putint(p, *t++);
|
||||
for (size_t i = 0; i < _MAXDEFSTR && *t != '\0'; i++)
|
||||
putint(p, *t++);
|
||||
|
||||
putint(p, 0);
|
||||
}
|
||||
putint(p, 0);
|
||||
}
|
||||
|
||||
static const OFString *modenames[] = {
|
||||
|
|
62
src/sound.mm
62
src/sound.mm
|
@ -87,43 +87,37 @@ music(OFString *name)
|
|||
return;
|
||||
stopsound();
|
||||
if (soundvol && musicvol) {
|
||||
@autoreleasepool {
|
||||
name = [name stringByReplacingOccurrencesOfString:@"\\"
|
||||
withString:@"/"];
|
||||
OFString *path =
|
||||
[OFString stringWithFormat:@"packages/%@", name];
|
||||
OFIRI *IRI = [Cube.sharedInstance.gameDataIRI
|
||||
IRIByAppendingPathComponent:path];
|
||||
name = [name stringByReplacingOccurrencesOfString:@"\\"
|
||||
withString:@"/"];
|
||||
OFString *path =
|
||||
[OFString stringWithFormat:@"packages/%@", name];
|
||||
OFIRI *IRI = [Cube.sharedInstance.gameDataIRI
|
||||
IRIByAppendingPathComponent:path];
|
||||
|
||||
#ifdef USE_MIXER
|
||||
if ((mod = Mix_LoadMUS(
|
||||
IRI.fileSystemRepresentation.UTF8String)) !=
|
||||
NULL) {
|
||||
Mix_PlayMusic(mod, -1);
|
||||
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
|
||||
if ((mod = Mix_LoadMUS(
|
||||
IRI.fileSystemRepresentation.UTF8String)) != NULL) {
|
||||
Mix_PlayMusic(mod, -1);
|
||||
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
|
||||
}
|
||||
}
|
||||
COMMAND(music, ARG_1STR)
|
||||
|
|
22
src/world.mm
22
src/world.mm
|
@ -67,13 +67,11 @@ trigger(int tag, int type, bool savegame)
|
|||
if (!savegame && type != 3)
|
||||
playsound(S_RUMBLE);
|
||||
|
||||
@autoreleasepool {
|
||||
OFString *aliasname =
|
||||
[OFString stringWithFormat:@"level_trigger_%d", tag];
|
||||
OFString *aliasname =
|
||||
[OFString stringWithFormat:@"level_trigger_%d", tag];
|
||||
|
||||
if (identexists(aliasname))
|
||||
execute(aliasname);
|
||||
}
|
||||
if (identexists(aliasname))
|
||||
execute(aliasname);
|
||||
|
||||
if (type == 2)
|
||||
endsp(false);
|
||||
|
@ -306,9 +304,7 @@ delent()
|
|||
return;
|
||||
}
|
||||
int t = ents[e].type;
|
||||
@autoreleasepool {
|
||||
conoutf(@"%@ entity deleted", entnames[t]);
|
||||
}
|
||||
conoutf(@"%@ entity deleted", entnames[t]);
|
||||
ents[e].type = NOTUSED;
|
||||
addmsg(1, 10, SV_EDITENT, e, NOTUSED, 0, 0, 0, 0, 0, 0, 0);
|
||||
if (t == LIGHT)
|
||||
|
@ -318,11 +314,9 @@ delent()
|
|||
int
|
||||
findtype(OFString *what)
|
||||
{
|
||||
@autoreleasepool {
|
||||
loopi(MAXENTTYPES) if ([what isEqual:entnames[i]]) return i;
|
||||
conoutf(@"unknown entity type \"%@\"", what);
|
||||
return NOTUSED;
|
||||
}
|
||||
loopi(MAXENTTYPES) if ([what isEqual:entnames[i]]) return i;
|
||||
conoutf(@"unknown entity type \"%@\"", what);
|
||||
return NOTUSED;
|
||||
}
|
||||
|
||||
entity *
|
||||
|
|
445
src/worldio.mm
445
src/worldio.mm
|
@ -14,30 +14,27 @@ static OFString *cgzname, *bakname, *pcfname, *mcfname;
|
|||
static void
|
||||
setnames(OFString *name)
|
||||
{
|
||||
@autoreleasepool {
|
||||
OFCharacterSet *cs =
|
||||
[OFCharacterSet characterSetWithCharactersInString:@"/\\"];
|
||||
OFRange range = [name rangeOfCharacterFromSet:cs];
|
||||
OFString *pakname, *mapname;
|
||||
OFCharacterSet *cs =
|
||||
[OFCharacterSet characterSetWithCharactersInString:@"/\\"];
|
||||
OFRange range = [name rangeOfCharacterFromSet:cs];
|
||||
OFString *pakname, *mapname;
|
||||
|
||||
if (range.location != OFNotFound) {
|
||||
pakname = [name substringToIndex:range.location];
|
||||
mapname = [name substringFromIndex:range.location + 1];
|
||||
} else {
|
||||
pakname = @"base";
|
||||
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];
|
||||
if (range.location != OFNotFound) {
|
||||
pakname = [name substringToIndex:range.location];
|
||||
mapname = [name substringFromIndex:range.location + 1];
|
||||
} else {
|
||||
pakname = @"base";
|
||||
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];
|
||||
}
|
||||
|
||||
// the optimize routines below are here to reduce the detrimental effects of
|
||||
|
@ -160,38 +157,37 @@ readmap(OFString *mname)
|
|||
void
|
||||
save_world(OFString *mname)
|
||||
{
|
||||
@autoreleasepool {
|
||||
resettagareas(); // wouldn't be able to reproduce tagged areas
|
||||
// otherwise
|
||||
voptimize();
|
||||
toptimize();
|
||||
if (mname.length == 0)
|
||||
mname = getclientmap();
|
||||
setnames(mname);
|
||||
backup(cgzname, bakname);
|
||||
gzFile f = gzopen(
|
||||
[cgzname cStringWithEncoding:OFLocale.encoding], "wb9");
|
||||
if (!f) {
|
||||
conoutf(@"could not write map to %@", cgzname);
|
||||
return;
|
||||
resettagareas(); // wouldn't be able to reproduce tagged areas
|
||||
// otherwise
|
||||
voptimize();
|
||||
toptimize();
|
||||
if (mname.length == 0)
|
||||
mname = getclientmap();
|
||||
setnames(mname);
|
||||
backup(cgzname, bakname);
|
||||
gzFile f =
|
||||
gzopen([cgzname cStringWithEncoding:OFLocale.encoding], "wb9");
|
||||
if (!f) {
|
||||
conoutf(@"could not write map to %@", cgzname);
|
||||
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;
|
||||
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));
|
||||
}
|
||||
}
|
||||
sqr *t = NULL;
|
||||
int sc = 0;
|
||||
}
|
||||
sqr *t = NULL;
|
||||
int sc = 0;
|
||||
#define spurge \
|
||||
while (sc) { \
|
||||
gzputc(f, 255); \
|
||||
|
@ -203,50 +199,49 @@ save_world(OFString *mname)
|
|||
sc = 0; \
|
||||
} \
|
||||
}
|
||||
loopk(cubicsize)
|
||||
{
|
||||
sqr *s = &world[k];
|
||||
loopk(cubicsize)
|
||||
{
|
||||
sqr *s = &world[k];
|
||||
#define c(f) (s->f == t->f)
|
||||
// 4 types of blocks, to compress a bit:
|
||||
// 255 (2): same as previous block + count
|
||||
// 254 (3): same as previous, except light // deprecated
|
||||
// SOLID (5)
|
||||
// anything else (9)
|
||||
// 4 types of blocks, to compress a bit:
|
||||
// 255 (2): same as previous block + count
|
||||
// 254 (3): same as previous, except light // deprecated
|
||||
// SOLID (5)
|
||||
// anything else (9)
|
||||
|
||||
if (SOLID(s)) {
|
||||
if (t && c(type) && c(wtex) && c(vdelta)) {
|
||||
sc++;
|
||||
} else {
|
||||
spurge;
|
||||
gzputc(f, s->type);
|
||||
gzputc(f, s->wtex);
|
||||
gzputc(f, s->vdelta);
|
||||
}
|
||||
if (SOLID(s)) {
|
||||
if (t && c(type) && c(wtex) && c(vdelta)) {
|
||||
sc++;
|
||||
} else {
|
||||
if (t && c(type) && c(floor) && c(ceil) &&
|
||||
c(ctex) && c(ftex) && c(utex) && c(wtex) &&
|
||||
c(vdelta) && c(tag)) {
|
||||
sc++;
|
||||
} else {
|
||||
spurge;
|
||||
gzputc(f, s->type);
|
||||
gzputc(f, s->floor);
|
||||
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);
|
||||
}
|
||||
spurge;
|
||||
gzputc(f, s->type);
|
||||
gzputc(f, s->wtex);
|
||||
gzputc(f, s->vdelta);
|
||||
}
|
||||
} else {
|
||||
if (t && c(type) && c(floor) && c(ceil) && c(ctex) &&
|
||||
c(ftex) && c(utex) && c(wtex) && c(vdelta) &&
|
||||
c(tag)) {
|
||||
sc++;
|
||||
} else {
|
||||
spurge;
|
||||
gzputc(f, s->type);
|
||||
gzputc(f, s->floor);
|
||||
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;
|
||||
gzclose(f);
|
||||
conoutf(@"wrote map file %@", cgzname);
|
||||
settagareas();
|
||||
t = s;
|
||||
}
|
||||
spurge;
|
||||
gzclose(f);
|
||||
conoutf(@"wrote map file %@", cgzname);
|
||||
settagareas();
|
||||
}
|
||||
COMMANDN(savemap, save_world, ARG_1STR)
|
||||
|
||||
|
@ -254,142 +249,136 @@ void
|
|||
load_world(OFString *mname) // still supports all map formats that have existed
|
||||
// since the earliest cube betas!
|
||||
{
|
||||
@autoreleasepool {
|
||||
stopifrecording();
|
||||
cleardlights();
|
||||
pruneundos();
|
||||
setnames(mname);
|
||||
gzFile f = gzopen(
|
||||
[cgzname cStringWithEncoding:OFLocale.encoding], "rb9");
|
||||
if (!f) {
|
||||
conoutf(@"could not read map %@", cgzname);
|
||||
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]);
|
||||
stopifrecording();
|
||||
cleardlights();
|
||||
pruneundos();
|
||||
setnames(mname);
|
||||
gzFile f =
|
||||
gzopen([cgzname cStringWithEncoding:OFLocale.encoding], "rb9");
|
||||
if (!f) {
|
||||
conoutf(@"could not read map %@", cgzname);
|
||||
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]);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue