home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2007 September / maximum-cd-2007-09.iso / Assets / data / AssaultCube_v0.93.exe / source / src / worldio.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2007-06-01  |  11.1 KB  |  372 lines

  1. // worldio.cpp: loading & saving of maps and savegames
  2.  
  3. #include "cube.h"
  4.  
  5. void backup(char *name, char *backupname)
  6. {
  7.     remove(backupname);
  8.     rename(name, backupname);
  9. }
  10.  
  11. string cgzname, bakname, pcfname, mcfname; 
  12.  
  13. void setnames(char *name)
  14. {
  15.     string pakname, mapname;
  16.     char *slash = strpbrk(name, "/\\");
  17.     if(slash)
  18.     {
  19.         s_strncpy(pakname, name, slash-name+1);
  20.         s_strcpy(mapname, slash+1);
  21.     }
  22.     else
  23.     {
  24.         s_strcpy(pakname, "maps");
  25.         s_strcpy(mapname, name);
  26.     }
  27.     s_sprintf(cgzname)("packages/%s/%s.cgz",      pakname, mapname);
  28.     s_sprintf(bakname)("packages/%s/%s_%d.BAK",   pakname, mapname, lastmillis);
  29.     s_sprintf(pcfname)("packages/%s/package.cfg", pakname);
  30.     s_sprintf(mcfname)("packages/%s/%s.cfg",      pakname, mapname);
  31.  
  32.     path(cgzname);
  33.     path(bakname);
  34. }
  35.  
  36. // the optimize routines below are here to reduce the detrimental effects of messy mapping by
  37. // setting certain properties (vdeltas and textures) to neighbouring values wherever there is no
  38. // visible difference. This allows the mipmapper to generate more efficient mips.
  39. // the reason it is done on save is to reduce the amount spend in the mipmapper (as that is done
  40. // in realtime).
  41.  
  42. inline bool nhf(sqr *s) { return s->type!=FHF && s->type!=CHF; }
  43.  
  44. void voptimize()        // reset vdeltas on non-hf cubes
  45. {
  46.     loop(x, ssize) loop(y, ssize)
  47.     {
  48.         sqr *s = S(x, y);
  49.         if(x && y) { if(nhf(s) && nhf(S(x-1, y)) && nhf(S(x-1, y-1)) && nhf(S(x, y-1))) s->vdelta = 0; }
  50.         else s->vdelta = 0;
  51.     }
  52. }
  53.  
  54. void topt(sqr *s, bool &wf, bool &uf, int &wt, int &ut)
  55. {
  56.     sqr *o[4];
  57.     o[0] = SWS(s,0,-1,ssize);
  58.     o[1] = SWS(s,0,1,ssize);
  59.     o[2] = SWS(s,1,0,ssize);
  60.     o[3] = SWS(s,-1,0,ssize);
  61.     wf = true;
  62.     uf = true;
  63.     if(SOLID(s))
  64.     {
  65.         loopi(4) if(!SOLID(o[i]))
  66.         {
  67.             wf = false;
  68.             wt = s->wtex;
  69.             ut = s->utex;
  70.             return;
  71.         }
  72.     }
  73.     else
  74.     {
  75.         loopi(4) if(!SOLID(o[i]))
  76.         {
  77.             if(o[i]->floor<s->floor) { wt = s->wtex; wf = false; }
  78.             if(o[i]->ceil>s->ceil)   { ut = s->utex; uf = false; }
  79.         }
  80.     }
  81. }
  82.  
  83. void toptimize() // FIXME: only does 2x2, make atleast for 4x4 also
  84. {
  85.     bool wf[4], uf[4];
  86.     sqr *s[4];
  87.     for(int x = 2; x<ssize-4; x += 2) for(int y = 2; y<ssize-4; y += 2)
  88.     {
  89.         s[0] = S(x,y);
  90.         int wt = s[0]->wtex, ut = s[0]->utex;
  91.         topt(s[0], wf[0], uf[0], wt, ut);
  92.         topt(s[1] = SWS(s[0],0,1,ssize), wf[1], uf[1], wt, ut);
  93.         topt(s[2] = SWS(s[0],1,1,ssize), wf[2], uf[2], wt, ut);
  94.         topt(s[3] = SWS(s[0],1,0,ssize), wf[3], uf[3], wt, ut);
  95.         loopi(4)
  96.         {
  97.             if(wf[i]) s[i]->wtex = wt;
  98.             if(uf[i]) s[i]->utex = ut;
  99.         }
  100.     }
  101. }
  102.  
  103. // these two are used by getmap/sendmap.. transfers compressed maps directly 
  104.  
  105. void writemap(char *mname, int msize, uchar *mdata)
  106. {
  107.     setnames(mname);
  108.     backup(cgzname, bakname);
  109.     FILE *f = fopen(cgzname, "wb");
  110.     if(!f) { conoutf("could not write map to %s", cgzname); return; }
  111.     fwrite(mdata, 1, msize, f);
  112.     fclose(f);
  113.     conoutf("wrote map %s as file %s", mname, cgzname);
  114. }
  115.  
  116. uchar *readmap(char *mname, int *msize)
  117. {
  118.     setnames(mname);
  119.     uchar *mdata = (uchar *)loadfile(cgzname, msize);
  120.     if(!mdata) { conoutf("could not read map %s", cgzname); return NULL; }
  121.     return mdata;
  122. }
  123.  
  124. // save map as .cgz file. uses 2 layers of compression: first does simple run-length
  125. // encoding and leaves out data for certain kinds of cubes, then zlib removes the
  126. // last bits of redundancy. Both passes contribute greatly to the miniscule map sizes.
  127.  
  128. void save_world(char *mname)
  129. {
  130.     if(!*mname) mname = getclientmap();
  131.     extern bool securemapcheck(char *map);
  132.     if(securemapcheck(mname)) return;
  133.     voptimize();
  134.     toptimize();
  135.     setnames(mname);
  136.     backup(cgzname, bakname);
  137.     gzFile f = gzopen(cgzname, "wb9");
  138.     if(!f) { conoutf("could not write map to %s", cgzname); return; }
  139.     hdr.version = MAPVERSION;
  140.     hdr.numents = 0;
  141.     loopv(ents) if(ents[i].type!=NOTUSED) hdr.numents++;
  142.     header tmp = hdr;
  143.     endianswap(&tmp.version, sizeof(int), 4);
  144.     endianswap(&tmp.waterlevel, sizeof(int), 16);
  145.     gzwrite(f, &tmp, sizeof(header));
  146.     loopv(ents) 
  147.     {
  148.         if(ents[i].type!=NOTUSED) 
  149.         {
  150.             entity tmp = ents[i];
  151.             endianswap(&tmp, sizeof(short), 4);
  152.             gzwrite(f, &tmp, sizeof(persistent_entity));
  153.         }
  154.     }
  155.     sqr *t = NULL;
  156.     int sc = 0;
  157.     #define spurge while(sc) { gzputc(f, 255); if(sc>255) { gzputc(f, 255); sc -= 255; } else { gzputc(f, sc); sc = 0; } }
  158.     loopk(cubicsize)
  159.     {
  160.         sqr *s = &world[k];
  161.         #define c(f) (s->f==t->f)
  162.         // 4 types of blocks, to compress a bit:
  163.         // 255 (2): same as previous block + count
  164.         // 254 (3): same as previous, except light // deprecated
  165.         // SOLID (5)
  166.         // anything else (9)
  167.  
  168.         if(SOLID(s))
  169.         {
  170.             if(t && c(type) && c(wtex) && c(vdelta))
  171.             {
  172.                 sc++;
  173.             }
  174.             else
  175.             {
  176.                 spurge;
  177.                 gzputc(f, s->type);
  178.                 gzputc(f, s->wtex);
  179.                 gzputc(f, s->vdelta);
  180.             }
  181.         }
  182.         else
  183.         {
  184.             if(t && c(type) && c(floor) && c(ceil) && c(ctex) && c(ftex) && c(utex) && c(wtex) && c(vdelta) && c(tag))
  185.             {
  186.                 sc++;
  187.             }
  188.             else
  189.             {
  190.                 spurge;
  191.                 gzputc(f, s->type);
  192.                 gzputc(f, s->floor);
  193.                 gzputc(f, s->ceil);
  194.                 gzputc(f, s->wtex);
  195.                 gzputc(f, s->ftex);
  196.                 gzputc(f, s->ctex);
  197.                 gzputc(f, s->vdelta);
  198.                 gzputc(f, s->utex);
  199.                 gzputc(f, s->tag);
  200.             }
  201.         }
  202.         t = s;
  203.     }
  204.     spurge;
  205.     gzclose(f);
  206.     conoutf("wrote map file %s", cgzname);
  207. }
  208.  
  209. extern void preparectf(bool cleanonly = false);
  210.  
  211. void load_world(char *mname)        // still supports all map formats that have existed since the earliest cube betas!
  212. {
  213.     preparectf(true);
  214.     stopifrecording();
  215.     cleardlights();
  216.     pruneundos();
  217.     setnames(mname);
  218.     gzFile f = gzopen(cgzname, "rb9");
  219.     if(!f) { conoutf("could not read map %s", cgzname); return; }
  220.     loadingscreen();
  221.     gzread(f, &hdr, sizeof(header)-sizeof(int)*16);
  222.     endianswap(&hdr.version, sizeof(int), 4);
  223.     if(strncmp(hdr.head, "CUBE", 4)!=0  && strncmp(hdr.head, "ACMP",4)!=0) fatal("while reading map: header malformatted");
  224.     if(hdr.version>MAPVERSION) fatal("this map requires a newer version of cube");
  225.     if(hdr.sfactor<SMALLEST_FACTOR || hdr.sfactor>LARGEST_FACTOR) fatal("illegal map size");
  226.     if(hdr.version>=4)
  227.     {
  228.         gzread(f, &hdr.waterlevel, sizeof(int)*16);
  229.         endianswap(&hdr.waterlevel, sizeof(int), 16);
  230.         if(!hdr.watercolor[3]) setwatercolor();
  231.     }
  232.     else
  233.     {
  234.         hdr.waterlevel = -100000;
  235.     }
  236.     ents.setsize(0);
  237.     loopi(hdr.numents)
  238.     {
  239.         entity &e = ents.add();
  240.         gzread(f, &e, sizeof(persistent_entity));
  241.         endianswap(&e, sizeof(short), 4);
  242.         e.spawned = false;
  243.         if(e.type==LIGHT)
  244.         {
  245.             if(!e.attr2) e.attr2 = 255;  // needed for MAPVERSION<=2
  246.             if(e.attr1>32) e.attr1 = 32; // 12_03 and below
  247.         }
  248.         
  249.         if (hdr.version<MAPVERSION  && strncmp(hdr.head,"CUBE",4)==0)  //only render lights, pl starts and map models on old maps
  250.         {
  251.                 switch(e.type)
  252.                 {
  253.                     case 1: //old light
  254.                         e.type=LIGHT;
  255.                         break;
  256.                     case 2: //old player start
  257.                         e.type=PLAYERSTART;
  258.                         break;
  259.                     case 3:
  260.                         case 4:
  261.                     case 5:
  262.                     case 6:
  263.                         e.type=I_AMMO;
  264.                         break;
  265.                     case 7: //old health
  266.                         e.type=I_HEALTH;
  267.                         break;
  268.                     case 8: //old boost
  269.                         e.type=I_HEALTH;
  270.                         break;
  271.                     case 9: //armor
  272.                     case 10: //armor
  273.                         e.type=I_ARMOUR;
  274.                         break;
  275.                     case 11: //quad
  276.                         e.type=I_AKIMBO;
  277.                         break;                
  278.                     case 14: //old map model
  279.                         e.type=MAPMODEL;
  280.                         break;
  281.                     default:
  282.                         e.type=NOTUSED;
  283.                 }
  284.         }
  285.     }
  286.     delete[] world;
  287.     setupworld(hdr.sfactor);
  288.     if(!mapinfo.numelems || (mapinfo.access(mname) && !cmpf(cgzname, mapinfo[mname]))) world = (sqr *)ents.getbuf();
  289.     c2skeepalive();
  290.     char texuse[256];
  291.     loopi(256) texuse[i] = 0;
  292.     sqr *t = NULL;
  293.     loopk(cubicsize)
  294.     {
  295.         sqr *s = &world[k];
  296.         int type = gzgetc(f);
  297.         switch(type)
  298.         {
  299.             case 255:  
  300.             {
  301.                 int n = gzgetc(f);
  302.                 for(int i = 0; i<n; i++, k++) memcpy(&world[k], t, sizeof(sqr));
  303.                 k--;
  304.                 break;
  305.             }
  306.             case 254: // only in MAPVERSION<=2
  307.             {
  308.                 memcpy(s, t, sizeof(sqr));
  309.                 s->r = s->g = s->b = gzgetc(f);
  310.                 gzgetc(f);
  311.                 break;
  312.             }
  313.             case SOLID:
  314.             {
  315.                 s->type = SOLID;
  316.                 s->wtex = gzgetc(f);
  317.                 s->vdelta = gzgetc(f);
  318.                 if(hdr.version<=2) { gzgetc(f); gzgetc(f); }
  319.                 s->ftex = DEFAULT_FLOOR;
  320.                 s->ctex = DEFAULT_CEIL;
  321.                 s->utex = s->wtex;
  322.                 s->tag = 0;
  323.                 s->floor = 0;
  324.                 s->ceil = 16;
  325.                 break;
  326.             }
  327.             default:
  328.             {
  329.                 if(type<0 || type>=MAXTYPE)
  330.                 {
  331.                     s_sprintfd(t)("%d @ %d", type, k);
  332.                     fatal("while reading map: type out of range: ", t);
  333.                 }
  334.                 s->type = type;
  335.                 s->floor = gzgetc(f);
  336.                 s->ceil = gzgetc(f);
  337.                 if(s->floor>=s->ceil) s->floor = s->ceil-1;  // for pre 12_13
  338.                 s->wtex = gzgetc(f);
  339.                 s->ftex = gzgetc(f);
  340.                 s->ctex = gzgetc(f);
  341.                 if(hdr.version<=2) { gzgetc(f); gzgetc(f); }
  342.                 s->vdelta = gzgetc(f);
  343.                 s->utex = (hdr.version>=2) ? gzgetc(f) : s->wtex;
  344.                 s->tag = (hdr.version>=5) ? gzgetc(f) : 0;
  345.                 s->type = type;
  346.             }
  347.         }
  348.         s->defer = 0;
  349.         t = s;
  350.         texuse[s->wtex] = 1;
  351.         if(!SOLID(s)) texuse[s->utex] = texuse[s->ftex] = texuse[s->ctex] = 1;
  352.     }
  353.     gzclose(f);
  354.     c2skeepalive();
  355.     calclight();
  356.     conoutf("read map %s (%d milliseconds)", cgzname, SDL_GetTicks()-lastmillis);
  357.     conoutf("%s", hdr.maptitle);
  358.     startmap(mname);
  359.     execfile("config/default_map_settings.cfg");
  360.     execfile(pcfname);
  361.     execfile(mcfname);
  362.     int xs, ys;
  363.     c2skeepalive();
  364.     loopi(256) if(texuse[i]) lookuptexture(i, xs, ys);
  365.     c2skeepalive();
  366.     preload_mapmodels();
  367.     c2skeepalive();
  368. }
  369.  
  370. COMMANDN(savemap, save_world, ARG_1STR);
  371.  
  372.