diff --git a/source/src/client.cpp b/source/src/client.cpp index 1038aeb3..687c5a46 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -10,7 +10,7 @@ ENetHost *clienthost = NULL; ENetPeer *curpeer = NULL, *connpeer = NULL; int connmillis = 0, connattempts = 0, discmillis = 0; bool c2sinit = false; // whether we need to tell the other clients our stats -bool watchingdemo = false; // flowtron : enables SV_ITEMLIST in demos - req. because mapchanged == false by then +bool watchingdemo = false; int getclientnum() { return player1 ? player1->clientnum : -1; } @@ -277,7 +277,7 @@ void addmsg(int type, const char *fmt, ...) } static int lastupdate = -1000, lastping = 0; -bool senditemstoserver = false, sendspawnlist = false; // after a map change, since server doesn't have map data +bool sendmapidenttoserver = false; void sendpackettoserv(int chan, ENetPacket *packet) { @@ -321,7 +321,7 @@ void c2sinfo(playerent *d) // send update to the server sendpackettoserv(0, packet); } - if(senditemstoserver || sendspawnlist || !c2sinit || messages.length() || totalmillis-lastping>250) + if(sendmapidenttoserver || !c2sinit || messages.length() || totalmillis-lastping>250) { ENetPacket *packet = enet_packet_create (NULL, MAXTRANS, 0); ucharbuf p(packet->data, packet->dataLength); @@ -335,29 +335,14 @@ void c2sinfo(playerent *d) // send update to the server sendstring(player1->team, p); putint(p, player1->skin); } - if(senditemstoserver) - { + if(sendmapidenttoserver) + { // new map + spawnallitems(); packet->flags = ENET_PACKET_FLAG_RELIABLE; - if(maploaded > 0) - { - putint(p, SV_ITEMLIST); - if(!m_noitems) putitems(p); - putint(p, -1); - } - senditemstoserver = false; - } - if(sendspawnlist) - { - packet->flags = ENET_PACKET_FLAG_RELIABLE; - putint(p, SV_SPAWNLIST); + putint(p, SV_MAPIDENT); putint(p, maploaded); - if(maploaded > 0) - { - putint(p, hdr.maprevision); - loopi(3) putint(p, numspawn[i]); - loopi(2) putint(p, numflagspawn[i]); - } - sendspawnlist = false; + putint(p, hdr.maprevision); + sendmapidenttoserver = false; } int i = 0; while(i < messages.length()) // send messages collected during the previous frames diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 8cc4954a..a0b53e81 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -36,7 +36,7 @@ char *getclientmap() { return clientmap; } void mapname() { result(getclientmap()); } COMMAND(mapname, ARG_NONE); -extern bool c2sinit, senditemstoserver, sendspawnlist; +extern bool c2sinit, sendmapidenttoserver; void setskin(playerent *pl, uint skin) { @@ -721,7 +721,7 @@ int suicided = -1; void startmap(const char *name, bool reset) // called just after a map load { s_strcpy(clientmap, name); - senditemstoserver = sendspawnlist = true; + sendmapidenttoserver = true; // Added by Rick if(m_botmode) BotManager.BeginMap(name); else kickallbots(); diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index ff8295ca..8610e084 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -7,7 +7,7 @@ VARP(networkdebug, 0, 0, 1); #define DEBUGCOND (networkdebug==1) -extern bool c2sinit, senditemstoserver, watchingdemo; +extern bool c2sinit, watchingdemo; extern string clientpassword; packetqueue pktlogger; @@ -173,7 +173,7 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) { static char text[MAXTRANS]; int type, joining = 0; - bool mapchanged = false, demoplayback = false; + bool demoplayback = false; while(p.remaining()) { @@ -284,21 +284,20 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) int revision = getint(p); changemapserv(text, mode, downloadable, revision); if(m_arena && joining>2) deathstate(player1); - mapchanged = true; break; } case SV_ITEMLIST: { int n; - if(mapchanged||watchingdemo) { senditemstoserver = false; resetspawns(); } - while((n = getint(p))!=-1) { getint(p); if(mapchanged||watchingdemo) setspawn(n, true); } + resetspawns(); + while((n = getint(p))!=-1) setspawn(n, true); break; } - case SV_SPAWNLIST: + case SV_MAPIDENT: { - if(getint(p) > 0) loopi(6) getint(p); + loopi(2) getint(p); break; } diff --git a/source/src/entities.cpp b/source/src/entities.cpp index afa702e8..bb389ca2 100644 --- a/source/src/entities.cpp +++ b/source/src/entities.cpp @@ -289,12 +289,10 @@ void checkitems(playerent *d) } } -void putitems(ucharbuf &p) // puts items in network stream and also spawns them locally +void spawnallitems() // spawns items locally { loopv(ents) if(ents[i].fitsmode(gamemode) || (multiplayer(false) && gamespeed!=100 && (i=-1))) { - putint(p, i); - putint(p, ents[i].type); ents[i].spawned = true; } } diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index 6c0610e6..b710319f 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -206,7 +206,7 @@ char msgsizesl[] = // size inclusive message token, 0 for variable SV_CONNECT, 0, SV_CLIENT, 0, SV_EXTENSION, 0, - SV_SPAWNLIST, 0, SV_FORCENOTIFY, 3, + SV_MAPIDENT, 3, SV_FORCENOTIFY, 3, -1 }; diff --git a/source/src/protocol.h b/source/src/protocol.h index 08bc45a6..23dc0436 100644 --- a/source/src/protocol.h +++ b/source/src/protocol.h @@ -35,7 +35,7 @@ enum SV_CONNECT, SV_CLIENT, SV_EXTENSION, - SV_SPAWNLIST, SV_FORCENOTIFY, SV_NUM + SV_MAPIDENT, SV_FORCENOTIFY, SV_NUM }; #ifdef _DEBUG @@ -66,7 +66,7 @@ const static char *messagenames[] = "SV_CONNECT", "SV_CLIENT", "SV_EXTENSION", - "SV_SPAWNLIST", "SV_FORCENOTIFY" + "SV_MAPIDENT", "SV_FORCENOTIFY" }; #endif diff --git a/source/src/protos.h b/source/src/protos.h index c58267b2..f647045c 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -562,6 +562,7 @@ extern bool addscorchmark(vec &o, float radius = 7); extern void render_particles(int time, int typemask = ~0); // worldio +extern const char *setnames(const char *name); extern void save_world(char *fname); extern bool load_world(char *mname); extern void writemap(char *name, int size, uchar *data); @@ -642,7 +643,7 @@ extern struct projectile *newprojectile(vec &from, vec &to, float speed, bool lo // entities extern const char *entnames[]; -extern void putitems(ucharbuf &p); +extern void spawnallitems(); extern void pickupeffects(int n, playerent *d); extern void renderentities(); extern void rendermapmodels(); diff --git a/source/src/server.cpp b/source/src/server.cpp index bad19162..c804ce0e 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -26,7 +26,7 @@ void getservermap(void); mapstats *getservermapstats(const char *mapname, bool getlayout = false); int findmappath(const char *mapname, char *filename = NULL); -enum { MAP_NOTFOUND = 0, MAP_TEMP, MAP_CUSTOM, MAP_OFFICIAL }; +enum { MAP_NOTFOUND = 0, MAP_TEMP, MAP_CUSTOM, MAP_LOCAL, MAP_OFFICIAL }; #define readonlymap(x) ((x) >= MAP_CUSTOM) // eval x only once! servercontroller *svcctrl = NULL; @@ -54,7 +54,7 @@ int mastermode = MM_OPEN; #define gamemode smode string smapname, nextmapname; int smode = 0, nextgamemode; -int smapsize = 0; +mapstats smapstats; struct shotevent { @@ -549,9 +549,6 @@ struct server_entity // server side version of "entity" type vector sents; -bool notgotitems = true; // true when map has changed and waiting for clients to send item -int clnumspawn[3], clnumflagspawn[2]; - void restoreserverstate(vector &ents) // hack: called from savegame code, only works in SP { loopv(sents) @@ -1272,8 +1269,8 @@ vector sdistrib; void distributeteam(int team) { - int numsp = team == 100 ? clnumspawn[2] : clnumspawn[team]; - if(!numsp) numsp = 30; // no map data yet: make a guess + int numsp = team == 100 ? smapstats.spawns[2] : smapstats.spawns[team]; + if(!numsp) numsp = 30; // no spawns: try to distribute anyway twoint ti; tdistrib.setsize(0); loopv(clients) if(clients[i]->type!=ST_EMPTY) @@ -1439,8 +1436,6 @@ void sendvoicecomteam(int sound, int sender) if(packet->referenceCount==0) enet_packet_destroy(packet); } -void resetitems() { sents.setsize(0); notgotitems = true; } - int spawntime(int type) { int np = numclients(); @@ -2150,11 +2145,33 @@ bool refillteams(bool now, bool notify) // force only minimal amounts of player return switched; } -void resetmap(const char *newname, int newmode, int newtime, bool notify) +void resetserver(const char *newname, int newmode, int newtime) { if(m_demo) enddemoplayback(); else enddemorecord(); + smode = newmode; + s_strcpy(smapname, newname); + + minremain = newtime >= 0 ? newtime : (m_teammode ? 15 : 10); + gamemillis = 0; + gamelimit = minremain*60000; + + mapreload = false; + interm = 0; + if(!laststatus) laststatus = servmillis-61*1000; + lastfillup = servmillis; + resetvotes(VOTE_YES); // flowtron: VOTE_YES => reset lastvotecall too + sents.setsize(0); + scores.setsize(0); + ctfreset(); +} + +void resetmap(const char *newname, int newmode, int newtime, bool notify) +{ + bool lastteammode = m_teammode; + resetserver(newname, newmode, newtime); + if(custom_servdesc && findcnbyaddress(&servdesc_caller) < 0) { updatesdesc(NULL); @@ -2165,64 +2182,44 @@ void resetmap(const char *newname, int newmode, int newtime, bool notify) } } - bool lastteammode = m_teammode; - smode = newmode; - s_strcpy(smapname, newname); - if(isdedicated && smapname[0]) getservermap(); - - minremain = newtime >= 0 ? newtime : (m_teammode ? 15 : 10); - gamemillis = 0; - gamelimit = minremain*60000; - - mapreload = false; - interm = 0; - if(!laststatus) laststatus = servmillis-61*1000; - lastfillup = servmillis; - resetvotes(VOTE_YES); // flowtron: VOTE_YES => reset lastvotecall too - resetitems(); + if(isdedicated) getservermap(); mapstats *ms = getservermapstats(smapname, isdedicated); - loopi(3) clnumspawn[i] = ms ? ms->spawns[i] : 0; - loopi(2) - { - clnumflagspawn[i] = ms ? ms->flags[i] : 0; - sflaginfo &f = sflaginfos[i]; - if(clnumflagspawn[i] == 1) // don't check flag positions, if there is more than one flag per team - { - short *fe = ms->entposs + ms->flagents[i] * 3; - f.x = *fe; - fe++; - f.y = *fe; - } - else f.x = f.y = -1; - } if(ms) { - entity e; - loopi(ms->hdr.numents) + smapstats = *ms; + loopi(2) { - e.type = ms->enttypes[i]; + sflaginfo &f = sflaginfos[i]; + if(smapstats.flags[i] == 1) // don't check flag positions, if there is more than one flag per team + { + short *fe = smapstats.entposs + smapstats.flagents[i] * 3; + f.x = *fe; + fe++; + f.y = *fe; + } + else f.x = f.y = -1; + } + entity e; + loopi(smapstats.hdr.numents) + { + e.type = smapstats.enttypes[i]; e.transformtype(smode); - server_entity se = { e.type, false, true, 0, ms->entposs[i * 3], ms->entposs[i * 3 + 1]}; + server_entity se = { e.type, false, true, 0, smapstats.entposs[i * 3], smapstats.entposs[i * 3 + 1]}; sents.add(se); if(e.fitsmode(smode)) sents[i].spawned = true; } - notgotitems = false; - copyrevision = copymapsize == ms->cgzsize ? ms->hdr.maprevision : 0; + copyrevision = copymapsize == smapstats.cgzsize ? smapstats.hdr.maprevision : 0; } - smapsize = ms ? ms->cgzsize : 0; - scores.setsize(0); - ctfreset(); + else sendservmsg("\f3server error: map not found - please start another map"); if(notify) { // change map sendf(-1, 1, "risiii", SV_MAPCHANGE, smapname, smode, mapavailable(smapname), copyrevision); if(smode>1 || (smode==0 && numnonlocalclients()>0)) sendf(-1, 1, "ri2", SV_TIMEUP, minremain); } - if(newname[0]) - { - logger->writeline(log::info, "\nGame start: %s on %s, %d players, %d minutes remaining, mastermode %d, (map rev %d/%d, itemlist %spreloaded, 'getmap' %sprepared)", - modestr(smode), smapname, numclients(), minremain, mastermode, copyrevision, smapsize, ms ? "" : "not ", mapavailable(smapname) ? "" : "not "); - } + logger->writeline(log::info, "\nGame start: %s on %s, %d players, %d minutes remaining, mastermode %d, (map rev %d/%d, itemlist %spreloaded, 'getmap' %sprepared)", + modestr(smode), smapname, numclients(), minremain, mastermode, copyrevision, smapstats.cgzsize, ms ? "" : "not ", mapavailable(smapname) ? "" : "not "); + arenaround = 0; if(m_arena) { @@ -2558,28 +2555,37 @@ int findmappath(const char *mapname, char *filename) string tempname; if(!filename) filename = tempname; const char *name = behindpath(mapname); + if(!mapname[0]) return MAP_NOTFOUND; s_sprintf(filename)(SERVERMAP_PATH_BUILTIN "%s.cgz", name); path(filename); int loc = MAP_NOTFOUND; - if(fileexists(filename, "r")) loc = MAP_OFFICIAL; + if(getfilesize(filename) > 10) loc = MAP_OFFICIAL; else { - s_sprintf(filename)(SERVERMAP_PATH "%s.cgz", name); - path(filename); - if(fileexists(filename, "r")) loc = MAP_CUSTOM; +#ifndef STANDALONE + s_strcpy(filename, setnames(name)); + if(!isdedicated && getfilesize(filename) > 10) loc = MAP_LOCAL; else { - s_sprintf(filename)(SERVERMAP_PATH_INCOMING "%s.cgz", name); +#endif + s_sprintf(filename)(SERVERMAP_PATH "%s.cgz", name); path(filename); - if(fileexists(filename, "r")) loc = MAP_TEMP; + if(isdedicated && getfilesize(filename) > 10) loc = MAP_CUSTOM; + else + { + s_sprintf(filename)(SERVERMAP_PATH_INCOMING "%s.cgz", name); + path(filename); + if(isdedicated && getfilesize(filename) > 10) loc = MAP_TEMP; + } +#ifndef STANDALONE } +#endif } return loc; } mapstats *getservermapstats(const char *mapname, bool getlayout) { - const char *name = behindpath(mapname); string filename; int loc = findmappath(mapname, filename); if(getlayout) DELETEA(maplayout); @@ -2695,13 +2701,12 @@ void welcomepacket(ucharbuf &p, int n, ENetPacket *packet, bool forcedeath) putint(p, SV_TIMEUP); putint(p, minremain); } - if(numcl>1) + if(numcl>0) { putint(p, SV_ITEMLIST); loopv(sents) if(sents[i].spawned) { putint(p, i); - putint(p, sents[i].type); CHECKSPACE(256); } putint(p, -1); @@ -2821,7 +2826,7 @@ int checktype(int type, client *cl) SV_ITEMSPAWN, SV_TIMEUP, SV_CDIS, SV_PONG, SV_RESUME, SV_FLAGINFO, SV_FLAGMSG, SV_FLAGCNT, SV_ARENAWIN, SV_SENDDEMOLIST, SV_SENDDEMO, SV_DEMOPLAYBACK, SV_CLIENT, - SV_CALLVOTESUC, SV_CALLVOTEERR, SV_VOTERESULT, SV_WHOISINFO }; + SV_CALLVOTESUC, SV_CALLVOTEERR, SV_VOTERESULT, SV_WHOISINFO, SV_ITEMLIST }; if(cl) loopi(sizeof(servtypes)/sizeof(int)) if(type == servtypes[i]) return -1; return type; } @@ -3054,36 +3059,11 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1 break; } - case SV_ITEMLIST: + case SV_MAPIDENT: { - int n; - while((n = getint(p))!=-1) - { - server_entity se = { getint(p), false, false, 0, 0, 0}; - if(notgotitems) - { - while(sents.length()<=n) sents.add(se); - sents[n].spawned = true; - } - } - notgotitems = false; - break; - } - - case SV_SPAWNLIST: - { - int gzs = getint(p), rev = 0; - if(gzs > 0) - { - rev = getint(p); - if(copyrevision == 0) - { - loopi(3) clnumspawn[i] = getint(p); - loopi(2) clnumflagspawn[i] = getint(p); - } - else loopi(5) getint(p); - } - if(smapsize == 0 || (smapsize == gzs && copyrevision == rev)) cl->isonrightmap = true; + int gzs = getint(p); + int rev = getint(p); + if(!isdedicated || (smapstats.cgzsize == gzs && copyrevision == rev)) cl->isonrightmap = true; else forcedeath(cl); QUEUE_MSG; break; @@ -3128,6 +3108,7 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1 break; case SV_TRYSPAWN: + if(!cl->isonrightmap) sendservmsg("\f3you can't spawn until you download the map from the server; please type /getmap", sender); if(cl->state.state!=CS_DEAD || cl->state.lastspawn>=0 || !canspawn(cl) || !cl->isonrightmap) break; if(cl->state.lastdeath) cl->state.respawn(); sendspawn(cl); @@ -3603,7 +3584,7 @@ void checkintermission() void resetserverifempty() { loopv(clients) if(clients[i]->type!=ST_EMPTY) return; - resetmap("", 0, 10, false); + resetserver("", 0, 10); mastermode = MM_OPEN; autoteam = true; nextmapname[0] = '\0'; @@ -3684,7 +3665,7 @@ void serverslice(uint timeout) // main server update, called from cube main lo { sflaginfo &f = sflaginfos[i]; if(f.state == CTFF_DROPPED && gamemillis-f.lastupdate > (m_ctf ? 30000 : 10000)) flagaction(i, FA_RESET, -1); - if(m_htf && f.state == CTFF_INBASE && gamemillis-f.lastupdate > (clnumflagspawn[0] && clnumflagspawn[1] ? 10000 : 1000)) + if(m_htf && f.state == CTFF_INBASE && gamemillis-f.lastupdate > (smapstats.hasflags ? 10000 : 1000)) { htf_forceflag(i); } diff --git a/source/src/worldio.cpp b/source/src/worldio.cpp index 5b4da689..c87d6236 100644 --- a/source/src/worldio.cpp +++ b/source/src/worldio.cpp @@ -13,7 +13,7 @@ void backup(char *name, char *backupname) static string cgzname, ocgzname, bakname, pcfname, mcfname, omcfname; -void setnames(char *name) +const char *setnames(const char *name) { string pakname, mapname; char *slash = strpbrk(name, "/\\"); @@ -37,6 +37,7 @@ void setnames(char *name) path(cgzname); path(bakname); + return cgzname; } // the optimize routines below are here to reduce the detrimental effects of messy mapping by