Advertisement
Guest User

Untitled

a guest
May 23rd, 2017
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 37.47 KB | None | 0 0
  1.  
  2. // worldio.cpp: loading & saving of maps and savegames
  3.  
  4. #include "engine.h"
  5. #include "game.h" // INTENSITY
  6.  
  7. // INTENSITY
  8. #include "intensity.h"
  9. #include "world_system.h"
  10. #include "message_system.h"
  11. #ifdef CLIENT
  12. #include "client_system.h"
  13. #endif
  14. #include "intensity_physics.h"
  15.  
  16.  
  17. void backup(char *name, char *backupname)
  18. {
  19. string backupfile;
  20. copystring(backupfile, findfile(backupname, "wb"));
  21. remove(backupfile);
  22. rename(findfile(name, "wb"), backupfile);
  23. }
  24.  
  25. string ogzname, bakname, cfgname, picname;
  26.  
  27. VARP(savebak, 0, 2, 2);
  28.  
  29. void cutogz(char *s)
  30. {
  31. char *ogzp = strstr(s, ".ogz");
  32. if(ogzp) *ogzp = '\0';
  33. }
  34.  
  35. void getmapfilenames(const char *fname, const char *cname, char *pakname, char *mapname, char *cfgname)
  36. {
  37. if(!cname) cname = fname;
  38. string name;
  39. copystring(name, cname, 100);
  40. cutogz(name);
  41. char *slash = strpbrk(name, "/\\");
  42. if(slash)
  43. {
  44. copystring(pakname, name, slash-name+1);
  45. copystring(cfgname, slash+1);
  46. }
  47. else
  48. {
  49. copystring(pakname, "base");
  50. copystring(cfgname, name);
  51. }
  52. if(strpbrk(fname, "/\\")) copystring(mapname, fname);
  53. else formatstring(mapname)("base/%s", fname);
  54. cutogz(mapname);
  55. }
  56.  
  57. void setmapfilenames(const char *fname, const char *cname = 0)
  58. {
  59. string pakname, mapname, mcfgname;
  60. getmapfilenames(fname, cname, pakname, mapname, mcfgname);
  61.  
  62. formatstring(ogzname)("packages/%s.ogz", mapname);
  63. if(savebak==1) formatstring(bakname)("packages/%s.BAK", mapname);
  64. else formatstring(bakname)("packages/%s_%d.BAK", mapname, totalmillis);
  65. formatstring(cfgname)("packages/%s/%s.cfg", pakname, mcfgname);
  66. formatstring(picname)("packages/%s.jpg", mapname);
  67.  
  68. path(ogzname);
  69. path(bakname);
  70. path(cfgname);
  71. path(picname);
  72. }
  73.  
  74. void mapcfgname()
  75. {
  76. const char *mname = game::getclientmap();
  77. if(!*mname) mname = "untitled";
  78.  
  79. string pakname, mapname, mcfgname;
  80. getmapfilenames(mname, NULL, pakname, mapname, mcfgname);
  81. defformatstring(cfgname)("packages/%s/%s.js", pakname, mcfgname); // INTENSITY: Switched to .js TODO: More files
  82. path(cfgname);
  83. result(cfgname);
  84. }
  85.  
  86. COMMAND(mapcfgname, "");
  87.  
  88. enum { OCTSAV_CHILDREN = 0, OCTSAV_EMPTY, OCTSAV_SOLID, OCTSAV_NORMAL, OCTSAV_LODCUBE };
  89.  
  90. void savec(cube *c, stream *f, bool nolms)
  91. {
  92. loopi(8)
  93. {
  94. if(c[i].children && (!c[i].ext || !c[i].ext->surfaces))
  95. {
  96. f->putchar(OCTSAV_CHILDREN);
  97. savec(c[i].children, f, nolms);
  98. }
  99. else
  100. {
  101. int oflags = 0;
  102. if(c[i].ext && c[i].ext->merged) oflags |= 0x80;
  103. if(c[i].children) f->putchar(oflags | OCTSAV_LODCUBE);
  104. else if(isempty(c[i])) f->putchar(oflags | OCTSAV_EMPTY);
  105. else if(isentirelysolid(c[i])) f->putchar(oflags | OCTSAV_SOLID);
  106. else
  107. {
  108. f->putchar(oflags | OCTSAV_NORMAL);
  109. f->write(c[i].edges, 12);
  110. }
  111. loopj(6) f->putlil<ushort>(c[i].texture[j]);
  112. uchar mask = 0;
  113. if(c[i].ext)
  114. {
  115. if(c[i].ext->material != MAT_AIR) mask |= 0x80;
  116. if(c[i].ext->normals && !nolms)
  117. {
  118. mask |= 0x40;
  119. loopj(6) if(c[i].ext->normals[j].normals[0] != bvec(128, 128, 128)) mask |= 1 << j;
  120. }
  121. }
  122. // save surface info for lighting
  123. if(!c[i].ext || !c[i].ext->surfaces || nolms)
  124. {
  125. f->putchar(mask);
  126. if(c[i].ext)
  127. {
  128. if(c[i].ext->material != MAT_AIR) f->putchar(c[i].ext->material);
  129. if(c[i].ext->normals && !nolms) loopj(6) if(mask & (1 << j))
  130. {
  131. loopk(sizeof(surfaceinfo)) f->putchar(0);
  132. f->write(&c[i].ext->normals[j], sizeof(surfacenormals));
  133. }
  134. }
  135. }
  136. else
  137. {
  138. int numsurfs = 6;
  139. loopj(6)
  140. {
  141. surfaceinfo &surface = c[i].ext->surfaces[j];
  142. if(surface.lmid >= LMID_RESERVED || surface.layer!=LAYER_TOP)
  143. {
  144. mask |= 1 << j;
  145. if(surface.layer&LAYER_BLEND) numsurfs++;
  146. }
  147. }
  148. f->putchar(mask);
  149. if(c[i].ext->material != MAT_AIR) f->putchar(c[i].ext->material);
  150. loopj(numsurfs) if(j >= 6 || mask & (1 << j))
  151. {
  152. surfaceinfo tmp = c[i].ext->surfaces[j];
  153. lilswap(&tmp.x, 2);
  154. f->write(&tmp, sizeof(surfaceinfo));
  155. if(j < 6 && c[i].ext->normals) f->write(&c[i].ext->normals[j], sizeof(surfacenormals));
  156. }
  157. }
  158. if(c[i].ext && c[i].ext->merged)
  159. {
  160. f->putchar(c[i].ext->merged | (c[i].ext->mergeorigin ? 0x80 : 0));
  161. if(c[i].ext->mergeorigin)
  162. {
  163. f->putchar(c[i].ext->mergeorigin);
  164. int index = 0;
  165. loopj(6) if(c[i].ext->mergeorigin&(1<<j))
  166. {
  167. mergeinfo tmp = c[i].ext->merges[index++];
  168. lilswap(&tmp.u1, 4);
  169. f->write(&tmp, sizeof(mergeinfo));
  170. }
  171. }
  172. }
  173. if(c[i].children) savec(c[i].children, f, nolms);
  174. }
  175. }
  176. }
  177.  
  178. cube *loadchildren(stream *f);
  179.  
  180. void loadc(stream *f, cube &c)
  181. {
  182. bool haschildren = false;
  183. int octsav = f->getchar();
  184. switch(octsav&0x7)
  185. {
  186. case OCTSAV_CHILDREN:
  187. c.children = loadchildren(f);
  188. return;
  189.  
  190. case OCTSAV_LODCUBE: haschildren = true; break;
  191. case OCTSAV_EMPTY: emptyfaces(c); break;
  192. case OCTSAV_SOLID: solidfaces(c); break;
  193. case OCTSAV_NORMAL: f->read(c.edges, 12); break;
  194.  
  195. default:
  196. fatal("garbage in map");
  197. }
  198. loopi(6) c.texture[i] = mapversion<14 ? f->getchar() : f->getlil<ushort>();
  199. if(mapversion < 7) f->seek(3, SEEK_CUR);
  200. else
  201. {
  202. uchar mask = f->getchar();
  203. if(mask & 0x80)
  204. {
  205. int mat = f->getchar();
  206. if(mapversion < 27)
  207. {
  208. static uchar matconv[] = { MAT_AIR, MAT_WATER, MAT_CLIP, MAT_GLASS|MAT_CLIP, MAT_NOCLIP, MAT_LAVA|MAT_DEATH, MAT_GAMECLIP, MAT_DEATH };
  209. mat = size_t(mat) < sizeof(matconv)/sizeof(matconv[0]) ? matconv[mat] : MAT_AIR;
  210. }
  211. ext(c).material = mat;
  212. }
  213. if(mask & 0x3F)
  214. {
  215. uchar lit = 0, bright = 0;
  216. static surfaceinfo surfaces[12];
  217. memset(surfaces, 0, 6*sizeof(surfaceinfo));
  218. if(mask & 0x40) newnormals(c);
  219. int numsurfs = 6;
  220. loopi(numsurfs)
  221. {
  222. if(i >= 6 || mask & (1 << i))
  223. {
  224. f->read(&surfaces[i], sizeof(surfaceinfo));
  225. lilswap(&surfaces[i].x, 2);
  226. if(mapversion < 10) ++surfaces[i].lmid;
  227. if(mapversion < 18)
  228. {
  229. if(surfaces[i].lmid >= LMID_AMBIENT1) ++surfaces[i].lmid;
  230. if(surfaces[i].lmid >= LMID_BRIGHT1) ++surfaces[i].lmid;
  231. }
  232. if(mapversion < 19)
  233. {
  234. if(surfaces[i].lmid >= LMID_DARK) surfaces[i].lmid += 2;
  235. }
  236. if(i < 6)
  237. {
  238. if(mask & 0x40) f->read(&c.ext->normals[i], sizeof(surfacenormals));
  239. if(surfaces[i].layer != LAYER_TOP) lit |= 1 << i;
  240. else if(surfaces[i].lmid == LMID_BRIGHT) bright |= 1 << i;
  241. else if(surfaces[i].lmid != LMID_AMBIENT) lit |= 1 << i;
  242. if(surfaces[i].layer&LAYER_BLEND) numsurfs++;
  243. }
  244. }
  245. else surfaces[i].lmid = LMID_AMBIENT;
  246. }
  247. if(lit) newsurfaces(c, surfaces, numsurfs);
  248. else if(bright) brightencube(c);
  249. }
  250. if(mapversion >= 20)
  251. {
  252. if(octsav&0x80)
  253. {
  254. int merged = f->getchar();
  255. ext(c).merged = merged&0x3F;
  256. if(merged&0x80)
  257. {
  258. c.ext->mergeorigin = f->getchar();
  259. int nummerges = 0;
  260. loopi(6) if(c.ext->mergeorigin&(1<<i)) nummerges++;
  261. if(nummerges)
  262. {
  263. c.ext->merges = new mergeinfo[nummerges];
  264. loopi(nummerges)
  265. {
  266. mergeinfo *m = &c.ext->merges[i];
  267. f->read(m, sizeof(mergeinfo));
  268. lilswap(&m->u1, 4);
  269. if(mapversion <= 25)
  270. {
  271. int uorigin = m->u1 & 0xE000, vorigin = m->v1 & 0xE000;
  272. m->u1 = (m->u1 - uorigin) << 2;
  273. m->u2 = (m->u2 - uorigin) << 2;
  274. m->v1 = (m->v1 - vorigin) << 2;
  275. m->v2 = (m->v2 - vorigin) << 2;
  276. }
  277. }
  278. }
  279. }
  280. }
  281. }
  282. }
  283. c.children = (haschildren ? loadchildren(f) : NULL);
  284. }
  285.  
  286. cube *loadchildren(stream *f)
  287. {
  288. cube *c = newcubes();
  289. loopi(8) loadc(f, c[i]);
  290. // TODO: remip c from children here
  291. return c;
  292. }
  293.  
  294. VAR(dbgvars, 0, 0, 1);
  295.  
  296. void savevslot(stream *f, VSlot &vs, int prev)
  297. {
  298. f->putlil<int>(vs.changed);
  299. f->putlil<int>(prev);
  300. if(vs.changed & (1<<VSLOT_SHPARAM))
  301. {
  302. f->putlil<ushort>(vs.params.length());
  303. loopv(vs.params)
  304. {
  305. ShaderParam &p = vs.params[i];
  306. f->putlil<ushort>(strlen(p.name));
  307. f->write(p.name, strlen(p.name));
  308. loopk(4) f->putlil<float>(p.val[k]);
  309. }
  310. }
  311. if(vs.changed & (1<<VSLOT_SCALE)) f->putlil<float>(vs.scale);
  312. if(vs.changed & (1<<VSLOT_ROTATION)) f->putlil<int>(vs.rotation);
  313. if(vs.changed & (1<<VSLOT_OFFSET))
  314. {
  315. f->putlil<int>(vs.xoffset);
  316. f->putlil<int>(vs.yoffset);
  317. }
  318. if(vs.changed & (1<<VSLOT_SCROLL))
  319. {
  320. f->putlil<float>(vs.scrollS);
  321. f->putlil<float>(vs.scrollT);
  322. }
  323. if(vs.changed & (1<<VSLOT_LAYER)) f->putlil<int>(vs.layer);
  324. if(vs.changed & (1<<VSLOT_ALPHA))
  325. {
  326. f->putlil<float>(vs.alphafront);
  327. f->putlil<float>(vs.alphaback);
  328. }
  329. if(vs.changed & (1<<VSLOT_COLOR))
  330. {
  331. loopk(3) f->putlil<float>(vs.colorscale[k]);
  332. }
  333. }
  334.  
  335. void savevslots(stream *f, int numvslots)
  336. {
  337. if(vslots.empty()) return;
  338. int *prev = new int[numvslots];
  339. memset(prev, -1, numvslots*sizeof(int));
  340. loopi(numvslots)
  341. {
  342. VSlot *vs = vslots[i];
  343. if(vs->changed) continue;
  344. for(;;)
  345. {
  346. VSlot *cur = vs;
  347. do vs = vs->next; while(vs && vs->index >= numvslots);
  348. if(!vs) break;
  349. prev[vs->index] = cur->index;
  350. }
  351. }
  352. int lastroot = 0;
  353. loopi(numvslots)
  354. {
  355. VSlot &vs = *vslots[i];
  356. if(!vs.changed) continue;
  357. if(lastroot < i) f->putlil<int>(-(i - lastroot));
  358. savevslot(f, vs, prev[i]);
  359. lastroot = i+1;
  360. }
  361. if(lastroot < numvslots) f->putlil<int>(-(numvslots - lastroot));
  362. delete[] prev;
  363. }
  364.  
  365. void loadvslot(stream *f, VSlot &vs, int changed)
  366. {
  367. vs.changed = changed;
  368. if(vs.changed & (1<<VSLOT_SHPARAM))
  369. {
  370. int numparams = f->getlil<ushort>();
  371. string name;
  372. loopi(numparams)
  373. {
  374. ShaderParam &p = vs.params.add();
  375. int nlen = f->getlil<ushort>();
  376. f->read(name, min(nlen, MAXSTRLEN-1));
  377. name[min(nlen, MAXSTRLEN-1)] = '\0';
  378. if(nlen >= MAXSTRLEN) f->seek(nlen - (MAXSTRLEN-1), SEEK_CUR);
  379. p.name = getshaderparamname(name);
  380. p.type = SHPARAM_LOOKUP;
  381. p.index = -1;
  382. p.loc = -1;
  383. loopk(4) p.val[k] = f->getlil<float>();
  384. }
  385. }
  386. if(vs.changed & (1<<VSLOT_SCALE)) vs.scale = f->getlil<float>();
  387. if(vs.changed & (1<<VSLOT_ROTATION)) vs.rotation = f->getlil<int>();
  388. if(vs.changed & (1<<VSLOT_OFFSET))
  389. {
  390. vs.xoffset = f->getlil<int>();
  391. vs.yoffset = f->getlil<int>();
  392. }
  393. if(vs.changed & (1<<VSLOT_SCROLL))
  394. {
  395. vs.scrollS = f->getlil<float>();
  396. vs.scrollT = f->getlil<float>();
  397. }
  398. if(vs.changed & (1<<VSLOT_LAYER)) vs.layer = f->getlil<int>();
  399. if(vs.changed & (1<<VSLOT_ALPHA))
  400. {
  401. vs.alphafront = f->getlil<float>();
  402. vs.alphaback = f->getlil<float>();
  403. }
  404. if(vs.changed & (1<<VSLOT_COLOR))
  405. {
  406. loopk(3) vs.colorscale[k] = f->getlil<float>();
  407. }
  408. }
  409.  
  410. void loadvslots(stream *f, int numvslots)
  411. {
  412. int *prev = new int[numvslots];
  413. memset(prev, -1, numvslots*sizeof(int));
  414. while(numvslots > 0)
  415. {
  416. int changed = f->getlil<int>();
  417. if(changed < 0)
  418. {
  419. loopi(-changed) vslots.add(new VSlot(NULL, vslots.length()));
  420. numvslots += changed;
  421. }
  422. else
  423. {
  424. prev[vslots.length()] = f->getlil<int>();
  425. loadvslot(f, *vslots.add(new VSlot(NULL, vslots.length())), changed);
  426. numvslots--;
  427. }
  428. }
  429. loopv(vslots) if(vslots.inrange(prev[i])) vslots[prev[i]]->next = vslots[i];
  430. delete[] prev;
  431. }
  432.  
  433. bool save_world(const char *mname, bool nolms)
  434. {
  435. if(!*mname) mname = game::getclientmap();
  436. setmapfilenames(*mname ? mname : "untitled");
  437. if(savebak) backup(ogzname, bakname);
  438. stream *f = opengzfile(ogzname, "wb");
  439. if(!f) { conoutf(CON_WARN, "could not write map to %s", ogzname); return false; }
  440.  
  441. int numvslots = vslots.length();
  442. if(!nolms && !multiplayer(false))
  443. {
  444. numvslots = compactvslots();
  445. allchanged();
  446. }
  447.  
  448. renderprogress(0, "saving map...");
  449.  
  450. octaheader hdr;
  451. memcpy(hdr.magic, "OCTA", 4);
  452. hdr.version = MAPVERSION;
  453. hdr.headersize = sizeof(hdr);
  454. hdr.worldsize = worldsize;
  455. hdr.numents = 0;
  456. // const vector<extentity *> &ents = entities::getents(); // INTENSITY: No ents in .ogz
  457. // loopv(ents) if(ents[i]->type!=ET_EMPTY || nolms) hdr.numents++; // INTENSITY: No ents in .ogz
  458. hdr.numpvs = nolms ? 0 : getnumviewcells();
  459. hdr.lightmaps = nolms ? 0 : lightmaps.length();
  460. hdr.blendmap = shouldsaveblendmap();
  461. hdr.numvars = 0;
  462. hdr.numvslots = numvslots;
  463. enumerate(*idents, ident, id,
  464. {
  465. if((id.type == ID_VAR || id.type == ID_FVAR || id.type == ID_SVAR) && id.flags&IDF_OVERRIDE && !(id.flags&IDF_READONLY) && id.override!=NO_OVERRIDE) hdr.numvars++;
  466. });
  467. lilswap(&hdr.version, 9);
  468. f->write(&hdr, sizeof(hdr));
  469.  
  470. enumerate(*idents, ident, id,
  471. {
  472. if((id.type!=ID_VAR && id.type!=ID_FVAR && id.type!=ID_SVAR) || !(id.flags&IDF_OVERRIDE) || id.flags&IDF_READONLY || id.override==NO_OVERRIDE) continue;
  473. f->putchar(id.type);
  474. f->putlil<ushort>(strlen(id.name));
  475. f->write(id.name, strlen(id.name));
  476. switch(id.type)
  477. {
  478. case ID_VAR:
  479. if(dbgvars) conoutf(CON_DEBUG, "wrote var %s: %d", id.name, *id.storage.i);
  480. f->putlil<int>(*id.storage.i);
  481. break;
  482.  
  483. case ID_FVAR:
  484. if(dbgvars) conoutf(CON_DEBUG, "wrote fvar %s: %f", id.name, *id.storage.f);
  485. f->putlil<float>(*id.storage.f);
  486. break;
  487.  
  488. case ID_SVAR:
  489. if(dbgvars) conoutf(CON_DEBUG, "wrote svar %s: %s", id.name, *id.storage.s);
  490. f->putlil<ushort>(strlen(*id.storage.s));
  491. f->write(*id.storage.s, strlen(*id.storage.s));
  492. break;
  493. }
  494. });
  495.  
  496. if(dbgvars) conoutf(CON_DEBUG, "wrote %d vars", hdr.numvars);
  497.  
  498. f->putchar((int)strlen(game::gameident()));
  499. f->write(game::gameident(), (int)strlen(game::gameident())+1);
  500. f->putlil<ushort>(entities::extraentinfosize());
  501. vector<char> extras;
  502. game::writegamedata(extras);
  503. f->putlil<ushort>(extras.length());
  504. f->write(extras.getbuf(), extras.length());
  505.  
  506. f->putlil<ushort>(texmru.length());
  507. loopv(texmru) f->putlil<ushort>(texmru[i]);
  508. #if 0 // INTENSITY: No ents in .ogz
  509. char *ebuf = new char[entities::extraentinfosize()];
  510. loopv(ents)
  511. {
  512. if(ents[i]->type!=ET_EMPTY || nolms)
  513. {
  514. entity tmp = *ents[i];
  515. lilswap(&tmp.o.x, 3);
  516. lilswap(&tmp.attr1, 5);
  517. f->write(&tmp, sizeof(entity));
  518. entities::writeent(*ents[i], ebuf);
  519. if(entities::extraentinfosize()) f->write(ebuf, entities::extraentinfosize());
  520. }
  521. }
  522. delete[] ebuf;
  523. #endif // 0
  524.  
  525. savevslots(f, numvslots);
  526.  
  527. savec(worldroot, f, nolms);
  528. if(!nolms)
  529. {
  530. loopv(lightmaps)
  531. {
  532. LightMap &lm = lightmaps[i];
  533. f->putchar(lm.type | (lm.unlitx>=0 ? 0x80 : 0));
  534. if(lm.unlitx>=0)
  535. {
  536. f->putlil<ushort>(ushort(lm.unlitx));
  537. f->putlil<ushort>(ushort(lm.unlity));
  538. }
  539. f->write(lm.data, lm.bpp*LM_PACKW*LM_PACKH);
  540. }
  541. if(getnumviewcells()>0) savepvs(f);
  542. }
  543. if(shouldsaveblendmap()) saveblendmap(f);
  544.  
  545. delete f;
  546. conoutf("wrote map file %s", ogzname);
  547.  
  548. return true;
  549. }
  550.  
  551. static uint mapcrc = 0;
  552.  
  553. uint getmapcrc() { return mapcrc; }
  554.  
  555. static void swapXZ(cube *c)
  556. {
  557. loopi(8)
  558. {
  559. swap(c[i].faces[0], c[i].faces[2]);
  560. swap(c[i].texture[0], c[i].texture[4]);
  561. swap(c[i].texture[1], c[i].texture[5]);
  562. if(c[i].ext && c[i].ext->surfaces)
  563. {
  564. swap(c[i].ext->surfaces[0], c[i].ext->surfaces[4]);
  565. swap(c[i].ext->surfaces[1], c[i].ext->surfaces[5]);
  566. }
  567. if(c[i].children) swapXZ(c[i].children);
  568. }
  569. }
  570.  
  571. static void fixoversizedcubes(cube *c, int size)
  572. {
  573. if(size <= 0x1000) return;
  574. loopi(8)
  575. {
  576. if(!c[i].children) subdividecube(c[i], true, false);
  577. fixoversizedcubes(c[i].children, size>>1);
  578. }
  579. }
  580.  
  581. bool finish_load_world(); // INTENSITY: Added this, and use it inside load_world
  582.  
  583. const char *_saved_mname = NULL; // INTENSITY
  584. const char *_saved_cname = NULL; // INTENSITY
  585. octaheader *saved_hdr = NULL; // INTENSITY
  586.  
  587. bool load_world(const char *mname, const char *cname) // still supports all map formats that have existed since the earliest cube betas!
  588. {
  589. WorldSystem::loadingWorld = true; // INTENSITY
  590. LogicSystem::init(); // INTENSITY: Start our game data system, wipe all existing LogicEntities, and add the player
  591.  
  592. #if 0 // INTENSITY
  593. int loadingstart = SDL_GetTicks();
  594. #endif
  595. setmapfilenames(mname, cname);
  596.  
  597. _saved_mname = mname; // INTENSITY
  598. _saved_cname = cname; // INTENSITY
  599.  
  600. stream *f = opengzfile(ogzname, "rb");
  601. if(!f) { conoutf(CON_ERROR, "could not read map %s", ogzname); return false; }
  602. saved_hdr = new octaheader; // INTENSITY
  603. octaheader& hdr = *saved_hdr; // INTENSITY
  604. if(f->read(&hdr, 7*sizeof(int))!=int(7*sizeof(int))) { conoutf(CON_ERROR, "map %s has malformatted header", ogzname); delete f; return false; }
  605. lilswap(&hdr.version, 6);
  606. if(strncmp(hdr.magic, "OCTA", 4)!=0 || hdr.worldsize <= 0|| hdr.numents < 0) { conoutf(CON_ERROR, "map %s has malformatted header", ogzname); delete f; return false; }
  607. if(hdr.version>MAPVERSION) { conoutf(CON_ERROR, "map %s requires a newer version of Cube 2: Sauerbraten", ogzname); delete f; return false; }
  608. compatheader chdr;
  609. if(hdr.version <= 28)
  610. {
  611. if(f->read(&chdr.lightprecision, sizeof(chdr) - 7*sizeof(int)) != int(sizeof(chdr) - 7*sizeof(int))) { conoutf(CON_ERROR, "map %s has malformatted header", ogzname); delete f; return false; }
  612. }
  613. else
  614. {
  615. int extra = 0;
  616. if(hdr.version <= 29) extra++;
  617. if(f->read(&hdr.blendmap, sizeof(hdr) - (7+extra)*sizeof(int)) != int(sizeof(hdr) - (7+extra)*sizeof(int))) { conoutf(CON_ERROR, "map %s has malformatted header", ogzname); delete f; return false; }
  618. }
  619.  
  620. resetmap();
  621. Texture *mapshot = textureload(picname, 3, true, false);
  622. renderbackground("loading...", mapshot, mname, game::getmapinfo());
  623.  
  624. setvar("mapversion", hdr.version, true, false);
  625.  
  626. if(hdr.version <= 28)
  627. {
  628. lilswap(&chdr.lightprecision, 3);
  629. if(hdr.version<=20) conoutf(CON_WARN, "loading older / less efficient map format, may benefit from \"calclight\", then \"savecurrentmap\"");
  630. if(chdr.lightprecision) setvar("lightprecision", chdr.lightprecision);
  631. if(chdr.lighterror) setvar("lighterror", chdr.lighterror);
  632. if(chdr.bumperror) setvar("bumperror", chdr.bumperror);
  633. setvar("lightlod", chdr.lightlod);
  634. if(chdr.ambient) setvar("ambient", chdr.ambient);
  635. setvar("skylight", (int(chdr.skylight[0])<<16) | (int(chdr.skylight[1])<<8) | int(chdr.skylight[2]));
  636. setvar("watercolour", (int(chdr.watercolour[0])<<16) | (int(chdr.watercolour[1])<<8) | int(chdr.watercolour[2]), true);
  637. setvar("waterfallcolour", (int(chdr.waterfallcolour[0])<<16) | (int(chdr.waterfallcolour[1])<<8) | int(chdr.waterfallcolour[2]));
  638. setvar("lavacolour", (int(chdr.lavacolour[0])<<16) | (int(chdr.lavacolour[1])<<8) | int(chdr.lavacolour[2]));
  639. setvar("fullbright", 0, true);
  640. if(chdr.lerpsubdivsize || chdr.lerpangle) setvar("lerpangle", chdr.lerpangle);
  641. if(chdr.lerpsubdivsize)
  642. {
  643. setvar("lerpsubdiv", chdr.lerpsubdiv);
  644. setvar("lerpsubdivsize", chdr.lerpsubdivsize);
  645. }
  646. setsvar("maptitle", chdr.maptitle);
  647. hdr.blendmap = chdr.blendmap;
  648. hdr.numvars = 0;
  649. hdr.numvslots = 0;
  650. }
  651. else
  652. {
  653. lilswap(&hdr.blendmap, 2);
  654. if(hdr.version <= 29) hdr.numvslots = 0;
  655. else lilswap(&hdr.numvslots, 1);
  656. }
  657.  
  658. loopi(hdr.numvars)
  659. {
  660. int type = f->getchar(), ilen = f->getlil<ushort>();
  661. string name;
  662. f->read(name, min(ilen, MAXSTRLEN-1));
  663. name[min(ilen, MAXSTRLEN-1)] = '\0';
  664. if(ilen >= MAXSTRLEN) f->seek(ilen - (MAXSTRLEN-1), SEEK_CUR);
  665. ident *id = getident(name);
  666. bool exists = id && id->type == type;
  667. switch(type)
  668. {
  669. case ID_VAR:
  670. {
  671. int val = f->getlil<int>();
  672. if(exists && id->minval <= id->maxval) setvar(name, val);
  673. if(dbgvars) conoutf(CON_DEBUG, "read var %s: %d", name, val);
  674. break;
  675. }
  676.  
  677. case ID_FVAR:
  678. {
  679. float val = f->getlil<float>();
  680. if(exists && id->minvalf <= id->maxvalf) setfvar(name, val);
  681. if(dbgvars) conoutf(CON_DEBUG, "read fvar %s: %f", name, val);
  682. break;
  683. }
  684.  
  685. case ID_SVAR:
  686. {
  687. int slen = f->getlil<ushort>();
  688. string val;
  689. f->read(val, min(slen, MAXSTRLEN-1));
  690. val[min(slen, MAXSTRLEN-1)] = '\0';
  691. if(slen >= MAXSTRLEN) f->seek(slen - (MAXSTRLEN-1), SEEK_CUR);
  692. if(exists) setsvar(name, val);
  693. if(dbgvars) conoutf(CON_DEBUG, "read svar %s: %s", name, val);
  694. break;
  695. }
  696. }
  697. }
  698. if(dbgvars) conoutf(CON_DEBUG, "read %d vars", hdr.numvars);
  699.  
  700. string gametype;
  701. copystring(gametype, "fps");
  702. bool samegame = true;
  703. int eif = 0;
  704. if(hdr.version>=16)
  705. {
  706. int len = f->getchar();
  707. f->read(gametype, len+1);
  708. }
  709. if(strcmp(gametype, game::gameident())!=0)
  710. {
  711. samegame = false;
  712. conoutf(CON_WARN, "WARNING: loading map from %s game, ignoring entities except for lights/mapmodels)", gametype);
  713. }
  714. if(hdr.version>=16)
  715. {
  716. eif = f->getlil<ushort>();
  717. int extrasize = f->getlil<ushort>();
  718. vector<char> extras;
  719. loopj(extrasize) extras.add(f->getchar());
  720. if(samegame) game::readgamedata(extras);
  721. }
  722.  
  723. renderprogress(0, "clearing world...");
  724.  
  725. texmru.shrink(0);
  726. if(hdr.version<14)
  727. {
  728. uchar oldtl[256];
  729. f->read(oldtl, sizeof(oldtl));
  730. loopi(256) texmru.add(oldtl[i]);
  731. }
  732. else
  733. {
  734. ushort nummru = f->getlil<ushort>();
  735. loopi(nummru) texmru.add(f->getlil<ushort>());
  736. }
  737.  
  738. freeocta(worldroot);
  739. worldroot = NULL;
  740.  
  741. setvar("mapsize", hdr.worldsize, true, false);
  742. int worldscale = 0;
  743. while(1<<worldscale < hdr.worldsize) worldscale++;
  744. setvar("mapscale", worldscale, true, false);
  745.  
  746. renderprogress(0, "loading entities...");
  747.  
  748. vector<extentity *> &ents = entities::getents();
  749. int einfosize = entities::extraentinfosize();
  750. char *ebuf = einfosize > 0 ? new char[einfosize] : NULL;
  751. loopi(min(hdr.numents, MAXENTS))
  752. {
  753. // extentity &e = *entities::newentity();
  754. // ents.add(&e);
  755. extentity e; // INTENSITY: Do *NOT* actually load entities from .ogz files - we use our own system.
  756. // But, read the data from the file so we can move on (might be a sauer .ogz)
  757. // So 'e' here is just a dummy
  758.  
  759. f->read(&e, sizeof(entity));
  760. lilswap(&e.o.x, 3);
  761. lilswap(&e.attr1, 5);
  762. e.spawned = false;
  763. e.inoctanode = false;
  764. if(hdr.version <= 10 && e.type >= 7) e.type++;
  765. if(hdr.version <= 12 && e.type >= 8) e.type++;
  766. if(hdr.version <= 14 && e.type >= ET_MAPMODEL && e.type <= 16)
  767. {
  768. if(e.type == 16) e.type = ET_MAPMODEL;
  769. else e.type++;
  770. }
  771. if(hdr.version <= 20 && e.type >= ET_ENVMAP) e.type++;
  772. if(hdr.version <= 21 && e.type >= ET_PARTICLES) e.type++;
  773. if(hdr.version <= 22 && e.type >= ET_SOUND) e.type++;
  774. if(hdr.version <= 23 && e.type >= ET_SPOTLIGHT) e.type++;
  775. if(hdr.version <= 30 && (e.type == ET_MAPMODEL || e.type == ET_PLAYERSTART)) e.attr1 = (int(e.attr1)+180)%360;
  776. if(samegame)
  777. {
  778. if(einfosize > 0) f->read(ebuf, einfosize);
  779. entities::readent(e, ebuf);
  780. }
  781. else
  782. {
  783. if(eif > 0) f->seek(eif, SEEK_CUR);
  784. if(e.type>=ET_GAMESPECIFIC || hdr.version<=14)
  785. {
  786. entities::deleteentity(ents.pop());
  787. continue;
  788. }
  789. }
  790. if(!insideworld(e.o))
  791. {
  792. if(e.type != ET_LIGHT && e.type != ET_SPOTLIGHT)
  793. {
  794. conoutf(CON_WARN, "warning: ent outside of world: enttype[%s] index %d (%f, %f, %f)", entities::entname(e.type), i, e.o.x, e.o.y, e.o.z);
  795. }
  796. }
  797. if(hdr.version <= 14 && e.type == ET_MAPMODEL)
  798. {
  799. e.o.z += e.attr3;
  800. if(e.attr4) conoutf(CON_WARN, "warning: mapmodel ent (index %d) uses texture slot %d", i, e.attr4);
  801. e.attr3 = e.attr4 = 0;
  802. }
  803. // INTENSITY: Print ent out, useful for copy-paste importing sauer maps
  804. // we usually begin with 3 on emptymap
  805. static int uniqueId = 3;
  806. printf("[%d, \"", uniqueId);
  807. if (e.type == ET_LIGHT) printf("Light");
  808. else if (e.type == ET_MAPMODEL) printf("Mapmodel");
  809. else if (e.type == ET_PLAYERSTART) printf("WorldMarker");
  810. else if (e.type == ET_ENVMAP) printf("Envmap");
  811. else if (e.type == ET_PARTICLES) printf("ParticleEffect");
  812. else if (e.type == ET_SOUND) printf("SoundEffect***");
  813. else if (e.type == ET_SPOTLIGHT) printf("SpotLight***");
  814. printf("\", {");
  815. printf("\"attr1\":\"%d\", ", e.attr1);
  816. printf("\"attr2\":\"%d\", ", e.attr2);
  817. printf("\"attr3\":\"%d\", ", e.attr3);
  818. printf("\"attr4\":\"%d\", ", e.attr4);
  819. printf("\"position\":\"[%f|%f|%f]\", ", e.o.x, e.o.y, e.o.z);
  820. printf("\"animation\":\"130\", ");
  821. printf("\"startTime\":\"@REPLACE_STARTTIME@\", ");
  822. if (e.type == ET_MAPMODEL)
  823. printf("\"modelName\":\"@REPLACE_MODEL_PATH@\", ");
  824. else
  825. printf("\"modelName\":\"\", ");
  826. printf("\"attachments\":\"[]\", ");
  827. if (e.type == ET_PLAYERSTART)
  828. printf("\"tags\":\"[start_@REPLACE_TEAM@]\", ");
  829. else
  830. printf("\"tags\":\"[]\", ");
  831. printf("\"_persistent\":\"true\"");
  832. printf("}], \r\n");
  833. uniqueId++;
  834. // INTENSITY: end Print ent out
  835. }
  836. if(ebuf) delete[] ebuf;
  837.  
  838. if(hdr.numents > MAXENTS)
  839. {
  840. conoutf(CON_WARN, "warning: map has %d entities", hdr.numents);
  841. f->seek((hdr.numents-MAXENTS)*(samegame ? sizeof(entity) + einfosize : eif), SEEK_CUR);
  842. }
  843.  
  844. //#ifdef CLIENT // INTENSITY: hey, dont crash! lets not load vslots on server
  845. renderprogress(0, "loading slots...");
  846. loadvslots(f, hdr.numvslots);
  847. //#endif
  848.  
  849. renderprogress(0, "loading octree...");
  850. worldroot = loadchildren(f);
  851.  
  852. if(hdr.version <= 11)
  853. swapXZ(worldroot);
  854.  
  855. if(hdr.version <= 8)
  856. converttovectorworld();
  857.  
  858. if(hdr.version <= 25 && hdr.worldsize > 0x1000)
  859. fixoversizedcubes(worldroot, hdr.worldsize>>1);
  860.  
  861. renderprogress(0, "validating...");
  862. validatec(worldroot, hdr.worldsize>>1);
  863.  
  864. #ifdef CLIENT // INTENSITY: Server doesn't need lightmaps, pvs and blendmap (and current code for server wouldn't clean
  865. // them up if we did read them, so would have a leak)
  866. if(hdr.version >= 7) loopi(hdr.lightmaps)
  867. {
  868. renderprogress(i/(float)hdr.lightmaps, "loading lightmaps...");
  869. LightMap &lm = lightmaps.add();
  870. if(hdr.version >= 17)
  871. {
  872. int type = f->getchar();
  873. lm.type = type&0x7F;
  874. if(hdr.version >= 20 && type&0x80)
  875. {
  876. lm.unlitx = f->getlil<ushort>();
  877. lm.unlity = f->getlil<ushort>();
  878. }
  879. }
  880. if(lm.type&LM_ALPHA && (lm.type&LM_TYPE)!=LM_BUMPMAP1) lm.bpp = 4;
  881. lm.data = new uchar[lm.bpp*LM_PACKW*LM_PACKH];
  882. f->read(lm.data, lm.bpp * LM_PACKW * LM_PACKH);
  883. lm.finalize();
  884. }
  885.  
  886. if(hdr.version >= 25 && hdr.numpvs > 0) loadpvs(f, hdr.numpvs);
  887. if(hdr.version >= 28 && hdr.blendmap) loadblendmap(f, hdr.blendmap);
  888. #endif // INTENSITY
  889.  
  890. // mapcrc = f->getcrc(); // INTENSITY: We use our own signatures
  891. delete f;
  892.  
  893. #if 0 // INTENSITY
  894. conoutf("read map %s (%.1f seconds)", ogzname, (SDL_GetTicks()-loadingstart)/1000.0f);
  895. #endif
  896.  
  897. clearmainmenu();
  898.  
  899. overrideidents = true;
  900. execfile("data/default_map_settings.cfg", false);
  901. #if 0 // INTENSITY: Use our scripting script instead
  902. execfile(cfgname, false);
  903. #else
  904. WorldSystem::runMapScript();
  905. #endif
  906. overrideidents = false;
  907.  
  908. #ifdef CLIENT // INTENSITY: Stop, finish loading later when we have all the entities
  909. renderprogress(0, "requesting entities...");
  910. Logging::log(Logging::DEBUG, "Requesting active entities...\r\n");
  911. MessageSystem::send_ActiveEntitiesRequest(ClientSystem::currScenarioCode); // Ask for the NPCs and other players, which are not part of the map proper
  912. #else // SERVER
  913. Logging::log(Logging::DEBUG, "Finishing loading of the world...\r\n");
  914. finish_load_world();
  915. #endif
  916.  
  917. return true;
  918. }
  919.  
  920. bool finish_load_world() // INTENSITY: Second half, after all entities received
  921. {
  922. renderprogress(0, "finalizing world..."); // INTENSITY
  923.  
  924. const char *mname = _saved_mname; // INTENSITY
  925. const char *cname = _saved_cname; // INTENSITY
  926. octaheader& hdr = *saved_hdr; // INTENSITY
  927.  
  928. extern void fixlightmapnormals();
  929. if(hdr.version <= 25) fixlightmapnormals();
  930.  
  931. #if 0 // INTENSITY: We use our own preloading system
  932. vector<int> mapmodels;
  933. loopv(ents)
  934. {
  935. extentity &e = *ents[i];
  936. if(e.type==ET_MAPMODEL && e.attr2 >= 0)
  937. {
  938. if(mapmodels.find(e.attr2) < 0) mapmodels.add(e.attr2);
  939. }
  940. }
  941.  
  942. loopv(mapmodels)
  943. {
  944. loadprogress = float(i+1)/mapmodels.length();
  945. int mmindex = mapmodels[i];
  946. mapmodelinfo &mmi = getmminfo(mmindex);
  947. if(!&mmi) conoutf(CON_WARN, "could not find map model: %d", mmindex);
  948. else if(!loadmodel(NULL, mmindex, true)) conoutf(CON_WARN, "could not load model: %s", mmi.name);
  949. else if(mmi.m && bih) mmi.m->preloadBIH();
  950. }
  951. #endif // INTENSITY
  952.  
  953. loadprogress = 0;
  954.  
  955. game::preload();
  956. flushpreloadedmodels();
  957.  
  958. entitiesinoctanodes();
  959. attachentities();
  960. initlights();
  961. allchanged(true);
  962.  
  963. // if(maptitle[0] && strcmp(maptitle, "Untitled Map by Unknown")) conoutf(CON_ECHO, "%s", maptitle); // INTENSITY
  964.  
  965. startmap(cname ? cname : mname);
  966.  
  967. Logging::log(Logging::DEBUG, "load_world complete.\r\n"); // INTENSITY
  968. WorldSystem::loadingWorld = false; // INTENSITY
  969.  
  970. delete saved_hdr; // INTENSITY
  971.  
  972. printf("\r\n\r\n[[MAP LOADING]] - Success.\r\n"); // INTENSITY
  973.  
  974. return true;
  975. }
  976.  
  977. void savecurrentmap() { save_world(game::getclientmap()); }
  978. void savemap(char *mname) { save_world(mname); }
  979.  
  980. COMMAND(savemap, "s");
  981. COMMAND(savecurrentmap, "");
  982.  
  983. static int mtlsort(const int *x, const int *y)
  984. {
  985. if(*x < *y) return -1;
  986. if(*x > *y) return 1;
  987. return 0;
  988. }
  989.  
  990. void writeobj(char *name)
  991. {
  992. defformatstring(fname)("%s.obj", name);
  993. stream *f = openfile(path(fname), "w");
  994. if(!f) return;
  995. f->printf("# obj file of Cube 2 level\n\n");
  996. defformatstring(mtlname)("%s.mtl", name);
  997. path(mtlname);
  998. f->printf("mtllib %s\n\n", mtlname);
  999. extern vector<vtxarray *> valist;
  1000. vector<vec> verts;
  1001. vector<vec2> texcoords;
  1002. hashtable<vec, int> shareverts(1<<16);
  1003. hashtable<vec2, int> sharetc(1<<16);
  1004. hashtable<int, vector<ivec> > mtls(1<<8);
  1005. vector<int> usedmtl;
  1006. vec bbmin(1e16f, 1e16f, 1e16f), bbmax(-1e16f, -1e16f, -1e16f);
  1007. loopv(valist)
  1008. {
  1009. vtxarray &va = *valist[i];
  1010. ushort *edata = NULL;
  1011. uchar *vdata = NULL;
  1012. if(!readva(&va, edata, vdata)) continue;
  1013. int vtxsize = VTXSIZE;
  1014. ushort *idx = edata;
  1015. loopj(va.texs)
  1016. {
  1017. elementset &es = va.eslist[j];
  1018. if(usedmtl.find(es.texture) < 0) usedmtl.add(es.texture);
  1019. vector<ivec> &keys = mtls[es.texture];
  1020. loopk(es.length[1])
  1021. {
  1022. int n = idx[k] - va.voffset;
  1023. const vec &pos = renderpath==R_FIXEDFUNCTION ? ((const vertexff *)&vdata[n*vtxsize])->pos : ((const vertex *)&vdata[n*vtxsize])->pos;
  1024. vec2 tc(renderpath==R_FIXEDFUNCTION ? ((const vertexff *)&vdata[n*vtxsize])->u : ((const vertex *)&vdata[n*vtxsize])->u,
  1025. renderpath==R_FIXEDFUNCTION ? ((const vertexff *)&vdata[n*vtxsize])->v : ((const vertex *)&vdata[n*vtxsize])->v);
  1026. ivec &key = keys.add();
  1027. key.x = shareverts.access(pos, verts.length());
  1028. if(key.x == verts.length())
  1029. {
  1030. verts.add(pos);
  1031. loopl(3)
  1032. {
  1033. bbmin[l] = min(bbmin[l], pos[l]);
  1034. bbmax[l] = max(bbmax[l], pos[l]);
  1035. }
  1036. }
  1037. key.y = sharetc.access(tc, texcoords.length());
  1038. if(key.y == texcoords.length()) texcoords.add(tc);
  1039. }
  1040. idx += es.length[1];
  1041. }
  1042. delete[] edata;
  1043. delete[] vdata;
  1044. }
  1045.  
  1046. vec center(-(bbmax.x + bbmin.x)/2, -(bbmax.y + bbmin.y)/2, -bbmin.z);
  1047. loopv(verts)
  1048. {
  1049. vec v = verts[i];
  1050. v.add(center);
  1051. if(v.y != floor(v.y)) f->printf("v %.3f ", -v.y); else f->printf("v %d ", int(-v.y));
  1052. if(v.z != floor(v.z)) f->printf("%.3f ", v.z); else f->printf("%d ", int(v.z));
  1053. if(v.x != floor(v.x)) f->printf("%.3f\n", v.x); else f->printf("%d\n", int(v.x));
  1054. }
  1055. f->printf("\n");
  1056. loopv(texcoords)
  1057. {
  1058. const vec2 &tc = texcoords[i];
  1059. f->printf("vt %.6f %.6f\n", tc.x, 1-tc.y);
  1060. }
  1061. f->printf("\n");
  1062.  
  1063. usedmtl.sort(mtlsort);
  1064. loopv(usedmtl)
  1065. {
  1066. vector<ivec> &keys = mtls[usedmtl[i]];
  1067. f->printf("g slot%d\n", usedmtl[i]);
  1068. f->printf("usemtl slot%d\n\n", usedmtl[i]);
  1069. for(int i = 0; i < keys.length(); i += 3)
  1070. {
  1071. f->printf("f");
  1072. loopk(3) f->printf(" %d/%d", keys[i+2-k].x+1, keys[i+2-k].y+1);
  1073. f->printf("\n");
  1074. }
  1075. f->printf("\n");
  1076. }
  1077. delete f;
  1078.  
  1079. f = openfile(mtlname, "w");
  1080. if(!f) return;
  1081. f->printf("# mtl file of Cube 2 level\n\n");
  1082. loopv(usedmtl)
  1083. {
  1084. VSlot &vslot = lookupvslot(usedmtl[i], false);
  1085. f->printf("newmtl slot%d\n", usedmtl[i]);
  1086. f->printf("map_Kd %s\n", vslot.slot->sts.empty() ? notexture->name : path(makerelpath("packages", vslot.slot->sts[0].name)));
  1087. f->printf("\n");
  1088. }
  1089. delete f;
  1090. }
  1091.  
  1092. COMMAND(writeobj, "s");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement