Advertisement
Guest User

Untitled

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