diff --git a/source/src/audiomanager.cpp b/source/src/audiomanager.cpp index 7fe21a14..8b46eb00 100644 --- a/source/src/audiomanager.cpp +++ b/source/src/audiomanager.cpp @@ -233,20 +233,23 @@ int audiomanager::addsound(char *name, int vol, int maxuses, bool loop, vectorload(trydl) && !trydl) conoutf("\f3failed to load sample %s", buf->name); + if(!buf->load(trydl) && !trydl) { conoutf("\f3failed to load sample %s", buf->name); return false; } + return true; } -void audiomanager::preloadmapsounds(bool trydl) +bool audiomanager::preloadmapsounds(bool trydl) { + int missing = 0; loopv(ents) { entity &e = ents[i]; - if(e.type==SOUND) preloadmapsound(e, trydl); + if(e.type == SOUND && !preloadmapsound(e, trydl)) missing++; } + return !missing; } void audiomanager::applymapsoundchanges() // during map editing, drop all mapsounds so they can be re-added @@ -820,7 +823,11 @@ COMMANDF(mapsound, "si", (char *name, int *maxuses) filtertext(name, name, FTXT__MEDIAFILEPATH); defformatstring(stripped)("%s%s", mapsoundbasepath, name); unixpath(path(stripped)); - if(mapconfigdata.mapsoundlines.length() > 254) conoutf("\f3error: too many mapsounds"); + if(mapconfigdata.mapsoundlines.length() > 254) + { + conoutf("\f3error: too many mapsounds"); + flagmapconfigerror(LWW_CONFIGERR); + } else if(!strncmp(stripped, mapsoundbasepath, mapsoundbasepath_n)) { name = stripped + mapsoundbasepath_n; @@ -832,7 +839,11 @@ COMMANDF(mapsound, "si", (char *name, int *maxuses) mapsoundchanged = 1; flagmapconfigchange(); } - else conoutf("\f3error: mapsound \"%s\" outside packages/audio/", stripped); + else + { + conoutf("\f3error: mapsound \"%s\" outside packages/audio/", stripped); + flagmapconfigerror(LWW_CONFIGERR); + } }); COMMANDF(registermusic, "s", (char *name) diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index 3f40db1d..ee5bad28 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -37,11 +37,11 @@ bool changemapserv(char *name, int mode, int download, int revision) // f if(m_demo) return true; if(m_coop) { - if(!name[0] || !load_world(name)) empty_world(0, true); + if(!name[0] || load_world(name) < 0) empty_world(0, true); return true; } else if(player1->state==CS_EDITING) { /*conoutf("SANITY drop from EDITING");*/ toggleedit(true); } // fix stuck-in-editmode bug - bool loaded = load_world(name); + bool loaded = load_world(name) >= 0; if(download > 0) { bool revmatch = hdr.maprevision == revision || revision == 0; diff --git a/source/src/command.cpp b/source/src/command.cpp index 3c8f17cc..d48da5f4 100644 --- a/source/src/command.cpp +++ b/source/src/command.cpp @@ -691,6 +691,7 @@ char *executeret(const char *p) // all evaluation hap { i1 = i1minval ? id->minval : id->maxval; // clamp to valid range conoutf("valid range for %s is %d..%d", id->name, id->minval, id->maxval); + flagmapconfigerror(LWW_SCRIPTERR); } *id->storage.i = i1; if(id->fun) ((void (__cdecl *)())id->fun)(); // call trigger function if available @@ -707,7 +708,7 @@ char *executeret(const char *p) // all evaluation hap { f1 = f1minvalf ? id->minvalf : id->maxvalf; // clamp to valid range conoutf("valid range for %s is %s..%s", id->name, floatstr(id->minvalf), floatstr(id->maxvalf)); - //scripterr(); // Why throw this error here when it's not done for ID_VAR above? Only difference is datatype, both are "valid range errors". // Bukz 2011june04 + flagmapconfigerror(LWW_SCRIPTERR * 2); } *id->storage.f = f1; if(id->fun) ((void (__cdecl *)())id->fun)(); // call trigger function if available @@ -1023,6 +1024,7 @@ void scripterr() { if(curcontext) conoutf("(%s: %s)", curcontext, curinfo); else conoutf("(from console or builtin)"); + flagmapconfigerror(LWW_SCRIPTERR * 4); } void setcontext(const char *context, const char *info) diff --git a/source/src/md2.h b/source/src/md2.h index b8d2303d..52619301 100644 --- a/source/src/md2.h +++ b/source/src/md2.h @@ -257,7 +257,7 @@ struct md2 : vertmodel Texture *skin; loadskin(loadname, pname, skin); loopv(mdl.meshes) mdl.meshes[i]->skin = skin; - if(skin==notexture) conoutf("could not load model skin for %s", name1); + if(skin==notexture) { conoutf("could not load model skin for %s", name1); flagmapconfigerror(LWW_MODELERR); } loadingmd2 = this; defformatstring(name2)("packages/models/%s/md2.cfg", loadname); per_idents = false; @@ -280,15 +280,15 @@ struct md2 : vertmodel void md2anim(char *anim, int *frame, int *range, float *speed) { - if(!loadingmd2 || loadingmd2->parts.empty()) { conoutf("not loading an md2"); return; } + if(!loadingmd2 || loadingmd2->parts.empty()) { conoutf("not loading an md2"); flagmapconfigerror(LWW_MODELERR); return; } int num = findanim(anim); - if(num<0) { conoutf("could not find animation %s", anim); return; } + if(num<0) { conoutf("could not find animation %s", anim); flagmapconfigerror(LWW_MODELERR); return; } loadingmd2->parts.last()->setanim(num, *frame, *range, *speed); } void md2tag(char *name, char *vert1, char *vert2, char *vert3, char *vert4) { - if(!loadingmd2 || loadingmd2->parts.empty()) { conoutf("not loading an md2"); return; } + if(!loadingmd2 || loadingmd2->parts.empty()) { conoutf("not loading an md2"); flagmapconfigerror(LWW_MODELERR); return; } md2::part &mdl = *loadingmd2->parts.last(); int indexes[4] = { -1, -1, -1, -1 }, numverts = 0; loopi(4) @@ -319,17 +319,17 @@ void md2tag(char *name, char *vert1, char *vert2, char *vert3, char *vert4) } if(!mdl.meshes.empty()) indexes[i] = mdl.meshes[0]->findvert(axis, dir); } - if(indexes[i] < 0) { conoutf("could not find vertex %s", vert); return; } + if(indexes[i] < 0) { conoutf("could not find vertex %s", vert); flagmapconfigerror(LWW_MODELERR); return; } numverts = i + 1; } - if(!mdl.gentag(name, indexes, numverts)) { conoutf("could not generate tag %s", name); return; } + if(!mdl.gentag(name, indexes, numverts)) { conoutf("could not generate tag %s", name); flagmapconfigerror(LWW_MODELERR); return; } } void md2emit(char *tag, int *type, int *arg1, int *arg2) { - if(!loadingmd2 || loadingmd2->parts.empty()) { conoutf("not loading an md2"); return; }; + if(!loadingmd2 || loadingmd2->parts.empty()) { conoutf("not loading an md2"); flagmapconfigerror(LWW_MODELERR); return; }; md2::part &mdl = *loadingmd2->parts.last(); - if(!mdl.addemitter(tag, *type, *arg1, *arg2)) { conoutf("could not find tag %s", tag); return; } + if(!mdl.addemitter(tag, *type, *arg1, *arg2)) { conoutf("could not find tag %s", tag); flagmapconfigerror(LWW_MODELERR); return; } } COMMAND(md2anim, "siif"); diff --git a/source/src/md3.h b/source/src/md3.h index d1f4c597..bf5cdcca 100644 --- a/source/src/md3.h +++ b/source/src/md3.h @@ -63,6 +63,7 @@ struct md3 : vertmodel { delete f; conoutf("md3: corrupted header"); + flagmapconfigerror(LWW_MODELERR); return false; } @@ -244,7 +245,7 @@ struct md3 : vertmodel Texture *skin; loadskin(loadname, pname, skin); loopv(mdl.meshes) mdl.meshes[i]->skin = skin; - if(skin==notexture) conoutf("could not load model skin for %s", name1); + if(skin==notexture) { conoutf("could not load model skin for %s", name1); flagmapconfigerror(LWW_MODELERR); } } loopv(parts) parts[i]->scaleverts(scale/16.0f, vec(translate.x, -translate.y, translate.z)); radius = calcradius(zradius); @@ -256,20 +257,20 @@ struct md3 : vertmodel void md3load(char *model) { - if(!loadingmd3) { conoutf("not loading an md3"); return; }; + if(!loadingmd3) { conoutf("not loading an md3"); flagmapconfigerror(LWW_MODELERR); return; }; filtertext(model, model, FTXT__MEDIAFILEPATH); defformatstring(filename)("%s/%s", md3dir, model); md3::md3part &mdl = *new md3::md3part; loadingmd3->parts.add(&mdl); mdl.model = loadingmd3; mdl.index = loadingmd3->parts.length()-1; - if(!mdl.load(path(filename))) conoutf("could not load %s", filename); // ignore failure + if(!mdl.load(path(filename))) { conoutf("could not load %s", filename); flagmapconfigerror(LWW_MODELERR); } // ignore failure } void md3skin(char *objname, char *skin) { filtertext(skin, skin, FTXT__MEDIAFILEPATH); - if(!loadingmd3 || loadingmd3->parts.empty()) { conoutf("not loading an md3"); return; }; + if(!loadingmd3 || loadingmd3->parts.empty()) { conoutf("not loading an md3"); flagmapconfigerror(LWW_MODELERR); return; }; md3::part &mdl = *loadingmd3->parts.last(); bool used = false; loopv(mdl.meshes) @@ -287,29 +288,30 @@ void md3skin(char *objname, char *skin) defformatstring(s)(", possibilities are: *"); loopv(mdl.meshes) concatformatstring(s, "|%s", mdl.meshes[i]->name); conoutf("mesh \"%s\" not found in model %s, skin %s not loaded%s", objname, loadingmd3->loadname, skin, mdl.meshes.length() ? s : ""); + flagmapconfigerror(LWW_MODELERR); } } void md3anim(char *anim, int *startframe, int *range, float *speed) { - if(!loadingmd3 || loadingmd3->parts.empty()) { conoutf("not loading an md3"); return; }; + if(!loadingmd3 || loadingmd3->parts.empty()) { conoutf("not loading an md3"); flagmapconfigerror(LWW_MODELERR); return; }; int num = findanim(anim); - if(num<0) { conoutf("could not find animation %s", anim); return; }; + if(num<0) { conoutf("could not find animation %s", anim); flagmapconfigerror(LWW_MODELERR); return; }; loadingmd3->parts.last()->setanim(num, *startframe, *range, *speed); } void md3link(int *parent, int *child, char *tagname) { if(!loadingmd3) { conoutf("not loading an md3"); return; }; - if(!loadingmd3->parts.inrange(*parent) || !loadingmd3->parts.inrange(*child)) { conoutf("no models loaded to link"); return; } - if(!loadingmd3->parts[*parent]->link(loadingmd3->parts[*child], tagname)) conoutf("could not link model %s", loadingmd3->loadname); + if(!loadingmd3->parts.inrange(*parent) || !loadingmd3->parts.inrange(*child)) { conoutf("no models loaded to link"); flagmapconfigerror(LWW_MODELERR); return; } + if(!loadingmd3->parts[*parent]->link(loadingmd3->parts[*child], tagname)) { conoutf("could not link model %s", loadingmd3->loadname); flagmapconfigerror(LWW_MODELERR); } } void md3emit(char *tag, int *type, int *arg1, int *arg2) { - if(!loadingmd3 || loadingmd3->parts.empty()) { conoutf("not loading an md3"); return; }; + if(!loadingmd3 || loadingmd3->parts.empty()) { conoutf("not loading an md3"); flagmapconfigerror(LWW_MODELERR); return; }; md3::part &mdl = *loadingmd3->parts.last(); - if(!mdl.addemitter(tag, *type, *arg1, *arg2)) { conoutf("could not find tag %s", tag); return; } + if(!mdl.addemitter(tag, *type, *arg1, *arg2)) { conoutf("could not find tag %s", tag); flagmapconfigerror(LWW_MODELERR); return; } } COMMAND(md3load, "s"); diff --git a/source/src/protos.h b/source/src/protos.h index 364940af..b14edb4d 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -429,7 +429,7 @@ extern const char *gettextureslot(int i); extern bool reloadtexture(Texture &t); extern void reloadtextures(); extern void blitsurface(SDL_Surface *dst, SDL_Surface *src, int x, int y); -extern void loadskymap(bool reload); +extern bool loadskymap(bool reload); extern void *texconfig_copy(); extern void texconfig_delete(void *s); extern uchar *texconfig_paste(void *_s, uchar *usedslots); @@ -813,18 +813,20 @@ extern bool addscorchmark(vec &o, float radius = 7); extern void render_particles(int time, int typemask = ~0); // worldio +enum { LWW_ENTATTROVERFLOW = 0x1, LWW_DECODEERR = 0x10, LWW_WORLDERROR = 0x100, LWW_MISSINGMEDIA = 0x1000, LWW_CONFIGERR = 0x10000, LWW_MODELERR = 0x100000, LWW_SCRIPTERR = 0x1000000 }; extern const char *setnames(const char *name); extern void save_world(char *mname, bool skipoptimise = false, bool addcomfort = false); -extern bool load_world(char *mname); +extern int load_world(char *mname); extern void writemap(char *name, int size, uchar *data); extern void writecfggz(char *name, int size, int sizegz, uchar *data); extern uchar *readmap(char *name, int *size, int *revision); extern uchar *readmcfggz(char *name, int *size, int *sizegz); extern void rlencodecubes(vector &f, sqr *s, int len, bool preservesolids); -extern void rldecodecubes(ucharbuf &f, sqr *s, int len, int version, bool silent); +extern bool rldecodecubes(ucharbuf &f, sqr *s, int len, int version, bool silent); extern void clearheaderextras(); extern void automapconfig(); extern void flagmapconfigchange(); +extern void flagmapconfigerror(int what); extern void getcurrentmapconfig(vector &f, bool onlysounds); extern char *mapinfo_license, *mapinfo_comment; extern void setmapinfo(const char *newlicense = NULL, const char *newcomment = NULL); @@ -879,7 +881,7 @@ extern void resetmdlnotfound(); extern void preload_playermodels(); extern void preload_entmodels(); extern void preload_hudguns(); -extern void preload_mapmodels(bool trydl = false); +extern bool preload_mapmodels(bool trydl = false); extern void renderclients(); extern void renderclient(playerent *d); extern void renderclient(playerent *d, const char *mdlname, const char *vwepname, int tex = 0); diff --git a/source/src/rendermodel.cpp b/source/src/rendermodel.cpp index 9501777f..1ff253c5 100644 --- a/source/src/rendermodel.cpp +++ b/source/src/rendermodel.cpp @@ -11,7 +11,7 @@ mapmodelattributes loadingattributes; #include "md2.h" #include "md3.h" -#define checkmdl if(!loadingmodel) { conoutf("not loading a model"); return; } +#define checkmdl if(!loadingmodel) { conoutf("not loading a model"); flagmapconfigerror(LWW_MODELERR); return; } void mdlcullface(int *cullface) { @@ -119,7 +119,11 @@ void mapmodel(int *rad, int *h, int *zoff, char *scale, char *name) mmi.h = *h; mmi.zoff = *zoff; mmi.scale = atof(scale); - if(mmi.scale < 0.25f || mmi.scale > 4.0f) mmi.scale = 1.0f; + if(mmi.scale < 0.25f || mmi.scale > 4.0f) + { + mmi.scale = 1.0f; + if(strcmp(scale, "0")) flagmapconfigerror(LWW_CONFIGERR * 2); + } mmi.m = NULL; filtertext(name, name, FTXT__MEDIAFILEPATH); @@ -382,7 +386,11 @@ model *loadmodel(const char *name, int i, bool trydl) // load model by name { mdllookup.access(m->name(), m); setmodelattributes(m->name(), loadingattributes); - if(m->shadowdist && !m->cullface) conoutf("\f3mapmodel config error: disabling face culling in combination with shadows will cause visual errors (%s)", m->name()); + if(m->shadowdist && !m->cullface) + { + conoutf("\f3mapmodel config error: disabling face culling in combination with shadows will cause visual errors (%s)", m->name()); + flagmapconfigerror(LWW_MODELERR); + } } loadingmodel = NULL; } @@ -896,15 +904,17 @@ void preload_entmodels() } } -void preload_mapmodels(bool trydl) +bool preload_mapmodels(bool trydl) { + int missing = 0; loopv(ents) { entity &e = ents[i]; if(e.type!=MAPMODEL || !mapmodels.inrange(e.attr2)) continue; - loadmodel(NULL, e.attr2, trydl); - if(e.attr4) lookuptexture(e.attr4, notexture, trydl); + if(!loadmodel(NULL, e.attr2, trydl)) missing++; + if(e.attr4 && lookuptexture(e.attr4, notexture, trydl) == notexture) missing++; } + return !missing; } inline void renderhboxpart(playerent *d, vec top, vec bottom, vec up) diff --git a/source/src/sound.h b/source/src/sound.h index b0dc8fff..1d7e2511 100644 --- a/source/src/sound.h +++ b/source/src/sound.h @@ -390,8 +390,8 @@ public: // init & setup void initsound(); - void preloadmapsound(entity &e, bool trydl = false); - void preloadmapsounds(bool trydl = false); + bool preloadmapsound(entity &e, bool trydl = false); + bool preloadmapsounds(bool trydl = false); void applymapsoundchanges(); // configuration diff --git a/source/src/texture.cpp b/source/src/texture.cpp index 527275ef..f80554aa 100644 --- a/source/src/texture.cpp +++ b/source/src/texture.cpp @@ -501,7 +501,11 @@ COMMANDF(texture, "fs", (float *scale, char *name) intret(slots.length()); Slot &s = slots.add(); _texture(s, scale, name); - if(*scale < 0.0f || *scale > 4.0f) conoutf("\f3texture slot #%d \"%s\" error: scale factor %.7g out of range 0..4", slots.length() - 1, name, *scale); + if(*scale < 0.0f || *scale > 4.0f) + { + conoutf("\f3texture slot #%d \"%s\" error: scale factor %.7g out of range 0..4", slots.length() - 1, name, *scale); + flagmapconfigerror(LWW_CONFIGERR * 4); + } flagmapconfigchange(); }); @@ -566,7 +570,7 @@ Texture *sky[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; SVARF(loadsky, "", { loadskymap(false); }); -void loadskymap(bool reload) +bool loadskymap(bool reload) { const char *side[] = { "lf", "rt", "ft", "bk", "dn", "up" }; const char *legacyprefix = "textures/skymaps/"; @@ -582,7 +586,7 @@ void loadskymap(bool reload) } flagmapconfigchange(); } - bool old_silent_texture_load = silent_texture_load; + bool old_silent_texture_load = silent_texture_load, success = true; if(autodownload && execcontext == IEXC_MAPCFG) silent_texture_load = true; loopi(6) { @@ -593,8 +597,10 @@ void loadskymap(bool reload) requirepackage(PCK_SKYBOX, loadsky); break; } + if(sky[i] == notexture && reload) success = false; } silent_texture_load = old_silent_texture_load; + return success; } void loadnotexture(char *c) @@ -606,7 +612,7 @@ void loadnotexture(char *c) filtertext(mapconfigdata.notexturename, c, FTXT__MEDIAFILEPATH); defformatstring(p)("packages/textures/%s", mapconfigdata.notexturename); noworldtexture = textureload(p); - if(noworldtexture==notexture) conoutf("could not load alternative texture '%s'.", p); + if(noworldtexture==notexture) { conoutf("could not load alternative texture '%s'.", p); flagmapconfigerror(LWW_CONFIGERR * 8); } } flagmapconfigchange(); } diff --git a/source/src/worldio.cpp b/source/src/worldio.cpp index fb0a66b9..ab9cdecc 100644 --- a/source/src/worldio.cpp +++ b/source/src/worldio.cpp @@ -168,7 +168,7 @@ void rlencodecubes(vector &f, sqr *s, int len, bool preservesolids) // ru spurge; } -void rldecodecubes(ucharbuf &f, sqr *s, int len, int version, bool silent) // run-length decoding of a series of cubes (version is only relevant, if < 6) +bool rldecodecubes(ucharbuf &f, sqr *s, int len, int version, bool silent) // run-length decoding of a series of cubes (version is only relevant, if < 6) { sqr *t = NULL, *e = s + len; while(s < e) @@ -215,7 +215,7 @@ void rldecodecubes(ucharbuf &f, sqr *s, int len, int version, bool silent) // ru if(type<0 || type>=MAXTYPE) { if(!silent) conoutf("while reading map at %d: type %d out of range", int(cubicsize - (e - s)), type); - f.overread(); + f.forceoverread(); continue; } sqrdefault(s); @@ -236,6 +236,7 @@ void rldecodecubes(ucharbuf &f, sqr *s, int len, int version, bool silent) // ru t = s; s++; } + return !f.overread(); // true: no problem } // headerextra stores additional data in a map file (support since format 10) @@ -282,7 +283,7 @@ void unpackheaderextra(uchar *buf, int len) // break the extra data from the ma { int len = getuint(p), flags = getuint(p), type = flags & HX_TYPEMASK; if(p.overread() || len > p.remaining()) break; - clientlogf(" found headerextra \"%s\", %d bytes%s", hx_name(type), len, flags & HX_FLAG_PERSIST ? "persistent" : ""); // debug info + clientlogf(" found headerextra \"%s\", %d bytes%s", hx_name(type), len, flags & HX_FLAG_PERSIST ? ", persistent" : ""); // debug info headerextras.add(new headerextra(len, flags, p.subbuf(len).buf)); } } @@ -414,6 +415,13 @@ void flagmapconfigchange() if(execcontext != IEXC_MAPCFG && hdr.flags & MHF_AUTOMAPCONFIG) unsavededits++; } +int mapconfigerror = 0; + +void flagmapconfigerror(int what) +{ + if(execcontext == IEXC_MAPCFG || execcontext == IEXC_MDLCFG) mapconfigerror |= what; +} + void getcurrentmapconfig(vector &f, bool onlysounds) { if(!onlysounds) @@ -757,7 +765,7 @@ extern float Mh; static string lastloadedconfigfile; -bool load_world(char *mname) // still supports all map formats that have existed since the earliest cube betas! +int load_world(char *mname) // still supports all map formats that have existed since the earliest cube betas! { const int sizeof_header = sizeof(header), sizeof_baseheader = sizeof_header - sizeof(int) * 16; stopwatch watch; @@ -775,23 +783,23 @@ bool load_world(char *mname) // still supports all map formats that have if(!validmapname(mname)) { conoutf("\f3Invalid map name. It must only contain letters, digits, '-', '_' and be less than %d characters long", MAXMAPNAMELEN); - return false; + return -1; } stream *f = opengzfile(cgzname, "rb"); - if(!f) { conoutf("\f3could not read map %s", cgzname); return false; } + if(!f) { conoutf("\f3could not read map %s", cgzname); return -2; } if(unsavededits) xmapbackup("load_map_", mname); unsavededits = 0; DEBUG("reading map \"" << cgzname << "\""); header tmp; memset(&tmp, 0, sizeof_header); if(f->read(&tmp, sizeof_baseheader) != sizeof_baseheader || - (strncmp(tmp.head, "CUBE", 4)!=0 && strncmp(tmp.head, "ACMP",4)!=0)) { conoutf("\f3while reading map: header malformatted (1)"); delete f; return false; } + (strncmp(tmp.head, "CUBE", 4)!=0 && strncmp(tmp.head, "ACMP",4)!=0)) { conoutf("\f3while reading map: header malformatted (1)"); delete f; return -3; } lilswap(&tmp.version, 4); // version, headersize, sfactor, numents - if(tmp.version > MAPVERSION) { conoutf("\f3this map requires a newer version of AssaultCube"); delete f; return false; } - if(tmp.sfactorLARGEST_FACTOR || tmp.numents > MAXENTITIES) { conoutf("\f3illegal map size"); delete f; return false; } + if(tmp.version > MAPVERSION) { conoutf("\f3this map requires a newer version of AssaultCube"); delete f; return -4; } + if(tmp.sfactorLARGEST_FACTOR || tmp.numents > MAXENTITIES) { conoutf("\f3illegal map size"); delete f; return -5; } tmp.headersize = fixmapheadersize(tmp.version, tmp.headersize); int restofhead = min(tmp.headersize, sizeof_header) - sizeof_baseheader; - if(f->read(&tmp.waterlevel, restofhead) != restofhead) { conoutf("\f3while reading map: header malformatted (2)"); delete f; return false; } + if(f->read(&tmp.waterlevel, restofhead) != restofhead) { conoutf("\f3while reading map: header malformatted (2)"); delete f; return -6; } DEBUG("version " << tmp.version << " headersize " << tmp.headersize << " headerextrasize " << tmp.headersize - int(sizeof(header)) << " entities " << tmp.numents << " factor " << tmp.sfactor << " revision " << tmp.maprevision); clearheaderextras(); if(tmp.headersize > sizeof_header) @@ -802,7 +810,7 @@ bool load_world(char *mname) // still supports all map formats that have if(extrasize) { // map file actually has extra header data that we want too preserve uchar *extrabuf = new uchar[extrasize]; - if(f->read(extrabuf, extrasize) != extrasize) { conoutf("\f3while reading map: header malformatted (3)"); delete f; return false; } + if(f->read(extrabuf, extrasize) != extrasize) { conoutf("\f3while reading map: header malformatted (3)"); delete f; return -7; } unpackheaderextra(extrabuf, extrasize); delete[] extrabuf; } @@ -813,6 +821,7 @@ bool load_world(char *mname) // still supports all map formats that have rebuildtexlists(); loadingscreen("%s", hdr.maptitle); resetmap(); + int res = 0; if(hdr.version>=4) { lilswap(&hdr.waterlevel, 1); @@ -852,7 +861,7 @@ bool load_world(char *mname) // still supports all map formats that have #define SCALEATTR(x) \ if((ss = abs(entwraparound[e.type][x - 1] / entscale[e.type][x - 1]))) e.attr##x = (int(e.attr##x) % ss + ss) % ss; \ e.attr##x = ov = e.attr##x * entscale[e.type][x - 1]; \ - if(ov != e.attr##x) conoutf("overflow during conversion of attr%d of entity #%d (%s) - pls check before saving the map", x, i, entnames[e.type]); + if(ov != e.attr##x) { conoutf("overflow during conversion of attr%d of entity #%d (%s) - pls check before saving the map", x, i, entnames[e.type]); res |= LWW_ENTATTROVERFLOW; } SCALEATTR(1); SCALEATTR(2); SCALEATTR(3); @@ -889,13 +898,14 @@ bool load_world(char *mname) // still supports all map formats that have if(q.len < cubicsize) break; } ucharbuf uf(rawcubes.getbuf(), rawcubes.length()); - rldecodecubes(uf, world, cubicsize, hdr.version, false); // decode file + res |= rldecodecubes(uf, world, cubicsize, hdr.version, false) ? 0 : LWW_DECODEERR; // decode file c2skeepalive(); // calculate map statistics servsqr *smallworld = createservworld(world, cubicsize); int we = calcmapdims(clmapdims, smallworld, ssize); if(we) conoutf("world error %d", we); + res |= LWW_WORLDERROR * (iabs(we) & 0xf); delete[] smallworld; @@ -930,6 +940,7 @@ bool load_world(char *mname) // still supports all map formats that have calclight(); conoutf("read map %s rev %d (%d milliseconds)", cgzname, hdr.maprevision, watch.elapsed()); conoutf("%s", hdr.maptitle); + mapconfigerror = 0; pushscontext(IEXC_MAPCFG); // untrusted altogether per_idents = false; neverpersist = true; @@ -975,18 +986,18 @@ bool load_world(char *mname) // still supports all map formats that have c2skeepalive(); - loadskymap(true); + res |= loadskymap(true) ? 0 : LWW_MISSINGMEDIA * 1; watch.start(); - loopi(256) if(texuse[i]) lookupworldtexture(i, false); + loopi(256) if(texuse[i] && lookupworldtexture(i, false) == notexture) res |= LWW_MISSINGMEDIA * 2; clientlogf("loaded textures (%d milliseconds)", texloadtime+watch.elapsed()); c2skeepalive(); watch.start(); - preload_mapmodels(false); + res |= preload_mapmodels(false) ? 0 : LWW_MISSINGMEDIA * 4; clientlogf("loaded mapmodels (%d milliseconds)", mdlloadtime+watch.elapsed()); c2skeepalive(); watch.start(); - audiomgr.preloadmapsounds(false); + res |= audiomgr.preloadmapsounds(false) ? 0 : LWW_MISSINGMEDIA * 8; // also set, if soundvol == 0, because no sounds are loaded (or checked) in that case clientlogf("loaded mapsounds (%d milliseconds)", audioloadtime+watch.elapsed()); c2skeepalive(); @@ -1006,15 +1017,15 @@ bool load_world(char *mname) // still supports all map formats that have defformatstring(startmillis)("%d", millis_()); alias("gametimestart", startmillis, true); startmap(mname); - return true; + res |= mapconfigerror; + if(res) conoutf("\f3unresolved problems occured during load_world(), warning: 0x%x", res); + return res; // negative: error (no map loaded), zero: no problem, positive: some problems (bitmask value) } -#ifdef _DEBUG COMMANDF(loadmap, "s", (char *mapname) { - if(!multiplayer()) load_world(mapname); + intret(!multiplayer() ? load_world(mapname) : -42); }); -#endif // support reading and writing binary data in config files